Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

315 lines
6.3 KiB

;++
;
;Copyright (c) 2000 Microsoft Corporation
;
;Module Name:
;
; amd64s.asm
;
;Abstract:
;
; Contains routines to aid in detecting and enabling Amd64 long mode.
;
;Author:
;
; Forrest Foltz (forrestf) 04-20-00
;
;
;Revision History:
;
;--
.586p
.xlist
include ks386.inc
.list
extrn _BlAmd64GdtDescriptor:QWORD
extrn _BlAmd64IdtDescriptor:QWORD
extrn _BlAmd64IdleStack64:QWORD
extrn _BlAmd64TopLevelPte:QWORD
extrn _BlAmd64KernelEntry:QWORD
extrn _BlAmd64LoaderParameterBlock:QWORD
extrn _BlAmd64_MSR_EFER:DWORD
extrn _BlAmd64_MSR_EFER_Flags:DWORD
extrn _BlAmd64_MSR_GS_BASE:DWORD
extrn _BlAmd64_KGDT64_SYS_TSS:WORD
extrn _BlAmd32GdtDescriptor:QWORD
extrn _HiberInProgress:DWORD
OP64 macro
db 048h
endm
ICEBP macro
db 0f1h
endm
;
; LOADREG loads the 64-bit contents of a memory location specified by
; a 32-bit immediate address.
;
; The resultant 64-bit address is zero-extended, as a result this macro
; only works with addresses < 2^32.
;
; This macro also assumes that esi is zero.
;
LDREG64 macro reg, address
OP64
mov reg, ds:[esi + offset address]
endm
_TEXT SEGMENT PARA PUBLIC 'CODE'
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
EFLAGS_ID equ 200000h
;++
;
; BOOLEAN
; BlIsAmd64Supported (
; VOID
; )
;
; Routine Description:
;
; This rouine determines whether the current processor supports AMD64
; mode, a.k.a. "long mode".
;
; Arguments:
;
; None.
;
; Return value:
;
; 0 if long mode is not supported, non-zero otherwise.
;
;--
public _BlIsAmd64Supported@0
_BlIsAmd64Supported@0 proc
;
; First determine whether the CPUID instruction is supported. If
; the EFLAGS_ID bit "sticks" when popped into the flags
; register then the CPUID instruction is available.
;
mov ecx, EFLAGS_ID
pushfd
pop eax ; eax == flags
xor ecx, eax ; ecx == flags ^ EFLAGS_ID
push ecx
popfd ; load new flags
pushfd
pop ecx ; ecx == result of flag load
xor eax, ecx ; Q: did the EFLAGS_ID bit stick?
jz done ; N: CPUID is not available
;
; We can use the CPUID instruction. Detect whether this is an
; AMD processor and if so whether long mode is supported.
;
push ebx ; CPUID steps on eax, ebx, ecx, edx
xor eax, eax ; eax = 0
cpuid
xor eax, eax ; Assume no long mode
cmp ebx, 'htuA' ; Q: ebx == 'Auth' ?
jne nolong ; N: no long mode
;
; We have an AMD processor, now determine whether long mode is
; available.
;
mov eax, 80000001h
xor edx, edx
cpuid
bt edx, 29 ; Q: Bit 29 is long mode bit, is it set?
sbb eax, eax ; Yes (eax != 0) if carry set, else eax == 0
nolong: pop ebx
done: ret
_BlIsAmd64Supported@0 endp
;++
;
; VOID
; BlAmd64SwitchToLongMode (
; VOID
; )
;
; Routine Description:
;
; Arguments:
;
; None.
;
; Return value:
;
; None.
;
;--
public _BlAmd64SwitchToLongMode@0
_BlAmd64SwitchToLongMode@0 proc
public _BlAmd64SwitchToLongModeStart
_BlAmd64SwitchToLongModeStart label dword
;
; Save the value of _HiberInProgress before disabling paging
;
mov ebx, dword ptr [_HiberInProgress]
cli
;
; Disable paging
;
mov eax, cr0
and eax, NOT CR0_PG
mov cr0, eax
jmp $+2
;
; Enable XMM and physical address extensions (paging still off)
;
mov eax, cr4
or eax, CR4_PAE OR CR4_FXSR OR CR4_XMMEXCPT OR CR4_PGE
mov cr4, eax
;
; Reference the four-level paging structure. This must exist
; below 4G physical (in fact it is somewhere in the low 32MB)
;
mov eax, DWORD PTR [_BlAmd64TopLevelPte]
and eax, 0FFFFF000h
mov cr3, eax
;
; Set Long Mode enable and enable syscall
;
mov ecx, [_BlAmd64_MSR_EFER]
rdmsr
or eax, [_BlAmd64_MSR_EFER_Flags]
wrmsr
;
; Turn paging on. Also turn on the write protect and alignment mask
; bits
;
mov eax, cr0
or eax, CR0_PG OR CR0_WP OR CR0_AM OR CR0_NE
mov cr0, eax
jmp $+2
;
; Return if we are waking up from hibernate.
;
cmp ebx, 1
jnz @f
ret
;
; Load the new global descriptor table. Note that because we're
; not in long mode (current code selector indicates compatibility
; mode), only a 32-bit base is loaded here.
;
@@: lgdt fword ptr _BlAmd32GdtDescriptor
;
; Far jump to the 64-bit code segment.
;
db 0eah
dd start64
;
; The following selector is set in amd64.c, BlAmd64BuildAmd64GDT, and
; is included as part of the far jump instruction.
;
public _BlAmd64_KGDT64_R0_CODE
_BlAmd64_KGDT64_R0_CODE:
dw ?
start64:
;
; Zero rsi so that the LDREG64 macros work
;
sub esi, esi ; zero rsi (zeroed esi is sign extended)
;
; Running in long mode now. Execute another lgdt, this one
; referencing the 64-bit mapping of the gdt.
;
; Note that an esi-relative address is used to avoid RIP-relative
; addressing.
;
; Keep in mind that a 32-bit assembler is used here to generate
; long-mode code.
;
lgdt fword ptr ds:[esi + offset _BlAmd64GdtDescriptor]
;
; Load the new interrupt descriptor table
;
lidt fword ptr ds:[esi + offset _BlAmd64IdtDescriptor]
;
; Switch stacks to the 64-bit idle stack
;
LDREG64 esp, _BlAmd64IdleStack64
;
; Set the current TSS
;
LDREG64 eax, _BlAmd64_KGDT64_SYS_TSS
ltr ax
;
; Set ss to the kernel-mode SS value (0)
;
sub eax, eax ; zero rax
mov ss, ax
;
; Allocate space on the stack for a parameter target area and jump
; to the kernel entrypoint. Rather than a call, we push a return
; address of zero to indicate to any stack walkers that this is the
; end.
;
push eax ; push null return address
LDREG64 ecx, _BlAmd64LoaderParameterBlock
LDREG64 eax, _BlAmd64KernelEntry
jmp eax ; jmp rax
public _BlAmd64SwitchToLongModeEnd
_BlAmd64SwitchToLongModeEnd label dword
_BlAmd64SwitchToLongMode@0 endp
_TEXT ends