x86_64: GS base work
[akaros.git] / kern / arch / x86 / trapentry64.S
1 /* See COPYRIGHT for copyright information.
2  * The two TRAP* macros (minus the .data parts) are from the JOS project.
3  * Everything else:
4  * Copyright (c) 2009, 2013 The Regents of the University of California
5  * Barret Rhoden <brho@cs.berkeley.edu>
6  * See LICENSE for details.
7  */
8 #include <arch/mmu.h>
9 #include <arch/trap.h>
10 #include <arch/x86.h>
11 #include <ros/memlayout.h>
12
13 ###################################################################
14 # exceptions/interrupts
15 ###################################################################
16
17 /* The TRAPHANDLER macro defines a globally-visible function for handling
18  * a trap.  It pushes a trap number onto the stack, then jumps to _alltraps.
19  * It also builds this traps portion of the trap_tbl.
20  * Use TRAPHANDLER for traps where the CPU automatically pushes an error code.
21  */
22 #define TRAPHANDLER(name, num)                                                                  \
23         .text;                                                                                                          \
24         .globl name;            /* define global symbol for 'name' */   \
25         .type name, @function;  /* symbol type is function */           \
26         .align 2;               /* align function definition */                         \
27         name:                   /* function starts here */                                      \
28         pushq $(num);                                                                                           \
29         jmp _alltraps;                                                                                          \
30         .data;                                                                                                          \
31         .quad name;                                                                                                     \
32         .long num
33
34 /* Use TRAPHANDLER_NOEC for traps where the CPU doesn't push an error code.
35  * It pushes a 0 in place of the error code, so the trap frame has the same
36  * format in either case.  */
37 #define TRAPHANDLER_NOEC(name, num)             \
38         .text;                                                          \
39         .globl name;                                            \
40         .type name, @function;                          \
41         .align 2;                                                       \
42         name:                                                           \
43         pushq $0;                                                       \
44         pushq $(num);                                           \
45         jmp _alltraps;                                          \
46         .data;                                                          \
47         .quad name;                                                     \
48         .long num
49
50 /* Same as NOEC, but for IRQs instead.  num is the ISR number it is mapped to */
51 #define IRQ_HANDLER(name, num)                  \
52         .text;                                                          \
53         .globl name;                                            \
54         .type name, @function;                          \
55         .align 2;                                                       \
56         name:                                                           \
57         pushq $0;                                                       \
58         pushq $(num);                                           \
59         jmp _allirqs;                                           \
60         .data;                                                          \
61         .quad name;                                                     \
62         .long num
63
64 .data
65 .globl trap_tbl
66 trap_tbl:
67
68 /*
69  * Generate entry points for the different traps.
70  */
71 TRAPHANDLER_NOEC(ISR_divide_error, T_DIVIDE)
72 TRAPHANDLER_NOEC(ISR_debug_exceptions, T_DEBUG)
73 TRAPHANDLER_NOEC(ISR_NMI, T_NMI)
74 TRAPHANDLER_NOEC(ISR_breakpoint, T_BRKPT)
75 TRAPHANDLER_NOEC(ISR_overflow, T_OFLOW)
76 TRAPHANDLER_NOEC(ISR_bounds_check, T_BOUND)
77 TRAPHANDLER_NOEC(ISR_invalid_opcode, T_ILLOP)
78 TRAPHANDLER_NOEC(ISR_device_not_available, T_DEVICE)
79 /* supposedly, DF generates an error code, but the one time we've had a DF so
80  * far, it didn't.  eventually, this should probably be handled with a task gate
81  * it might have pushed a 0, but just the rest of the stack was corrupt
82  */
83 TRAPHANDLER_NOEC(ISR_double_fault, T_DBLFLT)
84 /* 9 reserved */
85 TRAPHANDLER(ISR_invalid_TSS, T_TSS)
86 TRAPHANDLER(ISR_segment_not_present, T_SEGNP)
87 TRAPHANDLER(ISR_stack_exception, T_STACK)
88 TRAPHANDLER(ISR_general_protection_fault, T_GPFLT)
89 TRAPHANDLER(ISR_page_fault, T_PGFLT)
90 /* 15 reserved */
91 TRAPHANDLER_NOEC(ISR_floating_point_error, T_FPERR)
92 TRAPHANDLER(ISR_alignment_check, T_ALIGN)
93 TRAPHANDLER_NOEC(ISR_machine_check, T_MCHK)
94 TRAPHANDLER_NOEC(ISR_simd_error, T_SIMDERR)
95 /* 20 - 31 reserved */
96 IRQ_HANDLER(IRQ0, 32)
97 IRQ_HANDLER(IRQ1, 33)
98 IRQ_HANDLER(IRQ2, 34)
99 IRQ_HANDLER(IRQ3, 35)
100 IRQ_HANDLER(IRQ4, 36)
101 IRQ_HANDLER(IRQ5, 37)
102 IRQ_HANDLER(IRQ6, 38)
103 IRQ_HANDLER(IRQ7, 39)
104 IRQ_HANDLER(IRQ8, 40)
105 IRQ_HANDLER(IRQ9, 41)
106 IRQ_HANDLER(IRQ10, 42)
107 IRQ_HANDLER(IRQ11, 43)
108 IRQ_HANDLER(IRQ12, 44)
109 IRQ_HANDLER(IRQ13, 45)
110 IRQ_HANDLER(IRQ14, 46)
111 IRQ_HANDLER(IRQ15, 47)
112 /* 25 general purpose vectors, for use by the LAPIC.  Can expand later. */
113 IRQ_HANDLER(IRQ198, I_TESTING) # used in testing.c
114 IRQ_HANDLER(IRQ199, 231)
115 IRQ_HANDLER(IRQ200, 232)
116 IRQ_HANDLER(IRQ201, 233)
117 IRQ_HANDLER(IRQ202, 234)
118 IRQ_HANDLER(IRQ203, 235)
119 IRQ_HANDLER(IRQ204, 236)
120 IRQ_HANDLER(IRQ205, 237)
121 IRQ_HANDLER(IRQ206, 238)
122 IRQ_HANDLER(IRQ207, 239)
123 /* 0xf0 - start of the SMP_CALL IPIS */
124 IRQ_HANDLER(IRQ208, I_SMP_CALL0)
125 IRQ_HANDLER(IRQ209, I_SMP_CALL1)
126 IRQ_HANDLER(IRQ210, I_SMP_CALL2)
127 IRQ_HANDLER(IRQ211, I_SMP_CALL3)
128 IRQ_HANDLER(IRQ212, I_SMP_CALL4)
129 IRQ_HANDLER(IRQ213, 245)
130 IRQ_HANDLER(IRQ214, 246)
131 IRQ_HANDLER(IRQ215, 247)
132 IRQ_HANDLER(IRQ216, 248)
133 IRQ_HANDLER(IRQ217, 249)
134 IRQ_HANDLER(IRQ218, 250)
135 IRQ_HANDLER(IRQ219, 251)
136 IRQ_HANDLER(IRQ220, 252)
137 IRQ_HANDLER(IRQ221, 253)
138 IRQ_HANDLER(IRQ222, 254)
139 IRQ_HANDLER(IRQ223, I_KERNEL_MSG)
140
141 /* Technically, these HANDLER entries do not need to be in numeric order */
142 TRAPHANDLER_NOEC(ISR_syscall, T_SYSCALL)
143 /* But make sure default is last!! */
144 TRAPHANDLER_NOEC(ISR_default, T_DEFAULT)
145
146 .data
147 .globl trap_tbl_end
148 trap_tbl_end:
149
150 .text
151 _alltraps:
152         cld
153         swapgs                  # harmless if we were already in the kernel
154         pushq %r15
155         pushq %r14
156         pushq %r13
157         pushq %r12
158         pushq %r11
159         pushq %r10
160         pushq %r9
161         pushq %r8
162         pushq %rdi
163         pushq %rsi
164         pushq %rbp
165         pushq %rdx
166         pushq %rcx
167         pushq %rbx
168         pushq %rax
169         cmpw $GD_KT, 0x90(%rsp) # 0x90 - diff btw tf_cs and tf_rax
170         je trap_kernel_tf
171         # this is a user TF, so we need to save their fs/gsbase and load gs base for
172         # the kernel.
173         movl $MSR_FS_BASE, %ecx
174         rdmsr
175         shl $32, %rdx
176         orq %rax, %rdx
177         pushq %rdx
178         # because we swapped gs earlier, the TF in use is now in KERN_GS_BASE
179         movl $MSR_KERN_GS_BASE, %ecx
180         rdmsr
181         shl $32, %rdx
182         orq %rax, %rdx
183         pushq %rdx
184         # make sure the kernel's gs base is loaded into the KERN slot at all times
185         movl $MSR_GS_BASE, %ecx
186         rdmsr
187         movl $MSR_KERN_GS_BASE, %ecx
188         wrmsr
189         jmp trap_all_tf
190 trap_kernel_tf:
191         # we don't muck with fs/gsbase, push placeholders
192         movq $0xdeadbeef, %rax
193         pushq %rax
194         pushq %rax
195 trap_all_tf:
196         movq $0, %rbp                   # so we can backtrace to this point
197         movq %rsp, %rdi
198         call trap
199         # the return paths are only used by the kernel
200         addq $0x10, %rsp                        # skip fs/gs base
201         popq %rax
202         popq %rbx
203         popq %rcx
204         popq %rdx
205         popq %rbp
206         popq %rsi
207         popq %rdi
208         popq %r8
209         popq %r9
210         popq %r10
211         popq %r11
212         popq %r12
213         popq %r13
214         popq %r14
215         popq %r15
216         addq $0x10, %rsp                        # skip trapno and err
217         iretq
218
219 # might merge this with _alltraps
220 _allirqs:
221         cld
222         swapgs                  # harmless if we were already in the kernel
223         pushq %r15
224         pushq %r14
225         pushq %r13
226         pushq %r12
227         pushq %r11
228         pushq %r10
229         pushq %r9
230         pushq %r8
231         pushq %rdi
232         pushq %rsi
233         pushq %rbp
234         pushq %rdx
235         pushq %rcx
236         pushq %rbx
237         pushq %rax
238         cmpw $GD_KT, 0x90(%rsp) # 0x90 - diff btw tf_cs and tf_rax
239         je irq_kernel_tf
240         # this is a user TF, so we need to save their fs/gsbase and load gs base for
241         # the kernel.
242         movl $MSR_FS_BASE, %ecx
243         rdmsr
244         shl $32, %rdx
245         orq %rax, %rdx
246         pushq %rdx
247         # because we swapped gs earlier, the TF in use is now in KERN_GS_BASE
248         movl $MSR_KERN_GS_BASE, %ecx
249         rdmsr
250         shl $32, %rdx
251         orq %rax, %rdx
252         pushq %rdx
253         # make sure the kernel's gs base is loaded into the KERN slot at all times
254         movl $MSR_GS_BASE, %ecx
255         rdmsr
256         movl $MSR_KERN_GS_BASE, %ecx
257         wrmsr
258         jmp irq_all_tf
259 irq_kernel_tf:
260         # we don't muck with fs/gsbase, push placeholders
261         movq $0xdeadbeef, %rax
262         pushq %rax
263         pushq %rax
264 irq_all_tf:
265         movq $0, %rbp                   # so we can backtrace to this point
266         movq %rsp, %rdi
267         call irq_handler
268         # the return paths are only used by the kernel
269         addq $0x10, %rsp                        # skip fs/gs base
270         popq %rax
271         popq %rbx
272         popq %rcx
273         popq %rdx
274         popq %rbp
275         popq %rsi
276         popq %rdi
277         popq %r8
278         popq %r9
279         popq %r10
280         popq %r11
281         popq %r12
282         popq %r13
283         popq %r14
284         popq %r15
285         addq $0x10, %rsp                        # skip trapno and err
286         iretq
287
288 .globl sysenter_handler;
289 .type sysenter_handler, @function;
290 # All of the pushq zeros are to keep the trap frame looking the same as when we
291 # receive a trap or an interrupt
292 sysenter_handler:
293         cld
294         pushq $0                                # ss
295         pushq $0                                # rsp
296         pushfq                                  # eflags
297         pushq $0                                # CS == 0 lets the kernel know it was a sysenter        
298         pushq $0                                # eip
299         pushq $0                                # err 
300         pushq $T_SYSCALL                # helps with print_trapframe
301         # pushq %ds
302         # pushq %es
303         pushq %fs
304         pushq %gs
305         # pushal
306         movw $0, %ax;
307         movw %ax, %gs;
308         movw %ax, %fs;
309         movw $GD_KD, %ax
310         movw %ax, %ds
311         movw %ax, %es
312         pushq %rsp
313         movq $0, %rbp                   # so we can backtrace to this point
314         call sysenter_callwrapper
315         popq %rsp
316         # popal
317         popq %gs
318         popq %fs
319         # popq %es
320         # popq %ds
321         addq $0x10, %rsp                # pop T_SYSCALL and the three zeros
322         popfq                                   # restore EFLAGS (and usually enables interrupts!)
323         movq %rbp, %rcx
324         sti                                             # interrupts are turned off when starting a core
325         sysexit