TITLE "Call Bios support" ;++ ; ; Copyright (c) 1989 Microsoft Corporation ; ; Module Name: ; ; spinlock.asm ; ; Abstract: ; ; This module implements the support routines for executing int bios ; call in v86 mode. ; ; Author: ; ; Shie-Lint Tzong (shielint) Sept 10, 1992 ; ; Environment: ; ; Kernel mode only. ; ; Revision History: ; ;-- .386p include ks386.inc include callconv.inc ; calling convention macros include i386\kimacro.inc VdmStartExecution EQU 0 V86_STACK_POINTER equ 11ffeh ; see BIOSC.C EXTRNP _NtVdmControl,2 extrn _KiExceptionExit:PROC _TEXT SEGMENT DWORD PUBLIC 'CODE' ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING PAGE SUBTTL "Switch to V86 mode" ;++ ; ; VOID ; Ki386SetupAndExitToV86Code ( ; VOID ; ) ; ; Routine Description: ; ; This function sets up return trap frame, switch stack and ; calls VdmStartExecution routine to put vdm context to ; base trap frame and causes the system to execute in v86 mode by ; doing a KiExceptionExit. ; ; Arguments: ; ; BiosArguments - Supplies a pointer to a structure which contains ; the arguments for v86 int function. ; ; Return Value: ; ; None. ; ;-- cPublicProc _Ki386SetupAndExitToV86Code,1 NewTEB equ [ecx+32] ; location of the parameter based on ; the ecx stack pointer. KsaeInitialStack equ [ecx] OriginalThTeb equ [ecx+4] OriginalPcTeb equ [ecx+8] ; ; Allocate TRAP FRAME at the bottom of the stack. ; push ebp push ebx push esi push edi sub esp, 12 ; 12 bytes for local variable mov ecx, esp ; (ecx) = saved esp sub esp, NPX_FRAME_LENGTH and esp, 0fffffff0h ; FXSAVE 16 byte alignment requirement sub esp, KTRAP_FRAME_LENGTH ; (esp)-> new trap frame mov eax, esp ; (eax)->New base trap frame ; ; Initialize newly allocated trap frame to caller's nonvolatle context. ; Note that it is very important that the trap frame we are going to create ; is a USER mode frame. The system expects the top trap frame for user ; mode thread is a user mode frame. (Get/SetContext enforce the rule.) ; ; (eax)-> Base of trap frame. ; mov dword ptr [eax].TsSegCs, KGDT_R0_CODE OR RPL_MASK ; an invalid cs to trap it back to kernel mov dword ptr [eax].TsSegEs, 0 mov dword ptr [eax].TsSegDs, 0 mov dword ptr [eax].TsSegFs, 0 mov dword ptr [eax].TsSegGs, 0 mov dword ptr [eax].TsErrCode, 0 mov ebx, PCR[PcSelfPcr] ; (ebx)->Pcr mov edi, [ebx]+PcPrcbData+PbCurrentThread ; (edi)->CurrentThread mov edx, [edi].ThInitialStack sub edx, NPX_FRAME_LENGTH ; space for NPX_FRAME mov KsaeInitialStack, edx ; Thread InitialSack mov edx, [edi].ThTeb mov OriginalThTeb, edx mov edx, PCR[PcTeb] mov OriginalPcTeb, edx mov edi, offset Ki386BiosCallReturnAddress mov [eax].TsEsi, ecx ; Saved esp mov [eax].TsEip, edi ; set up return address pushfd pop edi and edi, 60dd7h or edi, 200h ; sanitize EFLAGS mov dword ptr [eax].TsHardwareSegSs, KGDT_R3_DATA OR RPL_MASK mov dword ptr [eax].TsHardwareEsp, V86_STACK_POINTER mov [eax].TsEflags, edi mov [eax].TsExceptionList, EXCEPTION_CHAIN_END mov [eax].TsPreviousPreviousMode, 0ffffffffh ; No previous mode and [eax].TsDr7, 0 if DBG mov [eax].TsDbgArgMark, 0BADB0D00h ; set trap frame mark endif add eax, KTRAP_FRAME_LENGTH ; ; Disable interrupt and change the stack pointer to make the new ; trap frame be the current thread's base trap frame. ; ; (eax)->Npx save area ; cli ; ; Set up various stack pointers ; ; Low | | ; |-----------| <- New esp ; | New Base | ; |Trap Frame | ; |-----------| <- Tss.Esp0 ; |V86 segs | ; |-----------| <- Pcr.InitialStack ; |Npx Area | ; |-----------| <- Old Esp = Thread.InitialStack ; | | ; High | | ; ; ; Copy the FP state to the new FP state save area (NPX frame) ; push ecx ; save ecx (saved esp) mov edi, [ebx]+PcPrcbData+PbCurrentThread ; (edi)->CurrentThread mov esi, [edi].ThInitialStack sub esi, NPX_FRAME_LENGTH mov ecx, NPX_FRAME_LENGTH/4 mov edi, eax rep movsd pop ecx ; restore ecx mov edi, [ebx]+PcPrcbData+PbCurrentThread ; (edi)->CurrentThread mov esi,[ebx]+PcTss ; (esi)->TSS sub eax,TsV86Gs - TsHardwareSegSs ; bias for missing fields mov [ebx].PcExceptionList, EXCEPTION_CHAIN_END mov [esi]+TssEsp0,eax add eax, NPX_FRAME_LENGTH + (TsV86Gs - TsHardwareSegSs) mov [edi].ThInitialStack, eax ; ; Set up the pointers to the fake TEB so we can execute the int10 ; call ; mov eax, NewTeb mov PCR[PcTeb], eax mov [edi].ThTeb, eax mov ebx, PCR[PcGdt] mov [ebx]+(KGDT_R3_TEB+KgdtBaseLow), ax shr eax, 16 mov [ebx]+(KGDT_R3_TEB+KgdtBaseMid), al mov [ebx]+(KGDT_R3_TEB+KgdtBaseHi), ah sti ; Now call VdmControl to save return 32bit frame and put vdm context ; to new base trap frame stdCall _NtVdmControl, if 0 ; ; Now call _VdmpStartExecution to save return 32bit frame and put vdm context ; to new base trap frame ; mov eax, ExecAddr stdCall _VdmpStartExecution, endif ; ; Call KiexceptionExit to 'exit' to v86 code. ; mov ebp, esp ; (ebp)->Exit trap frame jmp _KiExceptionExit ; go execute int 10 public Ki386BiosCallReturnAddress Ki386BiosCallReturnAddress: ; ; After ROM BIOS int completes, the bop instruction gets executed. ; This results in a trap to kernel mode bop handler where the ; 16 bit Vdm context will be saved to VdmTib->VdmCOntext, and ; the faked 32 bit user mode context (i.e. the one we created earlier) ; be restored. Since the faked user mode context does NOT have a valid ; iret address, the 'iret' instruction of the EXIT_ALL will be trapped to ; our GP fault handler which recognizes this and transfers control back to ; here. ; ; when we come back here, all the segment registers are set up properly ; Interrupts are disabled. ; ; ; restore all the pointers. ; mov eax, PCR[PcSelfPcr] ; (eax)->Pcr mov edi, [ebp].TsEsi ; Fetch previous stack address mov edi, [edi] ; Initial Stack is saved at stack top ; ; Copy the FP state back down to the default stack ; mov ecx, [eax]+PcPrcbData+PbCurrentThread ; (ecx)->CurrentThread mov esi, [ecx].ThInitialStack sub esi, NPX_FRAME_LENGTH mov ecx, NPX_FRAME_LENGTH/4 rep movsd ; copy FP state ; (n.b. edi+= NPX_FRAME_LENGTH) mov esp, [ebp].TsEsi ; Shink stack add esp, 4 ; drop saved stack address mov ecx, [eax]+PcPrcbData+PbCurrentThread ; (ecx)->CurrentThread mov [ecx].ThInitialStack, edi ; Restore Thread.InitialStack mov eax,[eax]+PcTss ; (eax)->TSS sub edi, (TsV86Gs - TsHardwareSegSs) + NPX_FRAME_LENGTH mov [eax]+TssEsp0,edi ; ; restore pointers to the original TEB ; pop edx ; (edx) = OriginalThTeb mov [ecx].ThTeb, edx pop edx ; (edx) = OriginalPcTeb mov PCR[PcTeb], edx mov ebx, PCR[PcGdt] mov [ebx]+(KGDT_R3_TEB+KgdtBaseLow), dx shr edx, 16 mov [ebx]+(KGDT_R3_TEB+KgdtBaseMid), dl mov [ebx]+(KGDT_R3_TEB+KgdtBaseHi), dh sti pop edi pop esi pop ebx pop ebp stdRET _Ki386SetupAndExitToV86Code stdENDP _Ki386SetupAndExitToV86Code _TEXT ends end