527 lines
12 KiB
NASM
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
|