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