]> git.buserror.net Git - polintos/scott/priv.git/blob - kernel/arch/x86/entry.S
Regs struct, int98/99
[polintos/scott/priv.git] / kernel / arch / x86 / entry.S
1 // arch/x86/entry.S - x86 entry points (booting and traps)
2 //
3 // This software is copyright (c) 2006 Scott Wood.
4 // 
5 // This software is provided 'as-is', without any express or implied warranty.
6 // In no event will the authors or contributors be held liable for any damages
7 // arising from the use of this software.
8 // 
9 // Permission is hereby granted to everyone, free of charge, to use, copy,
10 // modify, prepare derivative works of, publish, distribute, perform,
11 // sublicense, and/or sell copies of the Software, provided that the above
12 // copyright notice and disclaimer of warranty be included in all copies or
13 // substantial portions of this software.
14
15 #include <arch/addrs.h>
16
17         .org 0
18         .code32
19         .global _start
20 .align  4
21 multiboot_hdr:
22         .long   0x1badb002              // Multi-boot magic
23         
24         // Multi-boot flags:
25         //  bit 0: 4KiB-align all boot modules
26         //  bit 1: must include memory size and map
27         //  bit 2: must include video mode table
28         //  bit 16: load addresses in this header are valid
29         //          and should be used instead of the ELF header
30
31         .long   0x00010003
32
33         // checksum: -(magic + flags), update if flags change
34         .long   0xe4514ffb
35
36         .long   multiboot_hdr - KERNEL_START    // header_addr
37         .long   0x00200000                      // load_addr
38         .long   0                               // load_end_addr: load whole file
39         .long   bss_end - KERNEL_START          // bss_end_addr
40         .long   _start - KERNEL_START           // entry_addr
41
42 _start:
43         cld
44         lgdt    x86_gdtr_phys + 6 - KERNEL_START
45         ljmp    $0x10, $using_our_gdt - KERNEL_START
46
47 using_our_gdt:
48         movw    $0x08, %ax
49         movw    %ax, %ds
50         movw    %ax, %es
51         movw    %ax, %fs
52         movw    %ax, %gs
53         movw    %ax, %ss
54         
55         movl    %ebx, %esi              // Save the multiboot pointer somewhere
56                                         // it won't be clobbered by CPUID
57         
58         // This gives 512 bytes to Threads::Thread; if it gets larger
59         // this needs to be updated (as well as the code at high_vaddr).
60
61         movl    $x86_init_stack + 3584 - KERNEL_START, %esp
62
63         // Test for CPUID
64         pushfl
65         popl    %eax
66         movl    %eax, %ebx
67         xorl    $0x00200000, %eax
68         pushl   %eax
69         popfl
70         pushfl
71         popl    %eax
72         cmpl    %eax, %ebx
73         je      no_pentium
74
75         // Test for Page Size Extensions
76         xorl    %eax, %eax
77         cpuid
78         cmpl    $1, %eax
79         jb      no_pentium
80         
81         movl    $1, %eax
82         cpuid
83         btl     $3, %edx
84         jnc     no_pentium
85         
86         // enable PSE
87         movl    %cr4, %eax
88         btsl    $4, %eax
89         movl    %eax, %cr4
90         
91         // Load the initial page table
92         movl    $x86_init_ptbl_l2 - KERNEL_START, %eax
93         movl    %eax, %cr3
94         
95         // enable paging, kernel write-protect, 
96         // and internal floating point error handling
97         movl    %cr0, %eax
98         orl     $0x80010020, %eax
99         movl    %eax, %cr0
100
101         // Set up high page tables for 0x80000000 mapping,
102         
103         movl    $0x87, x86_init_ptbl_l2 + 0x800 - KERNEL_START
104         ljmp    $0x10, $paging_on - KERNEL_START
105
106 paging_on:      
107         lgdt    x86_gdtr + 6
108         movl    %esi, x86_boot_info_phys
109         
110         movl    $high_vaddr, %eax
111         jmp     *%eax
112
113 high_vaddr:
114         movl    $x86_init_stack + 3584, %esp
115         jmp     start_kernel
116
117 no_multiboot:
118         movl    $no_multiboot_str - KERNEL_START, %esi
119         jmp     do_print
120 no_pentium:
121         movl    $no_pentium_str - KERNEL_START, %esi
122 do_print:
123         movl    $0xb8000, %edi
124         
125         movb    (%esi), %al
126         xorl    %ecx, %ecx
127 1:      movb    %al, (%edi, %ecx, 2)
128         movb    $14, 1(%edi, %ecx, 2)   // It's not at the cursor, so use
129                                         // yellow to make it stand out.
130         incl    %ecx
131         movb    (%esi, %ecx), %al
132         testb   %al, %al
133         jnz     1b
134
135 2:      jmp     2b
136         
137 no_pentium_str:
138         .string "This kernel requires a Pentium-compatible CPU.  Either CPUID or PSE is missing."
139
140 no_multiboot_str:
141         .string "Unrecognized bootloader; a multiboot-compliant loader is required."
142
143         .macro  enterkernel, reg
144         pushl   %es
145         pushl   %ds
146         movl    $8, \reg
147         cld
148         movl    \reg, %ds
149         movl    \reg, %es
150         .endm
151         
152         .macro  exitkernel
153         popl    %ds
154         popl    %es
155         .endm
156         
157         .macro  pushvolatilesnoeax
158         pushl   %ecx
159         pushl   %edx
160         enterkernel %ecx
161         .endm
162         
163         .macro  pushvolatiles
164         pushl   %eax
165         pushvolatilesnoeax
166         .endm
167
168         .macro  popvolatiles
169         exitkernel
170         popl    %edx
171         popl    %ecx
172         popl    %eax
173         .endm
174
175         // Non-volatile registers must be pushed if the handler will
176         // need to access all of the interrupted code's registers,
177         // such as when producing an error dump.  Does not include
178         // edi, as that is usually swapped with the error code.
179         
180         .macro  pushall
181         pushl   %esi
182         pushl   %ebp
183         pushl   %ebx
184         pushl   %edx
185         pushl   %ecx
186         pushl   %eax
187         enterkernel %esi
188         .endm
189         
190         .macro  pushallnoerr
191         pushl   %edi
192         pushall
193         .endm
194
195         .macro  popall
196         exitkernel
197         popl    %eax
198         popl    %ecx
199         popl    %edx
200         popl    %ebx
201         popl    %ebp
202         popl    %esi
203         popl    %edi
204         .endm
205         
206         .global x86_diverr
207 x86_diverr:
208         pushallnoerr
209
210         pushl   %esp
211         call    x86_do_diverr
212         addl    $4, %esp
213
214         popall
215         iret
216
217         .global x86_debug
218 x86_debug:
219         pushallnoerr
220
221         pushl   %esp
222         call    x86_do_debug
223         addl    $4, %esp
224
225         popall
226         iret
227         
228         .global x86_breakpoint
229 x86_breakpoint:
230         pushallnoerr
231
232         pushl   %esp
233         call    x86_do_breakpoint
234         addl    $4, %esp
235
236         popall
237         iret
238
239         .global x86_invalid_insn
240 x86_invalid_insn:
241         pushallnoerr
242
243         pushl   %esp
244         call    x86_do_invalid_insn
245         addl    $4, %esp
246
247         popall
248         iret
249
250         .global x86_gpf
251 x86_gpf:
252         xchgl   %edi, (%esp)    // get error code
253         pushall
254         
255         movl    %esp, %eax
256         pushl   %edi
257         pushl   %eax
258         call    x86_do_gpf
259         addl    $8, %esp
260         
261         popall
262         iret
263
264         .global x86_page_fault
265 x86_page_fault:
266         xchgl   %edi, (%esp)    // get error code
267         pushall
268         
269         movl    %esp, %ecx
270         movl    %cr2, %eax
271         pushl   %edi
272         pushl   %eax
273         pushl   %ecx
274         call    x86_do_page_fault
275         addl    $12, %esp
276         
277         popall
278         iret
279
280         .global x86_int98_entry
281 x86_int98_entry:
282         pushl   $0
283         pushl   %eax
284         enterkernel %ecx
285
286         pushl   %esp
287         call    x86_invoke_method
288         addl    $4, %esp
289
290         exitkernel
291         popl    %eax
292         xorl    %ecx, %ecx
293         popl    %edx
294         xorl    %ebx, %ebx
295         xorl    %ebp, %ebp
296         xorl    %esi, %esi
297         xorl    %edi, %edi
298         iret
299
300         .global x86_int99_entry
301 x86_int99_entry:
302         pushl   %ecx
303         pushl   %eax
304         enterkernel %edx
305
306         pushl   %esp
307         call    x86_return_from_method
308         addl    $4, %esp
309
310         exitkernel
311         popl    %eax
312         popl    %ecx
313         xorl    %edx, %edx
314         xorl    %ebx, %ebx
315         xorl    %ebp, %ebp
316         xorl    %esi, %esi
317         xorl    %edi, %edi
318         iret
319
320         .global x86_irq
321 x86_irq:
322         pushvolatilesnoeax
323
324         pushl   %eax
325         call    x86_do_irq
326         addl    $4, %esp
327
328         movl    need_resched, %eax
329         testl   %eax, %eax
330         jnz     x86_reschedule
331
332 x86_ret_irq:
333         popvolatiles
334         iret
335
336 x86_reschedule:
337         // The cli is to make sure interrupts don't get re-enabled in
338         // this thread context between the schedule and the ret from
339         // IRQ.
340         
341         cli     
342         call    schedule
343         jmp     x86_ret_irq
344         
345         .section ".irqs","x"
346         .global x86_irqs
347 x86_irqs:
348         .text
349
350         .macro  irq from,to
351 1:      pushl   %eax
352         movl    $\from, %eax
353         jmp     x86_irq
354         .section ".irqs","x"
355         .long   1b
356         .text
357         .if     \to-\from
358         irq     (\from+1),\to
359         .endif
360         .endm
361         
362         .macro  irq16 from,to
363         irq     \from,(\from+15)
364         .if     \to-\from
365         irq16   (\from+16),\to
366         .endif
367         .endm
368
369         irq16   0,240
370
371         .global x86_new_thread
372 x86_new_thread:
373         xorl    %ebx, %ebx
374         xorl    %ecx, %ecx
375         xorl    %edx, %edx
376         xorl    %ebp, %ebp
377         xorl    %esi, %esi
378         xorl    %edi, %edi
379         
380         call    sched_new_thread
381         pop     %eax
382         call    *%eax
383         call    exit_thread
384         ud2a
385
386         .section ".roshared","x"
387         
388         // The vsyscall table must be the first thing in roshared (at
389         // vaddr 0x7fff0000).
390
391 #define PTR(x) (x - x86_syscall_ptr + 0x7fff0000)
392         
393         .global x86_syscall_ptr
394 x86_syscall_ptr:
395         .long   PTR(x86_shared_int98)
396
397         .global x86_sysret_ptr
398 x86_sysret_ptr:
399         .long   PTR(x86_shared_int99)
400
401 x86_shared_int98:
402         // FIXME: This must be unpreemptible by traps
403         pushl   %gs
404         pushl   %fs
405         pushl   %ebp
406         pushl   %edi
407         pushl   %esi
408         pushl   %ebx
409         int     $0x98
410         popl    %ebx
411         popl    %esi
412         popl    %edi
413         popl    %ebp
414         popl    %fs
415         popl    %gs
416         ret
417
418 x86_shared_int99:
419         int     $0x99
420         ret
421
422         .section ".rwshared",""
423
424         // Userspace must set this to an appropriate entry point
425         // prior to registering objects with the kernel.  It should
426         // not be modified while an object is registered (the kernel
427         // won't mind, but there's no mechanism to wait until no more
428         // upcalls to the old entry point are in progress).
429         .global x86_upcall_entry
430 x86_upcall_entry:
431         .long   0