1433d6423SLionel Sambuc/* This file is part of the lowest layer of the MINIX kernel. (The other part 2433d6423SLionel Sambuc * is "proc.c".) The lowest layer does process switching and message handling. 3433d6423SLionel Sambuc * Furthermore it contains the assembler startup code for Minix and the 32-bit 4433d6423SLionel Sambuc * interrupt handlers. It cooperates with the code in "start.c" to set up a 5433d6423SLionel Sambuc * good environment for main(). 6433d6423SLionel Sambuc * 7433d6423SLionel Sambuc * Kernel is entered either because of kernel-calls, ipc-calls, interrupts or 8433d6423SLionel Sambuc * exceptions. TSS is set so that the kernel stack is loaded. The user context is 9433d6423SLionel Sambuc * saved to the proc table and the handler of the event is called. Once the 10433d6423SLionel Sambuc * handler is done, switch_to_user() function is called to pick a new process, 11433d6423SLionel Sambuc * finish what needs to be done for the next process to run, sets its context 12433d6423SLionel Sambuc * and switch to userspace. 13433d6423SLionel Sambuc * 14433d6423SLionel Sambuc * For communication with the boot monitor at startup time some constant 15433d6423SLionel Sambuc * data are compiled into the beginning of the text segment. This facilitates 16433d6423SLionel Sambuc * reading the data at the start of the boot process, since only the first 17433d6423SLionel Sambuc * sector of the file needs to be read. 18433d6423SLionel Sambuc * 19433d6423SLionel Sambuc * Some data storage is also allocated at the end of this file. This data 20433d6423SLionel Sambuc * will be at the start of the data segment of the kernel and will be read 21433d6423SLionel Sambuc * and modified by the boot monitor before the kernel starts. 22433d6423SLionel Sambuc */ 23433d6423SLionel Sambuc 24433d6423SLionel Sambuc#include "kernel/kernel.h" /* configures the kernel */ 25433d6423SLionel Sambuc 26433d6423SLionel Sambuc/* sections */ 27433d6423SLionel Sambuc 28433d6423SLionel Sambuc#include <machine/vm.h> 29433d6423SLionel Sambuc#include "kernel/kernel.h" 30433d6423SLionel Sambuc#include <minix/config.h> 31433d6423SLionel Sambuc#include <minix/const.h> 32433d6423SLionel Sambuc#include <minix/ipcconst.h> 33433d6423SLionel Sambuc#include <minix/com.h> 34433d6423SLionel Sambuc#include <machine/asm.h> 35433d6423SLionel Sambuc#include <machine/interrupt.h> 36433d6423SLionel Sambuc#include "archconst.h" 37433d6423SLionel Sambuc#include "kernel/const.h" 38433d6423SLionel Sambuc#include "kernel/proc.h" 39433d6423SLionel Sambuc#include "sconst.h" 40433d6423SLionel Sambuc#include <machine/multiboot.h> 41433d6423SLionel Sambuc 42433d6423SLionel Sambuc#include "arch_proto.h" /* K_STACK_SIZE */ 43433d6423SLionel Sambuc 44433d6423SLionel Sambuc#ifdef CONFIG_SMP 45433d6423SLionel Sambuc#include "kernel/smp.h" 46433d6423SLionel Sambuc#endif 47433d6423SLionel Sambuc 48433d6423SLionel Sambuc/* Selected 386 tss offsets. */ 49433d6423SLionel Sambuc#define TSS3_S_SP0 4 50433d6423SLionel Sambuc 51433d6423SLionel SambucIMPORT(usermapped_offset) 52433d6423SLionel SambucIMPORT(copr_not_available_handler) 53433d6423SLionel SambucIMPORT(params_size) 54433d6423SLionel SambucIMPORT(params_offset) 55433d6423SLionel SambucIMPORT(switch_to_user) 56433d6423SLionel SambucIMPORT(multiboot_init) 57433d6423SLionel Sambuc 58433d6423SLionel Sambuc.text 59433d6423SLionel Sambuc/*===========================================================================*/ 60433d6423SLionel Sambuc/* interrupt handlers */ 61433d6423SLionel Sambuc/* interrupt handlers for 386 32-bit protected mode */ 62433d6423SLionel Sambuc/*===========================================================================*/ 63433d6423SLionel Sambuc 64433d6423SLionel Sambuc#define PIC_IRQ_HANDLER(irq) \ 65433d6423SLionel Sambuc push $irq ;\ 66433d6423SLionel Sambuc call _C_LABEL(irq_handle) /* intr_handle(irq_handlers[irq]) */ ;\ 67433d6423SLionel Sambuc add $4, %esp ; 68433d6423SLionel Sambuc 69433d6423SLionel Sambuc/*===========================================================================*/ 70433d6423SLionel Sambuc/* hwint00 - 07 */ 71433d6423SLionel Sambuc/*===========================================================================*/ 72433d6423SLionel Sambuc/* Note this is a macro, it just looks like a subroutine. */ 73433d6423SLionel Sambuc 74433d6423SLionel Sambuc#define hwint_master(irq) \ 75433d6423SLionel Sambuc TEST_INT_IN_KERNEL(4, 0f) ;\ 76433d6423SLionel Sambuc \ 77433d6423SLionel Sambuc SAVE_PROCESS_CTX(0, KTS_INT_HARD) ;\ 78433d6423SLionel Sambuc push %ebp ;\ 79433d6423SLionel Sambuc movl $0, %ebp /* for stack trace */ ;\ 80433d6423SLionel Sambuc call _C_LABEL(context_stop) ;\ 81433d6423SLionel Sambuc add $4, %esp ;\ 82433d6423SLionel Sambuc PIC_IRQ_HANDLER(irq) ;\ 83433d6423SLionel Sambuc movb $END_OF_INT, %al ;\ 84433d6423SLionel Sambuc outb $INT_CTL /* reenable interrupts in master pic */ ;\ 85433d6423SLionel Sambuc jmp _C_LABEL(switch_to_user) ;\ 86433d6423SLionel Sambuc \ 87433d6423SLionel Sambuc0: \ 88433d6423SLionel Sambuc pusha ;\ 89433d6423SLionel Sambuc call _C_LABEL(context_stop_idle) ;\ 90433d6423SLionel Sambuc PIC_IRQ_HANDLER(irq) ;\ 91433d6423SLionel Sambuc movb $END_OF_INT, %al ;\ 92433d6423SLionel Sambuc outb $INT_CTL /* reenable interrupts in master pic */ ;\ 93433d6423SLionel Sambuc CLEAR_IF(10*4(%esp)) ;\ 94433d6423SLionel Sambuc popa ;\ 95433d6423SLionel Sambuc iret ; 96433d6423SLionel Sambuc 97433d6423SLionel Sambuc/* Each of these entry points is an expansion of the hwint_master macro */ 98433d6423SLionel SambucENTRY(hwint00) 99433d6423SLionel Sambuc/* Interrupt routine for irq 0 (the clock). */ 100433d6423SLionel Sambuc hwint_master(0) 101433d6423SLionel Sambuc 102433d6423SLionel SambucENTRY(hwint01) 103433d6423SLionel Sambuc/* Interrupt routine for irq 1 (keyboard) */ 104433d6423SLionel Sambuc hwint_master(1) 105433d6423SLionel Sambuc 106433d6423SLionel SambucENTRY(hwint02) 107433d6423SLionel Sambuc/* Interrupt routine for irq 2 (cascade!) */ 108433d6423SLionel Sambuc hwint_master(2) 109433d6423SLionel Sambuc 110433d6423SLionel SambucENTRY(hwint03) 111433d6423SLionel Sambuc/* Interrupt routine for irq 3 (second serial) */ 112433d6423SLionel Sambuc hwint_master(3) 113433d6423SLionel Sambuc 114433d6423SLionel SambucENTRY(hwint04) 115433d6423SLionel Sambuc/* Interrupt routine for irq 4 (first serial) */ 116433d6423SLionel Sambuc hwint_master(4) 117433d6423SLionel Sambuc 118433d6423SLionel SambucENTRY(hwint05) 119433d6423SLionel Sambuc/* Interrupt routine for irq 5 (XT winchester) */ 120433d6423SLionel Sambuc hwint_master(5) 121433d6423SLionel Sambuc 122433d6423SLionel SambucENTRY(hwint06) 123433d6423SLionel Sambuc/* Interrupt routine for irq 6 (floppy) */ 124433d6423SLionel Sambuc hwint_master(6) 125433d6423SLionel Sambuc 126433d6423SLionel SambucENTRY(hwint07) 127433d6423SLionel Sambuc/* Interrupt routine for irq 7 (printer) */ 128433d6423SLionel Sambuc hwint_master(7) 129433d6423SLionel Sambuc 130433d6423SLionel Sambuc/*===========================================================================*/ 131433d6423SLionel Sambuc/* hwint08 - 15 */ 132433d6423SLionel Sambuc/*===========================================================================*/ 133433d6423SLionel Sambuc/* Note this is a macro, it just looks like a subroutine. */ 134433d6423SLionel Sambuc#define hwint_slave(irq) \ 135433d6423SLionel Sambuc TEST_INT_IN_KERNEL(4, 0f) ;\ 136433d6423SLionel Sambuc \ 137433d6423SLionel Sambuc SAVE_PROCESS_CTX(0, KTS_INT_HARD) ;\ 138433d6423SLionel Sambuc push %ebp ;\ 139433d6423SLionel Sambuc movl $0, %ebp /* for stack trace */ ;\ 140433d6423SLionel Sambuc call _C_LABEL(context_stop) ;\ 141433d6423SLionel Sambuc add $4, %esp ;\ 142433d6423SLionel Sambuc PIC_IRQ_HANDLER(irq) ;\ 143433d6423SLionel Sambuc movb $END_OF_INT, %al ;\ 144433d6423SLionel Sambuc outb $INT_CTL /* reenable interrupts in master pic */ ;\ 145433d6423SLionel Sambuc outb $INT2_CTL /* reenable slave 8259 */ ;\ 146433d6423SLionel Sambuc jmp _C_LABEL(switch_to_user) ;\ 147433d6423SLionel Sambuc \ 148433d6423SLionel Sambuc0: \ 149433d6423SLionel Sambuc pusha ;\ 150433d6423SLionel Sambuc call _C_LABEL(context_stop_idle) ;\ 151433d6423SLionel Sambuc PIC_IRQ_HANDLER(irq) ;\ 152433d6423SLionel Sambuc movb $END_OF_INT, %al ;\ 153433d6423SLionel Sambuc outb $INT_CTL /* reenable interrupts in master pic */ ;\ 154433d6423SLionel Sambuc outb $INT2_CTL /* reenable slave 8259 */ ;\ 155433d6423SLionel Sambuc CLEAR_IF(10*4(%esp)) ;\ 156433d6423SLionel Sambuc popa ;\ 157433d6423SLionel Sambuc iret ; 158433d6423SLionel Sambuc 159433d6423SLionel Sambuc/* Each of these entry points is an expansion of the hwint_slave macro */ 160433d6423SLionel SambucENTRY(hwint08) 161433d6423SLionel Sambuc/* Interrupt routine for irq 8 (realtime clock) */ 162433d6423SLionel Sambuc hwint_slave(8) 163433d6423SLionel Sambuc 164433d6423SLionel SambucENTRY(hwint09) 165433d6423SLionel Sambuc/* Interrupt routine for irq 9 (irq 2 redirected) */ 166433d6423SLionel Sambuc hwint_slave(9) 167433d6423SLionel Sambuc 168433d6423SLionel SambucENTRY(hwint10) 169433d6423SLionel Sambuc/* Interrupt routine for irq 10 */ 170433d6423SLionel Sambuc hwint_slave(10) 171433d6423SLionel Sambuc 172433d6423SLionel SambucENTRY(hwint11) 173433d6423SLionel Sambuc/* Interrupt routine for irq 11 */ 174433d6423SLionel Sambuc hwint_slave(11) 175433d6423SLionel Sambuc 176433d6423SLionel SambucENTRY(hwint12) 177433d6423SLionel Sambuc/* Interrupt routine for irq 12 */ 178433d6423SLionel Sambuc hwint_slave(12) 179433d6423SLionel Sambuc 180433d6423SLionel SambucENTRY(hwint13) 181433d6423SLionel Sambuc/* Interrupt routine for irq 13 (FPU exception) */ 182433d6423SLionel Sambuc hwint_slave(13) 183433d6423SLionel Sambuc 184433d6423SLionel SambucENTRY(hwint14) 185433d6423SLionel Sambuc/* Interrupt routine for irq 14 (AT winchester) */ 186433d6423SLionel Sambuc hwint_slave(14) 187433d6423SLionel Sambuc 188433d6423SLionel SambucENTRY(hwint15) 189433d6423SLionel Sambuc/* Interrupt routine for irq 15 */ 190433d6423SLionel Sambuc hwint_slave(15) 191433d6423SLionel Sambuc 192433d6423SLionel Sambuc/* differences with sysenter: 193433d6423SLionel Sambuc * - we have to find our own per-cpu stack (i.e. post-SYSCALL 194433d6423SLionel Sambuc * %esp is not configured) 195433d6423SLionel Sambuc * - we have to save the post-SYSRET %eip, provided by the cpu 196433d6423SLionel Sambuc * in %ecx 197433d6423SLionel Sambuc * - the system call parameters are passed in %ecx, so we userland 198433d6423SLionel Sambuc * code that executes SYSCALL copies %ecx to %edx. So the roles 199433d6423SLionel Sambuc * of %ecx and %edx are reversed 200433d6423SLionel Sambuc * - we can use %esi as a scratch register 201433d6423SLionel Sambuc */ 202433d6423SLionel Sambuc#define ipc_entry_syscall_percpu(cpu) ;\ 203433d6423SLionel SambucENTRY(ipc_entry_syscall_cpu ## cpu) ;\ 204433d6423SLionel Sambuc xchg %ecx, %edx ;\ 205433d6423SLionel Sambuc mov k_percpu_stacks+4*cpu, %esi ;\ 206433d6423SLionel Sambuc mov (%esi), %ebp ;\ 207433d6423SLionel Sambuc movl $KTS_SYSCALL, P_KERN_TRAP_STYLE(%ebp) ;\ 208433d6423SLionel Sambuc xchg %esp, %esi ;\ 209433d6423SLionel Sambuc jmp syscall_sysenter_common 210433d6423SLionel Sambuc 211433d6423SLionel Sambucipc_entry_syscall_percpu(0) 212433d6423SLionel Sambucipc_entry_syscall_percpu(1) 213433d6423SLionel Sambucipc_entry_syscall_percpu(2) 214433d6423SLionel Sambucipc_entry_syscall_percpu(3) 215433d6423SLionel Sambucipc_entry_syscall_percpu(4) 216433d6423SLionel Sambucipc_entry_syscall_percpu(5) 217433d6423SLionel Sambucipc_entry_syscall_percpu(6) 218433d6423SLionel Sambucipc_entry_syscall_percpu(7) 219433d6423SLionel Sambuc 220433d6423SLionel SambucENTRY(ipc_entry_sysenter) 221433d6423SLionel Sambuc /* SYSENTER simply sets kernel segments, EIP to here, and ESP 222433d6423SLionel Sambuc * to tss->sp0 (through MSR). so no automatic context saving is done. 223433d6423SLionel Sambuc * interrupts are disabled. 224433d6423SLionel Sambuc * 225433d6423SLionel Sambuc * register usage: 226433d6423SLionel Sambuc * edi: call type (IPCVEC, KERVEC) 227433d6423SLionel Sambuc * ebx, eax, ecx: syscall params, set by userland 228433d6423SLionel Sambuc * esi, edx: esp, eip to restore, set by userland 229433d6423SLionel Sambuc * 230433d6423SLionel Sambuc * no state is automatically saved; userland does all of that. 231433d6423SLionel Sambuc */ 232433d6423SLionel Sambuc mov (%esp), %ebp /* get proc saved by arch_finish_switch_to_user */ 233433d6423SLionel Sambuc 234433d6423SLionel Sambuc /* inform kernel we entered by sysenter and should 235433d6423SLionel Sambuc * therefore exit through restore_user_context_sysenter 236433d6423SLionel Sambuc */ 237433d6423SLionel Sambuc movl $KTS_SYSENTER, P_KERN_TRAP_STYLE(%ebp) 238433d6423SLionel Sambuc add usermapped_offset, %edx /* compensate for mapping difference */ 239433d6423SLionel Sambuc 240433d6423SLionel Sambucsyscall_sysenter_common: 241433d6423SLionel Sambuc mov %esi, SPREG(%ebp) /* esi is return esp */ 242433d6423SLionel Sambuc mov %edx, PCREG(%ebp) /* edx is return eip */ 243433d6423SLionel Sambuc 244433d6423SLionel Sambuc /* save PSW */ 245433d6423SLionel Sambuc pushf 246433d6423SLionel Sambuc pop %edx 247433d6423SLionel Sambuc mov %edx, PSWREG(%ebp) 248433d6423SLionel Sambuc 249433d6423SLionel Sambuc /* check for call type; do_ipc? */ 250433d6423SLionel Sambuc cmp $IPCVEC_UM, %edi 251433d6423SLionel Sambuc jz ipc_entry_common 252433d6423SLionel Sambuc 253433d6423SLionel Sambuc /* check for kernel trap */ 254433d6423SLionel Sambuc cmp $KERVEC_UM, %edi 255433d6423SLionel Sambuc jz kernel_call_entry_common 256433d6423SLionel Sambuc 257433d6423SLionel Sambuc /* unrecognized call number; restore user with error */ 258433d6423SLionel Sambuc movl $-1, AXREG(%ebp) 259433d6423SLionel Sambuc push %ebp 260433d6423SLionel Sambuc call restore_user_context /* restore_user_context(%ebp); */ 261433d6423SLionel Sambuc 262433d6423SLionel Sambuc/* 263433d6423SLionel Sambuc * IPC is only from a process to kernel 264433d6423SLionel Sambuc */ 265433d6423SLionel SambucENTRY(ipc_entry_softint_orig) 266433d6423SLionel Sambuc SAVE_PROCESS_CTX(0, KTS_INT_ORIG) 267433d6423SLionel Sambuc jmp ipc_entry_common 268433d6423SLionel Sambuc 269433d6423SLionel SambucENTRY(ipc_entry_softint_um) 270433d6423SLionel Sambuc SAVE_PROCESS_CTX(0, KTS_INT_UM) 271433d6423SLionel Sambuc jmp ipc_entry_common 272433d6423SLionel Sambuc 273433d6423SLionel SambucENTRY(ipc_entry_common) 274433d6423SLionel Sambuc /* save the pointer to the current process */ 275433d6423SLionel Sambuc push %ebp 276433d6423SLionel Sambuc 277433d6423SLionel Sambuc /* 278433d6423SLionel Sambuc * pass the syscall arguments from userspace to the handler. 279433d6423SLionel Sambuc * SAVE_PROCESS_CTX() does not clobber these registers, they are still 280433d6423SLionel Sambuc * set as the userspace have set them 281433d6423SLionel Sambuc */ 282433d6423SLionel Sambuc push %ebx 283433d6423SLionel Sambuc push %eax 284433d6423SLionel Sambuc push %ecx 285433d6423SLionel Sambuc 286433d6423SLionel Sambuc /* stop user process cycles */ 287433d6423SLionel Sambuc push %ebp 288433d6423SLionel Sambuc /* for stack trace */ 289433d6423SLionel Sambuc movl $0, %ebp 290433d6423SLionel Sambuc call _C_LABEL(context_stop) 291433d6423SLionel Sambuc add $4, %esp 292433d6423SLionel Sambuc 293433d6423SLionel Sambuc call _C_LABEL(do_ipc) 294433d6423SLionel Sambuc 295433d6423SLionel Sambuc /* restore the current process pointer and save the return value */ 296433d6423SLionel Sambuc add $3 * 4, %esp 297433d6423SLionel Sambuc pop %esi 298433d6423SLionel Sambuc mov %eax, AXREG(%esi) 299433d6423SLionel Sambuc 300433d6423SLionel Sambuc jmp _C_LABEL(switch_to_user) 301433d6423SLionel Sambuc 302433d6423SLionel Sambuc 303433d6423SLionel Sambuc/* 304433d6423SLionel Sambuc * kernel call is only from a process to kernel 305433d6423SLionel Sambuc */ 306433d6423SLionel SambucENTRY(kernel_call_entry_orig) 307433d6423SLionel Sambuc SAVE_PROCESS_CTX(0, KTS_INT_ORIG) 308433d6423SLionel Sambuc jmp kernel_call_entry_common 309433d6423SLionel Sambuc 310433d6423SLionel SambucENTRY(kernel_call_entry_um) 311433d6423SLionel Sambuc SAVE_PROCESS_CTX(0, KTS_INT_UM) 312433d6423SLionel Sambuc jmp kernel_call_entry_common 313433d6423SLionel Sambuc 314433d6423SLionel SambucENTRY(kernel_call_entry_common) 315433d6423SLionel Sambuc /* save the pointer to the current process */ 316433d6423SLionel Sambuc push %ebp 317433d6423SLionel Sambuc 318433d6423SLionel Sambuc /* 319433d6423SLionel Sambuc * pass the syscall arguments from userspace to the handler. 320433d6423SLionel Sambuc * SAVE_PROCESS_CTX() does not clobber these registers, they are still 321433d6423SLionel Sambuc * set as the userspace have set them 322433d6423SLionel Sambuc */ 323433d6423SLionel Sambuc push %eax 324433d6423SLionel Sambuc 325433d6423SLionel Sambuc /* stop user process cycles */ 326433d6423SLionel Sambuc push %ebp 327433d6423SLionel Sambuc /* for stack trace */ 328433d6423SLionel Sambuc movl $0, %ebp 329433d6423SLionel Sambuc call _C_LABEL(context_stop) 330433d6423SLionel Sambuc add $4, %esp 331433d6423SLionel Sambuc 332433d6423SLionel Sambuc call _C_LABEL(kernel_call) 333433d6423SLionel Sambuc 334433d6423SLionel Sambuc /* restore the current process pointer and save the return value */ 335433d6423SLionel Sambuc add $8, %esp 336433d6423SLionel Sambuc 337433d6423SLionel Sambuc jmp _C_LABEL(switch_to_user) 338433d6423SLionel Sambuc 339433d6423SLionel Sambuc 340433d6423SLionel Sambuc.balign 16 341433d6423SLionel Sambuc/* 342433d6423SLionel Sambuc * called by the exception interrupt vectors. If the exception does not push 343433d6423SLionel Sambuc * errorcode, we assume that the vector handler pushed 0 instead. Next pushed 344433d6423SLionel Sambuc * thing is the vector number. From this point on we can continue as if every 345433d6423SLionel Sambuc * exception pushes an error code 346433d6423SLionel Sambuc */ 347433d6423SLionel Sambucexception_entry: 348433d6423SLionel Sambuc /* 349433d6423SLionel Sambuc * check if it is a nested trap by comparing the saved code segment 350433d6423SLionel Sambuc * descriptor with the kernel CS first 351433d6423SLionel Sambuc */ 352433d6423SLionel Sambuc TEST_INT_IN_KERNEL(12, exception_entry_nested) 353433d6423SLionel Sambuc 354433d6423SLionel Sambucexception_entry_from_user: 355433d6423SLionel Sambuc SAVE_PROCESS_CTX(8, KTS_INT_HARD) 356433d6423SLionel Sambuc 357433d6423SLionel Sambuc /* stop user process cycles */ 358433d6423SLionel Sambuc push %ebp 359433d6423SLionel Sambuc /* for stack trace clear %ebp */ 360433d6423SLionel Sambuc movl $0, %ebp 361433d6423SLionel Sambuc call _C_LABEL(context_stop) 362433d6423SLionel Sambuc add $4, %esp 363433d6423SLionel Sambuc 364433d6423SLionel Sambuc /* 365433d6423SLionel Sambuc * push a pointer to the interrupt state pushed by the cpu and the 366433d6423SLionel Sambuc * vector number pushed by the vector handler just before calling 367433d6423SLionel Sambuc * exception_entry and call the exception handler. 368433d6423SLionel Sambuc */ 369433d6423SLionel Sambuc push %esp 370433d6423SLionel Sambuc push $0 /* it's not a nested exception */ 371433d6423SLionel Sambuc call _C_LABEL(exception_handler) 372433d6423SLionel Sambuc 373433d6423SLionel Sambuc jmp _C_LABEL(switch_to_user) 374433d6423SLionel Sambuc 375433d6423SLionel Sambucexception_entry_nested: 376433d6423SLionel Sambuc 377433d6423SLionel Sambuc pusha 378433d6423SLionel Sambuc mov %esp, %eax 379433d6423SLionel Sambuc add $(8 * 4), %eax 380433d6423SLionel Sambuc push %eax 381433d6423SLionel Sambuc pushl $1 /* it's a nested exception */ 382433d6423SLionel Sambuc call _C_LABEL(exception_handler) 383433d6423SLionel Sambuc add $8, %esp 384433d6423SLionel Sambuc popa 385433d6423SLionel Sambuc 386433d6423SLionel Sambuc /* clear the error code and the exception number */ 387433d6423SLionel Sambuc add $8, %esp 388433d6423SLionel Sambuc /* resume execution at the point of exception */ 389433d6423SLionel Sambuc iret 390433d6423SLionel Sambuc 391433d6423SLionel SambucENTRY(restore_user_context_sysenter) 392433d6423SLionel Sambuc /* return to userspace using sysexit. 393433d6423SLionel Sambuc * most of the context saving the userspace process is 394433d6423SLionel Sambuc * responsible for, we just have to take care of the right EIP 395433d6423SLionel Sambuc * and ESP restoring here to resume execution, and set EAX and 396433d6423SLionel Sambuc * EBX to the saved status values. 397433d6423SLionel Sambuc */ 398433d6423SLionel Sambuc mov 4(%esp), %ebp /* retrieve proc ptr arg */ 399433d6423SLionel Sambuc movw $USER_DS_SELECTOR, %ax 400433d6423SLionel Sambuc movw %ax, %ds 401433d6423SLionel Sambuc mov PCREG(%ebp), %edx /* sysexit restores EIP using EDX */ 402433d6423SLionel Sambuc mov SPREG(%ebp), %ecx /* sysexit restores ESP using ECX */ 403433d6423SLionel Sambuc mov AXREG(%ebp), %eax /* trap return value */ 404433d6423SLionel Sambuc mov BXREG(%ebp), %ebx /* secondary return value */ 4059393439aSLionel Sambuc 4069393439aSLionel Sambuc /* restore PSW */ 407433d6423SLionel Sambuc movl PSWREG(%ebp), %edi /* load desired PSW to EDI */ 4089393439aSLionel Sambuc push %edi 4099393439aSLionel Sambuc popf 4109393439aSLionel Sambuc 411433d6423SLionel Sambuc sti /* enable interrupts */ 412433d6423SLionel Sambuc sysexit /* jump to EIP in user */ 413433d6423SLionel Sambuc 414433d6423SLionel SambucENTRY(restore_user_context_syscall) 415433d6423SLionel Sambuc /* return to userspace using sysret. 416433d6423SLionel Sambuc * the procedure is very similar to sysexit; it requires 417433d6423SLionel Sambuc * manual %esp restoring, new EIP in ECX, does not require 418433d6423SLionel Sambuc * enabling interrupts, and of course sysret instead of sysexit. 419433d6423SLionel Sambuc */ 420433d6423SLionel Sambuc mov 4(%esp), %ebp /* retrieve proc ptr arg */ 421*c9278f91SBen Gras 422*c9278f91SBen Gras /* restore PSW (before we switch to user stack!) */ 423*c9278f91SBen Gras movl PSWREG(%ebp), %edi /* load desired PSW to EDI */ 424*c9278f91SBen Gras push %edi 425*c9278f91SBen Gras popf 426*c9278f91SBen Gras 427433d6423SLionel Sambuc mov PCREG(%ebp), %ecx /* sysret restores EIP using ECX */ 428433d6423SLionel Sambuc mov SPREG(%ebp), %esp /* restore ESP directly */ 429433d6423SLionel Sambuc mov AXREG(%ebp), %eax /* trap return value */ 430433d6423SLionel Sambuc mov BXREG(%ebp), %ebx /* secondary return value */ 431*c9278f91SBen Gras 432433d6423SLionel Sambuc sysret /* jump to EIP in user */ 433433d6423SLionel Sambuc 434433d6423SLionel SambucENTRY(restore_user_context_int) 435433d6423SLionel Sambuc mov 4(%esp), %ebp /* will assume P_STACKBASE == 0 */ 436433d6423SLionel Sambuc 437433d6423SLionel Sambuc /* reconstruct the stack for iret */ 438433d6423SLionel Sambuc push $USER_DS_SELECTOR /* ss */ 439433d6423SLionel Sambuc movl SPREG(%ebp), %eax 440433d6423SLionel Sambuc push %eax 441433d6423SLionel Sambuc movl PSWREG(%ebp), %eax 442433d6423SLionel Sambuc push %eax 443433d6423SLionel Sambuc push $USER_CS_SELECTOR /* cs */ 444433d6423SLionel Sambuc movl PCREG(%ebp), %eax 445433d6423SLionel Sambuc push %eax 446433d6423SLionel Sambuc 447433d6423SLionel Sambuc /* Restore segments as the user should see them. */ 448433d6423SLionel Sambuc movw $USER_DS_SELECTOR, %si 449433d6423SLionel Sambuc movw %si, %ds 450433d6423SLionel Sambuc movw %si, %es 451433d6423SLionel Sambuc movw %si, %fs 452433d6423SLionel Sambuc movw %si, %gs 453433d6423SLionel Sambuc 454433d6423SLionel Sambuc /* Same for general-purpose registers. */ 455433d6423SLionel Sambuc RESTORE_GP_REGS(%ebp) 456433d6423SLionel Sambuc 457433d6423SLionel Sambuc movl BPREG(%ebp), %ebp 458433d6423SLionel Sambuc 459433d6423SLionel Sambuc iret /* continue process */ 460433d6423SLionel Sambuc 461433d6423SLionel Sambuc/*===========================================================================*/ 462433d6423SLionel Sambuc/* exception handlers */ 463433d6423SLionel Sambuc/*===========================================================================*/ 464433d6423SLionel Sambuc 465433d6423SLionel Sambuc#define EXCEPTION_ERR_CODE(vector) \ 466433d6423SLionel Sambuc push $vector ;\ 467433d6423SLionel Sambuc jmp exception_entry 468433d6423SLionel Sambuc 469433d6423SLionel Sambuc#define EXCEPTION_NO_ERR_CODE(vector) \ 470433d6423SLionel Sambuc pushl $0 ;\ 471433d6423SLionel Sambuc EXCEPTION_ERR_CODE(vector) 472433d6423SLionel Sambuc 473433d6423SLionel SambucLABEL(divide_error) 474433d6423SLionel Sambuc EXCEPTION_NO_ERR_CODE(DIVIDE_VECTOR) 475433d6423SLionel Sambuc 476433d6423SLionel SambucLABEL(single_step_exception) 477433d6423SLionel Sambuc EXCEPTION_NO_ERR_CODE(DEBUG_VECTOR) 478433d6423SLionel Sambuc 479433d6423SLionel SambucLABEL(nmi) 480433d6423SLionel Sambuc#ifndef USE_WATCHDOG 481433d6423SLionel Sambuc EXCEPTION_NO_ERR_CODE(NMI_VECTOR) 482433d6423SLionel Sambuc#else 483433d6423SLionel Sambuc /* 484433d6423SLionel Sambuc * We have to be very careful as this interrupt can occur anytime. On 485433d6423SLionel Sambuc * the other hand, if it interrupts a user process, we will resume the 486433d6423SLionel Sambuc * same process which makes things a little simpler. We know that we are 487433d6423SLionel Sambuc * already on kernel stack whenever it happened and we can be 488433d6423SLionel Sambuc * conservative and save everything as we don't need to be extremely 489433d6423SLionel Sambuc * efficient as the interrupt is infrequent and some overhead is already 490433d6423SLionel Sambuc * expected. 491433d6423SLionel Sambuc */ 492433d6423SLionel Sambuc 493433d6423SLionel Sambuc /* 494433d6423SLionel Sambuc * save the important registers. We don't save %cs and %ss and they are 495433d6423SLionel Sambuc * saved and restored by CPU 496433d6423SLionel Sambuc */ 497433d6423SLionel Sambuc pushw %ds 498433d6423SLionel Sambuc pushw %es 499433d6423SLionel Sambuc pushw %fs 500433d6423SLionel Sambuc pushw %gs 501433d6423SLionel Sambuc pusha 502433d6423SLionel Sambuc 503433d6423SLionel Sambuc /* 504433d6423SLionel Sambuc * We cannot be sure about the state of the kernel segment register, 505433d6423SLionel Sambuc * however, we always set %ds and %es to the same as %ss 506433d6423SLionel Sambuc */ 507433d6423SLionel Sambuc mov %ss, %si 508433d6423SLionel Sambuc mov %si, %ds 509433d6423SLionel Sambuc mov %si, %es 510433d6423SLionel Sambuc 511433d6423SLionel Sambuc push %esp 512433d6423SLionel Sambuc call _C_LABEL(nmi_watchdog_handler) 513433d6423SLionel Sambuc add $4, %esp 514433d6423SLionel Sambuc 515433d6423SLionel Sambuc /* restore all the important registers as they were before the trap */ 516433d6423SLionel Sambuc popa 517433d6423SLionel Sambuc popw %gs 518433d6423SLionel Sambuc popw %fs 519433d6423SLionel Sambuc popw %es 520433d6423SLionel Sambuc popw %ds 521433d6423SLionel Sambuc 522433d6423SLionel Sambuc iret 523433d6423SLionel Sambuc#endif 524433d6423SLionel Sambuc 525433d6423SLionel SambucLABEL(breakpoint_exception) 526433d6423SLionel Sambuc EXCEPTION_NO_ERR_CODE(BREAKPOINT_VECTOR) 527433d6423SLionel Sambuc 528433d6423SLionel SambucLABEL(overflow) 529433d6423SLionel Sambuc EXCEPTION_NO_ERR_CODE(OVERFLOW_VECTOR) 530433d6423SLionel Sambuc 531433d6423SLionel SambucLABEL(bounds_check) 532433d6423SLionel Sambuc EXCEPTION_NO_ERR_CODE(BOUNDS_VECTOR) 533433d6423SLionel Sambuc 534433d6423SLionel SambucLABEL(inval_opcode) 535433d6423SLionel Sambuc EXCEPTION_NO_ERR_CODE(INVAL_OP_VECTOR) 536433d6423SLionel Sambuc 537433d6423SLionel SambucLABEL(copr_not_available) 538433d6423SLionel Sambuc TEST_INT_IN_KERNEL(4, copr_not_available_in_kernel) 539433d6423SLionel Sambuc cld /* set direction flag to a known value */ 540433d6423SLionel Sambuc SAVE_PROCESS_CTX(0, KTS_INT_HARD) 541433d6423SLionel Sambuc /* stop user process cycles */ 542433d6423SLionel Sambuc push %ebp 543433d6423SLionel Sambuc mov $0, %ebp 544433d6423SLionel Sambuc call _C_LABEL(context_stop) 545433d6423SLionel Sambuc call _C_LABEL(copr_not_available_handler) 546433d6423SLionel Sambuc /* reached upon failure only */ 547433d6423SLionel Sambuc jmp _C_LABEL(switch_to_user) 548433d6423SLionel Sambuc 549433d6423SLionel Sambuccopr_not_available_in_kernel: 550433d6423SLionel Sambuc pushl $0 551433d6423SLionel Sambuc pushl $COPROC_NOT_VECTOR 552433d6423SLionel Sambuc jmp exception_entry_nested 553433d6423SLionel Sambuc 554433d6423SLionel SambucLABEL(double_fault) 555433d6423SLionel Sambuc EXCEPTION_ERR_CODE(DOUBLE_FAULT_VECTOR) 556433d6423SLionel Sambuc 557433d6423SLionel SambucLABEL(copr_seg_overrun) 558433d6423SLionel Sambuc EXCEPTION_NO_ERR_CODE(COPROC_SEG_VECTOR) 559433d6423SLionel Sambuc 560433d6423SLionel SambucLABEL(inval_tss) 561433d6423SLionel Sambuc EXCEPTION_ERR_CODE(INVAL_TSS_VECTOR) 562433d6423SLionel Sambuc 563433d6423SLionel SambucLABEL(segment_not_present) 564433d6423SLionel Sambuc EXCEPTION_ERR_CODE(SEG_NOT_VECTOR) 565433d6423SLionel Sambuc 566433d6423SLionel SambucLABEL(stack_exception) 567433d6423SLionel Sambuc EXCEPTION_ERR_CODE(STACK_FAULT_VECTOR) 568433d6423SLionel Sambuc 569433d6423SLionel SambucLABEL(general_protection) 570433d6423SLionel Sambuc EXCEPTION_ERR_CODE(PROTECTION_VECTOR) 571433d6423SLionel Sambuc 572433d6423SLionel SambucLABEL(page_fault) 573433d6423SLionel Sambuc EXCEPTION_ERR_CODE(PAGE_FAULT_VECTOR) 574433d6423SLionel Sambuc 575433d6423SLionel SambucLABEL(copr_error) 576433d6423SLionel Sambuc EXCEPTION_NO_ERR_CODE(COPROC_ERR_VECTOR) 577433d6423SLionel Sambuc 578433d6423SLionel SambucLABEL(alignment_check) 579433d6423SLionel Sambuc EXCEPTION_NO_ERR_CODE(ALIGNMENT_CHECK_VECTOR) 580433d6423SLionel Sambuc 581433d6423SLionel SambucLABEL(machine_check) 582433d6423SLionel Sambuc EXCEPTION_NO_ERR_CODE(MACHINE_CHECK_VECTOR) 583433d6423SLionel Sambuc 584433d6423SLionel SambucLABEL(simd_exception) 585433d6423SLionel Sambuc EXCEPTION_NO_ERR_CODE(SIMD_EXCEPTION_VECTOR) 586433d6423SLionel Sambuc 587433d6423SLionel Sambuc/*===========================================================================*/ 588433d6423SLionel Sambuc/* reload_cr3 */ 589433d6423SLionel Sambuc/*===========================================================================*/ 590433d6423SLionel Sambuc/* PUBLIC void reload_cr3(void); */ 591433d6423SLionel SambucENTRY(reload_cr3) 592433d6423SLionel Sambuc push %ebp 593433d6423SLionel Sambuc mov %esp, %ebp 594433d6423SLionel Sambuc mov %cr3, %eax 595433d6423SLionel Sambuc mov %eax, %cr3 596433d6423SLionel Sambuc pop %ebp 597433d6423SLionel Sambuc ret 598433d6423SLionel Sambuc 599433d6423SLionel Sambuc#ifdef CONFIG_SMP 600433d6423SLionel SambucENTRY(startup_ap_32) 601433d6423SLionel Sambuc /* 602433d6423SLionel Sambuc * we are in protected mode now, %cs is correct and we need to set the 603433d6423SLionel Sambuc * data descriptors before we can touch anything 604433d6423SLionel Sambuc * 605433d6423SLionel Sambuc * first load the regular, highly mapped idt, gdt 606433d6423SLionel Sambuc */ 607433d6423SLionel Sambuc 608433d6423SLionel Sambuc /* 609433d6423SLionel Sambuc * use the boot stack for now. The running CPUs are already using their 610433d6423SLionel Sambuc * own stack, the rest is still waiting to be booted 611433d6423SLionel Sambuc */ 612433d6423SLionel Sambuc movw $KERN_DS_SELECTOR, %ax 613433d6423SLionel Sambuc mov %ax, %ds 614433d6423SLionel Sambuc mov %ax, %ss 615433d6423SLionel Sambuc mov $_C_LABEL(k_boot_stktop) - 4, %esp 616433d6423SLionel Sambuc 617433d6423SLionel Sambuc /* load the highly mapped idt, gdt, per-cpu tss */ 618433d6423SLionel Sambuc call _C_LABEL(prot_load_selectors) 619433d6423SLionel Sambuc 620433d6423SLionel Sambuc jmp _C_LABEL(smp_ap_boot) 621433d6423SLionel Sambuc hlt 622433d6423SLionel Sambuc#endif 623433d6423SLionel Sambuc 624433d6423SLionel Sambuc/*===========================================================================*/ 625433d6423SLionel Sambuc/* data */ 626433d6423SLionel Sambuc/*===========================================================================*/ 627433d6423SLionel Sambuc 628433d6423SLionel Sambuc.data 629433d6423SLionel Sambuc.short 0x526F /* this must be the first data entry (magic #) */ 630433d6423SLionel Sambuc 631433d6423SLionel Sambuc.bss 632433d6423SLionel Sambuck_initial_stack: 633433d6423SLionel Sambuc.space K_STACK_SIZE 634433d6423SLionel SambucLABEL(__k_unpaged_k_initial_stktop) 635433d6423SLionel Sambuc 636433d6423SLionel Sambuc/* 637433d6423SLionel Sambuc * the kernel stack 638433d6423SLionel Sambuc */ 639433d6423SLionel Sambuck_boot_stack: 640433d6423SLionel Sambuc.space K_STACK_SIZE /* kernel stack */ /* FIXME use macro here */ 641433d6423SLionel SambucLABEL(k_boot_stktop) /* top of kernel stack */ 642433d6423SLionel Sambuc 643433d6423SLionel Sambuc.balign K_STACK_SIZE 644433d6423SLionel SambucLABEL(k_stacks_start) 645433d6423SLionel Sambuc 646433d6423SLionel Sambuc/* two pages for each stack, one for data, other as a sandbox */ 647433d6423SLionel Sambuc.space 2 * (K_STACK_SIZE * CONFIG_MAX_CPUS) 648433d6423SLionel Sambuc 649433d6423SLionel SambucLABEL(k_stacks_end) 650433d6423SLionel Sambuc 651433d6423SLionel Sambuc/* top of kernel stack */ 652