/* * trap.S: Trap and world switch handlers * * Leendert van Doorn, leendert@watson.ibm.com * Copyright (c) 2005, International Business Machines Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307 USA. */ #include "machine.h" #include "vm86.h" #include "offsets.h" /* * All processor exception/faults/interrupts end up here. * * On an exception/fault, the processor pushes CS:EIP, SS, ESP and an * optional error code onto the stack. The common_trap routine * below saves the processor context and transfers control to trap() * whose job it is to virtualize and pass on the trap. */ .macro TRAP_HANDLER trapno error .text .align 16 1: .if \error == 0 pushl $0 /* dummy error code */ .endif pushl $\trapno jmp common_trap .section .rodata .long 1b .text .endm .section .rodata .code32 .align 4 .global trap_handlers trap_handlers: TRAP_HANDLER 0, 0 /* divide error */ TRAP_HANDLER 1, 0 /* debug */ TRAP_HANDLER 2, 0 /* NMI interrupt */ TRAP_HANDLER 3, 0 /* breakpoint */ TRAP_HANDLER 4, 0 /* overflow */ TRAP_HANDLER 5, 0 /* BOUND range exceeded */ TRAP_HANDLER 6, 0 /* invalid opcode */ TRAP_HANDLER 7, 0 /* device not available */ TRAP_HANDLER 8, 1 /* double fault */ TRAP_HANDLER 9, 0 /* coprocessor segment overrun */ TRAP_HANDLER 10, 1 /* invalid TSS */ TRAP_HANDLER 11, 1 /* segment not present */ TRAP_HANDLER 12, 1 /* stack-segment fault */ TRAP_HANDLER 13, 1 /* general protection */ TRAP_HANDLER 14, 1 /* page fault */ TRAP_HANDLER 15, 0 /* reserved */ TRAP_HANDLER 16, 0 /* FPU floating-point error */ TRAP_HANDLER 17, 1 /* alignment check */ TRAP_HANDLER 18, 0 /* machine check */ TRAP_HANDLER 19, 0 /* SIMD floating-point error */ TRAP_HANDLER 20, 0 /* reserved */ TRAP_HANDLER 21, 0 /* reserved */ TRAP_HANDLER 22, 0 /* reserved */ TRAP_HANDLER 23, 0 /* reserved */ TRAP_HANDLER 24, 0 /* reserved */ TRAP_HANDLER 25, 0 /* reserved */ TRAP_HANDLER 26, 0 /* reserved */ TRAP_HANDLER 27, 0 /* reserved */ TRAP_HANDLER 28, 0 /* reserved */ TRAP_HANDLER 29, 0 /* reserved */ TRAP_HANDLER 30, 0 /* reserved */ TRAP_HANDLER 31, 0 /* reserved */ TRAP_HANDLER 32, 0 /* irq 0 */ TRAP_HANDLER 33, 0 /* irq 1 */ TRAP_HANDLER 34, 0 /* irq 2 */ TRAP_HANDLER 35, 0 /* irq 3 */ TRAP_HANDLER 36, 0 /* irq 4 */ TRAP_HANDLER 37, 0 /* irq 5 */ TRAP_HANDLER 38, 0 /* irq 6 */ TRAP_HANDLER 39, 0 /* irq 7 */ TRAP_HANDLER 40, 0 /* irq 8 */ TRAP_HANDLER 41, 0 /* irq 9 */ TRAP_HANDLER 42, 0 /* irq 10 */ TRAP_HANDLER 43, 0 /* irq 11 */ TRAP_HANDLER 44, 0 /* irq 12 */ TRAP_HANDLER 45, 0 /* irq 13 */ TRAP_HANDLER 46, 0 /* irq 14 */ TRAP_HANDLER 47, 0 /* irq 15 */ .text .code32 .align 16 common_trap: /* common trap handler */ pushal movl $(DATA_SELECTOR), %eax /* make sure these are sane */ movl %eax, %ds movl %eax, %es movl %eax, %fs movl %eax, %gs movl %esp, %ebp pushl %ebp pushl 36(%ebp) pushl 32(%ebp) call trap /* trap(trapno, errno, regs) */ addl $12, %esp trap_return: popal addl $8, %esp /* skip trapno, errno */ iret /* NOT REACHED */ /* * A world switch to real mode occured. The hypervisor saved the * executing context into "oldctx" and instantiated "newctx", which * gets us here. Here we push a stack frame that is compatible with * a trap frame (see above) so that we can handle this event as a * regular trap. */ .text .align 16 .globl switch_to_real_mode switch_to_real_mode: pushl oldctx+VMX_ASSIST_CTX_GS_SEL /* 16 to 32-bit transition */ pushl oldctx+VMX_ASSIST_CTX_FS_SEL pushl oldctx+VMX_ASSIST_CTX_DS_SEL pushl oldctx+VMX_ASSIST_CTX_ES_SEL pushl oldctx+VMX_ASSIST_CTX_SS_SEL pushl oldctx+VMX_ASSIST_CTX_ESP pushl oldctx+VMX_ASSIST_CTX_EFLAGS pushl oldctx+VMX_ASSIST_CTX_CS_SEL pushl oldctx+VMX_ASSIST_CTX_EIP pushl $-1 /* trapno, errno */ pushl $-1 pushal movl %esp, %ebp pushl %ebp call enter_real_mode addl $4, %esp jmp trap_return /* NOT REACHED */ /* * Switch to protected mode. At this point all the registers have * been reloaded by trap_return and all we have to do is cause a * world switch by turning on CR0.PE. */ .text .align 16 .globl switch_to_protected_mode switch_to_protected_mode: movl oldctx+VMX_ASSIST_CTX_CR0, %esp movl %esp, %cr0 /* actual world switch ! */ /* NOT REACHED */ pushl $switch_failed call panic jmp . .data .align 4 switch_failed: .asciz "World switch to protected mode failed\n"