windows-nt/Source/XPSP1/NT/base/boot/lib/i386/wakea.asm
2020-09-26 16:20:57 +08:00

527 lines
12 KiB
NASM

;++
;
;Copyright (c) 1997 Microsoft Corporation
;
;Module Name:
;
; wakea.asm
;
;Abstract:
;
;
;Author:
;
; Ken Reneris (kenr) 05-May-1997
;
;Revision History:
;
;--
.586p
.xlist
include ks386.inc
include callconv.inc ; calling convention macros
.list
extrn _HiberPtes:DWORD
extrn _HiberVa:DWORD
extrn _HiberFirstRemap:DWORD
extrn _HiberLastRemap:DWORD
extrn _HiberPageFrames:DWORD
extrn _HiberTransVa:DWORD
extrn _HiberIdentityVa:DWORD
extrn _HiberImageFeatureFlags:DWORD
extrn _HiberBreakOnWake:BYTE
extrn _HiberImagePageSelf:DWORD
DBGOUT macro Value
; push edx
; push eax
; mov edx, 80h
; mov al, Value
; out dx, al
; pop eax
; pop edx
endm
; These equates must match the defines in po.h
XPRESS_MAX_PAGES equ 16
;
; These equates must match the defines in bldr.h
;
PTE_SOURCE equ 0
PTE_DEST equ 1
PTE_MAP_PAGE equ 2
PTE_REMAP_PAGE equ 3
PTE_HIBER_CONTEXT equ 4
PTE_TRANSFER_PDE equ 5
PTE_WAKE_PTE equ 6
PTE_DISPATCHER_START equ 7
PTE_XPRESS_DEST_FIRST equ 9
PTE_XPRESS_DEST_LAST equ (PTE_XPRESS_DEST_FIRST + XPRESS_MAX_PAGES)
HIBER_PTES equ (16 + XPRESS_MAX_PAGES)
;
; Processor paging defines
;
PAGE_SIZE equ 4096
PAGE_SHIFT equ 12
PAGE_MASK equ (PAGE_SIZE - 1)
PTE_VALID equ 23h
PDE_SHIFT equ 22
PTE_SHIFT equ 12
PTE_INDEX_MASK equ 3ffh
;
; Internal defines and structures
;
STACK_SIZE equ 1024
HbGdt struc
Limit dw ?
Base dd ?
Pad dw ?
HbGdt ends
HbContextBlock struc
WakeContext db processorstatelength dup (?)
OldEsp dd ?
PteVa dd ?
TransCr3 dd ?
TransPteVa dd ?
WakeHiberVa dd ?
Buffer dd ?
MapIndex dd ?
LastMapIndex dd ?
FeatureFlags dd ?
Gdt db size HbGdt dup (?)
Stack db STACK_SIZE dup (?)
BufferData db ? ; buffer starts here
HbContextBlock ends
;
; Addresses based from ebp
;
SourcePage equ [ebp + PAGE_SIZE * PTE_SOURCE]
DestPage equ [ebp + PAGE_SIZE * PTE_DEST]
Map equ [ebp + PAGE_SIZE * PTE_MAP_PAGE]
Remap equ [ebp + PAGE_SIZE * PTE_REMAP_PAGE]
Context equ [ebp + PAGE_SIZE * PTE_HIBER_CONTEXT].HbContextBlock
_TEXT SEGMENT PARA PUBLIC 'CODE' ; Start 32 bit code
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
;++
;
; VOID
; WakeDispatch (
; )
;
; Routine Description:
;
; Relocatable code which copies any remap page to it's final resting
; place and then restores the processors wake context.
;
; Arguments:
;
; Return
;
; Only returns if there's an internal failure
;
;--
cPublicProc _WakeDispatcher, 0
public _WakeDispatcherStart
_WakeDispatcherStart label dword
push ebp
push ebx
push esi
push edi
;
; Load EBP with base of hiber va. Everything will be relative from EBP
;
mov ebp, _HiberVa
;
; Initialize HbContextBlock
;
mov eax, _HiberFirstRemap
mov ecx, _HiberLastRemap
lea edx, Context.BufferData
mov esi, _HiberPtes
mov Context.MapIndex, eax
mov Context.LastMapIndex, ecx
mov Context.OldEsp, esp
mov Context.Buffer, edx
mov Context.PteVa, esi
mov eax, _HiberPageFrames [PTE_TRANSFER_PDE * 4]
mov ecx, _HiberTransVa
mov edx, _HiberIdentityVa
mov Context.TransCr3, eax
mov Context.TransPteVa, ecx
mov Context.WakeHiberVa, edx
mov eax, _HiberImageFeatureFlags
mov Context.FeatureFlags, eax
DBGOUT 1
;
; Copy gdt to shared buffer and switch to it
;
sgdt fword ptr Context.Gdt
movzx ecx, Context.Gdt.Limit
inc ecx
push ecx
call AllocateHeap
pop ecx
mov edi, eax
mov esi, Context.Gdt.Base
rep movsb
mov Context.Gdt.Base, eax
lgdt fword ptr Context.Gdt
sub eax, ebp
add eax, Context.WakeHiberVa
mov Context.Gdt.Base, eax
;
; Locate hiber ptes in hibernated image. First get the PDE, then find
; the PTE for the hiber ptes.
;
mov eax, dword ptr Context.WakeContext.PsSpecialRegisters.SrCr3
shr eax, PAGE_SHIFT
call LocatePage
push eax
push PTE_SOURCE
call SetPte
mov ecx, Context.WakeHiberVa
shr ecx, PDE_SHIFT ; (ecx) = index into PDE
mov eax, [eax+ecx*4] ; (eax) = PDE for WakeHiberVa PTE
shr eax, PAGE_SHIFT
call LocatePage
push eax
push PTE_SOURCE
call SetPte
mov ecx, Context.WakeHiberVa
shr ecx, PTE_SHIFT
and ecx, PTE_INDEX_MASK ; (ecx) = index into PTE
lea edi, [eax+ecx*4] ; (edi) = address of WakeHiber PTEs
;
; Copy the current HiberPtes to the wake image Ptes
;
mov esi, Context.PteVa
mov ecx, HIBER_PTES
rep movsd
;
; If break on wake, set the image header signature in destionation
;
cmp _HiberBreakOnWake, 0
jz short hd05
mov eax, _HiberImagePageSelf
call LocatePage
push eax
push PTE_DEST
call SetPte
mov dword ptr [eax], 706B7262h ; 'brkp'
;
; Switch to transition CR3
;
hd05:
DBGOUT 2
mov ebx, Context.WakeHiberVa
mov eax, Context.TransCr3
shl eax, PAGE_SHIFT
mov cr3, eax
;
; Move to wake images hiber va
;
mov edi, ebx
add ebx, PTE_DISPATCHER_START * PAGE_SIZE
add ebx, offset hd10 - offset _WakeDispatcherStart
jmp ebx
hd10: mov ebp, edi
mov eax, Context.TransPteVa
mov Context.PteVa, eax
lea esp, Context.Stack + STACK_SIZE
lgdt fword ptr Context.Gdt
;
; Copy all pages to final locations
;
DBGOUT 3
mov edx, Context.MapIndex
hd30: cmp edx, Context.LastMapIndex
jnc short hd40
push dword ptr Map.[edx*4]
push PTE_SOURCE
call SetPte
mov esi, eax
push dword ptr Remap.[edx*4]
push PTE_DEST
call SetPte
mov edi, eax
mov ecx, PAGE_SIZE / 4
rep movsd
inc edx
jmp short hd30
;
; Restore processors wake context
;
hd40: DBGOUT 5
lea esi, Context.WakeContext.PsSpecialRegisters
mov eax, cr3 ; issue a couple of flushes
mov cr3, eax ; before enabling global ptes
mov cr3, eax
mov eax, [esi].SrCr4
test Context.FeatureFlags, KF_CR4
jz short hd50
mov cr4, eax
hd50: mov eax, [esi].SrCr3
mov cr3, eax
mov ecx, [esi].SrCr0
mov cr0, ecx ; on kernel's cr0
DBGOUT 6
mov ecx, [esi].SrGdtr+2 ; base of GDT
lgdt fword ptr [esi].SrGdtr ; load gdtr (w/matching flat cs & ds selectors)
lidt fword ptr [esi].SrIdtr ; load idtr
lldt word ptr [esi].SrLdtr ; load ldtr
movzx eax, word ptr [esi].SrTr ; tss selector
and byte ptr [eax+ecx+5], 0fdh ; clear the busy bit in the TSS
ltr ax ; load tr
mov ds, word ptr Context.WakeContext.PsContextFrame.CsSegDs
mov es, word ptr Context.WakeContext.PsContextFrame.CsSegEs
mov fs, word ptr Context.WakeContext.PsContextFrame.CsSegFs
mov gs, word ptr Context.WakeContext.PsContextFrame.CsSegGs
mov ss, word ptr Context.WakeContext.PsContextFrame.CsSegSs
mov ebx, dword ptr Context.WakeContext.PsContextFrame.CsEbx
mov ecx, dword ptr Context.WakeContext.PsContextFrame.CsEcx
mov edx, dword ptr Context.WakeContext.PsContextFrame.CsEdx
mov edi, dword ptr Context.WakeContext.PsContextFrame.CsEdi
mov esp, dword ptr Context.WakeContext.PsContextFrame.CsEsp
push dword ptr Context.WakeContext.PsContextFrame.CsEFlags
movzx eax, word ptr Context.WakeContext.PsContextFrame.CsSegCs
push eax
push dword ptr Context.WakeContext.PsContextFrame.CsEip
push dword ptr Context.WakeContext.PsContextFrame.CsEbp
push dword ptr Context.WakeContext.PsContextFrame.CsEsi
push dword ptr Context.WakeContext.PsContextFrame.CsEax
lea esi, Context.WakeContext.PsSpecialRegisters.SrKernelDr0
lodsd
mov dr0, eax ; load dr0-dr7
lodsd
mov dr1, eax
lodsd
mov dr2, eax
lodsd
mov dr3, eax
lodsd
mov dr6, eax
lodsd
mov dr7, eax
DBGOUT 7
pop eax
pop esi
pop ebp
iretd
; this exit is only used in the shared buffer overflows
Abort:
mov esp, Context.OldEsp
pop ebp
pop ebx
pop esi
pop edi
stdRET _WakeDispatcher
;++
;
; PUCHAR
; AllocateHeap (
; IN ULONG Length passed in ECX
; )
;
; Routine Description:
;
; Allocates the specified bytes from the wake context page.
;
; N.B. This function is part of HiberDispacther.
;
; Arguments:
; ECX - Length to allocate
;
; Returns:
; EAX - Virtual address of bytes allocated
;
; Uses:
; EAX, ECX, EDX
;
;--
AllocateHeap label proc
mov eax, Context.Buffer
mov edx, eax
test eax, 01fh ; round to 32 byte boundry
jz short ah20
and eax, not 01fh
add eax, 20h
ah20: add ecx, eax
mov Context.Buffer, ecx
xor ecx, edx
and ecx, 0ffffffffh - PAGE_MASK
jnz short Abort
ret
;++
;
; PUCHAR
; SetPte (
; IN ULONG PteIndex
; IN ULONG PageFrameNumber
; )
;
; Routine Description:
;
;
; N.B. This function is part of HiberDispacther.
;
; Arguments:
;
;
; Returns:
; EAX va of mapped pte
;
; Uses:
; EAX, ECX, EDX
;
;--
SetPte label proc
push ecx
mov eax, [esp+8] ; (eax) = pte index
shl eax, 2 ; * 4
add eax, Context.PteVa ; + pte base
mov ecx, [esp+12] ; (ecx) = page frame number
shl ecx, PAGE_SHIFT
or ecx, PTE_VALID
mov [eax], ecx ; set the Pte
mov eax, [esp+8]
shl eax, PAGE_SHIFT
add eax, ebp ; (eax) = va mapped by pte
invlpg [eax]
pop ecx
ret 8
;++
;
; ULONG
; LocatePage (
; IN ULONG PageNumber passed in eax
; )
;
; Routine Description:
;
; Find the page specified by page number in the wake context.
; The pagenumber must be a valid page.
;
; N.B. This function is part of HiberDispacther.
;
; Arguments:
; EAX - Length to allocate
;
; Returns:
; EAX - Virtual address of bytes allocated
;
; Uses:
; EAX, ECX, EDX
;
;--
LocatePage label proc
;
; Scan the remap entries for this page. If it's found, get the
; source address. If it's not found, then it's already at it's
; proper address
;
mov edx, Context.MapIndex
dec edx
lp10: inc edx
cmp edx, Context.LastMapIndex
jnc short lp20
cmp eax, Remap.[edx*4]
jnz short lp10
mov eax, Map.[edx*4]
lp20: ret
public _WakeDispatcherEnd
_WakeDispatcherEnd label dword
stdENDP _WakeDispatcher
_TEXT ends
end