04d602ca6ac1b58ace5e31c9de6e67741d5860bd
[polintos/scott/priv.git] / kernel / arch / x64 / entry.S
1 // arch/x86/entry.S - x64 entry points (booting and traps)
2 //
3 // This software is copyright (c) 2006 Scott Wood.
4 // 
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of
6 // this software and associated documentation files (the "Software"), to deal with
7 // the Software without restriction, including without limitation the rights to
8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 // of the Software, and to permit persons to whom the Software is furnished to do
10 // so, subject to the following conditions:
11 // 
12 //     * Redistributions of source code must retain the above copyright notice,
13 //       this list of conditions and the following disclaimers.
14 // 
15 //     * Redistributions in binary form must reproduce the above copyright notice,
16 //       this list of conditions and the following disclaimers in the
17 //       documentation and/or other materials provided with the distribution.
18 // 
19 //     * The names of the Software's authors and/or contributors
20 //       may not be used to endorse or promote products derived from
21 //       this Software without specific prior written permission.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
25 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
26 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
29 // SOFTWARE.
30
31 #include <arch/addrs.h>
32
33         .org 0
34         .code32
35         .global _start
36 .align  4
37 multiboot_hdr:
38         .long   0x1badb002              // Multi-boot magic
39         
40         // Multi-boot flags:
41         //  bit 0: 4KiB-align all boot modules
42         //  bit 1: must include memory size and map
43         //  bit 2: must include video mode table
44         //  bit 16: load addresses in this header are valid
45         //          and should be used instead of the ELF header
46
47         .long   0x00010003
48
49         // checksum: -(magic + flags), update if flags change
50         .long   0xe4514ffb
51
52         .long   multiboot_hdr - KERNEL_START    // header_addr
53         .long   0x00200000                      // load_addr
54         .long   0                               // load_end_addr: load whole file
55         .long   bss_end - KERNEL_START          // bss_end_addr
56         .long   _start - KERNEL_START           // entry_addr
57
58 _start:
59         cld
60         cmpl    $0x2badb002, %eax
61         bne     no_multiboot
62         
63         lgdt    x64_gdtr_phys + 6 - KERNEL_START
64         ljmp    $0x10, $using_our_gdt - KERNEL_START
65
66 using_our_gdt:
67         movw    $0x08, %ax
68         movw    %ax, %ds
69         movw    %ax, %es
70         movw    %ax, %fs
71         movw    %ax, %gs
72         movw    %ax, %ss
73         
74         movl    %ebx, %esi              // Save the multiboot pointer somewhere
75                                         // it won't be clobbered by CPUID
76
77         // This gives 256 bytes to Threads::Thread; if it gets larger
78         // this needs to be updated (as well as the code at high_vaddr).
79
80         movl    $x64_init_stack + 3840 - KERNEL_START, %esp
81         
82         // Test for CPUID
83         pushfl
84         popl    %eax
85         movl    %eax, %ebx
86         xorl    $0x00200000, %eax
87         pushl   %eax
88         popfl
89         pushfl
90         popl    %eax
91         cmpl    %eax, %ebx
92         je      no_long_mode
93
94         // Test for long mode
95         movl    $0x80000000, %eax
96         cpuid
97         cmpl    $0x80000000, %eax
98         jbe     no_long_mode
99         movl    $0x80000001, %eax
100         cpuid
101         btl     $29, %edx
102         jnc     no_long_mode
103
104         movl    $0xc0000080, %ecx       // Extended Feature Enable Register (EFER)
105         xorl    %edx, %edx
106         movl    $0x100, %eax            // Enable long mode
107         wrmsr
108         
109         // enable PAE
110         movl    %cr4, %eax
111         btsl    $5, %eax
112         movl    %eax, %cr4
113
114         // Set page table attributes
115         orl     $7, x64_init_ptbl_l4 - KERNEL_START
116         orl     $7, x64_init_ptbl_l3 - KERNEL_START
117 //      orl     $7, x64_init_ptbl_l2 - KERNEL_START
118         
119         // Load the initial page table
120         movl    $x64_init_ptbl_l4 - KERNEL_START, %eax
121         movl    %eax, %cr3
122         
123         // enable paging, kernel write-protect, 
124         // and internal floating point error handling
125         movl    %cr0, %eax
126         orl     $0x80010020, %eax
127         movl    %eax, %cr0
128         ljmp    $0x18, $in_code64 - KERNEL_START
129
130         .code64
131 in_code64:
132         // Set up high page tables for 0xffffffff80000000 mapping,
133         // reusing the tables previously used for the low identity
134         // mapping.
135         
136         movq    x64_init_ptbl_l4 - KERNEL_START, %rax
137         movq    %rax, x64_init_ptbl_l4 - KERNEL_START + 0xff8
138         
139         movq    x64_init_ptbl_l3 - KERNEL_START, %rax
140         movq    %rax, x64_init_ptbl_l3 - KERNEL_START + 0xff0
141         
142         lgdt    x64_gdtr + 6
143         movl    %esi, x64_boot_info_phys
144         
145         movq    $high_vaddr, %rax
146         jmp     *%rax
147
148 high_vaddr:
149         movq    $x64_init_stack + 3840, %rsp
150         jmp     start_kernel
151
152         .code32
153 no_multiboot:
154         movl    $no_multiboot_str - KERNEL_START, %esi
155         jmp     do_print
156 no_long_mode:
157         movl    $no_long_mode_str - KERNEL_START, %esi
158 do_print:
159         movl    $0xb8000, %edi
160         
161         movb    (%esi), %al
162         xorl    %ecx, %ecx
163 1:      movb    %al, (%edi, %ecx, 2)
164         movb    $14, 1(%edi, %ecx, 2)   // It's not at the cursor, so use
165                                         // yellow to make it stand out.
166         incl    %ecx
167         movb    (%esi, %ecx), %al
168         testb   %al, %al
169         jnz     1b
170
171 2:      jmp     2b
172         
173 no_long_mode_str:
174         .string "This CPU does not support long (64-bit) mode.  Use a 32-bit kernel."
175
176 no_multiboot_str:
177         .string "Unrecognized bootloader; a multiboot-compliant loader is required."
178
179         .code64
180         
181         .macro  pushvolatilesnordi
182         push    %rax
183         push    %rcx
184         push    %rdx
185         push    %rsi
186         push    %r8
187         push    %r9
188         push    %r10
189         push    %r11
190         .endm
191
192         .macro  pushvolatiles
193         push    %rax
194         pushvolatilesnordi
195         .endm
196         
197         .macro  popvolatiles
198         pop     %r11
199         pop     %r10
200         pop     %r9
201         pop     %r8
202         pop     %rsi
203         pop     %rdx
204         pop     %rcx
205         pop     %rax
206         pop     %rdi
207         .endm
208
209         // Non-volatile registers must be pushed if the handler will
210         // need to access all of the interrupted code's registers,
211         // such as when producing an error dump.  Does not include
212         // r15, as that is usually swapped with the error code.
213         
214         .macro  pushall
215         push    %r14
216         push    %r13
217         push    %r12
218         push    %r11
219         push    %r10
220         push    %r9
221         push    %r8
222         push    %rdi
223         push    %rsi
224         push    %rbp
225         push    %rsp
226         push    %rbx
227         push    %rdx
228         push    %rcx
229         push    %rax
230         .endm
231
232         .macro  pushallnoerr
233         push    %r15
234         pushall
235         .endm
236         
237         .macro  popall
238         pop     %rax
239         pop     %rcx
240         pop     %rdx
241         pop     %rbx
242         addq    $8, %rsp
243         pop     %rbp
244         pop     %rsi
245         pop     %rdi
246         pop     %r8
247         pop     %r9
248         pop     %r10
249         pop     %r11
250         pop     %r12
251         pop     %r13
252         pop     %r14
253         pop     %r15
254         .endm
255         
256         .global x64_diverr
257 x64_diverr:
258         pushallnoerr
259
260         movq    %rsp, %rdi
261         call    x64_do_diverr
262
263         popall
264         iretq
265
266         .global x64_invalid_insn
267 x64_invalid_insn:
268         pushallnoerr
269
270         movq    %rsp, %rdi
271         call    x64_do_invalid_insn
272
273         popall
274         iretq
275
276         .global x64_gpf
277 x64_gpf:
278         xchgq   %r15, (%rsp)    // get error code
279         pushall
280         
281         movq    %rsp, %rdi
282         movq    %r15, %rsi
283         call    x64_do_gpf
284         
285         popall
286         iretq
287
288         .global x64_page_fault
289 x64_page_fault:
290         xchgq   %r15, (%rsp)    // get error code
291         pushall
292         
293         movq    %rsp, %rdi
294         movq    %cr2, %rsi
295         movq    %r15, %rdx
296         call    x64_do_page_fault
297         
298         popall
299         iretq
300
301         .global x64_irq
302 x64_irq:
303         pushvolatilesnordi
304         subq    $8, %rsp        // Keep the stack frame 16-byte aligned
305         
306         call    x64_do_irq
307         movl    need_resched, %eax
308         testl   %eax, %eax
309         jnz     x64_reschedule
310
311 x64_ret_irq:
312         addq    $8, %rsp
313         popvolatiles
314         iretq
315
316 x64_reschedule:
317         // The cli is to make sure interrupts don't get re-enabled in
318         // this thread context between the schedule and the ret from
319         // IRQ.
320         
321         cli     
322         call    schedule
323         jmp     x64_ret_irq
324         
325         .section ".irqs","x"
326         .global x64_irqs
327 x64_irqs:
328         .text
329
330         .macro  irq from,to
331 1:      push    %rdi
332         movq    $\from, %rdi
333         jmp     x64_irq
334         .section ".irqs","x"
335         .quad   1b
336         .text
337         .if     \to-\from
338         irq     (\from+1),\to
339         .endif
340         .endm
341         
342         .macro  irq16 from,to
343         irq     \from,(\from+15)
344         .if     \to-\from
345         irq16   (\from+16),\to
346         .endif
347         .endm
348
349         irq16   0,240
350
351         .global x64_new_thread
352 x64_new_thread:
353         xorq    %rax, %rax
354         xorq    %rbx, %rbx
355         xorq    %rcx, %rcx
356         xorq    %rdx, %rdx
357         xorq    %rbp, %rbp
358         xorq    %r8, %r8
359         xorq    %r9, %r9
360         xorq    %r10, %r10
361         xorq    %r11, %r11
362         xorq    %r12, %r12
363         xorq    %r13, %r13
364         xorq    %r14, %r14
365         xorq    %r15, %r15
366         
367         call    sched_new_thread
368         pop     %rsi
369         pop     %rdi
370         call    *%rsi
371         call    exit_thread
372         ud2a