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