diff --git a/Clover.dsc b/Clover.dsc index 2609391155..c5ef8a7b2c 100644 --- a/Clover.dsc +++ b/Clover.dsc @@ -88,7 +88,7 @@ #EblCmdLib|EmbeddedPkg/Library/EblCmdLibNull/EblCmdLibNull.inf FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf - UefiCpuLib|UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf + UefiCpuLib|CloverEFI/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf !ifdef ENABLE_SECURE_BOOT OpensslLib|Library/OpensslLib/openssl-$(OPENSSL_VERSION)/OpensslLib.inf IntrinsicLib|Library/IntrinsicLib/IntrinsicLib.inf @@ -135,10 +135,10 @@ #SerialPortLib|PcAtChipsetPkg/Library/SerialIoLib/SerialIoLib.inf #SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf - MtrrLib|UefiCpuPkg/Library/MtrrLib/MtrrLib.inf + MtrrLib|CloverEFI/UefiCpuPkg/Library/MtrrLib/MtrrLib.inf IoApicLib|PcAtChipsetPkg/Library/BaseIoApicLib/BaseIoApicLib.inf - LocalApicLib|UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf - #LocalApicLib|UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf + LocalApicLib|CloverEFI/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf + #LocalApicLib|CloverEFI/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf # # To save size, use NULL library for DebugLib and ReportStatusCodeLib. @@ -595,7 +595,7 @@ PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf } MdeModulePkg/Universal/EbcDxe/EbcDxe.inf - UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf + CloverEFI/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf #UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf #UefiCpuPkg/CpuDxe/CpuDxe.inf #UefiCpuPkg/CpuDxe/CpuDxe.inf diff --git a/Clover.fdf b/Clover.fdf index 940cd348c5..febb5fdf88 100644 --- a/Clover.fdf +++ b/Clover.fdf @@ -104,7 +104,7 @@ INF CloverEFI/OsxSmbiosGenDxe/SmbiosGen.inf INF CloverEFI/OsxBdsDxe/BdsDxe.inf INF MdeModulePkg/Universal/EbcDxe/EbcDxe.inf INF MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf -#INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf +INF CloverEFI/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf #INF UefiCpuPkg/CpuDxe/CpuDxe.inf #INF IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIoDxe.inf diff --git a/CloverEFI/UefiCpuPkg/CpuDxe/CpuDxe.c b/CloverEFI/UefiCpuPkg/CpuDxe/CpuDxe.c new file mode 100755 index 0000000000..c090211b5b --- /dev/null +++ b/CloverEFI/UefiCpuPkg/CpuDxe/CpuDxe.c @@ -0,0 +1,1329 @@ +/** @file + CPU DXE Module. + + Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CpuDxe.h" + +#define USE_MTRR 0 + +// +// Global Variables +// +IA32_IDT_GATE_DESCRIPTOR gIdtTable[INTERRUPT_VECTOR_NUMBER] = { { { 0 } } }; + +EFI_CPU_INTERRUPT_HANDLER ExternalVectorTable[0x100]; +BOOLEAN InterruptState = FALSE; +EFI_HANDLE mCpuHandle = NULL; +BOOLEAN mIsFlushingGCD; +#if USE_MTRR +UINT64 mValidMtrrAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS; +UINT64 mValidMtrrBitsMask = MTRR_LIB_MSR_VALID_MASK; +#endif +IA32_IDT_GATE_DESCRIPTOR *mOrigIdtEntry = NULL; +UINT16 mOrigIdtEntryCount = 0; +#if USE_MTRR +FIXED_MTRR mFixedMtrrTable[] = { + { + MTRR_LIB_IA32_MTRR_FIX64K_00000, + 0, + 0x10000 + }, + { + MTRR_LIB_IA32_MTRR_FIX16K_80000, + 0x80000, + 0x4000 + }, + { + MTRR_LIB_IA32_MTRR_FIX16K_A0000, + 0xA0000, + 0x4000 + }, + { + MTRR_LIB_IA32_MTRR_FIX4K_C0000, + 0xC0000, + 0x1000 + }, + { + MTRR_LIB_IA32_MTRR_FIX4K_C8000, + 0xC8000, + 0x1000 + }, + { + MTRR_LIB_IA32_MTRR_FIX4K_D0000, + 0xD0000, + 0x1000 + }, + { + MTRR_LIB_IA32_MTRR_FIX4K_D8000, + 0xD8000, + 0x1000 + }, + { + MTRR_LIB_IA32_MTRR_FIX4K_E0000, + 0xE0000, + 0x1000 + }, + { + MTRR_LIB_IA32_MTRR_FIX4K_E8000, + 0xE8000, + 0x1000 + }, + { + MTRR_LIB_IA32_MTRR_FIX4K_F0000, + 0xF0000, + 0x1000 + }, + { + MTRR_LIB_IA32_MTRR_FIX4K_F8000, + 0xF8000, + 0x1000 + }, +}; +#endif + +EFI_CPU_ARCH_PROTOCOL gCpu = { + CpuFlushCpuDataCache, + CpuEnableInterrupt, + CpuDisableInterrupt, + CpuGetInterruptState, + CpuInit, + CpuRegisterInterruptHandler, + CpuGetTimerValue, + CpuSetMemoryAttributes, + 1, // NumberOfTimers + 4 // DmaBufferAlignment +}; + +// +// 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; +EFI_EVENT IdleLoopEvent; + +// +// Local function prototypes +// + +/** + Set Interrupt Descriptor Table Handler Address. + + @param Index The Index of the interrupt descriptor table handle. + @param Handler Handler address. + +**/ +VOID +SetInterruptDescriptorTableHandlerAddress ( + IN UINTN Index, + IN VOID *Handler OPTIONAL + ); + +// +// CPU Arch Protocol Functions +// + + +/** + Common exception handler. + + @param InterruptType Exception type + @param SystemContext EFI_SYSTEM_CONTEXT + +**/ +VOID +EFIAPI +CommonExceptionHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ +#if defined (MDE_CPU_IA32) + DEBUG (( + EFI_D_ERROR, + "!!!! IA32 Exception Type - %08x !!!!\n", + InterruptType + )); + if ((mErrorCodeFlag & (1 << InterruptType)) != 0) { + DEBUG (( + EFI_D_ERROR, + "ExceptionData - %08x\n", + SystemContext.SystemContextIa32->ExceptionData + )); + } + DEBUG (( + EFI_D_ERROR, + "CS - %04x, EIP - %08x, EFL - %08x, SS - %04x\n", + SystemContext.SystemContextIa32->Cs, + SystemContext.SystemContextIa32->Eip, + SystemContext.SystemContextIa32->Eflags, + SystemContext.SystemContextIa32->Ss + )); + DEBUG (( + EFI_D_ERROR, + "DS - %04x, ES - %04x, FS - %04x, GS - %04x\n", + SystemContext.SystemContextIa32->Ds, + SystemContext.SystemContextIa32->Es, + SystemContext.SystemContextIa32->Fs, + SystemContext.SystemContextIa32->Gs + )); + DEBUG (( + EFI_D_ERROR, + "EAX - %08x, EBX - %08x, ECX - %08x, EDX - %08x\n", + SystemContext.SystemContextIa32->Eax, + SystemContext.SystemContextIa32->Ebx, + SystemContext.SystemContextIa32->Ecx, + SystemContext.SystemContextIa32->Edx + )); + DEBUG (( + EFI_D_ERROR, + "ESP - %08x, EBP - %08x, ESI - %08x, EDI - %08x\n", + SystemContext.SystemContextIa32->Esp, + SystemContext.SystemContextIa32->Ebp, + SystemContext.SystemContextIa32->Esi, + SystemContext.SystemContextIa32->Edi + )); + DEBUG (( + EFI_D_ERROR, + "GDT - %08x LIM - %04x, IDT - %08x LIM - %04x\n", + SystemContext.SystemContextIa32->Gdtr[0], + SystemContext.SystemContextIa32->Gdtr[1], + SystemContext.SystemContextIa32->Idtr[0], + SystemContext.SystemContextIa32->Idtr[1] + )); + DEBUG (( + EFI_D_ERROR, + "LDT - %08x, TR - %08x\n", + SystemContext.SystemContextIa32->Ldtr, + SystemContext.SystemContextIa32->Tr + )); + DEBUG (( + EFI_D_ERROR, + "CR0 - %08x, CR2 - %08x, CR3 - %08x, CR4 - %08x\n", + SystemContext.SystemContextIa32->Cr0, + SystemContext.SystemContextIa32->Cr2, + SystemContext.SystemContextIa32->Cr3, + SystemContext.SystemContextIa32->Cr4 + )); + DEBUG (( + EFI_D_ERROR, + "DR0 - %08x, DR1 - %08x, DR2 - %08x, DR3 - %08x\n", + SystemContext.SystemContextIa32->Dr0, + SystemContext.SystemContextIa32->Dr1, + SystemContext.SystemContextIa32->Dr2, + SystemContext.SystemContextIa32->Dr3 + )); + DEBUG (( + EFI_D_ERROR, + "DR6 - %08x, DR7 - %08x\n", + SystemContext.SystemContextIa32->Dr6, + SystemContext.SystemContextIa32->Dr7 + )); +#elif defined (MDE_CPU_X64) + DEBUG (( + EFI_D_ERROR, + "!!!! X64 Exception Type - %016lx !!!!\n", + (UINT64)InterruptType + )); + if ((mErrorCodeFlag & (1 << InterruptType)) != 0) { + DEBUG (( + EFI_D_ERROR, + "ExceptionData - %016lx\n", + SystemContext.SystemContextX64->ExceptionData + )); + } + DEBUG (( + EFI_D_ERROR, + "RIP - %016lx, RFL - %016lx\n", + SystemContext.SystemContextX64->Rip, + SystemContext.SystemContextX64->Rflags + )); + 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, + "CS - %04lx, DS - %04lx, ES - %04lx, FS - %04lx, GS - %04lx, SS - %04lx\n", + SystemContext.SystemContextX64->Cs, + SystemContext.SystemContextX64->Ds, + SystemContext.SystemContextX64->Es, + SystemContext.SystemContextX64->Fs, + SystemContext.SystemContextX64->Gs, + SystemContext.SystemContextX64->Ss + )); + DEBUG (( + EFI_D_ERROR, + "GDT - %016lx; %04lx, IDT - %016lx; %04lx\n", + SystemContext.SystemContextX64->Gdtr[0], + SystemContext.SystemContextX64->Gdtr[1], + SystemContext.SystemContextX64->Idtr[0], + SystemContext.SystemContextX64->Idtr[1] + )); + DEBUG (( + EFI_D_ERROR, + "LDT - %016lx, TR - %016lx\n", + SystemContext.SystemContextX64->Ldtr, + 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 + )); +//#else +//#error CPU type not supported for exception information dump! +#endif + + // + // Hang the system with CpuSleep so the processor will enter a lower power + // state. + // + while (TRUE) { + CpuSleep (); + }; +} + + +/** + Flush CPU data cache. If the instruction cache is fully coherent + with all DMA operations then function can just return EFI_SUCCESS. + + @param This Protocol instance structure + @param Start Physical address to start flushing from. + @param Length Number of bytes to flush. Round up to chipset + granularity. + @param FlushType Specifies the type of flush operation to perform. + + @retval EFI_SUCCESS If cache was flushed + @retval EFI_UNSUPPORTED If flush type is not supported. + @retval EFI_DEVICE_ERROR If requested range could not be flushed. + +**/ +EFI_STATUS +EFIAPI +CpuFlushCpuDataCache ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length, + IN EFI_CPU_FLUSH_TYPE FlushType + ) +{ + if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) { + AsmWbinvd (); + return EFI_SUCCESS; + } else if (FlushType == EfiCpuFlushTypeInvalidate) { + AsmInvd (); + return EFI_SUCCESS; + } else { + return EFI_UNSUPPORTED; + } +} + + +/** + Enables CPU interrupts. + + @param This Protocol instance structure + + @retval EFI_SUCCESS If interrupts were enabled in the CPU + @retval EFI_DEVICE_ERROR If interrupts could not be enabled on the CPU. + +**/ +EFI_STATUS +EFIAPI +CpuEnableInterrupt ( + IN EFI_CPU_ARCH_PROTOCOL *This + ) +{ + EnableInterrupts (); + + InterruptState = TRUE; + return EFI_SUCCESS; +} + + +/** + Disables CPU interrupts. + + @param This Protocol instance structure + + @retval EFI_SUCCESS If interrupts were disabled in the CPU. + @retval EFI_DEVICE_ERROR If interrupts could not be disabled on the CPU. + +**/ +EFI_STATUS +EFIAPI +CpuDisableInterrupt ( + IN EFI_CPU_ARCH_PROTOCOL *This + ) +{ + DisableInterrupts (); + + InterruptState = FALSE; + return EFI_SUCCESS; +} + + +/** + Return the state of interrupts. + + @param This Protocol instance structure + @param State Pointer to the CPU's current interrupt state + + @retval EFI_SUCCESS If interrupts were disabled in the CPU. + @retval EFI_INVALID_PARAMETER State is NULL. + +**/ +EFI_STATUS +EFIAPI +CpuGetInterruptState ( + IN EFI_CPU_ARCH_PROTOCOL *This, + OUT BOOLEAN *State + ) +{ + if (State == NULL) { + return EFI_INVALID_PARAMETER; + } + + *State = InterruptState; + return EFI_SUCCESS; +} + + +/** + Generates an INIT to the CPU. + + @param This Protocol instance structure + @param InitType Type of CPU INIT to perform + + @retval EFI_SUCCESS If CPU INIT occurred. This value should never be + seen. + @retval EFI_DEVICE_ERROR If CPU INIT failed. + @retval EFI_UNSUPPORTED Requested type of CPU INIT not supported. + +**/ +EFI_STATUS +EFIAPI +CpuInit ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_CPU_INIT_TYPE InitType + ) +{ + return EFI_UNSUPPORTED; +} + + +/** + Registers a function to be called from the CPU interrupt handler. + + @param This Protocol instance structure + @param InterruptType Defines which interrupt to hook. IA-32 + valid range is 0x00 through 0xFF + @param InterruptHandler A pointer to a function of type + EFI_CPU_INTERRUPT_HANDLER that is called + when a processor interrupt occurs. A null + pointer is an error condition. + + @retval EFI_SUCCESS If handler installed or uninstalled. + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler + for InterruptType was previously installed. + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for + InterruptType was not previously installed. + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType + is not supported. + +**/ +EFI_STATUS +EFIAPI +CpuRegisterInterruptHandler ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ) +{ + if (InterruptType < 0 || InterruptType > 0xff) { + return EFI_UNSUPPORTED; + } + + if (InterruptHandler == NULL && ExternalVectorTable[InterruptType] == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (InterruptHandler != NULL && ExternalVectorTable[InterruptType] != NULL) { + return EFI_ALREADY_STARTED; + } + + if (InterruptHandler != NULL) { + SetInterruptDescriptorTableHandlerAddress ((UINTN)InterruptType, NULL); + } else { + // + // Restore the original IDT handler address if InterruptHandler is NULL. + // + RestoreInterruptDescriptorTableHandlerAddress ((UINTN)InterruptType); + } + + ExternalVectorTable[InterruptType] = InterruptHandler; + return EFI_SUCCESS; +} + + +/** + Returns a timer value from one of the CPU's internal timers. There is no + inherent time interval between ticks but is a function of the CPU frequency. + + @param This - Protocol instance structure. + @param TimerIndex - Specifies which CPU timer is requested. + @param TimerValue - Pointer to the returned timer value. + @param TimerPeriod - A pointer to the amount of time that passes + in femtoseconds (10-15) for each increment + of TimerValue. If TimerValue does not + increment at a predictable rate, then 0 is + returned. The amount of time that has + passed between two calls to GetTimerValue() + can be calculated with the formula + (TimerValue2 - TimerValue1) * TimerPeriod. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS - If the CPU timer count was returned. + @retval EFI_UNSUPPORTED - If the CPU does not have any readable timers. + @retval EFI_DEVICE_ERROR - If an error occurred while reading the timer. + @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL. + +**/ +EFI_STATUS +EFIAPI +CpuGetTimerValue ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN UINT32 TimerIndex, + OUT UINT64 *TimerValue, + OUT UINT64 *TimerPeriod OPTIONAL + ) +{ + if (TimerValue == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (TimerIndex != 0) { + return EFI_INVALID_PARAMETER; + } + + *TimerValue = AsmReadTsc (); + + if (TimerPeriod != NULL) { + // + // BugBug: Hard coded. Don't know how to do this generically + // + //Slice: Don't wonder. This value is for Tsc timer. + // using ACPI, HPET or TMR timer we will use other value for TimerPeriod. + // ;) + *TimerPeriod = 1000000000; + } + + return EFI_SUCCESS; +} + + +/** + Implementation of SetMemoryAttributes() service of CPU Architecture Protocol. + + This function modifies the attributes for the memory region specified by BaseAddress and + Length from their current attributes to the attributes specified by Attributes. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + @param BaseAddress The physical address that is the start address of a memory region. + @param Length The size in bytes of the memory region. + @param Attributes The bit mask of attributes to set for the memory region. + + @retval EFI_SUCCESS The attributes were set for the memory region. + @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by + BaseAddress and Length cannot be modified. + @retval EFI_INVALID_PARAMETER Length is zero. + Attributes specified an illegal combination of attributes that + cannot be set together. + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of + the memory resource range. + @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory + resource range specified by BaseAddress and Length. + The bit mask of attributes is not support for the memory resource + range specified by BaseAddress and Length. + +**/ +EFI_STATUS +EFIAPI +CpuSetMemoryAttributes ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ) +{ + return EFI_UNSUPPORTED; + +#if USE_MTRR /*this is extra bug, we need no it */ + RETURN_STATUS Status; + MTRR_MEMORY_CACHE_TYPE CacheType; + + if (!IsMtrrSupported ()) { + return EFI_UNSUPPORTED; + } + + // + // If this function is called because GCD SetMemorySpaceAttributes () is called + // by RefreshGcdMemoryAttributes (), then we are just synchronzing GCD memory + // map with MTRR values. So there is no need to modify MTRRs, just return immediately + // to avoid unnecessary computing. + // + if (mIsFlushingGCD) { + DEBUG((EFI_D_ERROR, " Flushing GCD\n")); + return EFI_SUCCESS; + } + + switch (Attributes) { + case EFI_MEMORY_UC: + CacheType = CacheUncacheable; + break; + + case EFI_MEMORY_WC: + CacheType = CacheWriteCombining; + break; + + case EFI_MEMORY_WT: + CacheType = CacheWriteThrough; + break; + + case EFI_MEMORY_WP: + CacheType = CacheWriteProtected; + break; + + case EFI_MEMORY_WB: + CacheType = CacheWriteBack; + break; + + case EFI_MEMORY_UCE: + case EFI_MEMORY_RP: + case EFI_MEMORY_XP: + case EFI_MEMORY_RUNTIME: + return EFI_UNSUPPORTED; + + default: + return EFI_INVALID_PARAMETER; + } + // + // call MTRR libary function + // + Status = MtrrSetMemoryAttribute ( + BaseAddress, + Length, + CacheType + ); + + return (EFI_STATUS) Status; +#endif +} + +/** + Initializes the valid bits mask and valid address mask for MTRRs. + + This function initializes the valid bits mask and valid address mask for MTRRs. + +**/ +#if USE_MTRR +VOID +InitializeMtrrMask ( + VOID + ) +{ + UINT32 RegEax; + UINT8 PhysicalAddressBits; + + AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); + + if (RegEax >= 0x80000008) { + AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); + + PhysicalAddressBits = (UINT8) RegEax; + + mValidMtrrBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1; + mValidMtrrAddressMask = mValidMtrrBitsMask & 0xfffffffffffff000ULL; + } else { + mValidMtrrBitsMask = MTRR_LIB_MSR_VALID_MASK; + mValidMtrrAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS; + } +} +#endif +/** + Gets GCD Mem Space type from MTRR Type. + + This function gets GCD Mem Space type from MTRR Type. + + @param MtrrAttributes MTRR memory type + + @return GCD Mem Space type + +**/ +#if USE_MTRR +UINT64 +GetMemorySpaceAttributeFromMtrrType ( + IN UINT8 MtrrAttributes + ) +{ + switch (MtrrAttributes) { + case MTRR_CACHE_UNCACHEABLE: + return EFI_MEMORY_UC; + case MTRR_CACHE_WRITE_COMBINING: + return EFI_MEMORY_WC; + case MTRR_CACHE_WRITE_THROUGH: + return EFI_MEMORY_WT; + case MTRR_CACHE_WRITE_PROTECTED: + return EFI_MEMORY_WP; + case MTRR_CACHE_WRITE_BACK: + return EFI_MEMORY_WB; + default: + return 0; + } +} +#endif +/** + Searches memory descriptors covered by given memory range. + + This function searches into the Gcd Memory Space for descriptors + (from StartIndex to EndIndex) that contains the memory range + specified by BaseAddress and Length. + + @param MemorySpaceMap Gcd Memory Space Map as array. + @param NumberOfDescriptors Number of descriptors in map. + @param BaseAddress BaseAddress for the requested range. + @param Length Length for the requested range. + @param StartIndex Start index into the Gcd Memory Space Map. + @param EndIndex End index into the Gcd Memory Space Map. + + @retval EFI_SUCCESS Search successfully. + @retval EFI_NOT_FOUND The requested descriptors does not exist. + +**/ +EFI_STATUS +SearchGcdMemorySpaces ( + IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap, + IN UINTN NumberOfDescriptors, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + OUT UINTN *StartIndex, + OUT UINTN *EndIndex + ) +{ + UINTN Index; + + *StartIndex = 0; + *EndIndex = 0; + for (Index = 0; Index < NumberOfDescriptors; Index++) { + if (BaseAddress >= MemorySpaceMap[Index].BaseAddress && + BaseAddress < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) { + *StartIndex = Index; + } + if (BaseAddress + Length - 1 >= MemorySpaceMap[Index].BaseAddress && + BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) { + *EndIndex = Index; + return EFI_SUCCESS; + } + } + return EFI_NOT_FOUND; +} + +/** + Sets the attributes for a specified range in Gcd Memory Space Map. + + This function sets the attributes for a specified range in + Gcd Memory Space Map. + + @param MemorySpaceMap Gcd Memory Space Map as array + @param NumberOfDescriptors Number of descriptors in map + @param BaseAddress BaseAddress for the range + @param Length Length for the range + @param Attributes Attributes to set + + @retval EFI_SUCCESS Memory attributes set successfully + @retval EFI_NOT_FOUND The specified range does not exist in Gcd Memory Space + +**/ +EFI_STATUS +SetGcdMemorySpaceAttributes ( + IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap, + IN UINTN NumberOfDescriptors, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ) +{ + EFI_STATUS Status; + UINTN Index; + UINTN StartIndex; + UINTN EndIndex; + EFI_PHYSICAL_ADDRESS RegionStart; + UINT64 RegionLength; + + // + // Get all memory descriptors covered by the memory range + // + Status = SearchGcdMemorySpaces ( + MemorySpaceMap, + NumberOfDescriptors, + BaseAddress, + Length, + &StartIndex, + &EndIndex + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Go through all related descriptors and set attributes accordingly + // + for (Index = StartIndex; Index <= EndIndex; Index++) { + if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) { + continue; + } + // + // Calculate the start and end address of the overlapping range + // + if (BaseAddress >= MemorySpaceMap[Index].BaseAddress) { + RegionStart = BaseAddress; + } else { + RegionStart = MemorySpaceMap[Index].BaseAddress; + } + if (BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) { + RegionLength = BaseAddress + Length - RegionStart; + } else { + RegionLength = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - RegionStart; + } + // + // Set memory attributes according to MTRR attribute and the original attribute of descriptor + // + gDS->SetMemorySpaceAttributes ( + RegionStart, + RegionLength, + (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) | (MemorySpaceMap[Index].Capabilities & Attributes) + ); + } + + return EFI_SUCCESS; +} + + +/** + Refreshes the GCD Memory Space attributes according to MTRRs. + + This function refreshes the GCD Memory Space attributes according to MTRRs. + +**/ +#if USE_MTRR +VOID +RefreshGcdMemoryAttributes ( + VOID + ) +{ + EFI_STATUS Status; + UINTN Index; + UINTN SubIndex; + UINT64 RegValue; + EFI_PHYSICAL_ADDRESS BaseAddress; + UINT64 Length; + UINT64 Attributes; + UINT64 CurrentAttributes; + UINT8 MtrrType; + UINTN NumberOfDescriptors; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap; + UINT64 DefaultAttributes; + VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR]; + MTRR_FIXED_SETTINGS MtrrFixedSettings; + UINT32 FirmwareVariableMtrrCount; + UINT8 DefaultMemoryType; + + if (!IsMtrrSupported ()) { + return; + } + + FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount (); + ASSERT (FirmwareVariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); + + mIsFlushingGCD = TRUE; + MemorySpaceMap = NULL; + + // + // Initialize the valid bits mask and valid address mask for MTRRs + // + InitializeMtrrMask (); + + // + // Get the memory attribute of variable MTRRs + // + MtrrGetMemoryAttributeInVariableMtrr ( + mValidMtrrBitsMask, + mValidMtrrAddressMask, + VariableMtrr + ); + + // + // Get the memory space map from GCD + // + Status = gDS->GetMemorySpaceMap ( + &NumberOfDescriptors, + &MemorySpaceMap + ); + ASSERT_EFI_ERROR (Status); + + DefaultMemoryType = (UINT8) MtrrGetDefaultMemoryType (); + DefaultAttributes = GetMemorySpaceAttributeFromMtrrType (DefaultMemoryType); + + // + // Set default attributes to all spaces. + // + for (Index = 0; Index < NumberOfDescriptors; Index++) { + if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) { + continue; + } + gDS->SetMemorySpaceAttributes ( + MemorySpaceMap[Index].BaseAddress, + MemorySpaceMap[Index].Length, + (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) | + (MemorySpaceMap[Index].Capabilities & DefaultAttributes) + ); + } + + // + // Go for variable MTRRs with WB attribute + // + for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) { + if (VariableMtrr[Index].Valid && + VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) { + SetGcdMemorySpaceAttributes ( + MemorySpaceMap, + NumberOfDescriptors, + VariableMtrr[Index].BaseAddress, + VariableMtrr[Index].Length, + EFI_MEMORY_WB + ); + } + } + + // + // Go for variable MTRRs with the attribute except for WB and UC attributes + // + for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) { + if (VariableMtrr[Index].Valid && + VariableMtrr[Index].Type != MTRR_CACHE_WRITE_BACK && + VariableMtrr[Index].Type != MTRR_CACHE_UNCACHEABLE) { + Attributes = GetMemorySpaceAttributeFromMtrrType ((UINT8) VariableMtrr[Index].Type); + SetGcdMemorySpaceAttributes ( + MemorySpaceMap, + NumberOfDescriptors, + VariableMtrr[Index].BaseAddress, + VariableMtrr[Index].Length, + Attributes + ); + } + } + + // + // Go for variable MTRRs with UC attribute + // + for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) { + if (VariableMtrr[Index].Valid && + VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE) { + SetGcdMemorySpaceAttributes ( + MemorySpaceMap, + NumberOfDescriptors, + VariableMtrr[Index].BaseAddress, + VariableMtrr[Index].Length, + EFI_MEMORY_UC + ); + } + } + + // + // Go for fixed MTRRs + // + Attributes = 0; + BaseAddress = 0; + Length = 0; + MtrrGetFixedMtrr (&MtrrFixedSettings); + for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { + RegValue = MtrrFixedSettings.Mtrr[Index]; + // + // Check for continuous fixed MTRR sections + // + for (SubIndex = 0; SubIndex < 8; SubIndex++) { + MtrrType = (UINT8) RShiftU64 (RegValue, SubIndex * 8); + CurrentAttributes = GetMemorySpaceAttributeFromMtrrType (MtrrType); + if (Length == 0) { + // + // A new MTRR attribute begins + // + Attributes = CurrentAttributes; + } else { + // + // If fixed MTRR attribute changed, then set memory attribute for previous atrribute + // + if (CurrentAttributes != Attributes) { + SetGcdMemorySpaceAttributes ( + MemorySpaceMap, + NumberOfDescriptors, + BaseAddress, + Length, + Attributes + ); + BaseAddress = mFixedMtrrTable[Index].BaseAddress + mFixedMtrrTable[Index].Length * SubIndex; + Length = 0; + Attributes = CurrentAttributes; + } + } + Length += mFixedMtrrTable[Index].Length; + } + } + // + // Handle the last fixed MTRR region + // + SetGcdMemorySpaceAttributes ( + MemorySpaceMap, + NumberOfDescriptors, + BaseAddress, + Length, + Attributes + ); + + // + // Free memory space map allocated by GCD service GetMemorySpaceMap () + // + if (MemorySpaceMap != NULL) { + FreePool (MemorySpaceMap); + } + + mIsFlushingGCD = FALSE; +} +#endif +/** + Set Interrupt Descriptor Table Handler Address. + + @param Index The Index of the interrupt descriptor table handle. + @param Handler Handler address. + +**/ +VOID +SetInterruptDescriptorTableHandlerAddress ( + IN UINTN Index, + IN VOID *Handler OPTIONAL + ) +{ + UINTN UintnHandler; + + if (Handler != NULL) { + UintnHandler = (UINTN) Handler; + } else { + UintnHandler = ((UINTN) AsmIdtVector00) + (8 * Index); + } + + gIdtTable[Index].Bits.OffsetLow = (UINT16)UintnHandler; + gIdtTable[Index].Bits.Reserved_0 = 0; + gIdtTable[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; + gIdtTable[Index].Bits.OffsetHigh = (UINT16)(UintnHandler >> 16); +#if defined (MDE_CPU_X64) + gIdtTable[Index].Bits.OffsetUpper = (UINT32)(UintnHandler >> 32); + gIdtTable[Index].Bits.Reserved_1 = 0; +#endif +} + +/** + Restore original Interrupt Descriptor Table Handler Address. + + @param Index The Index of the interrupt descriptor table handle. + +**/ +VOID +RestoreInterruptDescriptorTableHandlerAddress ( + IN UINTN Index + ) +{ + if (Index < mOrigIdtEntryCount) { + gIdtTable[Index].Bits.OffsetLow = mOrigIdtEntry[Index].Bits.OffsetLow; + gIdtTable[Index].Bits.OffsetHigh = mOrigIdtEntry[Index].Bits.OffsetHigh; +#if defined (MDE_CPU_X64) + gIdtTable[Index].Bits.OffsetUpper = mOrigIdtEntry[Index].Bits.OffsetUpper; +#endif + } + if (Index >= mOrigIdtEntryCount) + return; + CopyMem(gIdtTable + Index, mOrigIdtEntry + Index, + sizeof(gIdtTable[Index])); +} + +/** + Initialize Interrupt Descriptor Table for interrupt handling. + +**/ +VOID +InitInterruptDescriptorTable ( + VOID + ) +{ + EFI_STATUS Status; + IA32_DESCRIPTOR OldIdtPtr; + IA32_IDT_GATE_DESCRIPTOR *OldIdt; + UINTN OldIdtSize; + VOID *IdtPtrAlignmentBuffer; + IA32_DESCRIPTOR *IdtPtr; + UINTN Index; + UINT16 CurrentCs; + VOID *IntHandler; + + SetMem (ExternalVectorTable, sizeof(ExternalVectorTable), 0); + + // + // Get original IDT address and size. + // + AsmReadIdtr ((IA32_DESCRIPTOR *) &OldIdtPtr); + + if ((OldIdtPtr.Base != 0) && ((OldIdtPtr.Limit & 7) == 7)) { + OldIdt = (IA32_IDT_GATE_DESCRIPTOR*) OldIdtPtr.Base; + OldIdtSize = (OldIdtPtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR); + // + // Save original IDT entry and IDT entry count. + // + mOrigIdtEntry = AllocateCopyPool (OldIdtPtr.Limit + 1, (VOID *) OldIdtPtr.Base); +// ASSERT (mOrigIdtEntry != NULL); + mOrigIdtEntryCount = (UINT16) OldIdtSize; + } else { + OldIdt = NULL; + OldIdtSize = 0; + } + + // + // Intialize IDT + // + CurrentCs = AsmReadCs(); + for (Index = 0; Index < INTERRUPT_VECTOR_NUMBER; Index ++) { + // + // If the old IDT had a handler for this interrupt, then + // preserve it. + // + if (Index < OldIdtSize) { + IntHandler = + (VOID*) ( + OldIdt[Index].Bits.OffsetLow + + (((UINTN) OldIdt[Index].Bits.OffsetHigh) << 16) +#if defined (MDE_CPU_X64) + + (((UINTN) OldIdt[Index].Bits.OffsetUpper) << 32) +#endif + ); + } else { + IntHandler = NULL; + } +#if 1 //patch by nms42 for AMD CPU + if (Index == 0x6F) { + IntHandler = NULL; + } +#endif + + gIdtTable[Index].Bits.Selector = CurrentCs; + gIdtTable[Index].Bits.Reserved_0 = 0; + gIdtTable[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; + SetInterruptDescriptorTableHandlerAddress (Index, IntHandler); + } + + // + // Load IDT Pointer + // + IdtPtrAlignmentBuffer = AllocatePool (sizeof (*IdtPtr) + 16); + IdtPtr = ALIGN_POINTER (IdtPtrAlignmentBuffer, 16); +// IdtPtr->Base = (UINT32)(((UINTN)(VOID*) gIdtTable) & (BASE_4GB-1)); + IdtPtr->Base = (UINTN)(VOID*) gIdtTable; + IdtPtr->Limit = (UINT16) (sizeof (gIdtTable) - 1); + AsmWriteIdtr (IdtPtr); + + FreePool (IdtPtrAlignmentBuffer); + + // + // Initialize Exception Handlers + // + for (Index = OldIdtSize; Index < 32; Index++) { + Status = CpuRegisterInterruptHandler (&gCpu, Index, CommonExceptionHandler); +// ASSERT_EFI_ERROR (Status); + } + + // + // Set the pointer to the array of C based exception handling routines. + // + InitializeExternalVectorTablePtr (ExternalVectorTable); + +} + + +/** + Callback function for idle events. + + @param Event Event whose notification function is being invoked. + @param Context The pointer to the notification function's context, + which is implementation-dependent. + +**/ +VOID +EFIAPI +IdleLoopEventCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + CpuSleep (); +} + + +/** + Initialize the state information for the CPU Architectural Protocol. + + @param ImageHandle Image handle this driver. + @param SystemTable Pointer to the System Table. + + @retval EFI_SUCCESS Thread can be successfully created + @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure + @retval EFI_DEVICE_ERROR Cannot create the thread + +**/ +EFI_STATUS +EFIAPI +InitializeCpu ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + +// InitializeFloatingPointUnits (); //nah + + // + // Make sure interrupts are disabled + // + DisableInterrupts (); + + // + // Init GDT for DXE + // + InitGlobalDescriptorTable (); + + // + // Setup IDT pointer, IDT and interrupt entry points + // + InitInterruptDescriptorTable (); + + // + // Enable the local APIC for Virtual Wire Mode. + // + ProgramVirtualWireMode (); + + // + // Install CPU Architectural Protocol + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mCpuHandle, + &gEfiCpuArchProtocolGuid, &gCpu, + NULL + ); +// ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Refresh GCD memory space map according to MTRR value. + // +// RefreshGcdMemoryAttributes (); + + // + // Setup a callback for idle events + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + IdleLoopEventCallback, + NULL, + &gIdleLoopEventGuid, + &IdleLoopEvent + ); +// ASSERT_EFI_ERROR (Status); + + return Status; +} + diff --git a/CloverEFI/UefiCpuPkg/CpuDxe/CpuDxe.h b/CloverEFI/UefiCpuPkg/CpuDxe/CpuDxe.h new file mode 100755 index 0000000000..a75ec0593f --- /dev/null +++ b/CloverEFI/UefiCpuPkg/CpuDxe/CpuDxe.h @@ -0,0 +1,292 @@ +/** @file + CPU DXE Module. + + Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _CPU_DXE_H_ +#define _CPU_DXE_H_ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// +// +#define INTERRUPT_VECTOR_NUMBER 256 + +#define EFI_MEMORY_CACHETYPE_MASK (EFI_MEMORY_UC | \ + EFI_MEMORY_WC | \ + EFI_MEMORY_WT | \ + EFI_MEMORY_WB | \ + EFI_MEMORY_UCE \ + ) + + +/** + Flush CPU data cache. If the instruction cache is fully coherent + with all DMA operations then function can just return EFI_SUCCESS. + + @param This Protocol instance structure + @param Start Physical address to start flushing from. + @param Length Number of bytes to flush. Round up to chipset + granularity. + @param FlushType Specifies the type of flush operation to perform. + + @retval EFI_SUCCESS If cache was flushed + @retval EFI_UNSUPPORTED If flush type is not supported. + @retval EFI_DEVICE_ERROR If requested range could not be flushed. + +**/ +EFI_STATUS +EFIAPI +CpuFlushCpuDataCache ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length, + IN EFI_CPU_FLUSH_TYPE FlushType + ); + +/** + Enables CPU interrupts. + + @param This Protocol instance structure + + @retval EFI_SUCCESS If interrupts were enabled in the CPU + @retval EFI_DEVICE_ERROR If interrupts could not be enabled on the CPU. + +**/ +EFI_STATUS +EFIAPI +CpuEnableInterrupt ( + IN EFI_CPU_ARCH_PROTOCOL *This + ); + +/** + Disables CPU interrupts. + + @param This Protocol instance structure + + @retval EFI_SUCCESS If interrupts were disabled in the CPU. + @retval EFI_DEVICE_ERROR If interrupts could not be disabled on the CPU. + +**/ +EFI_STATUS +EFIAPI +CpuDisableInterrupt ( + IN EFI_CPU_ARCH_PROTOCOL *This + ); + +/** + Return the state of interrupts. + + @param This Protocol instance structure + @param State Pointer to the CPU's current interrupt state + + @retval EFI_SUCCESS If interrupts were disabled in the CPU. + @retval EFI_INVALID_PARAMETER State is NULL. + +**/ +EFI_STATUS +EFIAPI +CpuGetInterruptState ( + IN EFI_CPU_ARCH_PROTOCOL *This, + OUT BOOLEAN *State + ); + +/** + Generates an INIT to the CPU. + + @param This Protocol instance structure + @param InitType Type of CPU INIT to perform + + @retval EFI_SUCCESS If CPU INIT occurred. This value should never be + seen. + @retval EFI_DEVICE_ERROR If CPU INIT failed. + @retval EFI_UNSUPPORTED Requested type of CPU INIT not supported. + +**/ +EFI_STATUS +EFIAPI +CpuInit ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_CPU_INIT_TYPE InitType + ); + +/** + Registers a function to be called from the CPU interrupt handler. + + @param This Protocol instance structure + @param InterruptType Defines which interrupt to hook. IA-32 + valid range is 0x00 through 0xFF + @param InterruptHandler A pointer to a function of type + EFI_CPU_INTERRUPT_HANDLER that is called + when a processor interrupt occurs. A null + pointer is an error condition. + + @retval EFI_SUCCESS If handler installed or uninstalled. + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler + for InterruptType was previously installed. + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for + InterruptType was not previously installed. + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType + is not supported. + +**/ +EFI_STATUS +EFIAPI +CpuRegisterInterruptHandler ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ); + +/** + Returns a timer value from one of the CPU's internal timers. There is no + inherent time interval between ticks but is a function of the CPU frequency. + + @param This - Protocol instance structure. + @param TimerIndex - Specifies which CPU timer is requested. + @param TimerValue - Pointer to the returned timer value. + @param TimerPeriod - A pointer to the amount of time that passes + in femtoseconds (10-15) for each increment + of TimerValue. If TimerValue does not + increment at a predictable rate, then 0 is + returned. The amount of time that has + passed between two calls to GetTimerValue() + can be calculated with the formula + (TimerValue2 - TimerValue1) * TimerPeriod. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS - If the CPU timer count was returned. + @retval EFI_UNSUPPORTED - If the CPU does not have any readable timers. + @retval EFI_DEVICE_ERROR - If an error occurred while reading the timer. + @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL. + +**/ +EFI_STATUS +EFIAPI +CpuGetTimerValue ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN UINT32 TimerIndex, + OUT UINT64 *TimerValue, + OUT UINT64 *TimerPeriod OPTIONAL + ); + +/** + Set memory cacheability attributes for given range of memeory. + + @param This Protocol instance structure + @param BaseAddress Specifies the start address of the + memory range + @param Length Specifies the length of the memory range + @param Attributes The memory cacheability for the memory range + + @retval EFI_SUCCESS If the cacheability of that memory range is + set successfully + @retval EFI_UNSUPPORTED If the desired operation cannot be done + @retval EFI_INVALID_PARAMETER The input parameter is not correct, + such as Length = 0 + +**/ +EFI_STATUS +EFIAPI +CpuSetMemoryAttributes ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ); + +/** + Label of base address of IDT vector 0. + + This is just a label of base address of IDT vector 0. + +**/ +VOID +EFIAPI +AsmIdtVector00 ( + VOID + ); + +/** + Initializes the pointer to the external interrupt vector table. + + @param VectorTable Address of the external interrupt vector table. + +**/ +VOID +EFIAPI +InitializeExternalVectorTablePtr ( + EFI_CPU_INTERRUPT_HANDLER *VectorTable + ); + +/** + Initialize Global Descriptor Table. + +**/ +VOID +InitGlobalDescriptorTable ( + VOID + ); + +/** + Sets the code selector (CS). + + @param Selector Value of code selector. + +**/ +VOID +EFIAPI +SetCodeSelector ( + UINT16 Selector + ); + +/** + Sets the data selector (DS). + + @param Selector Value of data selector. + +**/ +VOID +EFIAPI +SetDataSelectors ( + UINT16 Selector + ); + +/** + Restore original Interrupt Descriptor Table Handler Address. + + @param Index The Index of the interrupt descriptor table handle. + +**/ +VOID +RestoreInterruptDescriptorTableHandlerAddress ( + IN UINTN Index + ); + +#endif + diff --git a/CloverEFI/UefiCpuPkg/CpuDxe/CpuDxe.inf b/CloverEFI/UefiCpuPkg/CpuDxe/CpuDxe.inf new file mode 100755 index 0000000000..6fd981a7cd --- /dev/null +++ b/CloverEFI/UefiCpuPkg/CpuDxe/CpuDxe.inf @@ -0,0 +1,70 @@ +## @file +# +# Component description file for simple CPU driver +# +# Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = CpuDxeClover + FILE_GUID = 1A1E4886-9517-440e-9FDE-3BE44CEE2136 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeCpu + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + CloverEFI/UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + CpuLib + DebugLib + DxeServicesTableLib + MemoryAllocationLib + MtrrLib + UefiBootServicesTableLib + UefiDriverEntryPoint + LocalApicLib + UefiCpuLib + +[Sources] + CpuDxe.c + CpuDxe.h + CpuGdt.c + + Ia32/IvtAsm.asm | MSFT + Ia32/IvtAsm.asm | INTEL + Ia32/IvtAsm.S | GCC + +[Sources.IA32] + Ia32/CpuAsm.asm | MSFT + Ia32/CpuAsm.asm | INTEL + Ia32/CpuAsm.S | GCC + +[Sources.X64] + X64/CpuAsm.asm | MSFT + X64/CpuAsm.asm | INTEL + X64/CpuAsm.S | GCC + +[Protocols] + gEfiCpuArchProtocolGuid + +[Guids] + gIdleLoopEventGuid ## CONSUMES ## GUID + +[Depex] + TRUE + diff --git a/CloverEFI/UefiCpuPkg/CpuDxe/CpuGdt.c b/CloverEFI/UefiCpuPkg/CpuDxe/CpuGdt.c new file mode 100755 index 0000000000..25d40735c3 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/CpuDxe/CpuGdt.c @@ -0,0 +1,201 @@ +/** @file + C based implemention of IA32 interrupt handling only + requiring a minimal assembly interrupt entry point. + + Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CpuDxe.h" + + +// +// Local structure definitions +// + +#pragma pack (1) + +// +// Global Descriptor Entry structures +// + +typedef struct _GDT_ENTRY { + UINT16 Limit15_0; + UINT16 Base15_0; + UINT8 Base23_16; + UINT8 Type; + UINT8 Limit19_16_and_flags; + UINT8 Base31_24; +} GDT_ENTRY; + +typedef +struct _GDT_ENTRIES { + GDT_ENTRY Null; + GDT_ENTRY Linear; + GDT_ENTRY LinearCode; + GDT_ENTRY SysData; + GDT_ENTRY SysCode; + GDT_ENTRY LinearCode64; + GDT_ENTRY Spare4; + GDT_ENTRY Spare5; +} GDT_ENTRIES; + +#define NULL_SEL OFFSET_OF (GDT_ENTRIES, Null) +#define LINEAR_SEL OFFSET_OF (GDT_ENTRIES, Linear) +#define LINEAR_CODE_SEL OFFSET_OF (GDT_ENTRIES, LinearCode) +#define SYS_DATA_SEL OFFSET_OF (GDT_ENTRIES, SysData) +#define SYS_CODE_SEL OFFSET_OF (GDT_ENTRIES, SysCode) +#define LINEAR_CODE64_SEL OFFSET_OF (GDT_ENTRIES, LinearCode64) +#define SPARE4_SEL OFFSET_OF (GDT_ENTRIES, Spare4) +#define SPARE5_SEL OFFSET_OF (GDT_ENTRIES, Spare5) + +#if defined (MDE_CPU_IA32) +#define CPU_CODE_SEL LINEAR_CODE_SEL +#define CPU_DATA_SEL LINEAR_SEL +#elif defined (MDE_CPU_X64) +#define CPU_CODE_SEL LINEAR_CODE64_SEL +#define CPU_DATA_SEL LINEAR_SEL +//#else +//#error CPU type not supported for CPU GDT initialization! +#endif + +// +// Global descriptor table (GDT) Template +// +STATIC GDT_ENTRIES GdtTemplate = { + // + // NULL_SEL + // + { + 0x0, // limit 15:0 + 0x0, // base 15:0 + 0x0, // base 23:16 + 0x0, // type + 0x0, // limit 19:16, flags + 0x0, // base 31:24 + }, + // + // LINEAR_SEL + // + { + 0x0FFFF, // limit 0xFFFFF + 0x0, // base 0 + 0x0, + 0x092, // present, ring 0, data, expand-up, writable + 0x0CF, // page-granular, 32-bit + 0x0, + }, + // + // LINEAR_CODE_SEL + // + { + 0x0FFFF, // limit 0xFFFFF + 0x0, // base 0 + 0x0, + 0x09A, // present, ring 0, data, expand-up, writable + 0x0CF, // page-granular, 32-bit + 0x0, + }, + // + // SYS_DATA_SEL + // + { + 0x0FFFF, // limit 0xFFFFF + 0x0, // base 0 + 0x0, + 0x092, // present, ring 0, data, expand-up, writable + 0x0CF, // page-granular, 32-bit + 0x0, + }, + // + // SYS_CODE_SEL + // + { + 0x0FFFF, // limit 0xFFFFF + 0x0, // base 0 + 0x0, + 0x09A, // present, ring 0, data, expand-up, writable + 0x0CF, // page-granular, 32-bit + 0x0, + }, + // + // LINEAR_CODE64_SEL + // + { + 0x0FFFF, // limit 0xFFFFF + 0x0, // base 0 + 0x0, + 0x09B, // present, ring 0, code, expand-up, writable + 0x0AF, // LimitHigh (CS.L=1, CS.D=0) + 0x0, // base (high) + }, + // + // SPARE4_SEL + // + { + 0x0, // limit 0 + 0x0, // base 0 + 0x0, + 0x0, // present, ring 0, data, expand-up, writable + 0x0, // page-granular, 32-bit + 0x0, + }, + // + // SPARE5_SEL + // + { + 0x0, // limit 0 + 0x0, // base 0 + 0x0, + 0x0, // present, ring 0, data, expand-up, writable + 0x0, // page-granular, 32-bit + 0x0, + }, +}; + +/** + Initialize Global Descriptor Table. + +**/ +VOID +InitGlobalDescriptorTable ( + VOID + ) +{ + GDT_ENTRIES *gdt; + IA32_DESCRIPTOR gdtPtr; + + // + // Allocate Runtime Data for the GDT + // + gdt = AllocateRuntimePool (sizeof (GdtTemplate) + 8); + ASSERT (gdt != NULL); + gdt = ALIGN_POINTER (gdt, 8); + + // + // Initialize all GDT entries + // + CopyMem (gdt, &GdtTemplate, sizeof (GdtTemplate)); + + // + // Write GDT register + // + //gdtPtr.Base = (UINT32)(UINTN)(VOID*) gdt; + gdtPtr.Base = (UINTN)(VOID*) gdt; + gdtPtr.Limit = (UINT16) (sizeof (GdtTemplate) - 1); + AsmWriteGdtr (&gdtPtr); + + // + // Update selector (segment) registers base on new GDT + // + SetCodeSelector ((UINT16)CPU_CODE_SEL); + SetDataSelectors ((UINT16)CPU_DATA_SEL); +} + diff --git a/CloverEFI/UefiCpuPkg/CpuDxe/Ia32/CpuAsm.S b/CloverEFI/UefiCpuPkg/CpuDxe/Ia32/CpuAsm.S new file mode 100755 index 0000000000..3b43b6fd8b --- /dev/null +++ b/CloverEFI/UefiCpuPkg/CpuDxe/Ia32/CpuAsm.S @@ -0,0 +1,365 @@ +#------------------------------------------------------------------------------ +#* +#* Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.
+#* This program and the accompanying materials +#* are licensed and made available under the terms and conditions of the BSD License +#* which accompanies this distribution. The full text of the license may be found at +#* http://opensource.org/licenses/bsd-license.php +#* +#* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +#* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +#* +#* CpuAsm.S +#* +#* Abstract: +#* +#------------------------------------------------------------------------------ + + +#.MMX +#.XMM + +#EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions + + +# +# point to the external interrupt vector table +# +ExternalVectorTablePtr: + .byte 0, 0, 0, 0 + +ASM_GLOBAL ASM_PFX(InitializeExternalVectorTablePtr) +ASM_PFX(InitializeExternalVectorTablePtr): + movl 4(%esp), %eax + movl %eax, ExternalVectorTablePtr + ret + +#------------------------------------------------------------------------------ +# VOID +# SetCodeSelector ( +# UINT16 Selector +# ); +#------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(SetCodeSelector) +ASM_PFX(SetCodeSelector): + movl 4(%esp), %ecx + subl $0x10, %esp + leal setCodeSelectorLongJump, %eax + movl %eax, (%esp) + movw %cx, 4(%esp) + .byte 0xFF, 0x2C, 0x24 # jmp *(%esp) note:(FWORD jmp) +setCodeSelectorLongJump: + addl $0x10, %esp + ret + +#------------------------------------------------------------------------------ +# VOID +# SetDataSelectors ( +# UINT16 Selector +# ); +#------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(SetDataSelectors) +ASM_PFX(SetDataSelectors): + movl 4(%esp), %ecx + movw %cx, %ss + movw %cx, %ds + movw %cx, %es + movw %cx, %fs + movw %cx, %gs + ret + +#---------------------------------------; +# CommonInterruptEntry ; +#---------------------------------------; +# The follow algorithm is used for the common interrupt routine. + +ASM_GLOBAL ASM_PFX(CommonInterruptEntry) +ASM_PFX(CommonInterruptEntry): + cli + # + # All interrupt handlers are invoked through interrupt gates, so + # IF flag automatically cleared at the entry point + # + + # + # Calculate vector number + # + # Get the return address of call, actually, it is the + # address of vector number. + # + xchgl (%esp), %ecx + movw (%ecx), %cx + andl $0x0FFFF, %ecx + cmpl $32, %ecx # Intel reserved vector for exceptions? + jae NoErrorCode + bt %ecx, ASM_PFX(mErrorCodeFlag) + jc HasErrorCode + +NoErrorCode: + + # + # Stack: + # +---------------------+ + # + EFlags + + # +---------------------+ + # + CS + + # +---------------------+ + # + EIP + + # +---------------------+ + # + ECX + + # +---------------------+ <-- ESP + # + # Registers: + # ECX - Vector Number + # + + # + # Put Vector Number on stack + # + pushl %ecx + + # + # Put 0 (dummy) error code on stack, and restore ECX + # + xorl %ecx, %ecx # ECX = 0 + xchgl 4(%esp), %ecx + + jmp ErrorCodeAndVectorOnStack + +HasErrorCode: + + # + # Stack: + # +---------------------+ + # + EFlags + + # +---------------------+ + # + CS + + # +---------------------+ + # + EIP + + # +---------------------+ + # + Error Code + + # +---------------------+ + # + ECX + + # +---------------------+ <-- ESP + # + # Registers: + # ECX - Vector Number + # + + # + # Put Vector Number on stack and restore ECX + # + xchgl (%esp), %ecx + +ErrorCodeAndVectorOnStack: + pushl %ebp + movl %esp, %ebp + + # + # Stack: + # +---------------------+ + # + EFlags + + # +---------------------+ + # + CS + + # +---------------------+ + # + EIP + + # +---------------------+ + # + Error Code + + # +---------------------+ + # + Vector Number + + # +---------------------+ + # + EBP + + # +---------------------+ <-- EBP + # + + # + # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32 + # is 16-byte aligned + # + andl $0x0fffffff0, %esp + subl $12, %esp + +#; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + pushl %eax + pushl %ecx + pushl %edx + pushl %ebx + leal 24(%ebp), %ecx + pushl %ecx # ESP + pushl (%ebp) # EBP + pushl %esi + pushl %edi + +#; UINT32 Gs, Fs, Es, Ds, Cs, Ss; + movl %ss, %eax + pushl %eax + movzwl 16(%ebp), %eax + pushl %eax + movl %ds, %eax + pushl %eax + movl %es, %eax + pushl %eax + movl %fs, %eax + pushl %eax + movl %gs, %eax + pushl %eax + +#; UINT32 Eip; + movl 12(%ebp), %eax + pushl %eax + +#; UINT32 Gdtr[2], Idtr[2]; + subl $8, %esp + sidt (%esp) + movl 2(%esp), %eax + xchgl (%esp), %eax + andl $0x0FFFF, %eax + movl %eax, 4(%esp) + + subl $8, %esp + sgdt (%esp) + movl 2(%esp), %eax + xchgl (%esp), %eax + andl $0x0FFFF, %eax + movl %eax, 4(%esp) + +#; UINT32 Ldtr, Tr; + xorl %eax, %eax + str %ax + pushl %eax + sldt %ax + pushl %eax + +#; UINT32 EFlags; + movl 20(%ebp), %eax + pushl %eax + +#; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + movl %cr4, %eax + orl $0x208, %eax + movl %eax, %cr4 + pushl %eax + movl %cr3, %eax + pushl %eax + movl %cr2, %eax + pushl %eax + xorl %eax, %eax + pushl %eax + movl %cr0, %eax + pushl %eax + +#; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + movl %dr7, %eax + pushl %eax + movl %dr6, %eax + pushl %eax + movl %dr3, %eax + pushl %eax + movl %dr2, %eax + pushl %eax + movl %dr1, %eax + pushl %eax + movl %dr0, %eax + pushl %eax + +#; FX_SAVE_STATE_IA32 FxSaveState; + subl $512, %esp + movl %esp, %edi + .byte 0x0f, 0x0ae, 0x07 #fxsave [edi] + +#; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear + cld + +#; UINT32 ExceptionData; + pushl 8(%ebp) + +#; call into exception handler + movl ExternalVectorTablePtr, %eax # get the interrupt vectors base + orl %eax, %eax # NULL? + jz nullExternalExceptionHandler + + mov 4(%ebp), %ecx + movl (%eax,%ecx,4), %eax + orl %eax, %eax # NULL? + jz nullExternalExceptionHandler + +#; Prepare parameter and call + movl %esp, %edx + pushl %edx + movl 4(%ebp), %edx + pushl %edx + + # + # Call External Exception Handler + # + call *%eax + addl $8, %esp + +nullExternalExceptionHandler: + + cli +#; UINT32 ExceptionData; + addl $4, %esp + +#; FX_SAVE_STATE_IA32 FxSaveState; + movl %esp, %esi + .byte 0x0f, 0x0ae, 0x0e # fxrstor [esi] + addl $512, %esp + +#; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; +#; Skip restoration of DRx registers to support in-circuit emualators +#; or debuggers set breakpoint in interrupt/exception context + addl $24, %esp + +#; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + popl %eax + movl %eax, %cr0 + addl $4, %esp # not for Cr1 + popl %eax + movl %eax, %cr2 + popl %eax + movl %eax, %cr3 + popl %eax + movl %eax, %cr4 + +#; UINT32 EFlags; + popl 20(%ebp) + +#; UINT32 Ldtr, Tr; +#; UINT32 Gdtr[2], Idtr[2]; +#; Best not let anyone mess with these particular registers... + addl $24, %esp + +#; UINT32 Eip; + popl 12(%ebp) + +#; UINT32 Gs, Fs, Es, Ds, Cs, Ss; +#; NOTE - modified segment registers could hang the debugger... We +#; could attempt to insulate ourselves against this possibility, +#; but that poses risks as well. +#; + popl %gs + popl %fs + popl %es + popl %ds + popl 16(%ebp) + popl %ss + +#; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + popl %edi + popl %esi + addl $4, %esp # not for ebp + addl $4, %esp # not for esp + popl %ebx + popl %edx + popl %ecx + popl %eax + + movl %ebp, %esp + popl %ebp + addl $8, %esp + iretl + + +#END + diff --git a/CloverEFI/UefiCpuPkg/CpuDxe/Ia32/CpuAsm.asm b/CloverEFI/UefiCpuPkg/CpuDxe/Ia32/CpuAsm.asm new file mode 100755 index 0000000000..0924dc5bb3 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/CpuDxe/Ia32/CpuAsm.asm @@ -0,0 +1,363 @@ + TITLE CpuAsm.asm: +;------------------------------------------------------------------------------ +;* +;* Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.
+;* This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* CpuAsm.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + + .686 + .model flat,C + .code + +EXTRN mErrorCodeFlag:DWORD ; Error code flags for exceptions + +; +; point to the external interrupt vector table +; +ExternalVectorTablePtr DWORD 0 + +InitializeExternalVectorTablePtr PROC PUBLIC + mov eax, [esp+4] + mov ExternalVectorTablePtr, eax + ret +InitializeExternalVectorTablePtr ENDP + +;------------------------------------------------------------------------------ +; VOID +; SetCodeSelector ( +; UINT16 Selector +; ); +;------------------------------------------------------------------------------ +SetCodeSelector PROC PUBLIC + mov ecx, [esp+4] + sub esp, 0x10 + lea eax, setCodeSelectorLongJump + mov [esp], eax + mov [esp+4], cx + jmp fword ptr [esp] +setCodeSelectorLongJump: + add esp, 0x10 + ret +SetCodeSelector ENDP + +;------------------------------------------------------------------------------ +; VOID +; SetDataSelectors ( +; UINT16 Selector +; ); +;------------------------------------------------------------------------------ +SetDataSelectors PROC PUBLIC + mov ecx, [esp+4] + mov ss, cx + mov ds, cx + mov es, cx + mov fs, cx + mov gs, cx + ret +SetDataSelectors ENDP + +;---------------------------------------; +; CommonInterruptEntry ; +;---------------------------------------; +; The follow algorithm is used for the common interrupt routine. + +CommonInterruptEntry PROC PUBLIC + cli + ; + ; All interrupt handlers are invoked through interrupt gates, so + ; IF flag automatically cleared at the entry point + ; + + ; + ; Calculate vector number + ; + ; Get the return address of call, actually, it is the + ; address of vector number. + ; + xchg ecx, [esp] + mov cx, [ecx] + and ecx, 0FFFFh + cmp ecx, 32 ; Intel reserved vector for exceptions? + jae NoErrorCode + bt mErrorCodeFlag, ecx + jc HasErrorCode + +NoErrorCode: + + ; + ; Stack: + ; +---------------------+ + ; + EFlags + + ; +---------------------+ + ; + CS + + ; +---------------------+ + ; + EIP + + ; +---------------------+ + ; + ECX + + ; +---------------------+ <-- ESP + ; + ; Registers: + ; ECX - Vector Number + ; + + ; + ; Put Vector Number on stack + ; + push ecx + + ; + ; Put 0 (dummy) error code on stack, and restore ECX + ; + xor ecx, ecx ; ECX = 0 + xchg ecx, [esp+4] + + jmp ErrorCodeAndVectorOnStack + +HasErrorCode: + + ; + ; Stack: + ; +---------------------+ + ; + EFlags + + ; +---------------------+ + ; + CS + + ; +---------------------+ + ; + EIP + + ; +---------------------+ + ; + Error Code + + ; +---------------------+ + ; + ECX + + ; +---------------------+ <-- ESP + ; + ; Registers: + ; ECX - Vector Number + ; + + ; + ; Put Vector Number on stack and restore ECX + ; + xchg ecx, [esp] + +ErrorCodeAndVectorOnStack: + push ebp + mov ebp, esp + + ; + ; Stack: + ; +---------------------+ + ; + EFlags + + ; +---------------------+ + ; + CS + + ; +---------------------+ + ; + EIP + + ; +---------------------+ + ; + Error Code + + ; +---------------------+ + ; + Vector Number + + ; +---------------------+ + ; + EBP + + ; +---------------------+ <-- EBP + ; + + ; + ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32 + ; is 16-byte aligned + ; + and esp, 0fffffff0h + sub esp, 12 + +;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + push eax + push ecx + push edx + push ebx + lea ecx, [ebp + 6 * 4] + push ecx ; ESP + push dword ptr [ebp] ; EBP + push esi + push edi + +;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; + mov eax, ss + push eax + movzx eax, word ptr [ebp + 4 * 4] + push eax + mov eax, ds + push eax + mov eax, es + push eax + mov eax, fs + push eax + mov eax, gs + push eax + +;; UINT32 Eip; + mov eax, [ebp + 3 * 4] + push eax + +;; UINT32 Gdtr[2], Idtr[2]; + sub esp, 8 + sidt [esp] + mov eax, [esp + 2] + xchg eax, [esp] + and eax, 0FFFFh + mov [esp+4], eax + + sub esp, 8 + sgdt [esp] + mov eax, [esp + 2] + xchg eax, [esp] + and eax, 0FFFFh + mov [esp+4], eax + +;; UINT32 Ldtr, Tr; + xor eax, eax + str ax + push eax + sldt ax + push eax + +;; UINT32 EFlags; + mov eax, [ebp + 5 * 4] + push eax + +;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + mov eax, cr4 + or eax, 208h + mov cr4, eax + push eax + mov eax, cr3 + push eax + mov eax, cr2 + push eax + xor eax, eax + push eax + mov eax, cr0 + push eax + +;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + mov eax, dr7 + push eax + mov eax, dr6 + push eax + mov eax, dr3 + push eax + mov eax, dr2 + push eax + mov eax, dr1 + push eax + mov eax, dr0 + push eax + +;; FX_SAVE_STATE_IA32 FxSaveState; + sub esp, 512 + mov edi, esp + db 0fh, 0aeh, 07h ;fxsave [edi] + +;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear + cld + +;; UINT32 ExceptionData; + push dword ptr [ebp + 2 * 4] + +;; call into exception handler + mov eax, ExternalVectorTablePtr ; get the interrupt vectors base + or eax, eax ; NULL? + jz nullExternalExceptionHandler + + mov ecx, [ebp + 4] + mov eax, [eax + ecx * 4] + or eax, eax ; NULL? + jz nullExternalExceptionHandler + +;; Prepare parameter and call + mov edx, esp + push edx + mov edx, dword ptr [ebp + 1 * 4] + push edx + + ; + ; Call External Exception Handler + ; + call eax + add esp, 8 + +nullExternalExceptionHandler: + + cli +;; UINT32 ExceptionData; + add esp, 4 + +;; FX_SAVE_STATE_IA32 FxSaveState; + mov esi, esp + db 0fh, 0aeh, 0eh ; fxrstor [esi] + add esp, 512 + +;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; +;; Skip restoration of DRx registers to support in-circuit emualators +;; or debuggers set breakpoint in interrupt/exception context + add esp, 4 * 6 + +;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + pop eax + mov cr0, eax + add esp, 4 ; not for Cr1 + pop eax + mov cr2, eax + pop eax + mov cr3, eax + pop eax + mov cr4, eax + +;; UINT32 EFlags; + pop dword ptr [ebp + 5 * 4] + +;; UINT32 Ldtr, Tr; +;; UINT32 Gdtr[2], Idtr[2]; +;; Best not let anyone mess with these particular registers... + add esp, 24 + +;; UINT32 Eip; + pop dword ptr [ebp + 3 * 4] + +;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; +;; NOTE - modified segment registers could hang the debugger... We +;; could attempt to insulate ourselves against this possibility, +;; but that poses risks as well. +;; + pop gs + pop fs + pop es + pop ds + pop dword ptr [ebp + 4 * 4] + pop ss + +;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + pop edi + pop esi + add esp, 4 ; not for ebp + add esp, 4 ; not for esp + pop ebx + pop edx + pop ecx + pop eax + + mov esp, ebp + pop ebp + add esp, 8 + iretd + +CommonInterruptEntry ENDP + +END diff --git a/CloverEFI/UefiCpuPkg/CpuDxe/Ia32/IvtAsm.S b/CloverEFI/UefiCpuPkg/CpuDxe/Ia32/IvtAsm.S new file mode 100755 index 0000000000..c38461dc9c --- /dev/null +++ b/CloverEFI/UefiCpuPkg/CpuDxe/Ia32/IvtAsm.S @@ -0,0 +1,818 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# IvtAsm.S +# +# Abstract: +# +# Interrupt Vector Table +# +#------------------------------------------------------------------------------ + +# +# Interrupt Vector Table +# + + +ASM_GLOBAL ASM_PFX(AsmIdtVector00) +.p2align 3 +ASM_PFX(AsmIdtVector00): + call ASM_PFX(CommonInterruptEntry) + .short 0x00 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x01 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x02 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x03 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x04 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x05 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x06 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x07 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x08 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x09 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x0a + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x0b + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x0c + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x0d + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x0e + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x0f + nop + + call ASM_PFX(CommonInterruptEntry) + .short 0x10 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x11 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x12 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x13 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x14 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x15 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x16 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x17 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x18 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x19 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x1a + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x1b + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x1c + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x1d + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x1e + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x1f + nop + + call ASM_PFX(CommonInterruptEntry) + .short 0x00 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x21 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x22 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x23 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x24 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x25 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x26 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x27 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x28 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x29 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x2a + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x2b + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x2c + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x2d + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x2e + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x2f + nop + + call ASM_PFX(CommonInterruptEntry) + .short 0x30 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x31 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x32 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x33 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x34 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x35 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x36 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x37 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x38 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x39 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x3a + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x3b + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x3c + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x3d + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x3e + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x3f + nop + + call ASM_PFX(CommonInterruptEntry) + .short 0x40 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x41 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x42 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x43 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x44 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x45 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x46 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x47 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x48 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x49 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x4a + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x4b + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x4c + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x4d + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x4e + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x4f + nop + + call ASM_PFX(CommonInterruptEntry) + .short 0x50 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x51 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x52 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x53 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x54 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x55 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x56 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x57 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x58 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x59 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x5a + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x5b + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x5c + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x5d + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x5e + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x5f + nop + + call ASM_PFX(CommonInterruptEntry) + .short 0x60 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x61 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x62 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x63 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x64 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x65 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x66 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x67 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x68 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x69 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x6a + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x6b + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x6c + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x6d + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x6e + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x6f + nop + + call ASM_PFX(CommonInterruptEntry) + .short 0x70 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x71 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x72 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x73 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x74 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x75 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x76 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x77 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x78 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x79 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x7a + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x7b + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x7c + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x7d + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x7e + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x7f + nop + + call ASM_PFX(CommonInterruptEntry) + .short 0x80 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x81 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x82 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x83 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x84 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x85 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x86 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x87 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x88 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x89 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x8a + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x8b + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x8c + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x8d + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x8e + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x8f + nop + + call ASM_PFX(CommonInterruptEntry) + .short 0x90 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x91 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x92 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x93 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x94 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x95 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x96 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x97 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x98 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x99 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x9a + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x9b + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x9c + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x9d + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x9e + nop + call ASM_PFX(CommonInterruptEntry) + .short 0x9f + nop + + call ASM_PFX(CommonInterruptEntry) + .short 0xa0 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xa1 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xa2 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xa3 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xa4 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xa5 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xa6 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xa7 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xa8 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xa9 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xaa + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xab + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xac + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xad + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xae + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xaf + nop + + call ASM_PFX(CommonInterruptEntry) + .short 0xb0 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xb1 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xb2 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xb3 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xb4 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xb5 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xb6 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xb7 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xb8 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xb9 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xba + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xbb + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xbc + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xbd + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xbe + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xbf + nop + + call ASM_PFX(CommonInterruptEntry) + .short 0xc0 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xc1 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xc2 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xc3 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xc4 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xc5 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xc6 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xc7 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xc8 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xc9 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xca + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xcb + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xcc + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xcd + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xce + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xcf + nop + + call ASM_PFX(CommonInterruptEntry) + .short 0xd0 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xd1 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xd2 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xd3 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xd4 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xd5 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xd6 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xd7 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xd8 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xd9 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xda + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xdb + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xdc + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xdd + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xde + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xdf + nop + + call ASM_PFX(CommonInterruptEntry) + .short 0xe0 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xe1 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xe2 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xe3 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xe4 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xe5 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xe6 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xe7 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xe8 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xe9 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xea + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xeb + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xec + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xed + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xee + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xef + nop + + call ASM_PFX(CommonInterruptEntry) + .short 0xf0 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xf1 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xf2 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xf3 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xf4 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xf5 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xf6 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xf7 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xf8 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xf9 + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xfa + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xfb + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xfc + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xfd + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xfe + nop + call ASM_PFX(CommonInterruptEntry) + .short 0xff + nop + +ASM_GLOBAL ASM_PFX(AsmCommonIdtEnd) +ASM_PFX(AsmCommonIdtEnd): + .byte 0 + + diff --git a/CloverEFI/UefiCpuPkg/CpuDxe/Ia32/IvtAsm.asm b/CloverEFI/UefiCpuPkg/CpuDxe/Ia32/IvtAsm.asm new file mode 100755 index 0000000000..02003c9fa5 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/CpuDxe/Ia32/IvtAsm.asm @@ -0,0 +1,51 @@ + TITLE IvtAsm.asm: +;------------------------------------------------------------------------------ +;* +;* Copyright (c) 2008 - 2009, Intel Corporation. All rights reserved.
+;* This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* IvtAsm.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + +#include + +#ifdef MDE_CPU_IA32 + .686 + .model flat,C +#endif + .code + +;------------------------------------------------------------------------------ +; 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 +; +;------------------------------------------------------------------------------ + +EXTRN CommonInterruptEntry:PROC + +ALIGN 8 + +PUBLIC AsmIdtVector00 + +AsmIdtVector00 LABEL BYTE +REPEAT 256 + call CommonInterruptEntry + dw ($ - AsmIdtVector00 - 5) / 8 ; vector number + nop +ENDM + +END + diff --git a/CloverEFI/UefiCpuPkg/CpuDxe/X64/CpuAsm.S b/CloverEFI/UefiCpuPkg/CpuDxe/X64/CpuAsm.S new file mode 100755 index 0000000000..3ea54090eb --- /dev/null +++ b/CloverEFI/UefiCpuPkg/CpuDxe/X64/CpuAsm.S @@ -0,0 +1,346 @@ +# TITLE CpuAsm.S: + +#------------------------------------------------------------------------------ +#* +#* Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.
+#* This program and the accompanying materials +#* are licensed and made available under the terms and conditions of the BSD License +#* which accompanies this distribution. The full text of the license may be found at +#* http://opensource.org/licenses/bsd-license.php +#* +#* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +#* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +#* +#* CpuAsm.S +#* +#* Abstract: +#* +#------------------------------------------------------------------------------ + + +#text SEGMENT + + +#EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions + + +# +# point to the external interrupt vector table +# +ExternalVectorTablePtr: + .byte 0, 0, 0, 0, 0, 0, 0, 0 + +ASM_GLOBAL ASM_PFX(InitializeExternalVectorTablePtr) +ASM_PFX(InitializeExternalVectorTablePtr): + leaq ExternalVectorTablePtr(%rip), %rax # save vector number + movq %rcx, (%rax) + ret + + +#------------------------------------------------------------------------------ +# VOID +# SetCodeSelector ( +# UINT16 Selector +# ); +#------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(SetCodeSelector) +ASM_PFX(SetCodeSelector): + subq $0x14, %rsp + leaq L_setCodeSelectorLongJump(%rip), %rax + movq %rax, (%rsp) + movw %cx, 4(%rsp) + .byte 0x48, 0xFF, 0x2C, 0x24 # jmp (%rsp) note:fword jmp +L_setCodeSelectorLongJump: + addq $0x14, %rsp + ret + +#------------------------------------------------------------------------------ +# VOID +# SetDataSelectors ( +# UINT16 Selector +# ); +#------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(SetDataSelectors) +ASM_PFX(SetDataSelectors): + movw %cx, %ss + movw %cx, %ds + movw %cx, %es + movw %cx, %fs + movw %cx, %gs + ret + +#---------------------------------------; +# CommonInterruptEntry ; +#---------------------------------------; +# The follow algorithm is used for the common interrupt routine. + +ASM_GLOBAL ASM_PFX(CommonInterruptEntry) +ASM_PFX(CommonInterruptEntry): + cli + # + # All interrupt handlers are invoked through interrupt gates, so + # IF flag automatically cleared at the entry point + # + # + # Calculate vector number + # + xchgq (%rsp), %rcx # get the return address of call, actually, it is the address of vector number. + movzwl (%rcx), %ecx + cmp $32, %ecx # Intel reserved vector for exceptions? + jae NoErrorCode + pushq %rax + leaq ASM_PFX(mErrorCodeFlag)(%rip), %rax + bt %ecx, (%rax) + popq %rax + jc CommonInterruptEntry_al_0000 + +NoErrorCode: + + # + # Push a dummy error code on the stack + # to maintain coherent stack map + # + pushq (%rsp) + movq $0, 8(%rsp) +CommonInterruptEntry_al_0000: + pushq %rbp + movq %rsp, %rbp + + # + # Stack: + # +---------------------+ <-- 16-byte aligned ensured by processor + # + Old SS + + # +---------------------+ + # + Old RSP + + # +---------------------+ + # + RFlags + + # +---------------------+ + # + CS + + # +---------------------+ + # + RIP + + # +---------------------+ + # + Error Code + + # +---------------------+ + # + RCX / Vector Number + + # +---------------------+ + # + RBP + + # +---------------------+ <-- RBP, 16-byte aligned + # + + + # + # 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; + pushq %r15 + pushq %r14 + pushq %r13 + pushq %r12 + pushq %r11 + pushq %r10 + pushq %r9 + pushq %r8 + pushq %rax + pushq 8(%rbp) # RCX + pushq %rdx + pushq %rbx + pushq 48(%rbp) # RSP + pushq (%rbp) # RBP + pushq %rsi + pushq %rdi + +#; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero + movzwq 56(%rbp), %rax + pushq %rax # for ss + movzwq 32(%rbp), %rax + pushq %rax # for cs + movl %ds, %eax + pushq %rax + movl %es, %eax + pushq %rax + movl %fs, %eax + pushq %rax + movl %gs, %eax + pushq %rax + + movq %rcx, 8(%rbp) # save vector number + +#; UINT64 Rip; + pushq 24(%rbp) + +#; UINT64 Gdtr[2], Idtr[2]; + xorq %rax, %rax + pushq %rax + pushq %rax + sidt (%rsp) + xchgq 2(%rsp), %rax + xchgq (%rsp), %rax + xchgq 8(%rsp), %rax + + xorq %rax, %rax + pushq %rax + pushq %rax + sgdt (%rsp) + xchgq 2(%rsp), %rax + xchgq (%rsp), %rax + xchgq 8(%rsp), %rax + +#; UINT64 Ldtr, Tr; + xorq %rax, %rax + str %ax + pushq %rax + sldt %ax + pushq %rax + +#; UINT64 RFlags; + pushq 40(%rbp) + +#; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; + movq %cr8, %rax + pushq %rax + movq %cr4, %rax + orq $0x208, %rax + movq %rax, %cr4 + pushq %rax + mov %cr3, %rax + pushq %rax + mov %cr2, %rax + pushq %rax + xorq %rax, %rax + pushq %rax + mov %cr0, %rax + pushq %rax + +#; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + movq %dr7, %rax + pushq %rax + movq %dr6, %rax + pushq %rax + movq %dr3, %rax + pushq %rax + movq %dr2, %rax + pushq %rax + movq %dr1, %rax + pushq %rax + movq %dr0, %rax + pushq %rax + +#; FX_SAVE_STATE_X64 FxSaveState; + subq $512, %rsp + movq %rsp, %rdi + .byte 0x0f, 0x0ae, 0x07 #fxsave [rdi] + +#; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear + cld + +#; UINT32 ExceptionData; + pushq 16(%rbp) + +#; call into exception handler + movq 8(%rbp), %rcx + leaq ExternalVectorTablePtr(%rip), %rax +# movl (%eax), %eax + movq (%rax), %rax + movq (%rax,%rcx,8), %rax + orq %rax, %rax # NULL? + + je nonNullValue# + +#; Prepare parameter and call +# mov rcx, [rbp + 8] + mov %rsp, %rdx + # + # Per X64 calling convention, allocate maximum parameter stack space + # and make sure RSP is 16-byte aligned + # + subq $40, %rsp + call *%rax + addq $40, %rsp + +nonNullValue: + cli +#; UINT64 ExceptionData; + addq $8, %rsp + +#; FX_SAVE_STATE_X64 FxSaveState; + + movq %rsp, %rsi + .byte 0x0f, 0x0ae, 0x0E # fxrstor [rsi] + addq $512, %rsp + +#; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; +#; Skip restoration of DRx registers to support in-circuit emualators +#; or debuggers set breakpoint in interrupt/exception context + addq $48, %rsp + +#; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; + popq %rax + movq %rax, %cr0 + addq $8, %rsp # not for Cr1 + popq %rax + movq %rax, %cr2 + popq %rax + movq %rax, %cr3 + popq %rax + movq %rax, %cr4 + popq %rax + movq %rax, %cr8 + +#; UINT64 RFlags; + popq 40(%rbp) + +#; UINT64 Ldtr, Tr; +#; UINT64 Gdtr[2], Idtr[2]; +#; Best not let anyone mess with these particular registers... + addq $48, %rsp + +#; UINT64 Rip; + popq 24(%rbp) + +#; UINT64 Gs, Fs, Es, Ds, Cs, Ss; + popq %rax + # mov %rax, %gs ; not for gs + popq %rax + # mov %rax, %fs ; not for fs + # (X64 will not use fs and gs, so we do not restore it) + popq %rax + movl %eax, %es + popq %rax + movl %eax, %ds + popq 32(%rbp) # for cs + popq 56(%rbp) # for ss + +#; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; +#; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; + popq %rdi + popq %rsi + addq $8, %rsp # not for rbp + popq 48(%rbp) # for rsp + popq %rbx + popq %rdx + popq %rcx + popq %rax + popq %r8 + popq %r9 + popq %r10 + popq %r11 + popq %r12 + popq %r13 + popq %r14 + popq %r15 + + movq %rbp, %rsp + popq %rbp + addq $16, %rsp + iretq + + +#text ENDS + +#END + + diff --git a/CloverEFI/UefiCpuPkg/CpuDxe/X64/CpuAsm.asm b/CloverEFI/UefiCpuPkg/CpuDxe/X64/CpuAsm.asm new file mode 100755 index 0000000000..56955d37d5 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/CpuDxe/X64/CpuAsm.asm @@ -0,0 +1,337 @@ + TITLE CpuAsm.asm: +;------------------------------------------------------------------------------ +;* +;* Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.
+;* This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* CpuAsm.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + +.code + +EXTRN mErrorCodeFlag:DWORD ; Error code flags for exceptions + +; +; point to the external interrupt vector table +; +ExternalVectorTablePtr QWORD 0 + +InitializeExternalVectorTablePtr PROC PUBLIC + mov ExternalVectorTablePtr, rcx + ret +InitializeExternalVectorTablePtr ENDP + +;------------------------------------------------------------------------------ +; VOID +; SetCodeSelector ( +; UINT16 Selector +; ); +;------------------------------------------------------------------------------ +SetCodeSelector PROC PUBLIC + sub rsp, 0x14 + lea rax, setCodeSelectorLongJump + mov [rsp], rax + mov [rsp+8], cx +;* I'm not sure how to encode this. We need to jmp [esp], where in esp there is +;* w16(selector):q64(address). +;* in gcc version this is encoded as 48 ff 2c 24 [ rex.W ljmpq (%esp) ] +;* but in VC jmp qword ptr [rsp] generates code ff 24 24 [ jmpq(%esp) ] +;* so I've just inserted db 0x48 to emit REX.W and get original 48 ff 2c 24 + db 0x48 + jmp fword ptr [rsp] +setCodeSelectorLongJump: + add rsp, 0x14 + ret +SetCodeSelector ENDP + +;------------------------------------------------------------------------------ +; VOID +; SetDataSelectors ( +; UINT16 Selector +; ); +;------------------------------------------------------------------------------ +SetDataSelectors PROC PUBLIC + mov ss, cx + mov ds, cx + mov es, cx + mov fs, cx + mov gs, cx + ret +SetDataSelectors ENDP + +;---------------------------------------; +; CommonInterruptEntry ; +;---------------------------------------; +; The follow algorithm is used for the common interrupt routine. + +CommonInterruptEntry PROC PUBLIC + cli + ; + ; 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 + + ; + ; Stack: + ; +---------------------+ <-- 16-byte aligned ensured by processor + ; + Old SS + + ; +---------------------+ + ; + Old RSP + + ; +---------------------+ + ; + RFlags + + ; +---------------------+ + ; + CS + + ; +---------------------+ + ; + RIP + + ; +---------------------+ + ; + Error Code + + ; +---------------------+ + ; + RCX / Vector Number + + ; +---------------------+ + ; + RBP + + ; +---------------------+ <-- RBP, 16-byte aligned + ; + + + ; + ; 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]; + xor rax, rax + push rax + push rax + sidt [rsp] + xchg rax, [rsp + 2] + xchg rax, [rsp] + xchg rax, [rsp + 8] + + xor rax, rax + push rax + push rax + sgdt [rsp] + xchg rax, [rsp + 2] + xchg rax, [rsp] + xchg rax, [rsp + 8] + +;; 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 + mov rax, dr6 + push 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, 07h ;fxsave [rdi] + +;; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear + cld + +;; 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, 0Eh ; fxrstor [rsi] + add rsp, 512 + +;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; +;; Skip restoration of DRx registers to support in-circuit emualators +;; or debuggers set breakpoint in interrupt/exception context + add rsp, 8 * 6 + +;; 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 + +END + diff --git a/CloverEFI/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.c b/CloverEFI/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.c new file mode 100755 index 0000000000..f53606692b --- /dev/null +++ b/CloverEFI/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.c @@ -0,0 +1,539 @@ +/** @file + Produces the CPU I/O 2 Protocol. + +Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CpuIo2Dxe.h" + +// +// Handle for the CPU I/O 2 Protocol +// +EFI_HANDLE mHandle = NULL; + +// +// CPU I/O 2 Protocol instance +// +EFI_CPU_IO2_PROTOCOL mCpuIo2 = { + { + CpuMemoryServiceRead, + CpuMemoryServiceWrite + }, + { + CpuIoServiceRead, + CpuIoServiceWrite + } +}; + +// +// Lookup table for increment values based on transfer widths +// +UINT8 mInStride[] = { + 1, // EfiCpuIoWidthUint8 + 2, // EfiCpuIoWidthUint16 + 4, // EfiCpuIoWidthUint32 + 8, // EfiCpuIoWidthUint64 + 0, // EfiCpuIoWidthFifoUint8 + 0, // EfiCpuIoWidthFifoUint16 + 0, // EfiCpuIoWidthFifoUint32 + 0, // EfiCpuIoWidthFifoUint64 + 1, // EfiCpuIoWidthFillUint8 + 2, // EfiCpuIoWidthFillUint16 + 4, // EfiCpuIoWidthFillUint32 + 8 // EfiCpuIoWidthFillUint64 +}; + +// +// Lookup table for increment values based on transfer widths +// +UINT8 mOutStride[] = { + 1, // EfiCpuIoWidthUint8 + 2, // EfiCpuIoWidthUint16 + 4, // EfiCpuIoWidthUint32 + 8, // EfiCpuIoWidthUint64 + 1, // EfiCpuIoWidthFifoUint8 + 2, // EfiCpuIoWidthFifoUint16 + 4, // EfiCpuIoWidthFifoUint32 + 8, // EfiCpuIoWidthFifoUint64 + 0, // EfiCpuIoWidthFillUint8 + 0, // EfiCpuIoWidthFillUint16 + 0, // EfiCpuIoWidthFillUint32 + 0 // EfiCpuIoWidthFillUint64 +}; + +/** + Check parameters to a CPU I/O 2 Protocol service request. + + The I/O operations are carried out exactly as requested. The caller is responsible + for satisfying any alignment and I/O width restrictions that a PI System on a + platform might require. For example on some platforms, width requests of + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will + be handled by the driver. + + @param[in] MmioOperation TRUE for an MMIO operation, FALSE for I/O Port operation. + @param[in] Width Signifies the width of the I/O or Memory operation. + @param[in] Address The base address of the I/O operation. + @param[in] Count The number of I/O operations to perform. The number of + bytes moved is Width size * Count, starting at Address. + @param[in] Buffer For read operations, the destination buffer to store the results. + For write operations, the source buffer from which to write data. + + @retval EFI_SUCCESS The parameters for this request pass the checks. + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this PI system. + +**/ +EFI_STATUS +CpuIoCheckParameter ( + IN BOOLEAN MmioOperation, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) +{ + UINT64 MaxCount; + UINT64 Limit; + + // + // Check to see if Buffer is NULL + // + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Check to see if Width is in the valid range + // + if ((UINT32)Width >= EfiCpuIoWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + // + // For FIFO type, the target address won't increase during the access, + // so treat Count as 1 + // + if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) { + Count = 1; + } + + // + // Check to see if Width is in the valid range for I/O Port operations + // + Width = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03); + if (!MmioOperation && (Width == EfiCpuIoWidthUint64)) { + return EFI_INVALID_PARAMETER; + } + + // + // Check to see if Address is aligned + // + if ((Address & (UINT64)(mInStride[Width] - 1)) != 0) { + return EFI_UNSUPPORTED; + } + + // + // Check to see if any address associated with this transfer exceeds the maximum + // allowed address. The maximum address implied by the parameters passed in is + // Address + Size * Count. If the following condition is met, then the transfer + // is not supported. + // + // Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1 + // + // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count + // can also be the maximum integer value supported by the CPU, this range + // check must be adjusted to avoid all oveflow conditions. + // + // The following form of the range check is equivalent but assumes that + // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1). + // + Limit = (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS); + if (Count == 0) { + if (Address > Limit) { + return EFI_UNSUPPORTED; + } + } else { + MaxCount = RShiftU64 (Limit, Width); + if (MaxCount < (Count - 1)) { + return EFI_UNSUPPORTED; + } + if (Address > LShiftU64 (MaxCount - Count + 1, Width)) { + return EFI_UNSUPPORTED; + } + } + + // + // Check to see if Buffer is aligned +/* // (IA-32 allows UINT64 and INT64 data types to be 32-bit aligned.) + // + if (((UINTN)Buffer & ((MIN (sizeof (UINTN), mInStride[Width]) - 1))) != 0) { + return EFI_UNSUPPORTED; + }*/ + if (((UINTN)Buffer & (mInStride[Width] - 1)) != 0) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +/** + Reads memory-mapped registers. + + The I/O operations are carried out exactly as requested. The caller is responsible + for satisfying any alignment and I/O width restrictions that a PI System on a + platform might require. For example on some platforms, width requests of + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will + be handled by the driver. + + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32, + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for + each of the Count operations that is performed. + + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16, + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times on the same Address. + + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16, + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times from the first element of Buffer. + + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance. + @param[in] Width Signifies the width of the I/O or Memory operation. + @param[in] Address The base address of the I/O operation. + @param[in] Count The number of I/O operations to perform. The number of + bytes moved is Width size * Count, starting at Address. + @param[out] Buffer For read operations, the destination buffer to store the results. + For write operations, the source buffer from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the PI system. + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this PI system. + +**/ +EFI_STATUS +EFIAPI +CpuMemoryServiceRead ( + IN EFI_CPU_IO2_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT8 InStride; + UINT8 OutStride; + EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth; + UINT8 *Uint8Buffer; + + Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Select loop based on the width of the transfer + // + InStride = mInStride[Width]; + OutStride = mOutStride[Width]; + OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03); + for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { + if (OperationWidth == EfiCpuIoWidthUint8) { + *Uint8Buffer = MmioRead8 ((UINTN)Address); + } else if (OperationWidth == EfiCpuIoWidthUint16) { + *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address); + } else if (OperationWidth == EfiCpuIoWidthUint32) { + *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address); + } else if (OperationWidth == EfiCpuIoWidthUint64) { + *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address); + } + } + return EFI_SUCCESS; +} + +/** + Writes memory-mapped registers. + + The I/O operations are carried out exactly as requested. The caller is responsible + for satisfying any alignment and I/O width restrictions that a PI System on a + platform might require. For example on some platforms, width requests of + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will + be handled by the driver. + + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32, + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for + each of the Count operations that is performed. + + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16, + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times on the same Address. + + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16, + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times from the first element of Buffer. + + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance. + @param[in] Width Signifies the width of the I/O or Memory operation. + @param[in] Address The base address of the I/O operation. + @param[in] Count The number of I/O operations to perform. The number of + bytes moved is Width size * Count, starting at Address. + @param[in] Buffer For read operations, the destination buffer to store the results. + For write operations, the source buffer from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the PI system. + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this PI system. + +**/ +EFI_STATUS +EFIAPI +CpuMemoryServiceWrite ( + IN EFI_CPU_IO2_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT8 InStride; + UINT8 OutStride; + EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth; + UINT8 *Uint8Buffer; + + Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Select loop based on the width of the transfer + // + InStride = mInStride[Width]; + OutStride = mOutStride[Width]; + OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03); + for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { + if (OperationWidth == EfiCpuIoWidthUint8) { + MmioWrite8 ((UINTN)Address, *Uint8Buffer); + } else if (OperationWidth == EfiCpuIoWidthUint16) { + MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer)); + } else if (OperationWidth == EfiCpuIoWidthUint32) { + MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer)); + } else if (OperationWidth == EfiCpuIoWidthUint64) { + MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer)); + } + } + return EFI_SUCCESS; +} + +/** + Reads I/O registers. + + The I/O operations are carried out exactly as requested. The caller is responsible + for satisfying any alignment and I/O width restrictions that a PI System on a + platform might require. For example on some platforms, width requests of + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will + be handled by the driver. + + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32, + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for + each of the Count operations that is performed. + + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16, + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times on the same Address. + + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16, + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times from the first element of Buffer. + + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance. + @param[in] Width Signifies the width of the I/O or Memory operation. + @param[in] Address The base address of the I/O operation. + @param[in] Count The number of I/O operations to perform. The number of + bytes moved is Width size * Count, starting at Address. + @param[out] Buffer For read operations, the destination buffer to store the results. + For write operations, the source buffer from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the PI system. + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this PI system. + +**/ +EFI_STATUS +EFIAPI +CpuIoServiceRead ( + IN EFI_CPU_IO2_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT8 InStride; + UINT8 OutStride; + EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth; + UINT8 *Uint8Buffer; + + Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Select loop based on the width of the transfer + // + InStride = mInStride[Width]; + OutStride = mOutStride[Width]; + OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03); + for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { + if (OperationWidth == EfiCpuIoWidthUint8) { + *Uint8Buffer = IoRead8 ((UINTN)Address); + } else if (OperationWidth == EfiCpuIoWidthUint16) { + *((UINT16 *)Uint8Buffer) = IoRead16 ((UINTN)Address); + } else if (OperationWidth == EfiCpuIoWidthUint32) { + *((UINT32 *)Uint8Buffer) = IoRead32 ((UINTN)Address); + } + } + + return EFI_SUCCESS; +} + +/** + Write I/O registers. + + The I/O operations are carried out exactly as requested. The caller is responsible + for satisfying any alignment and I/O width restrictions that a PI System on a + platform might require. For example on some platforms, width requests of + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will + be handled by the driver. + + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32, + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for + each of the Count operations that is performed. + + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16, + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times on the same Address. + + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16, + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times from the first element of Buffer. + + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance. + @param[in] Width Signifies the width of the I/O or Memory operation. + @param[in] Address The base address of the I/O operation. + @param[in] Count The number of I/O operations to perform. The number of + bytes moved is Width size * Count, starting at Address. + @param[in] Buffer For read operations, the destination buffer to store the results. + For write operations, the source buffer from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the PI system. + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this PI system. + +**/ +EFI_STATUS +EFIAPI +CpuIoServiceWrite ( + IN EFI_CPU_IO2_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT8 InStride; + UINT8 OutStride; + EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth; + UINT8 *Uint8Buffer; + + // + // Make sure the parameters are valid + // + Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Select loop based on the width of the transfer + // + InStride = mInStride[Width]; + OutStride = mOutStride[Width]; + OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03); + for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { + if (OperationWidth == EfiCpuIoWidthUint8) { + IoWrite8 ((UINTN)Address, *Uint8Buffer); + } else if (OperationWidth == EfiCpuIoWidthUint16) { + IoWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer)); + } else if (OperationWidth == EfiCpuIoWidthUint32) { + IoWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer)); + } + } + + return EFI_SUCCESS; +} + +/** + The user Entry Point for module CpuIo2Dxe. The user code starts with this function. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +CpuIo2Initialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiCpuIo2ProtocolGuid); + Status = gBS->InstallMultipleProtocolInterfaces ( + &mHandle, + &gEfiCpuIo2ProtocolGuid, &mCpuIo2, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/CloverEFI/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.h b/CloverEFI/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.h new file mode 100755 index 0000000000..7d00da16f4 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.h @@ -0,0 +1,225 @@ +/** @file + Internal include file for the CPU I/O 2 Protocol. + +Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _CPU_IO2_DXE_H_ +#define _CPU_IO2_DXE_H_ + +#include + +#include + +#include +#include +#include +#include + +#define MAX_IO_PORT_ADDRESS 0xFFFF + +/** + Reads memory-mapped registers. + + The I/O operations are carried out exactly as requested. The caller is responsible + for satisfying any alignment and I/O width restrictions that a PI System on a + platform might require. For example on some platforms, width requests of + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will + be handled by the driver. + + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32, + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for + each of the Count operations that is performed. + + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16, + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times on the same Address. + + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16, + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times from the first element of Buffer. + + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance. + @param[in] Width Signifies the width of the I/O or Memory operation. + @param[in] Address The base address of the I/O operation. + @param[in] Count The number of I/O operations to perform. The number of + bytes moved is Width size * Count, starting at Address. + @param[out] Buffer For read operations, the destination buffer to store the results. + For write operations, the source buffer from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the PI system. + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this PI system. + +**/ +EFI_STATUS +EFIAPI +CpuMemoryServiceRead ( + IN EFI_CPU_IO2_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ); + +/** + Writes memory-mapped registers. + + The I/O operations are carried out exactly as requested. The caller is responsible + for satisfying any alignment and I/O width restrictions that a PI System on a + platform might require. For example on some platforms, width requests of + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will + be handled by the driver. + + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32, + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for + each of the Count operations that is performed. + + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16, + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times on the same Address. + + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16, + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times from the first element of Buffer. + + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance. + @param[in] Width Signifies the width of the I/O or Memory operation. + @param[in] Address The base address of the I/O operation. + @param[in] Count The number of I/O operations to perform. The number of + bytes moved is Width size * Count, starting at Address. + @param[in] Buffer For read operations, the destination buffer to store the results. + For write operations, the source buffer from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the PI system. + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this PI system. + +**/ +EFI_STATUS +EFIAPI +CpuMemoryServiceWrite ( + IN EFI_CPU_IO2_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ); + +/** + Reads I/O registers. + + The I/O operations are carried out exactly as requested. The caller is responsible + for satisfying any alignment and I/O width restrictions that a PI System on a + platform might require. For example on some platforms, width requests of + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will + be handled by the driver. + + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32, + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for + each of the Count operations that is performed. + + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16, + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times on the same Address. + + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16, + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times from the first element of Buffer. + + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance. + @param[in] Width Signifies the width of the I/O or Memory operation. + @param[in] Address The base address of the I/O operation. + @param[in] Count The number of I/O operations to perform. The number of + bytes moved is Width size * Count, starting at Address. + @param[out] Buffer For read operations, the destination buffer to store the results. + For write operations, the source buffer from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the PI system. + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this PI system. + +**/ +EFI_STATUS +EFIAPI +CpuIoServiceRead ( + IN EFI_CPU_IO2_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ); + +/** + Write I/O registers. + + The I/O operations are carried out exactly as requested. The caller is responsible + for satisfying any alignment and I/O width restrictions that a PI System on a + platform might require. For example on some platforms, width requests of + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will + be handled by the driver. + + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32, + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for + each of the Count operations that is performed. + + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16, + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times on the same Address. + + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16, + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times from the first element of Buffer. + + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance. + @param[in] Width Signifies the width of the I/O or Memory operation. + @param[in] Address The base address of the I/O operation. + @param[in] Count The number of I/O operations to perform. The number of + bytes moved is Width size * Count, starting at Address. + @param[in] Buffer For read operations, the destination buffer to store the results. + For write operations, the source buffer from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the PI system. + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this PI system. + +**/ +EFI_STATUS +EFIAPI +CpuIoServiceWrite ( + IN EFI_CPU_IO2_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ); + +#endif diff --git a/CloverEFI/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf b/CloverEFI/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf new file mode 100755 index 0000000000..3abf2677f7 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf @@ -0,0 +1,54 @@ +## @file +# Produces the CPU I/O 2 Protocol. +# +# This DXE driver produces of the CPU I/O 2 Protocol, as introduced by PI 1.2. +# +# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = CpuIo2Dxe + FILE_GUID = A19B1FE7-C1BC-49F8-875F-54A5D542443F + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = CpuIo2Initialize + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + CpuIo2Dxe.c + CpuIo2Dxe.h + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + BaseLib + DebugLib + IoLib + UefiBootServicesTableLib + +[Protocols] + gEfiCpuIo2ProtocolGuid ## PRODUCES + +[Depex] + TRUE + +[BuildOptions] + XCODE:*_*_*_CC_FLAGS = -Os -DMDEPKG_NDEBUG + GCC:*_*_*_CC_FLAGS = -O0 -DMDEPKG_NDEBUG + MSFT:*_*_*_CC_FLAGS = /D MDEPKG_NDEBUG diff --git a/CloverEFI/UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.c b/CloverEFI/UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.c new file mode 100755 index 0000000000..1c172a096c --- /dev/null +++ b/CloverEFI/UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.c @@ -0,0 +1,413 @@ +/** @file + Produces the SMM CPU I/O Protocol. + +Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CpuIo2Smm.h" + +// +// Handle for the SMM CPU I/O Protocol +// +EFI_HANDLE mHandle = NULL; + +// +// SMM CPU I/O Protocol instance +// +EFI_SMM_CPU_IO2_PROTOCOL mSmmCpuIo2 = { + { + CpuMemoryServiceRead, + CpuMemoryServiceWrite + }, + { + CpuIoServiceRead, + CpuIoServiceWrite + } +}; + +// +// Lookup table for increment values based on transfer widths +// +UINT8 mStride[] = { + 1, // SMM_IO_UINT8 + 2, // SMM_IO_UINT16 + 4, // SMM_IO_UINT32 + 8 // SMM_IO_UINT64 +}; + +/** + Check parameters to a SMM CPU I/O Protocol service request. + + @param[in] MmioOperation TRUE for an MMIO operation, FALSE for I/O Port operation. + @param[in] Width Signifies the width of the I/O operations. + @param[in] Address The base address of the I/O operations. The caller is + responsible for aligning the Address if required. + @param[in] Count The number of I/O operations to perform. + @param[in] Buffer For read operations, the destination buffer to store + the results. For write operations, the source buffer + from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the device. + @retval EFI_UNSUPPORTED The Address is not valid for this system. + @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid. + +**/ +EFI_STATUS +CpuIoCheckParameter ( + IN BOOLEAN MmioOperation, + IN EFI_SMM_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) +{ + UINT64 MaxCount; + UINT64 Limit; + + // + // Check to see if Buffer is NULL + // + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Check to see if Width is in the valid range + // + if (Width < 0 || Width > SMM_IO_UINT64) { + return EFI_INVALID_PARAMETER; + } + + // + // Check to see if Width is in the valid range for I/O Port operations + // + if (!MmioOperation && (Width == SMM_IO_UINT64)) { + return EFI_INVALID_PARAMETER; + } + + // + // Check to see if any address associated with this transfer exceeds the maximum + // allowed address. The maximum address implied by the parameters passed in is + // Address + Size * Count. If the following condition is met, then the transfer + // is not supported. + // + // Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1 + // + // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count + // can also be the maximum integer value supported by the CPU, this range + // check must be adjusted to avoid all overflow conditions. + // + // The following form of the range check is equivalent but assumes that + // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1). + // + Limit = (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS); + if (Count == 0) { + if (Address > Limit) { + return EFI_UNSUPPORTED; + } + } else { + MaxCount = RShiftU64 (Limit, Width); + if (MaxCount < (Count - 1)) { + return EFI_UNSUPPORTED; + } + if (Address > LShiftU64 (MaxCount - Count + 1, Width)) { + return EFI_UNSUPPORTED; + } + } + + // + // Check to see if Address is aligned + // + if ((Address & (UINT64)(mStride[Width] - 1)) != 0) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +/** + Reads memory-mapped registers. + + The I/O operations are carried out exactly as requested. The caller is + responsible for any alignment and I/O width issues that the bus, device, + platform, or type of I/O might require. + + @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance. + @param[in] Width Signifies the width of the I/O operations. + @param[in] Address The base address of the I/O operations. The caller is + responsible for aligning the Address if required. + @param[in] Count The number of I/O operations to perform. + @param[out] Buffer For read operations, the destination buffer to store + the results. For write operations, the source buffer + from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the device. + @retval EFI_UNSUPPORTED The Address is not valid for this system. + @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources + +**/ +EFI_STATUS +EFIAPI +CpuMemoryServiceRead ( + IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This, + IN EFI_SMM_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT8 Stride; + UINT8 *Uint8Buffer; + + Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Select loop based on the width of the transfer + // + Stride = mStride[Width]; + for (Uint8Buffer = Buffer; Count > 0; Address += Stride, Uint8Buffer += Stride, Count--) { + if (Width == SMM_IO_UINT8) { + *Uint8Buffer = MmioRead8 ((UINTN)Address); + } else if (Width == SMM_IO_UINT16) { + *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address); + } else if (Width == SMM_IO_UINT32) { + *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address); + } else if (Width == SMM_IO_UINT64) { + *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address); + } + } + return EFI_SUCCESS; +} + +/** + Writes memory-mapped registers. + + The I/O operations are carried out exactly as requested. The caller is + responsible for any alignment and I/O width issues that the bus, device, + platform, or type of I/O might require. + + @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance. + @param[in] Width Signifies the width of the I/O operations. + @param[in] Address The base address of the I/O operations. The caller is + responsible for aligning the Address if required. + @param[in] Count The number of I/O operations to perform. + @param[in] Buffer For read operations, the destination buffer to store + the results. For write operations, the source buffer + from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the device. + @retval EFI_UNSUPPORTED The Address is not valid for this system. + @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources + +**/ +EFI_STATUS +EFIAPI +CpuMemoryServiceWrite ( + IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This, + IN EFI_SMM_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT8 Stride; + UINT8 *Uint8Buffer; + + Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Select loop based on the width of the transfer + // + Stride = mStride[Width]; + for (Uint8Buffer = Buffer; Count > 0; Address += Stride, Uint8Buffer += Stride, Count--) { + if (Width == SMM_IO_UINT8) { + MmioWrite8 ((UINTN)Address, *Uint8Buffer); + } else if (Width == SMM_IO_UINT16) { + MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer)); + } else if (Width == SMM_IO_UINT32) { + MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer)); + } else if (Width == SMM_IO_UINT64) { + MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer)); + } + } + return EFI_SUCCESS; +} + +/** + Reads I/O registers. + + The I/O operations are carried out exactly as requested. The caller is + responsible for any alignment and I/O width issues that the bus, device, + platform, or type of I/O might require. + + @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance. + @param[in] Width Signifies the width of the I/O operations. + @param[in] Address The base address of the I/O operations. The caller is + responsible for aligning the Address if required. + @param[in] Count The number of I/O operations to perform. + @param[out] Buffer For read operations, the destination buffer to store + the results. For write operations, the source buffer + from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the device. + @retval EFI_UNSUPPORTED The Address is not valid for this system. + @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources + +**/ +EFI_STATUS +EFIAPI +CpuIoServiceRead ( + IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This, + IN EFI_SMM_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT8 Stride; + UINT8 *Uint8Buffer; + + Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Select loop based on the width of the transfer + // + Stride = mStride[Width]; + for (Uint8Buffer = Buffer; Count > 0; Address += Stride, Uint8Buffer += Stride, Count--) { + if (Width == SMM_IO_UINT8) { + *Uint8Buffer = IoRead8 ((UINTN)Address); + } else if (Width == SMM_IO_UINT16) { + *((UINT16 *)Uint8Buffer) = IoRead16 ((UINTN)Address); + } else if (Width == SMM_IO_UINT32) { + *((UINT32 *)Uint8Buffer) = IoRead32 ((UINTN)Address); + } + } + + return EFI_SUCCESS; +} + +/** + Write I/O registers. + + The I/O operations are carried out exactly as requested. The caller is + responsible for any alignment and I/O width issues that the bus, device, + platform, or type of I/O might require. + + @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance. + @param[in] Width Signifies the width of the I/O operations. + @param[in] Address The base address of the I/O operations. The caller is + responsible for aligning the Address if required. + @param[in] Count The number of I/O operations to perform. + @param[in] Buffer For read operations, the destination buffer to store + the results. For write operations, the source buffer + from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the device. + @retval EFI_UNSUPPORTED The Address is not valid for this system. + @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources + +**/ +EFI_STATUS +EFIAPI +CpuIoServiceWrite ( + IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This, + IN EFI_SMM_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT8 Stride; + UINT8 *Uint8Buffer; + + // + // Make sure the parameters are valid + // + Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Select loop based on the width of the transfer + // + Stride = mStride[Width]; + for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += Stride, Uint8Buffer += Stride, Count--) { + if (Width == SMM_IO_UINT8) { + IoWrite8 ((UINTN)Address, *Uint8Buffer); + } else if (Width == SMM_IO_UINT16) { + IoWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer)); + } else if (Width == SMM_IO_UINT32) { + IoWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer)); + } + } + + return EFI_SUCCESS; +} + +/** + The module Entry Point SmmCpuIoProtocol driver + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval Other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +SmmCpuIo2Initialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Copy the SMM CPU I/O Protocol instance into the System Management System Table + // + CopyMem (&gSmst->SmmIo, &mSmmCpuIo2, sizeof (mSmmCpuIo2)); + + // + // Install the SMM CPU I/O Protocol into the SMM protocol database + // + Status = gSmst->SmmInstallProtocolInterface ( + &mHandle, + &gEfiSmmCpuIo2ProtocolGuid, + EFI_NATIVE_INTERFACE, + &mSmmCpuIo2 + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/CloverEFI/UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.h b/CloverEFI/UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.h new file mode 100755 index 0000000000..5a092594d7 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.h @@ -0,0 +1,162 @@ +/** @file + Internal include file for the SMM CPU I/O Protocol. + +Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _CPU_IO2_SMM_H_ +#define _CPU_IO2_SMM_H_ + +#include + +#include + +#include +#include +#include +#include +#include + +#define MAX_IO_PORT_ADDRESS 0xFFFF + +/** + Reads memory-mapped registers. + + The I/O operations are carried out exactly as requested. The caller is + responsible for any alignment and I/O width issues that the bus, device, + platform, or type of I/O might require. + + @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance. + @param[in] Width Signifies the width of the I/O operations. + @param[in] Address The base address of the I/O operations. The caller is + responsible for aligning the Address if required. + @param[in] Count The number of I/O operations to perform. + @param[out] Buffer For read operations, the destination buffer to store + the results. For write operations, the source buffer + from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the device. + @retval EFI_UNSUPPORTED The Address is not valid for this system. + @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources + +**/ +EFI_STATUS +EFIAPI +CpuMemoryServiceRead ( + IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This, + IN EFI_SMM_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ); + +/** + Writes memory-mapped registers. + + The I/O operations are carried out exactly as requested. The caller is + responsible for any alignment and I/O width issues that the bus, device, + platform, or type of I/O might require. + + @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance. + @param[in] Width Signifies the width of the I/O operations. + @param[in] Address The base address of the I/O operations. The caller is + responsible for aligning the Address if required. + @param[in] Count The number of I/O operations to perform. + @param[in] Buffer For read operations, the destination buffer to store + the results. For write operations, the source buffer + from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the device. + @retval EFI_UNSUPPORTED The Address is not valid for this system. + @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources + +**/ +EFI_STATUS +EFIAPI +CpuMemoryServiceWrite ( + IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This, + IN EFI_SMM_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ); + +/** + Reads I/O registers. + + The I/O operations are carried out exactly as requested. The caller is + responsible for any alignment and I/O width issues that the bus, device, + platform, or type of I/O might require. + + @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance. + @param[in] Width Signifies the width of the I/O operations. + @param[in] Address The base address of the I/O operations. The caller is + responsible for aligning the Address if required. + @param[in] Count The number of I/O operations to perform. + @param[out] Buffer For read operations, the destination buffer to store + the results. For write operations, the source buffer + from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the device. + @retval EFI_UNSUPPORTED The Address is not valid for this system. + @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources + +**/ +EFI_STATUS +EFIAPI +CpuIoServiceRead ( + IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This, + IN EFI_SMM_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ); + +/** + Write I/O registers. + + The I/O operations are carried out exactly as requested. The caller is + responsible for any alignment and I/O width issues that the bus, device, + platform, or type of I/O might require. + + @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance. + @param[in] Width Signifies the width of the I/O operations. + @param[in] Address The base address of the I/O operations. The caller is + responsible for aligning the Address if required. + @param[in] Count The number of I/O operations to perform. + @param[in] Buffer For read operations, the destination buffer to store + the results. For write operations, the source buffer + from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the device. + @retval EFI_UNSUPPORTED The Address is not valid for this system. + @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources + +**/ +EFI_STATUS +EFIAPI +CpuIoServiceWrite ( + IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This, + IN EFI_SMM_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ); + +#endif diff --git a/CloverEFI/UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf b/CloverEFI/UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf new file mode 100755 index 0000000000..e77b61f655 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf @@ -0,0 +1,48 @@ +## @file +# Module that produces the SMM CPU I/O 2 Protocol using the services of the I/O Library +# +# Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = CpuIo2Smm + FILE_GUID = A47EE2D8-F60E-42fd-8E58-7BD65EE4C29B + MODULE_TYPE = DXE_SMM_DRIVER + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x0001000A + ENTRY_POINT = SmmCpuIo2Initialize + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + CpuIo2Smm.c + CpuIo2Smm.h + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + BaseLib + DebugLib + IoLib + SmmServicesTableLib + BaseMemoryLib + +[Protocols] + gEfiSmmCpuIo2ProtocolGuid # PROTOCOL ALWAYS_CONSUMED + +[Depex] + TRUE diff --git a/CloverEFI/UefiCpuPkg/CpuIoPei/CpuIoPei.c b/CloverEFI/UefiCpuPkg/CpuIoPei/CpuIoPei.c new file mode 100755 index 0000000000..8888000533 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/CpuIoPei/CpuIoPei.c @@ -0,0 +1,864 @@ +/** @file + Produces the CPU I/O PPI. + +Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CpuIoPei.h" + +// +// Instance of CPU I/O PPI +// +EFI_PEI_CPU_IO_PPI gCpuIoPpi = { + { + CpuMemoryServiceRead, + CpuMemoryServiceWrite + }, + { + CpuIoServiceRead, + CpuIoServiceWrite + }, + CpuIoRead8, + CpuIoRead16, + CpuIoRead32, + CpuIoRead64, + CpuIoWrite8, + CpuIoWrite16, + CpuIoWrite32, + CpuIoWrite64, + CpuMemRead8, + CpuMemRead16, + CpuMemRead32, + CpuMemRead64, + CpuMemWrite8, + CpuMemWrite16, + CpuMemWrite32, + CpuMemWrite64 +}; + +// +// PPI Descriptor used to install the CPU I/O PPI +// +EFI_PEI_PPI_DESCRIPTOR gPpiList = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiCpuIoPpiInstalledGuid, + NULL +}; + +// +// Lookup table for increment values based on transfer widths +// +UINT8 mInStride[] = { + 1, // EfiPeiCpuIoWidthUint8 + 2, // EfiPeiCpuIoWidthUint16 + 4, // EfiPeiCpuIoWidthUint32 + 8, // EfiPeiCpuIoWidthUint64 + 0, // EfiPeiCpuIoWidthFifoUint8 + 0, // EfiPeiCpuIoWidthFifoUint16 + 0, // EfiPeiCpuIoWidthFifoUint32 + 0, // EfiPeiCpuIoWidthFifoUint64 + 1, // EfiPeiCpuIoWidthFillUint8 + 2, // EfiPeiCpuIoWidthFillUint16 + 4, // EfiPeiCpuIoWidthFillUint32 + 8 // EfiPeiCpuIoWidthFillUint64 +}; + +// +// Lookup table for increment values based on transfer widths +// +UINT8 mOutStride[] = { + 1, // EfiPeiCpuIoWidthUint8 + 2, // EfiPeiCpuIoWidthUint16 + 4, // EfiPeiCpuIoWidthUint32 + 8, // EfiPeiCpuIoWidthUint64 + 1, // EfiPeiCpuIoWidthFifoUint8 + 2, // EfiPeiCpuIoWidthFifoUint16 + 4, // EfiPeiCpuIoWidthFifoUint32 + 8, // EfiPeiCpuIoWidthFifoUint64 + 0, // EfiPeiCpuIoWidthFillUint8 + 0, // EfiPeiCpuIoWidthFillUint16 + 0, // EfiPeiCpuIoWidthFillUint32 + 0 // EfiPeiCpuIoWidthFillUint64 +}; + +/** + Check parameters to a CPU I/O PPI service request. + + @param[in] MmioOperation TRUE for an MMIO operation, FALSE for I/O Port operation. + @param[in] Width The width of the access. Enumerated in bytes. + @param[in] Address The physical address of the access. + @param[in] Count The number of accesses to perform. + @param[in] Buffer A pointer to the buffer of data. + + @retval EFI_SUCCESS The parameters for this request pass the checks. + @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this EFI system. + +**/ +EFI_STATUS +CpuIoCheckParameter ( + IN BOOLEAN MmioOperation, + IN EFI_PEI_CPU_IO_PPI_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) +{ + UINT64 MaxCount; + UINT64 Limit; + + // + // Check to see if Buffer is NULL + // + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Check to see if Width is in the valid range + // + if (Width < 0 || Width >= EfiPeiCpuIoWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + // + // For FIFO type, the target address won't increase during the access, + // so treat Count as 1 + // + if (Width >= EfiPeiCpuIoWidthFifoUint8 && Width <= EfiPeiCpuIoWidthFifoUint64) { + Count = 1; + } + + // + // Check to see if Width is in the valid range for I/O Port operations + // + Width = (EFI_PEI_CPU_IO_PPI_WIDTH) (Width & 0x03); + if (!MmioOperation && (Width == EfiPeiCpuIoWidthUint64)) { + return EFI_INVALID_PARAMETER; + } + + // + // Check to see if any address associated with this transfer exceeds the maximum + // allowed address. The maximum address implied by the parameters passed in is + // Address + Size * Count. If the following condition is met, then the transfer + // is not supported. + // + // Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1 + // + // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count + // can also be the maximum integer value supported by the CPU, this range + // check must be adjusted to avoid all overflow conditions. + // + // The following form of the range check is equivalent but assumes that + // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1). + // + Limit = (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS); + if (Count == 0) { + if (Address > Limit) { + return EFI_UNSUPPORTED; + } + } else { + MaxCount = RShiftU64 (Limit, Width); + if (MaxCount < (Count - 1)) { + return EFI_UNSUPPORTED; + } + if (Address > LShiftU64 (MaxCount - Count + 1, Width)) { + return EFI_UNSUPPORTED; + } + } + + return EFI_SUCCESS; +} + +/** + Reads memory-mapped registers. + + @param[in] PeiServices An indirect pointer to the PEI Services Table + published by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Width The width of the access. Enumerated in bytes. + @param[in] Address The physical address of the access. + @param[in] Count The number of accesses to perform. + @param[out] Buffer A pointer to the buffer of data. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this EFI system. + +**/ +EFI_STATUS +EFIAPI +CpuMemoryServiceRead ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN EFI_PEI_CPU_IO_PPI_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT8 InStride; + UINT8 OutStride; + EFI_PEI_CPU_IO_PPI_WIDTH OperationWidth; + BOOLEAN Aligned; + UINT8 *Uint8Buffer; + + Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Select loop based on the width of the transfer + // + InStride = mInStride[Width]; + OutStride = mOutStride[Width]; + OperationWidth = (EFI_PEI_CPU_IO_PPI_WIDTH) (Width & 0x03); + Aligned = (BOOLEAN)(((UINTN)Buffer & (mInStride[OperationWidth] - 1)) == 0x00); + for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { + if (OperationWidth == EfiPeiCpuIoWidthUint8) { + *Uint8Buffer = MmioRead8 ((UINTN)Address); + } else if (OperationWidth == EfiPeiCpuIoWidthUint16) { + if (Aligned) { + *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address); + } else { + WriteUnaligned16 ((UINT16 *)Uint8Buffer, MmioRead16 ((UINTN)Address)); + } + } else if (OperationWidth == EfiPeiCpuIoWidthUint32) { + if (Aligned) { + *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address); + } else { + WriteUnaligned32 ((UINT32 *)Uint8Buffer, MmioRead32 ((UINTN)Address)); + } + } else if (OperationWidth == EfiPeiCpuIoWidthUint64) { + if (Aligned) { + *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address); + } else { + WriteUnaligned64 ((UINT64 *)Uint8Buffer, MmioRead64 ((UINTN)Address)); + } + } + } + return EFI_SUCCESS; +} + +/** + Writes memory-mapped registers. + + @param[in] PeiServices An indirect pointer to the PEI Services Table + published by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Width The width of the access. Enumerated in bytes. + @param[in] Address The physical address of the access. + @param[in] Count The number of accesses to perform. + @param[in] Buffer A pointer to the buffer of data. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this EFI system. + +**/ +EFI_STATUS +EFIAPI +CpuMemoryServiceWrite ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN EFI_PEI_CPU_IO_PPI_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT8 InStride; + UINT8 OutStride; + EFI_PEI_CPU_IO_PPI_WIDTH OperationWidth; + BOOLEAN Aligned; + UINT8 *Uint8Buffer; + + Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Select loop based on the width of the transfer + // + InStride = mInStride[Width]; + OutStride = mOutStride[Width]; + OperationWidth = (EFI_PEI_CPU_IO_PPI_WIDTH) (Width & 0x03); + Aligned = (BOOLEAN)(((UINTN)Buffer & (mInStride[OperationWidth] - 1)) == 0x00); + for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { + if (OperationWidth == EfiPeiCpuIoWidthUint8) { + MmioWrite8 ((UINTN)Address, *Uint8Buffer); + } else if (OperationWidth == EfiPeiCpuIoWidthUint16) { + if (Aligned) { + MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer)); + } else { + MmioWrite16 ((UINTN)Address, ReadUnaligned16 ((UINT16 *)Uint8Buffer)); + } + } else if (OperationWidth == EfiPeiCpuIoWidthUint32) { + if (Aligned) { + MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer)); + } else { + MmioWrite32 ((UINTN)Address, ReadUnaligned32 ((UINT32 *)Uint8Buffer)); + } + } else if (OperationWidth == EfiPeiCpuIoWidthUint64) { + if (Aligned) { + MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer)); + } else { + MmioWrite64 ((UINTN)Address, ReadUnaligned64 ((UINT64 *)Uint8Buffer)); + } + } + } + return EFI_SUCCESS; +} + +/** + Reads I/O registers. + + @param[in] PeiServices An indirect pointer to the PEI Services Table + published by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Width The width of the access. Enumerated in bytes. + @param[in] Address The physical address of the access. + @param[in] Count The number of accesses to perform. + @param[out] Buffer A pointer to the buffer of data. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this EFI system. + +**/ +EFI_STATUS +EFIAPI +CpuIoServiceRead ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN EFI_PEI_CPU_IO_PPI_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT8 InStride; + UINT8 OutStride; + EFI_PEI_CPU_IO_PPI_WIDTH OperationWidth; + BOOLEAN Aligned; + UINT8 *Uint8Buffer; + + Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Select loop based on the width of the transfer + // + InStride = mInStride[Width]; + OutStride = mOutStride[Width]; + OperationWidth = (EFI_PEI_CPU_IO_PPI_WIDTH) (Width & 0x03); + Aligned = (BOOLEAN)(((UINTN)Buffer & (mInStride[OperationWidth] - 1)) == 0x00); + for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { + if (OperationWidth == EfiPeiCpuIoWidthUint8) { + *Uint8Buffer = IoRead8 ((UINTN)Address); + } else if (OperationWidth == EfiPeiCpuIoWidthUint16) { + if (Aligned) { + *((UINT16 *)Uint8Buffer) = IoRead16 ((UINTN)Address); + } else { + WriteUnaligned16 ((UINT16 *)Uint8Buffer, IoRead16 ((UINTN)Address)); + } + } else if (OperationWidth == EfiPeiCpuIoWidthUint32) { + if (Aligned) { + *((UINT32 *)Uint8Buffer) = IoRead32 ((UINTN)Address); + } else { + WriteUnaligned32 ((UINT32 *)Uint8Buffer, IoRead32 ((UINTN)Address)); + } + } + } + + return EFI_SUCCESS; +} + +/** + Write I/O registers. + + @param[in] PeiServices An indirect pointer to the PEI Services Table + published by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Width The width of the access. Enumerated in bytes. + @param[in] Address The physical address of the access. + @param[in] Count The number of accesses to perform. + @param[in] Buffer A pointer to the buffer of data. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this EFI system. + +**/ +EFI_STATUS +EFIAPI +CpuIoServiceWrite ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN EFI_PEI_CPU_IO_PPI_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT8 InStride; + UINT8 OutStride; + EFI_PEI_CPU_IO_PPI_WIDTH OperationWidth; + BOOLEAN Aligned; + UINT8 *Uint8Buffer; + + // + // Make sure the parameters are valid + // + Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Select loop based on the width of the transfer + // + InStride = mInStride[Width]; + OutStride = mOutStride[Width]; + OperationWidth = (EFI_PEI_CPU_IO_PPI_WIDTH) (Width & 0x03); + Aligned = (BOOLEAN)(((UINTN)Buffer & (mInStride[OperationWidth] - 1)) == 0x00); + for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { + if (OperationWidth == EfiPeiCpuIoWidthUint8) { + IoWrite8 ((UINTN)Address, *Uint8Buffer); + } else if (OperationWidth == EfiPeiCpuIoWidthUint16) { + if (Aligned) { + IoWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer)); + } else { + IoWrite16 ((UINTN)Address, ReadUnaligned16 ((UINT16 *)Uint8Buffer)); + } + } else if (OperationWidth == EfiPeiCpuIoWidthUint32) { + if (Aligned) { + IoWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer)); + } else { + IoWrite32 ((UINTN)Address, ReadUnaligned32 ((UINT32 *)Uint8Buffer)); + } + } + } + + return EFI_SUCCESS; +} + +/** + 8-bit I/O read operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + + @return An 8-bit value returned from the I/O space. +**/ +UINT8 +EFIAPI +CpuIoRead8 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address + ) +{ + return IoRead8 ((UINTN)Address); +} + +/** + 16-bit I/O read operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + + @return A 16-bit value returned from the I/O space. + +**/ +UINT16 +EFIAPI +CpuIoRead16 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address + ) +{ + return IoRead16 ((UINTN)Address); +} + +/** + 32-bit I/O read operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + + @return A 32-bit value returned from the I/O space. + +**/ +UINT32 +EFIAPI +CpuIoRead32 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address + ) +{ + return IoRead32 ((UINTN)Address); +} + +/** + 64-bit I/O read operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + + @return A 64-bit value returned from the I/O space. + +**/ +UINT64 +EFIAPI +CpuIoRead64 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address + ) +{ + return IoRead64 ((UINTN)Address); +} + +/** + 8-bit I/O write operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + @param[in] Data The data to write. + +**/ +VOID +EFIAPI +CpuIoWrite8 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address, + IN UINT8 Data + ) +{ + IoWrite8 ((UINTN)Address, Data); +} + +/** + 16-bit I/O write operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + @param[in] Data The data to write. + +**/ +VOID +EFIAPI +CpuIoWrite16 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address, + IN UINT16 Data + ) +{ + IoWrite16 ((UINTN)Address, Data); +} + +/** + 32-bit I/O write operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + @param[in] Data The data to write. + +**/ +VOID +EFIAPI +CpuIoWrite32 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address, + IN UINT32 Data + ) +{ + IoWrite32 ((UINTN)Address, Data); +} + +/** + 64-bit I/O write operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + @param[in] Data The data to write. + +**/ +VOID +EFIAPI +CpuIoWrite64 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address, + IN UINT64 Data + ) +{ + IoWrite64 ((UINTN)Address, Data); +} + +/** + 8-bit memory read operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + + @return An 8-bit value returned from the memory space. + +**/ +UINT8 +EFIAPI +CpuMemRead8 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address + ) +{ + return MmioRead8 ((UINTN)Address); +} + +/** + 16-bit memory read operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + + @return A 16-bit value returned from the memory space. + +**/ +UINT16 +EFIAPI +CpuMemRead16 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address + ) +{ + return MmioRead16 ((UINTN)Address); +} + +/** + 32-bit memory read operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + + @return A 32-bit value returned from the memory space. + +**/ +UINT32 +EFIAPI +CpuMemRead32 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address + ) +{ + return MmioRead32 ((UINTN)Address); +} + +/** + 64-bit memory read operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + + @return A 64-bit value returned from the memory space. + +**/ +UINT64 +EFIAPI +CpuMemRead64 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address + ) +{ + return MmioRead64 ((UINTN)Address); +} + +/** + 8-bit memory write operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + @param[in] Data The data to write. + +**/ +VOID +EFIAPI +CpuMemWrite8 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address, + IN UINT8 Data + ) +{ + MmioWrite8 ((UINTN)Address, Data); +} + +/** + 16-bit memory write operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + @param[in] Data The data to write. + +**/ +VOID +EFIAPI +CpuMemWrite16 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address, + IN UINT16 Data + ) +{ + MmioWrite16 ((UINTN)Address, Data); +} + +/** + 32-bit memory write operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + @param[in] Data The data to write. + +**/ +VOID +EFIAPI +CpuMemWrite32 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address, + IN UINT32 Data + ) +{ + MmioWrite32 ((UINTN)Address, Data); +} + +/** + 64-bit memory write operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + @param[in] Data The data to write. + +**/ +VOID +EFIAPI +CpuMemWrite64 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address, + IN UINT64 Data + ) +{ + MmioWrite64 ((UINTN)Address, Data); +} + +/** + The Entry point of the CPU I/O PEIM + + This function is the Entry point of the CPU I/O PEIM which installs CpuIoPpi. + + @param[in] FileHandle Pointer to image file handle. + @param[in] PeiServices Pointer to PEI Services Table + + @retval EFI_SUCCESS CPU I/O PPI successfully installed + +**/ +EFI_STATUS +EFIAPI +CpuIoInitialize ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + + // + // Register so it will be automatically shadowed to memory + // + Status = PeiServicesRegisterForShadow (FileHandle); + + // + // Make CpuIo pointer in PeiService table point to gCpuIoPpi + // + (*((EFI_PEI_SERVICES **)PeiServices))->CpuIo = &gCpuIoPpi; + + if (Status == EFI_ALREADY_STARTED) { + // + // Shadow completed and running from memory + // + // DEBUG ((EFI_D_INFO, "CpuIO PPI has been loaded into memory. Reinstalled PPI=0x%x\n", &gCpuIoPpi)); + } else { + Status = PeiServicesInstallPpi (&gPpiList); + ASSERT_EFI_ERROR (Status); + } + + return EFI_SUCCESS; +} diff --git a/CloverEFI/UefiCpuPkg/CpuIoPei/CpuIoPei.h b/CloverEFI/UefiCpuPkg/CpuIoPei/CpuIoPei.h new file mode 100755 index 0000000000..052f0e3d0e --- /dev/null +++ b/CloverEFI/UefiCpuPkg/CpuIoPei/CpuIoPei.h @@ -0,0 +1,448 @@ +/** @file + Internal include file for the CPU I/O PPI. + +Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _CPU_IO2_PEI_H_ +#define _CPU_IO2_PEI_H_ + +#include + +#include + +#include +#include +#include +#include + +#define MAX_IO_PORT_ADDRESS 0xFFFF + +/** + Reads memory-mapped registers. + + @param[in] PeiServices An indirect pointer to the PEI Services Table + published by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Width The width of the access. Enumerated in bytes. + @param[in] Address The physical address of the access. + @param[in] Count The number of accesses to perform. + @param[out] Buffer A pointer to the buffer of data. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this EFI system. + +**/ +EFI_STATUS +EFIAPI +CpuMemoryServiceRead ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN EFI_PEI_CPU_IO_PPI_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ); + +/** + Writes memory-mapped registers. + + @param[in] PeiServices An indirect pointer to the PEI Services Table + published by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Width The width of the access. Enumerated in bytes. + @param[in] Address The physical address of the access. + @param[in] Count The number of accesses to perform. + @param[in] Buffer A pointer to the buffer of data. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this EFI system. + +**/ +EFI_STATUS +EFIAPI +CpuMemoryServiceWrite ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN EFI_PEI_CPU_IO_PPI_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ); + +/** + Reads I/O registers. + + @param[in] PeiServices An indirect pointer to the PEI Services Table + published by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Width The width of the access. Enumerated in bytes. + @param[in] Address The physical address of the access. + @param[in] Count The number of accesses to perform. + @param[out] Buffer A pointer to the buffer of data. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this EFI system. + +**/ +EFI_STATUS +EFIAPI +CpuIoServiceRead ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN EFI_PEI_CPU_IO_PPI_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ); + +/** + Write I/O registers. + + @param[in] PeiServices An indirect pointer to the PEI Services Table + published by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Width The width of the access. Enumerated in bytes. + @param[in] Address The physical address of the access. + @param[in] Count The number of accesses to perform. + @param[in] Buffer A pointer to the buffer of data. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this EFI system. + +**/ +EFI_STATUS +EFIAPI +CpuIoServiceWrite ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN EFI_PEI_CPU_IO_PPI_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ); + +/** + 8-bit I/O read operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + + @return An 8-bit value returned from the I/O space. +**/ +UINT8 +EFIAPI +CpuIoRead8 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address + ); + +/** + 16-bit I/O read operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + + @return A 16-bit value returned from the I/O space. + +**/ +UINT16 +EFIAPI +CpuIoRead16 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address + ); + +/** + 32-bit I/O read operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + + @return A 32-bit value returned from the I/O space. + +**/ +UINT32 +EFIAPI +CpuIoRead32 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address + ); + +/** + 64-bit I/O read operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + + @return A 64-bit value returned from the I/O space. + +**/ +UINT64 +EFIAPI +CpuIoRead64 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address + ); + +/** + 8-bit I/O write operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + @param[in] Data The data to write. + +**/ +VOID +EFIAPI +CpuIoWrite8 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address, + IN UINT8 Data + ); + +/** + 16-bit I/O write operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + @param[in] Data The data to write. + +**/ +VOID +EFIAPI +CpuIoWrite16 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address, + IN UINT16 Data + ); + +/** + 32-bit I/O write operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + @param[in] Data The data to write. + +**/ +VOID +EFIAPI +CpuIoWrite32 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address, + IN UINT32 Data + ); + +/** + 64-bit I/O write operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + @param[in] Data The data to write. + +**/ +VOID +EFIAPI +CpuIoWrite64 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address, + IN UINT64 Data + ); + +/** + 8-bit memory read operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + + @return An 8-bit value returned from the memory space. + +**/ +UINT8 +EFIAPI +CpuMemRead8 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address + ); + +/** + 16-bit memory read operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + + @return A 16-bit value returned from the memory space. + +**/ +UINT16 +EFIAPI +CpuMemRead16 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address + ); + +/** + 32-bit memory read operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + + @return A 32-bit value returned from the memory space. + +**/ +UINT32 +EFIAPI +CpuMemRead32 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address + ); + +/** + 64-bit memory read operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + + @return A 64-bit value returned from the memory space. + +**/ +UINT64 +EFIAPI +CpuMemRead64 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address + ); + +/** + 8-bit memory write operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + @param[in] Data The data to write. + +**/ +VOID +EFIAPI +CpuMemWrite8 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address, + IN UINT8 Data + ); + +/** + 16-bit memory write operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + @param[in] Data The data to write. + +**/ +VOID +EFIAPI +CpuMemWrite16 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address, + IN UINT16 Data + ); + +/** + 32-bit memory write operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + @param[in] Data The data to write. + +**/ +VOID +EFIAPI +CpuMemWrite32 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address, + IN UINT32 Data + ); + +/** + 64-bit memory write operations. + + @param[in] PeiServices An indirect pointer to the PEI Services Table published + by the PEI Foundation. + @param[in] This Pointer to local data for the interface. + @param[in] Address The physical address of the access. + @param[in] Data The data to write. + +**/ +VOID +EFIAPI +CpuMemWrite64 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_CPU_IO_PPI *This, + IN UINT64 Address, + IN UINT64 Data + ); + +#endif diff --git a/CloverEFI/UefiCpuPkg/CpuIoPei/CpuIoPei.inf b/CloverEFI/UefiCpuPkg/CpuIoPei/CpuIoPei.inf new file mode 100755 index 0000000000..4ebd9e2fb1 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/CpuIoPei/CpuIoPei.inf @@ -0,0 +1,49 @@ +## @file +# Produces the CPU I/O PPI. +# +# This PEIM produces of the CPU I/O PPI. +# +# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = CpuIoPei + FILE_GUID = AE265864-CF5D-41a8-913D-71C155E76442 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = CpuIoInitialize + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + CpuIoPei.c + CpuIoPei.h + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + PeimEntryPoint + BaseLib + DebugLib + IoLib + PeiServicesLib + +[Ppis] + gEfiPeiCpuIoPpiInstalledGuid # PPI ALWAYS_PRODUCED + +[Depex] + TRUE diff --git a/CloverEFI/UefiCpuPkg/Include/Library/LocalApicLib.h b/CloverEFI/UefiCpuPkg/Include/Library/LocalApicLib.h new file mode 100755 index 0000000000..52914fa9bd --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Include/Library/LocalApicLib.h @@ -0,0 +1,372 @@ +/** @file + Public include file for Local APIC library. + + Local APIC library assumes local APIC is enabled. It does not + handles cases where local APIC is disabled. + + Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __LOCAL_APIC_LIB_H__ +#define __LOCAL_APIC_LIB_H__ + +#define LOCAL_APIC_MODE_XAPIC 0x1 ///< xAPIC mode. +#define LOCAL_APIC_MODE_X2APIC 0x2 ///< x2APIC mode. + +/** + Get the current local APIC mode. + + If local APIC is disabled, then ASSERT. + + @retval LOCAL_APIC_MODE_XAPIC current APIC mode is xAPIC. + @retval LOCAL_APIC_MODE_X2APIC current APIC mode is x2APIC. +**/ +UINTN +EFIAPI +GetApicMode ( + VOID + ); + +/** + Set the current local APIC mode. + + If the specified local APIC mode is not valid, then ASSERT. + If the specified local APIC mode can't be set as current, then ASSERT. + + @param ApicMode APIC mode to be set. +**/ +VOID +EFIAPI +SetApicMode ( + IN UINTN ApicMode + ); + +/** + Get the initial local APIC ID of the executing processor assigned by hardware upon power on or reset. + + In xAPIC mode, the initial local APIC ID is 8-bit, and may be different from current APIC ID. + In x2APIC mode, the local APIC ID can't be changed and there is no concept of initial APIC ID. In this case, + the 32-bit local APIC ID is returned as initial APIC ID. + + @return 32-bit initial local APIC ID of the executing processor. +**/ +UINT32 +EFIAPI +GetInitialApicId ( + VOID + ); + +/** + Get the local APIC ID of the executing processor. + + @return 32-bit local APIC ID of the executing processor. +**/ +UINT32 +EFIAPI +GetApicId ( + VOID + ); + +/** + Get the value of the local APIC version register. + + @return the value of the local APIC version register. +**/ +UINT32 +EFIAPI +GetApicVersion ( + VOID + ); + +/** + Send a Fixed IPI to a specified target processor. + + This function returns after the IPI has been accepted by the target processor. + + @param ApicId The local APIC ID of the target processor. + @param Vector The vector number of the interrupt being sent. +**/ +VOID +EFIAPI +SendFixedIpi ( + IN UINT32 ApicId, + IN UINT8 Vector + ); + +/** + Send a Fixed IPI to all processors excluding self. + + This function returns after the IPI has been accepted by the target processors. + + @param Vector The vector number of the interrupt being sent. +**/ +VOID +EFIAPI +SendFixedIpiAllExcludingSelf ( + IN UINT8 Vector + ); + +/** + Send a SMI IPI to a specified target processor. + + This function returns after the IPI has been accepted by the target processor. + + @param ApicId Specify the local APIC ID of the target processor. +**/ +VOID +EFIAPI +SendSmiIpi ( + IN UINT32 ApicId + ); + +/** + Send a SMI IPI to all processors excluding self. + + This function returns after the IPI has been accepted by the target processors. +**/ +VOID +EFIAPI +SendSmiIpiAllExcludingSelf ( + VOID + ); + +/** + Send an INIT IPI to a specified target processor. + + This function returns after the IPI has been accepted by the target processor. + + @param ApicId Specify the local APIC ID of the target processor. +**/ +VOID +EFIAPI +SendInitIpi ( + IN UINT32 ApicId + ); + +/** + Send an INIT IPI to all processors excluding self. + + This function returns after the IPI has been accepted by the target processors. +**/ +VOID +EFIAPI +SendInitIpiAllExcludingSelf ( + VOID + ); + +/** + Send an INIT-Start-up-Start-up IPI sequence to a specified target processor. + + This function returns after the IPI has been accepted by the target processor. + + if StartupRoutine >= 1M, then ASSERT. + if StartupRoutine is not multiple of 4K, then ASSERT. + + @param ApicId Specify the local APIC ID of the target processor. + @param StartupRoutine Points to a start-up routine which is below 1M physical + address and 4K aligned. +**/ +VOID +EFIAPI +SendInitSipiSipi ( + IN UINT32 ApicId, + IN UINT32 StartupRoutine + ); + +/** + Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self. + + This function returns after the IPI has been accepted by the target processors. + + if StartupRoutine >= 1M, then ASSERT. + if StartupRoutine is not multiple of 4K, then ASSERT. + + @param StartupRoutine Points to a start-up routine which is below 1M physical + address and 4K aligned. +**/ +VOID +EFIAPI +SendInitSipiSipiAllExcludingSelf ( + IN UINT32 StartupRoutine + ); + +/** + Programming Virtual Wire Mode. + + This function programs the local APIC for virtual wire mode following + the example described in chapter A.3 of the MP 1.4 spec. + + IOxAPIC is not involved in this type of virtual wire mode. +**/ +VOID +EFIAPI +ProgramVirtualWireMode ( + VOID + ); + +/** + Disable LINT0 & LINT1 interrupts. + + This function sets the mask flag in the LVT LINT0 & LINT1 registers. +**/ +VOID +EFIAPI +DisableLvtInterrupts ( + VOID + ); + +/** + Read the initial count value from the init-count register. + + @return The initial count value read from the init-count register. +**/ +UINT32 +EFIAPI +GetApicTimerInitCount ( + VOID + ); + +/** + Read the current count value from the current-count register. + + @return The current count value read from the current-count register. +**/ +UINT32 +EFIAPI +GetApicTimerCurrentCount ( + VOID + ); + +/** + Initialize the local APIC timer. + + The local APIC timer is initialized and enabled. + + @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128. + If it is 0, then use the current divide value in the DCR. + @param InitCount The initial count value. + @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot. + @param Vector The timer interrupt vector number. +**/ +VOID +EFIAPI +InitializeApicTimer ( + IN UINTN DivideValue, + IN UINT32 InitCount, + IN BOOLEAN PeriodicMode, + IN UINT8 Vector + ); + +/** + Get the state of the local APIC timer. + + @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128. + @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot. + @param Vector Return the timer interrupt vector number. +**/ +VOID +EFIAPI +GetApicTimerState ( + OUT UINTN *DivideValue OPTIONAL, + OUT BOOLEAN *PeriodicMode OPTIONAL, + OUT UINT8 *Vector OPTIONAL + ); + +/** + Enable the local APIC timer interrupt. +**/ +VOID +EFIAPI +EnableApicTimerInterrupt ( + VOID + ); + +/** + Disable the local APIC timer interrupt. +**/ +VOID +EFIAPI +DisableApicTimerInterrupt ( + VOID + ); + +/** + Get the local APIC timer interrupt state. + + @retval TRUE The local APIC timer interrupt is enabled. + @retval FALSE The local APIC timer interrupt is disabled. +**/ +BOOLEAN +EFIAPI +GetApicTimerInterruptState ( + VOID + ); + +/** + Send EOI to the local APIC. +**/ +VOID +EFIAPI +SendApicEoi ( + VOID + ); + +/** + Get the 32-bit address that a device should use to send a Message Signaled + Interrupt (MSI) to the Local APIC of the currently executing processor. + + @return 32-bit address used to send an MSI to the Local APIC. +**/ +UINT32 +EFIAPI +GetApicMsiAddress ( + VOID + ); + +/** + Get the 64-bit data value that a device should use to send a Message Signaled + Interrupt (MSI) to the Local APIC of the currently executing processor. + + If Vector is not in range 0x10..0xFE, then ASSERT(). + If DeliveryMode is not supported, then ASSERT(). + + @param Vector The 8-bit interrupt vector associated with the MSI. + Must be in the range 0x10..0xFE + @param DeliveryMode A 3-bit value that specifies how the recept of the MSI + is handled. The only supported values are: + 0: LOCAL_APIC_DELIVERY_MODE_FIXED + 1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY + 2: LOCAL_APIC_DELIVERY_MODE_SMI + 4: LOCAL_APIC_DELIVERY_MODE_NMI + 5: LOCAL_APIC_DELIVERY_MODE_INIT + 7: LOCAL_APIC_DELIVERY_MODE_EXTINT + + @param LevelTriggered TRUE specifies a level triggered interrupt. + FALSE specifies an edge triggered interrupt. + @param AssertionLevel Ignored if LevelTriggered is FALSE. + TRUE specifies a level triggered interrupt that active + when the interrupt line is asserted. + FALSE specifies a level triggered interrupt that active + when the interrupt line is deasserted. + + @return 64-bit data value used to send an MSI to the Local APIC. +**/ +UINT64 +EFIAPI +GetApicMsiValue ( + IN UINT8 Vector, + IN UINTN DeliveryMode, + IN BOOLEAN LevelTriggered, + IN BOOLEAN AssertionLevel + ); + +#endif + diff --git a/CloverEFI/UefiCpuPkg/Include/Library/MtrrLib.h b/CloverEFI/UefiCpuPkg/Include/Library/MtrrLib.h new file mode 100755 index 0000000000..d24f10f36b --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Include/Library/MtrrLib.h @@ -0,0 +1,334 @@ +/** @file + MTRR setting library + + Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _MTRR_LIB_H_ +#define _MTRR_LIB_H_ + +// +// According to IA32 SDM, MTRRs number and msr offset are always consistent +// for IA32 processor family +// + +// +// The semantics of below macro is MAX_MTRR_NUMBER_OF_VARIABLE_MTRR, the real number can be read out from MTRR_CAP register. +// +#define MTRR_NUMBER_OF_VARIABLE_MTRR 32 +// +// Firmware need reserve 2 MTRR for OS +// +#define RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER 2 + +#define MTRR_NUMBER_OF_FIXED_MTRR 11 +// +// Below macro is deprecated, and should not be used. +// +#define FIRMWARE_VARIABLE_MTRR_NUMBER 6 +#define MTRR_LIB_IA32_MTRR_CAP 0x0FE +#define MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK 0x0FF +#define MTRR_LIB_IA32_MTRR_FIX64K_00000 0x250 +#define MTRR_LIB_IA32_MTRR_FIX16K_80000 0x258 +#define MTRR_LIB_IA32_MTRR_FIX16K_A0000 0x259 +#define MTRR_LIB_IA32_MTRR_FIX4K_C0000 0x268 +#define MTRR_LIB_IA32_MTRR_FIX4K_C8000 0x269 +#define MTRR_LIB_IA32_MTRR_FIX4K_D0000 0x26A +#define MTRR_LIB_IA32_MTRR_FIX4K_D8000 0x26B +#define MTRR_LIB_IA32_MTRR_FIX4K_E0000 0x26C +#define MTRR_LIB_IA32_MTRR_FIX4K_E8000 0x26D +#define MTRR_LIB_IA32_MTRR_FIX4K_F0000 0x26E +#define MTRR_LIB_IA32_MTRR_FIX4K_F8000 0x26F +#define MTRR_LIB_IA32_VARIABLE_MTRR_BASE 0x200 +// +// Below macro is deprecated, and should not be used. +// +#define MTRR_LIB_IA32_VARIABLE_MTRR_END 0x20F +#define MTRR_LIB_IA32_MTRR_DEF_TYPE 0x2FF +#define MTRR_LIB_MSR_VALID_MASK 0xFFFFFFFFFULL +#define MTRR_LIB_CACHE_VALID_ADDRESS 0xFFFFFF000ULL +#define MTRR_LIB_CACHE_MTRR_ENABLED 0x800 +#define MTRR_LIB_CACHE_FIXED_MTRR_ENABLED 0x400 + +// +// Structure to describe a fixed MTRR +// +typedef struct { + UINT32 Msr; + UINT32 BaseAddress; + UINT32 Length; +} FIXED_MTRR; + +// +// Structure to describe a variable MTRR +// +typedef struct { + UINT64 BaseAddress; + UINT64 Length; + UINT64 Type; + UINT32 Msr; + BOOLEAN Valid; + BOOLEAN Used; +} VARIABLE_MTRR; + +// +// Structure to hold base and mask pair for variable MTRR register +// +typedef struct _MTRR_VARIABLE_SETTING_ { + UINT64 Base; + UINT64 Mask; +} MTRR_VARIABLE_SETTING; + +// +// Array for variable MTRRs +// +typedef struct _MTRR_VARIABLE_SETTINGS_ { + MTRR_VARIABLE_SETTING Mtrr[MTRR_NUMBER_OF_VARIABLE_MTRR]; +} MTRR_VARIABLE_SETTINGS; + +// +// Array for fixed mtrrs +// +typedef struct _MTRR_FIXED_SETTINGS_ { + UINT64 Mtrr[MTRR_NUMBER_OF_FIXED_MTRR]; +} MTRR_FIXED_SETTINGS; + +// +// Structure to hold all MTRRs +// +typedef struct _MTRR_SETTINGS_ { + MTRR_FIXED_SETTINGS Fixed; + MTRR_VARIABLE_SETTINGS Variables; + UINT64 MtrrDefType; +} MTRR_SETTINGS; + +// +// Memory cache types +// +typedef enum { + CacheUncacheable = 0, + CacheWriteCombining = 1, + CacheWriteThrough = 4, + CacheWriteProtected = 5, + CacheWriteBack = 6 +} MTRR_MEMORY_CACHE_TYPE; + +#define MTRR_CACHE_UNCACHEABLE 0 +#define MTRR_CACHE_WRITE_COMBINING 1 +#define MTRR_CACHE_WRITE_THROUGH 4 +#define MTRR_CACHE_WRITE_PROTECTED 5 +#define MTRR_CACHE_WRITE_BACK 6 +#define MTRR_CACHE_INVALID_TYPE 7 + +/** + Returns the variable MTRR count for the CPU. + + @return Variable MTRR count + +**/ +UINT32 +EFIAPI +GetVariableMtrrCount ( + VOID + ); + +/** + Returns the firmware usable variable MTRR count for the CPU. + + @return Firmware usable variable MTRR count + +**/ +UINT32 +EFIAPI +GetFirmwareVariableMtrrCount ( + VOID + ); + +/** + This function attempts to set the attributes for a memory range. + + @param BaseAddress The physical address that is the start address of a memory region. + @param Length The size in bytes of the memory region. + @param Attributes The bit mask of attributes to set for the memory region. + + @retval RETURN_SUCCESS The attributes were set for the memory region. + @retval RETURN_INVALID_PARAMETER Length is zero. + @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the + memory resource range specified by BaseAddress and Length. + @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource + range specified by BaseAddress and Length. + @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by + BaseAddress and Length cannot be modified. + @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of + the memory resource range. + +**/ +RETURN_STATUS +EFIAPI +MtrrSetMemoryAttribute ( + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN MTRR_MEMORY_CACHE_TYPE Attribute + ); + + +/** + This function will get the memory cache type of the specific address. + This function is mainly for debugging purposes. + + @param Address The specific address + + @return The memory cache type of the specific address + +**/ +MTRR_MEMORY_CACHE_TYPE +EFIAPI +MtrrGetMemoryAttribute ( + IN PHYSICAL_ADDRESS Address + ); + + +/** + This function will get the raw value in variable MTRRs + + @param VariableSettings A buffer to hold variable MTRRs content. + + @return The buffer point to MTRR_VARIABLE_SETTINGS in which holds the content of the variable mtrr + +**/ +MTRR_VARIABLE_SETTINGS* +EFIAPI +MtrrGetVariableMtrr ( + OUT MTRR_VARIABLE_SETTINGS *VariableSettings + ); + + +/** + This function sets fixed MTRRs + + @param VariableSettings A buffer to hold variable MTRRs content. + + @return The pointer of VariableSettings + +**/ +MTRR_VARIABLE_SETTINGS* +EFIAPI +MtrrSetVariableMtrr ( + IN MTRR_VARIABLE_SETTINGS *VariableSettings + ); + + +/** + This function gets the content in fixed MTRRs + + @param FixedSettings A buffer to hold fixed MTRRs content. + + @return The pointer of FixedSettings + +**/ +MTRR_FIXED_SETTINGS* +EFIAPI +MtrrGetFixedMtrr ( + OUT MTRR_FIXED_SETTINGS *FixedSettings + ); + + +/** + This function sets fixed MTRRs + + @param FixedSettings A buffer holding fixed MTRRs content. + + @return The pointer of FixedSettings + +**/ +MTRR_FIXED_SETTINGS* +EFIAPI +MtrrSetFixedMtrr ( + IN MTRR_FIXED_SETTINGS *FixedSettings + ); + + +/** + This function gets the content in all MTRRs (variable and fixed) + + @param MtrrSetting A buffer to hold all MTRRs content. + + @return The pointer of MtrrSetting + +**/ +MTRR_SETTINGS * +EFIAPI +MtrrGetAllMtrrs ( + OUT MTRR_SETTINGS *MtrrSetting + ); + + +/** + This function sets all MTRRs (variable and fixed) + + @param MtrrSetting A buffer to hold all MTRRs content. + + @return The pointer of MtrrSetting + +**/ +MTRR_SETTINGS * +EFIAPI +MtrrSetAllMtrrs ( + IN MTRR_SETTINGS *MtrrSetting + ); + + +/** + Get the attribute of variable MTRRs. + + This function shadows the content of variable MTRRs into + an internal array: VariableMtrr + + @param MtrrValidBitsMask The mask for the valid bit of the MTRR + @param MtrrValidAddressMask The valid address mask for MTRR since the base address in + MTRR must align to 4K, so valid address mask equal to + MtrrValidBitsMask & 0xfffffffffffff000ULL + @param VariableMtrr The array to shadow variable MTRRs content + @return The ruturn value of this paramter indicates the number of + MTRRs which has been used. +**/ +UINT32 +EFIAPI +MtrrGetMemoryAttributeInVariableMtrr ( + IN UINT64 MtrrValidBitsMask, + IN UINT64 MtrrValidAddressMask, + OUT VARIABLE_MTRR *VariableMtrr + ); + + +/** + This function prints all MTRRs for debugging. +**/ +VOID +EFIAPI +MtrrDebugPrintAllMtrrs ( + VOID + ); + +/** + Checks if MTRR is supported. + + @retval TRUE MTRR is supported. + @retval FALSE MTRR is not supported. + +**/ +BOOLEAN +EFIAPI +IsMtrrSupported ( + VOID + ); + +#endif // _MTRR_LIB_H_ diff --git a/CloverEFI/UefiCpuPkg/Include/Library/UefiCpuLib.h b/CloverEFI/UefiCpuPkg/Include/Library/UefiCpuLib.h new file mode 100755 index 0000000000..561d579968 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Include/Library/UefiCpuLib.h @@ -0,0 +1,38 @@ +/** @file + Public header file for UEFI CPU library class. + + This library class defines some routines that are generic for IA32 family CPU + to be UEFI specification compliant. + + Copyright (c) 2009, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __UEFI_CPU_LIB_H__ +#define __UEFI_CPU_LIB_H__ + + + +/** + Initializes floating point units for requirement of UEFI specification. + + This function initializes floating-point control word to 0x027F (all exceptions + masked,double-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). + +**/ +VOID +EFIAPI +InitializeFloatingPointUnits ( + VOID + ); + +#endif diff --git a/CloverEFI/UefiCpuPkg/Include/Register/LocalApic.h b/CloverEFI/UefiCpuPkg/Include/Register/LocalApic.h new file mode 100755 index 0000000000..bb0e211dc7 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Include/Register/LocalApic.h @@ -0,0 +1,214 @@ +/** @file + IA32 Local APIC Definitions. + + Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __LOCAL_APIC_H__ +#define __LOCAL_APIC_H__ + +// +// Definitions for IA32 architectural MSRs +// +#define MSR_IA32_APIC_BASE_ADDRESS 0x1B + +// +// Definitions for CPUID instruction +// +#define CPUID_VERSION_INFO 0x1 +#define CPUID_EXTENDED_FUNCTION 0x80000000 +#define CPUID_VIR_PHY_ADDRESS_SIZE 0x80000008 + +// +// Definition for Local APIC registers and related values +// +#define XAPIC_ID_OFFSET 0x20 +#define XAPIC_VERSION_OFFSET 0x30 +#define XAPIC_EOI_OFFSET 0x0b0 +#define XAPIC_ICR_DFR_OFFSET 0x0e0 +#define XAPIC_SPURIOUS_VECTOR_OFFSET 0x0f0 +#define XAPIC_ICR_LOW_OFFSET 0x300 +#define XAPIC_ICR_HIGH_OFFSET 0x310 +#define XAPIC_LVT_TIMER_OFFSET 0x320 +#define XAPIC_LVT_LINT0_OFFSET 0x350 +#define XAPIC_LVT_LINT1_OFFSET 0x360 +#define XAPIC_TIMER_INIT_COUNT_OFFSET 0x380 +#define XAPIC_TIMER_CURRENT_COUNT_OFFSET 0x390 +#define XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET 0x3E0 + +#define X2APIC_MSR_BASE_ADDRESS 0x800 +#define X2APIC_MSR_ICR_ADDRESS 0x830 + +#define LOCAL_APIC_DELIVERY_MODE_FIXED 0 +#define LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY 1 +#define LOCAL_APIC_DELIVERY_MODE_SMI 2 +#define LOCAL_APIC_DELIVERY_MODE_NMI 4 +#define LOCAL_APIC_DELIVERY_MODE_INIT 5 +#define LOCAL_APIC_DELIVERY_MODE_STARTUP 6 +#define LOCAL_APIC_DELIVERY_MODE_EXTINT 7 + +#define LOCAL_APIC_DESTINATION_SHORTHAND_NO_SHORTHAND 0 +#define LOCAL_APIC_DESTINATION_SHORTHAND_SELF 1 +#define LOCAL_APIC_DESTINATION_SHORTHAND_ALL_INCLUDING_SELF 2 +#define LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF 3 + +typedef union { + struct { + UINT32 Reserved0:8; ///< Reserved. + UINT32 Bsp:1; ///< Processor is BSP. + UINT32 Reserved1:1; ///< Reserved. + UINT32 Extd:1; ///< Enable x2APIC mode. + UINT32 En:1; ///< xAPIC global enable/disable. + UINT32 ApicBaseLow:20; ///< APIC Base physical address. The actual field width depends on physical address width. + UINT32 ApicBaseHigh:32; + } Bits; + UINT64 Uint64; +} MSR_IA32_APIC_BASE; + +// +// Local APIC Version Register. +// +typedef union { + struct { + UINT32 Version:8; ///< The version numbers of the local APIC. + UINT32 Reserved0:8; ///< Reserved. + UINT32 MaxLvtEntry:8; ///< Number of LVT entries minus 1. + UINT32 EoiBroadcastSuppression:1; ///< 1 if EOI-broadcast suppression supported. + UINT32 Reserved1:7; ///< Reserved. + } Bits; + UINT32 Uint32; +} LOCAL_APIC_VERSION; + +// +// Low half of Interrupt Command Register (ICR). +// +typedef union { + struct { + UINT32 Vector:8; ///< The vector number of the interrupt being sent. + UINT32 DeliveryMode:3; ///< Specifies the type of IPI to be sent. + UINT32 DestinationMode:1; ///< 0: physical destination mode, 1: logical destination mode. + UINT32 DeliveryStatus:1; ///< Indicates the IPI delivery status. This field is reserved in x2APIC mode. + UINT32 Reserved0:1; ///< Reserved. + UINT32 Level:1; ///< 0 for the INIT level de-assert delivery mode. Otherwise 1. + UINT32 TriggerMode:1; ///< 0: edge, 1: level when using the INIT level de-assert delivery mode. + UINT32 Reserved1:2; ///< Reserved. + UINT32 DestinationShorthand:2; ///< A shorthand notation to specify the destination of the interrupt. + UINT32 Reserved2:12; ///< Reserved. + } Bits; + UINT32 Uint32; +} LOCAL_APIC_ICR_LOW; + +// +// High half of Interrupt Command Register (ICR) +// +typedef union { + struct { + UINT32 Reserved0:24; ///< Reserved. + UINT32 Destination:8; ///< Specifies the target processor or processors in xAPIC mode. + } Bits; + UINT32 Uint32; ///< Destination field expanded to 32-bit in x2APIC mode. +} LOCAL_APIC_ICR_HIGH; + +// +// Spurious-Interrupt Vector Register (SVR) +// +typedef union { + struct { + UINT32 SpuriousVector:8; ///< Spurious Vector. + UINT32 SoftwareEnable:1; ///< APIC Software Enable/Disable. + UINT32 FocusProcessorChecking:1; ///< Focus Processor Checking. + UINT32 Reserved0:2; ///< Reserved. + UINT32 EoiBroadcastSuppression:1; ///< EOI-Broadcast Suppression. + UINT32 Reserved1:19; ///< Reserved. + } Bits; + UINT32 Uint32; +} LOCAL_APIC_SVR; + +// +// Divide Configuration Register (DCR) +// +typedef union { + struct { + UINT32 DivideValue1:2; ///< Low 2 bits of the divide value. + UINT32 Reserved0:1; ///< Always 0. + UINT32 DivideValue2:1; ///< Highest 1 bit of the divide value. + UINT32 Reserved1:28; ///< Reserved. + } Bits; + UINT32 Uint32; +} LOCAL_APIC_DCR; + +// +// LVT Timer Register +// +typedef union { + struct { + UINT32 Vector:8; ///< The vector number of the interrupt being sent. + UINT32 Reserved0:4; ///< Reserved. + UINT32 DeliveryStatus:1; ///< 0: Idle, 1: send pending. + UINT32 Reserved1:3; ///< Reserved. + UINT32 Mask:1; ///< 0: Not masked, 1: Masked. + UINT32 TimerMode:1; ///< 0: One-shot, 1: Periodic. + UINT32 Reserved2:14; ///< Reserved. + } Bits; + UINT32 Uint32; +} LOCAL_APIC_LVT_TIMER; + +// +// LVT LINT0/LINT1 Register +// +typedef union { + struct { + UINT32 Vector:8; ///< The vector number of the interrupt being sent. + UINT32 DeliveryMode:3; ///< Specifies the type of interrupt to be sent. + UINT32 Reserved0:1; ///< Reserved. + UINT32 DeliveryStatus:1; ///< 0: Idle, 1: send pending. + UINT32 InputPinPolarity:1; ///< Interrupt Input Pin Polarity. + UINT32 RemoteIrr:1; ///< RO. Set when the local APIC accepts the interrupt and reset when an EOI is received. + UINT32 TriggerMode:1; ///< 0:edge, 1:level. + UINT32 Mask:1; ///< 0: Not masked, 1: Masked. + UINT32 Reserved1:15; ///< Reserved. + } Bits; + UINT32 Uint32; +} LOCAL_APIC_LVT_LINT; + +// +// MSI Address Register +// +typedef union { + struct { + UINT32 Reserved0:2; ///< Reserved + UINT32 DestinationMode:1; ///< Specifies the Destination Mode. + UINT32 RedirectionHint:1; ///< Specifies the Redirection Hint. + UINT32 Reserved1:8; ///< Reserved. + UINT32 DestinationId:8; ///< Specifies the Destination ID. + UINT32 BaseAddress:12; ///< Must be 0FEEH + } Bits; + UINT32 Uint32; +} LOCAL_APIC_MSI_ADDRESS; + +// +// MSI Address Register +// +typedef union { + struct { + UINT32 Vector:8; ///< Interrupt vector in range 010h..0FEH + UINT32 DeliveryMode:3; ///< Specifies the type of interrupt to be sent. + UINT32 Reserved0:3; ///< Reserved. + UINT32 Level:1; ///< 0:Deassert, 1:Assert. Ignored for Edge triggered interrupts. + UINT32 TriggerMode:1; ///< 0:Edge, 1:Level. + UINT32 Reserved1:16; ///< Reserved. + UINT32 Reserved2:32; ///< Reserved. + } Bits; + UINT64 Uint64; +} LOCAL_APIC_MSI_DATA; + +#endif + diff --git a/CloverEFI/UefiCpuPkg/Include/Register/Microcode.h b/CloverEFI/UefiCpuPkg/Include/Register/Microcode.h new file mode 100755 index 0000000000..94529a1ca2 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Include/Register/Microcode.h @@ -0,0 +1,200 @@ +/** @file + Microcode Definitions. + + Microcode Definitions based on contents of the + Intel(R) 64 and IA-32 Architectures Software Developer's Manual + Volume 3A, Section 9.11 Microcode Definitions + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Specification Reference: + Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 3A, + June 2016, Chapter 9 Processor Management and Initialization, Section 9-11. + +**/ + +#ifndef __MICROCODE_H__ +#define __MICROCODE_H__ + +/// +/// CPU Microcode Date in BCD format +/// +typedef union { + struct { + UINT32 Year:16; + UINT32 Day:8; + UINT32 Month:8; + } Bits; + UINT32 Uint32; +} CPU_MICROCODE_DATE; + +/// +/// CPU Microcode Processor Signature format +/// +typedef union { + struct { + UINT32 Stepping:4; + UINT32 Model:4; + UINT32 Family:4; + UINT32 Type:2; + UINT32 Reserved1:2; + UINT32 ExtendedModel:4; + UINT32 ExtendedFamily:8; + UINT32 Reserved2:4; + } Bits; + UINT32 Uint32; +} CPU_MICROCODE_PROCESSOR_SIGNATURE; + +#pragma pack (1) + +/// +/// Microcode Update Format definition +/// +typedef struct { + /// + /// Version number of the update header + /// + UINT32 HeaderVersion; + /// + /// Unique version number for the update, the basis for the update + /// signature provided by the processor to indicate the current update + /// functioning within the processor. Used by the BIOS to authenticate + /// the update and verify that the processor loads successfully. The + /// value in this field cannot be used for processor stepping identification + /// alone. This is a signed 32-bit number. + /// + UINT32 UpdateRevision; + /// + /// Date of the update creation in binary format: mmddyyyy (e.g. + /// 07/18/98 is 07181998H). + /// + CPU_MICROCODE_DATE Date; + /// + /// Extended family, extended model, type, family, model, and stepping + /// of processor that requires this particular update revision (e.g., + /// 00000650H). Each microcode update is designed specifically for a + /// given extended family, extended model, type, family, model, and + /// stepping of the processor. + /// The BIOS uses the processor signature field in conjunction with the + /// CPUID instruction to determine whether or not an update is + /// appropriate to load on a processor. The information encoded within + /// this field exactly corresponds to the bit representations returned by + /// the CPUID instruction. + /// + CPU_MICROCODE_PROCESSOR_SIGNATURE ProcessorSignature; + /// + /// Checksum of Update Data and Header. Used to verify the integrity of + /// the update header and data. Checksum is correct when the + /// summation of all the DWORDs (including the extended Processor + /// Signature Table) that comprise the microcode update result in + /// 00000000H. + /// + UINT32 Checksum; + /// + /// Version number of the loader program needed to correctly load this + /// update. The initial version is 00000001H + /// + UINT32 LoaderRevision; + /// + /// Platform type information is encoded in the lower 8 bits of this 4- + /// byte field. Each bit represents a particular platform type for a given + /// CPUID. The BIOS uses the processor flags field in conjunction with + /// the platform Id bits in MSR (17H) to determine whether or not an + /// update is appropriate to load on a processor. Multiple bits may be set + /// representing support for multiple platform IDs. + /// + UINT32 ProcessorFlags; + /// + /// Specifies the size of the encrypted data in bytes, and must be a + /// multiple of DWORDs. If this value is 00000000H, then the microcode + /// update encrypted data is 2000 bytes (or 500 DWORDs). + /// + UINT32 DataSize; + /// + /// Specifies the total size of the microcode update in bytes. It is the + /// summation of the header size, the encrypted data size and the size of + /// the optional extended signature table. This value is always a multiple + /// of 1024. + /// + UINT32 TotalSize; + /// + /// Reserved fields for future expansion. + /// + UINT8 Reserved[12]; +} CPU_MICROCODE_HEADER; + +/// +/// Extended Signature Table Header Field Definitions +/// +typedef struct { + /// + /// Specifies the number of extended signature structures (Processor + /// Signature[n], processor flags[n] and checksum[n]) that exist in this + /// microcode update + /// + UINT32 ExtendedSignatureCount; + /// + /// Checksum of update extended processor signature table. Used to + /// verify the integrity of the extended processor signature table. + /// Checksum is correct when the summation of the DWORDs that + /// comprise the extended processor signature table results in + /// 00000000H. + /// + UINT32 ExtendedChecksum; + /// + /// Reserved fields. + /// + UINT8 Reserved[12]; +} CPU_MICROCODE_EXTENDED_TABLE_HEADER; + +/// +/// Extended Signature Table Field Definitions +/// +typedef struct { + /// + /// Extended family, extended model, type, family, model, and stepping + /// of processor that requires this particular update revision (e.g., + /// 00000650H). Each microcode update is designed specifically for a + /// given extended family, extended model, type, family, model, and + /// stepping of the processor. + /// The BIOS uses the processor signature field in conjunction with the + /// CPUID instruction to determine whether or not an update is + /// appropriate to load on a processor. The information encoded within + /// this field exactly corresponds to the bit representations returned by + /// the CPUID instruction. + /// + CPU_MICROCODE_PROCESSOR_SIGNATURE ProcessorSignature; + /// + /// Platform type information is encoded in the lower 8 bits of this 4- + /// byte field. Each bit represents a particular platform type for a given + /// CPUID. The BIOS uses the processor flags field in conjunction with + /// the platform Id bits in MSR (17H) to determine whether or not an + /// update is appropriate to load on a processor. Multiple bits may be set + /// representing support for multiple platform IDs. + /// + UINT32 ProcessorFlag; + /// + /// Used by utility software to decompose a microcode update into + /// multiple microcode updates where each of the new updates is + /// constructed without the optional Extended Processor Signature + /// Table. + /// To calculate the Checksum, substitute the Primary Processor + /// Signature entry and the Processor Flags entry with the + /// corresponding Extended Patch entry. Delete the Extended Processor + /// Signature Table entries. The Checksum is correct when the + /// summation of all DWORDs that comprise the created Extended + /// Processor Patch results in 00000000H. + /// + UINT32 Checksum; +} CPU_MICROCODE_EXTENDED_TABLE; + +#pragma pack () + +#endif diff --git a/CloverEFI/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf b/CloverEFI/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf new file mode 100755 index 0000000000..442eb07e97 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf @@ -0,0 +1,44 @@ +## @file +# This library defines some routines that are generic for IA32 family CPU +# to be UEFI specification compliant. +# +# Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseUefiCpuLib + FILE_GUID = 34C24FD7-7A90-45c2-89FD-946473D9CE98 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = UefiCpuLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.IA32] + Ia32/InitializeFpu.asm + Ia32/InitializeFpu.S + +[Sources.X64] + X64/InitializeFpu.asm + X64/InitializeFpu.S + +[Packages] + MdePkg/MdePkg.dec + CloverEFI/UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + UefiCpuLib + diff --git a/CloverEFI/UefiCpuPkg/Library/BaseUefiCpuLib/Ia32/InitializeFpu.S b/CloverEFI/UefiCpuPkg/Library/BaseUefiCpuLib/Ia32/InitializeFpu.S new file mode 100755 index 0000000000..4972bc2e7f --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/BaseUefiCpuLib/Ia32/InitializeFpu.S @@ -0,0 +1,73 @@ +#------------------------------------------------------------------------------ +#* +#* Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+#* This program and the accompanying materials +#* are licensed and made available under the terms and conditions of the BSD License +#* which accompanies this distribution. The full text of the license may be found at +#* http://opensource.org/licenses/bsd-license.php +#* +#* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +#* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +#* +#* +#------------------------------------------------------------------------------ + +# +# Float control word initial value: +# all exceptions masked, double-precision, round-to-nearest +# +ASM_PFX(mFpuControlWord): .word 0x027F +# +# Multimedia-extensions control word: +# all exceptions masked, round-to-nearest, flush to zero for masked underflow +# +ASM_PFX(mMmxControlWord): .long 0x01F80 + +# +# Initializes floating point units for requirement of UEFI specification. +# +# This function initializes floating-point control word to 0x027F (all exceptions +# masked,double-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). +# +ASM_GLOBAL ASM_PFX(InitializeFloatingPointUnits) +ASM_PFX(InitializeFloatingPointUnits): + + pushl %ebx + + # + # Initialize floating point units + # + finit + fldcw ASM_PFX(mFpuControlWord) + + # + # Use CpuId instructuion (CPUID.01H:EDX.SSE[bit 25] = 1) to test + # whether the processor supports SSE instruction. + # + movl $1, %eax + cpuid + btl $25, %edx + jnc Done + + # + # Set OSFXSR bit 9 in CR4 + # + movl %cr4, %eax + or $0x200, %eax + movl %eax, %cr4 + + # + # The processor should support SSE instruction and we can use + # ldmxcsr instruction + # + ldmxcsr ASM_PFX(mMmxControlWord) + +Done: + popl %ebx + + ret + +#END + diff --git a/CloverEFI/UefiCpuPkg/Library/BaseUefiCpuLib/Ia32/InitializeFpu.asm b/CloverEFI/UefiCpuPkg/Library/BaseUefiCpuLib/Ia32/InitializeFpu.asm new file mode 100755 index 0000000000..3c31da98f6 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/BaseUefiCpuLib/Ia32/InitializeFpu.asm @@ -0,0 +1,79 @@ +;------------------------------------------------------------------------------ +;* +;* Copyright (c) 2009, Intel Corporation. All rights reserved.
+;* This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* +;------------------------------------------------------------------------------ + + + .686 + .model flat,C + .const +; +; Float control word initial value: +; all exceptions masked, double-precision, round-to-nearest +; +mFpuControlWord DW 027Fh +; +; Multimedia-extensions control word: +; all exceptions masked, round-to-nearest, flush to zero for masked underflow +; +mMmxControlWord DD 01F80h + + .xmm + .code + +; +; Initializes floating point units for requirement of UEFI specification. +; +; This function initializes floating-point control word to 0x027F (all exceptions +; masked,double-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). +; +InitializeFloatingPointUnits PROC PUBLIC + + push ebx + + ; + ; Initialize floating point units + ; + finit + fldcw mFpuControlWord + + ; + ; Use CpuId instructuion (CPUID.01H:EDX.SSE[bit 25] = 1) to test + ; whether the processor supports SSE instruction. + ; + mov eax, 1 + cpuid + bt edx, 25 + jnc Done + + ; + ; Set OSFXSR bit 9 in CR4 + ; + mov eax, cr4 + or eax, BIT9 + mov cr4, eax + + ; + ; The processor should support SSE instruction and we can use + ; ldmxcsr instruction + ; + ldmxcsr mMmxControlWord +Done: + pop ebx + + ret + +InitializeFloatingPointUnits ENDP + +END diff --git a/CloverEFI/UefiCpuPkg/Library/BaseUefiCpuLib/X64/InitializeFpu.S b/CloverEFI/UefiCpuPkg/Library/BaseUefiCpuLib/X64/InitializeFpu.S new file mode 100755 index 0000000000..64750afb85 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/BaseUefiCpuLib/X64/InitializeFpu.S @@ -0,0 +1,57 @@ +#------------------------------------------------------------------------------ +#* +#* Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+#* This program and the accompanying materials +#* are licensed and made available under the terms and conditions of the BSD License +#* which accompanies this distribution. The full text of the license may be found at +#* http://opensource.org/licenses/bsd-license.php +#* +#* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +#* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +#* +#* +#------------------------------------------------------------------------------ + +# +# Initializes floating point units for requirement of UEFI specification. +# +# This function initializes floating-point control word to 0x027F (all exceptions +# masked,double-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). +# +ASM_GLOBAL ASM_PFX(InitializeFloatingPointUnits) +ASM_PFX(InitializeFloatingPointUnits): + + # + # Initialize floating point units + # + finit + + # + # Float control word initial value: + # all exceptions masked, double-precision, round-to-nearest + # + pushq $0x027F + lea (%rsp), %rax + fldcw (%rax) + popq %rax + + # + # Set OSFXSR bit 9 in CR4 + # + movq %cr4, %rax + or $0x200, %rax + movq %rax, %cr4 + + # + # Multimedia-extensions control word: + # all exceptions masked, round-to-nearest, flush to zero for masked underflow + # + pushq $0x01F80 + lea (%rsp), %rax + ldmxcsr (%rax) + popq %rax + + ret + diff --git a/CloverEFI/UefiCpuPkg/Library/BaseUefiCpuLib/X64/InitializeFpu.asm b/CloverEFI/UefiCpuPkg/Library/BaseUefiCpuLib/X64/InitializeFpu.asm new file mode 100755 index 0000000000..0a036b6ae3 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/BaseUefiCpuLib/X64/InitializeFpu.asm @@ -0,0 +1,62 @@ +;------------------------------------------------------------------------------ +;* +;* Copyright (c) 2009, Intel Corporation. All rights reserved.
+;* This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* +;------------------------------------------------------------------------------ + + +.const +; +; Float control word initial value: +; all exceptions masked, double-precision, round-to-nearest +; +mFpuControlWord DW 027Fh +; +; Multimedia-extensions control word: +; all exceptions masked, round-to-nearest, flush to zero for masked underflow +; +mMmxControlWord DD 01F80h + +.code + + +; +; Initializes floating point units for requirement of UEFI specification. +; +; This function initializes floating-point control word to 0x027F (all exceptions +; masked,double-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). +; +InitializeFloatingPointUnits 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, BIT9 + mov cr4, rax + + ldmxcsr mMmxControlWord + + ret +InitializeFloatingPointUnits ENDP + +END diff --git a/CloverEFI/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c b/CloverEFI/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c new file mode 100755 index 0000000000..77c24deed0 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c @@ -0,0 +1,754 @@ +/** @file + Local APIC Library. + + This local APIC library instance supports xAPIC mode only. + + Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include +#include +#include +#include + +// +// Library internal functions +// + +/** + Read from a local APIC register. + + This function reads from a local APIC register either in xAPIC or x2APIC mode. + It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be + accessed using multiple 32-bit loads or stores, so this function only performs + 32-bit read. + + @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode. + It must be 16-byte aligned. + + @return 32-bit Value read from the register. +**/ +UINT32 +EFIAPI +ReadLocalApicReg ( + IN UINTN MmioOffset + ) +{ + ASSERT ((MmioOffset & 0xf) == 0); + ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC); + + return MmioRead32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + MmioOffset); +} + +/** + Write to a local APIC register. + + This function writes to a local APIC register either in xAPIC or x2APIC mode. + It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be + accessed using multiple 32-bit loads or stores, so this function only performs + 32-bit write. + + if the register index is invalid or unsupported in current APIC mode, then ASSERT. + + @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode. + It must be 16-byte aligned. + @param Value Value to be written to the register. +**/ +VOID +EFIAPI +WriteLocalApicReg ( + IN UINTN MmioOffset, + IN UINT32 Value + ) +{ + ASSERT ((MmioOffset & 0xf) == 0); + ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC); + + MmioWrite32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + MmioOffset, Value); +} + +/** + Send an IPI by writing to ICR. + + This function returns after the IPI has been accepted by the target processor. + + @param IcrLow 32-bit value to be written to the low half of ICR. + @param ApicId APIC ID of the target processor if this IPI is targeted for a specific processor. +**/ +VOID +SendIpi ( + IN UINT32 IcrLow, + IN UINT32 ApicId + ) +{ + LOCAL_APIC_ICR_LOW IcrLowReg; + + ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC); + ASSERT (ApicId <= 0xff); + + // + // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent. + // + WriteLocalApicReg (XAPIC_ICR_HIGH_OFFSET, ApicId << 24); + WriteLocalApicReg (XAPIC_ICR_LOW_OFFSET, IcrLow); + do { + IcrLowReg.Uint32 = ReadLocalApicReg (XAPIC_ICR_LOW_OFFSET); + } while (IcrLowReg.Bits.DeliveryStatus != 0); +} + +// +// Library API implementation functions +// + +/** + Get the current local APIC mode. + + If local APIC is disabled, then ASSERT. + + @retval LOCAL_APIC_MODE_XAPIC current APIC mode is xAPIC. + @retval LOCAL_APIC_MODE_X2APIC current APIC mode is x2APIC. +**/ +UINTN +EFIAPI +GetApicMode ( + VOID + ) +{ + DEBUG_CODE ( + { + MSR_IA32_APIC_BASE ApicBaseMsr; + + ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS); + // + // Local APIC should have been enabled + // + ASSERT (ApicBaseMsr.Bits.En != 0); + ASSERT (ApicBaseMsr.Bits.Extd == 0); + } + ); + return LOCAL_APIC_MODE_XAPIC; +} + +/** + Set the current local APIC mode. + + If the specified local APIC mode is not valid, then ASSERT. + If the specified local APIC mode can't be set as current, then ASSERT. + + @param ApicMode APIC mode to be set. +**/ +VOID +EFIAPI +SetApicMode ( + IN UINTN ApicMode + ) +{ + ASSERT (ApicMode == LOCAL_APIC_MODE_XAPIC); + ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC); +} + +/** + Get the initial local APIC ID of the executing processor assigned by hardware upon power on or reset. + + In xAPIC mode, the initial local APIC ID is 8-bit, and may be different from current APIC ID. + In x2APIC mode, the local APIC ID can't be changed and there is no concept of initial APIC ID. In this case, + the 32-bit local APIC ID is returned as initial APIC ID. + + @return 32-bit initial local APIC ID of the executing processor. +**/ +UINT32 +EFIAPI +GetInitialApicId ( + VOID + ) +{ + UINT32 RegEbx; + + ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC); + + AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL); + return RegEbx >> 24; +} + +/** + Get the local APIC ID of the executing processor. + + @return 32-bit local APIC ID of the executing processor. +**/ +UINT32 +EFIAPI +GetApicId ( + VOID + ) +{ + UINT32 ApicId; + + ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC); + + ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET); + ApicId >>= 24; + return ApicId; +} + +/** + Get the value of the local APIC version register. + + @return the value of the local APIC version register. +**/ +UINT32 +EFIAPI +GetApicVersion ( + VOID + ) +{ + return ReadLocalApicReg (XAPIC_VERSION_OFFSET); +} + +/** + Send a Fixed IPI to a specified target processor. + + This function returns after the IPI has been accepted by the target processor. + + @param ApicId The local APIC ID of the target processor. + @param Vector The vector number of the interrupt being sent. +**/ +VOID +EFIAPI +SendFixedIpi ( + IN UINT32 ApicId, + IN UINT8 Vector + ) +{ + LOCAL_APIC_ICR_LOW IcrLow; + + IcrLow.Uint32 = 0; + IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED; + IcrLow.Bits.Level = 1; + IcrLow.Bits.Vector = Vector; + SendIpi (IcrLow.Uint32, ApicId); +} + +/** + Send a Fixed IPI to all processors excluding self. + + This function returns after the IPI has been accepted by the target processors. + + @param Vector The vector number of the interrupt being sent. +**/ +VOID +EFIAPI +SendFixedIpiAllExcludingSelf ( + IN UINT8 Vector + ) +{ + LOCAL_APIC_ICR_LOW IcrLow; + + IcrLow.Uint32 = 0; + IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED; + IcrLow.Bits.Level = 1; + IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF; + IcrLow.Bits.Vector = Vector; + SendIpi (IcrLow.Uint32, 0); +} + +/** + Send a SMI IPI to a specified target processor. + + This function returns after the IPI has been accepted by the target processor. + + @param ApicId Specify the local APIC ID of the target processor. +**/ +VOID +EFIAPI +SendSmiIpi ( + IN UINT32 ApicId + ) +{ + LOCAL_APIC_ICR_LOW IcrLow; + + IcrLow.Uint32 = 0; + IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI; + IcrLow.Bits.Level = 1; + SendIpi (IcrLow.Uint32, ApicId); +} + +/** + Send a SMI IPI to all processors excluding self. + + This function returns after the IPI has been accepted by the target processors. +**/ +VOID +EFIAPI +SendSmiIpiAllExcludingSelf ( + VOID + ) +{ + LOCAL_APIC_ICR_LOW IcrLow; + + IcrLow.Uint32 = 0; + IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI; + IcrLow.Bits.Level = 1; + IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF; + SendIpi (IcrLow.Uint32, 0); +} + +/** + Send an INIT IPI to a specified target processor. + + This function returns after the IPI has been accepted by the target processor. + + @param ApicId Specify the local APIC ID of the target processor. +**/ +VOID +EFIAPI +SendInitIpi ( + IN UINT32 ApicId + ) +{ + LOCAL_APIC_ICR_LOW IcrLow; + + IcrLow.Uint32 = 0; + IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT; + IcrLow.Bits.Level = 1; + SendIpi (IcrLow.Uint32, ApicId); +} + +/** + Send an INIT IPI to all processors excluding self. + + This function returns after the IPI has been accepted by the target processors. +**/ +VOID +EFIAPI +SendInitIpiAllExcludingSelf ( + VOID + ) +{ + LOCAL_APIC_ICR_LOW IcrLow; + + IcrLow.Uint32 = 0; + IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT; + IcrLow.Bits.Level = 1; + IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF; + SendIpi (IcrLow.Uint32, 0); +} + +/** + Send an INIT-Start-up-Start-up IPI sequence to a specified target processor. + + This function returns after the IPI has been accepted by the target processor. + + if StartupRoutine >= 1M, then ASSERT. + if StartupRoutine is not multiple of 4K, then ASSERT. + + @param ApicId Specify the local APIC ID of the target processor. + @param StartupRoutine Points to a start-up routine which is below 1M physical + address and 4K aligned. +**/ +VOID +EFIAPI +SendInitSipiSipi ( + IN UINT32 ApicId, + IN UINT32 StartupRoutine + ) +{ + LOCAL_APIC_ICR_LOW IcrLow; + + ASSERT (StartupRoutine < 0x100000); + ASSERT ((StartupRoutine & 0xfff) == 0); + + SendInitIpi (ApicId); + MicroSecondDelay (10); + IcrLow.Uint32 = 0; + IcrLow.Bits.Vector = (StartupRoutine >> 12); + IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP; + IcrLow.Bits.Level = 1; + SendIpi (IcrLow.Uint32, ApicId); + MicroSecondDelay (200); + SendIpi (IcrLow.Uint32, ApicId); +} + +/** + Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self. + + This function returns after the IPI has been accepted by the target processors. + + if StartupRoutine >= 1M, then ASSERT. + if StartupRoutine is not multiple of 4K, then ASSERT. + + @param StartupRoutine Points to a start-up routine which is below 1M physical + address and 4K aligned. +**/ +VOID +EFIAPI +SendInitSipiSipiAllExcludingSelf ( + IN UINT32 StartupRoutine + ) +{ + LOCAL_APIC_ICR_LOW IcrLow; + + ASSERT (StartupRoutine < 0x100000); + ASSERT ((StartupRoutine & 0xfff) == 0); + + SendInitIpiAllExcludingSelf (); + MicroSecondDelay (10); + IcrLow.Uint32 = 0; + IcrLow.Bits.Vector = (StartupRoutine >> 12); + IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP; + IcrLow.Bits.Level = 1; + IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF; + SendIpi (IcrLow.Uint32, 0); + MicroSecondDelay (200); + SendIpi (IcrLow.Uint32, 0); +} + +/** + Programming Virtual Wire Mode. + + This function programs the local APIC for virtual wire mode following + the example described in chapter A.3 of the MP 1.4 spec. + + IOxAPIC is not involved in this type of virtual wire mode. +**/ +VOID +EFIAPI +ProgramVirtualWireMode ( + VOID + ) +{ + LOCAL_APIC_SVR Svr; + LOCAL_APIC_LVT_LINT Lint; + + // + // Enable the APIC via SVR and set the spurious interrupt to use Int 00F. + // + Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET); + Svr.Bits.SpuriousVector = 0xf; + Svr.Bits.SoftwareEnable = 1; + WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32); + + // + // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high. + // + Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET); + Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT; + Lint.Bits.InputPinPolarity = 0; + Lint.Bits.TriggerMode = 0; + Lint.Bits.Mask = 0; + WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32); + + // + // Program the LINT0 vector entry as NMI. Not masked, edge, active high. + // + Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET); + Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI; + Lint.Bits.InputPinPolarity = 0; + Lint.Bits.TriggerMode = 0; + Lint.Bits.Mask = 0; + WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32); +} + +/** + Disable LINT0 & LINT1 interrupts. + + This function sets the mask flag in the LVT LINT0 & LINT1 registers. +**/ +VOID +EFIAPI +DisableLvtInterrupts ( + VOID + ) +{ + LOCAL_APIC_LVT_LINT LvtLint; + + LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET); + LvtLint.Bits.Mask = 1; + WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, LvtLint.Uint32); + + LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET); + LvtLint.Bits.Mask = 1; + WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, LvtLint.Uint32); +} + +/** + Read the initial count value from the init-count register. + + @return The initial count value read from the init-count register. +**/ +UINT32 +EFIAPI +GetApicTimerInitCount ( + VOID + ) +{ + return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET); +} + +/** + Read the current count value from the current-count register. + + @return The current count value read from the current-count register. +**/ +UINT32 +EFIAPI +GetApicTimerCurrentCount ( + VOID + ) +{ + return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET); +} + +/** + Initialize the local APIC timer. + + The local APIC timer is initialized and enabled. + + @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128. + If it is 0, then use the current divide value in the DCR. + @param InitCount The initial count value. + @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot. + @param Vector The timer interrupt vector number. +**/ +VOID +EFIAPI +InitializeApicTimer ( + IN UINTN DivideValue, + IN UINT32 InitCount, + IN BOOLEAN PeriodicMode, + IN UINT8 Vector + ) +{ + LOCAL_APIC_SVR Svr; + LOCAL_APIC_DCR Dcr; + LOCAL_APIC_LVT_TIMER LvtTimer; + UINT32 Divisor; + + // + // Ensure local APIC is in software-enabled state. + // + Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET); + Svr.Bits.SoftwareEnable = 1; + WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32); + + // + // Program init-count register. + // + WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount); + + if (DivideValue != 0) { + ASSERT (DivideValue <= 128); + ASSERT (DivideValue == GetPowerOfTwo32((UINT32)DivideValue)); + Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7); + + Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET); + Dcr.Bits.DivideValue1 = (Divisor & 0x3); + Dcr.Bits.DivideValue2 = (Divisor >> 2); + WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32); + } + + // + // Enable APIC timer interrupt with specified timer mode. + // + LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET); + if (PeriodicMode) { + LvtTimer.Bits.TimerMode = 1; + } else { + LvtTimer.Bits.TimerMode = 0; + } + LvtTimer.Bits.Mask = 0; + LvtTimer.Bits.Vector = Vector; + WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32); +} + +/** + Get the state of the local APIC timer. + + @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128. + @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot. + @param Vector Return the timer interrupt vector number. +**/ +VOID +EFIAPI +GetApicTimerState ( + OUT UINTN *DivideValue OPTIONAL, + OUT BOOLEAN *PeriodicMode OPTIONAL, + OUT UINT8 *Vector OPTIONAL + ) +{ + UINT32 Divisor; + LOCAL_APIC_DCR Dcr; + LOCAL_APIC_LVT_TIMER LvtTimer; + + if (DivideValue != NULL) { + Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET); + Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2); + Divisor = (Divisor + 1) & 0x7; + *DivideValue = ((UINTN)1) << Divisor; + } + + if (PeriodicMode != NULL || Vector != NULL) { + LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET); + if (PeriodicMode != NULL) { + if (LvtTimer.Bits.TimerMode == 1) { + *PeriodicMode = TRUE; + } else { + *PeriodicMode = FALSE; + } + } + if (Vector != NULL) { + *Vector = (UINT8) LvtTimer.Bits.Vector; + } + } +} + +/** + Enable the local APIC timer interrupt. +**/ +VOID +EFIAPI +EnableApicTimerInterrupt ( + VOID + ) +{ + LOCAL_APIC_LVT_TIMER LvtTimer; + + LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET); + LvtTimer.Bits.Mask = 0; + WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32); +} + +/** + Disable the local APIC timer interrupt. +**/ +VOID +EFIAPI +DisableApicTimerInterrupt ( + VOID + ) +{ + LOCAL_APIC_LVT_TIMER LvtTimer; + + LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET); + LvtTimer.Bits.Mask = 1; + WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32); +} + +/** + Get the local APIC timer interrupt state. + + @retval TRUE The local APIC timer interrupt is enabled. + @retval FALSE The local APIC timer interrupt is disabled. +**/ +BOOLEAN +EFIAPI +GetApicTimerInterruptState ( + VOID + ) +{ + LOCAL_APIC_LVT_TIMER LvtTimer; + + LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET); + return (BOOLEAN)(LvtTimer.Bits.Mask == 0); +} + +/** + Send EOI to the local APIC. +**/ +VOID +EFIAPI +SendApicEoi ( + VOID + ) +{ + WriteLocalApicReg (XAPIC_EOI_OFFSET, 0); +} + +/** + Get the 32-bit address that a device should use to send a Message Signaled + Interrupt (MSI) to the Local APIC of the currently executing processor. + + @return 32-bit address used to send an MSI to the Local APIC. +**/ +UINT32 +EFIAPI +GetApicMsiAddress ( + VOID + ) +{ + LOCAL_APIC_MSI_ADDRESS MsiAddress; + + // + // Return address for an MSI interrupt to be delivered only to the APIC ID + // of the currently executing processor. + // + MsiAddress.Uint32 = 0; + MsiAddress.Bits.BaseAddress = 0xFEE; + MsiAddress.Bits.DestinationId = GetApicId (); + return MsiAddress.Uint32; +} + +/** + Get the 64-bit data value that a device should use to send a Message Signaled + Interrupt (MSI) to the Local APIC of the currently executing processor. + + If Vector is not in range 0x10..0xFE, then ASSERT(). + If DeliveryMode is not supported, then ASSERT(). + + @param Vector The 8-bit interrupt vector associated with the MSI. + Must be in the range 0x10..0xFE + @param DeliveryMode A 3-bit value that specifies how the recept of the MSI + is handled. The only supported values are: + 0: LOCAL_APIC_DELIVERY_MODE_FIXED + 1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY + 2: LOCAL_APIC_DELIVERY_MODE_SMI + 4: LOCAL_APIC_DELIVERY_MODE_NMI + 5: LOCAL_APIC_DELIVERY_MODE_INIT + 7: LOCAL_APIC_DELIVERY_MODE_EXTINT + + @param LevelTriggered TRUE specifies a level triggered interrupt. + FALSE specifies an edge triggered interrupt. + @param AssertionLevel Ignored if LevelTriggered is FALSE. + TRUE specifies a level triggered interrupt that active + when the interrupt line is asserted. + FALSE specifies a level triggered interrupt that active + when the interrupt line is deasserted. + + @return 64-bit data value used to send an MSI to the Local APIC. +**/ +UINT64 +EFIAPI +GetApicMsiValue ( + IN UINT8 Vector, + IN UINTN DeliveryMode, + IN BOOLEAN LevelTriggered, + IN BOOLEAN AssertionLevel + ) +{ + LOCAL_APIC_MSI_DATA MsiData; + + ASSERT (Vector >= 0x10 && Vector <= 0xFE); + ASSERT (DeliveryMode < 8 && DeliveryMode != 6 && DeliveryMode != 3); + + MsiData.Uint64 = 0; + MsiData.Bits.Vector = Vector; + MsiData.Bits.DeliveryMode = (UINT32)DeliveryMode; + if (LevelTriggered) { + MsiData.Bits.TriggerMode = 1; + if (AssertionLevel) { + MsiData.Bits.Level = 1; + } + } + return MsiData.Uint64; +} diff --git a/CloverEFI/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf b/CloverEFI/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf new file mode 100755 index 0000000000..a86789b5f4 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf @@ -0,0 +1,46 @@ +## @file +# Component description file for CPU Local APIC Library. +# +# This library instance supports xAPIC mode only. +# +# Copyright (c) 2010, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseXApicLib + FILE_GUID = D87CA0A8-1AC2-439b-90F8-EF4A2AC88DAF + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = LocalApicLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + BaseXApicLib.c + +[Packages] + MdePkg/MdePkg.dec + CloverEFI/UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + TimerLib + IoLib + +[Pcd] + gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress + diff --git a/CloverEFI/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c b/CloverEFI/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c new file mode 100755 index 0000000000..62201cd240 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c @@ -0,0 +1,837 @@ +/** @file + Local APIC Library. + + This local APIC library instance supports x2APIC capable processors + which have xAPIC and x2APIC modes. + + Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include +#include +#include +#include + +// +// Library internal functions +// + +/** + Read from a local APIC register. + + This function reads from a local APIC register either in xAPIC or x2APIC mode. + It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be + accessed using multiple 32-bit loads or stores, so this function only performs + 32-bit read. + + @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode. + It must be 16-byte aligned. + + @return 32-bit Value read from the register. +**/ +UINT32 +EFIAPI +ReadLocalApicReg ( + IN UINTN MmioOffset + ) +{ + UINT32 MsrIndex; + + ASSERT ((MmioOffset & 0xf) == 0); + + if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) { + return MmioRead32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + MmioOffset); + } else { + // + // DFR is not supported in x2APIC mode. + // + ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET); + // + // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It + // is not supported in this function for simplicity. + // + ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET); + + MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS; + return AsmReadMsr32 (MsrIndex); + } +} + +/** + Write to a local APIC register. + + This function writes to a local APIC register either in xAPIC or x2APIC mode. + It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be + accessed using multiple 32-bit loads or stores, so this function only performs + 32-bit write. + + if the register index is invalid or unsupported in current APIC mode, then ASSERT. + + @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode. + It must be 16-byte aligned. + @param Value Value to be written to the register. +**/ +VOID +EFIAPI +WriteLocalApicReg ( + IN UINTN MmioOffset, + IN UINT32 Value + ) +{ + UINT32 MsrIndex; + + ASSERT ((MmioOffset & 0xf) == 0); + + if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) { + MmioWrite32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + MmioOffset, Value); + } else { + // + // DFR is not supported in x2APIC mode. + // + ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET); + // + // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It + // is not supported in this function for simplicity. + // + ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET); + ASSERT (MmioOffset != XAPIC_ICR_LOW_OFFSET); + + MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS; + // + // The serializing semantics of WRMSR are relaxed when writing to the APIC registers. + // Use memory fence here to force the serializing semantics to be consisent with xAPIC mode. + // + MemoryFence (); + AsmWriteMsr32 (MsrIndex, Value); + } +} + +/** + Send an IPI by writing to ICR. + + This function returns after the IPI has been accepted by the target processor. + + @param IcrLow 32-bit value to be written to the low half of ICR. + @param ApicId APIC ID of the target processor if this IPI is targeted for a specific processor. +**/ +VOID +SendIpi ( + IN UINT32 IcrLow, + IN UINT32 ApicId + ) +{ + UINT64 MsrValue; + LOCAL_APIC_ICR_LOW IcrLowReg; + + if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) { + ASSERT (ApicId <= 0xff); + + // + // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent. + // + MmioWrite32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + XAPIC_ICR_HIGH_OFFSET, ApicId << 24); + MmioWrite32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + XAPIC_ICR_LOW_OFFSET, IcrLow); + do { + IcrLowReg.Uint32 = MmioRead32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + XAPIC_ICR_LOW_OFFSET); + } while (IcrLowReg.Bits.DeliveryStatus != 0); + } else { + // + // For x2APIC, A single MSR write to the Interrupt Command Register is required for dispatching an + // interrupt in x2APIC mode. + // + MsrValue = LShiftU64 ((UINT64) ApicId, 32) | IcrLow; + AsmWriteMsr64 (X2APIC_MSR_ICR_ADDRESS, MsrValue); + } +} + +// +// Library API implementation functions +// + +/** + Get the current local APIC mode. + + If local APIC is disabled, then ASSERT. + + @retval LOCAL_APIC_MODE_XAPIC current APIC mode is xAPIC. + @retval LOCAL_APIC_MODE_X2APIC current APIC mode is x2APIC. +**/ +UINTN +EFIAPI +GetApicMode ( + VOID + ) +{ + MSR_IA32_APIC_BASE ApicBaseMsr; + + ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS); + // + // Local APIC should have been enabled + // + ASSERT (ApicBaseMsr.Bits.En != 0); + if (ApicBaseMsr.Bits.Extd != 0) { + return LOCAL_APIC_MODE_X2APIC; + } else { + return LOCAL_APIC_MODE_XAPIC; + } +} + +/** + Set the current local APIC mode. + + If the specified local APIC mode is not valid, then ASSERT. + If the specified local APIC mode can't be set as current, then ASSERT. + + @param ApicMode APIC mode to be set. +**/ +VOID +EFIAPI +SetApicMode ( + IN UINTN ApicMode + ) +{ + UINTN CurrentMode; + MSR_IA32_APIC_BASE ApicBaseMsr; + + CurrentMode = GetApicMode (); + if (CurrentMode == LOCAL_APIC_MODE_XAPIC) { + switch (ApicMode) { + case LOCAL_APIC_MODE_XAPIC: + break; + case LOCAL_APIC_MODE_X2APIC: + ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS); + ApicBaseMsr.Bits.Extd = 1; + AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64); + break; + default: + ASSERT (FALSE); + } + } else { + switch (ApicMode) { + case LOCAL_APIC_MODE_XAPIC: + // + // Transition from x2APIC mode to xAPIC mode is a two-step process: + // x2APIC -> Local APIC disabled -> xAPIC + // + ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS); + ApicBaseMsr.Bits.Extd = 0; + ApicBaseMsr.Bits.En = 0; + AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64); + ApicBaseMsr.Bits.En = 1; + AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64); + break; + case LOCAL_APIC_MODE_X2APIC: + break; + default: + ASSERT (FALSE); + } + } +} + +/** + Get the initial local APIC ID of the executing processor assigned by hardware upon power on or reset. + + In xAPIC mode, the initial local APIC ID is 8-bit, and may be different from current APIC ID. + In x2APIC mode, the local APIC ID can't be changed and there is no concept of initial APIC ID. In this case, + the 32-bit local APIC ID is returned as initial APIC ID. + + @return 32-bit initial local APIC ID of the executing processor. +**/ +UINT32 +EFIAPI +GetInitialApicId ( + VOID + ) +{ + UINT32 RegEbx; + + if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) { + AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL); + return RegEbx >> 24; + } else { + return GetApicId (); + } +} + +/** + Get the local APIC ID of the executing processor. + + @return 32-bit local APIC ID of the executing processor. +**/ +UINT32 +EFIAPI +GetApicId ( + VOID + ) +{ + UINT32 ApicId; + + ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET); + if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) { + ApicId >>= 24; + } + return ApicId; +} + +/** + Get the value of the local APIC version register. + + @return the value of the local APIC version register. +**/ +UINT32 +EFIAPI +GetApicVersion ( + VOID + ) +{ + return ReadLocalApicReg (XAPIC_VERSION_OFFSET); +} + +/** + Send a Fixed IPI to a specified target processor. + + This function returns after the IPI has been accepted by the target processor. + + @param ApicId The local APIC ID of the target processor. + @param Vector The vector number of the interrupt being sent. +**/ +VOID +EFIAPI +SendFixedIpi ( + IN UINT32 ApicId, + IN UINT8 Vector + ) +{ + LOCAL_APIC_ICR_LOW IcrLow; + + IcrLow.Uint32 = 0; + IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED; + IcrLow.Bits.Level = 1; + IcrLow.Bits.Vector = Vector; + SendIpi (IcrLow.Uint32, ApicId); +} + +/** + Send a Fixed IPI to all processors excluding self. + + This function returns after the IPI has been accepted by the target processors. + + @param Vector The vector number of the interrupt being sent. +**/ +VOID +EFIAPI +SendFixedIpiAllExcludingSelf ( + IN UINT8 Vector + ) +{ + LOCAL_APIC_ICR_LOW IcrLow; + + IcrLow.Uint32 = 0; + IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED; + IcrLow.Bits.Level = 1; + IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF; + IcrLow.Bits.Vector = Vector; + SendIpi (IcrLow.Uint32, 0); +} + +/** + Send a SMI IPI to a specified target processor. + + This function returns after the IPI has been accepted by the target processor. + + @param ApicId Specify the local APIC ID of the target processor. +**/ +VOID +EFIAPI +SendSmiIpi ( + IN UINT32 ApicId + ) +{ + LOCAL_APIC_ICR_LOW IcrLow; + + IcrLow.Uint32 = 0; + IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI; + IcrLow.Bits.Level = 1; + SendIpi (IcrLow.Uint32, ApicId); +} + +/** + Send a SMI IPI to all processors excluding self. + + This function returns after the IPI has been accepted by the target processors. +**/ +VOID +EFIAPI +SendSmiIpiAllExcludingSelf ( + VOID + ) +{ + LOCAL_APIC_ICR_LOW IcrLow; + + IcrLow.Uint32 = 0; + IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI; + IcrLow.Bits.Level = 1; + IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF; + SendIpi (IcrLow.Uint32, 0); +} + +/** + Send an INIT IPI to a specified target processor. + + This function returns after the IPI has been accepted by the target processor. + + @param ApicId Specify the local APIC ID of the target processor. +**/ +VOID +EFIAPI +SendInitIpi ( + IN UINT32 ApicId + ) +{ + LOCAL_APIC_ICR_LOW IcrLow; + + IcrLow.Uint32 = 0; + IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT; + IcrLow.Bits.Level = 1; + SendIpi (IcrLow.Uint32, ApicId); +} + +/** + Send an INIT IPI to all processors excluding self. + + This function returns after the IPI has been accepted by the target processors. +**/ +VOID +EFIAPI +SendInitIpiAllExcludingSelf ( + VOID + ) +{ + LOCAL_APIC_ICR_LOW IcrLow; + + IcrLow.Uint32 = 0; + IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT; + IcrLow.Bits.Level = 1; + IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF; + SendIpi (IcrLow.Uint32, 0); +} + +/** + Send an INIT-Start-up-Start-up IPI sequence to a specified target processor. + + This function returns after the IPI has been accepted by the target processor. + + if StartupRoutine >= 1M, then ASSERT. + if StartupRoutine is not multiple of 4K, then ASSERT. + + @param ApicId Specify the local APIC ID of the target processor. + @param StartupRoutine Points to a start-up routine which is below 1M physical + address and 4K aligned. +**/ +VOID +EFIAPI +SendInitSipiSipi ( + IN UINT32 ApicId, + IN UINT32 StartupRoutine + ) +{ + LOCAL_APIC_ICR_LOW IcrLow; + + ASSERT (StartupRoutine < 0x100000); + ASSERT ((StartupRoutine & 0xfff) == 0); + + SendInitIpi (ApicId); + MicroSecondDelay (10); + IcrLow.Uint32 = 0; + IcrLow.Bits.Vector = (StartupRoutine >> 12); + IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP; + IcrLow.Bits.Level = 1; + SendIpi (IcrLow.Uint32, ApicId); + MicroSecondDelay (200); + SendIpi (IcrLow.Uint32, ApicId); +} + +/** + Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self. + + This function returns after the IPI has been accepted by the target processors. + + if StartupRoutine >= 1M, then ASSERT. + if StartupRoutine is not multiple of 4K, then ASSERT. + + @param StartupRoutine Points to a start-up routine which is below 1M physical + address and 4K aligned. +**/ +VOID +EFIAPI +SendInitSipiSipiAllExcludingSelf ( + IN UINT32 StartupRoutine + ) +{ + LOCAL_APIC_ICR_LOW IcrLow; + + ASSERT (StartupRoutine < 0x100000); + ASSERT ((StartupRoutine & 0xfff) == 0); + + SendInitIpiAllExcludingSelf (); + MicroSecondDelay (10); + IcrLow.Uint32 = 0; + IcrLow.Bits.Vector = (StartupRoutine >> 12); + IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP; + IcrLow.Bits.Level = 1; + IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF; + SendIpi (IcrLow.Uint32, 0); + MicroSecondDelay (200); + SendIpi (IcrLow.Uint32, 0); +} + +/** + Programming Virtual Wire Mode. + + This function programs the local APIC for virtual wire mode following + the example described in chapter A.3 of the MP 1.4 spec. + + IOxAPIC is not involved in this type of virtual wire mode. +**/ +VOID +EFIAPI +ProgramVirtualWireMode ( + VOID + ) +{ + LOCAL_APIC_SVR Svr; + LOCAL_APIC_LVT_LINT Lint; + + // + // Enable the APIC via SVR and set the spurious interrupt to use Int 00F. + // + Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET); + Svr.Bits.SpuriousVector = 0xf; + Svr.Bits.SoftwareEnable = 1; + WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32); + + // + // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high. + // + Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET); + Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT; + Lint.Bits.InputPinPolarity = 0; + Lint.Bits.TriggerMode = 0; + Lint.Bits.Mask = 0; + WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32); + + // + // Program the LINT0 vector entry as NMI. Not masked, edge, active high. + // + Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET); + Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI; + Lint.Bits.InputPinPolarity = 0; + Lint.Bits.TriggerMode = 0; + Lint.Bits.Mask = 0; + WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32); +} + +/** + Disable LINT0 & LINT1 interrupts. + + This function sets the mask flag in the LVT LINT0 & LINT1 registers. +**/ +VOID +EFIAPI +DisableLvtInterrupts ( + VOID + ) +{ + LOCAL_APIC_LVT_LINT LvtLint; + + LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET); + LvtLint.Bits.Mask = 1; + WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, LvtLint.Uint32); + + LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET); + LvtLint.Bits.Mask = 1; + WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, LvtLint.Uint32); +} + +/** + Read the initial count value from the init-count register. + + @return The initial count value read from the init-count register. +**/ +UINT32 +EFIAPI +GetApicTimerInitCount ( + VOID + ) +{ + return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET); +} + +/** + Read the current count value from the current-count register. + + @return The current count value read from the current-count register. +**/ +UINT32 +EFIAPI +GetApicTimerCurrentCount ( + VOID + ) +{ + return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET); +} + +/** + Initialize the local APIC timer. + + The local APIC timer is initialized and enabled. + + @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128. + If it is 0, then use the current divide value in the DCR. + @param InitCount The initial count value. + @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot. + @param Vector The timer interrupt vector number. +**/ +VOID +EFIAPI +InitializeApicTimer ( + IN UINTN DivideValue, + IN UINT32 InitCount, + IN BOOLEAN PeriodicMode, + IN UINT8 Vector + ) +{ + LOCAL_APIC_SVR Svr; + LOCAL_APIC_DCR Dcr; + LOCAL_APIC_LVT_TIMER LvtTimer; + UINT32 Divisor; + + // + // Ensure local APIC is in software-enabled state. + // + Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET); + Svr.Bits.SoftwareEnable = 1; + WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32); + + // + // Program init-count register. + // + WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount); + + if (DivideValue != 0) { + ASSERT (DivideValue <= 128); + ASSERT (DivideValue == GetPowerOfTwo32((UINT32)DivideValue)); + Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7); + + Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET); + Dcr.Bits.DivideValue1 = (Divisor & 0x3); + Dcr.Bits.DivideValue2 = (Divisor >> 2); + WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32); + } + + // + // Enable APIC timer interrupt with specified timer mode. + // + LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET); + if (PeriodicMode) { + LvtTimer.Bits.TimerMode = 1; + } else { + LvtTimer.Bits.TimerMode = 0; + } + LvtTimer.Bits.Mask = 0; + LvtTimer.Bits.Vector = Vector; + WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32); +} + +/** + Get the state of the local APIC timer. + + @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128. + @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot. + @param Vector Return the timer interrupt vector number. +**/ +VOID +EFIAPI +GetApicTimerState ( + OUT UINTN *DivideValue OPTIONAL, + OUT BOOLEAN *PeriodicMode OPTIONAL, + OUT UINT8 *Vector OPTIONAL + ) +{ + UINT32 Divisor; + LOCAL_APIC_DCR Dcr; + LOCAL_APIC_LVT_TIMER LvtTimer; + + if (DivideValue != NULL) { + Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET); + Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2); + Divisor = (Divisor + 1) & 0x7; + *DivideValue = ((UINTN)1) << Divisor; + } + + if (PeriodicMode != NULL || Vector != NULL) { + LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET); + if (PeriodicMode != NULL) { + if (LvtTimer.Bits.TimerMode == 1) { + *PeriodicMode = TRUE; + } else { + *PeriodicMode = FALSE; + } + } + if (Vector != NULL) { + *Vector = (UINT8) LvtTimer.Bits.Vector; + } + } +} + +/** + Enable the local APIC timer interrupt. +**/ +VOID +EFIAPI +EnableApicTimerInterrupt ( + VOID + ) +{ + LOCAL_APIC_LVT_TIMER LvtTimer; + + LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET); + LvtTimer.Bits.Mask = 0; + WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32); +} + +/** + Disable the local APIC timer interrupt. +**/ +VOID +EFIAPI +DisableApicTimerInterrupt ( + VOID + ) +{ + LOCAL_APIC_LVT_TIMER LvtTimer; + + LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET); + LvtTimer.Bits.Mask = 1; + WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32); +} + +/** + Get the local APIC timer interrupt state. + + @retval TRUE The local APIC timer interrupt is enabled. + @retval FALSE The local APIC timer interrupt is disabled. +**/ +BOOLEAN +EFIAPI +GetApicTimerInterruptState ( + VOID + ) +{ + LOCAL_APIC_LVT_TIMER LvtTimer; + + LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET); + return (BOOLEAN)(LvtTimer.Bits.Mask == 0); +} + +/** + Send EOI to the local APIC. +**/ +VOID +EFIAPI +SendApicEoi ( + VOID + ) +{ + WriteLocalApicReg (XAPIC_EOI_OFFSET, 0); +} + +/** + Get the 32-bit address that a device should use to send a Message Signaled + Interrupt (MSI) to the Local APIC of the currently executing processor. + + @return 32-bit address used to send an MSI to the Local APIC. +**/ +UINT32 +EFIAPI +GetApicMsiAddress ( + VOID + ) +{ + LOCAL_APIC_MSI_ADDRESS MsiAddress; + + // + // Return address for an MSI interrupt to be delivered only to the APIC ID + // of the currently executing processor. + // + MsiAddress.Uint32 = 0; + MsiAddress.Bits.BaseAddress = 0xFEE; + MsiAddress.Bits.DestinationId = GetApicId (); + return MsiAddress.Uint32; +} + +/** + Get the 64-bit data value that a device should use to send a Message Signaled + Interrupt (MSI) to the Local APIC of the currently executing processor. + + If Vector is not in range 0x10..0xFE, then ASSERT(). + If DeliveryMode is not supported, then ASSERT(). + + @param Vector The 8-bit interrupt vector associated with the MSI. + Must be in the range 0x10..0xFE + @param DeliveryMode A 3-bit value that specifies how the recept of the MSI + is handled. The only supported values are: + 0: LOCAL_APIC_DELIVERY_MODE_FIXED + 1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY + 2: LOCAL_APIC_DELIVERY_MODE_SMI + 4: LOCAL_APIC_DELIVERY_MODE_NMI + 5: LOCAL_APIC_DELIVERY_MODE_INIT + 7: LOCAL_APIC_DELIVERY_MODE_EXTINT + + @param LevelTriggered TRUE specifies a level triggered interrupt. + FALSE specifies an edge triggered interrupt. + @param AssertionLevel Ignored if LevelTriggered is FALSE. + TRUE specifies a level triggered interrupt that active + when the interrupt line is asserted. + FALSE specifies a level triggered interrupt that active + when the interrupt line is deasserted. + + @return 64-bit data value used to send an MSI to the Local APIC. +**/ +UINT64 +EFIAPI +GetApicMsiValue ( + IN UINT8 Vector, + IN UINTN DeliveryMode, + IN BOOLEAN LevelTriggered, + IN BOOLEAN AssertionLevel + ) +{ + LOCAL_APIC_MSI_DATA MsiData; + + ASSERT (Vector >= 0x10 && Vector <= 0xFE); + ASSERT (DeliveryMode < 8 && DeliveryMode != 6 && DeliveryMode != 3); + + MsiData.Uint64 = 0; + MsiData.Bits.Vector = Vector; + MsiData.Bits.DeliveryMode = (UINT32)DeliveryMode; + if (LevelTriggered) { + MsiData.Bits.TriggerMode = 1; + if (AssertionLevel) { + MsiData.Bits.Level = 1; + } + } + return MsiData.Uint64; +} diff --git a/CloverEFI/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf b/CloverEFI/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf new file mode 100755 index 0000000000..9fa2f0950b --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf @@ -0,0 +1,47 @@ +## @file +# Component description file for CPU Local APIC Library. +# +# This library instance supports x2APIC capable processors +# which have xAPIC and x2APIC modes. +# +# Copyright (c) 2010, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseXApicX2ApicLib + FILE_GUID = 967B6E05-F10D-4c10-8BF7-365291CA143F + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = LocalApicLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + BaseXApicX2ApicLib.c + +[Packages] + MdePkg/MdePkg.dec + CloverEFI/UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + TimerLib + IoLib + +[Pcd] + gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress + diff --git a/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c new file mode 100755 index 0000000000..f8cbcf080d --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c @@ -0,0 +1,173 @@ +/** @file + CPU Exception Handler Library common functions. + + Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CpuExceptionCommon.h" + +// +// 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 +// +CONST UINT32 mErrorCodeFlag = 0x00027d00; +RESERVED_VECTORS_DATA *mReservedVectors = NULL; + +// +// Define the maximum message length +// +#define MAX_DEBUG_MESSAGE_LENGTH 0x100 + +/** + Prints a message to the serial port. + + @param Format Format string for the message to print. + @param ... Variable argument list whose contents are accessed + based on the format string specified by Format. + +**/ +VOID +EFIAPI +InternalPrintMessage ( + IN CONST CHAR8 *Format, + ... + ) +{ + CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH]; + VA_LIST Marker; + + // + // Convert the message to an ASCII String + // + VA_START (Marker, Format); + AsciiVSPrint (Buffer, sizeof (Buffer), Format, Marker); + VA_END (Marker); + + // + // Send the print string to a Serial Port + // + SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer)); +} + +/** + Find and display image base address and return image base and its entry point. + + @param CurrentEip Current instruction pointer. + @param EntryPoint Return module entry point if module header is found. + + @return !0 Image base address. + @return 0 Image header cannot be found. +**/ +UINTN +FindModuleImageBase ( + IN UINTN CurrentEip, + OUT UINTN *EntryPoint + ) +{ + UINTN Pe32Data; + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + VOID *PdbPointer; + + // + // Find Image Base + // + Pe32Data = CurrentEip & ~(mImageAlignSize - 1); + while (Pe32Data != 0) { + DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data; + if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { + // + // DOS image header is present, so read the PE header after the DOS image header. + // + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff)); + // + // Make sure PE header address does not overflow and is less than the initial address. + // + if (((UINTN)Hdr.Pe32 > Pe32Data) && ((UINTN)Hdr.Pe32 < CurrentEip)) { + if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) { + // + // It's PE image. + // + InternalPrintMessage ("!!!! Find PE image "); + *EntryPoint = (UINTN)Pe32Data + (UINTN)(Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff); + break; + } + } + } else { + // + // DOS image header is not present, TE header is at the image base. + // + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data; + if ((Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) && + ((Hdr.Te->Machine == IMAGE_FILE_MACHINE_I386) || Hdr.Te->Machine == IMAGE_FILE_MACHINE_X64)) { + // + // It's TE image, it TE header and Machine type match + // + InternalPrintMessage ("!!!! Find TE image "); + *EntryPoint = (UINTN)Pe32Data + (UINTN)(Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof(EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize; + break; + } + } + + // + // Not found the image base, check the previous aligned address + // + Pe32Data -= mImageAlignSize; + } + + if (Pe32Data != 0) { + PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *) Pe32Data); + if (PdbPointer != NULL) { + InternalPrintMessage ("%a", PdbPointer); + } else { + InternalPrintMessage ("(No PDB) " ); + } + } else { + InternalPrintMessage ("!!!! Can't find image information. !!!!\n"); + } + + return Pe32Data; +} + +/** + Read and save reserved vector information + + @param[in] VectorInfo Pointer to reserved vector list. + @param[out] ReservedVector Pointer to reserved vector data buffer. + @param[in] VectorCount Vector number to be updated. + + @return EFI_SUCCESS Read and save vector info successfully. + @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL. + +**/ +EFI_STATUS +ReadAndVerifyVectorInfo ( + IN EFI_VECTOR_HANDOFF_INFO *VectorInfo, + OUT RESERVED_VECTORS_DATA *ReservedVector, + IN UINTN VectorCount + ) +{ + while (VectorInfo->Attribute != EFI_VECTOR_HANDOFF_LAST_ENTRY) { + if (VectorInfo->Attribute > EFI_VECTOR_HANDOFF_HOOK_AFTER) { + // + // If vector attrubute is invalid + // + return EFI_INVALID_PARAMETER; + } + if (VectorInfo->VectorNumber < VectorCount) { + ReservedVector[VectorInfo->VectorNumber].Attribute = VectorInfo->Attribute; + } + VectorInfo ++; + } + return EFI_SUCCESS; +} \ No newline at end of file diff --git a/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h new file mode 100755 index 0000000000..d72ecb6927 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h @@ -0,0 +1,242 @@ +/** @file + Common header file for CPU Exception Handler Library. + + Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _CPU_EXCEPTION_COMMON_H_ +#define _CPU_EXCEPTION_COMMON_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CPU_EXCEPTION_NUM 32 +#define CPU_INTERRUPT_NUM 256 +#define HOOKAFTER_STUB_SIZE 16 + +#include "ArchInterruptDefs.h" + +// +// Record exception handler information +// +typedef struct { + UINTN ExceptionStart; + UINTN ExceptionStubHeaderSize; + UINTN HookAfterStubHeaderStart; +} EXCEPTION_HANDLER_TEMPLATE_MAP; + +extern CONST UINT32 mErrorCodeFlag; +extern CONST UINTN mImageAlignSize; +extern CONST UINTN mDoFarReturnFlag; +extern RESERVED_VECTORS_DATA *mReservedVectors; + +/** + Return address map of exception handler template so that C code can generate + exception tables. + + @param AddressMap Pointer to a buffer where the address map is returned. +**/ +VOID +EFIAPI +AsmGetTemplateAddressMap ( + OUT EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap + ); + +/** + Return address map of exception handler template so that C code can generate + exception tables. + + @param IdtEntry Pointer to IDT entry to be updated. + @param InterruptHandler IDT handler value. + +**/ +VOID +ArchUpdateIdtEntry ( + IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry, + IN UINTN InterruptHandler + ); + +/** + Read IDT handler value from IDT entry. + + @param IdtEntry Pointer to IDT entry to be read. + +**/ +UINTN +ArchGetIdtHandler ( + IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry + ); + +/** + Prints a message to the serial port. + + @param Format Format string for the message to print. + @param ... Variable argument list whose contents are accessed + based on the format string specified by Format. + +**/ +VOID +EFIAPI +InternalPrintMessage ( + IN CONST CHAR8 *Format, + ... + ); + +/** + Find and display image base address and return image base and its entry point. + + @param CurrentEip Current instruction pointer. + @param EntryPoint Return module entry point if module header is found. + + @return !0 Image base address. + @return 0 Image header cannot be found. +**/ +UINTN +FindModuleImageBase ( + IN UINTN CurrentEip, + OUT UINTN *EntryPoint + ); + +/** + Display CPU information. + + @param ExceptionType Exception type. + @param SystemContext Pointer to EFI_SYSTEM_CONTEXT. +**/ +VOID +DumpCpuContent ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN EFI_SYSTEM_CONTEXT SystemContext + ); + +/** + Internal worker function to initialize exception handler. + + @param[in] VectorInfo Pointer to reserved vector list. + + @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized + with default exception handlers. + @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL. + @retval EFI_UNSUPPORTED This function is not supported. + +**/ +EFI_STATUS +InitializeCpuExceptionHandlersWorker ( + IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL + ); + +/** + Registers a function to be called from the processor interrupt handler. + + @param[in] InterruptType Defines which interrupt or exception to hook. + @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called + when a processor interrupt occurs. If this parameter is NULL, then the handler + will be uninstalled. + + @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was + previously installed. + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not + previously installed. + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported, + or this function is not supported. +**/ +EFI_STATUS +RegisterCpuInterruptHandlerWorker ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ); + +/** + Internal worker function to update IDT entries accordling to vector attributes. + + @param[in] IdtTable Pointer to IDT table. + @param[in] TemplateMap Pointer to a buffer where the address map is returned. + @param[in] IdtEntryCount IDT entries number to be updated. + +**/ +VOID +UpdateIdtTable ( + IN IA32_IDT_GATE_DESCRIPTOR *IdtTable, + IN EXCEPTION_HANDLER_TEMPLATE_MAP *TemplateMap, + IN UINTN IdtEntryCount + ); + +/** + Save CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case. + + @param[in] ExceptionType Exception type. + @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT. + +**/ +VOID +ArchSaveExceptionContext ( + IN UINTN ExceptionType, + IN EFI_SYSTEM_CONTEXT SystemContext + ); + +/** + Restore CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case. + + @param[in] ExceptionType Exception type. + @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT. + +**/ +VOID +ArchRestoreExceptionContext ( + IN UINTN ExceptionType, + IN EFI_SYSTEM_CONTEXT SystemContext + ); + +/** + Fix up the vector number in the vector code. + + @param[in] VectorBase Base address of the vector handler. + @param[in] VectorNum Index of vector. + @param[in] HookStub TRUE HookAfterStubHeaderEnd. + FALSE HookAfterStubHeaderEnd + +**/ +VOID +EFIAPI +AsmVectorNumFixup ( + IN VOID *VectorBase, + IN UINT8 VectorNum, + IN BOOLEAN HookStub + ); + +/** + Read and save reserved vector information + + @param[in] VectorInfo Pointer to reserved vector list. + @param[out] ReservedVector Pointer to reserved vector data buffer. + @param[in] VectorCount Vector number to be updated. + + @return EFI_SUCCESS Read and save vector info successfully. + @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL. + +**/ +EFI_STATUS +ReadAndVerifyVectorInfo ( + IN EFI_VECTOR_HANDOFF_INFO *VectorInfo, + OUT RESERVED_VECTORS_DATA *ReservedVector, + IN UINTN VectorCount + ); + +#endif + diff --git a/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf new file mode 100755 index 0000000000..5873bf021d --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf @@ -0,0 +1,64 @@ +## @file +# CPU Exception Handler library instance for DXE modules. +# +# Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeCpuExceptionHandlerLib + MODULE_UNI_FILE = DxeCpuExceptionHandlerLib.uni + FILE_GUID = B6E9835A-EDCF-4748-98A8-27D3C722E02D + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = CpuExceptionHandlerLib|DXE_CORE DXE_DRIVER UEFI_APPLICATION + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.Ia32] + Ia32/ExceptionHandlerAsm.asm + Ia32/ExceptionHandlerAsm.S |GCC + Ia32/ArchExceptionHandler.c + Ia32/ArchInterruptDefs.h + +[Sources.X64] + X64/ExceptionHandlerAsm.asm + X64/ExceptionHandlerAsm.S |GCC + X64/ArchExceptionHandler.c + X64/ArchInterruptDefs.h + +[Sources.common] + CpuExceptionCommon.h + CpuExceptionCommon.c + DxeSmmCpuException.c + DxeException.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + CloverEFI/UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + SerialPortLib + PrintLib + SynchronizationLib + LocalApicLib + PeCoffGetEntryPointLib + MemoryAllocationLib + DebugLib + +[Ppis] + gEfiVectorHandoffInfoPpiGuid diff --git a/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.uni b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.uni new file mode 100755 index 0000000000..7aaaa5b537 Binary files /dev/null and b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.uni differ diff --git a/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c new file mode 100755 index 0000000000..f02355ec82 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c @@ -0,0 +1,170 @@ +/** @file + CPU exception handler library implemenation for DXE modules. + + Copyright (c) 2013, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include "CpuExceptionCommon.h" +#include +#include + +CONST UINTN mDoFarReturnFlag = 0; + +extern SPIN_LOCK mDisplayMessageSpinLock; +extern EFI_CPU_INTERRUPT_HANDLER *mExternalInterruptHandler; + +/** + Initializes all CPU exceptions entries and provides the default exception handlers. + + Caller should try to get an array of interrupt and/or exception vectors that are in use and need to + persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification. + If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL. + If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly. + + @param[in] VectorInfo Pointer to reserved vector list. + + @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized + with default exception handlers. + @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL. + @retval EFI_UNSUPPORTED This function is not supported. + +**/ +EFI_STATUS +EFIAPI +InitializeCpuExceptionHandlers ( + IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL + ) +{ + return InitializeCpuExceptionHandlersWorker (VectorInfo); +} + +/** + Initializes all CPU interrupt/exceptions entries and provides the default interrupt/exception handlers. + + Caller should try to get an array of interrupt and/or exception vectors that are in use and need to + persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification. + If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL. + If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly. + + @param[in] VectorInfo Pointer to reserved vector list. + + @retval EFI_SUCCESS All CPU interrupt/exception entries have been successfully initialized + with default interrupt/exception handlers. + @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL. + @retval EFI_UNSUPPORTED This function is not supported. + +**/ +EFI_STATUS +EFIAPI +InitializeCpuInterruptHandlers ( + IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL + ) +{ + EFI_STATUS Status; + IA32_IDT_GATE_DESCRIPTOR *IdtTable; + IA32_DESCRIPTOR IdtDescriptor; + UINTN IdtEntryCount; + EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap; + UINTN Index; + UINTN InterruptEntry; + UINT8 *InterruptEntryCode; + + mReservedVectors = AllocatePool (sizeof (RESERVED_VECTORS_DATA) * CPU_INTERRUPT_NUM); + ASSERT (mReservedVectors != NULL); + SetMem ((VOID *) mReservedVectors, sizeof (RESERVED_VECTORS_DATA) * CPU_INTERRUPT_NUM, 0xff); + if (VectorInfo != NULL) { + Status = ReadAndVerifyVectorInfo (VectorInfo, mReservedVectors, CPU_INTERRUPT_NUM); + if (EFI_ERROR (Status)) { + FreePool (mReservedVectors); + return EFI_INVALID_PARAMETER; + } + } + InitializeSpinLock (&mDisplayMessageSpinLock); + mExternalInterruptHandler = AllocateZeroPool (sizeof (EFI_CPU_INTERRUPT_HANDLER) * CPU_INTERRUPT_NUM); + ASSERT (mExternalInterruptHandler != NULL); + + // + // Read IDT descriptor and calculate IDT size + // + AsmReadIdtr (&IdtDescriptor); + IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR); + if (IdtEntryCount > CPU_INTERRUPT_NUM) { + IdtEntryCount = CPU_INTERRUPT_NUM; + } + // + // Create Interrupt Descriptor Table and Copy the old IDT table in + // + IdtTable = AllocateZeroPool (sizeof (IA32_IDT_GATE_DESCRIPTOR) * CPU_INTERRUPT_NUM); + ASSERT (IdtTable != NULL); + CopyMem (IdtTable, (VOID *)IdtDescriptor.Base, sizeof (IA32_IDT_GATE_DESCRIPTOR) * IdtEntryCount); + + AsmGetTemplateAddressMap (&TemplateMap); + ASSERT (TemplateMap.ExceptionStubHeaderSize <= HOOKAFTER_STUB_SIZE); + InterruptEntryCode = AllocatePool (TemplateMap.ExceptionStubHeaderSize * CPU_INTERRUPT_NUM); + ASSERT (InterruptEntryCode != NULL); + + InterruptEntry = (UINTN) InterruptEntryCode; + for (Index = 0; Index < CPU_INTERRUPT_NUM; Index ++) { + CopyMem ( + (VOID *) InterruptEntry, + (VOID *) TemplateMap.ExceptionStart, + TemplateMap.ExceptionStubHeaderSize + ); + AsmVectorNumFixup ((VOID *) InterruptEntry, (UINT8) Index, FALSE); + InterruptEntry += TemplateMap.ExceptionStubHeaderSize; + } + + TemplateMap.ExceptionStart = (UINTN) InterruptEntryCode; + UpdateIdtTable (IdtTable, &TemplateMap, CPU_INTERRUPT_NUM); + + // + // Load Interrupt Descriptor Table + // + IdtDescriptor.Base = (UINTN) IdtTable; + IdtDescriptor.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * CPU_INTERRUPT_NUM - 1); + AsmWriteIdtr ((IA32_DESCRIPTOR *) &IdtDescriptor); + + return EFI_SUCCESS; +} + +/** + Registers a function to be called from the processor interrupt handler. + + This function registers and enables the handler specified by InterruptHandler for a processor + interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the + handler for the processor interrupt or exception type specified by InterruptType is uninstalled. + The installed handler is called once for each processor interrupt or exception. + NOTE: This function should be invoked after InitializeCpuExceptionHandlers() or + InitializeCpuInterruptHandlers() invoked, otherwise EFI_UNSUPPORTED returned. + + @param[in] InterruptType Defines which interrupt or exception to hook. + @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called + when a processor interrupt occurs. If this parameter is NULL, then the handler + will be uninstalled. + + @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was + previously installed. + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not + previously installed. + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported, + or this function is not supported. +**/ +EFI_STATUS +EFIAPI +RegisterCpuInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ) +{ + return RegisterCpuInterruptHandlerWorker (InterruptType, InterruptHandler); +} diff --git a/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeSmmCpuException.c b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeSmmCpuException.c new file mode 100755 index 0000000000..4829016141 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeSmmCpuException.c @@ -0,0 +1,288 @@ +/** @file + CPU Exception Library provides DXE/SMM CPU common exception handler. + +Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CpuExceptionCommon.h" +#include + +// +// Spinlock for CPU information display +// +SPIN_LOCK mDisplayMessageSpinLock; + +// +// Image align size for DXE/SMM +// +CONST UINTN mImageAlignSize = SIZE_4KB; + +RESERVED_VECTORS_DATA mReservedVectorsData[CPU_INTERRUPT_NUM]; +EFI_CPU_INTERRUPT_HANDLER mExternalInterruptHandlerTable[CPU_INTERRUPT_NUM]; +EFI_CPU_INTERRUPT_HANDLER *mExternalInterruptHandler = NULL; +UINTN mEnabledInterruptNum = 0; + +/** + Common exception handler. + + @param ExceptionType Exception type. + @param SystemContext Pointer to EFI_SYSTEM_CONTEXT. +**/ +VOID +EFIAPI +CommonExceptionHandler ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + EXCEPTION_HANDLER_CONTEXT *ExceptionHandlerContext; + + ExceptionHandlerContext = (EXCEPTION_HANDLER_CONTEXT *) (UINTN) (SystemContext.SystemContextIa32); + + switch (mReservedVectors[ExceptionType].Attribute) { + case EFI_VECTOR_HANDOFF_HOOK_BEFORE: + // + // Need to jmp to old IDT handler after this exception handler + // + ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE; + ExceptionHandlerContext->OldIdtHandler = mReservedVectors[ExceptionType].ExceptonHandler; + break; + case EFI_VECTOR_HANDOFF_HOOK_AFTER: + while (TRUE) { + // + // If if anyone has gotten SPIN_LOCK for owner running hook after + // + if (AcquireSpinLockOrFail (&mReservedVectors[ExceptionType].SpinLock)) { + // + // Need to execute old IDT handler before running this exception handler + // + mReservedVectors[ExceptionType].ApicId = GetApicId (); + ArchSaveExceptionContext (ExceptionType, SystemContext); + ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE; + ExceptionHandlerContext->OldIdtHandler = mReservedVectors[ExceptionType].ExceptonHandler; + return; + } + // + // If failed to acquire SPIN_LOCK, check if it was locked by processor itself + // + if (mReservedVectors[ExceptionType].ApicId == GetApicId ()) { + // + // Old IDT handler has been executed, then retore CPU exception content to + // run new exception handler. + // + ArchRestoreExceptionContext (ExceptionType, SystemContext); + // + // Rlease spin lock for ApicId + // + ReleaseSpinLock (&mReservedVectors[ExceptionType].SpinLock); + break; + } + CpuPause (); + } + break; + case 0xffffffff: + break; + default: + // + // It should never reach here + // + CpuDeadLoop (); + break; + } + + if (mExternalInterruptHandler[ExceptionType] != NULL) { + (mExternalInterruptHandler[ExceptionType]) (ExceptionType, SystemContext); + } else if (ExceptionType < CPU_EXCEPTION_NUM) { + // + // Get Spinlock to display CPU information + // + while (!AcquireSpinLockOrFail (&mDisplayMessageSpinLock)) { + CpuPause (); + } + // + // Display ExceptionType, CPU information and Image information + // + DumpCpuContent (ExceptionType, SystemContext); + // + // Release Spinlock of output message + // + ReleaseSpinLock (&mDisplayMessageSpinLock); + // + // Enter a dead loop if needn't to execute old IDT handler further + // + if (mReservedVectors[ExceptionType].Attribute != EFI_VECTOR_HANDOFF_HOOK_BEFORE) { + CpuDeadLoop (); + } + } +} + +/** + Internal worker function to update IDT entries accordling to vector attributes. + + @param[in] IdtTable Pointer to IDT table. + @param[in] TemplateMap Pointer to a buffer where the address map is returned. + @param[in] IdtEntryCount IDT entries number to be updated. + +**/ +VOID +UpdateIdtTable ( + IN IA32_IDT_GATE_DESCRIPTOR *IdtTable, + IN EXCEPTION_HANDLER_TEMPLATE_MAP *TemplateMap, + IN UINTN IdtEntryCount + ) +{ + UINT16 CodeSegment; + UINTN Index; + UINTN InterruptHandler; + + // + // Use current CS as the segment selector of interrupt gate in IDT + // + CodeSegment = AsmReadCs (); + + for (Index = 0; Index < IdtEntryCount; Index ++) { + IdtTable[Index].Bits.Selector = CodeSegment; + // + // Check reserved vectors attributes + // + switch (mReservedVectors[Index].Attribute) { + case EFI_VECTOR_HANDOFF_DO_NOT_HOOK: + // + // Keep original IDT entry + // + continue; + case EFI_VECTOR_HANDOFF_HOOK_AFTER: + InitializeSpinLock (&mReservedVectors[Index].SpinLock); + CopyMem ( + (VOID *) mReservedVectors[Index].HookAfterStubHeaderCode, + (VOID *) TemplateMap->HookAfterStubHeaderStart, + TemplateMap->ExceptionStubHeaderSize + ); + AsmVectorNumFixup ((VOID *) mReservedVectors[Index].HookAfterStubHeaderCode, (UINT8) Index, TRUE); + // + // Go on the following code + // + case EFI_VECTOR_HANDOFF_HOOK_BEFORE: + // + // Save original IDT handler address + // + mReservedVectors[Index].ExceptonHandler = ArchGetIdtHandler (&IdtTable[Index]); + // + // Go on the following code + // + default: + // + // Update new IDT entry + // + InterruptHandler = TemplateMap->ExceptionStart + Index * TemplateMap->ExceptionStubHeaderSize; + ArchUpdateIdtEntry (&IdtTable[Index], InterruptHandler); + break; + } + } + + // + // Save Interrupt number to global variable used for RegisterCpuInterruptHandler () + // + mEnabledInterruptNum = IdtEntryCount; +} + +/** + Internal worker function to initialize exception handler. + + @param[in] VectorInfo Pointer to reserved vector list. + + @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized + with default exception handlers. + @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL. + @retval EFI_UNSUPPORTED This function is not supported. + +**/ +EFI_STATUS +InitializeCpuExceptionHandlersWorker ( + IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL + ) +{ + EFI_STATUS Status; + IA32_DESCRIPTOR IdtDescriptor; + UINTN IdtEntryCount; + EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap; + IA32_IDT_GATE_DESCRIPTOR *IdtTable; + + mReservedVectors = mReservedVectorsData; + SetMem ((VOID *) mReservedVectors, sizeof (RESERVED_VECTORS_DATA) * CPU_EXCEPTION_NUM, 0xff); + if (VectorInfo != NULL) { + Status = ReadAndVerifyVectorInfo (VectorInfo, mReservedVectors, CPU_EXCEPTION_NUM); + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + } + InitializeSpinLock (&mDisplayMessageSpinLock); + + mExternalInterruptHandler = mExternalInterruptHandlerTable; + // + // Read IDT descriptor and calculate IDT size + // + AsmReadIdtr (&IdtDescriptor); + IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR); + if (IdtEntryCount > CPU_EXCEPTION_NUM) { + // + // CPU exeption library only setup CPU_EXCEPTION_NUM exception handler at most + // + IdtEntryCount = CPU_EXCEPTION_NUM; + } + + IdtTable = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base; + AsmGetTemplateAddressMap (&TemplateMap); + ASSERT (TemplateMap.ExceptionStubHeaderSize <= HOOKAFTER_STUB_SIZE); + UpdateIdtTable (IdtTable, &TemplateMap, IdtEntryCount); + mEnabledInterruptNum = IdtEntryCount; + return EFI_SUCCESS; +} + +/** + Registers a function to be called from the processor interrupt handler. + + @param[in] InterruptType Defines which interrupt or exception to hook. + @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called + when a processor interrupt occurs. If this parameter is NULL, then the handler + will be uninstalled. + + @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was + previously installed. + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not + previously installed. + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported, + or this function is not supported. +**/ +EFI_STATUS +RegisterCpuInterruptHandlerWorker ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ) +{ + if (InterruptType < 0 || InterruptType >= (EFI_EXCEPTION_TYPE)mEnabledInterruptNum || + mReservedVectors[InterruptType].Attribute == EFI_VECTOR_HANDOFF_DO_NOT_HOOK) { + return EFI_UNSUPPORTED; + } + + if (InterruptHandler == NULL && mExternalInterruptHandler[InterruptType] == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (InterruptHandler != NULL && mExternalInterruptHandler[InterruptType] != NULL) { + return EFI_ALREADY_STARTED; + } + + mExternalInterruptHandler[InterruptType] = InterruptHandler; + return EFI_SUCCESS; +} + diff --git a/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c new file mode 100755 index 0000000000..40cdedface --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c @@ -0,0 +1,202 @@ +/** @file + IA32 CPU Exception Handler functons. + + Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CpuExceptionCommon.h" + +/** + Return address map of exception handler template so that C code can generate + exception tables. + + @param IdtEntry Pointer to IDT entry to be updated. + @param InterruptHandler IDT handler value. + +**/ +VOID +ArchUpdateIdtEntry ( + IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry, + IN UINTN InterruptHandler + ) +{ + IdtEntry->Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler; + IdtEntry->Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16); + IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; +} + +/** + Read IDT handler value from IDT entry. + + @param IdtEntry Pointer to IDT entry to be read. + +**/ +UINTN +ArchGetIdtHandler ( + IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry + ) +{ + return (UINTN)IdtEntry->Bits.OffsetLow + (((UINTN)IdtEntry->Bits.OffsetHigh) << 16); +} + +/** + Save CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case. + + @param ExceptionType Exception type. + @param SystemContext Pointer to EFI_SYSTEM_CONTEXT. + +**/ +VOID +ArchSaveExceptionContext ( + IN UINTN ExceptionType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + IA32_EFLAGS32 Eflags; + // + // Save Exception context in global variable + // + mReservedVectors[ExceptionType].OldFlags = SystemContext.SystemContextIa32->Eflags; + mReservedVectors[ExceptionType].OldCs = SystemContext.SystemContextIa32->Cs; + mReservedVectors[ExceptionType].OldIp = SystemContext.SystemContextIa32->Eip; + mReservedVectors[ExceptionType].ExceptionData = SystemContext.SystemContextIa32->ExceptionData; + // + // Clear IF flag to avoid old IDT handler enable interrupt by IRET + // + Eflags.UintN = SystemContext.SystemContextIa32->Eflags; + Eflags.Bits.IF = 0; + SystemContext.SystemContextIa32->Eflags = Eflags.UintN; + // + // Modify the EIP in stack, then old IDT handler will return to the stub code + // + SystemContext.SystemContextIa32->Eip = (UINTN) mReservedVectors[ExceptionType].HookAfterStubHeaderCode; +} + +/** + Restore CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case. + + @param ExceptionType Exception type. + @param SystemContext Pointer to EFI_SYSTEM_CONTEXT. +**/ +VOID +ArchRestoreExceptionContext ( + IN UINTN ExceptionType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + SystemContext.SystemContextIa32->Eflags = mReservedVectors[ExceptionType].OldFlags; + SystemContext.SystemContextIa32->Cs = mReservedVectors[ExceptionType].OldCs; + SystemContext.SystemContextIa32->Eip = mReservedVectors[ExceptionType].OldIp; + SystemContext.SystemContextIa32->ExceptionData = mReservedVectors[ExceptionType].ExceptionData; +} + +/** + Display CPU information. + + @param ExceptionType Exception type. + @param SystemContext Pointer to EFI_SYSTEM_CONTEXT. +**/ +VOID +DumpCpuContent ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + UINTN ImageBase; + UINTN EntryPoint; + + InternalPrintMessage ( + "!!!! IA32 Exception Type - %08x CPU Apic ID - %08x !!!!\n", + ExceptionType, + GetApicId () + ); + InternalPrintMessage ( + "EIP - %08x, CS - %08x, EFLAGS - %08x\n", + SystemContext.SystemContextIa32->Eip, + SystemContext.SystemContextIa32->Cs, + SystemContext.SystemContextIa32->Eflags + ); + if ((mErrorCodeFlag & (1 << ExceptionType)) != 0) { + InternalPrintMessage ( + "ExceptionData - %08x\n", + SystemContext.SystemContextIa32->ExceptionData + ); + } + InternalPrintMessage ( + "EAX - %08x, ECX - %08x, EDX - %08x, EBX - %08x\n", + SystemContext.SystemContextIa32->Eax, + SystemContext.SystemContextIa32->Ecx, + SystemContext.SystemContextIa32->Edx, + SystemContext.SystemContextIa32->Ebx + ); + InternalPrintMessage ( + "ESP - %08x, EBP - %08x, ESI - %08x, EDI - %08x\n", + SystemContext.SystemContextIa32->Esp, + SystemContext.SystemContextIa32->Ebp, + SystemContext.SystemContextIa32->Esi, + SystemContext.SystemContextIa32->Edi + ); + InternalPrintMessage ( + "DS - %08x, ES - %08x, FS - %08x, GS - %08x, SS - %08x\n", + SystemContext.SystemContextIa32->Ds, + SystemContext.SystemContextIa32->Es, + SystemContext.SystemContextIa32->Fs, + SystemContext.SystemContextIa32->Gs, + SystemContext.SystemContextIa32->Ss + ); + InternalPrintMessage ( + "CR0 - %08x, CR2 - %08x, CR3 - %08x, CR4 - %08x\n", + SystemContext.SystemContextIa32->Cr0, + SystemContext.SystemContextIa32->Cr2, + SystemContext.SystemContextIa32->Cr3, + SystemContext.SystemContextIa32->Cr4 + ); + InternalPrintMessage ( + "DR0 - %08x, DR1 - %08x, DR2 - %08x, DR3 - %08x\n", + SystemContext.SystemContextIa32->Dr0, + SystemContext.SystemContextIa32->Dr1, + SystemContext.SystemContextIa32->Dr2, + SystemContext.SystemContextIa32->Dr3 + ); + InternalPrintMessage ( + "DR6 - %08x, DR7 - %08x\n", + SystemContext.SystemContextIa32->Dr6, + SystemContext.SystemContextIa32->Dr7 + ); + InternalPrintMessage ( + "GDTR - %08x %08x, IDTR - %08x %08x\n", + SystemContext.SystemContextIa32->Gdtr[0], + SystemContext.SystemContextIa32->Gdtr[1], + SystemContext.SystemContextIa32->Idtr[0], + SystemContext.SystemContextIa32->Idtr[1] + ); + InternalPrintMessage ( + "LDTR - %08x, TR - %08x\n", + SystemContext.SystemContextIa32->Ldtr, + SystemContext.SystemContextIa32->Tr + ); + InternalPrintMessage ( + "FXSAVE_STATE - %08x\n", + &SystemContext.SystemContextIa32->FxSaveState + ); + + // + // Find module image base and module entry point by RIP + // + ImageBase = FindModuleImageBase (SystemContext.SystemContextIa32->Eip, &EntryPoint); + if (ImageBase != 0) { + InternalPrintMessage ( + " (ImageBase=%08x, EntryPoint=%08x) !!!!\n", + ImageBase, + EntryPoint + ); + } +} diff --git a/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchInterruptDefs.h b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchInterruptDefs.h new file mode 100755 index 0000000000..a8d3556a80 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchInterruptDefs.h @@ -0,0 +1,44 @@ +/** @file + Ia32 arch definition for CPU Exception Handler Library. + + Copyright (c) 2013, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _ARCH_CPU_INTERRUPT_DEFS_H_ +#define _ARCH_CPU_INTERRUPT_DEFS_H_ + +typedef struct { + EFI_SYSTEM_CONTEXT_IA32 SystemContext; + BOOLEAN ExceptionDataFlag; + UINTN OldIdtHandler; +} EXCEPTION_HANDLER_CONTEXT; + +// +// Register Structure Definitions +// +typedef struct { + EFI_STATUS_CODE_DATA Header; + EFI_SYSTEM_CONTEXT_IA32 SystemContext; +} CPU_STATUS_CODE_TEMPLATE; + +typedef struct { + SPIN_LOCK SpinLock; + UINT32 ApicId; + UINT32 Attribute; + UINTN ExceptonHandler; + UINTN OldFlags; + UINTN OldCs; + UINTN OldIp; + UINTN ExceptionData; + UINT8 HookAfterStubHeaderCode[HOOKAFTER_STUB_SIZE]; +} RESERVED_VECTORS_DATA; + +#endif diff --git a/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.S b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.S new file mode 100755 index 0000000000..086e896e44 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.S @@ -0,0 +1,642 @@ +#------------------------------------------------------------------------------ +#* +#* Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.
+#* This program and the accompanying materials +#* are licensed and made available under the terms and conditions of the BSD License +#* which accompanies this distribution. The full text of the license may be found at +#* http://opensource.org/licenses/bsd-license.php +#* +#* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +#* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +#* +#* ExceptionHandlerAsm.S +#* +#* Abstract: +#* +#* IA32 CPU Exception Handler +# +#------------------------------------------------------------------------------ + + +#.MMX +#.XMM + +ASM_GLOBAL ASM_PFX(CommonExceptionHandler) +ASM_GLOBAL ASM_PFX(CommonInterruptEntry) +ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd) + +#EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions +#EXTRN ASM_PFX(mDoFarReturnFlag):DWORD # Do far return flag + +.text + +# +# exception handler stub table +# +Exception0Handle: + .byte 0x6a # push #VectorNum + .byte 0 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception1Handle: + .byte 0x6a # push #VectorNum + .byte 1 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception2Handle: + .byte 0x6a # push #VectorNum + .byte 2 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception3Handle: + .byte 0x6a # push #VectorNum + .byte 3 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception4Handle: + .byte 0x6a # push #VectorNum + .byte 4 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception5Handle: + .byte 0x6a # push #VectorNum + .byte 5 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception6Handle: + .byte 0x6a # push #VectorNum + .byte 6 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception7Handle: + .byte 0x6a # push #VectorNum + .byte 7 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception8Handle: + .byte 0x6a # push #VectorNum + .byte 8 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception9Handle: + .byte 0x6a # push #VectorNum + .byte 9 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception10Handle: + .byte 0x6a # push #VectorNum + .byte 10 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception11Handle: + .byte 0x6a # push #VectorNum + .byte 11 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception12Handle: + .byte 0x6a # push #VectorNum + .byte 12 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception13Handle: + .byte 0x6a # push #VectorNum + .byte 13 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception14Handle: + .byte 0x6a # push #VectorNum + .byte 14 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception15Handle: + .byte 0x6a # push #VectorNum + .byte 15 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception16Handle: + .byte 0x6a # push #VectorNum + .byte 16 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception17Handle: + .byte 0x6a # push #VectorNum + .byte 17 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception18Handle: + .byte 0x6a # push #VectorNum + .byte 18 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception19Handle: + .byte 0x6a # push #VectorNum + .byte 19 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception20Handle: + .byte 0x6a # push #VectorNum + .byte 20 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception21Handle: + .byte 0x6a # push #VectorNum + .byte 21 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception22Handle: + .byte 0x6a # push #VectorNum + .byte 22 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception23Handle: + .byte 0x6a # push #VectorNum + .byte 23 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception24Handle: + .byte 0x6a # push #VectorNum + .byte 24 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception25Handle: + .byte 0x6a # push #VectorNum + .byte 25 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception26Handle: + .byte 0x6a # push #VectorNum + .byte 26 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception27Handle: + .byte 0x6a # push #VectorNum + .byte 27 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception28Handle: + .byte 0x6a # push #VectorNum + .byte 28 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception29Handle: + .byte 0x6a # push #VectorNum + .byte 29 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception30Handle: + .byte 0x6a # push #VectorNum + .byte 30 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax +Exception31Handle: + .byte 0x6a # push #VectorNum + .byte 31 + pushl %eax + .byte 0xB8 + .long ASM_PFX(CommonInterruptEntry) + jmp *%eax + +HookAfterStubBegin: + .byte 0x6a # push +VectorNum: + .byte 0 # 0 will be fixed + pushl %eax + .byte 0xB8 # movl ASM_PFX(HookAfterStubHeaderEnd), %eax + .long ASM_PFX(HookAfterStubHeaderEnd) + jmp *%eax +ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd) +ASM_PFX(HookAfterStubHeaderEnd): + popl %eax + subl $8, %esp # reserve room for filling exception data later + pushl 8(%esp) + xchgl (%esp), %ecx # get vector number + bt %ecx, ASM_PFX(mErrorCodeFlag) + jnc NoErrorData + pushl (%esp) # addition push if exception data needed +NoErrorData: + xchg (%esp), %ecx # restore ecx + pushl %eax + +#---------------------------------------; +# CommonInterruptEntry ; +#---------------------------------------; +# The follow algorithm is used for the common interrupt routine. + +ASM_GLOBAL ASM_PFX(CommonInterruptEntry) +ASM_PFX(CommonInterruptEntry): + cli + popl %eax + # + # All interrupt handlers are invoked through interrupt gates, so + # IF flag automatically cleared at the entry point + # + + # + # Get vector number from top of stack + # + xchgl (%esp), %ecx + andl $0x0FF, %ecx # Vector number should be less than 256 + cmpl $32, %ecx # Intel reserved vector for exceptions? + jae NoErrorCode + bt %ecx, ASM_PFX(mErrorCodeFlag) + jc HasErrorCode + +NoErrorCode: + + # + # Stack: + # +---------------------+ + # + EFlags + + # +---------------------+ + # + CS + + # +---------------------+ + # + EIP + + # +---------------------+ + # + ECX + + # +---------------------+ <-- ESP + # + # Registers: + # ECX - Vector Number + # + + # + # Put Vector Number on stack + # + pushl %ecx + + # + # Put 0 (dummy) error code on stack, and restore ECX + # + xorl %ecx, %ecx # ECX = 0 + xchgl 4(%esp), %ecx + + jmp ErrorCodeAndVectorOnStack + +HasErrorCode: + + # + # Stack: + # +---------------------+ + # + EFlags + + # +---------------------+ + # + CS + + # +---------------------+ + # + EIP + + # +---------------------+ + # + Error Code + + # +---------------------+ + # + ECX + + # +---------------------+ <-- ESP + # + # Registers: + # ECX - Vector Number + # + + # + # Put Vector Number on stack and restore ECX + # + xchgl (%esp), %ecx + +ErrorCodeAndVectorOnStack: + pushl %ebp + movl %esp, %ebp + + # + # Stack: + # +---------------------+ + # + EFlags + + # +---------------------+ + # + CS + + # +---------------------+ + # + EIP + + # +---------------------+ + # + Error Code + + # +---------------------+ + # + Vector Number + + # +---------------------+ + # + EBP + + # +---------------------+ <-- EBP + # + + # + # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32 + # is 16-byte aligned + # + andl $0x0fffffff0, %esp + subl $12, %esp + + subl $8, %esp + pushl $0 # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler + pushl $0 # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag + +#; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + pushl %eax + pushl %ecx + pushl %edx + pushl %ebx + leal 24(%ebp), %ecx + pushl %ecx # ESP + pushl (%ebp) # EBP + pushl %esi + pushl %edi + +#; UINT32 Gs, Fs, Es, Ds, Cs, Ss; + movl %ss, %eax + pushl %eax + movzwl 16(%ebp), %eax + pushl %eax + movl %ds, %eax + pushl %eax + movl %es, %eax + pushl %eax + movl %fs, %eax + pushl %eax + movl %gs, %eax + pushl %eax + +#; UINT32 Eip; + movl 12(%ebp), %eax + pushl %eax + +#; UINT32 Gdtr[2], Idtr[2]; + subl $8, %esp + sidt (%esp) + movl 2(%esp), %eax + xchgl (%esp), %eax + andl $0x0FFFF, %eax + movl %eax, 4(%esp) + + subl $8, %esp + sgdt (%esp) + movl 2(%esp), %eax + xchgl (%esp), %eax + andl $0x0FFFF, %eax + movl %eax, 4(%esp) + +#; UINT32 Ldtr, Tr; + xorl %eax, %eax + str %ax + pushl %eax + sldt %ax + pushl %eax + +#; UINT32 EFlags; + movl 20(%ebp), %eax + pushl %eax + +#; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + movl %cr4, %eax + orl $0x208, %eax + movl %eax, %cr4 + pushl %eax + movl %cr3, %eax + pushl %eax + movl %cr2, %eax + pushl %eax + xorl %eax, %eax + pushl %eax + movl %cr0, %eax + pushl %eax + +#; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + movl %dr7, %eax + pushl %eax + movl %dr6, %eax + pushl %eax + movl %dr3, %eax + pushl %eax + movl %dr2, %eax + pushl %eax + movl %dr1, %eax + pushl %eax + movl %dr0, %eax + pushl %eax + +#; FX_SAVE_STATE_IA32 FxSaveState; + subl $512, %esp + movl %esp, %edi + .byte 0x0f, 0x0ae, 0x07 #fxsave [edi] + +#; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear + cld + +#; UINT32 ExceptionData; + pushl 8(%ebp) + +#; Prepare parameter and call + movl %esp, %edx + pushl %edx + movl 4(%ebp), %edx + pushl %edx + + # + # Call External Exception Handler + # + call ASM_PFX(CommonExceptionHandler) + addl $8, %esp + + cli +#; UINT32 ExceptionData; + addl $4, %esp + +#; FX_SAVE_STATE_IA32 FxSaveState; + movl %esp, %esi + .byte 0x0f, 0x0ae, 0x0e # fxrstor [esi] + addl $512, %esp + +#; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; +#; Skip restoration of DRx registers to support in-circuit emualators +#; or debuggers set breakpoint in interrupt/exception context + addl $24, %esp + +#; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + popl %eax + movl %eax, %cr0 + addl $4, %esp # not for Cr1 + popl %eax + movl %eax, %cr2 + popl %eax + movl %eax, %cr3 + popl %eax + movl %eax, %cr4 + +#; UINT32 EFlags; + popl 20(%ebp) + +#; UINT32 Ldtr, Tr; +#; UINT32 Gdtr[2], Idtr[2]; +#; Best not let anyone mess with these particular registers... + addl $24, %esp + +#; UINT32 Eip; + popl 12(%ebp) + +#; UINT32 Gs, Fs, Es, Ds, Cs, Ss; +#; NOTE - modified segment registers could hang the debugger... We +#; could attempt to insulate ourselves against this possibility, +#; but that poses risks as well. +#; + popl %gs + popl %fs + popl %es + popl %ds + popl 16(%ebp) + popl %ss + +#; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + popl %edi + popl %esi + addl $4, %esp # not for ebp + addl $4, %esp # not for esp + popl %ebx + popl %edx + popl %ecx + popl %eax + + popl -8(%ebp) + popl -4(%ebp) + movl %ebp, %esp + popl %ebp + addl $8, %esp + cmpl $0, -16(%esp) # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler + jz DoReturn + cmpl $1, -20(%esp) # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag + jz ErrorCode + jmp *-16(%esp) +ErrorCode: + subl $4, %esp + jmp *-12(%esp) + +DoReturn: + cmpl $0, ASM_PFX(mDoFarReturnFlag) + jz DoIret + pushl 8(%esp) # save EFLAGS + addl $16, %esp + pushl -8(%esp) # save CS in new location + pushl -8(%esp) # save EIP in new location + pushl -8(%esp) # save EFLAGS in new location + popfl # restore EFLAGS + retf # far return + +DoIret: + iretl + + +#---------------------------------------; +# _AsmGetTemplateAddressMap ; +#---------------------------------------; +# +# Protocol prototype +# AsmGetTemplateAddressMap ( +# EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap +# ); +# +# Routine Description: +# +# Return address map of interrupt handler template so that C code can generate +# interrupt table. +# +# Arguments: +# +# +# Returns: +# +# Nothing +# +# +# Input: [ebp][0] = Original ebp +# [ebp][4] = Return address +# +# Output: Nothing +# +# Destroys: Nothing +#-----------------------------------------------------------------------------; +#------------------------------------------------------------------------------------- +# AsmGetAddressMap (&AddressMap); +#------------------------------------------------------------------------------------- +ASM_GLOBAL ASM_PFX(AsmGetTemplateAddressMap) +ASM_PFX(AsmGetTemplateAddressMap): + + pushl %ebp + movl %esp,%ebp + pushal + + movl 0x8(%ebp), %ebx + movl $Exception0Handle, (%ebx) + movl $(Exception1Handle - Exception0Handle), 0x4(%ebx) + movl $(HookAfterStubBegin), 0x8(%ebx) + + popal + popl %ebp + ret +#------------------------------------------------------------------------------------- +# AsmVectorNumFixup (*VectorBase, VectorNum, HookStub); +#------------------------------------------------------------------------------------- +ASM_GLOBAL ASM_PFX(AsmVectorNumFixup) +ASM_PFX(AsmVectorNumFixup): + movl 8(%esp), %eax + movl 4(%esp), %ecx + movb %al, (VectorNum - HookAfterStubBegin)(%ecx) + ret diff --git a/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.asm b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.asm new file mode 100755 index 0000000000..90da51bd6a --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.asm @@ -0,0 +1,445 @@ +;------------------------------------------------------------------------------ ; +; Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; ExceptionHandlerAsm.Asm +; +; Abstract: +; +; IA32 CPU Exception Handler +; +; Notes: +; +;------------------------------------------------------------------------------ + + .686 + .model flat,C + +; +; CommonExceptionHandler() +; +CommonExceptionHandler PROTO C + +.data + +EXTRN mErrorCodeFlag:DWORD ; Error code flags for exceptions +EXTRN mDoFarReturnFlag:DWORD ; Do far return flag + +.code + +ALIGN 8 + +; +; exception handler stub table +; +AsmIdtVectorBegin: +REPEAT 32 + db 6ah ; push #VectorNum + db ($ - AsmIdtVectorBegin) / ((AsmIdtVectorEnd - AsmIdtVectorBegin) / 32) ; VectorNum + push eax + mov eax, CommonInterruptEntry + jmp eax +ENDM +AsmIdtVectorEnd: + +HookAfterStubBegin: + db 6ah ; push +VectorNum: + db 0 ; 0 will be fixed + push eax + mov eax, HookAfterStubHeaderEnd + jmp eax +HookAfterStubHeaderEnd: + pop eax + sub esp, 8 ; reserve room for filling exception data later + push [esp + 8] + xchg ecx, [esp] ; get vector number + bt mErrorCodeFlag, ecx + jnc @F + push [esp] ; addition push if exception data needed +@@: + xchg ecx, [esp] ; restore ecx + push eax + +;----------------------------------------------------------------------------; +; CommonInterruptEntry ; +;----------------------------------------------------------------------------; +; The follow algorithm is used for the common interrupt routine. +; Entry from each interrupt with a push eax and eax=interrupt number +; Stack: +; +---------------------+ +; + EFlags + +; +---------------------+ +; + CS + +; +---------------------+ +; + EIP + +; +---------------------+ +; + Error Code + +; +---------------------+ +; + Vector Number + +; +---------------------+ +; + EBP + +; +---------------------+ <-- EBP +CommonInterruptEntry PROC PUBLIC + cli + pop eax + ; + ; All interrupt handlers are invoked through interrupt gates, so + ; IF flag automatically cleared at the entry point + ; + + ; + ; Get vector number from top of stack + ; + xchg ecx, [esp] + and ecx, 0FFh ; Vector number should be less than 256 + cmp ecx, 32 ; Intel reserved vector for exceptions? + jae NoErrorCode + bt mErrorCodeFlag, ecx + jc HasErrorCode + +NoErrorCode: + + ; + ; Stack: + ; +---------------------+ + ; + EFlags + + ; +---------------------+ + ; + CS + + ; +---------------------+ + ; + EIP + + ; +---------------------+ + ; + ECX + + ; +---------------------+ <-- ESP + ; + ; Registers: + ; ECX - Vector Number + ; + + ; + ; Put Vector Number on stack + ; + push ecx + + ; + ; Put 0 (dummy) error code on stack, and restore ECX + ; + xor ecx, ecx ; ECX = 0 + xchg ecx, [esp+4] + + jmp ErrorCodeAndVectorOnStack + +HasErrorCode: + + ; + ; Stack: + ; +---------------------+ + ; + EFlags + + ; +---------------------+ + ; + CS + + ; +---------------------+ + ; + EIP + + ; +---------------------+ + ; + Error Code + + ; +---------------------+ + ; + ECX + + ; +---------------------+ <-- ESP + ; + ; Registers: + ; ECX - Vector Number + ; + + ; + ; Put Vector Number on stack and restore ECX + ; + xchg ecx, [esp] + +ErrorCodeAndVectorOnStack: + push ebp + mov ebp, esp + + ; + ; Stack: + ; +---------------------+ + ; + EFlags + + ; +---------------------+ + ; + CS + + ; +---------------------+ + ; + EIP + + ; +---------------------+ + ; + Error Code + + ; +---------------------+ + ; + Vector Number + + ; +---------------------+ + ; + EBP + + ; +---------------------+ <-- EBP + ; + + ; + ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32 + ; is 16-byte aligned + ; + and esp, 0fffffff0h + sub esp, 12 + + sub esp, 8 + push 0 ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler + push 0 ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag + +;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + push eax + push ecx + push edx + push ebx + lea ecx, [ebp + 6 * 4] + push ecx ; ESP + push dword ptr [ebp] ; EBP + push esi + push edi + +;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; + mov eax, ss + push eax + movzx eax, word ptr [ebp + 4 * 4] + push eax + mov eax, ds + push eax + mov eax, es + push eax + mov eax, fs + push eax + mov eax, gs + push eax + +;; UINT32 Eip; + mov eax, [ebp + 3 * 4] + push eax + +;; UINT32 Gdtr[2], Idtr[2]; + sub esp, 8 + sidt [esp] + mov eax, [esp + 2] + xchg eax, [esp] + and eax, 0FFFFh + mov [esp+4], eax + + sub esp, 8 + sgdt [esp] + mov eax, [esp + 2] + xchg eax, [esp] + and eax, 0FFFFh + mov [esp+4], eax + +;; UINT32 Ldtr, Tr; + xor eax, eax + str ax + push eax + sldt ax + push eax + +;; UINT32 EFlags; + mov eax, [ebp + 5 * 4] + push eax + +;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + mov eax, cr4 + or eax, 208h + mov cr4, eax + push eax + mov eax, cr3 + push eax + mov eax, cr2 + push eax + xor eax, eax + push eax + mov eax, cr0 + push eax + +;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + mov eax, dr7 + push eax + mov eax, dr6 + push eax + mov eax, dr3 + push eax + mov eax, dr2 + push eax + mov eax, dr1 + push eax + mov eax, dr0 + push eax + +;; FX_SAVE_STATE_IA32 FxSaveState; + sub esp, 512 + mov edi, esp + db 0fh, 0aeh, 07h ;fxsave [edi] + +;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear + cld + +;; UINT32 ExceptionData; + push dword ptr [ebp + 2 * 4] + +;; Prepare parameter and call + mov edx, esp + push edx + mov edx, dword ptr [ebp + 1 * 4] + push edx + + ; + ; Call External Exception Handler + ; + mov eax, CommonExceptionHandler + call eax + add esp, 8 + + cli +;; UINT32 ExceptionData; + add esp, 4 + +;; FX_SAVE_STATE_IA32 FxSaveState; + mov esi, esp + db 0fh, 0aeh, 0eh ; fxrstor [esi] + add esp, 512 + +;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; +;; Skip restoration of DRx registers to support in-circuit emualators +;; or debuggers set breakpoint in interrupt/exception context + add esp, 4 * 6 + +;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + pop eax + mov cr0, eax + add esp, 4 ; not for Cr1 + pop eax + mov cr2, eax + pop eax + mov cr3, eax + pop eax + mov cr4, eax + +;; UINT32 EFlags; + pop dword ptr [ebp + 5 * 4] + +;; UINT32 Ldtr, Tr; +;; UINT32 Gdtr[2], Idtr[2]; +;; Best not let anyone mess with these particular registers... + add esp, 24 + +;; UINT32 Eip; + pop dword ptr [ebp + 3 * 4] + +;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; +;; NOTE - modified segment registers could hang the debugger... We +;; could attempt to insulate ourselves against this possibility, +;; but that poses risks as well. +;; + pop gs + pop fs + pop es + pop ds + pop dword ptr [ebp + 4 * 4] + pop ss + +;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + pop edi + pop esi + add esp, 4 ; not for ebp + add esp, 4 ; not for esp + pop ebx + pop edx + pop ecx + pop eax + + pop dword ptr [ebp - 8] + pop dword ptr [ebp - 4] + mov esp, ebp + pop ebp + add esp, 8 + cmp dword ptr [esp - 16], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler + jz DoReturn + cmp dword ptr [esp - 20], 1 ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag + jz ErrorCode + jmp dword ptr [esp - 16] +ErrorCode: + sub esp, 4 + jmp dword ptr [esp - 12] + +DoReturn: + cmp mDoFarReturnFlag, 0 ; Check if need to do far return instead of IRET + jz DoIret + push [esp + 8] ; save EFLAGS + add esp, 16 + push [esp - 8] ; save CS in new location + push [esp - 8] ; save EIP in new location + push [esp - 8] ; save EFLAGS in new location + popfd ; restore EFLAGS + retf ; far return + +DoIret: + iretd + +CommonInterruptEntry ENDP + +;---------------------------------------; +; _AsmGetTemplateAddressMap ; +;----------------------------------------------------------------------------; +; +; Protocol prototype +; AsmGetTemplateAddressMap ( +; EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap +; ); +; +; Routine Description: +; +; Return address map of interrupt handler template so that C code can generate +; interrupt table. +; +; Arguments: +; +; +; Returns: +; +; Nothing +; +; +; Input: [ebp][0] = Original ebp +; [ebp][4] = Return address +; +; Output: Nothing +; +; Destroys: Nothing +;-----------------------------------------------------------------------------; +AsmGetTemplateAddressMap proc near public + push ebp ; C prolog + mov ebp, esp + pushad + + mov ebx, dword ptr [ebp + 08h] + mov dword ptr [ebx], AsmIdtVectorBegin + mov dword ptr [ebx + 4h], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32 + mov dword ptr [ebx + 8h], HookAfterStubBegin + + popad + pop ebp + ret +AsmGetTemplateAddressMap ENDP + +;------------------------------------------------------------------------------------- +; AsmVectorNumFixup (*VectorBase, VectorNum, HookStub); +;------------------------------------------------------------------------------------- +AsmVectorNumFixup proc near public + mov eax, dword ptr [esp + 8] + mov ecx, [esp + 4] + mov [ecx + (VectorNum - HookAfterStubBegin)], al + ret +AsmVectorNumFixup ENDP +END diff --git a/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c new file mode 100755 index 0000000000..7e94e38ae1 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c @@ -0,0 +1,183 @@ +/** @file + CPU exception handler library implemenation for SEC/PEIM modules. + +Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include "CpuExceptionCommon.h" + +// +// Image Aglinment size for SEC/PEI phase +// +CONST UINTN mImageAlignSize = 4; +CONST UINTN mDoFarReturnFlag = 0; + +/** + Common exception handler. + + @param ExceptionType Exception type. + @param SystemContext Pointer to EFI_SYSTEM_CONTEXT. +**/ +VOID +EFIAPI +CommonExceptionHandler ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + // + // Display ExceptionType, CPU information and Image information + // + DumpCpuContent (ExceptionType, SystemContext); + + // + // Enter a dead loop. + // + CpuDeadLoop (); +} + +/** + Initializes all CPU exceptions entries and provides the default exception handlers. + + Caller should try to get an array of interrupt and/or exception vectors that are in use and need to + persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification. + If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL. + If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly. + Note: Before invoking this API, caller must allocate memory for IDT table and load + IDTR by AsmWriteIdtr(). + + @param[in] VectorInfo Pointer to reserved vector list. + + @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized + with default exception handlers. + @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL. + @retval EFI_UNSUPPORTED This function is not supported. + +**/ +EFI_STATUS +EFIAPI +InitializeCpuExceptionHandlers ( + IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL + ) +{ + EFI_STATUS Status; + RESERVED_VECTORS_DATA ReservedVectorData[CPU_EXCEPTION_NUM]; + IA32_DESCRIPTOR IdtDescriptor; + UINTN IdtEntryCount; + UINT16 CodeSegment; + EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap; + IA32_IDT_GATE_DESCRIPTOR *IdtTable; + UINTN Index; + UINTN InterruptHandler; + + if (VectorInfo != NULL) { + SetMem ((VOID *) ReservedVectorData, sizeof (RESERVED_VECTORS_DATA) * CPU_EXCEPTION_NUM, 0xff); + Status = ReadAndVerifyVectorInfo (VectorInfo, ReservedVectorData, CPU_EXCEPTION_NUM); + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + } + // + // Read IDT descriptor and calculate IDT size + // + AsmReadIdtr (&IdtDescriptor); + IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR); + if (IdtEntryCount > CPU_EXCEPTION_NUM) { + // + // CPU exeption library only setup CPU_EXCEPTION_NUM exception handler at most + // + IdtEntryCount = CPU_EXCEPTION_NUM; + } + // + // Use current CS as the segment selector of interrupt gate in IDT + // + CodeSegment = AsmReadCs (); + + AsmGetTemplateAddressMap (&TemplateMap); + IdtTable = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base; + for (Index = 0; Index < IdtEntryCount; Index ++) { + IdtTable[Index].Bits.Selector = CodeSegment; + // + // Check reserved vectors attributes if has, only EFI_VECTOR_HANDOFF_DO_NOT_HOOK + // supported in this instance + // + if (VectorInfo != NULL) { + if (ReservedVectorData[Index].Attribute == EFI_VECTOR_HANDOFF_DO_NOT_HOOK) { + continue; + } + } + // + // Update IDT entry + // + InterruptHandler = TemplateMap.ExceptionStart + Index * TemplateMap.ExceptionStubHeaderSize; + ArchUpdateIdtEntry (&IdtTable[Index], InterruptHandler); + } + return EFI_SUCCESS; +} + +/** + Initializes all CPU interrupt/exceptions entries and provides the default interrupt/exception handlers. + + Caller should try to get an array of interrupt and/or exception vectors that are in use and need to + persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification. + If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL. + If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly. + + @param[in] VectorInfo Pointer to reserved vector list. + + @retval EFI_SUCCESS All CPU interrupt/exception entries have been successfully initialized + with default interrupt/exception handlers. + @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL. + @retval EFI_UNSUPPORTED This function is not supported. + +**/ +EFI_STATUS +EFIAPI +InitializeCpuInterruptHandlers ( + IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Registers a function to be called from the processor interrupt handler. + + This function registers and enables the handler specified by InterruptHandler for a processor + interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the + handler for the processor interrupt or exception type specified by InterruptType is uninstalled. + The installed handler is called once for each processor interrupt or exception. + NOTE: This function should be invoked after InitializeCpuExceptionHandlers() or + InitializeCpuInterruptHandlers() invoked, otherwise EFI_UNSUPPORTED returned. + + @param[in] InterruptType Defines which interrupt or exception to hook. + @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called + when a processor interrupt occurs. If this parameter is NULL, then the handler + will be uninstalled. + + @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was + previously installed. + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not + previously installed. + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported, + or this function is not supported. +**/ +EFI_STATUS +EFIAPI +RegisterCpuInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ) +{ + return EFI_UNSUPPORTED; +} \ No newline at end of file diff --git a/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf new file mode 100755 index 0000000000..dfd7562898 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf @@ -0,0 +1,57 @@ +## @file +# CPU Exception Handler library instance for SEC/PEI modules. +# +# Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SecPeiCpuExceptionHandlerLib + MODULE_UNI_FILE = SecPeiCpuExceptionHandlerLib.uni + FILE_GUID = CA4BBC99-DFC6-4234-B553-8B6586B7B113 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + LIBRARY_CLASS = CpuExceptionHandlerLib|SEC PEI_CORE PEIM + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.Ia32] + Ia32/ExceptionHandlerAsm.asm + Ia32/ExceptionHandlerAsm.S |GCC + Ia32/ArchExceptionHandler.c + Ia32/ArchInterruptDefs.h + +[Sources.X64] + X64/ExceptionHandlerAsm.asm + X64/ExceptionHandlerAsm.S |GCC + X64/ArchExceptionHandler.c + X64/ArchInterruptDefs.h + +[Sources.common] + CpuExceptionCommon.h + CpuExceptionCommon.c + SecPeiCpuException.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + CloverEFI/UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + SerialPortLib + PrintLib + LocalApicLib + PeCoffGetEntryPointLib diff --git a/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.uni b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.uni new file mode 100755 index 0000000000..af45a33874 Binary files /dev/null and b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.uni differ diff --git a/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf new file mode 100755 index 0000000000..37031204c6 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf @@ -0,0 +1,61 @@ +## @file +# CPU Exception Handler library instance for SMM modules. +# +# Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SmmCpuExceptionHandlerLib + MODULE_UNI_FILE = SmmCpuExceptionHandlerLib.uni + FILE_GUID = 8D2C439B-3981-42ff-9CE5-1B50ECA502D6 + MODULE_TYPE = DXE_SMM_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = CpuExceptionHandlerLib|DXE_SMM_DRIVER + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.Ia32] + Ia32/ExceptionHandlerAsm.asm + Ia32/ExceptionHandlerAsm.S |GCC + Ia32/ArchExceptionHandler.c + Ia32/ArchInterruptDefs.h + +[Sources.X64] + X64/ExceptionHandlerAsm.asm + X64/ExceptionHandlerAsm.S |GCC + X64/ArchExceptionHandler.c + X64/ArchInterruptDefs.h + +[Sources.common] + CpuExceptionCommon.h + CpuExceptionCommon.c + DxeSmmCpuException.c + SmmException.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + CloverEFI/UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + SerialPortLib + PrintLib + SynchronizationLib + LocalApicLib + PeCoffGetEntryPointLib + DebugLib + diff --git a/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.uni b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.uni new file mode 100755 index 0000000000..6d3ee1c9eb Binary files /dev/null and b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.uni differ diff --git a/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmException.c b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmException.c new file mode 100755 index 0000000000..40f1250266 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmException.c @@ -0,0 +1,101 @@ +/** @file + CPU exception handler library implemenation for SMM modules. + + Copyright (c) 2013, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include "CpuExceptionCommon.h" + +CONST UINTN mDoFarReturnFlag = 1; + +/** + Initializes all CPU exceptions entries and provides the default exception handlers. + + Caller should try to get an array of interrupt and/or exception vectors that are in use and need to + persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification. + If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL. + If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly. + + @param[in] VectorInfo Pointer to reserved vector list. + + @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized + with default exception handlers. + @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL. + @retval EFI_UNSUPPORTED This function is not supported. + +**/ +EFI_STATUS +EFIAPI +InitializeCpuExceptionHandlers ( + IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL + ) +{ + return InitializeCpuExceptionHandlersWorker (VectorInfo); +} + +/** + Initializes all CPU interrupt/exceptions entries and provides the default interrupt/exception handlers. + + Caller should try to get an array of interrupt and/or exception vectors that are in use and need to + persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification. + If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL. + If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly. + + @param[in] VectorInfo Pointer to reserved vector list. + + @retval EFI_SUCCESS All CPU interrupt/exception entries have been successfully initialized + with default interrupt/exception handlers. + @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL. + @retval EFI_UNSUPPORTED This function is not supported. + +**/ +EFI_STATUS +EFIAPI +InitializeCpuInterruptHandlers ( + IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Registers a function to be called from the processor interrupt handler. + + This function registers and enables the handler specified by InterruptHandler for a processor + interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the + handler for the processor interrupt or exception type specified by InterruptType is uninstalled. + The installed handler is called once for each processor interrupt or exception. + NOTE: This function should be invoked after InitializeCpuExceptionHandlers() or + InitializeCpuInterruptHandlers() invoked, otherwise EFI_UNSUPPORTED returned. + + @param[in] InterruptType Defines which interrupt or exception to hook. + @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called + when a processor interrupt occurs. If this parameter is NULL, then the handler + will be uninstalled. + + @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was + previously installed. + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not + previously installed. + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported, + or this function is not supported. +**/ +EFI_STATUS +EFIAPI +RegisterCpuInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ) +{ + return RegisterCpuInterruptHandlerWorker (InterruptType, InterruptHandler); +} \ No newline at end of file diff --git a/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c new file mode 100755 index 0000000000..ee16ea856a --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c @@ -0,0 +1,233 @@ +/** @file + x64 CPU Exception Handler. + + Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CpuExceptionCommon.h" + +/** + Return address map of exception handler template so that C code can generate + exception tables. + + @param IdtEntry Pointer to IDT entry to be updated. + @param InterruptHandler IDT handler value. +**/ +VOID +ArchUpdateIdtEntry ( + IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry, + IN UINTN InterruptHandler + ) +{ + IdtEntry->Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler; + IdtEntry->Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16); + IdtEntry->Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32); + IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; +} + +/** + Read IDT handler value from IDT entry. + + @param IdtEntry Pointer to IDT entry to be read. + +**/ +UINTN +ArchGetIdtHandler ( + IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry + ) +{ + return IdtEntry->Bits.OffsetLow + (((UINTN) IdtEntry->Bits.OffsetHigh) << 16) + + (((UINTN) IdtEntry->Bits.OffsetUpper) << 32); +} + +/** + Save CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case. + + @param ExceptionType Exception type. + @param SystemContext Pointer to EFI_SYSTEM_CONTEXT. +**/ +VOID +ArchSaveExceptionContext ( + IN UINTN ExceptionType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + IA32_EFLAGS32 Eflags; + // + // Save Exception context in global variable + // + mReservedVectors[ExceptionType].OldSs = SystemContext.SystemContextX64->Ss; + mReservedVectors[ExceptionType].OldSp = SystemContext.SystemContextX64->Rsp; + mReservedVectors[ExceptionType].OldFlags = SystemContext.SystemContextX64->Rflags; + mReservedVectors[ExceptionType].OldCs = SystemContext.SystemContextX64->Cs; + mReservedVectors[ExceptionType].OldIp = SystemContext.SystemContextX64->Rip; + mReservedVectors[ExceptionType].ExceptionData = SystemContext.SystemContextX64->ExceptionData; + // + // Clear IF flag to avoid old IDT handler enable interrupt by IRET + // + Eflags.UintN = SystemContext.SystemContextX64->Rflags; + Eflags.Bits.IF = 0; + SystemContext.SystemContextX64->Rflags = Eflags.UintN; + // + // Modify the EIP in stack, then old IDT handler will return to the stub code + // + SystemContext.SystemContextX64->Rip = (UINTN) mReservedVectors[ExceptionType].HookAfterStubHeaderCode; +} + +/** + Restore CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case. + + @param ExceptionType Exception type. + @param SystemContext Pointer to EFI_SYSTEM_CONTEXT. +**/ +VOID +ArchRestoreExceptionContext ( + IN UINTN ExceptionType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + SystemContext.SystemContextX64->Ss = mReservedVectors[ExceptionType].OldSs; + SystemContext.SystemContextX64->Rsp = mReservedVectors[ExceptionType].OldSp; + SystemContext.SystemContextX64->Rflags = mReservedVectors[ExceptionType].OldFlags; + SystemContext.SystemContextX64->Cs = mReservedVectors[ExceptionType].OldCs; + SystemContext.SystemContextX64->Rip = mReservedVectors[ExceptionType].OldIp; + SystemContext.SystemContextX64->ExceptionData = mReservedVectors[ExceptionType].ExceptionData; +} + +/** + Display CPU information. + + @param ExceptionType Exception type. + @param SystemContext Pointer to EFI_SYSTEM_CONTEXT. +**/ +VOID +DumpCpuContent ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + UINTN ImageBase; + UINTN EntryPoint; + + InternalPrintMessage ( + "!!!! X64 Exception Type - %016lx CPU Apic ID - %08x !!!!\n", + ExceptionType, + GetApicId () + ); + InternalPrintMessage ( + "RIP - %016lx, CS - %016lx, RFLAGS - %016lx\n", + SystemContext.SystemContextX64->Rip, + SystemContext.SystemContextX64->Cs, + SystemContext.SystemContextX64->Rflags + ); + if (mErrorCodeFlag & (1 << ExceptionType)) { + InternalPrintMessage ( + "ExceptionData - %016lx\n", + SystemContext.SystemContextX64->ExceptionData + ); + } + InternalPrintMessage ( + "RAX - %016lx, RCX - %016lx, RDX - %016lx\n", + SystemContext.SystemContextX64->Rax, + SystemContext.SystemContextX64->Rcx, + SystemContext.SystemContextX64->Rdx + ); + InternalPrintMessage ( + "RBX - %016lx, RSP - %016lx, RBP - %016lx\n", + SystemContext.SystemContextX64->Rbx, + SystemContext.SystemContextX64->Rsp, + SystemContext.SystemContextX64->Rbp + ); + InternalPrintMessage ( + "RSI - %016lx, RDI - %016lx\n", + SystemContext.SystemContextX64->Rsi, + SystemContext.SystemContextX64->Rdi + ); + InternalPrintMessage ( + "R8 - %016lx, R9 - %016lx, R10 - %016lx\n", + SystemContext.SystemContextX64->R8, + SystemContext.SystemContextX64->R9, + SystemContext.SystemContextX64->R10 + ); + InternalPrintMessage ( + "R11 - %016lx, R12 - %016lx, R13 - %016lx\n", + SystemContext.SystemContextX64->R11, + SystemContext.SystemContextX64->R12, + SystemContext.SystemContextX64->R13 + ); + InternalPrintMessage ( + "R14 - %016lx, R15 - %016lx\n", + SystemContext.SystemContextX64->R14, + SystemContext.SystemContextX64->R15 + ); + InternalPrintMessage ( + "DS - %016lx, ES - %016lx, FS - %016lx\n", + SystemContext.SystemContextX64->Ds, + SystemContext.SystemContextX64->Es, + SystemContext.SystemContextX64->Fs + ); + InternalPrintMessage ( + "GS - %016lx, SS - %016lx\n", + SystemContext.SystemContextX64->Gs, + SystemContext.SystemContextX64->Ss + ); + InternalPrintMessage ( + "CR0 - %016lx, CR2 - %016lx, CR3 - %016lx\n", + SystemContext.SystemContextX64->Cr0, + SystemContext.SystemContextX64->Cr2, + SystemContext.SystemContextX64->Cr3 + ); + InternalPrintMessage ( + "CR4 - %016lx, CR8 - %016lx\n", + SystemContext.SystemContextX64->Cr4, + SystemContext.SystemContextX64->Cr8 + ); + InternalPrintMessage ( + "DR0 - %016lx, DR1 - %016lx, DR2 - %016lx\n", + SystemContext.SystemContextX64->Dr0, + SystemContext.SystemContextX64->Dr1, + SystemContext.SystemContextX64->Dr2 + ); + InternalPrintMessage ( + "DR3 - %016lx, DR6 - %016lx, DR7 - %016lx\n", + SystemContext.SystemContextX64->Dr3, + SystemContext.SystemContextX64->Dr6, + SystemContext.SystemContextX64->Dr7 + ); + InternalPrintMessage ( + "GDTR - %016lx %016lx, LDTR - %016lx\n", + SystemContext.SystemContextX64->Gdtr[0], + SystemContext.SystemContextX64->Gdtr[1], + SystemContext.SystemContextX64->Ldtr + ); + InternalPrintMessage ( + "IDTR - %016lx %016lx, TR - %016lx\n", + SystemContext.SystemContextX64->Idtr[0], + SystemContext.SystemContextX64->Idtr[1], + SystemContext.SystemContextX64->Tr + ); + InternalPrintMessage ( + "FXSAVE_STATE - %016lx\n", + &SystemContext.SystemContextX64->FxSaveState + ); + + // + // Find module image base and module entry point by RIP + // + ImageBase = FindModuleImageBase (SystemContext.SystemContextX64->Rip, &EntryPoint); + if (ImageBase != 0) { + InternalPrintMessage ( + " (ImageBase=%016lx, EntryPoint=%016lx) !!!!\n", + ImageBase, + EntryPoint + ); + } +} diff --git a/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchInterruptDefs.h b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchInterruptDefs.h new file mode 100755 index 0000000000..906480134a --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchInterruptDefs.h @@ -0,0 +1,46 @@ +/** @file + X64 arch definition for CPU Exception Handler Library. + + Copyright (c) 2013, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _ARCH_CPU_INTERRUPT_DEFS_H_ +#define _ARCH_CPU_INTERRUPT_DEFS_H_ + +typedef struct { + EFI_SYSTEM_CONTEXT_X64 SystemContext; + BOOLEAN ExceptionDataFlag; + UINTN OldIdtHandler; +} EXCEPTION_HANDLER_CONTEXT; + +// +// Register Structure Definitions +// +typedef struct { + EFI_STATUS_CODE_DATA Header; + EFI_SYSTEM_CONTEXT_X64 SystemContext; +} CPU_STATUS_CODE_TEMPLATE; + +typedef struct { + SPIN_LOCK SpinLock; + UINT32 ApicId; + UINT32 Attribute; + UINTN ExceptonHandler; + UINTN OldSs; + UINTN OldSp; + UINTN OldFlags; + UINTN OldCs; + UINTN OldIp; + UINTN ExceptionData; + UINT8 HookAfterStubHeaderCode[HOOKAFTER_STUB_SIZE]; +} RESERVED_VECTORS_DATA; + +#endif diff --git a/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.S b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.S new file mode 100755 index 0000000000..7711d274b1 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.S @@ -0,0 +1,641 @@ +#------------------------------------------------------------------------------ ; +# Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# ExceptionHandlerAsm.S +# +# Abstract: +# +# x64 CPU Exception Handler +# +# Notes: +# +#------------------------------------------------------------------------------ + + + +ASM_GLOBAL ASM_PFX(CommonExceptionHandler) +#ASM_GLOBAL ASM_PFX(CommonInterruptEntry) +#ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd) + +#EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions +#EXTRN ASM_PFX(mDoFarReturnFlag):QWORD # Do far return flag +.text +.align 3 + +# +# exception handler stub table +# +Exception0Handle: + .byte 0x6a # push #VectorNum + .byte 0 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception1Handle: + .byte 0x6a # push #VectorNum + .byte 1 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception2Handle: + .byte 0x6a # push #VectorNum + .byte 2 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception3Handle: + .byte 0x6a # push #VectorNum + .byte 3 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception4Handle: + .byte 0x6a # push #VectorNum + .byte 4 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception5Handle: + .byte 0x6a # push #VectorNum + .byte 5 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception6Handle: + .byte 0x6a # push #VectorNum + .byte 6 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception7Handle: + .byte 0x6a # push #VectorNum + .byte 7 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception8Handle: + .byte 0x6a # push #VectorNum + .byte 8 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception9Handle: + .byte 0x6a # push #VectorNum + .byte 9 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception10Handle: + .byte 0x6a # push #VectorNum + .byte 10 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception11Handle: + .byte 0x6a # push #VectorNum + .byte 11 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception12Handle: + .byte 0x6a # push #VectorNum + .byte 12 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception13Handle: + .byte 0x6a # push #VectorNum + .byte 13 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception14Handle: + .byte 0x6a # push #VectorNum + .byte 14 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception15Handle: + .byte 0x6a # push #VectorNum + .byte 15 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception16Handle: + .byte 0x6a # push #VectorNum + .byte 16 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception17Handle: + .byte 0x6a # push #VectorNum + .byte 17 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception18Handle: + .byte 0x6a # push #VectorNum + .byte 18 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception19Handle: + .byte 0x6a # push #VectorNum + .byte 19 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception20Handle: + .byte 0x6a # push #VectorNum + .byte 20 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception21Handle: + .byte 0x6a # push #VectorNum + .byte 21 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception22Handle: + .byte 0x6a # push #VectorNum + .byte 22 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception23Handle: + .byte 0x6a # push #VectorNum + .byte 23 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception24Handle: + .byte 0x6a # push #VectorNum + .byte 24 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception25Handle: + .byte 0x6a # push #VectorNum + .byte 25 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception26Handle: + .byte 0x6a # push #VectorNum + .byte 26 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception27Handle: + .byte 0x6a # push #VectorNum + .byte 27 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception28Handle: + .byte 0x6a # push #VectorNum + .byte 28 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception29Handle: + .byte 0x6a # push #VectorNum + .byte 29 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception30Handle: + .byte 0x6a # push #VectorNum + .byte 30 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax +Exception31Handle: + .byte 0x6a # push #VectorNum + .byte 31 + pushq %rax + .byte 0x48, 0xB8 + .quad 0 #ASM_PFX(CommonInterruptEntry) + jmp *%rax + +HookAfterStubHeaderBegin: + .byte 0x6a # push +#VectorNum: +PatchVectorNum: + .byte 0 # 0 will be fixed + pushq %rax + .byte 0x48, 0xB8 # movq ASM_PFX(HookAfterStubHeaderEnd), %rax +# .quad ASM_PFX(HookAfterStubHeaderEnd) +PatchFuncAddress: + .quad 0 + jmp *%rax +ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd) +ASM_PFX(HookAfterStubHeaderEnd): + movq %rsp, %rax + andl $0x0fffffff0, %esp # make sure 16-byte aligned for exception context + subq $0x18, %rsp # reserve room for filling exception data later + pushq %rcx + movq 8(%rax), %rcx +# pushq %rax +# movabsl ASM_PFX(mErrorCodeFlag), %eax +# bt %ecx, %eax +# popq %rax + bt %ecx, ASM_PFX(mErrorCodeFlag)(%rip) + jnc NoErrorData + pushq (%rsp) # push additional rcx to make stack alignment +NoErrorData: + xchgq (%rsp), %rcx # restore rcx, save Exception Number in stack + pushq (%rax) # push rax into stack to keep code consistence + +#---------------------------------------; +# CommonInterruptEntry ; +#---------------------------------------; +# The follow algorithm is used for the common interrupt routine. + +ASM_GLOBAL ASM_PFX(CommonInterruptEntry) +ASM_PFX(CommonInterruptEntry): + cli + popq %rax + # + # All interrupt handlers are invoked through interrupt gates, so + # IF flag automatically cleared at the entry point + # + # + # Calculate vector number + # + xchgq (%rsp), %rcx # get the return address of call, actually, it is the address of vector number. + andq $0x0FF, %rcx + cmp $32, %ecx # Intel reserved vector for exceptions? + jae NoErrorCode + pushq %rax +# movabsl ASM_PFX(mErrorCodeFlag), %eax + movl ASM_PFX(mErrorCodeFlag)(%rip), %eax + bt %ecx, %eax + popq %rax + jc CommonInterruptEntry_al_0000 + +NoErrorCode: + + # + # Push a dummy error code on the stack + # to maintain coherent stack map + # + pushq (%rsp) + movq $0, 8(%rsp) +CommonInterruptEntry_al_0000: + pushq %rbp + movq %rsp, %rbp + pushq $0 # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler + pushq $0 # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag + + # + # Stack: + # +---------------------+ <-- 16-byte aligned ensured by processor + # + Old SS + + # +---------------------+ + # + Old RSP + + # +---------------------+ + # + RFlags + + # +---------------------+ + # + CS + + # +---------------------+ + # + RIP + + # +---------------------+ + # + Error Code + + # +---------------------+ + # + RCX / Vector Number + + # +---------------------+ + # + RBP + + # +---------------------+ <-- RBP, 16-byte aligned + # + + + # + # 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; + pushq %r15 + pushq %r14 + pushq %r13 + pushq %r12 + pushq %r11 + pushq %r10 + pushq %r9 + pushq %r8 + pushq %rax + pushq 8(%rbp) # RCX + pushq %rdx + pushq %rbx + pushq 48(%rbp) # RSP + pushq (%rbp) # RBP + pushq %rsi + pushq %rdi + +#; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero + movzwq 56(%rbp), %rax + pushq %rax # for ss + movzwq 32(%rbp), %rax + pushq %rax # for cs + movl %ds, %eax + pushq %rax + movl %es, %eax + pushq %rax + movl %fs, %eax + pushq %rax + movl %gs, %eax + pushq %rax + + movq %rcx, 8(%rbp) # save vector number + +#; UINT64 Rip; + pushq 24(%rbp) + +#; UINT64 Gdtr[2], Idtr[2]; + xorq %rax, %rax + pushq %rax + pushq %rax + sidt (%rsp) + xchgq 2(%rsp), %rax + xchgq (%rsp), %rax + xchgq 8(%rsp), %rax + + xorq %rax, %rax + pushq %rax + pushq %rax + sgdt (%rsp) + xchgq 2(%rsp), %rax + xchgq (%rsp), %rax + xchgq 8(%rsp), %rax + +#; UINT64 Ldtr, Tr; + xorq %rax, %rax + str %ax + pushq %rax + sldt %ax + pushq %rax + +#; UINT64 RFlags; + pushq 40(%rbp) + +#; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; + movq %cr8, %rax + pushq %rax + movq %cr4, %rax + orq $0x208, %rax + movq %rax, %cr4 + pushq %rax + mov %cr3, %rax + pushq %rax + mov %cr2, %rax + pushq %rax + xorq %rax, %rax + pushq %rax + mov %cr0, %rax + pushq %rax + +#; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + movq %dr7, %rax + pushq %rax + movq %dr6, %rax + pushq %rax + movq %dr3, %rax + pushq %rax + movq %dr2, %rax + pushq %rax + movq %dr1, %rax + pushq %rax + movq %dr0, %rax + pushq %rax + +#; FX_SAVE_STATE_X64 FxSaveState; + subq $512, %rsp + movq %rsp, %rdi + .byte 0x0f, 0x0ae, 0x07 #fxsave [rdi] + +#; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear + cld + +#; UINT32 ExceptionData; + pushq 16(%rbp) + +#; Prepare parameter and call + mov 8(%rbp), %rcx + mov %rsp, %rdx + # + # Per X64 calling convention, allocate maximum parameter stack space + # and make sure RSP is 16-byte aligned + # + subq $40, %rsp + call ASM_PFX(CommonExceptionHandler) + addq $40, %rsp + + cli +#; UINT64 ExceptionData; + addq $8, %rsp + +#; FX_SAVE_STATE_X64 FxSaveState; + + movq %rsp, %rsi + .byte 0x0f, 0x0ae, 0x0E # fxrstor [rsi] + addq $512, %rsp + +#; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; +#; Skip restoration of DRx registers to support in-circuit emualators +#; or debuggers set breakpoint in interrupt/exception context + addq $48, %rsp + +#; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; + popq %rax + movq %rax, %cr0 + addq $8, %rsp # not for Cr1 + popq %rax + movq %rax, %cr2 + popq %rax + movq %rax, %cr3 + popq %rax + movq %rax, %cr4 + popq %rax + movq %rax, %cr8 + +#; UINT64 RFlags; + popq 40(%rbp) + +#; UINT64 Ldtr, Tr; +#; UINT64 Gdtr[2], Idtr[2]; +#; Best not let anyone mess with these particular registers... + addq $48, %rsp + +#; UINT64 Rip; + popq 24(%rbp) + +#; UINT64 Gs, Fs, Es, Ds, Cs, Ss; + popq %rax + # mov %rax, %gs ; not for gs + popq %rax + # mov %rax, %fs ; not for fs + # (X64 will not use fs and gs, so we do not restore it) + popq %rax + movl %eax, %es + popq %rax + movl %eax, %ds + popq 32(%rbp) # for cs + popq 56(%rbp) # for ss + +#; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; +#; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; + popq %rdi + popq %rsi + addq $8, %rsp # not for rbp + popq 48(%rbp) # for rsp + popq %rbx + popq %rdx + popq %rcx + popq %rax + popq %r8 + popq %r9 + popq %r10 + popq %r11 + popq %r12 + popq %r13 + popq %r14 + popq %r15 + + movq %rbp, %rsp + popq %rbp + addq $16, %rsp + cmpq $0, -32(%rsp) # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler + jz DoReturn # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag + cmpb $1, -40(%rsp) + jz ErrorCode + jmp *-32(%rsp) +ErrorCode: + subq $8, %rsp + jmp *-24(%rsp) + +DoReturn: + pushq %rax +# movabsq ASM_PFX(mDoFarReturnFlag), %rax + movq ASM_PFX(mDoFarReturnFlag)(%rip), %rax + cmpq $0, %rax # Check if need to do far return instead of IRET + popq %rax + jz DoIret + pushq %rax + movq %rsp, %rax # save old RSP to rax + movq 0x20(%rsp), %rsp + pushq 0x10(%rax) # save CS in new location + pushq 0x8(%rax) # save EIP in new location + pushq 0x18(%rax) # save EFLAGS in new location + movq (%rax), %rax # restore rax + popfq # restore EFLAGS +# .byte 0x48 # prefix to composite "retq" with next "retf" +# lretq #retf # far return + .byte 0x48 # prefix to composite "retq" with next "retf" +#ifdef __APPLE__ + .byte 0xCB +#else + retf # far return +#endif + +DoIret: + iretq + + +#------------------------------------------------------------------------------------- +# AsmGetTemplateAddressMap (&AddressMap); +#------------------------------------------------------------------------------------- +# comments here for definition of address map +ASM_GLOBAL ASM_PFX(AsmGetTemplateAddressMap) +ASM_PFX(AsmGetTemplateAddressMap): + +# movabsq $Exception0Handle, %rax +# movq %rax, (%rcx) +# movq $(Exception1Handle - Exception0Handle), 0x08(%rcx) +# movabsq $HookAfterStubHeaderBegin, %rax +# movq %rax, 0x10(%rcx) +# ret + leaq Exception0Handle(%rip), %rax + movq %rax, (%rcx) + movq $(Exception1Handle - Exception0Handle), 0x08(%rcx) + leaq HookAfterStubHeaderBegin(%rip), %rax + movq %rax, 0x10(%rcx) + ret + + +#------------------------------------------------------------------------------------- +# VOID +# EFIAPI +# AsmVectorNumFixup ( +# IN VOID *VectorBase, // RCX +# IN UINT8 VectorNum, // RDX +# IN BOOLEAN HookStub // R8 +# ); +#------------------------------------------------------------------------------------- +ASM_GLOBAL ASM_PFX(AsmVectorNumFixup) +ASM_PFX(AsmVectorNumFixup): +# movq %rdx, %rax +# movb %al, (VectorNum - HookAfterStubHeaderBegin)(%rcx) +# ret + pushq %rbp + movq %rsp, %rbp + +# Patch vector # + movb %dl, (PatchVectorNum - HookAfterStubHeaderBegin)(%rcx) + +# Patch Function address + leaq ASM_PFX(HookAfterStubHeaderEnd)(%rip), %rax + leaq ASM_PFX(CommonInterruptEntry)(%rip), %r10 + testb %r8b, %r8b + cmovneq %rax, %r10 + movq %r10, (PatchFuncAddress - HookAfterStubHeaderBegin)(%rcx) + + popq %rbp + ret + +#END + + diff --git a/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.asm b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.asm new file mode 100755 index 0000000000..dfb66e2bcf --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.asm @@ -0,0 +1,389 @@ +;------------------------------------------------------------------------------ ; +; Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; ExceptionHandlerAsm.Asm +; +; Abstract: +; +; x64 CPU Exception Handler +; +; Notes: +; +;------------------------------------------------------------------------------ + +; +; CommonExceptionHandler() +; +externdef CommonExceptionHandler:near + +EXTRN mErrorCodeFlag:DWORD ; Error code flags for exceptions +EXTRN mDoFarReturnFlag:QWORD ; Do far return flag + +data SEGMENT + +.code + +ALIGN 8 + +AsmIdtVectorBegin: +REPEAT 32 + db 6ah ; push #VectorNum + db ($ - AsmIdtVectorBegin) / ((AsmIdtVectorEnd - AsmIdtVectorBegin) / 32) ; VectorNum + push rax + mov rax, CommonInterruptEntry + jmp rax +ENDM +AsmIdtVectorEnd: + +HookAfterStubHeaderBegin: + db 6ah ; push +@VectorNum: + db 0 ; 0 will be fixed + push rax + mov rax, HookAfterStubHeaderEnd + jmp rax +HookAfterStubHeaderEnd: + mov rax, rsp + and sp, 0fff0h ; make sure 16-byte aligned for exception context + sub rsp, 18h ; reserve room for filling exception data later + push rcx + mov rcx, [rax + 8] + bt mErrorCodeFlag, ecx + jnc @F + push [rsp] ; push additional rcx to make stack alignment +@@: + xchg rcx, [rsp] ; restore rcx, save Exception Number in stack + push [rax] ; push rax into stack to keep code consistence + +;---------------------------------------; +; CommonInterruptEntry ; +;---------------------------------------; +; The follow algorithm is used for the common interrupt routine. +; Entry from each interrupt with a push eax and eax=interrupt number +; Stack frame would be as follows as specified in IA32 manuals: +; +; +---------------------+ <-- 16-byte aligned ensured by processor +; + Old SS + +; +---------------------+ +; + Old RSP + +; +---------------------+ +; + RFlags + +; +---------------------+ +; + CS + +; +---------------------+ +; + RIP + +; +---------------------+ +; + Error Code + +; +---------------------+ +; + Vector Number + +; +---------------------+ +; + RBP + +; +---------------------+ <-- RBP, 16-byte aligned +; The follow algorithm is used for the common interrupt routine. +CommonInterruptEntry PROC PUBLIC + cli + pop rax + ; + ; All interrupt handlers are invoked through interrupt gates, so + ; IF flag automatically cleared at the entry point + ; + xchg rcx, [rsp] ; Save rcx into stack and save vector number into rcx + and rcx, 0FFh + 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 + push 0 ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler + push 0 ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag + + ; + ; Stack: + ; +---------------------+ <-- 16-byte aligned ensured by processor + ; + Old SS + + ; +---------------------+ + ; + Old RSP + + ; +---------------------+ + ; + RFlags + + ; +---------------------+ + ; + CS + + ; +---------------------+ + ; + RIP + + ; +---------------------+ + ; + Error Code + + ; +---------------------+ + ; + RCX / Vector Number + + ; +---------------------+ + ; + RBP + + ; +---------------------+ <-- RBP, 16-byte aligned + ; + + + ; + ; 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]; + xor rax, rax + push rax + push rax + sidt [rsp] + xchg rax, [rsp + 2] + xchg rax, [rsp] + xchg rax, [rsp + 8] + + xor rax, rax + push rax + push rax + sgdt [rsp] + xchg rax, [rsp + 2] + xchg rax, [rsp] + xchg rax, [rsp + 8] + +;; 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 + mov rax, dr6 + push 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, 07h ;fxsave [rdi] + +;; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear + cld + +;; UINT32 ExceptionData; + push qword ptr [rbp + 16] + +;; 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 + mov rax, CommonExceptionHandler + call rax + add rsp, 4 * 8 + 8 + + cli +;; UINT64 ExceptionData; + add rsp, 8 + +;; FX_SAVE_STATE_X64 FxSaveState; + + mov rsi, rsp + db 0fh, 0aeh, 0Eh ; fxrstor [rsi] + add rsp, 512 + +;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; +;; Skip restoration of DRx registers to support in-circuit emualators +;; or debuggers set breakpoint in interrupt/exception context + add rsp, 8 * 6 + +;; 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 + cmp qword ptr [rsp - 32], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler + jz DoReturn + cmp qword ptr [rsp - 40], 1 ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag + jz ErrorCode + jmp qword ptr [rsp - 32] +ErrorCode: + sub rsp, 8 + jmp qword ptr [rsp - 24] + +DoReturn: + cmp mDoFarReturnFlag, 0 ; Check if need to do far return instead of IRET + jz DoIret + push rax + mov rax, rsp ; save old RSP to rax + mov rsp, [rsp + 20h] + push [rax + 10h] ; save CS in new location + push [rax + 8h] ; save EIP in new location + push [rax + 18h] ; save EFLAGS in new location + mov rax, [rax] ; restore rax + popfq ; restore EFLAGS + DB 48h ; prefix to composite "retq" with next "retf" + retf ; far return +DoIret: + iretq + +CommonInterruptEntry ENDP + +;------------------------------------------------------------------------------------- +; GetTemplateAddressMap (&AddressMap); +;------------------------------------------------------------------------------------- +; comments here for definition of address map +AsmGetTemplateAddressMap PROC + mov rax, offset AsmIdtVectorBegin + mov qword ptr [rcx], rax + mov qword ptr [rcx + 8h], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32 + mov rax, offset HookAfterStubHeaderBegin + mov qword ptr [rcx + 10h], rax + ret +AsmGetTemplateAddressMap ENDP + +;------------------------------------------------------------------------------------- +; AsmVectorNumFixup (*VectorBase, VectorNum, HookStub); +;------------------------------------------------------------------------------------- +AsmVectorNumFixup PROC + mov rax, rdx + mov [rcx + (@VectorNum - HookAfterStubHeaderBegin)], al + ret +AsmVectorNumFixup ENDP + +END diff --git a/CloverEFI/UefiCpuPkg/Library/MtrrLib/MtrrLib.c b/CloverEFI/UefiCpuPkg/Library/MtrrLib/MtrrLib.c new file mode 100755 index 0000000000..50a108726a --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/MtrrLib/MtrrLib.c @@ -0,0 +1,1692 @@ +/** @file + MTRR setting library + + Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include +#include +#include + +// +// This table defines the offset, base and length of the fixed MTRRs +// +CONST FIXED_MTRR mMtrrLibFixedMtrrTable[] = { + { + MTRR_LIB_IA32_MTRR_FIX64K_00000, + 0, + SIZE_64KB + }, + { + MTRR_LIB_IA32_MTRR_FIX16K_80000, + 0x80000, + SIZE_16KB + }, + { + MTRR_LIB_IA32_MTRR_FIX16K_A0000, + 0xA0000, + SIZE_16KB + }, + { + MTRR_LIB_IA32_MTRR_FIX4K_C0000, + 0xC0000, + SIZE_4KB + }, + { + MTRR_LIB_IA32_MTRR_FIX4K_C8000, + 0xC8000, + SIZE_4KB + }, + { + MTRR_LIB_IA32_MTRR_FIX4K_D0000, + 0xD0000, + SIZE_4KB + }, + { + MTRR_LIB_IA32_MTRR_FIX4K_D8000, + 0xD8000, + SIZE_4KB + }, + { + MTRR_LIB_IA32_MTRR_FIX4K_E0000, + 0xE0000, + SIZE_4KB + }, + { + MTRR_LIB_IA32_MTRR_FIX4K_E8000, + 0xE8000, + SIZE_4KB + }, + { + MTRR_LIB_IA32_MTRR_FIX4K_F0000, + 0xF0000, + SIZE_4KB + }, + { + MTRR_LIB_IA32_MTRR_FIX4K_F8000, + 0xF8000, + SIZE_4KB + }, +}; + +// +// Lookup table used to print MTRRs +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = { + "UC", // CacheUncacheable + "WC", // CacheWriteCombining + "R*", // Invalid + "R*", // Invalid + "WT", // CacheWriteThrough + "WP", // CacheWriteProtected + "WB", // CacheWriteBack + "R*" // Invalid +}; + +/** + Returns the variable MTRR count for the CPU. + + @return Variable MTRR count + +**/ +UINT32 +EFIAPI +GetVariableMtrrCount ( + VOID + ) +{ + UINT32 VariableMtrrCount; + + if (!IsMtrrSupported ()) { + return 0; + } + + VariableMtrrCount = (UINT32)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK); + ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); + + return VariableMtrrCount; +} + +/** + Returns the firmware usable variable MTRR count for the CPU. + + @return Firmware usable variable MTRR count + +**/ +UINT32 +EFIAPI +GetFirmwareVariableMtrrCount ( + VOID + ) +{ + UINT32 VariableMtrrCount; + + VariableMtrrCount = GetVariableMtrrCount (); + if (VariableMtrrCount < RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER) { + return 0; + } + + return VariableMtrrCount - RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER; +} + +/** + Returns the default MTRR cache type for the system. + + @return The default MTRR cache type. + +**/ +MTRR_MEMORY_CACHE_TYPE +EFIAPI +MtrrGetDefaultMemoryType ( + VOID +) +{ + if (!IsMtrrSupported ()) { + return CacheUncacheable; +} + + return (MTRR_MEMORY_CACHE_TYPE) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0x7); +} + +/** + Preparation before programming MTRR. + + This function will do some preparation for programming MTRRs: + disable cache, invalid cache and disable MTRR caching functionality + + @return CR4 value before changing. + +**/ +UINTN +PreMtrrChange ( + VOID + ) +{ + UINTN Value; + + // + // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29) + // + AsmDisableCache (); + + // + // Save original CR4 value and clear PGE flag (Bit 7) + // + Value = AsmReadCr4 (); + AsmWriteCr4 (Value & (~BIT7)); + + // + // Flush all TLBs + // + CpuFlushTlb (); + + // + // Disable Mtrrs + // + AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0); + + // + // Return original CR4 value + // + return Value; +} + + +/** + Cleaning up after programming MTRRs. + + This function will do some clean up after programming MTRRs: + enable MTRR caching functionality, and enable cache + + @param Cr4 CR4 value to restore + +**/ +VOID +PostMtrrChange ( + UINTN Cr4 + ) +{ + // + // Enable Cache MTRR + // + AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 3); + + // + // Flush all TLBs + // + CpuFlushTlb (); + + // + // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29) + // + AsmEnableCache (); + + // + // Restore original CR4 value + // + AsmWriteCr4 (Cr4); +} + + +/** + Programs fixed MTRRs registers. + + @param MemoryCacheType The memory type to set. + @param Base The base address of memory range. + @param Length The length of memory range. + + @retval RETURN_SUCCESS The cache type was updated successfully + @retval RETURN_UNSUPPORTED The requested range or cache type was invalid + for the fixed MTRRs. + +**/ +RETURN_STATUS +ProgramFixedMtrr ( + IN UINT64 MemoryCacheType, + IN OUT UINT64 *Base, + IN OUT UINT64 *Length + ) +{ + UINT32 MsrNum; + UINT32 ByteShift; + UINT64 TempQword; + UINT64 OrMask; + UINT64 ClearMask; + + TempQword = 0; + OrMask = 0; + ClearMask = 0; + + for (MsrNum = 0; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) { + if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) && + (*Base < + ( + mMtrrLibFixedMtrrTable[MsrNum].BaseAddress + + (8 * mMtrrLibFixedMtrrTable[MsrNum].Length) + ) + ) + ) { + break; + } + } + + if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) { + return RETURN_UNSUPPORTED; + } + + // + // We found the fixed MTRR to be programmed + // + for (ByteShift = 0; ByteShift < 8; ByteShift++) { + if (*Base == + ( + mMtrrLibFixedMtrrTable[MsrNum].BaseAddress + + (ByteShift * mMtrrLibFixedMtrrTable[MsrNum].Length) + ) + ) { + break; + } + } + + if (ByteShift == 8) { + return RETURN_UNSUPPORTED; + } + + for ( + ; + ((ByteShift < 8) && (*Length >= mMtrrLibFixedMtrrTable[MsrNum].Length)); + ByteShift++ + ) { + OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8)); + ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8)); + *Length -= mMtrrLibFixedMtrrTable[MsrNum].Length; + *Base += mMtrrLibFixedMtrrTable[MsrNum].Length; + } + + if (ByteShift < 8 && (*Length != 0)) { + return RETURN_UNSUPPORTED; + } + + TempQword = + (AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr) & ~ClearMask) | OrMask; + AsmWriteMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr, TempQword); + return RETURN_SUCCESS; +} + + +/** + Get the attribute of variable MTRRs. + + This function shadows the content of variable MTRRs into an + internal array: VariableMtrr. + + @param MtrrValidBitsMask The mask for the valid bit of the MTRR + @param MtrrValidAddressMask The valid address mask for MTRR + @param VariableMtrr The array to shadow variable MTRRs content + + @return The return value of this paramter indicates the + number of MTRRs which has been used. + +**/ +UINT32 +EFIAPI +MtrrGetMemoryAttributeInVariableMtrr ( + IN UINT64 MtrrValidBitsMask, + IN UINT64 MtrrValidAddressMask, + OUT VARIABLE_MTRR *VariableMtrr + ) +{ + UINTN Index; + UINT32 MsrNum; + UINT32 UsedMtrr; + UINT32 FirmwareVariableMtrrCount; + UINT32 VariableMtrrEnd; + + if (!IsMtrrSupported ()) { + return 0; + } + + FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount (); + VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1; + + ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR); + UsedMtrr = 0; + + for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE, Index = 0; + ( + (MsrNum < VariableMtrrEnd) && + (Index < FirmwareVariableMtrrCount) + ); + MsrNum += 2 + ) { + if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) { + VariableMtrr[Index].Msr = MsrNum; + VariableMtrr[Index].BaseAddress = (AsmReadMsr64 (MsrNum) & + MtrrValidAddressMask); + VariableMtrr[Index].Length = ((~(AsmReadMsr64 (MsrNum + 1) & + MtrrValidAddressMask) + ) & + MtrrValidBitsMask + ) + 1; + VariableMtrr[Index].Type = (AsmReadMsr64 (MsrNum) & 0x0ff); + VariableMtrr[Index].Valid = TRUE; + VariableMtrr[Index].Used = TRUE; + UsedMtrr = UsedMtrr + 1; + Index++; + } + } + return UsedMtrr; +} + + +/** + Checks overlap between given memory range and MTRRs. + + @param Start The start address of memory range. + @param End The end address of memory range. + @param VariableMtrr The array to shadow variable MTRRs content + + @retval TRUE Overlap exists. + @retval FALSE No overlap. + +**/ +BOOLEAN +CheckMemoryAttributeOverlap ( + IN PHYSICAL_ADDRESS Start, + IN PHYSICAL_ADDRESS End, + IN VARIABLE_MTRR *VariableMtrr + ) +{ + UINT32 Index; + + for (Index = 0; Index < 6; Index++) { + if ( + VariableMtrr[Index].Valid && + !( + (Start > (VariableMtrr[Index].BaseAddress + + VariableMtrr[Index].Length - 1) + ) || + (End < VariableMtrr[Index].BaseAddress) + ) + ) { + return TRUE; + } + } + + return FALSE; +} + + +/** + Marks a variable MTRR as non-valid. + + @param Index The index of the array VariableMtrr to be invalidated + @param VariableMtrr The array to shadow variable MTRRs content + @param UsedMtrr The number of MTRRs which has already been used + +**/ +VOID +InvalidateShadowMtrr ( + IN UINTN Index, + IN VARIABLE_MTRR *VariableMtrr, + OUT UINT32 *UsedMtrr + ) +{ + VariableMtrr[Index].Valid = FALSE; + *UsedMtrr = *UsedMtrr - 1; +} + + +/** + Combine memory attributes. + + If overlap exists between given memory range and MTRRs, try to combine them. + + @param Attributes The memory type to set. + @param Base The base address of memory range. + @param Length The length of memory range. + @param VariableMtrr The array to shadow variable MTRRs content + @param UsedMtrr The number of MTRRs which has already been used + @param OverwriteExistingMtrr Returns whether an existing MTRR was used + + @retval EFI_SUCCESS Memory region successfully combined. + @retval EFI_ACCESS_DENIED Memory region cannot be combined. + +**/ +RETURN_STATUS +CombineMemoryAttribute ( + IN UINT64 Attributes, + IN OUT UINT64 *Base, + IN OUT UINT64 *Length, + IN VARIABLE_MTRR *VariableMtrr, + IN OUT UINT32 *UsedMtrr, + OUT BOOLEAN *OverwriteExistingMtrr + ) +{ + UINT32 Index; + UINT64 CombineStart; + UINT64 CombineEnd; + UINT64 MtrrEnd; + UINT64 EndAddress; + UINT32 FirmwareVariableMtrrCount; + BOOLEAN CoveredByExistingMtrr; + + FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount (); + + *OverwriteExistingMtrr = FALSE; + CoveredByExistingMtrr = FALSE; + EndAddress = *Base +*Length - 1; + + for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) { + + MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1; + if ( + !VariableMtrr[Index].Valid || + ( + *Base > (MtrrEnd) || + (EndAddress < VariableMtrr[Index].BaseAddress) + ) + ) { + continue; + } + + // + // Combine same attribute MTRR range + // + if (Attributes == VariableMtrr[Index].Type) { + // + // if the Mtrr range contain the request range, set a flag, then continue to + // invalidate any MTRR of the same request range with higher priority cache type. + // + if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) { + CoveredByExistingMtrr = TRUE; + continue; + } + // + // invalid this MTRR, and program the combine range + // + CombineStart = + (*Base) < VariableMtrr[Index].BaseAddress ? + (*Base) : + VariableMtrr[Index].BaseAddress; + CombineEnd = EndAddress > MtrrEnd ? EndAddress : MtrrEnd; + + // + // Record the MTRR usage status in VariableMtrr array. + // + InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr); + *Base = CombineStart; + *Length = CombineEnd - CombineStart + 1; + EndAddress = CombineEnd; + *OverwriteExistingMtrr = TRUE; + continue; + } else { + // + // The cache type is different, but the range is convered by one MTRR + // + if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) { + InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr); + continue; + } + + } + + if ((Attributes== MTRR_CACHE_WRITE_THROUGH && + VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) || + (Attributes == MTRR_CACHE_WRITE_BACK && + VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) || + (Attributes == MTRR_CACHE_UNCACHEABLE) || + (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE) + ) { + *OverwriteExistingMtrr = TRUE; + continue; + } + // + // Other type memory overlap is invalid + // + return RETURN_ACCESS_DENIED; + } + + if (CoveredByExistingMtrr) { + *Length = 0; + } + + return RETURN_SUCCESS; +} + + +/** + Calculate the maximum value which is a power of 2, but less the MemoryLength. + + @param MemoryLength The number to pass in. + @return The maximum value which is align to power of 2 and less the MemoryLength + +**/ +UINT64 +Power2MaxMemory ( + IN UINT64 MemoryLength + ) +{ + UINT64 Result; + + if (RShiftU64 (MemoryLength, 32) != 0) { + Result = LShiftU64 ( + (UINT64) GetPowerOfTwo32 ( + (UINT32) RShiftU64 (MemoryLength, 32) + ), + 32 + ); + } else { + Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength); + } + + return Result; +} + + +/** + Determine the MTRR numbers used to program a memory range. + + This function first checks the alignment of the base address. If the alignment of the base address <= Length, + cover the memory range (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and Length -= alignment. + Repeat the step until alignment > Length. + + Then this function determines which direction of programming the variable MTRRs for the remaining length + will use fewer MTRRs. + + @param BaseAddress Length of Memory to program MTRR + @param Length Length of Memory to program MTRR + @param MtrrNumber Pointer to the number of necessary MTRRs + + @retval TRUE Positive direction is better. + FALSE Negtive direction is better. + +**/ +BOOLEAN +GetMtrrNumberAndDirection ( + IN UINT64 BaseAddress, + IN UINT64 Length, + IN UINTN *MtrrNumber + ) +{ + UINT64 TempQword; + UINT64 Alignment; + UINT32 Positive; + UINT32 Subtractive; + + *MtrrNumber = 0; + + if (BaseAddress != 0) { + do { + // + // Calculate the alignment of the base address. + // + Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress)); + + if (Alignment > Length) { + break; + } + + (*MtrrNumber)++; + BaseAddress += Alignment; + Length -= Alignment; + } while (TRUE); + + if (Length == 0) { + return TRUE; + } + } + + TempQword = Length; + Positive = 0; + Subtractive = 0; + + do { + TempQword -= Power2MaxMemory (TempQword); + Positive++; + } while (TempQword != 0); + + TempQword = Power2MaxMemory (LShiftU64 (Length, 1)) - Length; + Subtractive++; + do { + TempQword -= Power2MaxMemory (TempQword); + Subtractive++; + } while (TempQword != 0); + + if (Positive <= Subtractive) { + *MtrrNumber += Positive; + return TRUE; + } else { + *MtrrNumber += Subtractive; + return FALSE; + } +} + +/** + Invalid variable MTRRs according to the value in the shadow array. + + This function programs MTRRs according to the values specified + in the shadow array. + + @param VariableMtrr The array to shadow variable MTRRs content + +**/ +VOID +InvalidateMtrr ( + IN VARIABLE_MTRR *VariableMtrr + ) +{ + UINTN Index; + UINTN Cr4; + UINTN VariableMtrrCount; + + Cr4 = PreMtrrChange (); + Index = 0; + VariableMtrrCount = GetVariableMtrrCount (); + while (Index < VariableMtrrCount) { + if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) { + AsmWriteMsr64 (VariableMtrr[Index].Msr, 0); + AsmWriteMsr64 (VariableMtrr[Index].Msr + 1, 0); + VariableMtrr[Index].Used = FALSE; + } + Index ++; + } + PostMtrrChange (Cr4); +} + + +/** + Programs variable MTRRs + + This function programs variable MTRRs + + @param MtrrNumber Index of MTRR to program. + @param BaseAddress Base address of memory region. + @param Length Length of memory region. + @param MemoryCacheType Memory type to set. + @param MtrrValidAddressMask The valid address mask for MTRR + +**/ +VOID +ProgramVariableMtrr ( + IN UINTN MtrrNumber, + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 MemoryCacheType, + IN UINT64 MtrrValidAddressMask + ) +{ + UINT64 TempQword; + UINTN Cr4; + + Cr4 = PreMtrrChange (); + + // + // MTRR Physical Base + // + TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType; + AsmWriteMsr64 ((UINT32) MtrrNumber, TempQword); + + // + // MTRR Physical Mask + // + TempQword = ~(Length - 1); + AsmWriteMsr64 ( + (UINT32) (MtrrNumber + 1), + (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED + ); + + PostMtrrChange (Cr4); +} + + +/** + Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE. + + @param MtrrType MTRR memory type + + @return The enum item in MTRR_MEMORY_CACHE_TYPE + +**/ +MTRR_MEMORY_CACHE_TYPE +GetMemoryCacheTypeFromMtrrType ( + IN UINT64 MtrrType + ) +{ + switch (MtrrType) { + case MTRR_CACHE_UNCACHEABLE: + return CacheUncacheable; + case MTRR_CACHE_WRITE_COMBINING: + return CacheWriteCombining; + case MTRR_CACHE_WRITE_THROUGH: + return CacheWriteThrough; + case MTRR_CACHE_WRITE_PROTECTED: + return CacheWriteProtected; + case MTRR_CACHE_WRITE_BACK: + return CacheWriteBack; + default: + // + // MtrrType is MTRR_CACHE_INVALID_TYPE, that means + // no mtrr covers the range + // + return CacheUncacheable; + } +} + +/** + Initializes the valid bits mask and valid address mask for MTRRs. + + This function initializes the valid bits mask and valid address mask for MTRRs. + + @param MtrrValidBitsMask The mask for the valid bit of the MTRR + @param MtrrValidAddressMask The valid address mask for the MTRR + +**/ +VOID +MtrrLibInitializeMtrrMask ( + OUT UINT64 *MtrrValidBitsMask, + OUT UINT64 *MtrrValidAddressMask + ) +{ + UINT32 RegEax; + UINT8 PhysicalAddressBits; + + AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); + + if (RegEax >= 0x80000008) { + AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); + + PhysicalAddressBits = (UINT8) RegEax; + + *MtrrValidBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1; + *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL; + } else { + *MtrrValidBitsMask = MTRR_LIB_CACHE_VALID_ADDRESS; + *MtrrValidAddressMask = 0xFFFFFFFF; + } +} + + +/** + Determing the real attribute of a memory range. + + This function is to arbitrate the real attribute of the memory when + there are 2 MTRR covers the same memory range. For further details, + please refer the IA32 Software Developer's Manual, Volume 3, + Section 10.11.4.1. + + @param MtrrType1 the first kind of Memory type + @param MtrrType2 the second kind of memory type + +**/ +UINT64 +MtrrPrecedence ( + UINT64 MtrrType1, + UINT64 MtrrType2 + ) +{ + UINT64 MtrrType; + + MtrrType = MTRR_CACHE_INVALID_TYPE; + switch (MtrrType1) { + case MTRR_CACHE_UNCACHEABLE: + MtrrType = MTRR_CACHE_UNCACHEABLE; + break; + case MTRR_CACHE_WRITE_COMBINING: + if ( + MtrrType2==MTRR_CACHE_WRITE_COMBINING || + MtrrType2==MTRR_CACHE_UNCACHEABLE + ) { + MtrrType = MtrrType2; + } + break; + case MTRR_CACHE_WRITE_THROUGH: + if ( + MtrrType2==MTRR_CACHE_WRITE_THROUGH || + MtrrType2==MTRR_CACHE_WRITE_BACK + ) { + MtrrType = MTRR_CACHE_WRITE_THROUGH; + } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) { + MtrrType = MTRR_CACHE_UNCACHEABLE; + } + break; + case MTRR_CACHE_WRITE_PROTECTED: + if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED || + MtrrType2 == MTRR_CACHE_UNCACHEABLE) { + MtrrType = MtrrType2; + } + break; + case MTRR_CACHE_WRITE_BACK: + if ( + MtrrType2== MTRR_CACHE_UNCACHEABLE || + MtrrType2==MTRR_CACHE_WRITE_THROUGH || + MtrrType2== MTRR_CACHE_WRITE_BACK + ) { + MtrrType = MtrrType2; + } + break; + case MTRR_CACHE_INVALID_TYPE: + MtrrType = MtrrType2; + break; + default: + break; + } + + if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) { + MtrrType = MtrrType1; + } + return MtrrType; +} + + +/** + This function attempts to set the attributes for a memory range. + + @param BaseAddress The physical address that is the start + address of a memory region. + @param Length The size in bytes of the memory region. + @param Attributes The bit mask of attributes to set for the + memory region. + + @retval RETURN_SUCCESS The attributes were set for the memory + region. + @retval RETURN_INVALID_PARAMETER Length is zero. + @retval RETURN_UNSUPPORTED The processor does not support one or + more bytes of the memory resource range + specified by BaseAddress and Length. + @retval RETURN_UNSUPPORTED The bit mask of attributes is not support + for the memory resource range specified + by BaseAddress and Length. + @retval RETURN_ACCESS_DENIED The attributes for the memory resource + range specified by BaseAddress and Length + cannot be modified. + @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to + modify the attributes of the memory + resource range. + +**/ +RETURN_STATUS +EFIAPI +MtrrSetMemoryAttribute ( + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN MTRR_MEMORY_CACHE_TYPE Attribute + ) +{ + UINT64 TempQword; + RETURN_STATUS Status; + UINT64 MemoryType; + UINT64 Alignment; + BOOLEAN OverLap; + BOOLEAN Positive; + UINT32 MsrNum; + UINTN MtrrNumber; + VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR]; + UINT32 UsedMtrr; + UINT64 MtrrValidBitsMask; + UINT64 MtrrValidAddressMask; + UINTN Cr4; + BOOLEAN OverwriteExistingMtrr; + UINT32 FirmwareVariableMtrrCount; + UINT32 VariableMtrrEnd; + + DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length)); + + if (!IsMtrrSupported ()) { + Status = RETURN_UNSUPPORTED; + goto Done; + } + + FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount (); + VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1; + + MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask); + + TempQword = 0; + MemoryType = (UINT64)Attribute; + OverwriteExistingMtrr = FALSE; + + // + // Check for an invalid parameter + // + if (Length == 0) { + Status = RETURN_INVALID_PARAMETER; + goto Done; + } + + if ( + (BaseAddress & ~MtrrValidAddressMask) != 0 || + (Length & ~MtrrValidAddressMask) != 0 + ) { + Status = RETURN_UNSUPPORTED; + goto Done; + } + + // + // Check if Fixed MTRR + // + Status = RETURN_SUCCESS; + while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) { + Cr4 = PreMtrrChange (); + Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length); + PostMtrrChange (Cr4); + if (RETURN_ERROR (Status)) { + goto Done; + } + } + + if (Length == 0) { + // + // A Length of 0 can only make sense for fixed MTTR ranges. + // Since we just handled the fixed MTRRs, we can skip the + // variable MTRR section. + // + goto Done; + } + + // + // Since memory ranges below 1MB will be overridden by the fixed MTRRs, + // we can set the base to 0 to save variable MTRRs. + // + if (BaseAddress == BASE_1MB) { + BaseAddress = 0; + Length += SIZE_1MB; + } + + // + // Check for overlap + // + UsedMtrr = MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, VariableMtrr); + OverLap = CheckMemoryAttributeOverlap (BaseAddress, BaseAddress + Length - 1, VariableMtrr); + if (OverLap) { + Status = CombineMemoryAttribute (MemoryType, &BaseAddress, &Length, VariableMtrr, &UsedMtrr, &OverwriteExistingMtrr); + if (RETURN_ERROR (Status)) { + goto Done; + } + + if (Length == 0) { + // + // Combined successfully, invalidate the now-unused MTRRs + // + InvalidateMtrr(VariableMtrr); + Status = RETURN_SUCCESS; + goto Done; + } + } + + // + // The memory type is the same with the type specified by + // MTRR_LIB_IA32_MTRR_DEF_TYPE. + // + if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryType ())) { + // + // Invalidate the now-unused MTRRs + // + InvalidateMtrr(VariableMtrr); + goto Done; + } + + Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber); + + if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) { + Status = RETURN_OUT_OF_RESOURCES; + goto Done; + } + + // + // Invalidate the now-unused MTRRs + // + InvalidateMtrr(VariableMtrr); + + // + // Find first unused MTRR + // + for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE; + MsrNum < VariableMtrrEnd; + MsrNum += 2 + ) { + if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { + break; + } + } + + if (BaseAddress != 0) { + do { + // + // Calculate the alignment of the base address. + // + Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress)); + + if (Alignment > Length) { + break; + } + + // + // Find unused MTRR + // + for (; MsrNum < VariableMtrrEnd; MsrNum += 2) { + if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { + break; + } + } + + ProgramVariableMtrr ( + MsrNum, + BaseAddress, + Alignment, + MemoryType, + MtrrValidAddressMask + ); + BaseAddress += Alignment; + Length -= Alignment; + } while (TRUE); + + if (Length == 0) { + goto Done; + } + } + + TempQword = Length; + + if (!Positive) { + Length = Power2MaxMemory (LShiftU64 (TempQword, 1)); + + // + // Find unused MTRR + // + for (; MsrNum < VariableMtrrEnd; MsrNum += 2) { + if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { + break; + } + } + + ProgramVariableMtrr ( + MsrNum, + BaseAddress, + Length, + MemoryType, + MtrrValidAddressMask + ); + BaseAddress += Length; + TempQword = Length - TempQword; + MemoryType = MTRR_CACHE_UNCACHEABLE; + } + + do { + // + // Find unused MTRR + // + for (; MsrNum < VariableMtrrEnd; MsrNum += 2) { + if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { + break; + } + } + + Length = Power2MaxMemory (TempQword); + if (!Positive) { + BaseAddress -= Length; + } + + ProgramVariableMtrr ( + MsrNum, + BaseAddress, + Length, + MemoryType, + MtrrValidAddressMask + ); + + if (Positive) { + BaseAddress += Length; + } + TempQword -= Length; + + } while (TempQword > 0); + +Done: + DEBUG((DEBUG_CACHE, " Status = %r\n", Status)); + if (!RETURN_ERROR (Status)) { + MtrrDebugPrintAllMtrrs (); + } + + return Status; +} + + +/** + This function will get the memory cache type of the specific address. + + This function is mainly for debug purpose. + + @param Address The specific address + + @return Memory cache type of the sepcific address + +**/ +MTRR_MEMORY_CACHE_TYPE +EFIAPI +MtrrGetMemoryAttribute ( + IN PHYSICAL_ADDRESS Address + ) +{ + UINT64 TempQword; + UINTN Index; + UINTN SubIndex; + UINT64 MtrrType; + UINT64 TempMtrrType; + MTRR_MEMORY_CACHE_TYPE CacheType; + VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR]; + UINT64 MtrrValidBitsMask; + UINT64 MtrrValidAddressMask; + UINTN VariableMtrrCount; + + if (!IsMtrrSupported ()) { + return CacheUncacheable; + } + + // + // Check if MTRR is enabled, if not, return UC as attribute + // + TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE); + MtrrType = MTRR_CACHE_INVALID_TYPE; + + if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { + return CacheUncacheable; + } + + // + // If address is less than 1M, then try to go through the fixed MTRR + // + if (Address < BASE_1MB) { + if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) { + // + // Go through the fixed MTRR + // + for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { + if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress && + Address < ( + mMtrrLibFixedMtrrTable[Index].BaseAddress + + (mMtrrLibFixedMtrrTable[Index].Length * 8) + ) + ) { + SubIndex = + ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) / + mMtrrLibFixedMtrrTable[Index].Length; + TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr); + MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF; + return GetMemoryCacheTypeFromMtrrType (MtrrType); + } + } + } + } + MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask); + MtrrGetMemoryAttributeInVariableMtrr( + MtrrValidBitsMask, + MtrrValidAddressMask, + VariableMtrr + ); + + // + // Go through the variable MTRR + // + VariableMtrrCount = GetVariableMtrrCount (); + ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); + + for (Index = 0; Index < VariableMtrrCount; Index++) { + if (VariableMtrr[Index].Valid) { + if (Address >= VariableMtrr[Index].BaseAddress && + Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) { + TempMtrrType = VariableMtrr[Index].Type; + MtrrType = MtrrPrecedence (MtrrType, TempMtrrType); + } + } + } + CacheType = GetMemoryCacheTypeFromMtrrType (MtrrType); + + return CacheType; +} + + +/** + This function will get the raw value in variable MTRRs + + @param VariableSettings A buffer to hold variable MTRRs content. + + @return The VariableSettings input pointer + +**/ +MTRR_VARIABLE_SETTINGS* +EFIAPI +MtrrGetVariableMtrr ( + OUT MTRR_VARIABLE_SETTINGS *VariableSettings + ) +{ + UINT32 Index; + UINT32 VariableMtrrCount; + + if (!IsMtrrSupported ()) { + return VariableSettings; + } + + VariableMtrrCount = GetVariableMtrrCount (); + ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); + + for (Index = 0; Index < VariableMtrrCount; Index++) { + VariableSettings->Mtrr[Index].Base = + AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1)); + VariableSettings->Mtrr[Index].Mask = + AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1); + } + + return VariableSettings; +} + + +/** + Worker function setting variable MTRRs + + @param VariableSettings A buffer to hold variable MTRRs content. + +**/ +VOID +MtrrSetVariableMtrrWorker ( + IN MTRR_VARIABLE_SETTINGS *VariableSettings + ) +{ + UINT32 Index; + UINT32 VariableMtrrCount; + + VariableMtrrCount = GetVariableMtrrCount (); + ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); + + for (Index = 0; Index < VariableMtrrCount; Index++) { + AsmWriteMsr64 ( + MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1), + VariableSettings->Mtrr[Index].Base + ); + AsmWriteMsr64 ( + MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1, + VariableSettings->Mtrr[Index].Mask + ); + } +} + + +/** + This function sets variable MTRRs + + @param VariableSettings A buffer to hold variable MTRRs content. + + @return The pointer of VariableSettings + +**/ +MTRR_VARIABLE_SETTINGS* +EFIAPI +MtrrSetVariableMtrr ( + IN MTRR_VARIABLE_SETTINGS *VariableSettings + ) +{ + UINTN Cr4; + + if (!IsMtrrSupported ()) { + return VariableSettings; + } + + Cr4 = PreMtrrChange (); + MtrrSetVariableMtrrWorker (VariableSettings); + PostMtrrChange (Cr4); + return VariableSettings; +} + + +/** + This function gets the content in fixed MTRRs + + @param FixedSettings A buffer to hold fixed Mtrrs content. + + @retval The pointer of FixedSettings + +**/ +MTRR_FIXED_SETTINGS* +EFIAPI +MtrrGetFixedMtrr ( + OUT MTRR_FIXED_SETTINGS *FixedSettings + ) +{ + UINT32 Index; + + if (!IsMtrrSupported ()) { + return FixedSettings; + } + + for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { + FixedSettings->Mtrr[Index] = + AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr); + }; + + return FixedSettings; +} + +/** + Worker function setting fixed MTRRs + + @param FixedSettings A buffer to hold fixed Mtrrs content. + +**/ +VOID +MtrrSetFixedMtrrWorker ( + IN MTRR_FIXED_SETTINGS *FixedSettings + ) +{ + UINT32 Index; + + for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { + AsmWriteMsr64 ( + mMtrrLibFixedMtrrTable[Index].Msr, + FixedSettings->Mtrr[Index] + ); + } +} + + +/** + This function sets fixed MTRRs + + @param FixedSettings A buffer to hold fixed Mtrrs content. + + @retval The pointer of FixedSettings + +**/ +MTRR_FIXED_SETTINGS* +EFIAPI +MtrrSetFixedMtrr ( + IN MTRR_FIXED_SETTINGS *FixedSettings + ) +{ + UINTN Cr4; + + if (!IsMtrrSupported ()) { + return FixedSettings; + } + + Cr4 = PreMtrrChange (); + MtrrSetFixedMtrrWorker (FixedSettings); + PostMtrrChange (Cr4); + + return FixedSettings; +} + + +/** + This function gets the content in all MTRRs (variable and fixed) + + @param MtrrSetting A buffer to hold all Mtrrs content. + + @retval the pointer of MtrrSetting + +**/ +MTRR_SETTINGS * +EFIAPI +MtrrGetAllMtrrs ( + OUT MTRR_SETTINGS *MtrrSetting + ) +{ + if (!IsMtrrSupported ()) { + return MtrrSetting; + } + + // + // Get fixed MTRRs + // + MtrrGetFixedMtrr (&MtrrSetting->Fixed); + + // + // Get variable MTRRs + // + MtrrGetVariableMtrr (&MtrrSetting->Variables); + + // + // Get MTRR_DEF_TYPE value + // + MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE); + + return MtrrSetting; +} + + +/** + This function sets all MTRRs (variable and fixed) + + @param MtrrSetting A buffer holding all MTRRs content. + + @retval The pointer of MtrrSetting + +**/ +MTRR_SETTINGS * +EFIAPI +MtrrSetAllMtrrs ( + IN MTRR_SETTINGS *MtrrSetting + ) +{ + UINTN Cr4; + + if (!IsMtrrSupported ()) { + return MtrrSetting; + } + + Cr4 = PreMtrrChange (); + + // + // Set fixed MTRRs + // + MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed); + + // + // Set variable MTRRs + // + MtrrSetVariableMtrrWorker (&MtrrSetting->Variables); + + // + // Set MTRR_DEF_TYPE value + // + AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType); + + PostMtrrChange (Cr4); + + return MtrrSetting; +} + +/** + This function prints all MTRRs for debugging. +**/ +VOID +EFIAPI +MtrrDebugPrintAllMtrrs ( + VOID + ) +{ + DEBUG_CODE ( + MTRR_SETTINGS MtrrSettings; + UINTN Index; + UINTN Index1; + UINTN VariableMtrrCount; + UINT64 Base; + UINT64 Limit; + UINT64 MtrrBase; + UINT64 MtrrLimit; + UINT64 RangeBase; + UINT64 RangeLimit; + UINT64 NoRangeBase; + UINT64 NoRangeLimit; + UINT32 RegEax; + UINTN MemoryType; + UINTN PreviousMemoryType; + BOOLEAN Found; + + if (!IsMtrrSupported ()) { + return; + } + + DEBUG((DEBUG_CACHE, "MTRR Settings\n")); + DEBUG((DEBUG_CACHE, "=============\n")); + + MtrrGetAllMtrrs (&MtrrSettings); + DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", MtrrSettings.MtrrDefType)); + for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { + DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, MtrrSettings.Fixed.Mtrr[Index])); + } + + VariableMtrrCount = GetVariableMtrrCount (); + for (Index = 0; Index < VariableMtrrCount; Index++) { + DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n", + Index, + MtrrSettings.Variables.Mtrr[Index].Base, + MtrrSettings.Variables.Mtrr[Index].Mask + )); + } + DEBUG((DEBUG_CACHE, "\n")); + DEBUG((DEBUG_CACHE, "MTRR Ranges\n")); + DEBUG((DEBUG_CACHE, "====================================\n")); + + Base = 0; + PreviousMemoryType = MTRR_CACHE_INVALID_TYPE; + for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { + Base = mMtrrLibFixedMtrrTable[Index].BaseAddress; + for (Index1 = 0; Index1 < 8; Index1++) { + MemoryType = (UINTN)(RShiftU64 (MtrrSettings.Fixed.Mtrr[Index], Index1 * 8) & 0xff); + if (MemoryType > CacheWriteBack) { + MemoryType = MTRR_CACHE_INVALID_TYPE; + } + if (MemoryType != PreviousMemoryType) { + if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) { + DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1)); + } + PreviousMemoryType = MemoryType; + DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base)); + } + Base += mMtrrLibFixedMtrrTable[Index].Length; + } + } + DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1)); + + VariableMtrrCount = GetVariableMtrrCount (); + + Base = BASE_1MB; + PreviousMemoryType = MTRR_CACHE_INVALID_TYPE; + do { + MemoryType = MtrrGetMemoryAttribute (Base); + if (MemoryType > CacheWriteBack) { + MemoryType = MTRR_CACHE_INVALID_TYPE; + } + + if (MemoryType != PreviousMemoryType) { + if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) { + DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1)); + } + PreviousMemoryType = MemoryType; + DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base)); + } + + RangeBase = BASE_1MB; + NoRangeBase = BASE_1MB; + Limit = BIT36 - 1; + AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); + if (RegEax >= 0x80000008) { + AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); + Limit = LShiftU64 (1, RegEax & 0xff) - 1; + } + RangeLimit = Limit; + NoRangeLimit = Limit; + + for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) { + if ((MtrrSettings.Variables.Mtrr[Index].Mask & BIT11) == 0) { + // + // If mask is not valid, then do not display range + // + continue; + } + MtrrBase = (MtrrSettings.Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1))); + MtrrLimit = MtrrBase + ((~(MtrrSettings.Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit); + + if (Base >= MtrrBase && Base < MtrrLimit) { + Found = TRUE; + } + + if (Base >= MtrrBase && MtrrBase > RangeBase) { + RangeBase = MtrrBase; + } + if (Base > MtrrLimit && MtrrLimit > RangeBase) { + RangeBase = MtrrLimit + 1; + } + if (Base < MtrrBase && MtrrBase < RangeLimit) { + RangeLimit = MtrrBase - 1; + } + if (Base < MtrrLimit && MtrrLimit <= RangeLimit) { + RangeLimit = MtrrLimit; + } + + if (Base > MtrrLimit && NoRangeBase < MtrrLimit) { + NoRangeBase = MtrrLimit + 1; + } + if (Base < MtrrBase && NoRangeLimit > MtrrBase) { + NoRangeLimit = MtrrBase - 1; + } + } + + if (Found) { + Base = RangeLimit + 1; + } else { + Base = NoRangeLimit + 1; + } + } while (Found); + DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1)); + ); +} + +/** + Checks if MTRR is supported. + + @retval TRUE MTRR is supported. + @retval FALSE MTRR is not supported. + +**/ +BOOLEAN +EFIAPI +IsMtrrSupported ( + VOID + ) +{ + UINT32 RegEdx; + UINT64 MtrrCap; + + // + // Check CPUID(1).EDX[12] for MTRR capability + // + AsmCpuid (1, NULL, NULL, NULL, &RegEdx); + if (BitFieldRead32 (RegEdx, 12, 12) == 0) { + return FALSE; + } + + // + // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for + // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not + // exist, return false. + // + MtrrCap = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP); + if ((BitFieldRead64 (MtrrCap, 0, 7) == 0) || (BitFieldRead64 (MtrrCap, 8, 8) == 0)) { + return FALSE; + } + + return TRUE; +} diff --git a/CloverEFI/UefiCpuPkg/Library/MtrrLib/MtrrLib.inf b/CloverEFI/UefiCpuPkg/Library/MtrrLib/MtrrLib.inf new file mode 100755 index 0000000000..ef4a596512 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/MtrrLib/MtrrLib.inf @@ -0,0 +1,41 @@ +## @file +# MTRR library provides API for MTRR operation +# +# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MtrrLib + FILE_GUID = 6826b408-f4f3-47ee-917f-af7047f9d937 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = MtrrLib + + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + MtrrLib.c + +[Packages] + MdePkg/MdePkg.dec + CloverEFI/UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseMemoryLib + BaseLib + CpuLib + diff --git a/CloverEFI/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/IpfTimerLib.c b/CloverEFI/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/IpfTimerLib.c new file mode 100755 index 0000000000..714b99eec4 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/IpfTimerLib.c @@ -0,0 +1,216 @@ +/** @file + Timer Library functions built upon ITC on IPF. + + Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include + + +/** + Performs a delay measured as number of ticks. + + An internal function to perform a delay measured as number of ticks. It's + invoked by MicroSecondDelay() and NanoSecondDelay(). + + @param Delay The number of ticks to delay. + +**/ +VOID +EFIAPI +InternalIpfDelay ( + IN INT64 Delay + ) +{ + INT64 Ticks; + + // + // The target timer count is calculated here + // + Ticks = (INT64)AsmReadItc () + Delay; + + // + // Wait until time out + // Delay > 2^63 could not be handled by this function + // Timer wrap-arounds are handled correctly by this function + // + while (Ticks - (INT64)AsmReadItc() >= 0); +} + +/** + Stalls the CPU for at least the given number of microseconds. + + Stalls the CPU for the number of microseconds specified by MicroSeconds. + + @param MicroSeconds The minimum number of microseconds to delay. + + @return The value of MicroSeconds inputted. + +**/ +UINTN +EFIAPI +MicroSecondDelay ( + IN UINTN MicroSeconds + ) +{ + InternalIpfDelay ( + GetPerformanceCounterProperties (NULL, NULL) * + MicroSeconds / + 1000000 + ); + return MicroSeconds; +} + +/** + Stalls the CPU for at least the given number of nanoseconds. + + Stalls the CPU for the number of nanoseconds specified by NanoSeconds. + + @param NanoSeconds The minimum number of nanoseconds to delay. + + @return The value of NanoSeconds inputted. + +**/ +UINTN +EFIAPI +NanoSecondDelay ( + IN UINTN NanoSeconds + ) +{ + InternalIpfDelay ( + GetPerformanceCounterProperties (NULL, NULL) * + NanoSeconds / + 1000000000 + ); + return NanoSeconds; +} + +/** + Retrieves the current value of a 64-bit free running performance counter. + + The counter can either count up by 1 or count down by 1. If the physical + performance counter counts by a larger increment, then the counter values + must be translated. The properties of the counter can be retrieved from + GetPerformanceCounterProperties(). + + @return The current value of the free running performance counter. + +**/ +UINT64 +EFIAPI +GetPerformanceCounter ( + VOID + ) +{ + return AsmReadItc (); +} + +/** + Retrieves the 64-bit frequency in Hz and the range of performance counter + values. + + If StartValue is not NULL, then the value that the performance counter starts + with immediately after is it rolls over is returned in StartValue. If + EndValue is not NULL, then the value that the performance counter end with + immediately before it rolls over is returned in EndValue. The 64-bit + frequency of the performance counter in Hz is always returned. If StartValue + is less than EndValue, then the performance counter counts up. If StartValue + is greater than EndValue, then the performance counter counts down. For + example, a 64-bit free running counter that counts up would have a StartValue + of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter + that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0. + + @param StartValue The value the performance counter starts with when it + rolls over. + @param EndValue The value that the performance counter ends with before + it rolls over. + + @return The frequency in Hz. + +**/ +UINT64 +EFIAPI +GetPerformanceCounterProperties ( + OUT UINT64 *StartValue, OPTIONAL + OUT UINT64 *EndValue OPTIONAL + ) +{ + PAL_CALL_RETURN PalRet; + UINT64 BaseFrequence; + + if (StartValue != NULL) { + *StartValue = 0; + } + + if (EndValue != NULL) { + *EndValue = (UINT64)(-1); + } + + PalRet = PalCall (PAL_FREQ_BASE, 0, 0, 0); + if (PalRet.Status != 0) { + return 1000000; + } + BaseFrequence = PalRet.r9; + + PalRet = PalCall (PAL_FREQ_RATIOS, 0, 0, 0); + if (PalRet.Status != 0) { + return 1000000; + } + + return BaseFrequence * (PalRet.r11 >> 32) / (UINT32)PalRet.r11; +} + +/** + Converts elapsed ticks of performance counter to time in nanoseconds. + + This function converts the elapsed ticks of running performance counter to + time value in unit of nanoseconds. + + @param Ticks The number of elapsed ticks of running performance counter. + + @return The elapsed time in nanoseconds. + +**/ +UINT64 +EFIAPI +GetTimeInNanoSecond ( + IN UINT64 Ticks + ) +{ + UINT64 Frequency; + UINT64 NanoSeconds; + UINT64 Remainder; + INTN Shift; + + Frequency = GetPerformanceCounterProperties (NULL, NULL); + + // + // Ticks + // Time = --------- x 1,000,000,000 + // Frequency + // + NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u); + + // + // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit. + // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34, + // i.e. highest bit set in Remainder should <= 33. + // + Shift = MAX (0, HighBitSet64 (Remainder) - 33); + Remainder = RShiftU64 (Remainder, (UINTN) Shift); + Frequency = RShiftU64 (Frequency, (UINTN) Shift); + NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL); + + return NanoSeconds; +} diff --git a/CloverEFI/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.inf b/CloverEFI/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.inf new file mode 100755 index 0000000000..91566c6473 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.inf @@ -0,0 +1,63 @@ +## @file +# Instance of Timer Library only using CPU resources. +# +# Timer Library that only uses CPU resources to provide calibrated delays +# on IA-32, x64, and IPF. +# Note: Because CPU Local APIC and ITC could be programmed by OS, it cannot be +# used by SMM drivers and runtime drivers, ACPI timer is recommended for SMM +# drivers and runtime drivers. +# +# This library differs with the SecPeiDxeTimerLibCpu library in the MdePkg in +# that it uses the local APIC library so that it supports x2APIC mode. +# +# Copyright (c) 2010, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SecPeiDxeTimerLibUefiCpu + FILE_GUID = 4FFF2014-2086-4ee6-9B58-886D1967861C + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = TimerLib|BASE DXE_CORE DXE_DRIVER DXE_SAL_DRIVER PEIM PEI_CORE SEC UEFI_APPLICATION UEFI_DRIVER + + +# +# VALID_ARCHITECTURES = IA32 X64 IPF +# + +[Sources.Ia32, Sources.X64] + X86TimerLib.c + +[Sources.IPF] + IpfTimerLib.c + + +[Packages] + MdePkg/MdePkg.dec + CloverEFI/UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + +[LibraryClasses.IA32, LibraryClasses.X64] + PcdLib + DebugLib + LocalApicLib + +[LibraryClasses.IPF] + PalLib + + +[Pcd.IA32, Pcd.X64] + gEfiMdePkgTokenSpaceGuid.PcdFSBClock ## CONSUMES + diff --git a/CloverEFI/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/X86TimerLib.c b/CloverEFI/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/X86TimerLib.c new file mode 100755 index 0000000000..99f8121eed --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/X86TimerLib.c @@ -0,0 +1,239 @@ +/** @file + Timer Library functions built upon local APIC on IA32/x64. + + This library uses the local APIC library so that it supports x2APIC mode. + + Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include + +/** + Internal function to return the frequency of the local APIC timer. + + @return The frequency of the timer in Hz. + +**/ +UINT32 +EFIAPI +InternalX86GetTimerFrequency ( + VOID + ) +{ + UINTN Divisor; + + GetApicTimerState (&Divisor, NULL, NULL); + return PcdGet32(PcdFSBClock) / (UINT32)Divisor; +} + +/** + Stalls the CPU for at least the given number of ticks. + + Stalls the CPU for at least the given number of ticks. It's invoked by + MicroSecondDelay() and NanoSecondDelay(). + + @param Delay A period of time to delay in ticks. + +**/ +VOID +EFIAPI +InternalX86Delay ( + IN UINT32 Delay + ) +{ + INT32 Ticks; + UINT32 PowerOfTwoCounter; + + // + // The target timer count is calculated here + // + Ticks = GetApicTimerCurrentCount () - Delay; + + // + // Wait until time out + // Delay > 2^31 could not be handled by this function + // Timer wrap-arounds are handled correctly by this function + // + PowerOfTwoCounter = GetPowerOfTwo32 (GetApicTimerInitCount ()); + while (((UINT32)(GetApicTimerCurrentCount () - Ticks) & PowerOfTwoCounter) == 0) { + CpuPause (); + } +} + +/** + Stalls the CPU for at least the given number of microseconds. + + Stalls the CPU for the number of microseconds specified by MicroSeconds. + + @param MicroSeconds The minimum number of microseconds to delay. + + @return The value of MicroSeconds inputted. + +**/ +UINTN +EFIAPI +MicroSecondDelay ( + IN UINTN MicroSeconds + ) +{ + InternalX86Delay ( + (UINT32)DivU64x32 ( + MultU64x64 ( + InternalX86GetTimerFrequency (), + MicroSeconds + ), + 1000000u + ) + ); + return MicroSeconds; +} + +/** + Stalls the CPU for at least the given number of nanoseconds. + + Stalls the CPU for the number of nanoseconds specified by NanoSeconds. + + @param NanoSeconds The minimum number of nanoseconds to delay. + + @return The value of NanoSeconds inputted. + +**/ +UINTN +EFIAPI +NanoSecondDelay ( + IN UINTN NanoSeconds + ) +{ + InternalX86Delay ( + (UINT32)DivU64x32 ( + MultU64x64 ( + InternalX86GetTimerFrequency (), + NanoSeconds + ), + 1000000000u + ) + ); + return NanoSeconds; +} + +/** + Retrieves the current value of a 64-bit free running performance counter. + + The counter can either count up by 1 or count down by 1. If the physical + performance counter counts by a larger increment, then the counter values + must be translated. The properties of the counter can be retrieved from + GetPerformanceCounterProperties(). + + @return The current value of the free running performance counter. + +**/ +UINT64 +EFIAPI +GetPerformanceCounter ( + VOID + ) +{ + return (UINT64)GetApicTimerCurrentCount (); +} + +/** + Retrieves the 64-bit frequency in Hz and the range of performance counter + values. + + If StartValue is not NULL, then the value that the performance counter starts + with immediately after is it rolls over is returned in StartValue. If + EndValue is not NULL, then the value that the performance counter end with + immediately before it rolls over is returned in EndValue. The 64-bit + frequency of the performance counter in Hz is always returned. If StartValue + is less than EndValue, then the performance counter counts up. If StartValue + is greater than EndValue, then the performance counter counts down. For + example, a 64-bit free running counter that counts up would have a StartValue + of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter + that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0. + + @param StartValue The value the performance counter starts with when it + rolls over. + @param EndValue The value that the performance counter ends with before + it rolls over. + + @return The frequency in Hz. + +**/ +UINT64 +EFIAPI +GetPerformanceCounterProperties ( + OUT UINT64 *StartValue, OPTIONAL + OUT UINT64 *EndValue OPTIONAL + ) +{ + if (StartValue != NULL) { + *StartValue = (UINT64)GetApicTimerInitCount (); + // + // make sure StartValue is all 1s from High Bit + // + ASSERT ((*StartValue & (*StartValue + 1)) == 0); + } + + if (EndValue != NULL) { + *EndValue = 0; + } + + return (UINT64) InternalX86GetTimerFrequency (); +} + +/** + Converts elapsed ticks of performance counter to time in nanoseconds. + + This function converts the elapsed ticks of running performance counter to + time value in unit of nanoseconds. + + @param Ticks The number of elapsed ticks of running performance counter. + + @return The elapsed time in nanoseconds. + +**/ +UINT64 +EFIAPI +GetTimeInNanoSecond ( + IN UINT64 Ticks + ) +{ + UINT64 Frequency; + UINT64 NanoSeconds; + UINT64 Remainder; + INTN Shift; + + Frequency = GetPerformanceCounterProperties (NULL, NULL); + + // + // Ticks + // Time = --------- x 1,000,000,000 + // Frequency + // + NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u); + + // + // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit. + // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34, + // i.e. highest bit set in Remainder should <= 33. + // + Shift = MAX (0, HighBitSet64 (Remainder) - 33); + Remainder = RShiftU64 (Remainder, (UINTN) Shift); + Frequency = RShiftU64 (Frequency, (UINTN) Shift); + NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL); + + return NanoSeconds; +} diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.ia32.port80.raw b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.ia32.port80.raw new file mode 100755 index 0000000000..ec6bcfd48b Binary files /dev/null and b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.ia32.port80.raw differ diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.ia32.raw b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.ia32.raw new file mode 100755 index 0000000000..02cb66c848 Binary files /dev/null and b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.ia32.raw differ diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.ia32.serial.raw b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.ia32.serial.raw new file mode 100755 index 0000000000..58542ad9d1 Binary files /dev/null and b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.ia32.serial.raw differ diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.inf b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.inf new file mode 100755 index 0000000000..63e1e2cf56 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.inf @@ -0,0 +1,33 @@ +## @file +# Reset Vector binary +# +# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ResetVector + FILE_GUID = 1BA0062E-C779-4582-8566-336AE8F78F09 + MODULE_TYPE = SEC + VERSION_STRING = 1.1 + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Binaries.Ia32] + RAW|ResetVector.ia32.raw|* + +[Binaries.X64] + RAW|ResetVector.x64.raw|* + diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.x64.port80.raw b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.x64.port80.raw new file mode 100755 index 0000000000..393b6ef2ca Binary files /dev/null and b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.x64.port80.raw differ diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.x64.raw b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.x64.raw new file mode 100755 index 0000000000..7ab1161a21 Binary files /dev/null and b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.x64.raw differ diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.x64.serial.raw b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.x64.serial.raw new file mode 100755 index 0000000000..f32e81ac12 Binary files /dev/null and b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.x64.serial.raw differ diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Build.py b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Build.py new file mode 100755 index 0000000000..dad257c16a --- /dev/null +++ b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Build.py @@ -0,0 +1,53 @@ +## @file +# Automate the process of building the various reset vector types +# +# Copyright (c) 2009, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# + +import glob +import os +import subprocess +import sys + +def RunCommand(commandLine): + #print ' '.join(commandLine) + return subprocess.call(commandLine) + +for filename in glob.glob(os.path.join('Bin', '*.raw')): + os.remove(filename) + +for arch in ('ia32', 'x64'): + for debugType in (None, 'port80', 'serial'): + output = os.path.join('Bin', 'ResetVector') + output += '.' + arch + if debugType is not None: + output += '.' + debugType + output += '.raw' + commandLine = ( + 'nasm', + '-D', 'ARCH_%s' % arch.upper(), + '-D', 'DEBUG_%s' % str(debugType).upper(), + '-o', output, + 'ResetVectorCode.asm', + ) + ret = RunCommand(commandLine) + print '\tASM\t' + output + if ret != 0: sys.exit(ret) + + commandLine = ( + 'python', + 'Tools/FixupForRawSection.py', + output, + ) + print '\tFIXUP\t' + output + ret = RunCommand(commandLine) + if ret != 0: sys.exit(ret) + diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/CommonMacros.inc b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/CommonMacros.inc new file mode 100755 index 0000000000..b46da27686 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/CommonMacros.inc @@ -0,0 +1,31 @@ +;------------------------------------------------------------------------------ +; @file +; Common macros used in the ResetVector VTF module. +; +; Copyright (c) 2008, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +;------------------------------------------------------------------------------ + +%define ADDR16_OF(x) (0x10000 - fourGigabytes + x) +%define ADDR_OF(x) (0x100000000 - fourGigabytes + x) + +%macro OneTimeCall 1 + jmp %1 +%1 %+ OneTimerCallReturn: +%endmacro + +%macro OneTimeCallRet 1 + jmp %1 %+ OneTimerCallReturn +%endmacro + +StartOfResetVectorCode: + +%define ADDR_OF_START_OF_RESET_CODE ADDR_OF(StartOfResetVectorCode) + diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/DebugDisabled.asm b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/DebugDisabled.asm new file mode 100755 index 0000000000..883cef03e0 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/DebugDisabled.asm @@ -0,0 +1,26 @@ +;------------------------------------------------------------------------------ +; @file +; Debug disabled +; +; Copyright (c) 2009, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +;------------------------------------------------------------------------------ + +BITS 16 + +%macro debugInitialize 0 + ; + ; No initialization is required + ; +%endmacro + +%macro debugShowPostCode 1 +%endmacro + diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Ia16/Init16.asm b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Ia16/Init16.asm new file mode 100755 index 0000000000..226c49f220 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Ia16/Init16.asm @@ -0,0 +1,48 @@ +;------------------------------------------------------------------------------ +; @file +; 16-bit initialization code +; +; Copyright (c) 2008 - 2009, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +;------------------------------------------------------------------------------ + + +BITS 16 + +; +; @param[out] DI 'BP' to indicate boot-strap processor +; +EarlyBspInitReal16: + mov di, 'BP' + jmp short Main16 + +; +; @param[out] DI 'AP' to indicate application processor +; +EarlyApInitReal16: + mov di, 'AP' + jmp short Main16 + +; +; Modified: EAX +; +; @param[in] EAX Initial value of the EAX register (BIST: Built-in Self Test) +; @param[out] ESP Initial value of the EAX register (BIST: Built-in Self Test) +; +EarlyInit16: + ; + ; ESP - Initial value of the EAX register (BIST: Built-in Self Test) + ; + mov esp, eax + + debugInitialize + + OneTimeCallRet EarlyInit16 + diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Ia16/Real16ToFlat32.asm b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Ia16/Real16ToFlat32.asm new file mode 100755 index 0000000000..146df600a6 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Ia16/Real16ToFlat32.asm @@ -0,0 +1,133 @@ +;------------------------------------------------------------------------------ +; @file +; Transition from 16 bit real mode into 32 bit flat protected mode +; +; Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +;------------------------------------------------------------------------------ + +%define SEC_DEFAULT_CR0 0x40000023 +%define SEC_DEFAULT_CR4 0x640 + +BITS 16 + +; +; Modified: EAX, EBX +; +TransitionFromReal16To32BitFlat: + + debugShowPostCode POSTCODE_16BIT_MODE + + cli + + mov bx, 0xf000 + mov ds, bx + + mov bx, ADDR16_OF(gdtr) + +o32 lgdt [cs:bx] + + mov eax, SEC_DEFAULT_CR0 + mov cr0, eax + + jmp LINEAR_CODE_SEL:dword ADDR_OF(jumpTo32BitAndLandHere) +BITS 32 +jumpTo32BitAndLandHere: + + mov eax, SEC_DEFAULT_CR4 + mov cr4, eax + + debugShowPostCode POSTCODE_32BIT_MODE + + mov ax, LINEAR_SEL + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + + OneTimeCallRet TransitionFromReal16To32BitFlat + +ALIGN 2 + +gdtr: + dw GDT_END - GDT_BASE - 1 ; GDT limit + dd ADDR_OF(GDT_BASE) + +ALIGN 16 + +; +; Macros for GDT entries +; + +%define PRESENT_FLAG(p) (p << 7) +%define DPL(dpl) (dpl << 5) +%define SYSTEM_FLAG(s) (s << 4) +%define DESC_TYPE(t) (t) + +; Type: data, expand-up, writable, accessed +%define DATA32_TYPE 3 + +; Type: execute, readable, expand-up, accessed +%define CODE32_TYPE 0xb + +; Type: execute, readable, expand-up, accessed +%define CODE64_TYPE 0xb + +%define GRANULARITY_FLAG(g) (g << 7) +%define DEFAULT_SIZE32(d) (d << 6) +%define CODE64_FLAG(l) (l << 5) +%define UPPER_LIMIT(l) (l) + +; +; The Global Descriptor Table (GDT) +; + +GDT_BASE: +; null descriptor +NULL_SEL equ $-GDT_BASE + DW 0 ; limit 15:0 + DW 0 ; base 15:0 + DB 0 ; base 23:16 + DB 0 ; sys flag, dpl, type + DB 0 ; limit 19:16, flags + DB 0 ; base 31:24 + +; linear data segment descriptor +LINEAR_SEL equ $-GDT_BASE + DW 0xffff ; limit 15:0 + DW 0 ; base 15:0 + DB 0 ; base 23:16 + DB PRESENT_FLAG(1)|DPL(0)|SYSTEM_FLAG(1)|DESC_TYPE(DATA32_TYPE) + DB GRANULARITY_FLAG(1)|DEFAULT_SIZE32(1)|CODE64_FLAG(0)|UPPER_LIMIT(0xf) + DB 0 ; base 31:24 + +; linear code segment descriptor +LINEAR_CODE_SEL equ $-GDT_BASE + DW 0xffff ; limit 15:0 + DW 0 ; base 15:0 + DB 0 ; base 23:16 + DB PRESENT_FLAG(1)|DPL(0)|SYSTEM_FLAG(1)|DESC_TYPE(CODE32_TYPE) + DB GRANULARITY_FLAG(1)|DEFAULT_SIZE32(1)|CODE64_FLAG(0)|UPPER_LIMIT(0xf) + DB 0 ; base 31:24 + +%ifdef ARCH_X64 +; linear code (64-bit) segment descriptor +LINEAR_CODE64_SEL equ $-GDT_BASE + DW 0xffff ; limit 15:0 + DW 0 ; base 15:0 + DB 0 ; base 23:16 + DB PRESENT_FLAG(1)|DPL(0)|SYSTEM_FLAG(1)|DESC_TYPE(CODE64_TYPE) + DB GRANULARITY_FLAG(1)|DEFAULT_SIZE32(0)|CODE64_FLAG(1)|UPPER_LIMIT(0xf) + DB 0 ; base 31:24 +%endif + +GDT_END: + diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm new file mode 100755 index 0000000000..d0830ec87c --- /dev/null +++ b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm @@ -0,0 +1,58 @@ +;------------------------------------------------------------------------------ +; @file +; First code exectuted by processor after resetting. +; +; Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +;------------------------------------------------------------------------------ + +BITS 16 + +ALIGN 16 + +applicationProcessorEntryPoint: +; +; Application Processors entry point +; +; GenFv generates code aligned on a 4k boundary which will jump to this +; location. (0xffffffe0) This allows the Local APIC Startup IPI to be +; used to wake up the application processors. +; + jmp short EarlyApInitReal16 + +ALIGN 8 + + DD 0 + +; +; The VTF signature +; +; VTF-0 means that the VTF (Volume Top File) code does not require +; any fixups. +; +vtfSignature: + DB 'V', 'T', 'F', 0 + +ALIGN 16 + +resetVector: +; +; Reset Vector +; +; This is where the processor will begin execution +; + nop + nop + jmp short EarlyBspInitReal16 + +ALIGN 16 + +fourGigabytes: + diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Ia32/Flat32ToFlat64.asm b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Ia32/Flat32ToFlat64.asm new file mode 100755 index 0000000000..9eba864c28 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Ia32/Flat32ToFlat64.asm @@ -0,0 +1,46 @@ +;------------------------------------------------------------------------------ +; @file +; Transition from 32 bit flat protected mode into 64 bit flat protected mode +; +; Copyright (c) 2008 - 2009, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +;------------------------------------------------------------------------------ + +BITS 32 + +; +; Modified: EAX +; +Transition32FlatTo64Flat: + + mov eax, ((ADDR_OF_START_OF_RESET_CODE & ~0xfff) - 0x1000) + mov cr3, eax + + mov eax, cr4 + bts eax, 5 ; enable PAE + mov cr4, eax + + mov ecx, 0xc0000080 + rdmsr + bts eax, 8 ; set LME + wrmsr + + mov eax, cr0 + bts eax, 31 ; set PG + mov cr0, eax ; enable paging + + jmp LINEAR_CODE64_SEL:ADDR_OF(jumpTo64BitAndLandHere) +BITS 64 +jumpTo64BitAndLandHere: + + debugShowPostCode POSTCODE_64BIT_MODE + + OneTimeCallRet Transition32FlatTo64Flat + diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Ia32/SearchForBfvBase.asm b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Ia32/SearchForBfvBase.asm new file mode 100755 index 0000000000..d0c2d8c39c --- /dev/null +++ b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Ia32/SearchForBfvBase.asm @@ -0,0 +1,86 @@ +;------------------------------------------------------------------------------ +; @file +; Search for the Boot Firmware Volume (BFV) base address +; +; Copyright (c) 2008 - 2009, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +;------------------------------------------------------------------------------ + +;#define EFI_FIRMWARE_FILE_SYSTEM2_GUID \ +; { 0x8c8ce578, 0x8a3d, 0x4f1c, { 0x99, 0x35, 0x89, 0x61, 0x85, 0xc3, 0x2d, 0xd3 } } +%define FFS_GUID_DWORD0 0x8c8ce578 +%define FFS_GUID_DWORD1 0x4f1c8a3d +%define FFS_GUID_DWORD2 0x61893599 +%define FFS_GUID_DWORD3 0xd32dc385 + +BITS 32 + +; +; Modified: EAX, EBX +; Preserved: EDI, ESP +; +; @param[out] EBP Address of Boot Firmware Volume (BFV) +; +Flat32SearchForBfvBase: + + xor eax, eax +searchingForBfvHeaderLoop: + ; + ; We check for a firmware volume at every 4KB address in the top 16MB + ; just below 4GB. (Addresses at 0xffHHH000 where H is any hex digit.) + ; + sub eax, 0x1000 + cmp eax, 0xff000000 + jb searchedForBfvHeaderButNotFound + + ; + ; Check FFS GUID + ; + cmp dword [eax + 0x10], FFS_GUID_DWORD0 + jne searchingForBfvHeaderLoop + cmp dword [eax + 0x14], FFS_GUID_DWORD1 + jne searchingForBfvHeaderLoop + cmp dword [eax + 0x18], FFS_GUID_DWORD2 + jne searchingForBfvHeaderLoop + cmp dword [eax + 0x1c], FFS_GUID_DWORD3 + jne searchingForBfvHeaderLoop + + ; + ; Check FV Length + ; + cmp dword [eax + 0x24], 0 + jne searchingForBfvHeaderLoop + mov ebx, eax + add ebx, dword [eax + 0x20] + jnz searchingForBfvHeaderLoop + + jmp searchedForBfvHeaderAndItWasFound + +searchedForBfvHeaderButNotFound: + ; + ; Hang if the SEC entry point was not found + ; + debugShowPostCode POSTCODE_BFV_NOT_FOUND + + ; + ; 0xbfbfbfbf in the EAX & EBP registers helps signal what failed + ; for debugging purposes. + ; + mov eax, 0xBFBFBFBF + mov ebp, eax + jmp $ + +searchedForBfvHeaderAndItWasFound: + mov ebp, eax + + debugShowPostCode POSTCODE_BFV_FOUND + + OneTimeCallRet Flat32SearchForBfvBase + diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Ia32/SearchForSecEntry.asm b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Ia32/SearchForSecEntry.asm new file mode 100755 index 0000000000..9558b9d350 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Ia32/SearchForSecEntry.asm @@ -0,0 +1,196 @@ +;------------------------------------------------------------------------------ +; @file +; Search for the SEC Core entry point +; +; Copyright (c) 2008 - 2009, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +;------------------------------------------------------------------------------ + +BITS 32 + +%define EFI_FV_FILETYPE_SECURITY_CORE 0x03 + +; +; Modified: EAX, EBX, ECX, EDX +; Preserved: EDI, EBP, ESP +; +; @param[in] EBP Address of Boot Firmware Volume (BFV) +; @param[out] ESI SEC Core Entry Point Address +; +Flat32SearchForSecEntryPoint: + + ; + ; Initialize EBP and ESI to 0 + ; + xor ebx, ebx + mov esi, ebx + + ; + ; Pass over the BFV header + ; + mov eax, ebp + mov bx, [ebp + 0x30] + add eax, ebx + jc secEntryPointWasNotFound + + jmp searchingForFfsFileHeaderLoop + +moveForwardWhileSearchingForFfsFileHeaderLoop: + ; + ; Make forward progress in the search + ; + inc eax + jc secEntryPointWasNotFound + +searchingForFfsFileHeaderLoop: + test eax, eax + jz secEntryPointWasNotFound + + ; + ; Ensure 8 byte alignment + ; + add eax, 7 + jc secEntryPointWasNotFound + and al, 0xf8 + + ; + ; Look to see if there is an FFS file at eax + ; + mov bl, [eax + 0x17] + test bl, 0x20 + jz moveForwardWhileSearchingForFfsFileHeaderLoop + mov ecx, [eax + 0x14] + and ecx, 0x00ffffff + or ecx, ecx + jz moveForwardWhileSearchingForFfsFileHeaderLoop + add ecx, eax + jz jumpSinceWeFoundTheLastFfsFile + jc moveForwardWhileSearchingForFfsFileHeaderLoop +jumpSinceWeFoundTheLastFfsFile: + + ; + ; There seems to be a valid file at eax + ; + cmp byte [eax + 0x12], EFI_FV_FILETYPE_SECURITY_CORE ; Check File Type + jne readyToTryFfsFileAtEcx + +fileTypeIsSecCore: + OneTimeCall GetEntryPointOfFfsFile + test eax, eax + jnz doneSeachingForSecEntryPoint + +readyToTryFfsFileAtEcx: + ; + ; Try the next FFS file at ECX + ; + mov eax, ecx + jmp searchingForFfsFileHeaderLoop + +secEntryPointWasNotFound: + xor eax, eax + +doneSeachingForSecEntryPoint: + mov esi, eax + + test esi, esi + jnz secCoreEntryPointWasFound + +secCoreEntryPointWasNotFound: + ; + ; Hang if the SEC entry point was not found + ; + debugShowPostCode POSTCODE_SEC_NOT_FOUND + jz $ + +secCoreEntryPointWasFound: + debugShowPostCode POSTCODE_SEC_FOUND + + OneTimeCallRet Flat32SearchForSecEntryPoint + +%define EFI_SECTION_PE32 0x10 + +; +; Input: +; EAX - Start of FFS file +; ECX - End of FFS file +; +; Output: +; EAX - Entry point of PE32 (or 0 if not found) +; +; Modified: +; EBX +; +GetEntryPointOfFfsFile: + test eax, eax + jz getEntryPointOfFfsFileErrorReturn + add eax, 0x18 ; EAX = Start of section + +getEntryPointOfFfsFileLoopForSections: + cmp eax, ecx + jae getEntryPointOfFfsFileErrorReturn + + cmp byte [eax + 3], EFI_SECTION_PE32 + je getEntryPointOfFfsFileFoundPe32Section + + ; + ; The section type was not PE32, so move to next section + ; + mov ebx, dword [eax] + and ebx, 0x00ffffff + add eax, ebx + jc getEntryPointOfFfsFileErrorReturn + + ; + ; Ensure that FFS section is 32-bit aligned + ; + add eax, 3 + jc getEntryPointOfFfsFileErrorReturn + and al, 0xfc + jmp getEntryPointOfFfsFileLoopForSections + +getEntryPointOfFfsFileFoundPe32Section: + add eax, 4 ; EAX = Start of PE32 image + + mov ebx, eax + cmp word [eax], 'MZ' + jne thereIsNotAnMzSignature + movzx ebx, word [eax + 0x3c] + add ebx, eax +thereIsNotAnMzSignature: + + ; if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) + cmp word [ebx], 'VZ' + jne thereIsNoVzSignature + ; *EntryPoint = (VOID *)((UINTN)Pe32Data + + ; (UINTN)(Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + + ; sizeof(EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize); + add eax, [ebx + 0x8] + add eax, 0x28 + movzx ebx, word [ebx + 0x6] + sub eax, ebx + jmp getEntryPointOfFfsFileReturn + +thereIsNoVzSignature: + + ; if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) + cmp dword [ebx], `PE\x00\x00` + jne getEntryPointOfFfsFileErrorReturn + + ; *EntryPoint = (VOID *)((UINTN)Pe32Data + + ; (UINTN)(Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff)); + add eax, [ebx + 0x4 + 0x14 + 0x10] + jmp getEntryPointOfFfsFileReturn + +getEntryPointOfFfsFileErrorReturn: + mov eax, 0 + +getEntryPointOfFfsFileReturn: + OneTimeCallRet GetEntryPointOfFfsFile + diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Main.asm b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Main.asm new file mode 100755 index 0000000000..ebfb9015d4 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Main.asm @@ -0,0 +1,106 @@ +;------------------------------------------------------------------------------ +; @file +; Main routine of the pre-SEC code up through the jump into SEC +; +; Copyright (c) 2008 - 2009, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +;------------------------------------------------------------------------------ + + +BITS 16 + +; +; Modified: EBX, ECX, EDX, EBP +; +; @param[in,out] RAX/EAX Initial value of the EAX register +; (BIST: Built-in Self Test) +; @param[in,out] DI 'BP': boot-strap processor, or +; 'AP': application processor +; @param[out] RBP/EBP Address of Boot Firmware Volume (BFV) +; +; @return None This routine jumps to SEC and does not return +; +Main16: + OneTimeCall EarlyInit16 + + ; + ; Transition the processor from 16-bit real mode to 32-bit flat mode + ; + OneTimeCall TransitionFromReal16To32BitFlat + +BITS 32 + + ; + ; Search for the Boot Firmware Volume (BFV) + ; + OneTimeCall Flat32SearchForBfvBase + + ; + ; EBP - Start of BFV + ; + + ; + ; Search for the SEC entry point + ; + OneTimeCall Flat32SearchForSecEntryPoint + + ; + ; ESI - SEC Core entry point + ; EBP - Start of BFV + ; + +%ifdef ARCH_IA32 + + ; + ; Restore initial EAX value into the EAX register + ; + mov eax, esp + + ; + ; Jump to the 32-bit SEC entry point + ; + jmp esi + +%else + + ; + ; Transition the processor from 32-bit flat mode to 64-bit flat mode + ; + OneTimeCall Transition32FlatTo64Flat + +BITS 64 + + ; + ; Some values were calculated in 32-bit mode. Make sure the upper + ; 32-bits of 64-bit registers are zero for these values. + ; + mov rax, 0x00000000ffffffff + and rsi, rax + and rbp, rax + and rsp, rax + + ; + ; RSI - SEC Core entry point + ; RBP - Start of BFV + ; + + ; + ; Restore initial EAX value into the RAX register + ; + mov rax, rsp + + ; + ; Jump to the 64-bit SEC entry point + ; + jmp rsi + +%endif + + diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Port80Debug.asm b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Port80Debug.asm new file mode 100755 index 0000000000..4b13c4860b --- /dev/null +++ b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Port80Debug.asm @@ -0,0 +1,28 @@ +;------------------------------------------------------------------------------ +; @file +; Port 0x80 debug support macros +; +; Copyright (c) 2009, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +;------------------------------------------------------------------------------ + +BITS 16 + +%macro debugInitialize 0 + ; + ; No initialization is required + ; +%endmacro + +%macro debugShowPostCode 1 + mov al, %1 + out 0x80, al +%endmacro + diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/PostCodes.inc b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/PostCodes.inc new file mode 100755 index 0000000000..62eda5d992 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/PostCodes.inc @@ -0,0 +1,25 @@ +;------------------------------------------------------------------------------ +; @file +; Definitions of POST CODES for the reset vector module +; +; Copyright (c) 2009, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +;------------------------------------------------------------------------------ + +%define POSTCODE_16BIT_MODE 0x16 +%define POSTCODE_32BIT_MODE 0x32 +%define POSTCODE_64BIT_MODE 0x64 + +%define POSTCODE_BFV_NOT_FOUND 0xb0 +%define POSTCODE_BFV_FOUND 0xb1 + +%define POSTCODE_SEC_NOT_FOUND 0xf0 +%define POSTCODE_SEC_FOUND 0xf1 + diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/ReadMe.txt b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/ReadMe.txt new file mode 100755 index 0000000000..1b3d6643e5 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/ReadMe.txt @@ -0,0 +1,41 @@ + +=== HOW TO USE VTF0 === + +Add this line to your FDF FV section: +INF RuleOverride=RESET_VECTOR USE = IA32 CloverEFI/UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.inf +(For X64 SEC/PEI change IA32 to X64 => 'USE = X64') + +In your FDF FFS file rules sections add: +[Rule.Common.SEC.RESET_VECTOR] + FILE RAW = $(NAMED_GUID) { + RAW RAW |.raw + } + +=== VTF0 Boot Flow === + +1. Transition to IA32 flat mode +2. Locate BFV (Boot Firmware Volume) by checking every 4kb boundary +3. Locate SEC image +4. X64 VTF0 transitions to X64 mode +5. Call SEC image entry point + +== VTF0 SEC input parameters == + +All inputs to SEC image are register based: +EAX/RAX - Initial value of the EAX register (BIST: Built-in Self Test) +DI - 'BP': boot-strap processor, or 'AP': application processor +EBP/RBP - Pointer to the start of the Boot Firmware Volume + +=== HOW TO BUILD VTF0 === + +Dependencies: +* Python 2.5~2.7 +* Nasm 2.03 or newer + +To rebuild the VTF0 binaries: +1. Change to VTF0 source dir: UefiCpuPkg/ResetVector/Vtf0 +2. nasm and python should be in executable path +3. Run this command: + python Build.py +4. Binaries output will be in UefiCpuPkg/ResetVector/Vtf0/Bin + diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/ResetVectorCode.asm b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/ResetVectorCode.asm new file mode 100755 index 0000000000..96f686b0e6 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/ResetVectorCode.asm @@ -0,0 +1,52 @@ +;------------------------------------------------------------------------------ +; @file +; This file includes all other code files to assemble the reset vector code +; +; Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +;------------------------------------------------------------------------------ + +%ifdef ARCH_IA32 + %ifdef ARCH_X64 + %error "Only one of ARCH_IA32 or ARCH_X64 can be defined." + %endif +%elifdef ARCH_X64 +%else + %error "Either ARCH_IA32 or ARCH_X64 must be defined." +%endif + +%include "CommonMacros.inc" + +%include "PostCodes.inc" + +%ifdef DEBUG_NONE + %include "DebugDisabled.asm" +%elifdef DEBUG_PORT80 + %include "Port80Debug.asm" +%elifdef DEBUG_SERIAL + %include "SerialDebug.asm" +%else + %error "No debug type was specified." +%endif + +%include "Ia32/SearchForBfvBase.asm" +%include "Ia32/SearchForSecEntry.asm" + +%ifdef ARCH_X64 +%include "Ia32/Flat32ToFlat64.asm" +%endif + +%include "Ia16/Real16ToFlat32.asm" +%include "Ia16/Init16.asm" + +%include "Main.asm" + +%include "Ia16/ResetVectorVtf0.asm" + diff --git a/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/SerialDebug.asm b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/SerialDebug.asm new file mode 100755 index 0000000000..ebd0910f4a --- /dev/null +++ b/CloverEFI/UefiCpuPkg/ResetVector/Vtf0/SerialDebug.asm @@ -0,0 +1,132 @@ +;------------------------------------------------------------------------------ +; @file +; Serial port debug support macros +; +; Copyright (c) 2008 - 2009, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +;------------------------------------------------------------------------------ + +;//--------------------------------------------- +;// UART Register Offsets +;//--------------------------------------------- +%define BAUD_LOW_OFFSET 0x00 +%define BAUD_HIGH_OFFSET 0x01 +%define IER_OFFSET 0x01 +%define LCR_SHADOW_OFFSET 0x01 +%define FCR_SHADOW_OFFSET 0x02 +%define IR_CONTROL_OFFSET 0x02 +%define FCR_OFFSET 0x02 +%define EIR_OFFSET 0x02 +%define BSR_OFFSET 0x03 +%define LCR_OFFSET 0x03 +%define MCR_OFFSET 0x04 +%define LSR_OFFSET 0x05 +%define MSR_OFFSET 0x06 + +;//--------------------------------------------- +;// UART Register Bit Defines +;//--------------------------------------------- +%define LSR_TXRDY 0x20 +%define LSR_RXDA 0x01 +%define DLAB 0x01 + +; UINT16 gComBase = 0x3f8; +; UINTN gBps = 115200; +; UINT8 gData = 8; +; UINT8 gStop = 1; +; UINT8 gParity = 0; +; UINT8 gBreakSet = 0; + +%define DEFAULT_COM_BASE 0x3f8 +%define DEFAULT_BPS 115200 +%define DEFAULT_DATA 8 +%define DEFAULT_STOP 1 +%define DEFAULT_PARITY 0 +%define DEFAULT_BREAK_SET 0 + +%define SERIAL_DEFAULT_LCR ( \ + (DEFAULT_BREAK_SET << 6) | \ + (DEFAULT_PARITY << 3) | \ + (DEFAULT_STOP << 2) | \ + (DEFAULT_DATA - 5) \ + ) + +%define SERIAL_PORT_IO_BASE_ADDRESS DEFAULT_COM_BASE + +%macro inFromSerialPort 1 + mov dx, (SERIAL_PORT_IO_BASE_ADDRESS + %1) + in al, dx +%endmacro + +%macro waitForSerialTxReady 0 + +%%waitingForTx: + inFromSerialPort LSR_OFFSET + test al, LSR_TXRDY + jz %%waitingForTx + +%endmacro + +%macro outToSerialPort 2 + mov dx, (SERIAL_PORT_IO_BASE_ADDRESS + %1) + mov al, %2 + out dx, al +%endmacro + +%macro debugShowCharacter 1 + waitForSerialTxReady + outToSerialPort 0, %1 +%endmacro + +%macro debugShowHexDigit 1 + %if (%1 < 0xa) + debugShowCharacter BYTE ('0' + (%1)) + %else + debugShowCharacter BYTE ('a' + ((%1) - 0xa)) + %endif +%endmacro + +%macro debugNewline 0 + debugShowCharacter `\r` + debugShowCharacter `\n` +%endmacro + +%macro debugShowPostCode 1 + debugShowHexDigit (((%1) >> 4) & 0xf) + debugShowHexDigit ((%1) & 0xf) + debugNewline +%endmacro + +BITS 16 + +%macro debugInitialize 0 + jmp real16InitDebug +real16InitDebugReturn: +%endmacro + +real16InitDebug: + ; + ; Set communications format + ; + outToSerialPort LCR_OFFSET, ((DLAB << 7) | SERIAL_DEFAULT_LCR) + + ; + ; Configure baud rate + ; + outToSerialPort BAUD_HIGH_OFFSET, ((115200 / DEFAULT_BPS) >> 8) + outToSerialPort BAUD_LOW_OFFSET, ((115200 / DEFAULT_BPS) & 0xff) + + ; + ; Switch back to bank 0 + ; + outToSerialPort LCR_OFFSET, SERIAL_DEFAULT_LCR + + jmp real16InitDebugReturn + diff --git a/CloverEFI/UefiCpuPkg/UefiCpuPkg.dec b/CloverEFI/UefiCpuPkg/UefiCpuPkg.dec new file mode 100755 index 0000000000..31b7303e6f --- /dev/null +++ b/CloverEFI/UefiCpuPkg/UefiCpuPkg.dec @@ -0,0 +1,46 @@ +## @file UefiCpuPkg.dec +# +# This Package provides UEFI compatible CPU modules and libraries. +# +# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials are licensed and made available under +# the terms and conditions of the BSD License which accompanies this distribution. +# The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + DEC_SPECIFICATION = 0x00010005 + PACKAGE_NAME = UefiCpuPkg + PACKAGE_GUID = 2171df9b-0d39-45aa-ac37-2de190010d23 + PACKAGE_VERSION = 0.1 + +[Includes] + Include + +[LibraryClasses] + ## @libraryclass Defines some routines that are generic for IA32 family CPU + ## to be UEFI specification compliant. + ## + UefiCpuLib|Include/Library/UefiCpuLib.h + +[LibraryClasses.IA32, LibraryClasses.X64] + ## @libraryclass Provides functions to manage MTRR settings on IA32 and X64 CPUs. + ## + MtrrLib|Include/Library/MtrrLib.h + + ## @libraryclass Provides functions to manage the Local APIC on IA32 and X64 CPUs. + ## + LocalApicLib|Include/Library/LocalApicLib.h + +[Guids] + gUefiCpuPkgTokenSpaceGuid = { 0xac05bf33, 0x995a, 0x4ed4, { 0xaa, 0xb8, 0xef, 0x7a, 0xe8, 0xf, 0x5c, 0xb0 }} + +[PcdsFixedAtBuild, PcdsPatchableInModule] + gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress|0xfee00000|UINT32|0x00000001 + diff --git a/CloverEFI/UefiCpuPkg/UefiCpuPkg.dsc b/CloverEFI/UefiCpuPkg/UefiCpuPkg.dsc new file mode 100755 index 0000000000..c4c4e30854 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/UefiCpuPkg.dsc @@ -0,0 +1,89 @@ +## @file +# UefiCpuPkg Package +# +# Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + PLATFORM_NAME = UefiCpu + PLATFORM_GUID = a1b7be22-78b3-4260-9569-8649e8c17d49 + PLATFORM_VERSION = 0.1 + DSC_SPECIFICATION = 0x00010005 + OUTPUT_DIRECTORY = Build/UefiCpu + SUPPORTED_ARCHITECTURES = IA32|IPF|X64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + +# +# External libraries to build package +# + +[LibraryClasses] + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf + DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf + IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf + MtrrLib|CloverEFI/UefiCpuPkg/Library/MtrrLib/MtrrLib.inf + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf + DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf + PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf + PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf + PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf + TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf + DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf + LocalApicLib|CloverEFI/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf + ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf + +[LibraryClasses.common.PEIM] + MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf + HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf + LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf + +[LibraryClasses.IA32.PEIM, LibraryClasses.X64.PEIM] + PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLibIdt/PeiServicesTablePointerLibIdt.inf + +[LibraryClasses.IPF.PEIM] + PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLibKr7/PeiServicesTablePointerLibKr7.inf + +[LibraryClasses.common.DXE_DRIVER] + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + +[LibraryClasses.common.DXE_SMM_DRIVER] + SmmServicesTableLib|MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.inf + MemoryAllocationLib|MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf + +# +# Drivers/Libraries within this package +# + +[Components] + CloverEFI/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf + CloverEFI/UefiCpuPkg/CpuIoPei/CpuIoPei.inf + CloverEFI/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.inf + +[Components.IA32, Components.X64] + CloverEFI/UefiCpuPkg/CpuDxe/CpuDxe.inf + CloverEFI/UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf + CloverEFI/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf + CloverEFI/UefiCpuPkg/Library/MtrrLib/MtrrLib.inf + CloverEFI/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf + CloverEFI/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf + CloverEFI/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf + diff --git a/CloverEFI/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume.c b/CloverEFI/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume.c new file mode 100755 index 0000000000..58ba2a9ed9 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume.c @@ -0,0 +1,991 @@ +/** @file + This module produces the EFI_PEI_S3_RESUME_PPI. + This module works with StandAloneBootScriptExecutor to S3 resume to OS. + This module will excute the boot script saved during last boot and after that, + control is passed to OS waking up handler. + + Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions + of the BSD License which accompanies this distribution. The + full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma pack(1) +typedef union { + struct { + UINT32 LimitLow : 16; + UINT32 BaseLow : 16; + UINT32 BaseMid : 8; + UINT32 Type : 4; + UINT32 System : 1; + UINT32 Dpl : 2; + UINT32 Present : 1; + UINT32 LimitHigh : 4; + UINT32 Software : 1; + UINT32 Reserved : 1; + UINT32 DefaultSize : 1; + UINT32 Granularity : 1; + UINT32 BaseHigh : 8; + } Bits; + UINT64 Uint64; +} IA32_GDT; + +// +// 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; +} PAGE_MAP_AND_DIRECTORY_POINTER; + +// +// 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; +} PAGE_TABLE_ENTRY; + +// +// Page Table Entry 1GB +// +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:17; // Must be zero; + UINT64 PageTableBaseAddress:22; // 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; +} PAGE_TABLE_1G_ENTRY; + +#pragma pack() + +// +// Function prototypes +// +/** + a ASM function to transfer control to OS. + + @param S3WakingVector The S3 waking up vector saved in ACPI Facs table + @param AcpiLowMemoryBase a buffer under 1M which could be used during the transfer +**/ +typedef +VOID +(EFIAPI *ASM_TRANSFER_CONTROL) ( + IN UINT32 S3WakingVector, + IN UINT32 AcpiLowMemoryBase + ); + +/** + Restores the platform to its preboot configuration for an S3 resume and + jumps to the OS waking vector. + + This function will restore the platform to its pre-boot configuration that was + pre-stored in the boot script table and transfer control to OS waking vector. + Upon invocation, this function is responsible for locating the following + information before jumping to OS waking vector: + - ACPI tables + - boot script table + - any other information that it needs + + The S3RestoreConfig() function then executes the pre-stored boot script table + and transitions the platform to the pre-boot state. The boot script is recorded + during regular boot using the EFI_S3_SAVE_STATE_PROTOCOL.Write() and + EFI_S3_SMM_SAVE_STATE_PROTOCOL.Write() functions. Finally, this function + transfers control to the OS waking vector. If the OS supports only a real-mode + waking vector, this function will switch from flat mode to real mode before + jumping to the waking vector. If all platform pre-boot configurations are + successfully restored and all other necessary information is ready, this + function will never return and instead will directly jump to the OS waking + vector. If this function returns, it indicates that the attempt to resume + from the ACPI S3 sleep state failed. + + @param[in] This Pointer to this instance of the PEI_S3_RESUME_PPI + + @retval EFI_ABORTED Execution of the S3 resume boot script table failed. + @retval EFI_NOT_FOUND Some necessary information that is used for the S3 + resume boot path could not be located. + +**/ +EFI_STATUS +EFIAPI +S3RestoreConfig2 ( + IN EFI_PEI_S3_RESUME2_PPI *This + ); + +// +// Globals +// +EFI_PEI_S3_RESUME2_PPI mS3ResumePpi = { S3RestoreConfig2 }; + +EFI_PEI_PPI_DESCRIPTOR mPpiList = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiS3Resume2PpiGuid, + &mS3ResumePpi +}; + +EFI_PEI_PPI_DESCRIPTOR mPpiListPostScriptTable = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gPeiPostScriptTablePpiGuid, + 0 +}; + +EFI_PEI_PPI_DESCRIPTOR mPpiListEndOfPeiTable = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiEndOfPeiSignalPpiGuid, + 0 +}; + +// +// Global Descriptor Table (GDT) +// +GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries[] = { +/* selector { Global Segment Descriptor } */ +/* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, +/* 0x08 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, +/* 0x10 */ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 0, 1, 1, 0}}, +/* 0x18 */ {{0xFFFF, 0, 0, 0x3, 1, 0, 1, 0xF, 0, 0, 1, 1, 0}}, +/* 0x20 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, +/* 0x28 */ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 0, 0, 1, 0}}, +/* 0x30 */ {{0xFFFF, 0, 0, 0x3, 1, 0, 1, 0xF, 0, 0, 0, 1, 0}}, +/* 0x38 */ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 1, 0, 1, 0}}, +/* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, +}; + +// +// IA32 Gdt register +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR mGdt = { + sizeof (mGdtEntries) - 1, + (UINTN) mGdtEntries + }; + +/** + Performance measure function to get S3 detailed performance data. + + This function will getS3 detailed performance data and saved in pre-reserved ACPI memory. +**/ +VOID +WriteToOsS3PerformanceData ( + VOID + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS mAcpiLowMemoryBase; + PERF_HEADER *PerfHeader; + PERF_DATA *PerfData; + UINT64 Ticker; + UINTN Index; + EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariableServices; + UINTN VarSize; + UINTN LogEntryKey; + CONST VOID *Handle; + CONST CHAR8 *Token; + CONST CHAR8 *Module; + UINT64 StartTicker; + UINT64 EndTicker; + UINT64 StartValue; + UINT64 EndValue; + BOOLEAN CountUp; + UINT64 Freq; + + // + // Retrive time stamp count as early as possilbe + // + Ticker = GetPerformanceCounter (); + + Freq = GetPerformanceCounterProperties (&StartValue, &EndValue); + + Freq = DivU64x32 (Freq, 1000); + + Status = PeiServicesLocatePpi ( + &gEfiPeiReadOnlyVariable2PpiGuid, + 0, + NULL, + (VOID **) &VariableServices + ); + ASSERT_EFI_ERROR (Status); + + VarSize = sizeof (EFI_PHYSICAL_ADDRESS); + Status = VariableServices->GetVariable ( + VariableServices, + L"PerfDataMemAddr", + &gPerformanceProtocolGuid, + NULL, + &VarSize, + &mAcpiLowMemoryBase + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fail to retrieve variable to log S3 performance data \n")); + return; + } + + PerfHeader = (PERF_HEADER *) (UINTN) mAcpiLowMemoryBase; + + if (PerfHeader->Signiture != PERFORMANCE_SIGNATURE) { + DEBUG ((EFI_D_ERROR, "Performance data in ACPI memory get corrupted! \n")); + return; + } + + // + // Record total S3 resume time. + // + if (EndValue >= StartValue) { + PerfHeader->S3Resume = Ticker - StartValue; + CountUp = TRUE; + } else { + PerfHeader->S3Resume = StartValue - Ticker; + CountUp = FALSE; + } + + // + // Get S3 detailed performance data + // + Index = 0; + LogEntryKey = 0; + while ((LogEntryKey = GetPerformanceMeasurement ( + LogEntryKey, + &Handle, + &Token, + &Module, + &StartTicker, + &EndTicker)) != 0) { + if (EndTicker != 0) { + PerfData = &PerfHeader->S3Entry[Index]; + + // + // Use File Handle to specify the different performance log for PEIM. + // File Handle is the base address of PEIM FFS file. + // + if ((AsciiStrnCmp (Token, "PEIM", PEI_PERFORMANCE_STRING_SIZE) == 0) && (Handle != NULL)) { + AsciiSPrint (PerfData->Token, PERF_TOKEN_LENGTH, "0x%11p", Handle); + } else { + AsciiStrnCpyS (PerfData->Token, PERF_TOKEN_LENGTH+1, Token, PERF_TOKEN_LENGTH); + } + if (StartTicker == 1) { + StartTicker = StartValue; + } + if (EndTicker == 1) { + EndTicker = StartValue; + } + Ticker = CountUp? (EndTicker - StartTicker) : (StartTicker - EndTicker); + PerfData->Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); + + // + // Only Record > 1ms performance data so that more big performance can be recorded. + // + if ((Ticker > Freq) && (++Index >= PERF_PEI_ENTRY_MAX_NUM)) { + // + // Reach the maximum number of PEI performance log entries. + // + break; + } + } + } + PerfHeader->S3EntryNum = (UINT32) Index; +} + +/** + Jump to OS waking vector. + The function will install boot script done PPI, report S3 resume status code, and then jump to OS waking vector. + + @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT + @param PeiS3ResumeState a pointer to a structure of PEI_S3_RESUME_STATE +**/ +VOID +EFIAPI +S3ResumeBootOs ( + IN ACPI_S3_CONTEXT *AcpiS3Context, + IN PEI_S3_RESUME_STATE *PeiS3ResumeState + ) +{ + EFI_STATUS Status; + EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs; + ASM_TRANSFER_CONTROL AsmTransferControl; + UINTN TempStackTop; + UINTN TempStack[0x10]; + + // + // Restore IDT + // + AsmWriteIdtr (&PeiS3ResumeState->Idtr); + + // + // Install BootScriptDonePpi + // + Status = PeiServicesInstallPpi (&mPpiListPostScriptTable); + ASSERT_EFI_ERROR (Status); + + // + // Get ACPI Table Address + // + Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable)); + + if ((Facs == NULL) || + (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) || + ((Facs->FirmwareWakingVector == 0) && (Facs->XFirmwareWakingVector == 0)) ) { + CpuDeadLoop (); + return ; + } + + // + // report status code on S3 resume + // + REPORT_STATUS_CODE (EFI_PROGRESS_CODE, EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_OS_WAKE); + + // + // Install EndOfPeiPpi + // + Status = PeiServicesInstallPpi (&mPpiListEndOfPeiTable); + ASSERT_EFI_ERROR (Status); + + PERF_CODE ( + WriteToOsS3PerformanceData (); + ); + + AsmTransferControl = (ASM_TRANSFER_CONTROL)(UINTN)PeiS3ResumeState->AsmTransferControl; + if (Facs->XFirmwareWakingVector != 0) { + // + // Switch to native waking vector + // + TempStackTop = (UINTN)&TempStack + sizeof(TempStack); + if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) && + ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) && + ((Facs->Flags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) { + // + // X64 long mode waking vector + // + DEBUG (( EFI_D_ERROR, "Transfer to 64bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector)); + if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { + AsmEnablePaging64 ( + 0x38, + Facs->XFirmwareWakingVector, + 0, + 0, + (UINT64)(UINTN)TempStackTop + ); + } else { + DEBUG (( EFI_D_ERROR, "Unsupported for 32bit DXE transfer to 64bit OS waking vector!\r\n")); + ASSERT (FALSE); + } + } else { + // + // IA32 protected mode waking vector (Page disabled) + // + DEBUG (( EFI_D_ERROR, "Transfer to 32bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector)); + SwitchStack ( + (SWITCH_STACK_ENTRY_POINT) (UINTN) Facs->XFirmwareWakingVector, + NULL, + NULL, + (VOID *)(UINTN)TempStackTop + ); + } + } else { + // + // 16bit Realmode waking vector + // + DEBUG (( EFI_D_ERROR, "Transfer to 16bit OS waking vector - %x\r\n", (UINTN)Facs->FirmwareWakingVector)); + AsmTransferControl (Facs->FirmwareWakingVector, 0x0); + } + + // + // Never run to here + // + CpuDeadLoop(); +} + +/** + Restore S3 page table because we do not trust ACPINvs content. + If BootScriptExector driver will not run in 64-bit mode, this function will do nothing. + + @param S3NvsPageTableAddress PageTableAddress in ACPINvs +**/ +VOID +RestoreS3PageTables ( + IN UINTN S3NvsPageTableAddress + ) +{ +/* if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { + UINT32 RegEax; + UINT32 RegEdx; + UINT8 PhysicalAddressBits; + EFI_PHYSICAL_ADDRESS PageAddress; + UINTN IndexOfPml4Entries; + UINTN IndexOfPdpEntries; + UINTN IndexOfPageDirectoryEntries; + UINT32 NumberOfPml4EntriesNeeded; + UINT32 NumberOfPdpEntriesNeeded; + PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry; + PAGE_MAP_AND_DIRECTORY_POINTER *PageMap; + PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry; + PAGE_TABLE_ENTRY *PageDirectoryEntry; + VOID *Hob; + BOOLEAN Page1GSupport; + PAGE_TABLE_1G_ENTRY *PageDirectory1GEntry; + + // + // NOTE: We have to ASSUME the page table generation format, because we do not know whole page table information. + // The whole page table is too large to be saved in SMRAM. + // + // The assumption is : whole page table is allocated in CONTINOUS memory and CR3 points to TOP page. + // + DEBUG ((EFI_D_ERROR, "S3NvsPageTableAddress - %x\n", S3NvsPageTableAddress)); + + // + // By architecture only one PageMapLevel4 exists - so lets allocate storgage for it. + // + PageMap = (PAGE_MAP_AND_DIRECTORY_POINTER *)S3NvsPageTableAddress; + S3NvsPageTableAddress += SIZE_4KB; + + Page1GSupport = FALSE; + AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); + if (RegEax >= 0x80000001) { + AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx); + if ((RegEdx & BIT26) != 0) { + Page1GSupport = TRUE; + } + } + + // + // Get physical address bits supported. + // + Hob = GetFirstHob (EFI_HOB_TYPE_CPU); + if (Hob != NULL) { + PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace; + } else { + AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); + if (RegEax >= 0x80000008) { + AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); + PhysicalAddressBits = (UINT8) RegEax; + } else { + PhysicalAddressBits = 36; + } + } + + // + // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses. + // + ASSERT (PhysicalAddressBits <= 52); + if (PhysicalAddressBits > 48) { + PhysicalAddressBits = 48; + } + + // + // Calculate the table entries needed. + // + if (PhysicalAddressBits <= 39) { + NumberOfPml4EntriesNeeded = 1; + NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30)); + } else { + NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39)); + NumberOfPdpEntriesNeeded = 512; + } + + PageMapLevel4Entry = PageMap; + PageAddress = 0; + for (IndexOfPml4Entries = 0; IndexOfPml4Entries < NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++) { + // + // Each PML4 entry points to a page of Page Directory Pointer entires. + // So lets allocate space for them and fill them in in the IndexOfPdpEntries loop. + // + PageDirectoryPointerEntry = (PAGE_MAP_AND_DIRECTORY_POINTER *)S3NvsPageTableAddress; + S3NvsPageTableAddress += SIZE_4KB; + + // + // Make a PML4 Entry + // + PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry; + PageMapLevel4Entry->Bits.ReadWrite = 1; + PageMapLevel4Entry->Bits.Present = 1; + + if (Page1GSupport) { + PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry; + + for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) { + // + // Fill in the Page Directory entries + // + PageDirectory1GEntry->Uint64 = (UINT64)PageAddress; + PageDirectory1GEntry->Bits.ReadWrite = 1; + PageDirectory1GEntry->Bits.Present = 1; + PageDirectory1GEntry->Bits.MustBe1 = 1; + } + } else { + for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) { + // + // Each Directory Pointer entries points to a page of Page Directory entires. + // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop. + // + PageDirectoryEntry = (PAGE_TABLE_ENTRY *)S3NvsPageTableAddress; + S3NvsPageTableAddress += SIZE_4KB; + + // + // Fill in a Page Directory Pointer Entries + // + PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry; + PageDirectoryPointerEntry->Bits.ReadWrite = 1; + PageDirectoryPointerEntry->Bits.Present = 1; + + for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) { + // + // Fill in the Page Directory entries + // + PageDirectoryEntry->Uint64 = (UINT64)PageAddress; + PageDirectoryEntry->Bits.ReadWrite = 1; + PageDirectoryEntry->Bits.Present = 1; + PageDirectoryEntry->Bits.MustBe1 = 1; + } + } + } + } + return ; + } else { + // + // If DXE is running 32-bit mode, no need to establish page table. + // + return ; + } */ + return; +} + +/** + Jump to boot script executor driver. + + The function will close and lock SMRAM and then jump to boot script execute driver to executing S3 boot script table. + + @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT + @param EfiBootScriptExecutorVariable The function entry to executing S3 boot Script table. This function is build in + boot script execute driver +**/ +VOID +EFIAPI +S3ResumeExecuteBootScript ( + IN ACPI_S3_CONTEXT *AcpiS3Context, + IN BOOT_SCRIPT_EXECUTOR_VARIABLE *EfiBootScriptExecutorVariable + ) +{ + EFI_STATUS Status; + PEI_SMM_ACCESS_PPI *SmmAccess; + UINTN Index; + VOID *GuidHob; + IA32_DESCRIPTOR *IdtDescriptor; + VOID *IdtBuffer; + PEI_S3_RESUME_STATE *PeiS3ResumeState; + + DEBUG ((EFI_D_ERROR, "S3ResumeExecuteBootScript()\n")); + + // + // Attempt to use content from SMRAM first + // + GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid); + if (GuidHob != NULL) { + // + // Last step for SMM - send SMI for initialization + // + + // + // Send SMI to APs + // + SendSmiIpiAllExcludingSelf (); + // + // Send SMI to BSP + // + SendSmiIpi (GetApicId ()); + + Status = PeiServicesLocatePpi ( + &gPeiSmmAccessPpiGuid, + 0, + NULL, + (VOID **) &SmmAccess + ); + + DEBUG ((EFI_D_ERROR, "Close all SMRAM regions before executing boot script\n")); + + for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) { + Status = SmmAccess->Close ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index); + } + + DEBUG ((EFI_D_ERROR, "Lock all SMRAM regions before executing boot script\n")); + + for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) { + Status = SmmAccess->Lock ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index); + } + } + + if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { + // + // Need reconstruct page table here, since we do not trust ACPINvs. + // + RestoreS3PageTables ((UINTN)AcpiS3Context->S3NvsPageTableAddress); + AsmWriteCr3 ((UINTN)AcpiS3Context->S3NvsPageTableAddress); + } + + if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) { + // + // On some platform, such as ECP, a dispatch node in boot script table may execute a 32-bit PEIM which may need PeiServices + // pointer. So PeiServices need preserve in (IDTBase- sizeof (UINTN)). + // + IdtDescriptor = (IA32_DESCRIPTOR *) (UINTN) (AcpiS3Context->IdtrProfile); + // + // Make sure the newly allcated IDT align with 16-bytes + // + IdtBuffer = AllocatePages (EFI_SIZE_TO_PAGES((IdtDescriptor->Limit + 1) + 16)); + ASSERT (IdtBuffer != NULL); + CopyMem ((VOID*)((UINT8*)IdtBuffer + 16),(VOID*)(IdtDescriptor->Base), (IdtDescriptor->Limit + 1)); + IdtDescriptor->Base = (UINTN)((UINT8*)IdtBuffer + 16); + *(UINTN*)(IdtDescriptor->Base - sizeof(UINTN)) = (UINTN)GetPeiServicesTablePointer (); + } + + // + // Need to make sure the GDT is loaded with values that support long mode and real mode. + // + AsmWriteGdtr (&mGdt); + + // + // Prepare data for return back + // + PeiS3ResumeState = AllocatePool (sizeof(*PeiS3ResumeState)); + ASSERT (PeiS3ResumeState != NULL); + DEBUG (( EFI_D_ERROR, "PeiS3ResumeState - %x\r\n", PeiS3ResumeState)); + PeiS3ResumeState->ReturnCs = 0x10; + PeiS3ResumeState->ReturnEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)S3ResumeBootOs; + PeiS3ResumeState->ReturnStackPointer = (EFI_PHYSICAL_ADDRESS)(UINTN)&Status; + // + // Save IDT + // + AsmReadIdtr (&PeiS3ResumeState->Idtr); + + if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { + // + // X64 S3 Resume + // + DEBUG (( EFI_D_ERROR, "Enable X64 and transfer control to Standalone Boot Script Executor\r\n")); + + // + // Switch to long mode to complete resume. + // + AsmEnablePaging64 ( + 0x38, + EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint, + (UINT64)(UINTN)AcpiS3Context, + (UINT64)(UINTN)PeiS3ResumeState, + (UINT64)(UINTN)(AcpiS3Context->BootScriptStackBase + AcpiS3Context->BootScriptStackSize) + ); + } else { + // + // IA32 S3 Resume + // + DEBUG (( EFI_D_ERROR, "transfer control to Standalone Boot Script Executor\r\n")); + SwitchStack ( + (SWITCH_STACK_ENTRY_POINT) (UINTN) EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint, + (VOID *)AcpiS3Context, + (VOID *)PeiS3ResumeState, + (VOID *)(UINTN)(AcpiS3Context->BootScriptStackBase + AcpiS3Context->BootScriptStackSize) + ); + } + + // + // Never run to here + // + CpuDeadLoop(); +} +/** + Restores the platform to its preboot configuration for an S3 resume and + jumps to the OS waking vector. + + This function will restore the platform to its pre-boot configuration that was + pre-stored in the boot script table and transfer control to OS waking vector. + Upon invocation, this function is responsible for locating the following + information before jumping to OS waking vector: + - ACPI tables + - boot script table + - any other information that it needs + + The S3RestoreConfig() function then executes the pre-stored boot script table + and transitions the platform to the pre-boot state. The boot script is recorded + during regular boot using the EFI_S3_SAVE_STATE_PROTOCOL.Write() and + EFI_S3_SMM_SAVE_STATE_PROTOCOL.Write() functions. Finally, this function + transfers control to the OS waking vector. If the OS supports only a real-mode + waking vector, this function will switch from flat mode to real mode before + jumping to the waking vector. If all platform pre-boot configurations are + successfully restored and all other necessary information is ready, this + function will never return and instead will directly jump to the OS waking + vector. If this function returns, it indicates that the attempt to resume + from the ACPI S3 sleep state failed. + + @param[in] This Pointer to this instance of the PEI_S3_RESUME_PPI + + @retval EFI_ABORTED Execution of the S3 resume boot script table failed. + @retval EFI_NOT_FOUND Some necessary information that is used for the S3 + resume boot path could not be located. + +**/ +EFI_STATUS +EFIAPI +S3RestoreConfig2 ( + IN EFI_PEI_S3_RESUME2_PPI *This + ) +{ + EFI_STATUS Status; + PEI_SMM_ACCESS_PPI *SmmAccess; + UINTN Index; + ACPI_S3_CONTEXT *AcpiS3Context; + EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariableServices; + EFI_PHYSICAL_ADDRESS TempEfiBootScriptExecutorVariable; + EFI_PHYSICAL_ADDRESS TempAcpiS3Context; + BOOT_SCRIPT_EXECUTOR_VARIABLE *EfiBootScriptExecutorVariable; + UINTN VarSize; + EFI_SMRAM_DESCRIPTOR *SmramDescriptor; + SMM_S3_RESUME_STATE *SmmS3ResumeState; + VOID *GuidHob; + + DEBUG ((EFI_D_ERROR, "Enter S3 PEIM\r\n")); + + Status = PeiServicesLocatePpi ( + &gPeiSmmAccessPpiGuid, + 0, + NULL, + (VOID **) &SmmAccess + ); + for (Index = 0; !EFI_ERROR (Status); Index++) { + Status = SmmAccess->Open ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index); + } + + Status = PeiServicesLocatePpi ( + &gEfiPeiReadOnlyVariable2PpiGuid, + 0, + NULL, + (VOID **) &VariableServices + ); + if (EFI_ERROR (Status)) { + return Status; + } + + VarSize = sizeof (EFI_PHYSICAL_ADDRESS); + Status = RestoreLockBox ( + &gEfiAcpiVariableGuid, + &TempAcpiS3Context, + &VarSize + ); + ASSERT_EFI_ERROR (Status); + + AcpiS3Context = (ACPI_S3_CONTEXT *)(UINTN)TempAcpiS3Context; + ASSERT (AcpiS3Context != NULL); + + Status = RestoreLockBox ( + &gEfiAcpiS3ContextGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + VarSize = sizeof (TempEfiBootScriptExecutorVariable); + Status = RestoreLockBox ( + &gEfiBootScriptExecutorVariableGuid, + &TempEfiBootScriptExecutorVariable, + &VarSize + ); + ASSERT_EFI_ERROR (Status); + + Status = RestoreLockBox ( + &gEfiBootScriptExecutorContextGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + EfiBootScriptExecutorVariable = (BOOT_SCRIPT_EXECUTOR_VARIABLE *) (UINTN) TempEfiBootScriptExecutorVariable; + + DEBUG (( EFI_D_ERROR, "AcpiS3Context = %x\n", AcpiS3Context)); + DEBUG (( EFI_D_ERROR, "Waking Vector = %x\n", ((EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable)))->FirmwareWakingVector)); + DEBUG (( EFI_D_ERROR, "AcpiS3Context->AcpiFacsTable = %x\n", AcpiS3Context->AcpiFacsTable)); + DEBUG (( EFI_D_ERROR, "AcpiS3Context->S3NvsPageTableAddress = %x\n", AcpiS3Context->S3NvsPageTableAddress)); + DEBUG (( EFI_D_ERROR, "AcpiS3Context->S3DebugBufferAddress = %x\n", AcpiS3Context->S3DebugBufferAddress)); + DEBUG (( EFI_D_ERROR, "EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint = %x\n", EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint)); + + // + // Additional step for BootScript integrity - we only handle BootScript and BootScriptExecutor. + // Script dispatch image and context (parameter) are handled by platform. + // We just use restore all lock box in place, no need restore one by one. + // + Status = RestoreAllLockBoxInPlace (); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + // Something wrong + CpuDeadLoop (); + } + + // + // Attempt to use content from SMRAM first + // + GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid); + if (GuidHob != NULL) { + SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob); + SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart; + + SmmS3ResumeState->ReturnCs = AsmReadCs (); + SmmS3ResumeState->ReturnEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)S3ResumeExecuteBootScript; + SmmS3ResumeState->ReturnContext1 = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context; + SmmS3ResumeState->ReturnContext2 = (EFI_PHYSICAL_ADDRESS)(UINTN)EfiBootScriptExecutorVariable; + SmmS3ResumeState->ReturnStackPointer = (EFI_PHYSICAL_ADDRESS)(UINTN)&Status; + + DEBUG (( EFI_D_ERROR, "SMM S3 Signature = %x\n", SmmS3ResumeState->Signature)); + DEBUG (( EFI_D_ERROR, "SMM S3 Stack Base = %x\n", SmmS3ResumeState->SmmS3StackBase)); + DEBUG (( EFI_D_ERROR, "SMM S3 Stack Size = %x\n", SmmS3ResumeState->SmmS3StackSize)); + DEBUG (( EFI_D_ERROR, "SMM S3 Resume Entry Point = %x\n", SmmS3ResumeState->SmmS3ResumeEntryPoint)); + DEBUG (( EFI_D_ERROR, "SMM S3 CR0 = %x\n", SmmS3ResumeState->SmmS3Cr0)); + DEBUG (( EFI_D_ERROR, "SMM S3 CR3 = %x\n", SmmS3ResumeState->SmmS3Cr3)); + DEBUG (( EFI_D_ERROR, "SMM S3 CR4 = %x\n", SmmS3ResumeState->SmmS3Cr4)); + DEBUG (( EFI_D_ERROR, "SMM S3 Return CS = %x\n", SmmS3ResumeState->ReturnCs)); + DEBUG (( EFI_D_ERROR, "SMM S3 Return Entry Point = %x\n", SmmS3ResumeState->ReturnEntryPoint)); + DEBUG (( EFI_D_ERROR, "SMM S3 Return Context1 = %x\n", SmmS3ResumeState->ReturnContext1)); + DEBUG (( EFI_D_ERROR, "SMM S3 Return Context2 = %x\n", SmmS3ResumeState->ReturnContext2)); + DEBUG (( EFI_D_ERROR, "SMM S3 Return Stack Pointer = %x\n", SmmS3ResumeState->ReturnStackPointer)); + DEBUG (( EFI_D_ERROR, "SMM S3 Smst = %x\n", SmmS3ResumeState->Smst)); + + // + // Disable interrupt of Debug timer. + // + SaveAndSetDebugTimerInterrupt (FALSE); + + if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_32) { + SwitchStack ( + (SWITCH_STACK_ENTRY_POINT)(UINTN)SmmS3ResumeState->SmmS3ResumeEntryPoint, + (VOID *)AcpiS3Context, + 0, + (VOID *)(UINTN)(SmmS3ResumeState->SmmS3StackBase + SmmS3ResumeState->SmmS3StackSize) + ); + } + if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) { + // + // Switch to long mode to complete resume. + // + + // + // Need to make sure the GDT is loaded with values that support long mode and real mode. + // + AsmWriteGdtr (&mGdt); + AsmWriteCr3 ((UINTN)SmmS3ResumeState->SmmS3Cr3); + AsmEnablePaging64 ( + 0x38, + SmmS3ResumeState->SmmS3ResumeEntryPoint, + (UINT64)(UINTN)AcpiS3Context, + 0, + SmmS3ResumeState->SmmS3StackBase + SmmS3ResumeState->SmmS3StackSize + ); + } + + } + + S3ResumeExecuteBootScript (AcpiS3Context, EfiBootScriptExecutorVariable ); + return EFI_SUCCESS; +} +/** + Main entry for S3 Resume PEIM. + + This routine is to install EFI_PEI_S3_RESUME2_PPI. + + @param FileHandle Handle of the file being invoked. + @param PeiServices Pointer to PEI Services table. + + @retval EFI_SUCCESS S3Resume Ppi is installed successfully. + +**/ +EFI_STATUS +EFIAPI +PeimS3ResumeEntryPoint ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + + // + // Install S3 Resume Ppi + // + Status = (**PeiServices).InstallPpi (PeiServices, &mPpiList); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + diff --git a/CloverEFI/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf b/CloverEFI/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf new file mode 100755 index 0000000000..1a38f518ad --- /dev/null +++ b/CloverEFI/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf @@ -0,0 +1,79 @@ +## @file +# S3 Resume Module: +# This module works with StandAloneBootScriptExecutor to S3 resume to OS. +# This module will excute the boot script saved during last boot and after that, +# control is passed to OS waking up handler. +# +# Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials are +# licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = S3Resume2Pei + FILE_GUID = 89E549B0-7CFE-449d-9BA3-10D8B2312D71 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = PeimS3ResumeEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + S3Resume.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + CloverEFI/UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + PeiServicesTablePointerLib + PerformanceLib + HobLib + PeiServicesLib + PeimEntryPoint + TimerLib + BaseLib + DebugLib + PcdLib + IoLib + BaseMemoryLib + MemoryAllocationLib + DebugAgentLib + LocalApicLib + ReportStatusCodeLib + LockBoxLib + PrintLib + +[Guids] + gEfiBootScriptExecutorVariableGuid # SOMETIMES_CONSUMED + gEfiBootScriptExecutorContextGuid # SOMETIMES_CONSUMED + gPerformanceProtocolGuid # ALWAYS_CONSUMED L"PerfDataMemAddr" + gEfiAcpiVariableGuid # ALWAYS_CONSUMED Hob: GUID_EXTENSION + gEfiAcpiS3ContextGuid # ALWAYS_CONSUMED + +[Ppis] + gEfiPeiReadOnlyVariable2PpiGuid # PPI ALWAYS_CONSUMED + gEfiPeiS3Resume2PpiGuid # PPI ALWAYS_PRODUCED + gPeiSmmAccessPpiGuid # PPI ALWAYS_CONSUMED + gPeiPostScriptTablePpiGuid # PPI ALWAYS_PRODUCED + gEfiEndOfPeiSignalPpiGuid # PPI ALWAYS_PRODUCED + +[FeaturePcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode + gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport + +[Depex] + gEfiPeiReadOnlyVariable2PpiGuid diff --git a/CloverEFI/UefiCpuPkg/build.sh b/CloverEFI/UefiCpuPkg/build.sh new file mode 100755 index 0000000000..0d479420e6 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/build.sh @@ -0,0 +1,73 @@ +#!/bin/bash +# +# Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+# Copyright (c) 2010, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# + +set -e +shopt -s nocasematch + + +# +# Setup workspace if it is not set +# +if [ -z "$WORKSPACE" ] +then + echo Initializing workspace + if [ ! -e `pwd`/edksetup.sh ] + then + cd .. + fi +# This version is for the tools in the BaseTools project. +# this assumes svn pulls have the same root dir +# export EDK_TOOLS_PATH=`pwd`/../BaseTools +# This version is for the tools source in edk2 + export EDK_TOOLS_PATH=`pwd`/BaseTools + echo $EDK_TOOLS_PATH + source edksetup.sh BaseTools +else + echo Building from: $WORKSPACE +fi + +# +# Pick a default tool type for a given OS +# +TARGET_TOOLS=MYTOOLS +NETWORK_SUPPORT= +case `uname` in + CYGWIN*) echo Cygwin not fully supported yet. ;; + Darwin*) + Major=$(uname -r | cut -f 1 -d '.') + if [[ $Major == 9 ]] + then + echo UnixPkg requires Snow Leopard or later OS + exit 1 + else + TARGET_TOOLS=XCODE32 + fi +# NETWORK_SUPPORT="-D NETWORK_SUPPORT" + ;; + Linux*) TARGET_TOOLS=ELFGCC ;; + +esac + +BUILD_ROOT_ARCH=$WORKSPACE/Build/Shell/DEBUG_"$TARGET_TOOLS"/IA32 + + +# +# Build the edk2 UnixPkg +# +echo $PATH +echo `which build` +#build -p $WORKSPACE/UnixPkg/UnixPkg.dsc -a IA32 -t $TARGET_TOOLS $NETWORK_SUPPORT -n 3 $1 $2 $3 $4 $5 $6 $7 $8 +build -p $WORKSPACE/CloverEFI/UefiCpuPkg/UefiCpuPkg.dsc -a IA32 -t $TARGET_TOOLS -n 3 $* +exit $? + diff --git a/CloverEFI/UefiCpuPkg/edk2.patch-idtgdt b/CloverEFI/UefiCpuPkg/edk2.patch-idtgdt new file mode 100755 index 0000000000..34230487f6 --- /dev/null +++ b/CloverEFI/UefiCpuPkg/edk2.patch-idtgdt @@ -0,0 +1,283 @@ +Index: UefiCpuPkg/CpuDxe/CpuDxe.inf +=================================================================== +--- UefiCpuPkg/CpuDxe/CpuDxe.inf (revision 9332) ++++ UefiCpuPkg/CpuDxe/CpuDxe.inf (working copy) +@@ -62,6 +62,9 @@ + [Protocols] + gEfiCpuArchProtocolGuid + ++[Guids] ++ gEfiEventVirtualAddressChangeGuid # ALWAYS_CONSUMED Create Event: EVENT_GROUP_GUID ++ + [Depex] + TRUE + +Index: UefiCpuPkg/CpuDxe/CpuGdt.c +=================================================================== +--- UefiCpuPkg/CpuDxe/CpuGdt.c (revision 9332) ++++ UefiCpuPkg/CpuDxe/CpuGdt.c (working copy) +@@ -67,6 +67,9 @@ + #error CPU type not supported for CPU GDT initialization! + #endif + ++VOID * Gdt; ++UINT32 GdtSize; ++ + // + // Global descriptor table (GDT) Template + // +@@ -161,6 +164,20 @@ + }, + }; + ++VOID EFIAPI ++LoadGdt(VOID* Gdt, UINT32 GdtSize) ++{ ++ IA32_DESCRIPTOR gdtPtr; ++ ++ // ++ // Write GDT register ++ // ++ gdtPtr.Base = (UINT32)(UINTN)Gdt; ++ gdtPtr.Limit = GdtSize - 1; ++ ++ AsmWriteGdtr (&gdtPtr); ++} ++ + /** + Initialize Global Descriptor Table + +@@ -169,27 +186,27 @@ + InitGlobalDescriptorTable ( + ) + { +- GDT_ENTRIES *gdt; +- IA32_DESCRIPTOR gdtPtr; +- + // + // Allocate Runtime Data for the GDT + // +- gdt = AllocateRuntimePool (sizeof (GdtTemplate) + 8); +- ASSERT (gdt != NULL); +- gdt = ALIGN_POINTER (gdt, 8); ++ GdtSize = sizeof (GdtTemplate); ++#if 0 ++ Gdt = AllocateRuntimePool (GdtSize + 8); ++ ASSERT (Gdt != NULL); ++ Gdt = ALIGN_POINTER (Gdt, 8); ++#else ++ Gdt = (VOID*)(UINTN)HandyCpuPage; ++#endif + + // + // Initialize all GDT entries + // +- CopyMem (gdt, &GdtTemplate, sizeof (GdtTemplate)); ++ CopyMem (Gdt, &GdtTemplate, GdtSize); + + // + // Write GDT register + // +- gdtPtr.Base = (UINT32)(UINTN)(VOID*) gdt; +- gdtPtr.Limit = sizeof (GdtTemplate) - 1; +- AsmWriteGdtr (&gdtPtr); ++ LoadGdt(Gdt, GdtSize); + + // + // Update selector (segment) registers base on new GDT +@@ -197,4 +214,3 @@ + SetCodeSelector ((UINT16)CPU_CODE_SEL); + SetDataSelectors ((UINT16)CPU_DATA_SEL); + } +- +Index: UefiCpuPkg/CpuDxe/CpuDxe.c +=================================================================== +--- UefiCpuPkg/CpuDxe/CpuDxe.c (revision 9332) ++++ UefiCpuPkg/CpuDxe/CpuDxe.c (working copy) +@@ -14,11 +14,14 @@ + + #include "CpuDxe.h" + ++EFI_EVENT mEfiVirtualNotifyEvent; ++EFI_PHYSICAL_ADDRESS HandyCpuPage; ++IA32_IDT_GATE_DESCRIPTOR* Idt; ++UINT32 IdtSize; ++ + // + // Global Variables + // +-IA32_IDT_GATE_DESCRIPTOR gIdtTable[INTERRUPT_VECTOR_NUMBER] = { 0 }; +- + EFI_CPU_INTERRUPT_HANDLER ExternalVectorTable[0x100]; + BOOLEAN InterruptState = FALSE; + EFI_HANDLE mCpuHandle = NULL; +@@ -1004,8 +1007,6 @@ + ) + { + EFI_STATUS Status; +- VOID *IdtPtrAlignmentBuffer; +- IA32_DESCRIPTOR *IdtPtr; + UINTN Index; + UINTN CurrentHandler; + +@@ -1015,27 +1016,33 @@ + // Initialize IDT + // + CurrentHandler = (UINTN)AsmIdtVector00; ++ ++ // ++ // Allocate Runtime Data for the IDT ++ // ++ IdtSize = INTERRUPT_VECTOR_NUMBER*sizeof(IA32_IDT_GATE_DESCRIPTOR); ++#if 0 ++ Idt = AllocateRuntimePool (IdtSize + 16); ++ ASSERT (Idt != NULL); ++ Idt = ALIGN_POINTER (Idt, 16); ++#else ++ Idt = (VOID*)(UINTN)HandyCpuPage + 0x500; ++#endif ++ + for (Index = 0; Index < INTERRUPT_VECTOR_NUMBER; Index ++, CurrentHandler += 0x08) { +- gIdtTable[Index].Bits.OffsetLow = (UINT16)CurrentHandler; +- gIdtTable[Index].Bits.Selector = AsmReadCs(); +- gIdtTable[Index].Bits.Reserved_0 = 0; +- gIdtTable[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; +- gIdtTable[Index].Bits.OffsetHigh = (UINT16)(CurrentHandler >> 16); ++ Idt[Index].Bits.OffsetLow = (UINT16)CurrentHandler; ++ Idt[Index].Bits.Selector = AsmReadCs(); ++ Idt[Index].Bits.Reserved_0 = 0; ++ Idt[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; ++ Idt[Index].Bits.OffsetHigh = (UINT16)(CurrentHandler >> 16); + #if defined (MDE_CPU_X64) +- gIdtTable[Index].Bits.OffsetUpper = (UINT32)(CurrentHandler >> 32); +- gIdtTable[Index].Bits.Reserved_1 = 0; ++ Idt[Index].Bits.OffsetUpper = (UINT32)(CurrentHandler >> 32); ++ Idt[Index].Bits.Reserved_1 = 0; + #endif + } + +- // +- // Load IDT Pointer +- // +- IdtPtrAlignmentBuffer = AllocatePool (sizeof (*IdtPtr) + 16); +- IdtPtr = ALIGN_POINTER (IdtPtrAlignmentBuffer, 16); +- IdtPtr->Base = (UINT32)(((UINTN)(VOID*) gIdtTable) & (BASE_4GB-1)); +- IdtPtr->Limit = sizeof (gIdtTable) - 1; +- AsmWriteIdtr (IdtPtr); +- FreePool (IdtPtrAlignmentBuffer); ++ // Load IDT ++ LoadIdt(Idt, IdtSize); + + // + // Initialize Exception Handlers +@@ -1052,7 +1059,50 @@ + + } + ++VOID EFIAPI ++LoadIdt(VOID* Idt, UINT32 IdtSize) ++{ ++ IA32_DESCRIPTOR IdtPtr; + ++ IdtPtr.Base = (UINT32)(((UINTN) Idt) & (BASE_4GB-1)); ++ IdtPtr.Limit = IdtSize - 1; ++ AsmWriteIdtr (&IdtPtr); ++} ++ ++UINT32 ++EFIAPI ++IoWrite32 ( ++ IN UINTN Port, ++ IN UINT32 Value ++ ) ++{ ++ __asm__ __volatile__ ("outl %0,%w1" : : "a" (Value), "d" ((UINT16)Port)); ++ return Value; ++} ++ ++VOID ++EFIAPI ++CpuLibVirtualNotifyEvent ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ EFI_RUNTIME_SERVICES * rs = (EFI_RUNTIME_SERVICES *)Context; ++ ++ rs->ConvertPointer (0, (VOID **) &Gdt); ++ rs->ConvertPointer (0, (VOID **) &Idt); ++ ++ DisableInterrupts(); ++ ++ LoadIdt(Idt, IdtSize); ++ LoadGdt(Gdt, GdtSize); ++ ++ //IoWrite32(0xef11, 1); ++} ++ ++extern EFI_GUID gEfiEventVirtualAddressChangeGuid; ++ ++ + /** + Initialize the state information for the CPU Architectural Protocol. + +@@ -1073,6 +1123,17 @@ + { + EFI_STATUS Status; + ++ ++ // Allocate handy page ++ HandyCpuPage = 0xffffffff; ++ Status = gBS->AllocatePages ( ++ AllocateMaxAddress, ++ EfiReservedMemoryType, ++ 1, ++ &HandyCpuPage ); ++ ASSERT_EFI_ERROR (Status); ++ ASSERT (HandyCpuPage != 0xffffffff); ++ + // + // Make sure interrupts are disabled + // +@@ -1103,6 +1164,18 @@ + // + RefreshGcdMemoryAttributes (); + ++ ++ // Register virtual address change notifier ++#if 0 ++ gBS->CreateEventEx ( ++ EVT_NOTIFY_SIGNAL, ++ TPL_NOTIFY, ++ CpuLibVirtualNotifyEvent, ++ SystemTable->RuntimeServices, ++ &gEfiEventVirtualAddressChangeGuid, ++ &mEfiVirtualNotifyEvent ++ ); ++#endif ++ + return Status; + } +- +Index: UefiCpuPkg/CpuDxe/CpuDxe.h +=================================================================== +--- UefiCpuPkg/CpuDxe/CpuDxe.h (revision 9332) ++++ UefiCpuPkg/CpuDxe/CpuDxe.h (working copy) +@@ -136,5 +136,17 @@ + ); + + ++VOID EFIAPI ++LoadGdt(VOID* Gdt, UINT32 GdtSize); ++ ++VOID EFIAPI ++LoadIdt(VOID* Idt, UINT32 IdtSize); ++ ++extern EFI_PHYSICAL_ADDRESS HandyCpuPage; ++extern VOID* Gdt; ++extern UINT32 GdtSize; ++extern IA32_IDT_GATE_DESCRIPTOR* Idt; ++extern UINT32 IdtSize; ++ + #endif + diff --git a/Protocols/DataHubDxe/DataHub.c b/Protocols/DataHubDxe/DataHub.c old mode 100644 new mode 100755 index 1a97f4fa7d..9a193d5ff0 --- a/Protocols/DataHubDxe/DataHub.c +++ b/Protocols/DataHubDxe/DataHub.c @@ -14,596 +14,574 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #include "DataHub.h" -#include -// now using OpenCore library to avoid multiple definition of functions +// +// Since this driver will only ever produce one instance of the Logging Hub +// protocol you are not required to dynamically allocate the PrivateData. +// +DATA_HUB_INSTANCE mPrivateData; +/** + Log data record into the data logging hub + @param This Protocol instance structure + @param DataRecordGuid GUID that defines record contents + @param ProducerName GUID that defines the name of the producer of the data + @param DataRecordClass Class that defines generic record type + @param RawData Data Log record as defined by DataRecordGuid + @param RawDataSize Size of Data Log data in bytes -// -//// -//// Since this driver will only ever produce one instance of the Logging Hub -//// protocol you are not required to dynamically allocate the PrivateData. -//// -//DATA_HUB_INSTANCE mPrivateData; -// -///** -// Log data record into the data logging hub -// -// @param This Protocol instance structure -// @param DataRecordGuid GUID that defines record contents -// @param ProducerName GUID that defines the name of the producer of the data -// @param DataRecordClass Class that defines generic record type -// @param RawData Data Log record as defined by DataRecordGuid -// @param RawDataSize Size of Data Log data in bytes -// -// @retval EFI_SUCCESS If data was logged -// @retval EFI_OUT_OF_RESOURCES If data was not logged due to lack of system -// resources. -//**/ -//EFI_STATUS -//EFIAPI -//DataHubLogData ( -// IN EFI_DATA_HUB_PROTOCOL *This, -// IN EFI_GUID *DataRecordGuid, -// IN EFI_GUID *ProducerName, -// IN UINT64 DataRecordClass, -// IN VOID *RawData, -// IN UINT32 RawDataSize -// ) -//{ -// EFI_STATUS Status; -// DATA_HUB_INSTANCE *Private; -// EFI_DATA_ENTRY *LogEntry; -// UINT32 TotalSize; -// UINT32 RecordSize; -// EFI_DATA_RECORD_HEADER *Record; -// VOID *Raw; -// DATA_HUB_FILTER_DRIVER *FilterEntry; -// LIST_ENTRY *Link; -// LIST_ENTRY *Head; -// EFI_TIME LogTime; -// -// Private = DATA_HUB_INSTANCE_FROM_THIS (This); -// -// // -// // Combine the storage for the internal structs and a copy of the log record. -// // Record follows PrivateLogEntry. The consumer will be returned a pointer -// // to Record so we don't what it to be the thing that was allocated from -// // pool, so the consumer can't free an data record by mistake. -// // -// RecordSize = sizeof (EFI_DATA_RECORD_HEADER) + RawDataSize; -// TotalSize = sizeof (EFI_DATA_ENTRY) + RecordSize; -// -// // -// // First try to get log time at TPL level <= TPL_CALLBACK. -// // -// ZeroMem (&LogTime, sizeof (LogTime)); -// if (EfiGetCurrentTpl() <= TPL_CALLBACK) { -// gRT->GetTime (&LogTime, NULL); -// } -// -// // -// // The Logging action is the critical section, so it is locked. -// // The MTC asignment & update and logging must be an -// // atomic operation, so use the lock. -// // -// Status = EfiAcquireLockOrFail (&Private->DataLock); -// if (EFI_ERROR(Status)) { -// // -// // Reentrancy detected so exit! -// // -// return Status; -// } -// -// LogEntry = AllocatePool (TotalSize); -// -// if (LogEntry == NULL) { -// EfiReleaseLock (&Private->DataLock); -// return EFI_OUT_OF_RESOURCES; -// } -// -// ZeroMem (LogEntry, TotalSize); -// -// Record = (EFI_DATA_RECORD_HEADER *) (LogEntry + 1); -// Raw = (VOID *) (Record + 1); -// -// // -// // Build Standard Log Header -// // -// Record->Version = EFI_DATA_RECORD_HEADER_VERSION; -// Record->HeaderSize = (UINT16) sizeof (EFI_DATA_RECORD_HEADER); -// Record->RecordSize = RecordSize; -// CopyMem(&Record->DataRecordGuid, DataRecordGuid, sizeof (EFI_GUID)); -// CopyMem(&Record->ProducerName, ProducerName, sizeof (EFI_GUID)); -// Record->DataRecordClass = DataRecordClass; -// -// // -// // Ensure LogMonotonicCount is not zero -// // -// Record->LogMonotonicCount = ++Private->GlobalMonotonicCount; -// -// CopyMem(&Record->LogTime, &LogTime, sizeof (LogTime)); -// -// // -// // Insert log into the internal linked list. -// // -// LogEntry->Signature = EFI_DATA_ENTRY_SIGNATURE; -// LogEntry->Record = Record; -// LogEntry->RecordSize = sizeof (EFI_DATA_ENTRY) + RawDataSize; -// InsertTailList (&Private->DataListHead, &LogEntry->Link); -// -// CopyMem(Raw, RawData, RawDataSize); -// -// EfiReleaseLock (&Private->DataLock); -// -// // -// // Send Signal to all the filter drivers which are interested -// // in the record's class and guid. -// // -// Head = &Private->FilterDriverListHead; -// for (Link = GetFirstNode(Head); Link != Head; Link = GetNextNode(Head, Link)) { -// FilterEntry = FILTER_ENTRY_FROM_LINK (Link); -// if (((FilterEntry->ClassFilter & DataRecordClass) != 0) && -// (IsZeroGuid (&FilterEntry->FilterDataRecordGuid) || -// CompareGuid (&FilterEntry->FilterDataRecordGuid, DataRecordGuid))) { -// gBS->SignalEvent (FilterEntry->Event); -// } -// } -// -// return EFI_SUCCESS; -//} -// -///** -// Search the Head doubly linked list for the passed in MTC. Return the -// matching element in Head and the MTC on the next entry. -// -// @param Head Head of Data Log linked list. -// @param ClassFilter Only match the MTC if it is in the same Class as the -// ClassFilter. -// @param PtrCurrentMTC On IN contians MTC to search for. On OUT contians next -// MTC in the data log list or zero if at end of the list. -// -// @retval EFI_DATA_LOG_ENTRY Return pointer to data log data from Head list. -// @retval NULL If no data record exists. -// -//**/ -//EFI_DATA_RECORD_HEADER * -//GetNextDataRecord ( -// IN LIST_ENTRY *Head, -// IN UINT64 ClassFilter, -// IN OUT UINT64 *PtrCurrentMTC -// ) -// -//{ -// EFI_DATA_ENTRY *LogEntry; -// LIST_ENTRY *Link; -// BOOLEAN ReturnFirstEntry; -// EFI_DATA_RECORD_HEADER *Record; -// EFI_DATA_ENTRY *NextLogEntry; -// -// // -// // If MonotonicCount == 0 just return the first one -// // -// ReturnFirstEntry = (BOOLEAN) (*PtrCurrentMTC == 0); -// -// Record = NULL; -// for (Link = GetFirstNode(Head); Link != Head; Link = GetNextNode(Head, Link)) { -// LogEntry = DATA_ENTRY_FROM_LINK (Link); -// if ((LogEntry->Record->DataRecordClass & ClassFilter) == 0) { -// // -// // Skip any entry that does not have the correct ClassFilter -// // -// continue; -// } -// -// if ((LogEntry->Record->LogMonotonicCount == *PtrCurrentMTC) || ReturnFirstEntry) { -// // -// // Return record to the user -// // -// Record = LogEntry->Record; -// -// // -// // Calculate the next MTC value. If there is no next entry set -// // MTC to zero. -// // -// *PtrCurrentMTC = 0; -// for (Link = GetNextNode(Head, Link); Link != Head; Link = GetNextNode(Head, Link)) { -// NextLogEntry = DATA_ENTRY_FROM_LINK (Link); -// if ((NextLogEntry->Record->DataRecordClass & ClassFilter) != 0) { -// // -// // Return the MTC of the next thing to search for if found -// // -// *PtrCurrentMTC = NextLogEntry->Record->LogMonotonicCount; -// break; -// } -// } -// // -// // Record found exit loop and return -// // -// break; -// } -// } -// -// return Record; -//} -// -///** -// Search the Head list for a EFI_DATA_HUB_FILTER_DRIVER member that -// represents Event and return it. -// -// @param Head Pointer to head of dual linked list of EFI_DATA_HUB_FILTER_DRIVER structures. -// @param Event Event to be search for in the Head list. -// -// @retval EFI_DATA_HUB_FILTER_DRIVER Returned if Event stored in the Head doubly linked list. -// @retval NULL If Event is not in the list -// -//**/ -//DATA_HUB_FILTER_DRIVER * -//FindFilterDriverByEvent ( -// IN LIST_ENTRY *Head, -// IN EFI_EVENT Event -// ) -//{ -// DATA_HUB_FILTER_DRIVER *FilterEntry; -// LIST_ENTRY *Link; -// -// for (Link = GetFirstNode(Head); Link != Head; Link = GetNextNode(Head, Link)) { -// FilterEntry = FILTER_ENTRY_FROM_LINK (Link); -// if (FilterEntry->Event == Event) { -// return FilterEntry; -// } -// } -// -// return NULL; -//} -// -///** -// -// Get a previously logged data record and the MonotonicCount for the next -// available Record. This allows all records or all records later -// than a give MonotonicCount to be returned. If an optional FilterDriverEvent -// is passed in with a MonotonicCout of zero return the first record -// not yet read by the filter driver. If FilterDriverEvent is NULL and -// MonotonicCount is zero return the first data record. -// -// @param This Pointer to the EFI_DATA_HUB_PROTOCOL instance. -// @param MonotonicCount Specifies the Record to return. On input, zero means -// return the first record. On output, contains the next -// record to available. Zero indicates no more records. -// @param FilterDriverEvent If FilterDriverEvent is not passed in a MonotonicCount -// of zero, it means to return the first data record. -// If FilterDriverEvent is passed in, then a MonotonicCount -// of zero means to return the first data not yet read by -// FilterDriverEvent. -// @param Record Returns a dynamically allocated memory buffer with a data -// record that matches MonotonicCount. -// -// @retval EFI_SUCCESS Data was returned in Record. -// @retval EFI_INVALID_PARAMETER FilterDriverEvent was passed in but does not exist. -// @retval EFI_NOT_FOUND MonotonicCount does not match any data record in the -// system. If a MonotonicCount of zero was passed in, then -// no data records exist in the system. -// @retval EFI_OUT_OF_RESOURCES Record was not returned due to lack of system resources. -// -//**/ -//EFI_STATUS -//EFIAPI -//DataHubGetNextRecord ( -// IN EFI_DATA_HUB_PROTOCOL *This, -// IN OUT UINT64 *MonotonicCount, -// IN EFI_EVENT *FilterDriverEvent, OPTIONAL -// OUT EFI_DATA_RECORD_HEADER **Record -// ) -//{ -// DATA_HUB_INSTANCE *Private; -// DATA_HUB_FILTER_DRIVER *FilterDriver; -// UINT64 ClassFilter; -// -// Private = DATA_HUB_INSTANCE_FROM_THIS (This); -// -// FilterDriver = NULL; -// ClassFilter = EFI_DATA_RECORD_CLASS_DEBUG | -// EFI_DATA_RECORD_CLASS_ERROR | -// EFI_DATA_RECORD_CLASS_DATA | -// EFI_DATA_RECORD_CLASS_PROGRESS_CODE; -// -// // -// // If FilterDriverEvent is NULL, then return the next record -// // -// if (FilterDriverEvent == NULL) { -// *Record = GetNextDataRecord (&Private->DataListHead, ClassFilter, MonotonicCount); -// if (*Record == NULL) { -// return EFI_NOT_FOUND; -// } -// return EFI_SUCCESS; -// } -// -// // -// // For events the beginning is the last unread record. This info is -// // stored in the instance structure, so we must look up the event -// // to get the data. -// // -// FilterDriver = FindFilterDriverByEvent ( -// &Private->FilterDriverListHead, -// *FilterDriverEvent -// ); -// if (FilterDriver == NULL) { -// return EFI_INVALID_PARAMETER; -// } -// // -// // Use the Class filter the event was created with. -// // -// ClassFilter = FilterDriver->ClassFilter; -// -// // -// // Retrieve the next record or the first record. -// // -// if (*MonotonicCount != 0 || FilterDriver->GetNextMonotonicCount == 0) { -// *Record = GetNextDataRecord (&Private->DataListHead, ClassFilter, MonotonicCount); -// if (*Record == NULL) { -// return EFI_NOT_FOUND; -// } -// -// if (*MonotonicCount != 0) { -// // -// // If this was not the last record then update the count associated with the filter -// // -// FilterDriver->GetNextMonotonicCount = *MonotonicCount; -// } else { -// // -// // Save the MonotonicCount of the last record which has been read -// // -// FilterDriver->GetNextMonotonicCount = (*Record)->LogMonotonicCount; -// } -// return EFI_SUCCESS; -// } -// -// // -// // This is a request to read the first record that has not been read yet. -// // Set MonotoicCount to the last record successfuly read -// // -// *MonotonicCount = FilterDriver->GetNextMonotonicCount; -// -// // -// // Retrieve the last record successfuly read again, but do not return it since -// // it has already been returned before. -// // -// *Record = GetNextDataRecord (&Private->DataListHead, ClassFilter, MonotonicCount); -// if (*Record == NULL) { -// return EFI_NOT_FOUND; -// } -// -// if (*MonotonicCount != 0) { -// // -// // Update the count associated with the filter -// // -// FilterDriver->GetNextMonotonicCount = *MonotonicCount; -// -// // -// // Retrieve the record after the last record successfuly read -// // -// *Record = GetNextDataRecord (&Private->DataListHead, ClassFilter, MonotonicCount); -// if (*Record == NULL) { -// return EFI_NOT_FOUND; -// } -// } -// -// return EFI_SUCCESS; -//} -// -///** -// This function registers the data hub filter driver that is represented -// by FilterEvent. Only one instance of each FilterEvent can be registered. -// After the FilterEvent is registered, it will be signaled so it can sync -// with data records that have been recorded prior to the FilterEvent being -// registered. -// -// @param This Pointer to The EFI_DATA_HUB_PROTOCOL instance. -// @param FilterEvent The EFI_EVENT to signal whenever data that matches -// FilterClass is logged in the system. -// @param FilterTpl The maximum EFI_TPL at which FilterEvent can be -// signaled. It is strongly recommended that you use the -// lowest EFI_TPL possible. -// @param FilterClass FilterEvent will be signaled whenever a bit in -// EFI_DATA_RECORD_HEADER.DataRecordClass is also set in -// FilterClass. If FilterClass is zero, no class-based -// filtering will be performed. -// @param FilterDataRecordGuid FilterEvent will be signaled whenever FilterDataRecordGuid -// matches EFI_DATA_RECORD_HEADER.DataRecordGuid. If -// FilterDataRecordGuid is NULL, then no GUID-based filtering -// will be performed. -// -// @retval EFI_SUCCESS The filter driver event was registered. -// @retval EFI_ALREADY_STARTED FilterEvent was previously registered and cannot be -// registered again. -// @retval EFI_OUT_OF_RESOURCES The filter driver event was not registered due to lack of -// system resources. -// -//**/ -//EFI_STATUS -//EFIAPI -//DataHubRegisterFilterDriver ( -// IN EFI_DATA_HUB_PROTOCOL * This, -// IN EFI_EVENT FilterEvent, -// IN EFI_TPL FilterTpl, -// IN UINT64 FilterClass, -// IN EFI_GUID * FilterDataRecordGuid OPTIONAL -// ) -// -//{ -// DATA_HUB_INSTANCE *Private; -// DATA_HUB_FILTER_DRIVER *FilterDriver; -// -// Private = DATA_HUB_INSTANCE_FROM_THIS (This); -// -// FilterDriver = (DATA_HUB_FILTER_DRIVER *) AllocateZeroPool(sizeof (DATA_HUB_FILTER_DRIVER)); -// if (FilterDriver == NULL) { -// return EFI_OUT_OF_RESOURCES; -// } -// // -// // Initialize filter driver info -// // -// FilterDriver->Signature = EFI_DATA_HUB_FILTER_DRIVER_SIGNATURE; -// FilterDriver->Event = FilterEvent; -// FilterDriver->Tpl = FilterTpl; -// FilterDriver->GetNextMonotonicCount = 0; -// if (FilterClass == 0) { -// FilterDriver->ClassFilter = EFI_DATA_RECORD_CLASS_DEBUG | -// EFI_DATA_RECORD_CLASS_ERROR | -// EFI_DATA_RECORD_CLASS_DATA | -// EFI_DATA_RECORD_CLASS_PROGRESS_CODE; -// } else { -// FilterDriver->ClassFilter = FilterClass; -// } -// -// if (FilterDataRecordGuid != NULL) { -// CopyMem(&FilterDriver->FilterDataRecordGuid, FilterDataRecordGuid, sizeof (EFI_GUID)); -// } -// // -// // Search for duplicate entries -// // -// if (FindFilterDriverByEvent (&Private->FilterDriverListHead, FilterEvent) != NULL) { -// FreePool(FilterDriver); -// return EFI_ALREADY_STARTED; -// } -// // -// // Make insertion an atomic operation with the lock. -// // -// EfiAcquireLock (&Private->DataLock); -// InsertTailList (&Private->FilterDriverListHead, &FilterDriver->Link); -// EfiReleaseLock (&Private->DataLock); -// -// // -// // Signal the Filter driver we just loaded so they will recieve all the -// // previous history. If we did not signal here we would have to wait until -// // the next data was logged to get the history. In a case where no next -// // data was logged we would never get synced up. -// // -// gBS->SignalEvent (FilterEvent); -// -// return EFI_SUCCESS; -//} -// -///** -// Remove a Filter Driver, so it no longer gets called when data -// information is logged. -// -// @param This Protocol instance structure -// -// @param FilterEvent Event that represents a filter driver that is to be -// Unregistered. -// -// @retval EFI_SUCCESS If FilterEvent was unregistered -// @retval EFI_NOT_FOUND If FilterEvent does not exist -//**/ -//EFI_STATUS -//EFIAPI -//DataHubUnregisterFilterDriver ( -// IN EFI_DATA_HUB_PROTOCOL *This, -// IN EFI_EVENT FilterEvent -// ) -//{ -// DATA_HUB_INSTANCE *Private; -// DATA_HUB_FILTER_DRIVER *FilterDriver; -// -// Private = DATA_HUB_INSTANCE_FROM_THIS (This); -// -// // -// // Search for duplicate entries -// // -// FilterDriver = FindFilterDriverByEvent ( -// &Private->FilterDriverListHead, -// FilterEvent -// ); -// if (FilterDriver == NULL) { -// return EFI_NOT_FOUND; -// } -// // -// // Make removal an atomic operation with the lock -// // -// EfiAcquireLock (&Private->DataLock); -// RemoveEntryList (&FilterDriver->Link); -// EfiReleaseLock (&Private->DataLock); -// -// return EFI_SUCCESS; -//} -// -// -// -///** -// Driver's Entry point routine that install Driver to produce Data Hub protocol. -// -// @param ImageHandle Module's image handle -// @param SystemTable Pointer of EFI_SYSTEM_TABLE -// -// @retval EFI_SUCCESS Logging Hub protocol installed -// @retval Other No protocol installed, unload driver. -// -//**/ -//EFI_STATUS -//EFIAPI -//DataHubInstall ( -// IN EFI_HANDLE ImageHandle, -// IN EFI_SYSTEM_TABLE *SystemTable -// ) -//{ -// EFI_STATUS Status; -// UINT32 HighMontonicCount; -// -// mPrivateData.Signature = DATA_HUB_INSTANCE_SIGNATURE; -// mPrivateData.DataHub.LogData = DataHubLogData; -// mPrivateData.DataHub.GetNextRecord = DataHubGetNextRecord; -// mPrivateData.DataHub.RegisterFilterDriver = DataHubRegisterFilterDriver; -// mPrivateData.DataHub.UnregisterFilterDriver = DataHubUnregisterFilterDriver; -// -// // -// // Initialize Private Data in CORE_LOGGING_HUB_INSTANCE that is -// // required by this protocol -// // -// InitializeListHead (&mPrivateData.DataListHead); -// InitializeListHead (&mPrivateData.FilterDriverListHead); -// -// EfiInitializeLock (&mPrivateData.DataLock, TPL_NOTIFY); -// -// // -// // Make sure we get a bigger MTC number on every boot! -// // -// Status = gRT->GetNextHighMonotonicCount (&HighMontonicCount); -// if (EFI_ERROR(Status)) { -// // -// // if system service fails pick a sane value. -// // -// mPrivateData.GlobalMonotonicCount = 0; -// } else { -// mPrivateData.GlobalMonotonicCount = LShiftU64 ((UINT64) HighMontonicCount, 32); -// } -// // -// // Make a new handle and install the protocol -// // -// mPrivateData.Handle = NULL; -// Status = gBS->InstallProtocolInterface ( -// &mPrivateData.Handle, -// &gEfiDataHubProtocolGuid, -// EFI_NATIVE_INTERFACE, -// &mPrivateData.DataHub -// ); -// return Status; -//} - -EFI_DATA_HUB_PROTOCOL * -DataHubInstall ( - VOID - ); + @retval EFI_SUCCESS If data was logged + @retval EFI_OUT_OF_RESOURCES If data was not logged due to lack of system + resources. +**/ +EFI_STATUS +EFIAPI +DataHubLogData ( + IN EFI_DATA_HUB_PROTOCOL *This, + IN EFI_GUID *DataRecordGuid, + IN EFI_GUID *ProducerName, + IN UINT64 DataRecordClass, + IN VOID *RawData, + IN UINT32 RawDataSize + ) +{ + EFI_STATUS Status; + DATA_HUB_INSTANCE *Private; + EFI_DATA_ENTRY *LogEntry; + UINT32 TotalSize; + UINT32 RecordSize; + EFI_DATA_RECORD_HEADER *Record; + VOID *Raw; + DATA_HUB_FILTER_DRIVER *FilterEntry; + LIST_ENTRY *Link; + LIST_ENTRY *Head; + EFI_TIME LogTime; + + Private = DATA_HUB_INSTANCE_FROM_THIS (This); + + // + // Combine the storage for the internal structs and a copy of the log record. + // Record follows PrivateLogEntry. The consumer will be returned a pointer + // to Record so we don't what it to be the thing that was allocated from + // pool, so the consumer can't free an data record by mistake. + // + RecordSize = sizeof (EFI_DATA_RECORD_HEADER) + RawDataSize; + TotalSize = sizeof (EFI_DATA_ENTRY) + RecordSize; + + // + // First try to get log time at TPL level <= TPL_CALLBACK. + // + ZeroMem (&LogTime, sizeof (LogTime)); + if (EfiGetCurrentTpl() <= TPL_CALLBACK) { + gRT->GetTime (&LogTime, NULL); + } + + // + // The Logging action is the critical section, so it is locked. + // The MTC asignment & update and logging must be an + // atomic operation, so use the lock. + // + Status = EfiAcquireLockOrFail (&Private->DataLock); + if (EFI_ERROR (Status)) { + // + // Reentrancy detected so exit! + // + return Status; + } + + LogEntry = AllocatePool (TotalSize); + + if (LogEntry == NULL) { + EfiReleaseLock (&Private->DataLock); + return EFI_OUT_OF_RESOURCES; + } + + ZeroMem (LogEntry, TotalSize); + + Record = (EFI_DATA_RECORD_HEADER *) (LogEntry + 1); + Raw = (VOID *) (Record + 1); + + // + // Build Standard Log Header + // + Record->Version = EFI_DATA_RECORD_HEADER_VERSION; + Record->HeaderSize = (UINT16) sizeof (EFI_DATA_RECORD_HEADER); + Record->RecordSize = RecordSize; + CopyMem (&Record->DataRecordGuid, DataRecordGuid, sizeof (EFI_GUID)); + CopyMem (&Record->ProducerName, ProducerName, sizeof (EFI_GUID)); + Record->DataRecordClass = DataRecordClass; + // + // Ensure LogMonotonicCount is not zero + // + Record->LogMonotonicCount = ++Private->GlobalMonotonicCount; + + CopyMem (&Record->LogTime, &LogTime, sizeof (LogTime)); + + // + // Insert log into the internal linked list. + // + LogEntry->Signature = EFI_DATA_ENTRY_SIGNATURE; + LogEntry->Record = Record; + LogEntry->RecordSize = sizeof (EFI_DATA_ENTRY) + RawDataSize; + InsertTailList (&Private->DataListHead, &LogEntry->Link); + + CopyMem (Raw, RawData, RawDataSize); + + EfiReleaseLock (&Private->DataLock); + + // + // Send Signal to all the filter drivers which are interested + // in the record's class and guid. + // + Head = &Private->FilterDriverListHead; + for (Link = GetFirstNode(Head); Link != Head; Link = GetNextNode(Head, Link)) { + FilterEntry = FILTER_ENTRY_FROM_LINK (Link); + if (((FilterEntry->ClassFilter & DataRecordClass) != 0) && + (IsZeroGuid (&FilterEntry->FilterDataRecordGuid) || + CompareGuid (&FilterEntry->FilterDataRecordGuid, DataRecordGuid))) { + gBS->SignalEvent (FilterEntry->Event); + } + } + + return EFI_SUCCESS; +} + +/** + Search the Head doubly linked list for the passed in MTC. Return the + matching element in Head and the MTC on the next entry. + + @param Head Head of Data Log linked list. + @param ClassFilter Only match the MTC if it is in the same Class as the + ClassFilter. + @param PtrCurrentMTC On IN contians MTC to search for. On OUT contians next + MTC in the data log list or zero if at end of the list. + + @retval EFI_DATA_LOG_ENTRY Return pointer to data log data from Head list. + @retval NULL If no data record exists. + +**/ +EFI_DATA_RECORD_HEADER * +GetNextDataRecord ( + IN LIST_ENTRY *Head, + IN UINT64 ClassFilter, + IN OUT UINT64 *PtrCurrentMTC + ) + +{ + EFI_DATA_ENTRY *LogEntry; + LIST_ENTRY *Link; + BOOLEAN ReturnFirstEntry; + EFI_DATA_RECORD_HEADER *Record; + EFI_DATA_ENTRY *NextLogEntry; + + // + // If MonotonicCount == 0 just return the first one + // + ReturnFirstEntry = (BOOLEAN) (*PtrCurrentMTC == 0); + + Record = NULL; + for (Link = GetFirstNode(Head); Link != Head; Link = GetNextNode(Head, Link)) { + LogEntry = DATA_ENTRY_FROM_LINK (Link); + if ((LogEntry->Record->DataRecordClass & ClassFilter) == 0) { + // + // Skip any entry that does not have the correct ClassFilter + // + continue; + } + + if ((LogEntry->Record->LogMonotonicCount == *PtrCurrentMTC) || ReturnFirstEntry) { + // + // Return record to the user + // + Record = LogEntry->Record; + + // + // Calculate the next MTC value. If there is no next entry set + // MTC to zero. + // + *PtrCurrentMTC = 0; + for (Link = GetNextNode(Head, Link); Link != Head; Link = GetNextNode(Head, Link)) { + NextLogEntry = DATA_ENTRY_FROM_LINK (Link); + if ((NextLogEntry->Record->DataRecordClass & ClassFilter) != 0) { + // + // Return the MTC of the next thing to search for if found + // + *PtrCurrentMTC = NextLogEntry->Record->LogMonotonicCount; + break; + } + } + // + // Record found exit loop and return + // + break; + } + } + + return Record; +} + +/** + Search the Head list for a EFI_DATA_HUB_FILTER_DRIVER member that + represents Event and return it. + + @param Head Pointer to head of dual linked list of EFI_DATA_HUB_FILTER_DRIVER structures. + @param Event Event to be search for in the Head list. + + @retval EFI_DATA_HUB_FILTER_DRIVER Returned if Event stored in the Head doubly linked list. + @retval NULL If Event is not in the list + +**/ +DATA_HUB_FILTER_DRIVER * +FindFilterDriverByEvent ( + IN LIST_ENTRY *Head, + IN EFI_EVENT Event + ) +{ + DATA_HUB_FILTER_DRIVER *FilterEntry; + LIST_ENTRY *Link; + + for (Link = GetFirstNode(Head); Link != Head; Link = GetNextNode(Head, Link)) { + FilterEntry = FILTER_ENTRY_FROM_LINK (Link); + if (FilterEntry->Event == Event) { + return FilterEntry; + } + } + + return NULL; +} + +/** + + Get a previously logged data record and the MonotonicCount for the next + available Record. This allows all records or all records later + than a give MonotonicCount to be returned. If an optional FilterDriverEvent + is passed in with a MonotonicCout of zero return the first record + not yet read by the filter driver. If FilterDriverEvent is NULL and + MonotonicCount is zero return the first data record. + + @param This Pointer to the EFI_DATA_HUB_PROTOCOL instance. + @param MonotonicCount Specifies the Record to return. On input, zero means + return the first record. On output, contains the next + record to available. Zero indicates no more records. + @param FilterDriverEvent If FilterDriverEvent is not passed in a MonotonicCount + of zero, it means to return the first data record. + If FilterDriverEvent is passed in, then a MonotonicCount + of zero means to return the first data not yet read by + FilterDriverEvent. + @param Record Returns a dynamically allocated memory buffer with a data + record that matches MonotonicCount. + + @retval EFI_SUCCESS Data was returned in Record. + @retval EFI_INVALID_PARAMETER FilterDriverEvent was passed in but does not exist. + @retval EFI_NOT_FOUND MonotonicCount does not match any data record in the + system. If a MonotonicCount of zero was passed in, then + no data records exist in the system. + @retval EFI_OUT_OF_RESOURCES Record was not returned due to lack of system resources. + +**/ +EFI_STATUS +EFIAPI +DataHubGetNextRecord ( + IN EFI_DATA_HUB_PROTOCOL *This, + IN OUT UINT64 *MonotonicCount, + IN EFI_EVENT *FilterDriverEvent, OPTIONAL + OUT EFI_DATA_RECORD_HEADER **Record + ) +{ + DATA_HUB_INSTANCE *Private; + DATA_HUB_FILTER_DRIVER *FilterDriver; + UINT64 ClassFilter; + + Private = DATA_HUB_INSTANCE_FROM_THIS (This); + + FilterDriver = NULL; + ClassFilter = EFI_DATA_RECORD_CLASS_DEBUG | + EFI_DATA_RECORD_CLASS_ERROR | + EFI_DATA_RECORD_CLASS_DATA | + EFI_DATA_RECORD_CLASS_PROGRESS_CODE; + + // + // If FilterDriverEvent is NULL, then return the next record + // + if (FilterDriverEvent == NULL) { + *Record = GetNextDataRecord (&Private->DataListHead, ClassFilter, MonotonicCount); + if (*Record == NULL) { + return EFI_NOT_FOUND; + } + return EFI_SUCCESS; + } + + // + // For events the beginning is the last unread record. This info is + // stored in the instance structure, so we must look up the event + // to get the data. + // + FilterDriver = FindFilterDriverByEvent ( + &Private->FilterDriverListHead, + *FilterDriverEvent + ); + if (FilterDriver == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Use the Class filter the event was created with. + // + ClassFilter = FilterDriver->ClassFilter; + + // + // Retrieve the next record or the first record. + // + if (*MonotonicCount != 0 || FilterDriver->GetNextMonotonicCount == 0) { + *Record = GetNextDataRecord (&Private->DataListHead, ClassFilter, MonotonicCount); + if (*Record == NULL) { + return EFI_NOT_FOUND; + } + + if (*MonotonicCount != 0) { + // + // If this was not the last record then update the count associated with the filter + // + FilterDriver->GetNextMonotonicCount = *MonotonicCount; + } else { + // + // Save the MonotonicCount of the last record which has been read + // + FilterDriver->GetNextMonotonicCount = (*Record)->LogMonotonicCount; + } + return EFI_SUCCESS; + } + + // + // This is a request to read the first record that has not been read yet. + // Set MonotoicCount to the last record successfuly read + // + *MonotonicCount = FilterDriver->GetNextMonotonicCount; + + // + // Retrieve the last record successfuly read again, but do not return it since + // it has already been returned before. + // + *Record = GetNextDataRecord (&Private->DataListHead, ClassFilter, MonotonicCount); + if (*Record == NULL) { + return EFI_NOT_FOUND; + } + + if (*MonotonicCount != 0) { + // + // Update the count associated with the filter + // + FilterDriver->GetNextMonotonicCount = *MonotonicCount; + + // + // Retrieve the record after the last record successfuly read + // + *Record = GetNextDataRecord (&Private->DataListHead, ClassFilter, MonotonicCount); + if (*Record == NULL) { + return EFI_NOT_FOUND; + } + } + + return EFI_SUCCESS; +} + +/** + This function registers the data hub filter driver that is represented + by FilterEvent. Only one instance of each FilterEvent can be registered. + After the FilterEvent is registered, it will be signaled so it can sync + with data records that have been recorded prior to the FilterEvent being + registered. + + @param This Pointer to The EFI_DATA_HUB_PROTOCOL instance. + @param FilterEvent The EFI_EVENT to signal whenever data that matches + FilterClass is logged in the system. + @param FilterTpl The maximum EFI_TPL at which FilterEvent can be + signaled. It is strongly recommended that you use the + lowest EFI_TPL possible. + @param FilterClass FilterEvent will be signaled whenever a bit in + EFI_DATA_RECORD_HEADER.DataRecordClass is also set in + FilterClass. If FilterClass is zero, no class-based + filtering will be performed. + @param FilterDataRecordGuid FilterEvent will be signaled whenever FilterDataRecordGuid + matches EFI_DATA_RECORD_HEADER.DataRecordGuid. If + FilterDataRecordGuid is NULL, then no GUID-based filtering + will be performed. + + @retval EFI_SUCCESS The filter driver event was registered. + @retval EFI_ALREADY_STARTED FilterEvent was previously registered and cannot be + registered again. + @retval EFI_OUT_OF_RESOURCES The filter driver event was not registered due to lack of + system resources. + +**/ +EFI_STATUS +EFIAPI +DataHubRegisterFilterDriver ( + IN EFI_DATA_HUB_PROTOCOL * This, + IN EFI_EVENT FilterEvent, + IN EFI_TPL FilterTpl, + IN UINT64 FilterClass, + IN EFI_GUID * FilterDataRecordGuid OPTIONAL + ) + +{ + DATA_HUB_INSTANCE *Private; + DATA_HUB_FILTER_DRIVER *FilterDriver; + + Private = DATA_HUB_INSTANCE_FROM_THIS (This); + + FilterDriver = (DATA_HUB_FILTER_DRIVER *) AllocateZeroPool (sizeof (DATA_HUB_FILTER_DRIVER)); + if (FilterDriver == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Initialize filter driver info + // + FilterDriver->Signature = EFI_DATA_HUB_FILTER_DRIVER_SIGNATURE; + FilterDriver->Event = FilterEvent; + FilterDriver->Tpl = FilterTpl; + FilterDriver->GetNextMonotonicCount = 0; + if (FilterClass == 0) { + FilterDriver->ClassFilter = EFI_DATA_RECORD_CLASS_DEBUG | + EFI_DATA_RECORD_CLASS_ERROR | + EFI_DATA_RECORD_CLASS_DATA | + EFI_DATA_RECORD_CLASS_PROGRESS_CODE; + } else { + FilterDriver->ClassFilter = FilterClass; + } + + if (FilterDataRecordGuid != NULL) { + CopyMem (&FilterDriver->FilterDataRecordGuid, FilterDataRecordGuid, sizeof (EFI_GUID)); + } + // + // Search for duplicate entries + // + if (FindFilterDriverByEvent (&Private->FilterDriverListHead, FilterEvent) != NULL) { + FreePool (FilterDriver); + return EFI_ALREADY_STARTED; + } + // + // Make insertion an atomic operation with the lock. + // + EfiAcquireLock (&Private->DataLock); + InsertTailList (&Private->FilterDriverListHead, &FilterDriver->Link); + EfiReleaseLock (&Private->DataLock); + + // + // Signal the Filter driver we just loaded so they will recieve all the + // previous history. If we did not signal here we would have to wait until + // the next data was logged to get the history. In a case where no next + // data was logged we would never get synced up. + // + gBS->SignalEvent (FilterEvent); + + return EFI_SUCCESS; +} + +/** + Remove a Filter Driver, so it no longer gets called when data + information is logged. + + @param This Protocol instance structure + + @param FilterEvent Event that represents a filter driver that is to be + Unregistered. + + @retval EFI_SUCCESS If FilterEvent was unregistered + @retval EFI_NOT_FOUND If FilterEvent does not exist +**/ +EFI_STATUS +EFIAPI +DataHubUnregisterFilterDriver ( + IN EFI_DATA_HUB_PROTOCOL *This, + IN EFI_EVENT FilterEvent + ) +{ + DATA_HUB_INSTANCE *Private; + DATA_HUB_FILTER_DRIVER *FilterDriver; + + Private = DATA_HUB_INSTANCE_FROM_THIS (This); + + // + // Search for duplicate entries + // + FilterDriver = FindFilterDriverByEvent ( + &Private->FilterDriverListHead, + FilterEvent + ); + if (FilterDriver == NULL) { + return EFI_NOT_FOUND; + } + // + // Make removal an atomic operation with the lock + // + EfiAcquireLock (&Private->DataLock); + RemoveEntryList (&FilterDriver->Link); + EfiReleaseLock (&Private->DataLock); + + return EFI_SUCCESS; +} + + + +/** + Driver's Entry point routine that install Driver to produce Data Hub protocol. + + @param ImageHandle Module's image handle + @param SystemTable Pointer of EFI_SYSTEM_TABLE + + @retval EFI_SUCCESS Logging Hub protocol installed + @retval Other No protocol installed, unload driver. + +**/ EFI_STATUS EFIAPI -CloverDataHubInstall ( +DataHubInstall ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { - if ( DataHubInstall() != EFI_SUCCESS) return EFI_NOT_FOUND; - return EFI_SUCCESS; + EFI_STATUS Status; + UINT32 HighMontonicCount; + + mPrivateData.Signature = DATA_HUB_INSTANCE_SIGNATURE; + mPrivateData.DataHub.LogData = DataHubLogData; + mPrivateData.DataHub.GetNextRecord = DataHubGetNextRecord; + mPrivateData.DataHub.RegisterFilterDriver = DataHubRegisterFilterDriver; + mPrivateData.DataHub.UnregisterFilterDriver = DataHubUnregisterFilterDriver; + + // + // Initialize Private Data in CORE_LOGGING_HUB_INSTANCE that is + // required by this protocol + // + InitializeListHead (&mPrivateData.DataListHead); + InitializeListHead (&mPrivateData.FilterDriverListHead); + + EfiInitializeLock (&mPrivateData.DataLock, TPL_NOTIFY); + + // + // Make sure we get a bigger MTC number on every boot! + // + Status = gRT->GetNextHighMonotonicCount (&HighMontonicCount); + if (EFI_ERROR (Status)) { + // + // if system service fails pick a sane value. + // + mPrivateData.GlobalMonotonicCount = 0; + } else { + mPrivateData.GlobalMonotonicCount = LShiftU64 ((UINT64) HighMontonicCount, 32); + } + // + // Make a new handle and install the protocol + // + mPrivateData.Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &mPrivateData.Handle, + &gEfiDataHubProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPrivateData.DataHub + ); + return Status; } diff --git a/Protocols/DataHubDxe/DataHub.h b/Protocols/DataHubDxe/DataHub.h old mode 100644 new mode 100755 index 11c98ac46c..7770c438da --- a/Protocols/DataHubDxe/DataHub.h +++ b/Protocols/DataHubDxe/DataHub.h @@ -13,121 +13,117 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ -#ifndef _CLOVER_DATA_HUB_H_ -#define _CLOVER_DATA_HUB_H_ +#ifndef _DATA_HUB_H_ +#define _DATA_HUB_H_ -// now using OpenCore library to avoid multiple definition of functions -#include "../../OpenCorePkg/Library/OcDataHubLib/DataHub.h" +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DATA_HUB_INSTANCE_SIGNATURE SIGNATURE_32 ('D', 'H', 'u', 'b') +typedef struct { + UINT32 Signature; + + EFI_HANDLE Handle; + + // + // Produced protocol(s) + // + EFI_DATA_HUB_PROTOCOL DataHub; + + // + // Private Data + // + // + // Updates to GlobalMonotonicCount, LogListHead, and FilterDriverListHead + // must be locked. + // + EFI_LOCK DataLock; + + // + // Runing Monotonic Count to use for each error record. + // Increment AFTER use in an error record. + // + UINT64 GlobalMonotonicCount; + + // + // List of EFI_DATA_ENTRY structures. This is the data log! The list + // must be in assending order of LogMonotonicCount. + // + LIST_ENTRY DataListHead; + + // + // List of EFI_DATA_HUB_FILTER_DRIVER structures. Represents all + // the registered filter drivers. + // + LIST_ENTRY FilterDriverListHead; + +} DATA_HUB_INSTANCE; + +#define DATA_HUB_INSTANCE_FROM_THIS(this) CR (this, DATA_HUB_INSTANCE, DataHub, DATA_HUB_INSTANCE_SIGNATURE) // -//#include -// -//#include -// -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -// -//#define DATA_HUB_INSTANCE_SIGNATURE SIGNATURE_32 ('D', 'H', 'u', 'b') -//typedef struct { -// UINT32 Signature; -// -// EFI_HANDLE Handle; -// -// // -// // Produced protocol(s) -// // -// EFI_DATA_HUB_PROTOCOL DataHub; -// -// // -// // Private Data -// // -// // -// // Updates to GlobalMonotonicCount, LogListHead, and FilterDriverListHead -// // must be locked. -// // -// EFI_LOCK DataLock; -// -// // -// // Runing Monotonic Count to use for each error record. -// // Increment AFTER use in an error record. -// // -// UINT64 GlobalMonotonicCount; -// -// // -// // List of EFI_DATA_ENTRY structures. This is the data log! The list -// // must be in assending order of LogMonotonicCount. -// // -// LIST_ENTRY DataListHead; -// -// // -// // List of EFI_DATA_HUB_FILTER_DRIVER structures. Represents all -// // the registered filter drivers. -// // -// LIST_ENTRY FilterDriverListHead; -// -//} DATA_HUB_INSTANCE; -// -//#define DATA_HUB_INSTANCE_FROM_THIS(this) CR (this, DATA_HUB_INSTANCE, DataHub, DATA_HUB_INSTANCE_SIGNATURE) -// -//// -//// Private data structure to contain the data log. One record per -//// structure. Head pointer to the list is the Log member of -//// EFI_DATA_ENTRY. Record is a copy of the data passed in. -//// -//#define EFI_DATA_ENTRY_SIGNATURE SIGNATURE_32 ('D', 'r', 'e', 'c') -//typedef struct { -// UINT32 Signature; -// LIST_ENTRY Link; -// -// EFI_DATA_RECORD_HEADER *Record; -// -// UINTN RecordSize; -// -//} EFI_DATA_ENTRY; -// -//#define DATA_ENTRY_FROM_LINK(link) CR (link, EFI_DATA_ENTRY, Link, EFI_DATA_ENTRY_SIGNATURE) -// -//// -//// Private data to contain the filter driver Event and it's -//// associated EFI_TPL. -//// -//#define EFI_DATA_HUB_FILTER_DRIVER_SIGNATURE SIGNATURE_32 ('D', 'h', 'F', 'd') -// -//typedef struct { -// UINT32 Signature; -// LIST_ENTRY Link; -// -// // -// // Store Filter Driver Event and Tpl level it can be Signaled at. -// // -// EFI_EVENT Event; -// EFI_TPL Tpl; -// -// // -// // Monotonic count on the get next operation for Event. -// // Zero indicates get next has not been called for this event yet. -// // -// UINT64 GetNextMonotonicCount; -// -// // -// // Filter driver will register what class filter should be used. -// // -// UINT64 ClassFilter; +// Private data structure to contain the data log. One record per +// structure. Head pointer to the list is the Log member of +// EFI_DATA_ENTRY. Record is a copy of the data passed in. // -// // -// // Filter driver will register what record guid filter should be used. -// // -// EFI_GUID FilterDataRecordGuid; +#define EFI_DATA_ENTRY_SIGNATURE SIGNATURE_32 ('D', 'r', 'e', 'c') +typedef struct { + UINT32 Signature; + LIST_ENTRY Link; + + EFI_DATA_RECORD_HEADER *Record; + + UINTN RecordSize; + +} EFI_DATA_ENTRY; + +#define DATA_ENTRY_FROM_LINK(link) CR (link, EFI_DATA_ENTRY, Link, EFI_DATA_ENTRY_SIGNATURE) + // -//} DATA_HUB_FILTER_DRIVER; +// Private data to contain the filter driver Event and it's +// associated EFI_TPL. // -//#define FILTER_ENTRY_FROM_LINK(link) CR (link, DATA_HUB_FILTER_DRIVER, Link, EFI_DATA_HUB_FILTER_DRIVER_SIGNATURE) +#define EFI_DATA_HUB_FILTER_DRIVER_SIGNATURE SIGNATURE_32 ('D', 'h', 'F', 'd') + +typedef struct { + UINT32 Signature; + LIST_ENTRY Link; + + // + // Store Filter Driver Event and Tpl level it can be Signaled at. + // + EFI_EVENT Event; + EFI_TPL Tpl; + + // + // Monotonic count on the get next operation for Event. + // Zero indicates get next has not been called for this event yet. + // + UINT64 GetNextMonotonicCount; + + // + // Filter driver will register what class filter should be used. + // + UINT64 ClassFilter; + + // + // Filter driver will register what record guid filter should be used. + // + EFI_GUID FilterDataRecordGuid; + +} DATA_HUB_FILTER_DRIVER; + +#define FILTER_ENTRY_FROM_LINK(link) CR (link, DATA_HUB_FILTER_DRIVER, Link, EFI_DATA_HUB_FILTER_DRIVER_SIGNATURE) #endif diff --git a/Protocols/DataHubDxe/DataHubDxe.inf b/Protocols/DataHubDxe/DataHubDxe.inf old mode 100644 new mode 100755 index 338a114bc3..d2c6b04f23 --- a/Protocols/DataHubDxe/DataHubDxe.inf +++ b/Protocols/DataHubDxe/DataHubDxe.inf @@ -40,7 +40,7 @@ FILE_GUID = 53BCC14F-C24F-434C-B294-8ED2D4CC1860 MODULE_TYPE = DXE_DRIVER VERSION_STRING = 1.0 - ENTRY_POINT = CloverDataHubInstall + ENTRY_POINT = DataHubInstall # # The following information is for reference only and not required by the build tools. @@ -67,7 +67,7 @@ BaseLib UefiLib UefiDriverEntryPoint - OcDataHubLib + DebugLib [Protocols] diff --git a/Protocols/DataHubDxe/DataHubDxe.uni b/Protocols/DataHubDxe/DataHubDxe.uni old mode 100644 new mode 100755 diff --git a/Protocols/DataHubDxe/DataHubDxeExtra.uni b/Protocols/DataHubDxe/DataHubDxeExtra.uni old mode 100644 new mode 100755 diff --git a/buildme b/buildme index c75a7fdf3e..72a8b9c44d 100755 --- a/buildme +++ b/buildme @@ -157,7 +157,7 @@ else ./ebuild.sh -fr -D NO_GRUB_DRIVERS_EMBEDDED -D USE_APPLE_HFSPLUS_DRIVER -t $MYTOOLCHAIN else ./ebuild.sh -fr -mc --no-usb -D NO_GRUB_DRIVERS_EMBEDDED -t $MYTOOLCHAIN - ./ebuild.sh -fr -D NO_GRUB_DRIVERS_EMBEDDED -t $MYTOOLCHAIN + ./ebuild.sh -fr -D NO_GRUB_DRIVERS_EMBEDDED -D LESS_DEBUG -t $MYTOOLCHAIN fi fi