windows-nt/Source/XPSP1/NT/base/ntos/ke/i386/abiosa.asm

723 lines
17 KiB
NASM
Raw Normal View History

2020-09-26 03:20:57 -05:00
title "Abios Support Assembly Routines"
;++
;
; Copyright (c) 1989 Microsoft Corporation
;
; Module Name:
;
; abiosa.asm
;
; Abstract:
;
; This module implements assembley code for ABIOS support.
;
; Author:
;
; Shie-Lin Tzong (shielint) 25-May-1991
;
; Environment:
;
; Kernel mode only.
;
; Revision History:
;
;--
.386p
.xlist
include ks386.inc
include callconv.inc ; calling convention macros
include i386\kimacro.inc
.list
extrn _DbgPrint:proc
EXTRNP _KeRaiseIrql,2,IMPORT
EXTRNP _KeLowerIrql,1,IMPORT
EXTRNP _KeGetCurrentIrql,0,IMPORT
extrn _KiStack16GdtEntry:DWORD
;
; This should be either 0 or 1, if it's greater than 1, then we've re-entered the BIOS.
;
extrn _KiInBiosCall:DWORD
extrn _FlagState:DWORD
extrn _KiBiosFrame:DWORD
OPERAND_OVERRIDE equ 66h
ADDRESS_OVERRIDE equ 67h
KGDT_CDA16 equ 0E8h
LocalStack equ 16 ; 4 DWORDS of slop for PnPBioses.
if DBG
extrn KiBiosReenteredAssert:DWORD
endif
; Macro change note:
;
; This macro pair used to do an uncondtional sti coming back from the 16-bit
; side, this potentially caused problems in APM. Now we save and restore the
; flag state
;
;++
;
; STACK32_TO_STACK16
;
; Macro Description:
;
; This macro remaps current 32bit stack to 16bit stack.
;
; Arguments:
;
; None.
;
;--
STACK32_TO_STACK16 macro
pushfd
mov ecx,[esp]
mov _FlagState,ecx
popfd
mov eax, fs:PcStackLimit ; [eax] = 16-bit stack selector base
mov edx, eax
mov ecx, _KiStack16GdtEntry
mov word ptr [ecx].KgdtBaseLow, ax
shr eax, 16
mov byte ptr [ecx].KgdtBaseMid, al
mov byte ptr [ecx].KgdtBaseHi, ah
mov eax, esp
sub eax, edx
cli
mov esp, eax
mov eax, KGDT_STACK16
mov ss, ax
;
; NOTE that we MUST leave interrupts remain off.
; We'll turn it back on after we switch to 16 bit code.
;
endm
;++
;
; STACK16_TO_STACK32
;
; Macro Description:
;
; This macro remaps current 32bit stack to 16bit stack.
;
; Arguments:
;
; None.
;
;--
STACK16_TO_STACK32 macro Stack32
db OPERAND_OVERRIDE
mov eax, esp
db OPERAND_OVERRIDE
db ADDRESS_OVERRIDE
add eax, fs:PcStackLimit
cli
db OPERAND_OVERRIDE
mov esp, eax
db OPERAND_OVERRIDE
mov eax, KGDT_R0_DATA
mov ss, ax
db OPERAND_OVERRIDE
db ADDRESS_OVERRIDE
push ds:_FlagState
db OPERAND_OVERRIDE
popfd
endm
COPY_CALL_FRAME macro FramePtr
mov [FramePtr].TsEax,eax
mov [FramePtr].TsEbx,ebx
mov [FramePtr].TsEcx,ecx
mov [FramePtr].TsEdx,edx
mov [FramePtr].TsEsi,esi
mov [FramePtr].TsEdi,edi
mov [FramePtr].TsEbp,ebp
mov [FramePtr].TsHardwareEsp,esp
mov [FramePtr].TsSegFs,fs
mov [FramePtr].TsSegCs,cs
endm
page ,132
subttl "Abios Support Code"
_TEXT SEGMENT DWORD PUBLIC 'CODE'
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
;
; BBT cannot instrument code between this label and BBT_Exclude_Selector_Code_End
;
public _BBT_Exclude_Selector_Code_Begin
_BBT_Exclude_Selector_Code_Begin equ $
int 3
;++
; ULONG
; KiAbiosGetGdt (
; VOID
; )
;
; Routine Description:
;
; This routine returns the starting address of GDT of current processor.
;
; Arguments:
;
; None.
;
; Return Value:
;
; return Pcr->GDT
;
;--
cPublicProc _KiAbiosGetGdt,0
mov eax, fs:PcGdt
stdRET _KiAbiosGetGdt
stdENDP _KiAbiosGetGdt
;++
; VOID
; KiI386CallAbios(
; IN KABIOS_POINTER AbiosFunction,
; IN KABIOS_POINTER DeviceBlockPointer,
; IN KABIOS_POINTER FunctionTransferTable,
; IN KABIOS_POINTER RequestBlock
; )
;
; Routine Description:
;
; This function invokes ABIOS service function for device driver. This
; routine is executing at DIAPTCH_LEVEL to prevent context swapping.
;
; N.B. We arrive here from the Ke386AbiosCall with a 32bit CS. That is,
; we're executing the code with cs:eip where cs contains a selector for a
; 32bit flat segment. We want to get to a 16bit cs. That is, cs:ip.
; The reason is that ABIOS is running at 16 bit segment.
; Before we can call ABIOS service we must load ss and cs segment
; registers with selectors for 16bit segments. We start by pushing a far
; pointer to a label in the macro and then doing a retf. This allows us
; to fall through to the next instruction, but we're now executing
; through cs:ip with a 16bit CS. Then, we remap our 32-bit stack to 16-bit
; stack.
;
; Arguments:
;
; AbiosFunction - a 16:16 pointer to the abios service function.
;
; DeviceBlockPointer - a 16:16 pointer to Device Block.
;
; FunctionTransferTable - a 16:16 pointer to Function Transfer Table.
;
; RequestBlock - a 16:16 pointer to device driver's request block.
;
; Return Value:
;
; None.
;--
KacAbiosFunction equ [ebp + 8]
KacDeviceBlock equ [ebp + 12]
KacFunctionTable equ [ebp + 16]
KacRequestBlock equ [ebp + 20]
cPublicProc _KiI386CallAbios,4
;
; We're using a 32bit CS:EIP - go to a 16bit CS:IP
; Note the base of KiAbiosCallSelector is the flat address of _KiI386AbiosCall
; routine.
;
push ebp
mov ebp, esp
push ebx
COPY_CALL_FRAME _KiBiosFrame
sub esp,LocalStack ; After C style frame
stdCall _KeGetCurrentIrql
push eax ; Local Varible
cmp al, DISPATCH_LEVEL ; Is irql > Dispatch_level?
jae short Kac00
; Raise to Dispatch Level
mov eax, esp
stdCall _KeRaiseIrql, <DISPATCH_LEVEL,eax>
Kac00:
;
; Set up parameters on stack before remapping stack.
;
push word ptr KGDT_CDA16 ; CDA anchor selector
push KacRequestBlock ; Request Block
push KacFunctionTable ; Func transfer table
push KacDeviceBlock ; Device Block
mov ebx, KacAbiosFunction ; (ebx)-> Abios Entry
;
; Remap current stack to 16:16 stack. The base of the 16bit stack selector is
; the base of current kernel stack.
;
inc _KiInBiosCall ; Set the 'In Bios' flag
if DBG
cmp _KiInBiosCall,2
jb @F
push offset FLAT:KiBiosReenteredAssert
call _dbgPrint
add esp, 4
@@:
endif
STACK32_TO_STACK16 ; Switch to 16bit stack
push word ptr KGDT_CODE16
IFDEF STD_CALL
push word ptr (offset FLAT:Kac40 - offset FLAT:_KiI386CallAbios@16)
push KGDT_CODE16
push offset FLAT:Kac30 - offset FLAT:_KiI386CallAbios@16
ELSE
push word ptr (offset FLAT:Kac40 - offset FLAT:_KiI386CallAbios)
push KGDT_CODE16
push offset FLAT:Kac30 - offset FLAT:_KiI386CallAbios
ENDIF
retf
Kac30:
;
; Stack switching (from 32 to 16) turns interrupt off. We must turn it
; back on.
;
sti
push bx ; Yes, BX not EBX!
retf
Kac40:
add esp, 14 ; pop out all the parameters
STACK16_TO_STACK32 ; switch back to 32 bit stack
;
; Pull callers flat return address off stack and push the
; flat code selector followed by the return offset, then
; execute a far return and we'll be back in the 32-bit code space.
;
db OPERAND_OVERRIDE
push KGDT_R0_CODE
db OPERAND_OVERRIDE
push offset FLAT:Kac50
db OPERAND_OVERRIDE
retf
Kac50:
pop eax ; [eax] = OldIrql
pop ebx ; restore ebx
cmp al, DISPATCH_LEVEL
jae short Kac60
stdCall _KeLowerIrql, <eax> ; Lower irql to original level
Kac60:
dec _KiInBiosCall ;Clear 'In Bios' Flag
add esp,LocalStack ; subtract off the scratch space
pop ebp
stdRET _KiI386CallAbios
stdENDP _KiI386CallAbios
;; ********************************************************
;;
;; BEGIN - power_management
;;
;;
;++
; VOID
; KeI386Call16BitFunction (
; IN OUT PCONTEXT Regs
; )
;
; Routine Description:
;
; This function calls the 16 bit function specified in the Regs.
;
; Parameters:
;
; Regs - supplies a pointer to register context to call 16 function.
;
; NOTE: Caller must be at DPC_LEVEL
;
;--
cPublicProc _KeI386Call16BitFunction,1
; verify CurrentIrql
; verify context flags
push ebp ; save nonvolatile registers
push ebx
push esi
push edi
mov ebx, dword ptr [esp + 20] ; (ebx)-> Context
COPY_CALL_FRAME _KiBiosFrame
sub esp,LocalStack ; After prolog
inc _KiInBiosCall ; Set the 'In Bios' flag
if DBG
cmp _KiInBiosCall,2
jb @F
push offset FLAT:KiBiosReenteredAssert
call _dbgPrint
add esp, 4
@@:
endif
;
; We're using a 32bit CS:EIP - go to a 16bit CS:IP
; Note the base of KiAbiosCallSelector is the flat address of _KiI386AbiosCall
; routine.
;
;
; Remap current stack to 16:16 stack. The base of the 16bit stack selector is
; the base of current kernel stack.
;
STACK32_TO_STACK16 ; Switch to 16bit stack
;
; Push return address from 16 bit function call to kernel
;
push word ptr KGDT_CODE16
push word ptr (offset FLAT:Kbf40 - offset FLAT:_KiI386CallAbios@16)
;
; Load context to call with
;
push word ptr [ebx].CsEFlags
push word ptr [ebx].CsSegCs
push word ptr [ebx].CsEip
mov eax, [ebx].CsEax
mov ecx, [ebx].CsEcx
mov edx, [ebx].CsEdx
mov edi, [ebx].CsEdi
mov esi, [ebx].CsEsi
mov ebp, [ebx].CsEbp
push [ebx].CsSegGs
push [ebx].CsSegFs
push [ebx].CsSegEs
push [ebx].CsSegDs
mov ebx, [ebx].CsEbx
pop ds
pop es
pop fs
pop gs
;
; Switch to 16bit CS
;
push KGDT_CODE16
push offset FLAT:Kbf30 - offset FLAT:_KiI386CallAbios@16
retf
Kbf30:
;
; "call" to 16 bit function
;
iretd
Kbf40:
;
; Push some of the returned context which will be needed to
; switch back to the 32 bit SS & CS.
;
db OPERAND_OVERRIDE
push ds
db OPERAND_OVERRIDE
push es
db OPERAND_OVERRIDE
push fs
db OPERAND_OVERRIDE
push gs
db OPERAND_OVERRIDE
push eax
db OPERAND_OVERRIDE
pushfd
db OPERAND_OVERRIDE
mov eax, KGDT_R0_PCR
mov fs, ax
db OPERAND_OVERRIDE
mov eax, KGDT_R3_DATA OR RPL_MASK
mov ds, ax
mov es, ax
xor eax, eax
;
; Switch back to 32 bit stack
;
STACK16_TO_STACK32
;
; Push the flat code selector followed by the return offset, then
; execute a far return and we'll be back in the 32-bit code space.
;
db OPERAND_OVERRIDE
push KGDT_R0_CODE
db OPERAND_OVERRIDE
push offset FLAT:Kbf50
db OPERAND_OVERRIDE
retf
Kbf50:
;
; Return resulting context
;
mov eax, dword ptr [esp+44+LocalStack] ; (eax) = Context Record
pop [eax].CsEflags
pop [eax].CsEax
pop [eax].CsSegGs
pop [eax].CsSegFs
pop [eax].CsSegEs
pop [eax].CsSegDs
mov [eax].CsEbx, ebx
mov [eax].CsEcx, ecx
mov [eax].CsEdx, edx
mov [eax].CsEdi, edi
mov [eax].CsEsi, esi
mov [eax].CsEbp, ebp
;
; Restore regs & return
;
dec _KiInBiosCall ; Clear the 'In Bios' flag
add esp,LocalStack ;remove scratch space
pop edi
pop esi
pop ebx
pop ebp
stdRET _KeI386Call16BitFunction
stdENDP _KeI386Call16BitFunction
;++
; USHORT
; KeI386Call16BitCStyleFunction (
; IN ULONG EntryOffset,
; IN ULONG EntrySelector,
; IN PUCHAR Parameters,
; IN ULONG Size
; )
;
; Routine Description:
;
; This function calls the 16 bit function which supports C style calling convension.
;
; Parameters:
;
; EntryOffset and EntrySelector - specifies the entry point of the 16 bit function.
;
; Parameters - supplies a pointer to a parameter block which will be
; passed to 16 bit function as parameters.
;
; Size - supplies the size of the parameter block.
;
; NOTE: Caller must be at DPC_LEVEL
;
; Returned Value:
;
; AX returned by 16 bit function.
;
;--
cPublicProc _KeI386Call16BitCStyleFunction,4
;
; verify CurrentIrql
; verify context flags
;
push ebp ; save nonvolatile registers
push ebx
push esi
push edi
COPY_CALL_FRAME _KiBiosFrame
inc _KiInBiosCall ; Set the 'In Bios' flag
if DBG
cmp _KiInBiosCall,2
jb @F
push offset FLAT:KiBiosReenteredAssert
call _dbgPrint
add esp, 4
@@:
endif
mov edi, esp
sub esp,LocalStack ; now, add in some scratch space
mov esi, dword ptr [esp + LocalStack +28] ; (esi)->BiosParameters
or esi, esi
jz short @f
mov ecx, [esp + LocalStack +32] ; (ecx) = parameter size
sub esp, ecx ; allocate space on TOS to copy parameters
mov edi, esp
rep movsb ; (edi)-> Top of nonvolatile reg save area
add edi, LocalStack ; edi now points to original stack
@@:
;
; We're using a 32bit CS:EIP - go to a 16bit CS:IP
; Note the base of KiAbiosCallSelector is the flat address of _KiI386AbiosCall
; routine.
;
;
; Remap current stack to 16:16 stack. The base of the 16bit stack selector is
; the base of current kernel stack.
;
STACK32_TO_STACK16 ; Switch to 16bit stack
;
; Push return address from 16 bit function call to kernel
;
push word ptr KGDT_CODE16
push word ptr (offset FLAT:Kbfex40 - offset FLAT:_KiI386CallAbios@16)
push word ptr 0200h ; flags
push word ptr [edi + 24 ] ; entry selector
push word ptr [edi + 20 ] ; entry offset
;
; Switch to 16bit CS
;
push KGDT_CODE16
push offset FLAT:Kbfex30 - offset FLAT:_KiI386CallAbios@16
retf
Kbfex30:
;
; "call" to 16 bit function
;
iretd
Kbfex40:
;
; Save return value.
;
db OPERAND_OVERRIDE
push eax
;
; Restore Flat mode segment registers.
;
db OPERAND_OVERRIDE
mov eax, KGDT_R0_PCR
mov fs, ax
db OPERAND_OVERRIDE
mov eax, KGDT_R3_DATA OR RPL_MASK
mov ds, ax
mov es, ax
xor eax, eax
;
; Switch back to 32 bit stack
;
STACK16_TO_STACK32
;
; Push the flat code selector followed by the return offset, then
; execute a far return and we'll be back in the 32-bit code space.
;
db OPERAND_OVERRIDE
push KGDT_R0_CODE
db OPERAND_OVERRIDE
push offset FLAT:Kbfex50
db OPERAND_OVERRIDE
retf
Kbfex50:
pop eax
;
; Restore regs & return
;
dec _KiInBiosCall ; Clear the 'In Bios' flag
mov esp, edi ; Also removes the scratch space!
pop edi
pop esi
pop ebx
pop ebp
stdRET _KeI386Call16BitCStyleFunction
stdENDP _KeI386Call16BitCStyleFunction
;
; BBT cannot instrument code between BBT_Exclude_Selector_Code_Begin and this label
;
public _BBT_Exclude_Selector_Code_End
_BBT_Exclude_Selector_Code_End equ $
int 3
;;
;; END - power_management
;;
;; ********************************************************
public _KiEndOfCode16
_KiEndOfCode16 equ $
_TEXT ends
end