434 lines
6.8 KiB
NASM
434 lines
6.8 KiB
NASM
TITLE "AMD64 Support Routines"
|
|
;++
|
|
;
|
|
; Copyright (c) 2000 Microsoft Corporation
|
|
;
|
|
; Module Name:
|
|
;
|
|
; miscs.asm
|
|
;
|
|
; Abstract:
|
|
;
|
|
; This module implements various routines for the AMD64 that must be
|
|
; written in assembler.
|
|
;
|
|
; Author:
|
|
;
|
|
; Forrest Foltz (forrestf) 14-Oct-2000
|
|
;
|
|
; Environment:
|
|
;
|
|
; Kernel mode only.
|
|
;
|
|
;--
|
|
|
|
include kxamd64.inc
|
|
include ksamd64.inc
|
|
|
|
extern HalpMcaExceptionHandler:proc
|
|
|
|
;++
|
|
;
|
|
; ULONG
|
|
; HalpGetprocessorFlags(
|
|
; VOID
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This function retrieves and returns the contents of the processor's
|
|
; flag register.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; None.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; The contents of the processor's flag register.
|
|
;
|
|
;--
|
|
|
|
HdiFrame struct
|
|
FlagsLow dd ? ; processor flags, low
|
|
FlagsHi dd ? ; processor flags, high
|
|
HdiFrame ends
|
|
|
|
NESTED_ENTRY HalpGetProcessorFlags, _TEXT$00
|
|
|
|
push_eflags ; get processor flags
|
|
|
|
END_PROLOGUE
|
|
|
|
pop rax
|
|
ret
|
|
|
|
NESTED_END HalpGetProcessorFlags, _TEXT$00
|
|
|
|
;++
|
|
;
|
|
; VOID
|
|
; HalProcessorIdle(
|
|
; VOID
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This function is called when the current processor is idle.
|
|
;
|
|
; This function is called with interrupts disabled, and the processor
|
|
; is idle until it receives an interrupt. The does not need to return
|
|
; until an interrupt is received by the current processor.
|
|
;
|
|
; This is the lowest level of processor idle. It occurs frequently,
|
|
; and this function (alone) should not put the processor into a
|
|
; power savings mode which requeres large amount of time to enter & exit.
|
|
;
|
|
; Return Value:
|
|
;
|
|
;--
|
|
|
|
LEAF_ENTRY HalProcessorIdle, _TEXT$00
|
|
|
|
;
|
|
; the following code sequence "sti-halt" puts the processor
|
|
; into a Halted state, with interrupts enabled, without processing
|
|
; an interrupt before halting. The STI instruction has a delay
|
|
; slot such that it does not take effect until after the instruction
|
|
; following it - this has the effect of HALTing without allowing
|
|
; a possible interrupt and then enabling interrupts while HALTed.
|
|
;
|
|
|
|
;
|
|
; On an MP hal we don't stop the processor, since that causes
|
|
; the SNOOP to slow down as well
|
|
;
|
|
|
|
sti
|
|
|
|
ifdef NT_UP
|
|
hlt
|
|
endif
|
|
|
|
;
|
|
; Now return to the system. If there's still no work, then it
|
|
; will call us back to halt again.
|
|
;
|
|
|
|
ret
|
|
|
|
LEAF_END HalProcessorIdle, _TEXT$00
|
|
|
|
;++
|
|
;
|
|
; VOID
|
|
; HalpGenerateAPCInterrupt(
|
|
; VOID
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This function generates an APC software interrupt.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; None.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None.
|
|
;
|
|
;--
|
|
|
|
LEAF_ENTRY HalpGenerateAPCInterrupt, _TEXT$00
|
|
|
|
int 1
|
|
ret
|
|
|
|
LEAF_END HalpGenerateAPCInterrupt, _TEXT$00
|
|
|
|
;++
|
|
;
|
|
; VOID
|
|
; HalpGenerateDPCInterrupt(
|
|
; VOID
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This function generates an DPC software interrupt.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; None.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None.
|
|
;
|
|
;--
|
|
|
|
LEAF_ENTRY HalpGenerateDPCInterrupt, _TEXT$00
|
|
|
|
int 2
|
|
ret
|
|
|
|
LEAF_END HalpGenerateDPCInterrupt, _TEXT$00
|
|
|
|
;++
|
|
;
|
|
; VOID
|
|
; HalpGenerateUnexpectedInterrupt(
|
|
; VOID
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This function generates an unexpected software interrupt.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; None.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None.
|
|
;
|
|
;--
|
|
|
|
LEAF_ENTRY HalpGenerateUnexpectedInterrupt, _TEXT$00
|
|
|
|
int 0
|
|
ret
|
|
|
|
LEAF_END HalpGenerateUnexpectedInterrupt, _TEXT$00
|
|
|
|
;++
|
|
;
|
|
; VOID
|
|
; HalpHalt (
|
|
; VOID
|
|
; );
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; Executes a hlt instruction. Should the hlt instruction execute,
|
|
; control is returned to the caller.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; None.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None.
|
|
;
|
|
;--*/
|
|
|
|
LEAF_ENTRY HalpHalt, _TEXT$0
|
|
|
|
hlt
|
|
ret
|
|
|
|
LEAF_END HalpHalt, _TEXT$0
|
|
|
|
;++
|
|
;
|
|
; VOID
|
|
; HalpIoDelay (
|
|
; VOID
|
|
; );
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; Generate a delay after port I/O.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; None.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None.
|
|
;
|
|
;--
|
|
|
|
LEAF_ENTRY HalpIoDelay, _TEXT$00
|
|
|
|
jmp $+2
|
|
jmp $+2
|
|
ret
|
|
|
|
LEAF_END HalpIoDelay, _TEXT$00
|
|
|
|
|
|
;++
|
|
;
|
|
; VOID
|
|
; HalpSerialize (
|
|
; VOID
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This function implements the fence operation for out-of-order execution
|
|
;
|
|
; Arguments:
|
|
;
|
|
; None
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None
|
|
;
|
|
;--
|
|
|
|
HsFrame struct
|
|
SavedRbx dq ? ; preserve RBX
|
|
HsFrame ends
|
|
|
|
NESTED_ENTRY HalpSerialize, _TEXT$00
|
|
|
|
push_reg rbx
|
|
|
|
END_PROLOGUE
|
|
|
|
cpuid
|
|
pop rbx
|
|
ret
|
|
|
|
NESTED_END HalpSerialize, _TEXT$00
|
|
|
|
|
|
;++
|
|
;
|
|
; StartPx_LMStub
|
|
;
|
|
; This routine is entered during startup of a secondary processor. We
|
|
; have just left StartPx_PMStub (xmstub.asm) and are running on an
|
|
; identity-mapped address space.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; rdi -> idenity-mapped address of PROCESSOR_START_BLOCK
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None
|
|
;
|
|
;--
|
|
|
|
LEAF_ENTRY HalpLMStub, _TEXT$00
|
|
|
|
;
|
|
; Get the final CR3 value, set rdi to the self-map address of
|
|
; the processor start block, and set CR3. We are now executing
|
|
; in image-loaded code, rather than code that has been copied to
|
|
; low memory.
|
|
;
|
|
|
|
mov rax, [rdi] + PsbProcessorState + PsCr3
|
|
mov rdi, [rdi] + PsbSelfMap
|
|
mov cr3, rax
|
|
|
|
lea rsi, [rdi] + PsbProcessorState
|
|
ltr WORD PTR [rsi] + SrTr
|
|
|
|
;
|
|
; Load this processor's GDT and IDT. Because PSB_GDDT32_CODE64 is
|
|
; identical to KGDT64_R0_CODE (asserted in mpsproca.c), no far jump
|
|
; is necessary to load a new CS.
|
|
;
|
|
|
|
lgdt fword ptr [rsi] + PsSpecialRegisters + SrGdtr
|
|
lidt fword ptr [rsi] + PsSpecialRegisters + SrIdtr
|
|
|
|
;
|
|
; Set rdx to point to the context frame and load the segment
|
|
; registers.
|
|
;
|
|
|
|
lea rdx, [rdi] + PsbProcessorState + PsContextFrame
|
|
mov es, [rdx] + CxSegES
|
|
mov fs, [rdx] + CxSegFS
|
|
mov gs, [rdx] + CxSegGS
|
|
mov ss, [rdx] + CxSegSS
|
|
|
|
;
|
|
; Load the debug registers
|
|
;
|
|
|
|
cld
|
|
xor rax, rax
|
|
mov dr7, rax
|
|
|
|
add esi, SrKernelDr0
|
|
|
|
.errnz (SrKernelDr1 - SrKernelDr0 - 1 * 8)
|
|
.errnz (SrKernelDr2 - SrKernelDr0 - 2 * 8)
|
|
.errnz (SrKernelDr3 - SrKernelDr0 - 3 * 8)
|
|
.errnz (SrKernelDr6 - SrKernelDr0 - 4 * 8)
|
|
.errnz (SrKernelDr7 - SrKernelDr0 - 5 * 8)
|
|
|
|
lodsq
|
|
mov dr0, rax
|
|
|
|
lodsq
|
|
mov dr1, rax
|
|
|
|
lodsq
|
|
mov dr2, rax
|
|
|
|
lodsq
|
|
mov dr3, rax
|
|
|
|
lodsq
|
|
mov dr6, rax
|
|
|
|
lodsq
|
|
mov dr7, rax
|
|
|
|
;
|
|
; Load the stack pointer, eflags and store the new IP in
|
|
; a return frame. Also push two registers that will be used
|
|
; to the very end.
|
|
;
|
|
|
|
mov rsp, [rdx] + CxRsp
|
|
|
|
pushq [rdx] + CxEflags
|
|
popfq
|
|
|
|
pushq [rdx] + CxRip
|
|
push rdx
|
|
push rdi
|
|
|
|
mov rax, [rdx] + CxRax
|
|
mov rbx, [rdx] + CxRbx
|
|
mov rcx, [rdx] + CxRcx
|
|
mov rsi, [rdx] + CxRsi
|
|
mov rbp, [rdx] + CxRbp
|
|
mov r8, [rdx] + CxR8
|
|
mov r9, [rdx] + CxR9
|
|
mov r10, [rdx] + CxR10
|
|
mov r11, [rdx] + CxR11
|
|
mov r12, [rdx] + CxR12
|
|
mov r13, [rdx] + CxR13
|
|
mov r14, [rdx] + CxR14
|
|
mov r15, [rdx] + CxR15
|
|
|
|
;
|
|
; Indicate that we've started, pop the remaining two registers and
|
|
; return.
|
|
;
|
|
|
|
inc DWORD PTR [rdi] + PsbCompletionFlag
|
|
|
|
pop rdi
|
|
pop rsi
|
|
ret
|
|
|
|
LEAF_END HalpLMStub, _TEXT$00
|
|
|
|
END
|