1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
/*
* Copyright (c) 2012, 2013 Richard Braun.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <kern/init.h>
#include <machine/asm.h>
#include <machine/cpu.h>
.section INIT_SECTION
#ifdef __LP64__
ASM_ENTRY(tcb_context_load)
movq (%rdi), %rbp /* load frame pointer from TCB */
movq 8(%rdi), %rsp /* load stack pointer from TCB */
movq 16(%rdi), %rax /* load instruction pointer from TCB */
pushq $CPU_EFL_ONE /* prepare new RFLAGS register value */
popfq /* load value into RFLAGS register */
jmp *%rax /* branch to loaded instruction pointer */
ASM_END(tcb_context_load)
#else /* __LP64__ */
ASM_ENTRY(tcb_context_load)
movl 4(%esp), %eax /* load TCB address */
movl (%eax), %ebp /* load frame pointer from TCB */
movl 4(%eax), %esp /* load stack pointer from TCB */
movl 8(%eax), %ecx /* load instruction pointer from TCB */
pushl $CPU_EFL_ONE /* prepare new EFLAGS register value */
popfl /* load value into EFLAGS register */
jmp *%ecx /* branch to loaded instruction pointer */
ASM_END(tcb_context_load)
#endif /* __LP64__ */
.text
#ifdef __LP64__
ASM_ENTRY(tcb_start)
popq %rax /* load function passed at TCB initialization (this
makes the stack pointer reach the stack top) */
call *%rax /* branch to loaded function, pushing the return
address to start a clean stack trace */
/* Never reached */
nop /* Make the return address point to an instruction
inside the function to build a clean stack trace */
ASM_END(tcb_start)
ASM_ENTRY(tcb_context_switch)
pushfq /* store registers as required by ABI */
pushq %rbx
pushq %r12
pushq %r13
pushq %r14
pushq %r15
movq %rbp, (%rdi) /* store frame pointer into prev TCB */
movq %rsp, 8(%rdi) /* store stack pointer into prev TCB */
movq $1f, 16(%rdi) /* store next instruction address into prev TCB */
movq (%rsi), %rbp /* load frame pointer from next TCB */
movq 8(%rsi), %rsp /* load stack pointer from next TCB */
movq 16(%rsi), %rax /* load instruction pointer from next TCB */
jmp *%rax /* branch to loaded instruction pointer */
/*
* This code is run on context restoration. The frame and stack pointers
* have already been loaded to their correct values. Load registers which
* were stored on the stack when the context was saved and return.
*/
1:
popq %r15
popq %r14
popq %r13
popq %r12
popq %rbx
popfq
ret
ASM_END(tcb_context_switch)
#else /* __LP64__ */
ASM_ENTRY(tcb_start)
popl %eax /* load function passed at TCB initialization (this
makes the stack pointer reach the stack top) */
call *%eax /* branch to loaded function, pushing the return
address to start a clean stack trace */
/* Never reached */
nop /* Make the return address point to an instruction
inside the function to build a clean stack trace */
ASM_END(tcb_start)
ASM_ENTRY(tcb_context_switch)
movl 4(%esp), %eax /* load prev TCB address */
movl 8(%esp), %ecx /* load next TCB address */
pushfl /* store registers as required by ABI */
pushl %ebx
pushl %edi
pushl %esi
movl %ebp, (%eax) /* store frame pointer into prev TCB */
movl %esp, 4(%eax) /* store stack pointer into prev TCB */
movl $1f, 8(%eax) /* store next instruction address into prev TCB */
movl (%ecx), %ebp /* load frame pointer from next TCB */
movl 4(%ecx), %esp /* load stack pointer from next TCB */
movl 8(%ecx), %edx /* load instruction pointer from next TCB */
jmp *%edx /* branch to loaded instruction pointer */
/*
* This code is run on context restoration. The frame and stack pointers
* have already been loaded to their correct values. Load registers which
* were stored on the stack when the context was saved and return.
*/
1:
popl %esi
popl %edi
popl %ebx
popfl
ret
ASM_END(tcb_context_switch)
#endif /* __LP64__ */
|