summaryrefslogtreecommitdiff
path: root/arch/x86/machine/tcb_asm.S
blob: e4e2c452ae27d25118447ed51c9fab183f2e588f (plain)
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__ */