|
|
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
|