diff options
author | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
---|---|---|
committer | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
commit | b7c51c9cf4864df6aabb99a1ae843becd577237c (patch) | |
tree | eebe9b0d0ca03062955223097e57da84dd618b9a /ReferenceCode/Haswell/CpuInit/Dxe/x64 | |
download | zprj-b7c51c9cf4864df6aabb99a1ae843becd577237c.tar.xz |
Diffstat (limited to 'ReferenceCode/Haswell/CpuInit/Dxe/x64')
-rw-r--r-- | ReferenceCode/Haswell/CpuInit/Dxe/x64/Cpu.asm | 626 | ||||
-rw-r--r-- | ReferenceCode/Haswell/CpuInit/Dxe/x64/CpuLib.h | 168 | ||||
-rw-r--r-- | ReferenceCode/Haswell/CpuInit/Dxe/x64/Exception.c | 372 | ||||
-rw-r--r-- | ReferenceCode/Haswell/CpuInit/Dxe/x64/MemoryOperation.c | 729 | ||||
-rw-r--r-- | ReferenceCode/Haswell/CpuInit/Dxe/x64/MemoryOperationDbgr.c | 749 | ||||
-rw-r--r-- | ReferenceCode/Haswell/CpuInit/Dxe/x64/MpCpu.c | 89 | ||||
-rw-r--r-- | ReferenceCode/Haswell/CpuInit/Dxe/x64/MpEqu.inc | 51 | ||||
-rw-r--r-- | ReferenceCode/Haswell/CpuInit/Dxe/x64/MpFuncs.asm | 618 | ||||
-rw-r--r-- | ReferenceCode/Haswell/CpuInit/Dxe/x64/ProcessorDef.h | 57 | ||||
-rw-r--r-- | ReferenceCode/Haswell/CpuInit/Dxe/x64/VirtualMemory.h | 145 |
10 files changed, 3604 insertions, 0 deletions
diff --git a/ReferenceCode/Haswell/CpuInit/Dxe/x64/Cpu.asm b/ReferenceCode/Haswell/CpuInit/Dxe/x64/Cpu.asm new file mode 100644 index 0000000..9b28b54 --- /dev/null +++ b/ReferenceCode/Haswell/CpuInit/Dxe/x64/Cpu.asm @@ -0,0 +1,626 @@ +; +; This file contains an 'Intel Peripheral Driver' and is +; licensed for Intel CPUs and chipsets under the terms of your +; license agreement with Intel or your vendor. This file may +; be modified by the user, subject to additional terms of the +; license agreement +; + TITLE Cpu.asm: Assembly code for the IA-32 resources + +;------------------------------------------------------------------------------- +; +; Copyright (c) 2005 -2012 Intel Corporation. All rights reserved +; This software and associated documentation (if any) is furnished +; under a license and may only be used or copied in accordance +; with the terms of the license. Except as permitted by such +; license, no part of this software or documentation may be +; reproduced, stored in a retrieval system, or transmitted in any +; form or by any means without the express written consent of +; Intel Corporation. +; +; +; Module Name: +; +; Cpu.asm +; +; Abstract: +; +; +;------------------------------------------------------------------------------- + +text SEGMENT + +EXTRN mErrorCodeFlag:DWORD ; Error code flags for exceptions + +ExternalVectorTablePtr QWORD 0 ; point to the external interrupt vector table + +; +; Float control word initial value: +; all exceptions masked, double-extended-precision, round-to-nearest +; +mFpuControlWord DW 037Fh +; +; Multimedia-extensions control word: +; all exceptions masked, round-to-nearest, flush to zero for masked underflow +; +mMmxControlWord DD 01F80h + + +InitializeExternalVectorTablePtr PROC PUBLIC + mov ExternalVectorTablePtr, rcx + ret +InitializeExternalVectorTablePtr ENDP +; +; +; +;------------------------------------------------------------------------------ +; Generic IDT Vector Handlers for the Host. They are all the same so they +; will compress really well. +; +; By knowing the return address for Vector 00 you can can calculate the +; vector number by looking at the call CommonInterruptEntry return address. +; (return address - (AsmIdtVector00 + 5))/8 == IDT index +; +;------------------------------------------------------------------------------ + +ALIGN 8 + +PUBLIC AsmIdtVector00 + +AsmIdtVector00 LABEL BYTE +REPEAT 256 + call CommonInterruptEntry + dw ( $ - AsmIdtVector00 - 5 ) / 8 ; vector number + nop +ENDM + + +;---------------------------------------; +; CommonInterruptEntry ; +;---------------------------------------; +; The follow algorithm is used for the common interrupt routine. + +; +; +---------------------+ <-- 16-byte aligned ensured by processor +; + Old SS + +; +---------------------+ +; + Old RSP + +; +---------------------+ +; + RFlags + +; +---------------------+ +; + CS + +; +---------------------+ +; + RIP + +; +---------------------+ +; + Error Code + +; +---------------------+ +; + RCX / Vector Number + +; +---------------------+ +; + RBP + +; +---------------------+ <-- RBP, 16-byte aligned +; + +CommonInterruptEntry PROC PUBLIC + cli + cld + ; + ; All interrupt handlers are invoked through interrupt gates, so + ; IF flag automatically cleared at the entry point + ; + ; + ; Calculate vector number + ; + xchg rcx, [rsp] ; get the return address of call, actually, it is the address of vector number. + movzx ecx, word ptr [rcx] + cmp ecx, 32 ; Intel reserved vector for exceptions? + jae NoErrorCode + bt mErrorCodeFlag, ecx + jc @F + +NoErrorCode: + ; + ; Push a dummy error code on the stack + ; to maintain coherent stack map + ; + push [rsp] + mov qword ptr [rsp + 8], 0 +@@: + push rbp + mov rbp, rsp + + ; + ; Since here the stack pointer is 16-byte aligned, so + ; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64 + ; is 16-byte aligned + ; + +;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; +;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; + push r15 + push r14 + push r13 + push r12 + push r11 + push r10 + push r9 + push r8 + push rax + push qword ptr [rbp + 8] ; RCX + push rdx + push rbx + push qword ptr [rbp + 48] ; RSP + push qword ptr [rbp] ; RBP + push rsi + push rdi + +;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero + movzx rax, word ptr [rbp + 56] + push rax ; for ss + movzx rax, word ptr [rbp + 32] + push rax ; for cs + mov rax, ds + push rax + mov rax, es + push rax + mov rax, fs + push rax + mov rax, gs + push rax + + mov [rbp + 8], rcx ; save vector number + +;; UINT64 Rip; + push qword ptr [rbp + 24] + +;; UINT64 Gdtr[2], Idtr[2]; + sub rsp, 16 + sidt fword ptr [rsp] + sub rsp, 16 + sgdt fword ptr [rsp] + +;; UINT64 Ldtr, Tr; + xor rax, rax + str ax + push rax + sldt ax + push rax + +;; UINT64 RFlags; + push qword ptr [rbp + 40] + +;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; + mov rax, cr8 + push rax + mov rax, cr4 + or rax, 208h + mov cr4, rax + push rax + mov rax, cr3 + push rax + mov rax, cr2 + push rax + xor rax, rax + push rax + mov rax, cr0 + push rax + +;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + mov rax, dr7 + push rax +;; clear Dr7 while executing debugger itself + xor rax, rax + mov dr7, rax + + mov rax, dr6 + push rax +;; insure all status bits in dr6 are clear... + xor rax, rax + mov dr6, rax + + mov rax, dr3 + push rax + mov rax, dr2 + push rax + mov rax, dr1 + push rax + mov rax, dr0 + push rax + +;; FX_SAVE_STATE_X64 FxSaveState; + + sub rsp, 512 + mov rdi, rsp + db 0fh, 0aeh, 00000111y ;fxsave [rdi] + +;; UINT32 ExceptionData; + push qword ptr [rbp + 16] + +;; call into exception handler + mov rcx, [rbp + 8] + mov rax, ExternalVectorTablePtr ; get the interrupt vectors base + mov rax, [rax + rcx * 8] + or rax, rax ; NULL? + + je nonNullValue; + +;; Prepare parameter and call +; mov rcx, [rbp + 8] + mov rdx, rsp + ; + ; Per X64 calling convention, allocate maximum parameter stack space + ; and make sure RSP is 16-byte aligned + ; + sub rsp, 4 * 8 + 8 + call rax + add rsp, 4 * 8 + 8 + +nonNullValue: + cli +;; UINT64 ExceptionData; + add rsp, 8 + +;; FX_SAVE_STATE_X64 FxSaveState; + + mov rsi, rsp + db 0fh, 0aeh, 00001110y ; fxrstor [rsi] + add rsp, 512 + +;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + pop rax + mov dr0, rax + pop rax + mov dr1, rax + pop rax + mov dr2, rax + pop rax + mov dr3, rax +;; skip restore of dr6. We cleared dr6 during the context save. + add rsp, 8 + pop rax + mov dr7, rax + +;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; + pop rax + mov cr0, rax + add rsp, 8 ; not for Cr1 + pop rax + mov cr2, rax + pop rax + mov cr3, rax + pop rax + mov cr4, rax + pop rax + mov cr8, rax + +;; UINT64 RFlags; + pop qword ptr [rbp + 40] + +;; UINT64 Ldtr, Tr; +;; UINT64 Gdtr[2], Idtr[2]; +;; Best not let anyone mess with these particular registers... + add rsp, 48 + +;; UINT64 Rip; + pop qword ptr [rbp + 24] + +;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; + pop rax + ; mov gs, rax ; not for gs + pop rax + ; mov fs, rax ; not for fs + ; (X64 will not use fs and gs, so we do not restore it) + pop rax + mov es, rax + pop rax + mov ds, rax + pop qword ptr [rbp + 32] ; for cs + pop qword ptr [rbp + 56] ; for ss + +;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; +;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; + pop rdi + pop rsi + add rsp, 8 ; not for rbp + pop qword ptr [rbp + 48] ; for rsp + pop rbx + pop rdx + pop rcx + pop rax + pop r8 + pop r9 + pop r10 + pop r11 + pop r12 + pop r13 + pop r14 + pop r15 + + mov rsp, rbp + pop rbp + add rsp, 16 + iretq + +CommonInterruptEntry ENDP + + +LongMode PROC PUBLIC + +in_long_mode:: + ; + ; Debug Stop + ; + jmp in_long_mode + + ; + ; We're in long mode, so marshall the arguments to call the + ; passed in function pointers + ; Recall + ; [ebp][10h] = HobStart + ; [ebp][18h] = Stack + ; [ebp][20h] = PpisNeededByDxeIplEntryPoint <--- Call this first (for each call, pass HOB pointer) + ; [ebp][28h] = DxeCoreEntryPoint <--- Call this second + ; + mov rbx, [rbp+18h] ; Setup the stack + mov rsp, rbx ; On a new stack now + + mov rcx, [rbp+10h] ; Pass Hob Start in RCX + mov rax, [rbp+20h] ; Get the function pointer for + ; PpisNeededByDxeIplEntryPoint into EAX + call fword ptr [rax] ; Make the call into PpisNeededByDxeIplEntryPoint + + mov ecx, [rbp+10h] ; Pass Hob Start in RCX + mov eax, [rbp+28h] ; Get the function pointer for + ; DxeCoreEntryPoint into EAX + call fword ptr [rax] ; Make the call into Dxe Core + + call CommonInterruptEntry + + mov rdi, CommonInterruptEntry + + lgdt fword ptr [rdi] + + lidt fword ptr [rdi] + + call near ptr [rax] ; Make the call into PpisNeededByDxeIplEntryPoint + + call rax + + ; + ; Should never get here. + ; +no_long_mode: + jmp no_long_mode + ; + ; WE SHOULD NEVER GET HERE!!!!!!!!!!!!! + ; +LongMode endp + +EnableMce proc public + + mov rax, cr4 + or rax, 40h + mov cr4, rax + + ret + +EnableMce endp + +MpMtrrSynchUpEntry PROC PUBLIC + ; + ; Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29) + ; + mov rax, cr0 + and rax, 0DFFFFFFFh + or rax, 040000000h + mov cr0, rax + ; + ; Flush cache + ; + wbinvd + ; + ; Clear PGE flag Bit 7 + ; + mov rax, cr4 + mov rdx, rax + and rax, 0FFFFFF7Fh + mov cr4, rax + ; + ; Flush all TLBs + ; + mov rax, cr3 + mov cr3, rax + + mov rax, rdx + + ret + +MpMtrrSynchUpEntry ENDP + +MpMtrrSynchUpExit PROC PUBLIC + ; + ; Flush all TLBs the second time + ; + mov rax, cr3 + mov cr3, rax + ; + ; Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29) + ; + mov rax, cr0 + and rax, 09FFFFFFFh + mov cr0, rax + ; + ; Set PGE Flag in CR4 if set + ; + mov cr4, rcx + ret + +MpMtrrSynchUpExit ENDP + +; +; Initializes floating point units for requirement of UEFI specification. +; +; This function initializes floating-point control word to 0x037F (all exceptions +; masked,double-extended-precision, round-to-nearest) and multimedia-extensions control word +; (if supported) to 0x1F80 (all exceptions masked, round-to-nearest, flush to zero +; for masked underflow). +; +CpuInitFloatPointUnit PROC PUBLIC + ; + ; Initialize floating point units + ; + ; The following opcodes stand for instruction 'finit' + ; to be supported by some 64-bit assemblers + ; + DB 9Bh, 0DBh, 0E3h + fldcw mFpuControlWord + + ; + ; Set OSFXSR bit 9 in CR4 + ; + mov rax, cr4 + or rax, 200h + mov cr4, rax + + ldmxcsr mMmxControlWord + ret +CpuInitFloatPointUnit ENDP + +CpuDisableInterrupt PROC PUBLIC + + cli + ret + +CpuDisableInterrupt ENDP + +CpuEnableInterrupt PROC PUBLIC + + sti + ret + +CpuEnableInterrupt ENDP + +MAX_NR_BUS EQU 0FFh +CSR_DESIRED_CORES EQU 080h ; CSR D0:F0:R80 + +GetCsrDesiredCores PROC PUBLIC + + push rbx + + ; + ; get Bus number from CPUID[1] EBX[31:24] + ; + mov eax, 1 ; bus 0 + cpuid + bswap ebx + shr bl, 4 + movzx eax, bl + ; + ; Compute CPU Bus Num + ; Bus Num = (MAX_NB_BUS - socket ID) + ; + xor eax, MAX_NR_BUS ; bus number = MAX_NR_BUS - socket ID + ; + ; eax = bus number + ; out 0CF8h, GQ1_CR_PCIEXBAR OR (Bus Num shl 16) + ; + or eax, 8000h + shl eax, 16 + or eax, CSR_DESIRED_CORES ; D0:F1:R80h + mov dx, 0CF8h + out dx, eax + mov dx, 0CFCh + in eax, dx + + pop rbx + + ret + +GetCsrDesiredCores ENDP + +SetLockCsrDesiredCores PROC PUBLIC + + push rbx + + ; + ; get Bus number from CPUID[1] EBX[31:24] + ; + mov eax, 1 ; bus 0 + cpuid + bswap ebx + shr bl, 4 + movzx eax, bl + ; + ; Compute CPU Bus Num + ; Bus Num = (MAX_NB_BUS - socket ID) + ; + xor eax, MAX_NR_BUS ; bus number = MAX_NR_BUS - socket ID + ; + ; eax = bus number + ; out 0CF8h, GQ1_CR_PCIEXBAR OR (Bus Num shl 16) + ; + or eax, 8000h + shl eax, 16 + or eax, CSR_DESIRED_CORES ; D0:F1:R80h + mov dx, 0CF8h + out dx, eax + mov dx, 0CFCh + in eax, dx + or eax, 10000h ; Bit[16] = Lock + out dx, eax + + pop rbx + ret + +SetLockCsrDesiredCores ENDP + +;------------------------------------------------------------------------------ +; UINTN +; CpuFlushTlb ( +; VOID +; ) +;------------------------------------------------------------------------------ +CpuFlushTlb PROC PUBLIC + mov rax, cr3 + mov cr3, rax + ret +CpuFlushTlb ENDP + +;------------------------------------------------------------------------------ +; UINT16 +; CpuCodeSegment ( +; VOID +; ); +;------------------------------------------------------------------------------ +CpuCodeSegment PROC PUBLIC + xor eax, eax + mov eax, cs + ret +CpuCodeSegment ENDP + +;------------------------------------------------------------------------------ +; VOID +; CpuLoadGlobalDescriptorTable ( +; VOID *Table16ByteAligned +; ); +;------------------------------------------------------------------------------ +CpuLoadGlobalDescriptorTable PROC PUBLIC + lgdt FWORD PTR [rcx] + ret +CpuLoadGlobalDescriptorTable ENDP + +;------------------------------------------------------------------------------ +; VOID +; CpuLoadInterruptDescriptorTable ( +; VOID *Table16ByteAligned +; ); +;------------------------------------------------------------------------------ +CpuLoadInterruptDescriptorTable PROC PUBLIC + lidt FWORD PTR [rcx] + ret +CpuLoadInterruptDescriptorTable ENDP + + +text ENDS +END + + diff --git a/ReferenceCode/Haswell/CpuInit/Dxe/x64/CpuLib.h b/ReferenceCode/Haswell/CpuInit/Dxe/x64/CpuLib.h new file mode 100644 index 0000000..14699c1 --- /dev/null +++ b/ReferenceCode/Haswell/CpuInit/Dxe/x64/CpuLib.h @@ -0,0 +1,168 @@ +/** @file + Library functions that can be called in both PEI and DXE phase + +@copyright + Copyright (c) 2004 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +**/ +#ifndef _CPU_LIB_H_ +#define _CPU_LIB_H_ + +#if 0 +UINTN +CpuReadCr0 ( + VOID + ) +/** +@brief + Get CR0 value + + @param[in] None + + @retval CR0 value +**/ +; + +VOID +CpuWriteCr0 ( + UINTN Value + ) +/** +@brief + Write CR0 register + + @param[in] Value - Value that will be written into CR0 register +**/ +; + +UINTN +CpuReadCr3 ( + VOID + ) +/** +@brief + Get CR3 register value + + @param[in] None + + @retval CR3 register value +**/ +; + +VOID +CpuWriteCr3 ( + UINTN Value + ) +/** +@brief + Write CR3 register + + @param[in] Value - Value that will be written to CR3 register +**/ +; + +UINTN +CpuSetPower2 ( + IN UINTN Input + ) +/** +@brief + Calculate the power 2 value from the Input value + + @param[in] Input - The number that will be calculated + + @retval Power 2 value after calculated +**/ +; + +UINT64 +CpuReadTsc ( + VOID + ) +/** +@brief + Read CPU TSC value + + @param[in] None + + @retval TSC value +**/ +; + +VOID +CpuBreak ( + VOID + ) +/** +@brief + Break by INT3 + + @param[in] None +**/ +; + +VOID +CpuInitSelectors ( + VOID + ) +/** +@brief + Initialize selectors by calling INT 68 + + @param[in] None +**/ +; + +#endif + +UINT16 +CpuCodeSegment ( + VOID + ) +/** +@brief + Return code segment address - CS + + @param[in] None + + @retval Code segment address +**/ +; + +VOID +CpuLoadGlobalDescriptorTable ( + VOID *Table16ByteAligned + ) +/** +@brief + Get current GDT descriptor + + @param[in] Table16ByteAligned - the table buffer that will store current GDT table descriptor +**/ +; + +VOID +CpuLoadInterruptDescriptorTable ( + VOID *Table16ByteAligned + ) +/** +@brief + Get current IDT descriptor + + @param[in] Table16ByteAligned - the table buffer that will store current GDT table descriptor +**/ +; + +#endif diff --git a/ReferenceCode/Haswell/CpuInit/Dxe/x64/Exception.c b/ReferenceCode/Haswell/CpuInit/Dxe/x64/Exception.c new file mode 100644 index 0000000..bcd306b --- /dev/null +++ b/ReferenceCode/Haswell/CpuInit/Dxe/x64/Exception.c @@ -0,0 +1,372 @@ +/** @file + EM64T Exception Handler + +@copyright + Copyright (c) 2006 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement + +**/ +#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000) +#include "EdkIIGlueDxe.h" +#include "CpuInitDxe.h" +#include "MpCommon.h" +#include "Exception.h" +#endif + +typedef +VOID +(*EFI_INSTALL_EXCEPTION)( + IN UINT32 InterruptType, + IN VOID *SystemContext + ); + +typedef struct { + UINT32 ErrorMessage; + UINT8 Interrupt; +} EFI_EXCEPTION_HANDLER; + +/// +/// Error code flag indicating whether or not an error code will be +/// pushed on the stack if an exception occurs. +/// +/// 1 means an error code will be pushed, otherwise 0 +/// +/// bit 0 - exception 0 +/// bit 1 - exception 1 +/// etc. +/// +UINT32 mErrorCodeFlag = 0x00027d00; + +/// +/// Local Table +/// +EFI_EXCEPTION_HANDLER mExceptionTable[] = { + { + EFI_SW_EC_IA32_DIVIDE_ERROR, + INTERRUPT_HANDLER_DIVIDE_ZERO + }, + { + EFI_SW_EC_IA32_DEBUG, + INTERRUPT_HANDLER_DEBUG + }, + { + EFI_SW_EC_IA32_NMI, + INTERRUPT_HANDLER_NMI + }, + { + EFI_SW_EC_IA32_BREAKPOINT, + INTERRUPT_HANDLER_BREAKPOINT + }, + { + EFI_SW_EC_IA32_OVERFLOW, + INTERRUPT_HANDLER_OVERFLOW + }, + { + EFI_SW_EC_IA32_BOUND, + INTERRUPT_HANDLER_BOUND + }, + { + EFI_SW_EC_IA32_INVALID_OPCODE, + INTERRUPT_HANDLER_INVALID_OPCODE + }, + /// + /// Interrupt 7, 9, 15 not defined in the debug support protocol. Hence no status codes for them! + /// + { + EFI_SW_EC_IA32_DOUBLE_FAULT, + INTERRUPT_HANDLER_DOUBLE_FAULT + }, + { + EFI_SW_EC_IA32_INVALID_TSS, + INTERRUPT_HANDLER_INVALID_TSS + }, + { + EFI_SW_EC_IA32_SEG_NOT_PRESENT, + INTERRUPT_HANDLER_SEGMENT_NOT_PRESENT + }, + { + EFI_SW_EC_IA32_STACK_FAULT, + INTERRUPT_HANDLER_STACK_SEGMENT_FAULT + }, + { + EFI_SW_EC_IA32_GP_FAULT, + INTERRUPT_HANDLER_GP_FAULT + }, + { + EFI_SW_EC_IA32_PAGE_FAULT, + INTERRUPT_HANDLER_PAGE_FAULT + }, + { + EFI_SW_EC_IA32_FP_ERROR, + INTERRUPT_HANDLER_MATH_FAULT + }, + { + EFI_SW_EC_IA32_ALIGNMENT_CHECK, + INTERRUPT_HANDLER_ALIGNMENT_FAULT + }, + { + EFI_SW_EC_IA32_MACHINE_CHECK, + INTERRUPT_HANDLER_MACHINE_CHECK + }, + { + EFI_SW_EC_IA32_SIMD, + INTERRUPT_HANDLER_STREAMING_SIMD + } +}; + +UINTN mExceptionNumber = sizeof (mExceptionTable) / sizeof (EFI_EXCEPTION_HANDLER); + +CPU_STATUS_CODE_TEMPLATE mStatusCodeData = { + { + sizeof (EFI_STATUS_CODE_DATA), + sizeof (EFI_SYSTEM_CONTEXT_X64), + EFI_STATUS_CODE_DATA_TYPE_EXCEPTION_HANDLER_GUID + }, + { + 0 + } +}; + +UINT8 mExceptionLock = 0; + +/** + Report StatusCode for Exception + + @param[in] InterruptType - Interrupt type + @param[in] SystemContext - EFI_SYSTEM_CONTEXT + + @retval EFI_SUCCESS +**/ +EFI_STATUS +ReportData ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + UINT32 ErrorMessage; + UINT32 Index; + + CopyMem ( + &mStatusCodeData.SystemContext.SystemContextX64, + SystemContext.SystemContextX64, + sizeof (EFI_SYSTEM_CONTEXT_X64) + ); + + ErrorMessage = EFI_SOFTWARE_DXE_BS_DRIVER; + for (Index = 0; Index < mExceptionNumber; Index++) { + if (mExceptionTable[Index].Interrupt == InterruptType) { + ErrorMessage |= mExceptionTable[Index].ErrorMessage; + break; + } + } + + ReportStatusCode ( + (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED), + EFI_SOFTWARE_UNSPECIFIED | ErrorMessage + ); + + return EFI_SUCCESS; +} + +/** + Common exception handler + + @param[in] InterruptType - Exception type + @param[in] SystemContext - EFI_SYSTEM_CONTEXT +**/ +VOID +EFIAPI +CommonExceptionHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + AsmAcquireMPLock (&mExceptionLock); + + DEBUG ( + (EFI_D_ERROR, + "!!!! X64 Exception Type - %016lx CPU Apic ID - %08x!!!!\n", + InterruptType, + GetApicID (NULL, + NULL)) + ); + DEBUG ( + (EFI_D_ERROR, + "RIP - %016lx, CS - %016lx, RFLAGS - %016lx\n", + SystemContext.SystemContextX64->Rip, + SystemContext.SystemContextX64->Cs, + SystemContext.SystemContextX64->Rflags) + ); + if (mErrorCodeFlag & (1 << InterruptType)) { + DEBUG ( + (EFI_D_ERROR, + "ExceptionData - %016lx\n", + SystemContext.SystemContextX64->ExceptionData) + ); + } + + DEBUG ( + (EFI_D_ERROR, + "RAX - %016lx, RCX - %016lx, RDX - %016lx\n", + SystemContext.SystemContextX64->Rax, + SystemContext.SystemContextX64->Rcx, + SystemContext.SystemContextX64->Rdx) + ); + DEBUG ( + (EFI_D_ERROR, + "RBX - %016lx, RSP - %016lx, RBP - %016lx\n", + SystemContext.SystemContextX64->Rbx, + SystemContext.SystemContextX64->Rsp, + SystemContext.SystemContextX64->Rbp) + ); + DEBUG ( + (EFI_D_ERROR, + "RSI - %016lx, RDI - %016lx\n", + SystemContext.SystemContextX64->Rsi, + SystemContext.SystemContextX64->Rdi) + ); + DEBUG ( + (EFI_D_ERROR, + "R8 - %016lx, R9 - %016lx, R10 - %016lx\n", + SystemContext.SystemContextX64->R8, + SystemContext.SystemContextX64->R9, + SystemContext.SystemContextX64->R10) + ); + DEBUG ( + (EFI_D_ERROR, + "R11 - %016lx, R12 - %016lx, R13 - %016lx\n", + SystemContext.SystemContextX64->R11, + SystemContext.SystemContextX64->R12, + SystemContext.SystemContextX64->R13) + ); + DEBUG ( + (EFI_D_ERROR, + "R14 - %016lx, R15 - %016lx\n", + SystemContext.SystemContextX64->R14, + SystemContext.SystemContextX64->R15) + ); + DEBUG ( + (EFI_D_ERROR, + "DS - %016lx, ES - %016lx, FS - %016lx\n", + SystemContext.SystemContextX64->Ds, + SystemContext.SystemContextX64->Es, + SystemContext.SystemContextX64->Fs) + ); + DEBUG ( + (EFI_D_ERROR, + "GS - %016lx, SS - %016lx\n", + SystemContext.SystemContextX64->Gs, + SystemContext.SystemContextX64->Ss) + ); + DEBUG ( + (EFI_D_ERROR, + "GDTR - %016lx %016lx, LDTR - %016lx\n", + SystemContext.SystemContextX64->Gdtr[0], + SystemContext.SystemContextX64->Gdtr[1], + SystemContext.SystemContextX64->Ldtr) + ); + DEBUG ( + (EFI_D_ERROR, + "IDTR - %016lx %016lx, TR - %016lx\n", + SystemContext.SystemContextX64->Idtr[0], + SystemContext.SystemContextX64->Idtr[1], + SystemContext.SystemContextX64->Tr) + ); + DEBUG ( + (EFI_D_ERROR, + "CR0 - %016lx, CR2 - %016lx, CR3 - %016lx\n", + SystemContext.SystemContextX64->Cr0, + SystemContext.SystemContextX64->Cr2, + SystemContext.SystemContextX64->Cr3) + ); + DEBUG ( + (EFI_D_ERROR, + "CR4 - %016lx, CR8 - %016lx\n", + SystemContext.SystemContextX64->Cr4, + SystemContext.SystemContextX64->Cr8) + ); + DEBUG ( + (EFI_D_ERROR, + "DR0 - %016lx, DR1 - %016lx, DR2 - %016lx\n", + SystemContext.SystemContextX64->Dr0, + SystemContext.SystemContextX64->Dr1, + SystemContext.SystemContextX64->Dr2) + ); + DEBUG ( + (EFI_D_ERROR, + "DR3 - %016lx, DR6 - %016lx, DR7 - %016lx\n", + SystemContext.SystemContextX64->Dr3, + SystemContext.SystemContextX64->Dr6, + SystemContext.SystemContextX64->Dr7) + ); + + /// + /// Report Status Code + /// + ReportData (InterruptType, SystemContext); + AsmReleaseMPLock (&mExceptionLock); + + /// + /// Use this macro to hang so that the compiler does not optimize out + /// the following RET instructions. This allows us to return if we + /// have a debugger attached. + /// + EFI_DEADLOOP (); + + return; +} + +/** + Install the IA-32 EM64T Exception Handler. + The current operation (which likely will change) will uninstall all the + pertinent exception handlers (0-7, 10-14, 16-19) except for Int8 which the timer + is currently sitting on (or soon will be). + + It then installs all the appropriate handlers for each exception. + + The handler then calls gRT->ReportStatusCode with a specific progress code. The + progress codes for now start at 0x200 for IA-32 processors. See Status Code + Specification for details. The Status code Specification uses the enumeration from + the EFI 1.1 Debug Support Protocol. + + @param[in] CpuProtocol - Instance of CPU Arch Protocol + + @retval EFI_SUCCESS - This function always return success after registering handlers. +**/ +EFI_STATUS +InitializeException ( + IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol + ) +{ + EFI_STATUS Status; + UINTN Index; + + CpuProtocol->DisableInterrupt (CpuProtocol); + + for (Index = 0; Index < mExceptionNumber; Index++) { + Status = CpuProtocol->RegisterInterruptHandler (CpuProtocol, mExceptionTable[Index].Interrupt, NULL); + /// + /// Add in our handler + /// + Status = CpuProtocol->RegisterInterruptHandler ( + CpuProtocol, + mExceptionTable[Index].Interrupt, + CommonExceptionHandler + ); + ASSERT_EFI_ERROR (Status); + } + + return EFI_SUCCESS; +} diff --git a/ReferenceCode/Haswell/CpuInit/Dxe/x64/MemoryOperation.c b/ReferenceCode/Haswell/CpuInit/Dxe/x64/MemoryOperation.c new file mode 100644 index 0000000..5fae506 --- /dev/null +++ b/ReferenceCode/Haswell/CpuInit/Dxe/x64/MemoryOperation.c @@ -0,0 +1,729 @@ +/** @file + Memory Operation Functions for IA32 Architecture. + +@copyright + Copyright (c) 2006 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement + +**/ +#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000) +#include "EdkIIGlueDxe.h" +#include "CpuInitDxe.h" +#include "CpuLib.h" +#include "MpCommon.h" +#include "VirtualMemory.h" +#include "MemoryAttribute.h" +#endif + +VOID +InitializeExternalVectorTablePtr ( + EFI_CPU_INTERRUPT_HANDLER *VectorTable + ); + +extern EFI_CPU_INTERRUPT_HANDLER mExternalVectorTable[]; +extern EFI_PHYSICAL_ADDRESS mBackupBuffer; + +UINT8 *mPageStore = NULL; +UINTN mPageStoreSize = 16; +UINTN mPageStoreIndex = 0; + +UINT64 mValidMtrrAddressMask; +UINT64 mValidMtrrBitsMask; + +/// +/// BugBug: Non Portable +/// +#if defined (__GNUC__) +#define ALIGN_16BYTE_BOUNDRY __attribute__ ((aligned (16))) +#else +#define ALIGN_16BYTE_BOUNDRY __declspec (align (16)) +#endif + +#pragma pack(1) +typedef struct { + UINT16 LimitLow; + UINT16 BaseLow; + UINT8 BaseMiddle; + UINT8 Attributes1; + UINT8 Attributes2; + UINT8 BaseHigh; +} SEGMENT_DESCRIPTOR_x64; + +typedef struct { + UINT16 Limit; + UINTN Base; +} PSEUDO_DESCRIPTOR_x64; + +#pragma pack() + +ALIGN_16BYTE_BOUNDRY SEGMENT_DESCRIPTOR_x64 gGdt[] = { + { /// NULL Selector: selector[0] + 0, /// limit 15:0 + 0, /// base 15:0 + 0, /// base 23:16 + 0, /// + 0, /// type & limit 19:16 + 0, /// base 31:24 + /// 0, /// base 63:32 + /// 0 /// reserved + /// + }, + { /// Linear Selector: selector[8] + 0xffff, /// limit 15:0 + 0, /// base 15:0 + 0, /// base 23:16 + 0x93, /// present, ring 0, data, expand-up writable + 0xcf, /// type & limit 19:16 + 0, /// base 31:24 + /// 0, /// base 63:32 + /// 0 /// reserved + /// + }, + { /// Linear code Selector: selector[10] + 0xffff, /// limit 15:0 + 0, /// base 15:0 + 0, /// base 23:16 + 0x9b, /// present, ring 0, code, expand-up writable + 0xcf, /// type & limit 19:16 + 0, /// base 31:24 + /// 0, /// base 63:32 + /// 0 /// reserved + /// + }, + { /// Compatibility mode data Selector: selector[18] + 0xffff, /// limit 15:0 + 0, /// base 15:0 + 0, /// base 23:16 + 0x93, /// type & limit 19:16 + 0xcf, + 0, /// base 31:24 + /// 0, /// base 63:32 + /// 0 /// reserved + /// + }, + { /// Compatibility code Selector: selector[20] + 0xffff, /// limit 15:0 + 0, /// base 15:0 + 0, /// base 23:16 + 0x9b, /// type & limit 19:16 + 0xcf, + 0, /// base 31:24 + /// 0, /// base 63:32 + /// 0 /// reserved + /// + }, + { /// Spare3 Selector: selector[28] + 0, /// limit 15:0 + 0, /// base 15:0 + 0, /// base 23:16 + 0, /// type & limit 19:16 + 0, /// base 31:24 + 0, + /// + /// 0, /// base 63:32 + /// 0 /// reserved + /// + }, + { /// 64-bit data Selector:selector[30] + 0xffff, /// limit 15:0 + 0, /// base 15:0 + 0, /// base 23:16 + 0x93, /// type & limit 19:16 + 0xcf, + 0, /// base 31:24 + /// 0, /// base 63:32 + /// 0 /// reserved + /// + }, + { /// 64-bit code Selector: selector[38] + 0xffff, /// limit 15:0 + 0, /// base 15:0 + 0, /// base 23:16 + 0x9b, /// type & limit 19:16 + 0xaf, + 0, /// base 31:24 + /// 0, /// base 63:32 + /// 0 /// reserved + /// + }, + { /// Spare3 Selector: selector[40] + 0, /// limit 15:0 + 0, /// base 15:0 + 0, /// base 23:16 + 0, /// type & limit 19:16 + 0, /// base 31:24 + 0, + /// + /// 0, /// base 63:32 + /// 0 /// reserved + /// + } +}; + +ALIGN_16BYTE_BOUNDRY PSEUDO_DESCRIPTOR_x64 gGdtPseudoDescriptor = { + sizeof (gGdt) - 1, + (UINTN) gGdt +}; + +INTERRUPT_GATE_DESCRIPTOR gIdtTable[INTERRUPT_VECTOR_NUMBER] = { 0 }; + +ALIGN_16BYTE_BOUNDRY PSEUDO_DESCRIPTOR_x64 gLidtPseudoDescriptor = { + sizeof (gIdtTable) - 1, + (UINTN) gIdtTable +}; + +/** + Init Global Descriptor table +**/ +VOID +InitializeSelectors ( + VOID + ) +{ + CpuLoadGlobalDescriptorTable (&gGdtPseudoDescriptor); +} + +/** + Generic IDT Vector Handlers for the Host +**/ +VOID +AsmIdtVector00 ( + VOID + ); + +/** + Initialize Interrupt descriptor Tables +**/ +VOID +InitializeInterruptTables ( + VOID + ) +{ + UINT16 CodeSegment; + INTERRUPT_GATE_DESCRIPTOR *IdtEntry; + UINT8 *CurrentHandler; + UINT32 Index; + + CodeSegment = CpuCodeSegment (); + + IdtEntry = gIdtTable; + CurrentHandler = (UINT8 *) (UINTN) AsmIdtVector00; + for (Index = 0; Index < INTERRUPT_VECTOR_NUMBER; Index++) { + IdtEntry[Index].Offset15To0 = (UINT16) (UINTN) CurrentHandler; + IdtEntry[Index].SegmentSelector = CodeSegment; + IdtEntry[Index].Attributes = INTERRUPT_GATE_ATTRIBUTE; + /// + /// 8e00; + /// + IdtEntry[Index].Offset31To16 = (UINT16) ((UINTN) CurrentHandler >> 16); + IdtEntry[Index].Offset63To32 = (UINT32) ((UINTN) CurrentHandler >> 32); + + CurrentHandler += 0x8; + /// + } + + CpuLoadInterruptDescriptorTable (&gLidtPseudoDescriptor); + + return; +} + +/** + Initialize cache attributes based on MTRR +**/ +VOID +InitailizeCacheAttributes ( + VOID + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Page; + EFI_CPUID_REGISTER FeatureInfo; + EFI_CPUID_REGISTER FunctionInfo; + UINT8 PhysicalAddressBits; + UINT32 MsrNum; + UINT64 TempQword; + UINT64 ComplementBits; + UINT32 VariableMtrrLimit; + + VariableMtrrLimit = (UINT32) (AsmReadMsr64 (IA32_MTRR_CAP) & B_IA32_MTRR_VARIABLE_SUPPORT); + + /// + /// Allocate 16 pages + /// + Status = (gBS->AllocatePages)(AllocateAnyPages, EfiBootServicesData, mPageStoreSize, &Page); + ASSERT_EFI_ERROR (Status); + + mPageStore = (UINT8 *) (UINTN) Page; + + ZeroMem (mPageStore, 0x1000 * mPageStoreSize); + + /// + /// Check returned value of Eax for extended CPUID functions + /// + AsmCpuid ( + CPUID_EXTENDED_FUNCTION, + &FunctionInfo.RegEax, + &FunctionInfo.RegEbx, + &FunctionInfo.RegEcx, + &FunctionInfo.RegEdx + ); + + PhysicalAddressBits = 36; + + /// + /// If CPU supports extended functions, get the Physical Address size by reading EAX[7:0] + /// + if (FunctionInfo.RegEax > CPUID_EXTENDED_FUNCTION) { + AsmCpuid ( + CPUID_VIR_PHY_ADDRESS_SIZE, + &FeatureInfo.RegEax, + &FeatureInfo.RegEbx, + &FeatureInfo.RegEcx, + &FeatureInfo.RegEdx + ); + PhysicalAddressBits = (UINT8) FeatureInfo.RegEax; + } + + mValidMtrrBitsMask = (((UINT64) 1) << PhysicalAddressBits) - 1; + mValidMtrrAddressMask = mValidMtrrBitsMask & 0xfffffffffffff000; + + ComplementBits = mValidMtrrBitsMask & 0xfffffff000000000; + if (ComplementBits != 0) { + /// + /// Disable cache and clear the corresponding MTRR bits + /// + PreMtrrChange (); + for (MsrNum = CACHE_VARIABLE_MTRR_BASE; + MsrNum < (CACHE_VARIABLE_MTRR_BASE + VariableMtrrLimit * 2 - 1); + MsrNum += 2 + ) { + TempQword = AsmReadMsr64 (MsrNum + 1); + if ((TempQword & B_CACHE_MTRR_VALID) != 0) { + /// + /// MTRR Physical Mask + /// + TempQword = TempQword | ComplementBits; + AsmWriteMsr64 (MsrNum + 1, TempQword); + } + } + + /// + /// Enable Cache and set the corresponding MTRR bits + /// + PostMtrrChange (); + } +} + +/** + Allocate zeroed pages + + @retval Pointer to the page buffer +**/ +VOID * +AllocateZeroedPage ( + VOID + ) +{ + if (mPageStoreIndex >= mPageStoreSize) { + /// + /// We are out of space + /// + return NULL; + } + + return (VOID *) (UINTN) &mPageStore[0x1000 * mPageStoreIndex++]; +} + +/** + Convert 2MB page tables to 4KB page tables + + @param[in] PageAddress - Page address to convert + @param[in] PageDirectoryToConvert - Page table that will be converted +**/ +VOID +Convert2MBPageTo4KPages ( + IN EFI_PHYSICAL_ADDRESS PageAddress, + IN OUT x64_PAGE_TABLE_ENTRY **PageDirectoryToConvert + ) +{ + UINTN Index; + EFI_PHYSICAL_ADDRESS WorkingAddress; + x64_PAGE_TABLE_ENTRY_4K *PageTableEntry; + x64_PAGE_TABLE_ENTRY Attributes; + + /// + /// Save the attributes of the 2MB table + /// + Attributes.Page2Mb.Uint64 = (*PageDirectoryToConvert)->Page2Mb.Uint64; + + /// + /// Convert PageDirectoryEntry2MB into a 4K Page Directory + /// + PageTableEntry = AllocateZeroedPage (); + if (PageTableEntry == NULL) { + return; + } + (*PageDirectoryToConvert)->Page2Mb.Uint64 = (UINT64) PageTableEntry; + (*PageDirectoryToConvert)->Page2Mb.Bits.ReadWrite = 1; + (*PageDirectoryToConvert)->Page2Mb.Bits.Present = 1; + + WorkingAddress = PageAddress; + for (Index = 0; Index < 512; Index++, PageTableEntry++, WorkingAddress += 0x1000) { + PageTableEntry->Uint64 = (UINT64) WorkingAddress; + PageTableEntry->Bits.Present = 1; + + /// + /// Update the new page to have the same attributes as the 2MB page + /// + PageTableEntry->Bits.ReadWrite = Attributes.Common.ReadWrite; + PageTableEntry->Bits.CacheDisabled = Attributes.Common.CacheDisabled; + PageTableEntry->Bits.WriteThrough = Attributes.Common.WriteThrough; + + if (WorkingAddress == PageAddress) { + /// + /// Return back the 4K page that matches the Working addresss + /// + *PageDirectoryToConvert = (x64_PAGE_TABLE_ENTRY *) PageTableEntry; + } + } +} + +/** + Get current memory mapping information + + @param[in] BaseAddress - get current memory mapping by this Base address + @param[in] PageTable - page table that translated this base address + @param[in] Page2MBytes - TRUE if this is 2MBytes page table + + @retval EFI_NOT_FOUND - page table not found + @retval EFI_SUCCESS - page table found +**/ +EFI_STATUS +GetCurrentMapping ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + OUT x64_PAGE_TABLE_ENTRY **PageTable, + OUT BOOLEAN *Page2MBytes + ) +{ + UINT64 Cr3; + x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *PageMapLevel4Entry; + x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *PageDirectoryPointerEntry; + x64_PAGE_TABLE_ENTRY_2M *PageTableEntry2Mb; + x64_PAGE_DIRECTORY_ENTRY_4K *PageDirectoryEntry4k; + x64_PAGE_TABLE_ENTRY_4K *PageTableEntry4k; + UINTN Pml4Index; + UINTN PdpIndex; + UINTN Pde2MbIndex; + UINTN PteIndex; + + Cr3 = AsmReadCr3 (); + + PageMapLevel4Entry = (x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *) (Cr3 & 0x000ffffffffff000); + + Pml4Index = (UINTN) RShiftU64 (BaseAddress, 39) & 0x1ff; + if (PageMapLevel4Entry[Pml4Index].Bits.Present == 0) { + return EFI_NOT_FOUND; + } + + PageDirectoryPointerEntry = (x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *) (PageMapLevel4Entry[Pml4Index].Uint64 & 0x000ffffffffff000); + PdpIndex = (UINTN) RShiftU64 (BaseAddress, 30) & 0x1ff; + if (PageDirectoryPointerEntry[PdpIndex].Bits.Present == 0) { + return EFI_NOT_FOUND; + } + + PageTableEntry2Mb = (x64_PAGE_TABLE_ENTRY_2M *) (PageDirectoryPointerEntry[PdpIndex].Uint64 & 0x000ffffffffff000); + Pde2MbIndex = (UINTN) RShiftU64 (BaseAddress, 21) & 0x1ff; + if (PageTableEntry2Mb[Pde2MbIndex].Bits.Present == 0) { + return EFI_NOT_FOUND; + } + + if (PageTableEntry2Mb[Pde2MbIndex].Bits.MustBe1 == 1) { + /// + /// We found a 2MByte page so lets return it + /// + *Page2MBytes = TRUE; + *PageTable = (x64_PAGE_TABLE_ENTRY *) &PageTableEntry2Mb[Pde2MbIndex].Uint64; + return EFI_SUCCESS; + } + + /// + /// 4K page so keep walking + /// + PageDirectoryEntry4k = (x64_PAGE_DIRECTORY_ENTRY_4K *) &PageTableEntry2Mb[Pde2MbIndex].Uint64; + + PageTableEntry4k = (x64_PAGE_TABLE_ENTRY_4K *) (PageDirectoryEntry4k[Pde2MbIndex].Uint64 & 0x000ffffffffff000); + PteIndex = (UINTN) RShiftU64 (BaseAddress, 12) & 0x1ff; + if (PageTableEntry4k[PteIndex].Bits.Present == 0) { + return EFI_NOT_FOUND; + } + + *Page2MBytes = FALSE; + *PageTable = (x64_PAGE_TABLE_ENTRY *) &PageTableEntry4k[PteIndex]; + return EFI_SUCCESS; +} + +/** + Prepare memory for essential system tables. + + @retval EFI_SUCCESS - Memory successfully prepared. +**/ +EFI_STATUS +PrepareMemory ( + VOID + ) +{ + /// + /// Allocate space to convert 2MB page tables to 4K tables. + /// This can not be done at call time as the TPL level will + /// not be correct. + /// + InitailizeCacheAttributes (); + + InitializeExternalVectorTablePtr (mExternalVectorTable); + /// + /// Initialize the Interrupt Descriptor Table + /// + InitializeInterruptTables (); + + return EFI_SUCCESS; +} + +/** + Prepare Wakeup Buffer and stack for APs. + + @param[in] WakeUpBuffer - Pointer to the address of wakeup buffer for output. + @param[in] StackAddressStart - Pointer to the stack address of APs for output. + @param[in] MaximumCPUsForThisSystem - Maximum CPUs in this system. + + @retval EFI_SUCCESS - Memory successfully prepared for APs. + @retval Other - Error occurred while allocating memory. +**/ +EFI_STATUS +PrepareMemoryForAPs ( + OUT EFI_PHYSICAL_ADDRESS *WakeUpBuffer, + OUT VOID **StackAddressStart, + IN UINTN MaximumCPUsForThisSystem + ) +{ + EFI_STATUS Status; + MP_ASSEMBLY_ADDRESS_MAP AddressMap; + + /// + /// Release All APs with a lock and wait for them to retire to rendezvous procedure. + /// We need a page (4KB) of memory for IA-32 to use broadcast APIs, on a temporary basis. + /// + Status = AllocateWakeUpBuffer (WakeUpBuffer); + if (EFI_ERROR (Status)) { + return Status; + } + + /// + /// Claim memory for AP stack + /// + Status = AllocateReservedMemoryBelow4G ( + MaximumCPUsForThisSystem * STACK_SIZE_PER_PROC, + StackAddressStart + ); + + if (EFI_ERROR (Status)) { + (gBS->FreePages)(*WakeUpBuffer, 1); + return Status; + } + + AsmGetAddressMap (&AddressMap); + CopyMem ((VOID *) (UINTN) *WakeUpBuffer, AddressMap.RendezvousFunnelAddress, AddressMap.Size); + *(UINT32 *) (UINTN) (*WakeUpBuffer + AddressMap.FlatJumpOffset + 3) = (UINT32) (*WakeUpBuffer + AddressMap.PModeEntryOffset); + *(UINT32 *) (UINTN) (*WakeUpBuffer + AddressMap.LongJumpOffset + 2) = (UINT32) (*WakeUpBuffer + AddressMap.LModeEntryOffset); + + return EFI_SUCCESS; +} + +/** + Prepare exchange information for APs. + + @param[in] ExchangeInfo - Pointer to the exchange info buffer for output. + @param[in] StackAddressStart - Start address of APs' stacks. + @param[in] ApFunction - Address of function assigned to AP. + @param[in] WakeUpBuffer - Pointer to the address of wakeup buffer. + + @retval EFI_SUCCESS - Exchange Info successfully prepared for APs. +**/ +EFI_STATUS +PrepareExchangeInfo ( + OUT MP_CPU_EXCHANGE_INFO *ExchangeInfo, + IN VOID *StackAddressStart, + IN VOID *ApFunction, + IN EFI_PHYSICAL_ADDRESS WakeUpBuffer + ) +{ + ZeroMem ((VOID *) ExchangeInfo, EFI_PAGE_SIZE - MP_CPU_EXCHANGE_INFO_OFFSET); + + ExchangeInfo->Lock = VacantFlag; + ExchangeInfo->StackStart = StackAddressStart; + ExchangeInfo->StackSize = STACK_SIZE_PER_PROC; + ExchangeInfo->ApFunction = ApFunction; + + CopyMem ( + (VOID *) (UINTN) &ExchangeInfo->GdtrProfile, + (VOID *) (UINTN) mAcpiCpuData->GdtrProfile, + sizeof (PSEUDO_DESCRIPTOR) + ); + CopyMem ( + (VOID *) (UINTN) &ExchangeInfo->IdtrProfile, + (VOID *) (UINTN) mAcpiCpuData->IdtrProfile, + sizeof (PSEUDO_DESCRIPTOR) + ); + + ExchangeInfo->BufferStart = (UINT32) WakeUpBuffer; + ExchangeInfo->Cr3 = (UINT32) (AsmReadCr3 ()); + ExchangeInfo->InitFlag = 1; + + return EFI_SUCCESS; +} + +/** + Prepare Wakeup Buffer and stack for APs. + + @param[in] WakeUpBuffer - Pointer to the address of wakeup buffer for output. + @param[in] StackAddressStart - Pointer to the stack address of APs for output. + + @retval EFI_SUCCESS - Memory successfully prepared for APs. +**/ +EFI_STATUS +S3PrepareMemoryForAPs ( + OUT EFI_PHYSICAL_ADDRESS *WakeUpBuffer, + OUT VOID **StackAddressStart + ) +{ + return EFI_SUCCESS; +} + +/** + Prepare exchange information for APs. + + @param[in] ExchangeInfo - Pointer to the exchange info for output. + @param[in] StackAddressStart - Start address of APs' stacks. + @param[in] ApFunction - Address of function assigned to AP. + @param[in] WakeUpBuffer - Pointer to the address of wakeup buffer. + + @retval EFI_SUCCESS - Exchange Info successfully prepared for APs. +**/ +EFI_STATUS +S3PrepareExchangeInfo ( + OUT MP_CPU_EXCHANGE_INFO *ExchangeInfo, + IN VOID *StackAddressStart, + IN VOID *ApFunction, + IN EFI_PHYSICAL_ADDRESS WakeUpBuffer + ) +{ + return EFI_SUCCESS; +} + +/** + Dynamically write the far jump destination in APs' wakeup buffer, + in order to refresh APs' CS registers for mode switching. +**/ +VOID +RedirectFarJump ( + VOID + ) +{ + MP_ASSEMBLY_ADDRESS_MAP AddressMap; + + AsmGetAddressMap (&AddressMap); + *(UINT32 *) (UINTN) (mAcpiCpuData->WakeUpBuffer + AddressMap.FlatJumpOffset + 3) = (UINT32) (mAcpiCpuData->WakeUpBuffer + AddressMap.PModeEntryOffset); + *(UINT32 *) (UINTN) (mAcpiCpuData->WakeUpBuffer + AddressMap.LongJumpOffset + 2) = (UINT32) (mAcpiCpuData->WakeUpBuffer + AddressMap.LModeEntryOffset); + + return; +} + +/** + Prepare GDTR and IDTR for AP + + @param[in] Gdtr - The GDTR profile + @param[in] Idtr - The IDTR profile + + @retval EFI_STATUS - status returned by each sub-routine + @retval EFI_SUCCESS - GDTR and IDTR has been prepared for AP +**/ +EFI_STATUS +PrepareGdtIdtForAP ( + OUT PSEUDO_DESCRIPTOR *Gdtr, + OUT PSEUDO_DESCRIPTOR *Idtr + ) +{ + INTERRUPT_GATE_DESCRIPTOR *IdtForAP; + SEGMENT_DESCRIPTOR *GdtForAP; + + PSEUDO_DESCRIPTOR *IdtrForBSP; + PSEUDO_DESCRIPTOR *GdtrForBSP; + + UINT16 *MceHandler; + EFI_STATUS Status; + + AsmGetGdtrIdtr (&GdtrForBSP, &IdtrForBSP); + + /// + /// Allocate reserved memory for IDT + /// + Status = AllocateAlignedReservedMemory ( + IdtrForBSP->Limit + 1, + 8, + (VOID **) &IdtForAP + ); + if (EFI_ERROR (Status)) { + return Status; + } + + /// + /// Allocate reserved memory for GDT + /// + Status = AllocateAlignedReservedMemory ( + GdtrForBSP->Limit + 1, + 8, + (VOID **) &GdtForAP + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = (gBS->AllocatePool)(EfiReservedMemoryType, SIZE_OF_MCE_HANDLER, (VOID **) &MceHandler); + if (EFI_ERROR (Status)) { + return Status; + } + + /// + /// McheHandler content: iret (opcode = 0xcf) + /// + *MceHandler = 0xCF48; + + CopyMem (GdtForAP, (VOID *) GdtrForBSP->Base, GdtrForBSP->Limit + 1); + CopyMem (IdtForAP, (VOID *) IdtrForBSP->Base, IdtrForBSP->Limit + 1); + + IdtForAP[INTERRUPT_HANDLER_MACHINE_CHECK].Offset15To0 = (UINT16) (UINTN) MceHandler; + IdtForAP[INTERRUPT_HANDLER_MACHINE_CHECK].Offset31To16 = (UINT16) ((UINTN) MceHandler >> 16); + IdtForAP[INTERRUPT_HANDLER_MACHINE_CHECK].Offset63To32 = (UINT32) ((UINTN) MceHandler >> 32); + + /// + /// Create Gdtr, IDTR profile + /// + Gdtr->Base = (UINTN) GdtForAP; + Gdtr->Limit = GdtrForBSP->Limit; + + Idtr->Base = (UINTN) IdtForAP; + Idtr->Limit = IdtrForBSP->Limit; + + return EFI_SUCCESS; +} diff --git a/ReferenceCode/Haswell/CpuInit/Dxe/x64/MemoryOperationDbgr.c b/ReferenceCode/Haswell/CpuInit/Dxe/x64/MemoryOperationDbgr.c new file mode 100644 index 0000000..329a4a5 --- /dev/null +++ b/ReferenceCode/Haswell/CpuInit/Dxe/x64/MemoryOperationDbgr.c @@ -0,0 +1,749 @@ +/** @file + Memory Operation Functions for IA32 Architecture. + +@copyright + Copyright (c) 2006 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement + +**/ +#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000) +#include "EdkIIGlueDxe.h" +#include "CpuInitDxeDbgr.h" +#include "CpuLib.h" +#include "MpCommon.h" +#include "VirtualMemory.h" +#include "MemoryAttribute.h" +#endif + +//(AMI_CHG+)> +#if defined(AMI_PEI_DEBUG_SUPPORT) && AMI_PEI_DEBUG_SUPPORT +extern AMI_DEBUGGER_CPU_PROTOCOL *mAmiDebuggerCpuProtocol; +#endif +//<(AMI_CHG+) + +VOID +InitializeExternalVectorTablePtr ( + EFI_CPU_INTERRUPT_HANDLER *VectorTable + ); + +extern EFI_CPU_INTERRUPT_HANDLER mExternalVectorTable[]; +extern EFI_PHYSICAL_ADDRESS mBackupBuffer; + +UINT8 *mPageStore = NULL; +UINTN mPageStoreSize = 16; +UINTN mPageStoreIndex = 0; + +UINT64 mValidMtrrAddressMask; +UINT64 mValidMtrrBitsMask; + +/// +/// BugBug: Non Portable +/// +#if defined (__GNUC__) +#define ALIGN_16BYTE_BOUNDRY __attribute__ ((aligned (16))) +#else +#define ALIGN_16BYTE_BOUNDRY __declspec (align (16)) +#endif + +#pragma pack(1) +typedef struct { + UINT16 LimitLow; + UINT16 BaseLow; + UINT8 BaseMiddle; + UINT8 Attributes1; + UINT8 Attributes2; + UINT8 BaseHigh; +} SEGMENT_DESCRIPTOR_x64; + +typedef struct { + UINT16 Limit; + UINTN Base; +} PSEUDO_DESCRIPTOR_x64; + +#pragma pack() + +ALIGN_16BYTE_BOUNDRY SEGMENT_DESCRIPTOR_x64 gGdt[] = { + { /// NULL Selector: selector[0] + 0, /// limit 15:0 + 0, /// base 15:0 + 0, /// base 23:16 + 0, /// + 0, /// type & limit 19:16 + 0, /// base 31:24 + /// 0, /// base 63:32 + /// 0 /// reserved + /// + }, + { /// Linear Selector: selector[8] + 0xffff, /// limit 15:0 + 0, /// base 15:0 + 0, /// base 23:16 + 0x93, /// present, ring 0, data, expand-up writable + 0xcf, /// type & limit 19:16 + 0, /// base 31:24 + /// 0, /// base 63:32 + /// 0 /// reserved + /// + }, + { /// Linear code Selector: selector[10] + 0xffff, /// limit 15:0 + 0, /// base 15:0 + 0, /// base 23:16 + 0x9b, /// present, ring 0, code, expand-up writable + 0xcf, /// type & limit 19:16 + 0, /// base 31:24 + /// 0, /// base 63:32 + /// 0 /// reserved + /// + }, + { /// Compatibility mode data Selector: selector[18] + 0xffff, /// limit 15:0 + 0, /// base 15:0 + 0, /// base 23:16 + 0x93, /// type & limit 19:16 + 0xcf, + 0, /// base 31:24 + /// 0, /// base 63:32 + /// 0 /// reserved + /// + }, + { /// Compatibility code Selector: selector[20] + 0xffff, /// limit 15:0 + 0, /// base 15:0 + 0, /// base 23:16 + 0x9b, /// type & limit 19:16 + 0xcf, + 0, /// base 31:24 + /// 0, /// base 63:32 + /// 0 /// reserved + /// + }, + { /// Spare3 Selector: selector[28] + 0, /// limit 15:0 + 0, /// base 15:0 + 0, /// base 23:16 + 0, /// type & limit 19:16 + 0, /// base 31:24 + 0, + /// + /// 0, /// base 63:32 + /// 0 /// reserved + /// + }, + { /// 64-bit data Selector:selector[30] + 0xffff, /// limit 15:0 + 0, /// base 15:0 + 0, /// base 23:16 + 0x93, /// type & limit 19:16 + 0xcf, + 0, /// base 31:24 + /// 0, /// base 63:32 + /// 0 /// reserved + /// + }, + { /// 64-bit code Selector: selector[38] + 0xffff, /// limit 15:0 + 0, /// base 15:0 + 0, /// base 23:16 + 0x9b, /// type & limit 19:16 + 0xaf, + 0, /// base 31:24 + /// 0, /// base 63:32 + /// 0 /// reserved + /// + }, + { /// Spare3 Selector: selector[40] + 0, /// limit 15:0 + 0, /// base 15:0 + 0, /// base 23:16 + 0, /// type & limit 19:16 + 0, /// base 31:24 + 0, + /// + /// 0, /// base 63:32 + /// 0 /// reserved + /// + } +}; + +ALIGN_16BYTE_BOUNDRY PSEUDO_DESCRIPTOR_x64 gGdtPseudoDescriptor = { + sizeof (gGdt) - 1, + (UINTN) gGdt +}; + +INTERRUPT_GATE_DESCRIPTOR gIdtTable[INTERRUPT_VECTOR_NUMBER] = { 0 }; + +ALIGN_16BYTE_BOUNDRY PSEUDO_DESCRIPTOR_x64 gLidtPseudoDescriptor = { + sizeof (gIdtTable) - 1, + (UINTN) gIdtTable +}; + +/** + Init Global Descriptor table +**/ +VOID +InitializeSelectors ( + VOID + ) +{ + CpuLoadGlobalDescriptorTable (&gGdtPseudoDescriptor); +} + +/** + Generic IDT Vector Handlers for the Host +**/ +VOID +AsmIdtVector00 ( + VOID + ); + +/** + Initialize Interrupt descriptor Tables +**/ +VOID +InitializeInterruptTables ( + VOID + ) +{ + UINT16 CodeSegment; + INTERRUPT_GATE_DESCRIPTOR *IdtEntry; + UINT8 *CurrentHandler; + UINT32 Index; + +//(AMI_CHG+)> +#if defined(AMI_PEI_DEBUG_SUPPORT) && AMI_PEI_DEBUG_SUPPORT + EFI_STATUS Status; +#endif +//<(AMI_CHG+) + + CodeSegment = CpuCodeSegment (); + + IdtEntry = gIdtTable; + CurrentHandler = (UINT8 *) (UINTN) AsmIdtVector00; + for (Index = 0; Index < INTERRUPT_VECTOR_NUMBER; Index++) { + IdtEntry[Index].Offset15To0 = (UINT16) (UINTN) CurrentHandler; + IdtEntry[Index].SegmentSelector = CodeSegment; + IdtEntry[Index].Attributes = INTERRUPT_GATE_ATTRIBUTE; + /// + /// 8e00; + /// + IdtEntry[Index].Offset31To16 = (UINT16) ((UINTN) CurrentHandler >> 16); + IdtEntry[Index].Offset63To32 = (UINT32) ((UINTN) CurrentHandler >> 32); + +//(AMI_CHG+)> +#if defined(AMI_PEI_DEBUG_SUPPORT) && AMI_PEI_DEBUG_SUPPORT + Status = mAmiDebuggerCpuProtocol->DebuggerFixUpPEIExceptionHandlers( + (DEBUGGER_INTERRUPT_GATE_DESCRIPTOR *)IdtEntry, + Index); +#endif +//<(AMI_CHG+) + + CurrentHandler += 0x8; + /// + } + + CpuLoadInterruptDescriptorTable (&gLidtPseudoDescriptor); + + return; +} + +/** + Initialize cache attributes based on MTRR +**/ +VOID +InitailizeCacheAttributes ( + VOID + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Page; + EFI_CPUID_REGISTER FeatureInfo; + EFI_CPUID_REGISTER FunctionInfo; + UINT8 PhysicalAddressBits; + UINT32 MsrNum; + UINT64 TempQword; + UINT64 ComplementBits; + UINT32 VariableMtrrLimit; + + VariableMtrrLimit = (UINT32) (AsmReadMsr64 (IA32_MTRR_CAP) & B_IA32_MTRR_VARIABLE_SUPPORT); + + /// + /// Allocate 16 pages + /// + Status = (gBS->AllocatePages)(AllocateAnyPages, EfiBootServicesData, mPageStoreSize, &Page); + ASSERT_EFI_ERROR (Status); + + mPageStore = (UINT8 *) (UINTN) Page; + + ZeroMem (mPageStore, 0x1000 * mPageStoreSize); + + /// + /// Check returned value of Eax for extended CPUID functions + /// + AsmCpuid ( + CPUID_EXTENDED_FUNCTION, + &FunctionInfo.RegEax, + &FunctionInfo.RegEbx, + &FunctionInfo.RegEcx, + &FunctionInfo.RegEdx + ); + + PhysicalAddressBits = 36; + + /// + /// If CPU supports extended functions, get the Physical Address size by reading EAX[7:0] + /// + if (FunctionInfo.RegEax > CPUID_EXTENDED_FUNCTION) { + AsmCpuid ( + CPUID_VIR_PHY_ADDRESS_SIZE, + &FeatureInfo.RegEax, + &FeatureInfo.RegEbx, + &FeatureInfo.RegEcx, + &FeatureInfo.RegEdx + ); + PhysicalAddressBits = (UINT8) FeatureInfo.RegEax; + } + + mValidMtrrBitsMask = (((UINT64) 1) << PhysicalAddressBits) - 1; + mValidMtrrAddressMask = mValidMtrrBitsMask & 0xfffffffffffff000; + + ComplementBits = mValidMtrrBitsMask & 0xfffffff000000000; + if (ComplementBits != 0) { + /// + /// Disable cache and clear the corresponding MTRR bits + /// + PreMtrrChange (); + for (MsrNum = CACHE_VARIABLE_MTRR_BASE; + MsrNum < (CACHE_VARIABLE_MTRR_BASE + VariableMtrrLimit * 2 - 1); + MsrNum += 2 + ) { + TempQword = AsmReadMsr64 (MsrNum + 1); + if ((TempQword & B_CACHE_MTRR_VALID) != 0) { + /// + /// MTRR Physical Mask + /// + TempQword = TempQword | ComplementBits; + AsmWriteMsr64 (MsrNum + 1, TempQword); + } + } + + /// + /// Enable Cache and set the corresponding MTRR bits + /// + PostMtrrChange (); + } +} + +/** + Allocate zeroed pages + + @retval Pointer to the page buffer +**/ +VOID * +AllocateZeroedPage ( + VOID + ) +{ + if (mPageStoreIndex >= mPageStoreSize) { + /// + /// We are out of space + /// + return NULL; + } + + return (VOID *) (UINTN) &mPageStore[0x1000 * mPageStoreIndex++]; +} + +/** + Convert 2MB page tables to 4KB page tables + + @param[in] PageAddress - Page address to convert + @param[in] PageDirectoryToConvert - Page table that will be converted +**/ +VOID +Convert2MBPageTo4KPages ( + IN EFI_PHYSICAL_ADDRESS PageAddress, + IN OUT x64_PAGE_TABLE_ENTRY **PageDirectoryToConvert + ) +{ + UINTN Index; + EFI_PHYSICAL_ADDRESS WorkingAddress; + x64_PAGE_TABLE_ENTRY_4K *PageTableEntry; + x64_PAGE_TABLE_ENTRY Attributes; + + /// + /// Save the attributes of the 2MB table + /// + Attributes.Page2Mb.Uint64 = (*PageDirectoryToConvert)->Page2Mb.Uint64; + + /// + /// Convert PageDirectoryEntry2MB into a 4K Page Directory + /// + PageTableEntry = AllocateZeroedPage (); + if (PageTableEntry == NULL) { + return; + } + (*PageDirectoryToConvert)->Page2Mb.Uint64 = (UINT64) PageTableEntry; + (*PageDirectoryToConvert)->Page2Mb.Bits.ReadWrite = 1; + (*PageDirectoryToConvert)->Page2Mb.Bits.Present = 1; + + WorkingAddress = PageAddress; + for (Index = 0; Index < 512; Index++, PageTableEntry++, WorkingAddress += 0x1000) { + PageTableEntry->Uint64 = (UINT64) WorkingAddress; + PageTableEntry->Bits.Present = 1; + + /// + /// Update the new page to have the same attributes as the 2MB page + /// + PageTableEntry->Bits.ReadWrite = Attributes.Common.ReadWrite; + PageTableEntry->Bits.CacheDisabled = Attributes.Common.CacheDisabled; + PageTableEntry->Bits.WriteThrough = Attributes.Common.WriteThrough; + + if (WorkingAddress == PageAddress) { + /// + /// Return back the 4K page that matches the Working addresss + /// + *PageDirectoryToConvert = (x64_PAGE_TABLE_ENTRY *) PageTableEntry; + } + } +} + +/** + Get current memory mapping information + + @param[in] BaseAddress - get current memory mapping by this Base address + @param[in] PageTable - page table that translated this base address + @param[in] Page2MBytes - TRUE if this is 2MBytes page table + + @retval EFI_NOT_FOUND - page table not found + @retval EFI_SUCCESS - page table found +**/ +EFI_STATUS +GetCurrentMapping ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + OUT x64_PAGE_TABLE_ENTRY **PageTable, + OUT BOOLEAN *Page2MBytes + ) +{ + UINT64 Cr3; + x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *PageMapLevel4Entry; + x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *PageDirectoryPointerEntry; + x64_PAGE_TABLE_ENTRY_2M *PageTableEntry2Mb; + x64_PAGE_DIRECTORY_ENTRY_4K *PageDirectoryEntry4k; + x64_PAGE_TABLE_ENTRY_4K *PageTableEntry4k; + UINTN Pml4Index; + UINTN PdpIndex; + UINTN Pde2MbIndex; + UINTN PteIndex; + + Cr3 = AsmReadCr3 (); + + PageMapLevel4Entry = (x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *) (Cr3 & 0x000ffffffffff000); + + Pml4Index = (UINTN) RShiftU64 (BaseAddress, 39) & 0x1ff; + if (PageMapLevel4Entry[Pml4Index].Bits.Present == 0) { + return EFI_NOT_FOUND; + } + + PageDirectoryPointerEntry = (x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *) (PageMapLevel4Entry[Pml4Index].Uint64 & 0x000ffffffffff000); + PdpIndex = (UINTN) RShiftU64 (BaseAddress, 30) & 0x1ff; + if (PageDirectoryPointerEntry[PdpIndex].Bits.Present == 0) { + return EFI_NOT_FOUND; + } + + PageTableEntry2Mb = (x64_PAGE_TABLE_ENTRY_2M *) (PageDirectoryPointerEntry[PdpIndex].Uint64 & 0x000ffffffffff000); + Pde2MbIndex = (UINTN) RShiftU64 (BaseAddress, 21) & 0x1ff; + if (PageTableEntry2Mb[Pde2MbIndex].Bits.Present == 0) { + return EFI_NOT_FOUND; + } + + if (PageTableEntry2Mb[Pde2MbIndex].Bits.MustBe1 == 1) { + /// + /// We found a 2MByte page so lets return it + /// + *Page2MBytes = TRUE; + *PageTable = (x64_PAGE_TABLE_ENTRY *) &PageTableEntry2Mb[Pde2MbIndex].Uint64; + return EFI_SUCCESS; + } + + /// + /// 4K page so keep walking + /// + PageDirectoryEntry4k = (x64_PAGE_DIRECTORY_ENTRY_4K *) &PageTableEntry2Mb[Pde2MbIndex].Uint64; + + PageTableEntry4k = (x64_PAGE_TABLE_ENTRY_4K *) (PageDirectoryEntry4k[Pde2MbIndex].Uint64 & 0x000ffffffffff000); + PteIndex = (UINTN) RShiftU64 (BaseAddress, 12) & 0x1ff; + if (PageTableEntry4k[PteIndex].Bits.Present == 0) { + return EFI_NOT_FOUND; + } + + *Page2MBytes = FALSE; + *PageTable = (x64_PAGE_TABLE_ENTRY *) &PageTableEntry4k[PteIndex]; + return EFI_SUCCESS; +} + +/** + Prepare memory for essential system tables. + + @retval EFI_SUCCESS - Memory successfully prepared. +**/ +EFI_STATUS +PrepareMemory ( + VOID + ) +{ + /// + /// Allocate space to convert 2MB page tables to 4K tables. + /// This can not be done at call time as the TPL level will + /// not be correct. + /// + InitailizeCacheAttributes (); + + InitializeExternalVectorTablePtr (mExternalVectorTable); + /// + /// Initialize the Interrupt Descriptor Table + /// + InitializeInterruptTables (); + + return EFI_SUCCESS; +} + +/** + Prepare Wakeup Buffer and stack for APs. + + @param[in] WakeUpBuffer - Pointer to the address of wakeup buffer for output. + @param[in] StackAddressStart - Pointer to the stack address of APs for output. + @param[in] MaximumCPUsForThisSystem - Maximum CPUs in this system. + + @retval EFI_SUCCESS - Memory successfully prepared for APs. + @retval Other - Error occurred while allocating memory. +**/ +EFI_STATUS +PrepareMemoryForAPs ( + OUT EFI_PHYSICAL_ADDRESS *WakeUpBuffer, + OUT VOID **StackAddressStart, + IN UINTN MaximumCPUsForThisSystem + ) +{ + EFI_STATUS Status; + MP_ASSEMBLY_ADDRESS_MAP AddressMap; + + /// + /// Release All APs with a lock and wait for them to retire to rendezvous procedure. + /// We need a page (4KB) of memory for IA-32 to use broadcast APIs, on a temporary basis. + /// + Status = AllocateWakeUpBuffer (WakeUpBuffer); + if (EFI_ERROR (Status)) { + return Status; + } + + /// + /// Claim memory for AP stack + /// + Status = AllocateReservedMemoryBelow4G ( + MaximumCPUsForThisSystem * STACK_SIZE_PER_PROC, + StackAddressStart + ); + + if (EFI_ERROR (Status)) { + (gBS->FreePages)(*WakeUpBuffer, 1); + return Status; + } + + AsmGetAddressMap (&AddressMap); + CopyMem ((VOID *) (UINTN) *WakeUpBuffer, AddressMap.RendezvousFunnelAddress, AddressMap.Size); + *(UINT32 *) (UINTN) (*WakeUpBuffer + AddressMap.FlatJumpOffset + 3) = (UINT32) (*WakeUpBuffer + AddressMap.PModeEntryOffset); + *(UINT32 *) (UINTN) (*WakeUpBuffer + AddressMap.LongJumpOffset + 2) = (UINT32) (*WakeUpBuffer + AddressMap.LModeEntryOffset); + + return EFI_SUCCESS; +} + +/** + Prepare exchange information for APs. + + @param[in] ExchangeInfo - Pointer to the exchange info buffer for output. + @param[in] StackAddressStart - Start address of APs' stacks. + @param[in] ApFunction - Address of function assigned to AP. + @param[in] WakeUpBuffer - Pointer to the address of wakeup buffer. + + @retval EFI_SUCCESS - Exchange Info successfully prepared for APs. +**/ +EFI_STATUS +PrepareExchangeInfo ( + OUT MP_CPU_EXCHANGE_INFO *ExchangeInfo, + IN VOID *StackAddressStart, + IN VOID *ApFunction, + IN EFI_PHYSICAL_ADDRESS WakeUpBuffer + ) +{ + ZeroMem ((VOID *) ExchangeInfo, EFI_PAGE_SIZE - MP_CPU_EXCHANGE_INFO_OFFSET); + + ExchangeInfo->Lock = VacantFlag; + ExchangeInfo->StackStart = StackAddressStart; + ExchangeInfo->StackSize = STACK_SIZE_PER_PROC; + ExchangeInfo->ApFunction = ApFunction; + + CopyMem ( + (VOID *) (UINTN) &ExchangeInfo->GdtrProfile, + (VOID *) (UINTN) mAcpiCpuData->GdtrProfile, + sizeof (PSEUDO_DESCRIPTOR) + ); + CopyMem ( + (VOID *) (UINTN) &ExchangeInfo->IdtrProfile, + (VOID *) (UINTN) mAcpiCpuData->IdtrProfile, + sizeof (PSEUDO_DESCRIPTOR) + ); + + ExchangeInfo->BufferStart = (UINT32) WakeUpBuffer; + ExchangeInfo->Cr3 = (UINT32) (AsmReadCr3 ()); + ExchangeInfo->InitFlag = 1; + + return EFI_SUCCESS; +} + +/** + Prepare Wakeup Buffer and stack for APs. + + @param[in] WakeUpBuffer - Pointer to the address of wakeup buffer for output. + @param[in] StackAddressStart - Pointer to the stack address of APs for output. + + @retval EFI_SUCCESS - Memory successfully prepared for APs. +**/ +EFI_STATUS +S3PrepareMemoryForAPs ( + OUT EFI_PHYSICAL_ADDRESS *WakeUpBuffer, + OUT VOID **StackAddressStart + ) +{ + return EFI_SUCCESS; +} + +/** + Prepare exchange information for APs. + + @param[in] ExchangeInfo - Pointer to the exchange info for output. + @param[in] StackAddressStart - Start address of APs' stacks. + @param[in] ApFunction - Address of function assigned to AP. + @param[in] WakeUpBuffer - Pointer to the address of wakeup buffer. + + @retval EFI_SUCCESS - Exchange Info successfully prepared for APs. +**/ +EFI_STATUS +S3PrepareExchangeInfo ( + OUT MP_CPU_EXCHANGE_INFO *ExchangeInfo, + IN VOID *StackAddressStart, + IN VOID *ApFunction, + IN EFI_PHYSICAL_ADDRESS WakeUpBuffer + ) +{ + return EFI_SUCCESS; +} + +/** + Dynamically write the far jump destination in APs' wakeup buffer, + in order to refresh APs' CS registers for mode switching. +**/ +VOID +RedirectFarJump ( + VOID + ) +{ + MP_ASSEMBLY_ADDRESS_MAP AddressMap; + + AsmGetAddressMap (&AddressMap); + *(UINT32 *) (UINTN) (mAcpiCpuData->WakeUpBuffer + AddressMap.FlatJumpOffset + 3) = (UINT32) (mAcpiCpuData->WakeUpBuffer + AddressMap.PModeEntryOffset); + *(UINT32 *) (UINTN) (mAcpiCpuData->WakeUpBuffer + AddressMap.LongJumpOffset + 2) = (UINT32) (mAcpiCpuData->WakeUpBuffer + AddressMap.LModeEntryOffset); + + return; +} + +/** + Prepare GDTR and IDTR for AP + + @param[in] Gdtr - The GDTR profile + @param[in] Idtr - The IDTR profile + + @retval EFI_STATUS - status returned by each sub-routine + @retval EFI_SUCCESS - GDTR and IDTR has been prepared for AP +**/ +EFI_STATUS +PrepareGdtIdtForAP ( + OUT PSEUDO_DESCRIPTOR *Gdtr, + OUT PSEUDO_DESCRIPTOR *Idtr + ) +{ + INTERRUPT_GATE_DESCRIPTOR *IdtForAP; + SEGMENT_DESCRIPTOR *GdtForAP; + + PSEUDO_DESCRIPTOR *IdtrForBSP; + PSEUDO_DESCRIPTOR *GdtrForBSP; + + UINT16 *MceHandler; + EFI_STATUS Status; + + AsmGetGdtrIdtr (&GdtrForBSP, &IdtrForBSP); + + /// + /// Allocate reserved memory for IDT + /// + Status = AllocateAlignedReservedMemory ( + IdtrForBSP->Limit + 1, + 8, + (VOID **) &IdtForAP + ); + if (EFI_ERROR (Status)) { + return Status; + } + + /// + /// Allocate reserved memory for GDT + /// + Status = AllocateAlignedReservedMemory ( + GdtrForBSP->Limit + 1, + 8, + (VOID **) &GdtForAP + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = (gBS->AllocatePool)(EfiReservedMemoryType, SIZE_OF_MCE_HANDLER, (VOID **) &MceHandler); + if (EFI_ERROR (Status)) { + return Status; + } + + /// + /// McheHandler content: iret (opcode = 0xcf) + /// + *MceHandler = 0xCF48; + + CopyMem (GdtForAP, (VOID *) GdtrForBSP->Base, GdtrForBSP->Limit + 1); + CopyMem (IdtForAP, (VOID *) IdtrForBSP->Base, IdtrForBSP->Limit + 1); + + IdtForAP[INTERRUPT_HANDLER_MACHINE_CHECK].Offset15To0 = (UINT16) (UINTN) MceHandler; + IdtForAP[INTERRUPT_HANDLER_MACHINE_CHECK].Offset31To16 = (UINT16) ((UINTN) MceHandler >> 16); + IdtForAP[INTERRUPT_HANDLER_MACHINE_CHECK].Offset63To32 = (UINT32) ((UINTN) MceHandler >> 32); + + /// + /// Create Gdtr, IDTR profile + /// + Gdtr->Base = (UINTN) GdtForAP; + Gdtr->Limit = GdtrForBSP->Limit; + + Idtr->Base = (UINTN) IdtForAP; + Idtr->Limit = IdtrForBSP->Limit; + + return EFI_SUCCESS; +} diff --git a/ReferenceCode/Haswell/CpuInit/Dxe/x64/MpCpu.c b/ReferenceCode/Haswell/CpuInit/Dxe/x64/MpCpu.c new file mode 100644 index 0000000..806dcc0 --- /dev/null +++ b/ReferenceCode/Haswell/CpuInit/Dxe/x64/MpCpu.c @@ -0,0 +1,89 @@ +/** @file + MP Support functions + +@copyright + Copyright (c) 2007 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +**/ +#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000) +#include "EdkIIGlueDxe.h" +#include "MpService.h" +#include EFI_PROTOCOL_DEFINITION (MpService) +#endif + +extern EFI_CPU_MICROCODE_HEADER **mMicrocodePointerBuffer; + +ACPI_CPU_DATA *mAcpiCpuData; +MP_SYSTEM_DATA *mMPSystemData; + +/// +/// Function declarations +/// +/** + Initializes MP support in the system. + + @retval EFI_SUCCESS - Multiple processors are initialized successfully. + @retval EFI_OUT_OF_RESOURCES - No enough resoruces (such as out of memory). +**/ +EFI_STATUS +InitializeMpSupport ( + VOID + ) +{ + EFI_STATUS Status; + MP_CPU_RESERVED_DATA *MpCpuReservedData; + + /// + /// Allocate memory for MP CPU related data below 4G + /// + Status = AllocateReservedMemoryBelow4G ( + sizeof (MP_CPU_RESERVED_DATA), + (VOID **) &MpCpuReservedData + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + ZeroMem (MpCpuReservedData, sizeof (MP_CPU_RESERVED_DATA)); + + mMPSystemData = &(MpCpuReservedData->MPSystemData); + mAcpiCpuData = &(MpCpuReservedData->AcpiCpuData); + + /// + /// Copy microcode to allocated memory + /// + CopyMem ( + MpCpuReservedData->MicrocodePointerBuffer, + mMicrocodePointerBuffer, + sizeof (EFI_CPU_MICROCODE_HEADER *) * (NUMBER_OF_MICROCODE_UPDATE + 1) + ); + + /// + /// Initialize ACPI_CPU_DATA data + /// + mAcpiCpuData->CpuPrivateData = (EFI_PHYSICAL_ADDRESS) (UINTN) (&(mMPSystemData->S3DataPointer)); + mAcpiCpuData->S3BootPath = FALSE; + mAcpiCpuData->MicrocodePointerBuffer = (EFI_PHYSICAL_ADDRESS) MpCpuReservedData->MicrocodePointerBuffer; + mAcpiCpuData->GdtrProfile = (EFI_PHYSICAL_ADDRESS) & (MpCpuReservedData->GdtrProfile); + mAcpiCpuData->IdtrProfile = (EFI_PHYSICAL_ADDRESS) & (MpCpuReservedData->IdtrProfile); + + /// + /// Initialize MP services + /// + InitializeMpServices (); + + return EFI_SUCCESS; +} diff --git a/ReferenceCode/Haswell/CpuInit/Dxe/x64/MpEqu.inc b/ReferenceCode/Haswell/CpuInit/Dxe/x64/MpEqu.inc new file mode 100644 index 0000000..f7c97ad --- /dev/null +++ b/ReferenceCode/Haswell/CpuInit/Dxe/x64/MpEqu.inc @@ -0,0 +1,51 @@ +;@file +; @todo ADD DESCRIPTION +; +;@copyright +; Copyright (c) 2005 - 2012 Intel Corporation. All rights reserved +; This software and associated documentation (if any) is furnished +; under a license and may only be used or copied in accordance +; with the terms of the license. Except as permitted by such +; license, no part of this software or documentation may be +; reproduced, stored in a retrieval system, or transmitted in any +; form or by any means without the express written consent of +; Intel Corporation. +; +; This file contains an 'Intel Peripheral Driver' and uniquely +; identified as "Intel Reference Module" and is +; licensed for Intel CPUs and chipsets under the terms of your +; license agreement with Intel or your vendor. This file may +; be modified by the user, subject to additional terms of the +; license agreement +; + +VacantFlag Equ 00h +NotVacantFlag Equ 0ffh +BreakToRunApSignal Equ 6E755200h +MonitorFilterSize Equ 40h +WakeUpApCounterInit Equ 0 +WakeUpApPerHltLoop Equ 1 +WakeUpApPerMwaitLoop Equ 2 +WakeUpApPerRunLoop Equ 3 +WakeUpApPerMwaitLoop32 Equ 4 +WakeUpApPerRunLoop32 Equ 5 + +LockLocation equ 1000h - 0400h +StackStartAddressLocation equ LockLocation + 08h +StackSizeLocation equ LockLocation + 10h +CProcedureLocation equ LockLocation + 18h +GdtrLocation equ LockLocation + 20h +IdtrLocation equ LockLocation + 2Ah +BufferStartLocation equ LockLocation + 34h +Cr3OffsetLocation equ LockLocation + 38h +InitFlagLocation equ LockLocation + 3Ch +WakeUpApManner equ LockLocation + 40h +BistBuffer equ LockLocation + 44h + +PAUSE32 MACRO + DB 0F3h + DB 090h + ENDM + +;------------------------------------------------------------------------------- + diff --git a/ReferenceCode/Haswell/CpuInit/Dxe/x64/MpFuncs.asm b/ReferenceCode/Haswell/CpuInit/Dxe/x64/MpFuncs.asm new file mode 100644 index 0000000..58714f8 --- /dev/null +++ b/ReferenceCode/Haswell/CpuInit/Dxe/x64/MpFuncs.asm @@ -0,0 +1,618 @@ +; +; This file contains an 'Intel Peripheral Driver' and is +; licensed for Intel CPUs and chipsets under the terms of your +; license agreement with Intel or your vendor. This file may +; be modified by the user, subject to additional terms of the +; license agreement +; +;------------------------------------------------------------------------------- +; +; Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved +; This software and associated documentation (if any) is furnished +; under a license and may only be used or copied in accordance +; with the terms of the license. Except as permitted by such +; license, no part of this software or documentation may be +; reproduced, stored in a retrieval system, or transmitted in any +; form or by any means without the express written consent of +; Intel Corporation. +; +; +; Module Name: +; +; MpFuncs.asm +; +; Abstract: +; +; This is the assembly code for EM64T MP support +; +;------------------------------------------------------------------------------- + + +include MpEqu.inc +CpuInitFloatPointUnit PROTO C + +;------------------------------------------------------------------------------------- + +;------------------------------------------------------------------------------------- +;RendezvousFunnelProc procedure follows. All APs execute their procedure. This +;procedure serializes all the AP processors through an Init sequence. It must be +;noted that APs arrive here very raw...ie: real mode, no stack. +;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC +;IS IN MACHINE CODE. +;------------------------------------------------------------------------------------- +;RendezvousFunnelProc (&WakeUpBuffer,MemAddress); + +text SEGMENT + +RendezvousFunnelProc PROC PUBLIC +RendezvousFunnelProcStart:: + +; At this point CS = 0x(vv00) and ip= 0x0. + db 66h, 08bh, 0e8h ; mov ebp, eax + + db 8ch, 0c8h ; mov ax, cs + db 8eh, 0d8h ; mov ds, ax + db 8eh, 0c0h ; mov es, ax + db 8eh, 0d0h ; mov ss, ax + db 33h, 0c0h ; xor ax, ax + db 8eh, 0e0h ; mov fs, ax + db 8eh, 0e8h ; mov gs, ax + +; Get APIC ID +; + db 66h, 0B8h + dd 00000001h ; mov eax, 1 + db 0Fh, 0A2h ; cpuid + db 66h, 0C1h, 0EBh, 18h ; shr ebx, 24 + db 66h, 81h, 0E3h + dd 000000FFh ; and ebx, 0ffh ; EBX is APIC ID + +; If it is the first time AP wakes up, just record AP's BIST +; Otherwise, switch to protected mode. + + db 0BEh ; opcode of mov si, imm16 + dw InitFlagLocation ; mov si, InitFlag + db 66h, 83h, 3Ch, 00h ; cmp dword ptr [si], 0 + db 74h ; opcode of jz + db flat32Start - ($ + 1) ; jz flat32Start + +; Record BIST information +; + db 0B0h, 08h ; mov al, 8 + db 0F6h, 0E3h ; mul bl + + db 0BEh ; opcode of mov si, imm16 + dw BistBuffer ; mov si, BistBuffer + db 03h, 0F0h ; add si, ax + + db 66h, 0C7h, 04h + dd 00000001h ; mov dword ptr [si], 1 ; Set Valid Flag + db 66h, 89h, 6Ch, 04h ; mov dword ptr [si + 4], ebp ; Store BIST value + +; +; Switch to flat mode. +; +flat32Start:: + + db 0BFh ; opcode of mov di, imm16 + dw BufferStartLocation ; mov di, BufferStartLocation + db 66h, 8Bh, 35h ; mov esi,dword ptr [di] ; ESI is keeping the start address of wakeup buffer + + db 0BFh ; opcode of mov di, imm16 + dw Cr3OffsetLocation ; mov di, Cr3Location + db 66h, 8Bh, 0Dh ; mov ecx,dword ptr [di] ; ECX is keeping the value of CR3 + + db 0BFh ; opcode of mov di, imm16 + dw GdtrLocation ; mov di, GdtrProfile + db 66h ; db 66h + db 2Eh, 0Fh, 01h, 15h ; lgdt fword ptr cs:[di] + + db 0BFh ; opcode of mov di, imm16 + dw IdtrLocation ; mov di, IdtrProfile + db 66h ; db 66h + db 2Eh, 0Fh, 01h, 1Dh ; lidt fword ptr cs:[di] + + db 0BFh ; opcode of mov di, imm16 + dw LongModeStartJump - RendezvousFunnelProcStart ; Get offset of LongModeStartJump + db 66h, 8Bh, 3Dh ; mov edi,dword ptr [di] ; EDI is keeping the LongModeStart Jump Address + + db 31h, 0C0h ; xor ax, ax + db 8Eh, 0D8h ; mov ds, ax + + db 0Fh, 20h, 0C0h ; mov eax, cr0 ; Get control register 0 + db 66h, 83h, 0C8h, 03h ; or eax, 000000003h ; Set PE bit (bit #0) and MP + db 0Fh, 22h, 0C0h ; mov cr0, eax + +FLAT32_JUMP:: + + db 66h, 67h, 0EAh ; far jump + dd 0h ; 32-bit offset + dw 20h ; 16-bit selector + +NemInit:: ; 32-bits protected mode entry point + + db 66h, 0B8h, 18h, 00h ; mov ax, 18h + db 66h, 8Eh, 0D8h ; mov ds, ax + db 66h, 8Eh, 0C0h ; mov es, ax + db 66h, 8Eh, 0E0h ; mov fs, ax + db 66h, 8Eh, 0E8h ; mov gs, ax + db 66h, 8Eh, 0D0h ; mov ss, ax ; Flat mode setup. + + +PrepareToGoLongMode64:: + + db 0Fh, 20h, 0E0h ; mov eax, cr4 + db 66h, 0Dh, 020h, 06h ; or ax, 0620h ; Set PAE=1, OSFXSR=1, OSXMMEXCPT=1. + db 0Fh, 22h, 0E0h ; mov cr4, eax + + db 0Fh, 22h, 0D9h ; mov cr3, ecx + + db 0B9h + dd 0C0000080h ; mov ecx, 0c0000080h ; EFER MSR number. + db 0Fh, 32h ; rdmsr ; Read EFER. + db 0Fh, 0BAh, 0E8h, 08h ; bts eax, 8 ; Set LME=1. + db 0Fh, 30h ; wrmsr ; Write EFER. + + db 0Fh, 20h, 0C0h ; mov eax, cr0 ; Read CR0. + db 0Fh, 0BAh, 0E8h, 1Fh ; bts eax, 31 ; Set PG=1. + db 0Fh, 22h, 0C0h ; mov cr0, eax ; Write CR0. + +LONG_JUMP:: + + db 67h, 0EAh ; far jump + +LongModeStartJump: + + dd 0h ; 32-bit offset + dw 38h ; 16-bit selector + + +LongModeStart:: + + mov ax, 30h + mov ds, ax + mov es, ax + mov ss, ax + +WaitFirstApTaskAssigned:: +; +; First INIT-SIPI-SIPI will loop here until DetailedMpInitialization function assigned for each AP +; + pause + cmp qword ptr [esi+CProcedureLocation], 0 + jz WaitFirstApTaskAssigned + +; +; Patch Addresses for jumping between RUN and MONITOR MWAIT loops 32-bits and Long Monde Procedure 64-bits +; Based on the running address of LongModeStart in physic memory which was actually copied by CPU DXE INIT +; + xor rdx, rdx + mov eax, edi + add eax, RunLoopAndMwaitLoop32 - LongModeStart + mov edx, edi + add edx, RunLoopAndMwaitLoop32Jump - LongModeStart + mov dword ptr [rdx], eax + + mov rbp, rdx ; RBP = 32-bits compatibility mode FAR JUMP m16:32 operand pointer + + mov eax, edi + add eax, RunLoopAndMwaitLoop64 - LongModeStart + mov edx, edi + add edx, RunLoopAndMwaitLoop64Jump - LongModeStart + mov dword ptr [rdx], eax + +; +; ProgramStack +; + xor rcx, rcx + mov edi, esi + add edi, BistBuffer + mov ecx, dword ptr [edi + 8 * ebx] ; RCX = CpuNumber + + mov edi, esi + add edi, StackSizeLocation + mov rax, qword ptr [edi] + inc rcx + mul rcx ; RAX = StackSize * (CpuNumber + 1) + + mov edi, esi + add edi, StackStartAddressLocation + mov rdx, qword ptr [edi] + add rax, rdx ; RAX = StackStart + StackSize * (CpuNumber + 1) + + mov rsp, rax + sub rsp, MonitorFilterSize ; Reserved Monitor data space + or ebx, BreakToRunApSignal ; ebx = #Cpu run signature + +; +; Call assembly function to initialize FPU. +; + mov rax, CpuInitFloatPointUnit + sub rsp, 20h + call rax + add rsp, 20h + +; +; Load C Function pointer and wakeup manner location +; + mov edi, esi + add edi, CProcedureLocation + add esi, WakeUpApManner ; esi = WakeUpApManner Address Location + +WakeUpThisAp64:: + + mov rax, qword ptr [edi] + + test rax, rax + jz CheckWakeUpCounterInit64 + + push rbp + push rbx + push rsi + push rdi + + sub rsp, 20h + call rax + add rsp, 20h + + pop rdi + pop rsi + pop rbx + pop rbp + +CheckWakeUpCounterInit64:: + + cmp dword ptr [esi], WakeUpApCounterInit + jnz CheckWakeUpManner64 + +; +; Initialize MONITOR_MWAIT_DATA data structure per thread +; + xor rcx, rcx + mov qword ptr [rsp + 0], rcx ; BreakToRunApSignal + mov qword ptr [rsp + 8], rcx ; HltLoopBreakCounter + mov qword ptr [rsp + 16], rcx ; MwaitLoopBreakCounter + mov qword ptr [rsp + 24], rcx ; RunLoopBreakCounter + mov qword ptr [rsp + 32], rcx ; MwaitLoopBreakCounter32 + mov qword ptr [rsp + 40], rcx ; RunLoopBreakCounter32 + mov qword ptr [rsp + 48], rcx ; WakeUpApVectorChangeFlag + mov qword ptr [rsp + 56], rcx ; MwaitTargetCstate + +WaitWakeUpMannerAssigned:: + + pause + cmp dword ptr [esi], WakeUpApCounterInit + jz WaitWakeUpMannerAssigned + +CheckWakeUpManner64:: + + pause + mov edx, dword ptr [esi] + cmp edx, WakeUpApPerHltLoop + jz HltApLoop64 + + cmp edx, WakeUpApPerMwaitLoop + jz ApMwaitLoop64 + + cmp edx, WakeUpApPerRunLoop + jz CheckRunSignal64 + + jmp JumpToCompatibility32Mode + +ApMwaitLoop64:: + + cli + mov rax, rsp ; Set Monitor Address + xor rcx, rcx + xor rdx, rdx + DB 0fh, 1, 0c8h ; MONITOR + mov rax, qword ptr [rsp + 56] ; Mwait Target C-State per rax[7:4] + DB 0fh, 1, 0c9h ; MWAIT + +CheckRunSignal64:: + + cmp qword ptr [rsp], rbx ; Check if run signal correct? + jnz CheckWakeUpManner64 ; Unknown break, go checking run manner + + jmp WakeUpThisAp64 ; Jmp to execute AP task + +HltApLoop64:: + + cli + hlt + jmp HltApLoop64 ; Jump to halt loop + + +JumpToCompatibility32Mode:: + + db 0FFh, 6Dh, 0 ; jmp pword ptr [rbp+0] ; Far jump to m16:32 for 32-bits compatibility mode + +RunLoopAndMwaitLoop32Jump: + + dd 0h ; m32 part of m16:32 + dw 20h ; m16 part of m16:32 + +RunLoopAndMwaitLoop32:: + + db 66h, 0B8h, 18h, 00h ; mov ax, 18h + db 66h, 8Eh, 0D8h ; mov ds, ax + db 8eh, 0d0h ; mov ss, ax + + db 0Fh, 20h, 0C0h ; mov eax, cr0 ; Read CR0. + db 0Fh, 0BAh, 0F0h, 1Fh ; btr eax, 31 ; Reset PG=0. + db 0Fh, 22h, 0C0h ; mov cr0, eax ; Write CR0. + + db 0B9h + dd 0C0000080h ; mov ecx, 0c0000080h ; EFER MSR number. + db 0Fh, 32h ; rdmsr ; Read EFER. + db 0Fh, 0BAh, 0F0h, 08h ; btr eax, 8 ; Reset LME=0. + db 0Fh, 30h ; wrmsr ; Write EFER. + + db 0Fh, 20h, 0E0h ; mov eax, cr4 + db 24h, 0DFh ; and al, 0DFh ; Reset PAE=0 in CR4 bit 5 + db 0Fh, 22h, 0E0h ; mov cr4, eax + +CheckWakeUpManner32:: + + pause + cmp dword ptr [rsi], WakeUpApPerMwaitLoop32 ; Use rsi for esi per compling in 64-bits mode + jnz CheckRunSignal32 + + cli + mov eax, esp ; Set Monitor Address + xor ecx, ecx + xor edx, edx + DB 0fh, 1, 0c8h ; MONITOR + mov eax, dword ptr [rsp + 56] ; Mwait Target C-State per eax[7:4] + DB 0fh, 1, 0c9h ; MWAIT + + +CheckRunSignal32:: + + cmp dword ptr [rsp], ebx ; Check if run signal correct? + jnz CheckWakeUpManner32 ; Unknown break, go checking run manner + + db 0Fh, 20h, 0E0h ; mov eax, cr4 + db 0Ch, 20h ; or al, 20h ; Set PAE=1 in CR4 bit 5 + db 0Fh, 22h, 0E0h ; mov cr4, eax + + db 0B9h + dd 0C0000080h ; mov ecx, 0c0000080h ; EFER MSR number. + db 0Fh, 32h ; rdmsr ; Read EFER. + db 0Fh, 0BAh, 0E8h, 08h ; bts eax, 8 ; Set LME=1. + db 0Fh, 30h ; wrmsr ; Write EFER. + + db 0Fh, 20h, 0C0h ; mov eax, cr0 ; Read CR0. + db 0Fh, 0BAh, 0E8h, 1Fh ; bts eax, 31 ; Set PG=1. + db 0Fh, 22h, 0C0h ; mov cr0, eax ; Write CR0. + + db 67h, 0EAh ; far jump back to 64-bits long mode + +RunLoopAndMwaitLoop64Jump: + + dd 0h ; 32-bit offset + dw 38h ; 16-bit selector + +RunLoopAndMwaitLoop64:: + + mov ax, 30h + mov ds, ax + mov ss, ax + + jmp WakeUpThisAp64 + +RendezvousFunnelProc ENDP +RendezvousFunnelProcEnd:: + + +;------------------------------------------------------------------------------------- +; AsmGetAddressMap (&AddressMap); +;------------------------------------------------------------------------------------- +AsmGetAddressMap PROC PUBLIC + + mov rax, offset RendezvousFunnelProcStart + mov qword ptr [rcx], rax + mov qword ptr [rcx+8h], NemInit - RendezvousFunnelProcStart + mov qword ptr [rcx+10h], FLAT32_JUMP - RendezvousFunnelProcStart + mov qword ptr [rcx+18h], LongModeStart - RendezvousFunnelProcStart + mov qword ptr [rcx+20h], LONG_JUMP - RendezvousFunnelProcStart + mov qword ptr [rcx+28h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart + + ret + +AsmGetAddressMap ENDP + +AsmGetGdtrIdtr PROC PUBLIC + + sgdt GdtDesc + lea rax, GdtDesc + mov [rcx], rax + + sidt IdtDesc + lea rax, IdtDesc + mov [rdx], rax + + ret + +AsmGetGdtrIdtr ENDP + +AsmAcquireMPLock PROC PUBLIC + + mov al, NotVacantFlag +TryGetLock: + xchg al, byte ptr [rcx] + cmp al, VacantFlag + jz LockObtained + + pause + jmp TryGetLock + +LockObtained: + ret + +AsmAcquireMPLock ENDP + +AsmReleaseMPLock PROC PUBLIC + + mov al, VacantFlag + xchg al, byte ptr [rcx] + + ret + +AsmReleaseMPLock ENDP + +;------------------------------------------------------------------------------------- +;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is +;about to become an AP. It switches it'stack with the current AP. +;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo); +;------------------------------------------------------------------------------------- +CPU_SWITCH_STATE_IDLE equ 0 +CPU_SWITCH_STATE_STORED equ 1 +CPU_SWITCH_STATE_LOADED equ 2 + +AsmExchangeRole PROC PUBLIC + ; DO NOT call other functions in this function, since 2 CPU may use 1 stack + ; at the same time. If 1 CPU try to call a functiosn, stack will be corrupted. + + push rax + push rbx + push rcx + push rdx + push rsi + push rdi + push rbp + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + + mov rax, cr0 + push rax + + mov rax, cr4 + push rax + + ; rsi contains MyInfo pointer + mov rsi, rcx + + ; rdi contains OthersInfo pointer + mov rdi, rdx + + ;Store EFLAGS, GDTR and IDTR regiter to stack + pushfq + sgdt fword ptr [rsi + 16] + sidt fword ptr [rsi + 26] + + ; Store the its StackPointer + mov qword ptr [rsi + 8], rsp + + ; update its switch state to STORED + mov al, NotVacantFlag +TryLock1: + lock xchg al, byte ptr [rsi] + cmp al, VacantFlag + jz LockObtained1 + pause + jmp TryLock1 + +LockObtained1: + mov byte ptr [rsi + 1], CPU_SWITCH_STATE_STORED + lock xchg al, byte ptr [rsi] + +WaitForOtherStored:: + ; wait until the other CPU finish storing its state + mov al, NotVacantFlag +TryLock2: + lock xchg al, byte ptr [rdi] + cmp al, VacantFlag + jz LockObtained2 + PAUSE32 + jmp TryLock2 + +LockObtained2: + mov bl, byte ptr [rdi + 1] + lock xchg al, byte ptr [rdi] + cmp bl, CPU_SWITCH_STATE_STORED + jb WaitForOtherStored + + ; Since another CPU already stored its state, load them + ; load GDTR value + lgdt fword ptr [rdi + 16] + + ; load IDTR value + lidt fword ptr [rdi + 26] + + ; load its future StackPointer + mov rsp, qword ptr [rdi + 8] + + ; update its switch state to LOADED + mov al, NotVacantFlag +TryLock3: + lock xchg al, byte ptr [rsi] + cmp al, VacantFlag + jz LockObtained3 + PAUSE32 + jmp TryLock3 + +LockObtained3: + mov byte ptr [rsi+1], CPU_SWITCH_STATE_LOADED + lock xchg al, byte ptr [rsi] + +WaitForOtherLoaded:: + ; wait until the other CPU finish loading new state, + ; otherwise the data in stack may corrupt + mov al, NotVacantFlag +TryLock4: + lock xchg al, byte ptr [rdi] + cmp al, VacantFlag + jz LockObtained4 + PAUSE32 + jmp TryLock4 + +LockObtained4: + mov bl, byte ptr [rdi+1] + lock xchg al, byte ptr [rdi] + cmp bl, CPU_SWITCH_STATE_LOADED + jb WaitForOtherLoaded + + ; since the other CPU already get the data it want, leave this procedure + popfq + + pop rax + mov cr4, rax + + pop rax + mov cr0, rax + + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop rbp + pop rdi + pop rsi + pop rdx + pop rcx + pop rbx + pop rax + + ret +AsmExchangeRole ENDP + +GdtDesc QWORD 0 + WORD 0 + +IdtDesc QWORD 0 + WORD 0 + +text ENDS + +END diff --git a/ReferenceCode/Haswell/CpuInit/Dxe/x64/ProcessorDef.h b/ReferenceCode/Haswell/CpuInit/Dxe/x64/ProcessorDef.h new file mode 100644 index 0000000..28e55d7 --- /dev/null +++ b/ReferenceCode/Haswell/CpuInit/Dxe/x64/ProcessorDef.h @@ -0,0 +1,57 @@ +/** @file + Definition for EM64T processor + +@copyright + Copyright (c) 2006 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +**/ +#ifndef _PROCESSOR_DEF_H +#define _PROCESSOR_DEF_H + +#pragma pack(1) + +typedef struct { + UINT16 Offset15To0; + UINT16 SegmentSelector; + UINT16 Attributes; + UINT16 Offset31To16; + UINT32 Offset63To32; + UINT32 Reserved; +} INTERRUPT_GATE_DESCRIPTOR; + +#pragma pack() + +typedef struct { + UINT8 *RendezvousFunnelAddress; + UINTN PModeEntryOffset; + UINTN FlatJumpOffset; + UINTN LModeEntryOffset; + UINTN LongJumpOffset; + UINTN Size; +} MP_ASSEMBLY_ADDRESS_MAP; + +VOID +AsmGetAddressMap ( + OUT MP_ASSEMBLY_ADDRESS_MAP *AddressMap + ) +/** +@brief + Get address map of RendezvousFunnelProc. + + @param[in] AddressMap - Output buffer for address map information +**/ +; + +#endif diff --git a/ReferenceCode/Haswell/CpuInit/Dxe/x64/VirtualMemory.h b/ReferenceCode/Haswell/CpuInit/Dxe/x64/VirtualMemory.h new file mode 100644 index 0000000..f9bcc82 --- /dev/null +++ b/ReferenceCode/Haswell/CpuInit/Dxe/x64/VirtualMemory.h @@ -0,0 +1,145 @@ +/** @file + +@brief: + + x64 Long Mode Virtual Memory Management Definitions + + References: + 1) IA-32 Intel(R) Atchitecture Software Developer's Manual Volume 1:Basic Architecture, Intel + 2) IA-32 Intel(R) Atchitecture Software Developer's Manual Volume 2:Instruction Set Reference, Intel + 3) IA-32 Intel(R) Atchitecture Software Developer's Manual Volume 3:System Programmer's Guide, Intel + 4) AMD64 Architecture Programmer's Manual Volume 2: System Programming + +@copyright + Copyright (c) 2004 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +**/ +#ifndef _VIRTUAL_MEMORY_H_ +#define _VIRTUAL_MEMORY_H_ + +#pragma pack(1) +/// +/// Page-Map Level-4 Offset (PML4) and +///Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB +/// +typedef union { + struct { + UINT64 Present : 1; /// 0 = Not present in memory, 1 = Present in memory + UINT64 ReadWrite : 1; /// 0 = Read-Only, 1= Read/Write + UINT64 UserSupervisor : 1; /// 0 = Supervisor, 1=User + UINT64 WriteThrough : 1; /// 0 = Write-Back caching, 1=Write-Through caching + UINT64 CacheDisabled : 1; /// 0 = Cached, 1=Non-Cached + UINT64 Accessed : 1; /// 0 = Not accessed, 1 = Accessed (set by CPU) + UINT64 Reserved : 1; /// Reserved + UINT64 MustBeZero : 2; /// Must Be Zero + UINT64 Available : 3; /// Available for use by system software + UINT64 PageTableBaseAddress : 40; /// Page Table Base Address + UINT64 AvabilableHigh : 11; /// Available for use by system software + UINT64 Nx : 1; /// No Execute bit + } Bits; + UINT64 Uint64; +} x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K; + +/// +/// Page-Directory Offset 4K +/// +typedef union { + struct { + UINT64 Present : 1; /// 0 = Not present in memory, 1 = Present in memory + UINT64 ReadWrite : 1; /// 0 = Read-Only, 1= Read/Write + UINT64 UserSupervisor : 1; /// 0 = Supervisor, 1=User + UINT64 WriteThrough : 1; /// 0 = Write-Back caching, 1=Write-Through caching + UINT64 CacheDisabled : 1; /// 0 = Cached, 1=Non-Cached + UINT64 Accessed : 1; /// 0 = Not accessed, 1 = Accessed (set by CPU) + UINT64 Reserved : 1; /// Reserved + UINT64 MustBeZero : 1; /// Must Be Zero + UINT64 Reserved2 : 1; /// Reserved + UINT64 Available : 3; /// Available for use by system software + UINT64 PageTableBaseAddress : 40; /// Page Table Base Address + UINT64 AvabilableHigh : 11; /// Available for use by system software + UINT64 Nx : 1; /// No Execute bit + } Bits; + UINT64 Uint64; +} x64_PAGE_DIRECTORY_ENTRY_4K; + +/// +/// Page Table Entry 4K +/// +typedef union { + struct { + UINT64 Present : 1; /// 0 = Not present in memory, 1 = Present in memory + UINT64 ReadWrite : 1; /// 0 = Read-Only, 1= Read/Write + UINT64 UserSupervisor : 1; /// 0 = Supervisor, 1=User + UINT64 WriteThrough : 1; /// 0 = Write-Back caching, 1=Write-Through caching + UINT64 CacheDisabled : 1; /// 0 = Cached, 1=Non-Cached + UINT64 Accessed : 1; /// 0 = Not accessed, 1 = Accessed (set by CPU) + UINT64 Dirty : 1; /// 0 = Not Dirty, 1 = written by processor on access to page + UINT64 PAT : 1; /// 0 = Ignore Page Attribute Table + UINT64 Global : 1; /// 0 = Not global page, 1 = global page TLB not cleared on CR3 write + UINT64 Available : 3; /// Available for use by system software + UINT64 PageTableBaseAddress : 40; /// Page Table Base Address + UINT64 AvabilableHigh : 11; /// Available for use by system software + UINT64 Nx : 1; /// 0 = Execute Code, 1 = No Code Execution + } Bits; + UINT64 Uint64; +} x64_PAGE_TABLE_ENTRY_4K; + +/// +/// Page Table Entry 2MB +/// +typedef union { + struct { + UINT64 Present : 1; /// 0 = Not present in memory, 1 = Present in memory + UINT64 ReadWrite : 1; /// 0 = Read-Only, 1= Read/Write + UINT64 UserSupervisor : 1; /// 0 = Supervisor, 1=User + UINT64 WriteThrough : 1; /// 0 = Write-Back caching, 1=Write-Through caching + UINT64 CacheDisabled : 1; /// 0 = Cached, 1=Non-Cached + UINT64 Accessed : 1; /// 0 = Not accessed, 1 = Accessed (set by CPU) + UINT64 Dirty : 1; /// 0 = Not Dirty, 1 = written by processor on access to page + UINT64 MustBe1 : 1; /// Must be 1 + UINT64 Global : 1; /// 0 = Not global page, 1 = global page TLB not cleared on CR3 write + UINT64 Available : 3; /// Available for use by system software + UINT64 PAT : 1; /// + UINT64 MustBeZero : 8; /// Must be zero; + UINT64 PageTableBaseAddress : 31; /// Page Table Base Address + UINT64 AvabilableHigh : 11; /// Available for use by system software + UINT64 Nx : 1; /// 0 = Execute Code, 1 = No Code Execution + } Bits; + UINT64 Uint64; +} x64_PAGE_TABLE_ENTRY_2M; + +typedef union { + UINT64 Present : 1; /// 0 = Not present in memory, 1 = Present in memory + UINT64 ReadWrite : 1; /// 0 = Read-Only, 1= Read/Write + UINT64 UserSupervisor : 1; /// 0 = Supervisor, 1=User + UINT64 WriteThrough : 1; /// 0 = Write-Back caching, 1=Write-Through caching + UINT64 CacheDisabled : 1; /// 0 = Cached, 1=Non-Cached + UINT64 Accessed : 1; /// 0 = Not accessed, 1 = Accessed (set by CPU) + UINT64 Dirty : 1; /// 0 = Not Dirty, 1 = written by processor on access to page + UINT64 Reserved : 57; +} x64_PAGE_TABLE_ENTRY_COMMON; + +typedef union { + x64_PAGE_TABLE_ENTRY_4K Page4k; + x64_PAGE_TABLE_ENTRY_2M Page2Mb; + x64_PAGE_TABLE_ENTRY_COMMON Common; +} x64_PAGE_TABLE_ENTRY; + +/// +/// BugBug: x64 New stuff +/// +#pragma pack() + +#endif |