coverity appeasement
[minix.git] / kernel / arch / i386 / mpx.S
blob44af169d059dad457d922e4d8a788a7d2120aa4d
1 /* This file is part of the lowest layer of the MINIX kernel.  (The other part 
2  * is "proc.c".)  The lowest layer does process switching and message handling. 
3  * Furthermore it contains the assembler startup code for Minix and the 32-bit 
4  * interrupt handlers.  It cooperates with the code in "start.c" to set up a  
5  * good environment for main(). 
6  *
7  * Kernel is entered either because of kernel-calls, ipc-calls, interrupts or
8  * exceptions. TSS is set so that the kernel stack is loaded. The user context is
9  * saved to the proc table and the handler of the event is called. Once the
10  * handler is done, switch_to_user() function is called to pick a new process,
11  * finish what needs to be done for the next process to run, sets its context
12  * and switch to userspace.
13  *
14  * For communication with the boot monitor at startup time some constant 
15  * data are compiled into the beginning of the text segment. This facilitates  
16  * reading the data at the start of the boot process, since only the first 
17  * sector of the file needs to be read. 
18  *
19  * Some data storage is also allocated at the end of this file. This data  
20  * will be at the start of the data segment of the kernel and will be read 
21  * and modified by the boot monitor before the kernel starts.
22  */
24 #include "kernel/kernel.h" /* configures the kernel */
26 /* sections */
28 #include <machine/vm.h>
29 #include "../../kernel.h"
30 #include <minix/config.h>
31 #include <minix/const.h>
32 #include <minix/com.h>
33 #include <machine/asm.h>
34 #include <machine/interrupt.h>
35 #include "archconst.h"
36 #include "kernel/const.h"
37 #include "kernel/proc.h"
38 #include "sconst.h"
39 #include <machine/multiboot.h>
41 #include "arch_proto.h" /* K_STACK_SIZE */
43 #ifdef CONFIG_SMP
44 #include "kernel/smp.h"
45 #endif
47 /* Selected 386 tss offsets. */
48 #define TSS3_S_SP0      4
50 IMPORT(copr_not_available_handler)
51 IMPORT(params_size)
52 IMPORT(params_offset)
53 IMPORT(switch_to_user)
54 IMPORT(multiboot_init)
56 .text
57 /*===========================================================================*/
58 /*                              interrupt handlers                           */
59 /*              interrupt handlers for 386 32-bit protected mode             */
60 /*===========================================================================*/
62 #define PIC_IRQ_HANDLER(irq)    \
63         push    $irq                                                            ;\
64         call    _C_LABEL(irq_handle)    /* intr_handle(irq_handlers[irq]) */    ;\
65         add     $4, %esp                                                        ;
67 /*===========================================================================*/
68 /*                              hwint00 - 07                                 */
69 /*===========================================================================*/
70 /* Note this is a macro, it just looks like a subroutine. */
72 #define hwint_master(irq) \
73         TEST_INT_IN_KERNEL(4, 0f)                                       ;\
74                                                                         \
75         SAVE_PROCESS_CTX(0)                                             ;\
76         push    %ebp                                                    ;\
77         movl    $0, %ebp        /* for stack trace */                   ;\
78         call    _C_LABEL(context_stop)                                  ;\
79         add     $4, %esp                                                ;\
80         PIC_IRQ_HANDLER(irq)                                            ;\
81         movb    $END_OF_INT, %al                                        ;\
82         outb    $INT_CTL        /* reenable interrupts in master pic */ ;\
83         jmp     _C_LABEL(switch_to_user)                                ;\
84                                                                         \
85 0:                                                                      \
86         pusha                                                           ;\
87         call    _C_LABEL(context_stop_idle)                             ;\
88         PIC_IRQ_HANDLER(irq)                                            ;\
89         movb    $END_OF_INT, %al                                        ;\
90         outb    $INT_CTL        /* reenable interrupts in master pic */ ;\
91         CLEAR_IF(10*4(%esp))                                            ;\
92         popa                                                            ;\
93         iret                                                            ;
95 /* Each of these entry points is an expansion of the hwint_master macro */
96 ENTRY(hwint00)
97 /* Interrupt routine for irq 0 (the clock). */
98         hwint_master(0)
100 ENTRY(hwint01)
101 /* Interrupt routine for irq 1 (keyboard) */
102         hwint_master(1)
104 ENTRY(hwint02)
105 /* Interrupt routine for irq 2 (cascade!) */
106         hwint_master(2)
108 ENTRY(hwint03)
109 /* Interrupt routine for irq 3 (second serial) */
110         hwint_master(3)
112 ENTRY(hwint04)
113 /* Interrupt routine for irq 4 (first serial) */
114         hwint_master(4)
116 ENTRY(hwint05)
117 /* Interrupt routine for irq 5 (XT winchester) */
118         hwint_master(5)
120 ENTRY(hwint06)
121 /* Interrupt routine for irq 6 (floppy) */
122         hwint_master(6)
124 ENTRY(hwint07)
125 /* Interrupt routine for irq 7 (printer) */
126         hwint_master(7)
128 /*===========================================================================*/
129 /*                              hwint08 - 15                                 */
130 /*===========================================================================*/
131 /* Note this is a macro, it just looks like a subroutine. */
132 #define hwint_slave(irq)        \
133         TEST_INT_IN_KERNEL(4, 0f)                                       ;\
134                                                                         \
135         SAVE_PROCESS_CTX(0)                                             ;\
136         push    %ebp                                                    ;\
137         movl    $0, %ebp        /* for stack trace */                   ;\
138         call    _C_LABEL(context_stop)                                  ;\
139         add     $4, %esp                                                ;\
140         PIC_IRQ_HANDLER(irq)                                            ;\
141         movb    $END_OF_INT, %al                                        ;\
142         outb    $INT_CTL        /* reenable interrupts in master pic */ ;\
143         outb    $INT2_CTL       /* reenable slave 8259            */    ;\
144         jmp     _C_LABEL(switch_to_user)                                ;\
145                                                                         \
146 0:                                                                      \
147         pusha                                                           ;\
148         call    _C_LABEL(context_stop_idle)                             ;\
149         PIC_IRQ_HANDLER(irq)                                            ;\
150         movb    $END_OF_INT, %al                                        ;\
151         outb    $INT_CTL        /* reenable interrupts in master pic */ ;\
152         outb    $INT2_CTL       /* reenable slave 8259            */    ;\
153         CLEAR_IF(10*4(%esp))                                            ;\
154         popa                                                            ;\
155         iret                                                            ;
157 /* Each of these entry points is an expansion of the hwint_slave macro */
158 ENTRY(hwint08)
159 /* Interrupt routine for irq 8 (realtime clock) */
160         hwint_slave(8)
162 ENTRY(hwint09)
163 /* Interrupt routine for irq 9 (irq 2 redirected) */
164         hwint_slave(9)
166 ENTRY(hwint10)
167 /* Interrupt routine for irq 10 */
168         hwint_slave(10)
170 ENTRY(hwint11)
171 /* Interrupt routine for irq 11 */
172         hwint_slave(11)
174 ENTRY(hwint12)
175 /* Interrupt routine for irq 12 */
176         hwint_slave(12)
178 ENTRY(hwint13)
179 /* Interrupt routine for irq 13 (FPU exception) */
180         hwint_slave(13)
182 ENTRY(hwint14)
183 /* Interrupt routine for irq 14 (AT winchester) */
184         hwint_slave(14)
186 ENTRY(hwint15)
187 /* Interrupt routine for irq 15 */
188         hwint_slave(15)
191  * IPC is only from a process to kernel
192  */
193 ENTRY(ipc_entry)
195         SAVE_PROCESS_CTX(0)
197         /* save the pointer to the current process */
198         push    %ebp
200         /*
201          * pass the syscall arguments from userspace to the handler.
202          * SAVE_PROCESS_CTX() does not clobber these registers, they are still
203          * set as the userspace have set them
204          */
205         push    %ebx
206         push    %eax
207         push    %ecx
209         /* stop user process cycles */
210         push    %ebp
211         /* for stack trace */
212         movl    $0, %ebp
213         call    _C_LABEL(context_stop)
214         add     $4, %esp
216         call    _C_LABEL(do_ipc)
218         /* restore the current process pointer and save the return value */
219         add     $3 * 4, %esp
220         pop     %esi
221         mov     %eax, AXREG(%esi)
223         jmp     _C_LABEL(switch_to_user)
227  * kernel call is only from a process to kernel
228  */
229 ENTRY(kernel_call_entry)
231         SAVE_PROCESS_CTX(0)
233         /* save the pointer to the current process */
234         push    %ebp
236         /*
237          * pass the syscall arguments from userspace to the handler.
238          * SAVE_PROCESS_CTX() does not clobber these registers, they are still
239          * set as the userspace have set them
240          */
241         push    %eax
243         /* stop user process cycles */
244         push    %ebp
245         /* for stack trace */
246         movl    $0, %ebp
247         call    _C_LABEL(context_stop)
248         add     $4, %esp
250         call    _C_LABEL(kernel_call)
252         /* restore the current process pointer and save the return value */
253         add     $8, %esp
255         jmp     _C_LABEL(switch_to_user)
258 .balign 16
260  * called by the exception interrupt vectors. If the exception does not push
261  * errorcode, we assume that the vector handler pushed 0 instead. Next pushed
262  * thing is the vector number. From this point on we can continue as if every
263  * exception pushes an error code
264  */
265 exception_entry:
266         /*
267          * check if it is a nested trap by comparing the saved code segment
268          * descriptor with the kernel CS first
269          */
270         TEST_INT_IN_KERNEL(12, exception_entry_nested)
272 exception_entry_from_user:
273         SAVE_PROCESS_CTX(8)
275         /* stop user process cycles */
276         push    %ebp
277         /* for stack trace clear %ebp */
278         movl    $0, %ebp
279         call    _C_LABEL(context_stop)
280         add     $4, %esp
282         /*
283          * push a pointer to the interrupt state pushed by the cpu and the
284          * vector number pushed by the vector handler just before calling
285          * exception_entry and call the exception handler.
286          */
287         push    %esp
288         push    $0      /* it's not a nested exception */
289         call    _C_LABEL(exception_handler)
291         jmp     _C_LABEL(switch_to_user)
293 exception_entry_nested:
295         pusha
296         mov     %esp, %eax
297         add     $(8 * 4), %eax
298         push    %eax
299         pushl   $1                      /* it's a nested exception */
300         call    _C_LABEL(exception_handler)
301         add     $8, %esp
302         popa
304         /* clear the error code and the exception number */
305         add     $8, %esp
306         /* resume execution at the point of exception */
307         iret
309 /*===========================================================================*/
310 /*                              restart                                      */
311 /*===========================================================================*/
312 ENTRY(restore_user_context)
313         mov     4(%esp), %ebp   /* will assume P_STACKBASE == 0 */
315         /* reconstruct the stack for iret */
316         push    $USER_DS_SELECTOR       /* ss */
317         movl    SPREG(%ebp), %eax
318         push    %eax
319         movl    PSWREG(%ebp), %eax
320         push    %eax
321         push    $USER_CS_SELECTOR       /* cs */
322         movl    PCREG(%ebp), %eax
323         push    %eax
325         /* Restore segments as the user should see them. */
326         movw    $USER_DS_SELECTOR, %si
327         movw    %si, %ds
328         movw    %si, %es
329         movw    %si, %fs
330         movw    %si, %gs
332         /* Same for general-purpose registers. */
333         RESTORE_GP_REGS(%ebp)
335         movl    BPREG(%ebp), %ebp
337         iret    /* continue process */
339 /*===========================================================================*/
340 /*                              exception handlers                           */
341 /*===========================================================================*/
343 #define EXCEPTION_ERR_CODE(vector)      \
344         push    $vector                 ;\
345         jmp     exception_entry
347 #define EXCEPTION_NO_ERR_CODE(vector)   \
348         pushl   $0              ;\
349         EXCEPTION_ERR_CODE(vector)
351 LABEL(divide_error)
352         EXCEPTION_NO_ERR_CODE(DIVIDE_VECTOR)
354 LABEL(single_step_exception)
355         EXCEPTION_NO_ERR_CODE(DEBUG_VECTOR)
357 LABEL(nmi)
358 #ifndef USE_WATCHDOG
359         EXCEPTION_NO_ERR_CODE(NMI_VECTOR)
360 #else
361         /*
362          * We have to be very careful as this interrupt can occur anytime. On
363          * the other hand, if it interrupts a user process, we will resume the
364          * same process which makes things a little simpler. We know that we are
365          * already on kernel stack whenever it happened and we can be
366          * conservative and save everything as we don't need to be extremely
367          * efficient as the interrupt is infrequent and some overhead is already
368          * expected.
369          */
371         /*
372          * save the important registers. We don't save %cs and %ss and they are
373          * saved and restored by CPU
374          */
375         pushw   %ds
376         pushw   %es
377         pushw   %fs
378         pushw   %gs
379         pusha
381         /*
382          * We cannot be sure about the state of the kernel segment register,
383          * however, we always set %ds and %es to the same as %ss
384          */
385         mov     %ss, %si
386         mov     %si, %ds
387         mov     %si, %es
389         push    %esp
390         call    _C_LABEL(nmi_watchdog_handler)
391         add     $4, %esp
393         /* restore all the important registers as they were before the trap */
394         popa
395         popw    %gs
396         popw    %fs
397         popw    %es
398         popw    %ds
400         iret
401 #endif
403 LABEL(breakpoint_exception)
404         EXCEPTION_NO_ERR_CODE(BREAKPOINT_VECTOR)
406 LABEL(overflow)
407         EXCEPTION_NO_ERR_CODE(OVERFLOW_VECTOR)
409 LABEL(bounds_check)
410         EXCEPTION_NO_ERR_CODE(BOUNDS_VECTOR)
412 LABEL(inval_opcode)
413         EXCEPTION_NO_ERR_CODE(INVAL_OP_VECTOR)
415 LABEL(copr_not_available)
416         TEST_INT_IN_KERNEL(4, copr_not_available_in_kernel)
417         cld                     /* set direction flag to a known value */
418         SAVE_PROCESS_CTX(0)
419         /* stop user process cycles */
420         push    %ebp
421         mov     $0, %ebp
422         call    _C_LABEL(context_stop)
423         call    _C_LABEL(copr_not_available_handler)
424         /* reached upon failure only */
425         jmp     _C_LABEL(switch_to_user)
427 copr_not_available_in_kernel:
428         pushl   $0
429         pushl   $COPROC_NOT_VECTOR
430         jmp     exception_entry_nested
432 LABEL(double_fault)
433         EXCEPTION_ERR_CODE(DOUBLE_FAULT_VECTOR)
435 LABEL(copr_seg_overrun)
436         EXCEPTION_NO_ERR_CODE(COPROC_SEG_VECTOR)
438 LABEL(inval_tss)
439         EXCEPTION_ERR_CODE(INVAL_TSS_VECTOR)
441 LABEL(segment_not_present)
442         EXCEPTION_ERR_CODE(SEG_NOT_VECTOR)
444 LABEL(stack_exception)
445         EXCEPTION_ERR_CODE(STACK_FAULT_VECTOR)
447 LABEL(general_protection)
448         EXCEPTION_ERR_CODE(PROTECTION_VECTOR)
450 LABEL(page_fault)
451         EXCEPTION_ERR_CODE(PAGE_FAULT_VECTOR)
453 LABEL(copr_error)
454         EXCEPTION_NO_ERR_CODE(COPROC_ERR_VECTOR)
456 LABEL(alignment_check)
457         EXCEPTION_NO_ERR_CODE(ALIGNMENT_CHECK_VECTOR)
459 LABEL(machine_check)
460         EXCEPTION_NO_ERR_CODE(MACHINE_CHECK_VECTOR)
462 LABEL(simd_exception)
463         EXCEPTION_NO_ERR_CODE(SIMD_EXCEPTION_VECTOR)
465 /*===========================================================================*/
466 /*                              reload_cr3                                   */
467 /*===========================================================================*/
468 /* PUBLIC void reload_cr3(void); */
469 ENTRY(reload_cr3)
470         push    %ebp
471         mov     %esp, %ebp
472         mov     %cr3, %eax
473         mov     %eax, %cr3
474         pop     %ebp
475         ret
477 #ifdef CONFIG_SMP
478 ENTRY(startup_ap_32)
479         /*
480          * we are in protected mode now, %cs is correct and we need to set the
481          * data descriptors before we can touch anything
482          *
483          * first load the regular, highly mapped idt, gdt
484          */
486         /*
487          * use the boot stack for now. The running CPUs are already using their
488          * own stack, the rest is still waiting to be booted
489          */
490         movw    $KERN_DS_SELECTOR, %ax
491         mov     %ax, %ds
492         mov     %ax, %ss
493         mov     $_C_LABEL(k_boot_stktop) - 4, %esp
495         /* load the highly mapped idt, gdt, per-cpu tss */
496         call    _C_LABEL(prot_load_selectors)
498         jmp     _C_LABEL(smp_ap_boot)
499         hlt
500 #endif
502 /*===========================================================================*/
503 /*                              data                                         */
504 /*===========================================================================*/
506 .data
507 .short  0x526F  /* this must be the first data entry (magic #) */
508 .bss
509 k_initial_stack:
510 .space  K_STACK_SIZE
511 LABEL(__k_unpaged_k_initial_stktop)
514  * the kernel stack
515  */
516 k_boot_stack:
517 .space  K_STACK_SIZE    /* kernel stack */ /* FIXME use macro here */
518 LABEL(k_boot_stktop)    /* top of kernel stack */
520 .balign K_STACK_SIZE
521 LABEL(k_stacks_start)
523 /* two pages for each stack, one for data, other as a sandbox */
524 .space  2 * (K_STACK_SIZE * CONFIG_MAX_CPUS)
526 LABEL(k_stacks_end)
528 /* top of kernel stack */