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