723 lines
17 KiB
NASM
723 lines
17 KiB
NASM
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
|