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 HalpHiberInProgress:byte FLUSH_TB macro mov rcx, cr4 and rcx, NOT CR4_PGE mov cr4, rcx mov rax, cr3 mov cr3, rax or rcx, CR4_PGE mov cr4, rcx endm ;++ ; ; 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 ; 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 ;++ ; ; HalpLMIdentityStub ; ; This routine is entered during startup of a secondary processor. The ; contents of this routine is actually copied into the startup block ; (see mpsproca.c). It's purpose is to give StartPx_PMStub a 32-bit ; addressable target. ; ; The act of jumping here causes the processor to begin execution in ; long mode. Therefore, we can now perform a 64-bit jump to HalpLMStub. ; ; Arguments: ; ; rdi -> idenity-mapped address of PROCESSOR_START_BLOCK ; ; Return Value: ; ; None ; ;-- LEAF_ENTRY HalpLMIdentityStub, _TEXT$00 mov edi, edi ; zero extend high 32 bits mov rcx, QWORD PTR [rdi] + PsbLmTarget mov rax, QWORD PTR [rdi] + PsbProcessorState + PsCr3 mov rdi, QWORD PTR [rdi] + PsbSelfMap jmp rcx public HalpLMIdentityStubEnd HalpLMIdentityStubEnd:: LEAF_END HalpLMIdentityStub, _TEXT$00 ;++ ; ; HalpLMStub ; ; This routine is entered during startup of a secondary processor. We ; have just left StartPx_PMStub (xmstub.asm) and are running in an ; identity-mapped address space. ; ; Arguments: ; ; rax == Final CR3 to be used ; rdi -> idenity-mapped address of PROCESSOR_START_BLOCK ; ; Return Value: ; ; None ; ;-- LEAF_ENTRY HalpLMStub, _TEXT$00 ; ; Set the final CR3 value. We are now executing in image-loaded ; code, rather than code that has been copied to low memory. ; ; LEAF_ENTRY ensures 16-byte alignment, so the following two ; instructions are guaranteed to be on the same page. ; mov cr3, rax jmp $+2 ; ; Load the PAT and invalidate the TLB ; FLUSH_TB mov eax, [rdi] + PsbMsrPat mov edx, [rdi] + PsbMsrPat + 4 mov ecx, MSR_PAT wbinvd wrmsr wbinvd FLUSH_TB ; ; 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 [rdi] + PsbProcessorState + PsGdtr lidt fword ptr [rdi] + PsbProcessorState + PsIdtr ; ; Set rdx to point to the context frame and load the segment ; registers. ; mov ds, [rdi] + PsbProcessorState + PsContextFrame + CxSegDS mov es, [rdi] + PsbProcessorState + PsContextFrame + CxSegES mov fs, [rdi] + PsbProcessorState + PsContextFrame + CxSegFS mov gs, [rdi] + PsbProcessorState + PsContextFrame + CxSegGS mov ss, [rdi] + PsbProcessorState + PsContextFrame + CxSegSS ; ; Force the TSS descriptor into a non-busy state, so we don't fault ; when we load the TR. ; movzx eax, word ptr [rdi] + PsbProcessorState + SrTr ; get TSS selector add rax, [rdi] + PsbProcessorState + PsGdtr + 2 ; add TSS base and byte ptr [rax+5], NOT 2 ; clear the busy bit ; ; Load the task register ; ltr WORD PTR [rdi] + PsbProcessorState + SrTr ; ; Check if it is a fresh startup or a resume from hibernate ; mov al, HalpHiberInProgress cmp al, 0 jz @f ; ; We are waking up from lower power state. We should restore ; control registers and MSRs here. ; mov rax, [rdi] + PsbProcessorState + PsSpecialRegisters + PsCr8 mov cr8, rax mov ax, word ptr [rdi] + PsbProcessorState + PsLdtr lldt ax mov rdx, [rdi] + PsbProcessorState + PsSpecialRegisters + SrMsrGsBase mov eax, edx shr rdx, 32 mov ecx, MSR_GS_BASE wrmsr mov rdx, [rdi] + PsbProcessorState + PsSpecialRegisters + SrMsrGsSwap mov eax, edx shr rdx, 32 mov ecx, MSR_GS_SWAP wrmsr mov rdx, [rdi] + PsbProcessorState + PsSpecialRegisters + SrMsrStar mov eax, edx shr rdx, 32 mov ecx, MSR_STAR wrmsr mov rdx, [rdi] + PsbProcessorState + PsSpecialRegisters + SrMsrLStar mov eax, edx shr rdx, 32 mov ecx, MSR_LSTAR wrmsr mov rdx, [rdi] + PsbProcessorState + PsSpecialRegisters + SrMsrCStar mov eax, edx shr rdx, 32 mov ecx, MSR_CSTAR wrmsr mov rdx, [rdi] + PsbProcessorState + PsSpecialRegisters + SrMsrSyscallMask mov eax, edx shr rdx, 32 mov ecx, MSR_SYSCALL_MASK wrmsr ; ; Load the debug registers ; @@: xor rax, rax mov dr7, rax lea rsi, [rdi] + PsbProcessorState + 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. ; ; Note that up to this point, no stack is available. ; mov rsp, [rdi] + PsbProcessorState + PsContextFrame + CxRsp pushq [rdi] + PsbProcessorState + PsContextFrame + CxEflags popfq pushq [rdi] + PsbProcessorState + PsContextFrame + CxRip pushq [rdi] + PsbProcessorState + PsContextFrame + CxRdi mov rax, [rdi] + PsbProcessorState + PsContextFrame + CxRax mov rbx, [rdi] + PsbProcessorState + PsContextFrame + CxRbx mov rcx, [rdi] + PsbProcessorState + PsContextFrame + CxRcx mov rdx, [rdi] + PsbProcessorState + PsContextFrame + CxRdx mov rsi, [rdi] + PsbProcessorState + PsContextFrame + CxRsi mov rbp, [rdi] + PsbProcessorState + PsContextFrame + CxRbp mov r8, [rdi] + PsbProcessorState + PsContextFrame + CxR8 mov r9, [rdi] + PsbProcessorState + PsContextFrame + CxR9 mov r10, [rdi] + PsbProcessorState + PsContextFrame + CxR10 mov r11, [rdi] + PsbProcessorState + PsContextFrame + CxR11 mov r12, [rdi] + PsbProcessorState + PsContextFrame + CxR12 mov r13, [rdi] + PsbProcessorState + PsContextFrame + CxR13 mov r14, [rdi] + PsbProcessorState + PsContextFrame + CxR14 mov r15, [rdi] + PsbProcessorState + PsContextFrame + CxR15 ; ; Indicate that we've started, pop the correct value for rdi ; and return. ; inc DWORD PTR [rdi] + PsbCompletionFlag pop rdi ret LEAF_END HalpLMStub, _TEXT$00 END