diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/nthals/halx86/i386/xxbiosa.asm | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/ntos/nthals/halx86/i386/xxbiosa.asm')
-rw-r--r-- | private/ntos/nthals/halx86/i386/xxbiosa.asm | 712 |
1 files changed, 712 insertions, 0 deletions
diff --git a/private/ntos/nthals/halx86/i386/xxbiosa.asm b/private/ntos/nthals/halx86/i386/xxbiosa.asm new file mode 100644 index 000000000..e3d5493b6 --- /dev/null +++ b/private/ntos/nthals/halx86/i386/xxbiosa.asm @@ -0,0 +1,712 @@ +;++ +; +; Copyright (c) 1991 Microsoft Corporation +; +; Module Name: +; +; xxbiosa.asm +; +; Abstract: +; +; This implements the necessary code to put the processor into +; V86 mode, make a BIOS call, and return safely to protected mode. +; +; Author: +; +; John Vert (jvert) 29-Oct-1991 +; +; Environment: +; +; Kernel mode +; +; Notes: +; +; This module is intended for use in panic situations, such as a bugcheck. +; As a result, we cannot rely on the integrity of the system so we must +; handle everything ourselves. Notably, we must map our own memory by +; adding our own page tables and PTEs. +; +; We also cannot call KeBugCheck when we notice something has gone wrong. +; +; Revision History: +; +;-- +.386p + .xlist +include hal386.inc +include callconv.inc ; calling convention macros +include i386\kimacro.inc + .list + + extrn _DbgPrint:proc + EXTRNP _DbgBreakPoint,0,IMPORT + EXTRNP Kei386EoiHelper,0,IMPORT + + public _HalpRealModeStart + public _HalpRealModeEnd +; +; 32-bit override +; +OVERRIDE equ 66h + +; +; Reginfo structure +; + +RegInfo struc +RiSegSs dd 0 +RiEsp dd 0 +RiEFlags dd 0 +RiSegCs dd 0 +RiEip dd 0 +RiTrapFrame dd 0 +RiCsLimit dd 0 +RiCsBase dd 0 +RiCsFlags dd 0 +RiSsLimit dd 0 +RiSsBase dd 0 +RiSsFlags dd 0 +RiPrefixFlags dd 0 +RegInfo ends +REGINFOSIZE EQU 52 + +INT_NN_OPCODE EQU 0CDH + + page ,132 +_DATA SEGMENT DWORD PUBLIC 'DATA' + +; +; In order to return to the calling function after we've trapped out of +; V86 mode, we save our ESP value here. +; +HalpSavedEsp dd 0 + +_DATA ENDS + + +_TEXT SEGMENT DWORD PUBLIC 'CODE' + ASSUME DS:NOTHING, ES:NOTHING, SS:FLAT, FS:NOTHING, GS:NOTHING + +if DBG + page ,132 + subttl "Processing Exception occurred in ABIOS code" +;++ +; VOID +; KiAbiosException ( +; VOID +; ) +; +; Routine Description: +; +; This routine is called after an exception being detected +; in ABIOS ROM code. The system will switch 16 stack to 32 bit +; stack and bugcheck. +; +; N.B. In fact this routine is simply used to resolve a reference +; to KiAbiosException routine in the Kimacro.inc ENTER_TRAP +; macro. +; +; +; Arguments: +; +; None. +; +; Return value: +; +; system stopped. +; +;-- + public _KiAbiosException +_KiAbiosException proc +_Ki16BitStackException: + ret + +_KiAbiosException endp + +endif + + +;++ +; ULONG +; HalpBorrowTss ( +; VOID +; ) +; +; Routine Description: +; +; This routine checks if the current TSS has IO MAP space. +; if yes, it simply returns. Otherwise, it switches to use +; the regular TSS. +; +; Arguments: +; +; None. +; +; Return value: +; +; Return original TSS selector if the regular Tss is borrowed by us. +; +;-- +cPublicProc _HalpBorrowTss, 0 +cPublicFpo 0, 0 + + xor eax, eax + str ax + mov edx, PCR[PcGdt] + add edx, eax ; (edx)->Gdt Entry of current + ; TSS + xor ecx, ecx + mov cl, [edx].KgdtLimitHi + shl ecx, 16 + mov cx, [edx].KgdtLimitLow ; (ecx) = TSS limit + cmp ecx, 2000H ; Is Io map space available? + ja short Hbt99 ; if a, yes, return + + sub edx, eax ; (edx)->GDT table + mov ch, [edx+KGDT_TSS+KgdtBaseHi] + mov cl, [edx+KGDT_TSS+KgdtBaseMid] + shl ecx, 16 + mov cx, [edx+KGDT_TSS+KgdtBaseLow] + mov PCR[PcTss], ecx + mov ecx, KGDT_TSS ; switch to use regular TSS + mov byte ptr [edx+KGDT_TSS+5], 089h ; 32bit, dpl=0, present, TSS32, + ; not busy. + ltr cx + stdRET _HalpBorrowTss ; (eax) = Original TSS sel + +Hbt99: + xor eax, eax ; No TSS swapped + stdRET _HalpBorrowTss + +stdENDP _HalpBorrowTss + + +;++ +; VOID +; HalpReturnTss ( +; ULONG TssSelector +; ) +; +; Routine Description: +; +; This routine switches the current TSS from regular TSS back to +; the panic TSS (NMI TSS or Double fault TSS). +; +; Arguments: +; +; TssSelector - the TSS selector to return to. +; +; Return value: +; +; None. +; +;-- +cPublicProc _HalpReturnTss, 1 +cPublicFpo 1, 0 + + mov edx, PCR[PcGdt] ; (edx)-> Gdt table + mov eax, [esp + 4] + and eax, 0FFFFh ; (eax)= New TSS sel + add edx, eax ; (edx)->Gdt Entry of new TSS + + mov ch, [edx+KgdtBaseHi] + mov cl, [edx+KgdtBaseMid] + shl ecx, 16 + mov cx, [edx+KgdtBaseLow] + mov PCR[PcTss], ecx + mov byte ptr [edx+5], 089h ; 32bit, dpl=0, present, TSS32, + ltr ax + stdRET _HalpReturnTss ; return and clear stack + +stdENDP _HalpReturnTss + +;++ +; +; VOID +; HalpBiosCall +; VOID +; ) +; +; Routine Description: +; +; This routine completes the transition to real mode, calls BIOS, and +; returns to protected mode. +; +; Arguments: +; +; None. +; +; Return Value: +; +; None. +; +;-- +;;ALIGN 4096 +cPublicProc _HalpBiosCall ,0 + + push ebp + mov ebp, esp + pushfd + push edi + push esi + push ebx + push ds + push es + push fs + push gs + push offset FLAT:HbcProtMode ; address where we will start + ; protected mode again once + ; V86 has completed. + mov HalpSavedEsp, esp + + mov eax, cr0 ; make sure alignment + and eax, not CR0_AM ; checks are disabled + mov cr0, eax + +; +; Create space for the V86 trap frame and update the ESP0 value in the TSS +; to use this space. We will set this up just below our current stack pointer. +; The stuff we push on the stack after we set ESP0 is irrelevant once we +; make it to V86 mode, so it's ok to blast it. +; + mov esi, fs:PcTss ; (esi) -> TSS + mov eax, esp + sub eax, NPX_FRAME_LENGTH ; skip FP save area + mov [esi]+TssEsp0, eax + + push dword ptr 0h ; V86 GS + push dword ptr 0h ; V86 FS + push dword ptr 0h ; V86 DS + push dword ptr 0h ; V86 ES + push dword ptr 2000h ; V86 SS + +; +; We calculate the V86 sp by adding the difference between the linear address +; of the V86 ip (HbcReal) and the linear address of the V86 sp (HbcV86Stack) +; to the offset of the V86 ip (HbcReal & 0xfff). +; + + mov eax, offset FLAT:HbcV86Stack-4 + sub eax, offset FLAT:HbcReal + mov edx, offset HbcReal + and edx, 0fffh + add eax, edx + push eax ; V86 esp + + pushfd + or dword ptr [esp], EFLAGS_V86_MASK; V86 eflags + or [esp], 03000h ; Give IOPL3 + push dword ptr 2000h ; V86 CS + mov eax, offset HbcReal + and eax, 0fffh + + push edx ; V86-mode EIP is offset + ; into CS. + iretd + +_HalpRealModeStart label byte + +HbcReal: + db OVERRIDE ; make mov 32-bits + mov eax, 03h ; 80x25 mode, 16 colors + int 10h + + db OVERRIDE ; make mov 32-bits + mov eax, 1112h ; use 8x8 font (causes 50 line mode) + db OVERRIDE + mov ebx, 0 + int 10h + + db 0c4h, 0c4h ; BOP to indicate V86 mode is done. + +; +; V86-mode stack +; +align 4 + db 2048 dup(0) +HbcV86Stack: + +_HalpRealModeEnd label byte + +HbcProtMode: +; +; We are back from V86 mode, so restore everything we saved and we are done. +; + pop gs + pop fs + pop es + pop ds + pop ebx + pop esi + pop edi + popfd + pop ebp + stdRET _HalpBiosCall + + public _HalpBiosCallEnd +_HalpBiosCallEnd label byte + + + +_HalpBiosCall endp + + + subttl "HAL General Protection Fault" +;++ +; +; Routine Description: +; +; Handle General protection fault. +; +; This fault handler is used by the HAL for V86 mode faults only. +; It should NEVER be used except when running in V86 mode. The HAL +; replaces the general-purpose KiTrap0D handler entry in the IDT with +; this routine. This allows us to emulate V86-mode instructions which +; cause a fault. After we return from V86 mode, we can restore the +; KiTrap0D handler in the IDT. +; +; Arguments: +; +; At entry, the saved CS:EIP point to the faulting instruction +; Error code (whose value depends on detected condition) is provided. +; +; Return value: +; +; None +; +;-- + ASSUME DS:FLAT, SS:NOTHING, ES:FLAT + + ENTER_DR_ASSIST Htd_a, Htd_t, NoAbiosAssist +cPublicProc _HalpTrap0D ,0 + + ENTER_TRAP Htd_a, Htd_t + +; +; Did the trap occur in V86 mode? If not, something is completely screwed. +; + test dword ptr [ebp]+TsEFlags,00020000H + jnz Ht0d10 + +; +; The trap was not from V86 mode, so something is very wrong. We cannot +; BugCheck, since we are probably already in a BugCheck. So just stop. +; + +if DBG +_DATA segment +MsgBadHalTrap db 'HAL: Trap0D while not in V86 mode',0ah,0dh,0 +_DATA ends + + push offset FLAT:MsgBadHalTrap + call _DbgPrint + add esp,4 + stdCall _DbgBreakPoint +endif +; +; We can't bugcheck, so just commit suicide. Maybe we should reboot? +; + jmp $ + +Ht0d10: + stdCall HalpDispatchV86Opcode + SPURIOUS_INTERRUPT_EXIT +stdENDP _HalpTrap0d + + subttl "HAL Invalid Opcode Fault" +;++ +; +; Routine Description: +; +; Handle invalid opcode fault +; +; This fault handler is used by the HAL to indicate when V86 mode +; execution is finished. The V86 code attempts to execute an invalid +; instruction (BOP) when it is done, and that brings us here. +; This routine just removes the trap frame from the stack and does +; a RET. Note that this assumes that ESP0 in the TSS has been set +; up to point to the top of the stack that we want to be running on +; when the V86 call has completed. +; +; This should NEVER be used except when running in V86 mode. The HAL +; replaces the general-purpose KiTrap06 handler entry in the IDT with +; this routine. It also sets up ESP0 in the TSS appropriately. After +; the V86 call has completed, it restores these to their previous values. +; +; Arguments: +; +; At entry, the saved CS:EIP point to the faulting instruction +; Error code (whose value depends on detected condition) is provided. +; +; Return value: +; +; None +; +;-- + ASSUME DS:FLAT, SS:NOTHING, ES:FLAT + +cPublicProc _HalpTrap06 ,0 + mov eax,KGDT_R3_DATA OR RPL_MASK + mov ds,ax + mov es,ax + mov esp, HalpSavedEsp + ret + +stdENDP _HalpTrap06 + + subttl "Instruction Emulation Dispatcher" +;++ +; +; Routine Description: +; +; This routine dispatches to the opcode specific emulation routine, +; based on the first byte of the opcode. Two byte opcodes, and prefixes +; result in another level of dispatching, from the handling routine. +; +; This code blatantly stolen from ke\i386\instemul.asm +; +; Arguments: +; +; ebp = pointer to trap frame +; +; Returns: +; +; Nothing +; + +cPublicProc HalpDispatchV86Opcode ,0 + +RI equ [ebp - REGINFOSIZE] + push ebp + mov ebp,esp + sub esp,REGINFOSIZE + push esi + push edi + + ; Initialize RegInfo + + mov esi,[ebp] + mov RI.RiTrapFrame,esi + movzx eax,word ptr [esi].TsHardwareSegSs + mov RI.RiSegSs,eax + mov eax,[esi].TsHardwareEsp + mov RI.RiEsp,eax + mov eax,[esi].TsEFlags + mov RI.RiEFlags,eax + movzx eax,word ptr [esi].TsSegCs + mov RI.RiSegCs,eax + mov eax,[esi].TsEip + mov RI.RiEip,eax + + xor eax,eax + mov RI.RiPrefixFlags,eax + lea esi,RI + +; +; Convert CS to a linear address +; + + mov eax,[esi].RiSegCs + shl eax,4 + mov [esi].RiCsBase,eax + mov [esi].RiCsLimit,0FFFFh + mov [esi].RiCsFlags,0 + + mov edi,RI.RiEip + cmp edi,RI.RiCsLimit + ja doerr + + add edi,RI.RiCsBase + mov dl, [edi] ; get faulting opcode + cmp dl, INT_NN_OPCODE + je short @f + + stdCall HalpOpcodeInvalid + jmp short doerr + +@@: + stdCall HalpOpcodeINTnn + test eax,0FFFFh + jz do20 + + mov edi,RI.RiTrapFrame + mov eax,RI.RiEip ; advance eip + mov [edi].TsEip,eax + mov eax,1 +do20: pop edi + pop esi + mov esp,ebp + pop ebp + ret + +doerr: xor eax,eax + jmp do20 +stdENDP HalpDispatchV86Opcode + + page ,132 + subttl "Invalid Opcode Handler" +;++ +; +; Routine Description: +; +; This routine handles invalid opcodes. It prints the invalid +; opcode message, and breaks into the kernel debugger. +; +; Arguments: +; +; esi = address of reg info +; edx = opcode +; +; Returns: +; +; nothing +; + +cPublicProc HalpOpcodeInvalid ,0 + +_DATA segment +HalpMsgInvalidOpcode db 'HAL: An invalid V86 opcode was encountered at ' + db 'address %x:%x',0ah, 0dh, 0 +_DATA ends + + push [esi].RiEip + push [esi].RiSegCs + push offset FLAT:HalpMsgInvalidOpcode + call _DbgPrint ; display invalid opcode message + add esp,12 + int 3 + xor eax,eax + stdRET HalpOpcodeInvalid + +stdENDP HalpOpcodeInvalid + + subttl "INTnn Opcode Handler" +;++ +; +; Routine Description: +; +; This routine emulates an INTnn opcode. It retrieves the handler +; from the IVT, pushes the current cs:ip and flags on the stack, +; and dispatches to the handler. +; +; Arguments: +; +; esi = address of reg info +; edx = opcode +; +; Returns: +; +; Current CS:IP on user stack +; RiCs:RiEip -> handler from IVT +; + +cPublicProc HalpOpcodeINTnn ,0 + + push ebp + push edi + push ebx + +; +; Convert SS to linear address +; + mov eax,[esi].RiSegSs + shl eax,4 + mov [esi].RiSsBase,eax + mov [esi].RiSsLimit,0FFFFh + mov [esi].RiSsFlags,0 + + inc [esi].RiEip ; point to int # + mov edi,[esi].RiEip + cmp edi,[esi].RiCsLimit + ja oinerr + + add edi,[esi].RiCsBase + movzx ecx,byte ptr [edi] ; get int # + inc [esi].RiEip ; inc past end of instruction + stdCall HalpPushInt + test eax,0FFFFh + jz oin20 ; error! +; +; BugBug Some sort of check for BOP should go here, or in push int. +; + + mov ebp,[esi].RiTrapFrame + mov eax,[esi].RiSegSs + mov [ebp].TsHardwareSegSs,eax + mov eax,[esi].RiEsp + mov [ebp].TsHardwareEsp,eax + mov eax,[esi].RiSegCs + mov [ebp].TsSegCs,eax + mov eax,[esi].RiEFlags + mov [ebp].TsEFlags,eax + mov eax,1 +oin20: pop ebx + pop edi + pop ebp + stdRET HalpOpcodeINTnn + +oinerr: xor eax,eax + jmp oin20 + +stdENDP HalpOpcodeINTnn + + page ,132 + subttl "Push Interrupt frame on user stack" +;++ +; +; Routine Description: +; +; This routine pushes an interrupt frame on the user stack +; +; Arguments: +; +; ecx = interrupt # +; esi = address of reg info +; Returns: +; +; interrupt frame pushed on stack +; reg info updated +;bugbug does this routine trash BX?? +; +cPublicProc HalpPushInt ,0 + push ebx + + mov edx,[esi].RiEsp + mov ebx,[esi].RiSsBase + and edx,0FFFFh ; only use a 16 bit sp + sub dx,2 + mov ax,word ptr [esi].RiEFlags + mov [ebx+edx],ax ; push flags + sub dx,2 + mov ax,word ptr [esi].RiSegCs + mov [ebx+edx],ax ; push cs + sub dx,2 + mov ax,word ptr [esi].RiEip + mov [ebx+edx],ax ; push ip + mov eax,[ecx*4] ; get new cs:ip value + push eax + movzx eax,ax + mov [esi].RiEip,eax + pop eax + shr eax,16 + mov [esi].RiSegCs,eax + mov word ptr [esi].RiEsp,dx + +; +; Convert CS to a linear address +; + + mov eax,[esi].RiSegCs + shl eax,4 + mov [esi].RiCsBase,eax + mov [esi].RiCsLimit,0FFFFh + mov [esi].RiCsFlags,0 + + mov eax,1 ; success +pi80: pop ebx + stdRET HalpPushInt +stdENDP HalpPushInt + + +_TEXT ends + end |