/* * FILE: ntoskrnl/ke/i386/vm86_sup.S * PURPOSE: V86 mode support * PROGRAMMER: David Welch (welch@cwcom.net) * UPDATE HISTORY: * Created 09/10/00 */ #include .globl _Ki386RetToV86Mode .globl _KiV86Complete /* * VOID Ki386RetToV86Mode(KV86M_REGISTERS* InRegs, * KV86M_REGISTERS* OutRegs); * * Starts in v86 mode with the registers set to the * specified values. */ _Ki386RetToV86Mode: /* * Setup a stack frame */ pushl %ebp movl %esp, %ebp /* * Save registers */ pusha /* * Get a pointer to IN_REGS */ movl 8(%ebp), %ebx /* * Save ebp */ pushl %ebp /* * Save a pointer to IN_REGS which the v86m exception handler will * use to handle exceptions */ pushl %ebx /* * Since we are going to fiddle with the stack pointer this must be * a critical section for this processor */ cli /* * Save the exception handler stack from the TSS */ movl %fs:KPCR_TSS, %esi pushl KTSS_ESP0(%esi) /* * The stack used for handling exceptions from v86 mode in this thread * will be the current stack adjusted so we don't overwrite the * existing stack frames */ movl %esp, KTSS_ESP0(%esi) /* * Create the stack frame for an iret to v86 mode */ pushl KV86M_REGISTERS_GS(%ebx) pushl KV86M_REGISTERS_FS(%ebx) pushl KV86M_REGISTERS_DS(%ebx) pushl KV86M_REGISTERS_ES(%ebx) pushl KV86M_REGISTERS_SS(%ebx) pushl KV86M_REGISTERS_ESP(%ebx) pushl KV86M_REGISTERS_EFLAGS(%ebx) pushl KV86M_REGISTERS_CS(%ebx) pushl KV86M_REGISTERS_EIP(%ebx) /* * Setup the CPU registers */ movl KV86M_REGISTERS_EAX(%ebx), %eax movl KV86M_REGISTERS_ECX(%ebx), %ecx movl KV86M_REGISTERS_EDX(%ebx), %edx movl KV86M_REGISTERS_ESI(%ebx), %esi movl KV86M_REGISTERS_EDI(%ebx), %edi movl KV86M_REGISTERS_EBP(%ebx), %ebp movl KV86M_REGISTERS_EBX(%ebx), %ebx /* * Go to v86 mode */ iret /* * Handle the completion of a vm86 routine. We are called from * an exception handler with the registers at the point of the * exception on the stack. */ _KiV86Complete: /* Restore the original ebp */ movl TF_ORIG_EBP(%esp), %ebp /* Get a pointer to the OUT_REGS structure */ movl 12(%ebp), %ebx /* Skip debug information and unsaved registers */ addl $0x30, %esp /* Ignore 32-bit segment registers */ addl $12, %esp /* Save the vm86 registers into the OUT_REGS structure */ popl KV86M_REGISTERS_EDX(%ebx) popl KV86M_REGISTERS_ECX(%ebx) popl KV86M_REGISTERS_EAX(%ebx) /* Restore the old previous mode */ popl %eax movb %al, %ss:KTHREAD_PREVIOUS_MODE(%esi) /* Restore the old exception handler list */ popl %eax movl %eax, %fs:KPCR_EXCEPTION_LIST /* Ignore the 32-bit fs register */ addl $4, %esp popl KV86M_REGISTERS_EDI(%ebx) popl KV86M_REGISTERS_ESI(%ebx) popl KV86M_REGISTERS_EBX(%ebx) popl KV86M_REGISTERS_EBP(%ebx) /* Ignore error code */ addl $4, %esp popl KV86M_REGISTERS_EIP(%ebx) popl KV86M_REGISTERS_CS(%ebx) popl KV86M_REGISTERS_EFLAGS(%ebx) popl KV86M_REGISTERS_ESP(%ebx) popl KV86M_REGISTERS_SS(%ebx) popl KV86M_REGISTERS_ES(%ebx) popl KV86M_REGISTERS_DS(%ebx) popl KV86M_REGISTERS_FS(%ebx) popl KV86M_REGISTERS_GS(%ebx) /* * We are going to fiddle with the stack so this must be a critical * section for this process */ cli /* * Restore the exception handler stack in the TSS */ movl %fs:KPCR_TSS, %esi popl KTSS_ESP0(%esi) /* Exit the critical section */ sti /* Ignore IN_REGS pointer */ addl $4, %esp /* Ignore ebp restored above */ addl $4, %esp /* Return to caller */ popa movl %ebp, %esp popl %ebp ret