--- /dev/null
+/** @file\r
+ CPU DXE Module.\r
+\r
+ Copyright (c) 2008 - 2009, Intel Corporation\r
+ All rights reserved. This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "CpuDxe.h"\r
+\r
+//\r
+// Global Variables\r
+//\r
+IA32_IDT_GATE_DESCRIPTOR gIdtTable[INTERRUPT_VECTOR_NUMBER] = { 0 };\r
+\r
+EFI_CPU_INTERRUPT_HANDLER ExternalVectorTable[0x100];\r
+BOOLEAN InterruptState = FALSE;\r
+EFI_HANDLE mCpuHandle = NULL;\r
+BOOLEAN mIsFlushingGCD;\r
+UINT8 mDefaultMemoryType = MTRR_CACHE_WRITE_BACK;\r
+UINT64 mValidMtrrAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;\r
+UINT64 mValidMtrrBitsMask = MTRR_LIB_MSR_VALID_MASK;\r
+\r
+FIXED_MTRR mFixedMtrrTable[] = {\r
+ {\r
+ MTRR_LIB_IA32_MTRR_FIX64K_00000,\r
+ 0,\r
+ 0x10000\r
+ },\r
+ {\r
+ MTRR_LIB_IA32_MTRR_FIX16K_80000,\r
+ 0x80000,\r
+ 0x4000\r
+ },\r
+ {\r
+ MTRR_LIB_IA32_MTRR_FIX16K_A0000,\r
+ 0xA0000,\r
+ 0x4000\r
+ },\r
+ {\r
+ MTRR_LIB_IA32_MTRR_FIX4K_C0000,\r
+ 0xC0000,\r
+ 0x1000\r
+ },\r
+ {\r
+ MTRR_LIB_IA32_MTRR_FIX4K_C8000,\r
+ 0xC8000,\r
+ 0x1000\r
+ },\r
+ {\r
+ MTRR_LIB_IA32_MTRR_FIX4K_D0000,\r
+ 0xD0000,\r
+ 0x1000\r
+ },\r
+ {\r
+ MTRR_LIB_IA32_MTRR_FIX4K_D8000,\r
+ 0xD8000,\r
+ 0x1000\r
+ },\r
+ {\r
+ MTRR_LIB_IA32_MTRR_FIX4K_E0000,\r
+ 0xE0000,\r
+ 0x1000\r
+ },\r
+ {\r
+ MTRR_LIB_IA32_MTRR_FIX4K_E8000,\r
+ 0xE8000,\r
+ 0x1000\r
+ },\r
+ {\r
+ MTRR_LIB_IA32_MTRR_FIX4K_F0000,\r
+ 0xF0000,\r
+ 0x1000\r
+ },\r
+ {\r
+ MTRR_LIB_IA32_MTRR_FIX4K_F8000,\r
+ 0xF8000,\r
+ 0x1000\r
+ },\r
+};\r
+\r
+\r
+EFI_CPU_ARCH_PROTOCOL gCpu = {\r
+ CpuFlushCpuDataCache,\r
+ CpuEnableInterrupt,\r
+ CpuDisableInterrupt,\r
+ CpuGetInterruptState,\r
+ CpuInit,\r
+ CpuRegisterInterruptHandler,\r
+ CpuGetTimerValue,\r
+ CpuSetMemoryAttributes,\r
+ 1, // NumberOfTimers\r
+ 4 // DmaBufferAlignment\r
+};\r
+\r
+//\r
+// Error code flag indicating whether or not an error code will be\r
+// pushed on the stack if an exception occurs.\r
+//\r
+// 1 means an error code will be pushed, otherwise 0\r
+//\r
+// bit 0 - exception 0\r
+// bit 1 - exception 1\r
+// etc.\r
+//\r
+UINT32 mErrorCodeFlag = 0x00027d00;\r
+\r
+//\r
+// CPU Arch Protocol Functions\r
+//\r
+\r
+\r
+/**\r
+ Common exception handler.\r
+\r
+ @param InterruptType Exception type\r
+ @param SystemContext EFI_SYSTEM_CONTEXT\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+CommonExceptionHandler (\r
+ IN EFI_EXCEPTION_TYPE InterruptType,\r
+ IN EFI_SYSTEM_CONTEXT SystemContext\r
+ )\r
+{\r
+#if defined (MDE_CPU_IA32)\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "!!!! IA32 Exception Type - %08x !!!!\n",\r
+ InterruptType\r
+ ));\r
+ if (mErrorCodeFlag & (1 << InterruptType)) {\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "ExceptionData - %08x\n",\r
+ SystemContext.SystemContextIa32->ExceptionData\r
+ ));\r
+ }\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "CS - %04x, EIP - %08x, EFL - %08x, SS - %04x\n",\r
+ SystemContext.SystemContextIa32->Cs,\r
+ SystemContext.SystemContextIa32->Eip,\r
+ SystemContext.SystemContextIa32->Eflags,\r
+ SystemContext.SystemContextIa32->Ss\r
+ ));\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "DS - %04x, ES - %04x, FS - %04x, GS - %04x\n",\r
+ SystemContext.SystemContextIa32->Ds,\r
+ SystemContext.SystemContextIa32->Es,\r
+ SystemContext.SystemContextIa32->Fs,\r
+ SystemContext.SystemContextIa32->Gs\r
+ ));\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "EAX - %08x, EBX - %08x, ECX - %08x, EDX - %08x\n",\r
+ SystemContext.SystemContextIa32->Eax,\r
+ SystemContext.SystemContextIa32->Ebx,\r
+ SystemContext.SystemContextIa32->Ecx,\r
+ SystemContext.SystemContextIa32->Edx\r
+ ));\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "ESP - %08x, EBP - %08x, ESI - %08x, EDI - %08x\n",\r
+ SystemContext.SystemContextIa32->Esp,\r
+ SystemContext.SystemContextIa32->Ebp,\r
+ SystemContext.SystemContextIa32->Esi,\r
+ SystemContext.SystemContextIa32->Edi\r
+ ));\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "GDT - %08x LIM - %04x, IDT - %08x LIM - %04x\n",\r
+ SystemContext.SystemContextIa32->Gdtr[0],\r
+ SystemContext.SystemContextIa32->Gdtr[1],\r
+ SystemContext.SystemContextIa32->Idtr[0],\r
+ SystemContext.SystemContextIa32->Idtr[1]\r
+ ));\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "LDT - %08x, TR - %08x\n",\r
+ SystemContext.SystemContextIa32->Ldtr,\r
+ SystemContext.SystemContextIa32->Tr\r
+ ));\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "CR0 - %08x, CR2 - %08x, CR3 - %08x, CR4 - %08x\n",\r
+ SystemContext.SystemContextIa32->Cr0,\r
+ SystemContext.SystemContextIa32->Cr2,\r
+ SystemContext.SystemContextIa32->Cr3,\r
+ SystemContext.SystemContextIa32->Cr4\r
+ ));\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "DR0 - %08x, DR1 - %08x, DR2 - %08x, DR3 - %08x\n",\r
+ SystemContext.SystemContextIa32->Dr0,\r
+ SystemContext.SystemContextIa32->Dr1,\r
+ SystemContext.SystemContextIa32->Dr2,\r
+ SystemContext.SystemContextIa32->Dr3\r
+ ));\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "DR6 - %08x, DR7 - %08x\n",\r
+ SystemContext.SystemContextIa32->Dr6,\r
+ SystemContext.SystemContextIa32->Dr7\r
+ ));\r
+#elif defined (MDE_CPU_X64)\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "!!!! X64 Exception Type - %016lx !!!!\n",\r
+ (UINT64)InterruptType\r
+ ));\r
+ if (mErrorCodeFlag & (1 << InterruptType)) {\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "ExceptionData - %016lx\n",\r
+ SystemContext.SystemContextX64->ExceptionData\r
+ ));\r
+ }\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "RIP - %016lx, RFL - %016lx\n",\r
+ SystemContext.SystemContextX64->Rip,\r
+ SystemContext.SystemContextX64->Rflags\r
+ ));\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "RAX - %016lx, RCX - %016lx, RDX - %016lx\n",\r
+ SystemContext.SystemContextX64->Rax,\r
+ SystemContext.SystemContextX64->Rcx,\r
+ SystemContext.SystemContextX64->Rdx\r
+ ));\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "RBX - %016lx, RSP - %016lx, RBP - %016lx\n",\r
+ SystemContext.SystemContextX64->Rbx,\r
+ SystemContext.SystemContextX64->Rsp,\r
+ SystemContext.SystemContextX64->Rbp\r
+ ));\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "RSI - %016lx, RDI - %016lx\n",\r
+ SystemContext.SystemContextX64->Rsi,\r
+ SystemContext.SystemContextX64->Rdi\r
+ ));\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "R8 - %016lx, R9 - %016lx, R10 - %016lx\n",\r
+ SystemContext.SystemContextX64->R8,\r
+ SystemContext.SystemContextX64->R9,\r
+ SystemContext.SystemContextX64->R10\r
+ ));\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "R11 - %016lx, R12 - %016lx, R13 - %016lx\n",\r
+ SystemContext.SystemContextX64->R11,\r
+ SystemContext.SystemContextX64->R12,\r
+ SystemContext.SystemContextX64->R13\r
+ ));\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "R14 - %016lx, R15 - %016lx\n",\r
+ SystemContext.SystemContextX64->R14,\r
+ SystemContext.SystemContextX64->R15\r
+ ));\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "CS - %04lx, DS - %04lx, ES - %04lx, FS - %04lx, GS - %04lx, SS - %04lx\n",\r
+ SystemContext.SystemContextX64->Cs,\r
+ SystemContext.SystemContextX64->Ds,\r
+ SystemContext.SystemContextX64->Es,\r
+ SystemContext.SystemContextX64->Fs,\r
+ SystemContext.SystemContextX64->Gs,\r
+ SystemContext.SystemContextX64->Ss\r
+ ));\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "GDT - %016lx; %04lx, IDT - %016lx; %04lx\n",\r
+ SystemContext.SystemContextX64->Gdtr[0],\r
+ SystemContext.SystemContextX64->Gdtr[1],\r
+ SystemContext.SystemContextX64->Idtr[0],\r
+ SystemContext.SystemContextX64->Idtr[1]\r
+ ));\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "LDT - %016lx, TR - %016lx\n",\r
+ SystemContext.SystemContextX64->Ldtr,\r
+ SystemContext.SystemContextX64->Tr\r
+ ));\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "CR0 - %016lx, CR2 - %016lx, CR3 - %016lx\n",\r
+ SystemContext.SystemContextX64->Cr0,\r
+ SystemContext.SystemContextX64->Cr2,\r
+ SystemContext.SystemContextX64->Cr3\r
+ ));\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "CR4 - %016lx, CR8 - %016lx\n",\r
+ SystemContext.SystemContextX64->Cr4,\r
+ SystemContext.SystemContextX64->Cr8\r
+ ));\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "DR0 - %016lx, DR1 - %016lx, DR2 - %016lx\n",\r
+ SystemContext.SystemContextX64->Dr0,\r
+ SystemContext.SystemContextX64->Dr1,\r
+ SystemContext.SystemContextX64->Dr2\r
+ ));\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "DR3 - %016lx, DR6 - %016lx, DR7 - %016lx\n",\r
+ SystemContext.SystemContextX64->Dr3,\r
+ SystemContext.SystemContextX64->Dr6,\r
+ SystemContext.SystemContextX64->Dr7\r
+ ));\r
+#else\r
+#error CPU type not supported for exception information dump!\r
+#endif\r
+\r
+ //\r
+ // Hang the system with CpuSleep so the processor will enter a lower power\r
+ // state.\r
+ //\r
+ while (TRUE) {\r
+ CpuSleep ();\r
+ };\r
+}\r
+\r
+\r
+/**\r
+ Flush CPU data cache. If the instruction cache is fully coherent\r
+ with all DMA operations then function can just return EFI_SUCCESS.\r
+\r
+ @param This Protocol instance structure\r
+ @param Start Physical address to start flushing from.\r
+ @param Length Number of bytes to flush. Round up to chipset\r
+ granularity.\r
+ @param FlushType Specifies the type of flush operation to perform.\r
+\r
+ @retval EFI_SUCCESS If cache was flushed\r
+ @retval EFI_UNSUPPORTED If flush type is not supported.\r
+ @retval EFI_DEVICE_ERROR If requested range could not be flushed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuFlushCpuDataCache (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ IN EFI_PHYSICAL_ADDRESS Start,\r
+ IN UINT64 Length,\r
+ IN EFI_CPU_FLUSH_TYPE FlushType\r
+ )\r
+{\r
+ if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) {\r
+ AsmWbinvd ();\r
+ return EFI_SUCCESS;\r
+ } else if (FlushType == EfiCpuFlushTypeInvalidate) {\r
+ AsmInvd ();\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Enables CPU interrupts.\r
+\r
+ @param This Protocol instance structure\r
+\r
+ @retval EFI_SUCCESS If interrupts were enabled in the CPU\r
+ @retval EFI_DEVICE_ERROR If interrupts could not be enabled on the CPU.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuEnableInterrupt (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This\r
+ )\r
+{\r
+ EnableInterrupts ();\r
+\r
+ InterruptState = TRUE;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Disables CPU interrupts.\r
+\r
+ @param This Protocol instance structure\r
+\r
+ @retval EFI_SUCCESS If interrupts were disabled in the CPU.\r
+ @retval EFI_DEVICE_ERROR If interrupts could not be disabled on the CPU.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuDisableInterrupt (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This\r
+ )\r
+{\r
+ DisableInterrupts ();\r
+\r
+ InterruptState = FALSE;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Return the state of interrupts.\r
+\r
+ @param This Protocol instance structure\r
+ @param State Pointer to the CPU's current interrupt state\r
+\r
+ @retval EFI_SUCCESS If interrupts were disabled in the CPU.\r
+ @retval EFI_INVALID_PARAMETER State is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuGetInterruptState (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ OUT BOOLEAN *State\r
+ )\r
+{\r
+ if (State == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *State = InterruptState;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Generates an INIT to the CPU.\r
+\r
+ @param This Protocol instance structure\r
+ @param InitType Type of CPU INIT to perform\r
+\r
+ @retval EFI_SUCCESS If CPU INIT occurred. This value should never be\r
+ seen.\r
+ @retval EFI_DEVICE_ERROR If CPU INIT failed.\r
+ @retval EFI_UNSUPPORTED Requested type of CPU INIT not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuInit (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ IN EFI_CPU_INIT_TYPE InitType\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+/**\r
+ Registers a function to be called from the CPU interrupt handler.\r
+\r
+ @param This Protocol instance structure\r
+ @param InterruptType Defines which interrupt to hook. IA-32\r
+ valid range is 0x00 through 0xFF\r
+ @param InterruptHandler A pointer to a function of type\r
+ EFI_CPU_INTERRUPT_HANDLER that is called\r
+ when a processor interrupt occurs. A null\r
+ pointer is an error condition.\r
+\r
+ @retval EFI_SUCCESS If handler installed or uninstalled.\r
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler\r
+ for InterruptType was previously installed.\r
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for\r
+ InterruptType was not previously installed.\r
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType\r
+ is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuRegisterInterruptHandler (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ IN EFI_EXCEPTION_TYPE InterruptType,\r
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler\r
+ )\r
+{\r
+ if (InterruptType < 0 || InterruptType > 0xff) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (InterruptHandler == NULL && ExternalVectorTable[InterruptType] == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (InterruptHandler != NULL && ExternalVectorTable[InterruptType] != NULL) {\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+\r
+ ExternalVectorTable[InterruptType] = InterruptHandler;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Returns a timer value from one of the CPU's internal timers. There is no\r
+ inherent time interval between ticks but is a function of the CPU frequency.\r
+\r
+ @param This - Protocol instance structure.\r
+ @param TimerIndex - Specifies which CPU timer is requested.\r
+ @param TimerValue - Pointer to the returned timer value.\r
+ @param TimerPeriod - A pointer to the amount of time that passes\r
+ in femtoseconds (10-15) for each increment\r
+ of TimerValue. If TimerValue does not\r
+ increment at a predictable rate, then 0 is\r
+ returned. The amount of time that has\r
+ passed between two calls to GetTimerValue()\r
+ can be calculated with the formula\r
+ (TimerValue2 - TimerValue1) * TimerPeriod.\r
+ This parameter is optional and may be NULL.\r
+\r
+ @retval EFI_SUCCESS - If the CPU timer count was returned.\r
+ @retval EFI_UNSUPPORTED - If the CPU does not have any readable timers.\r
+ @retval EFI_DEVICE_ERROR - If an error occurred while reading the timer.\r
+ @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuGetTimerValue (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ IN UINT32 TimerIndex,\r
+ OUT UINT64 *TimerValue,\r
+ OUT UINT64 *TimerPeriod OPTIONAL\r
+ )\r
+{\r
+ if (TimerValue == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (TimerIndex != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *TimerValue = AsmReadTsc ();\r
+\r
+ if (TimerPeriod != NULL) {\r
+ //\r
+ // BugBug: Hard coded. Don't know how to do this generically\r
+ //\r
+ *TimerPeriod = 1000000000;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Set memory cacheability attributes for given range of memeory.\r
+\r
+ @param This Protocol instance structure\r
+ @param BaseAddress Specifies the start address of the\r
+ memory range\r
+ @param Length Specifies the length of the memory range\r
+ @param Attributes The memory cacheability for the memory range\r
+\r
+ @retval EFI_SUCCESS If the cacheability of that memory range is\r
+ set successfully\r
+ @retval EFI_UNSUPPORTED If the desired operation cannot be done\r
+ @retval EFI_INVALID_PARAMETER The input parameter is not correct,\r
+ such as Length = 0\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuSetMemoryAttributes (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length,\r
+ IN UINT64 Attributes\r
+ )\r
+{\r
+ RETURN_STATUS Status;\r
+ MTRR_MEMORY_CACHE_TYPE CacheType;\r
+\r
+ DEBUG((EFI_D_ERROR, "CpuAp: SetMemorySpaceAttributes(BA=%08x, Len=%08x, Attr=%08x)\n", BaseAddress, Length, Attributes));\r
+\r
+ //\r
+ // If this function is called because GCD SetMemorySpaceAttributes () is called\r
+ // by RefreshGcdMemoryAttributes (), then we are just synchronzing GCD memory\r
+ // map with MTRR values. So there is no need to modify MTRRs, just return immediately\r
+ // to avoid unnecessary computing.\r
+ //\r
+ if (mIsFlushingGCD) {\r
+ DEBUG((EFI_D_ERROR, " Flushing GCD\n"));\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ switch (Attributes) {\r
+ case EFI_MEMORY_UC:\r
+ CacheType = CacheUncacheable;\r
+ break;\r
+\r
+ case EFI_MEMORY_WC:\r
+ CacheType = CacheWriteCombining;\r
+ break;\r
+\r
+ case EFI_MEMORY_WT:\r
+ CacheType = CacheWriteThrough;\r
+ break;\r
+\r
+ case EFI_MEMORY_WP:\r
+ CacheType = CacheWriteProtected;\r
+ break;\r
+\r
+ case EFI_MEMORY_WB:\r
+ CacheType = CacheWriteBack;\r
+ break;\r
+\r
+ default:\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ //\r
+ // call MTRR libary function\r
+ //\r
+ DEBUG((EFI_D_ERROR, " MtrrSetMemoryAttribute()\n"));\r
+ Status = MtrrSetMemoryAttribute(\r
+ BaseAddress,\r
+ Length,\r
+ CacheType\r
+ );\r
+\r
+ MtrrDebugPrintAllMtrrs ();\r
+\r
+ return (EFI_STATUS) Status;\r
+}\r
+\r
+/**\r
+ Initializes the valid bits mask and valid address mask for MTRRs.\r
+\r
+ This function initializes the valid bits mask and valid address mask for MTRRs.\r
+\r
+**/\r
+VOID\r
+InitializeMtrrMask (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 RegEax;\r
+ UINT8 PhysicalAddressBits;\r
+\r
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+\r
+ if (RegEax >= 0x80000008) {\r
+ AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
+\r
+ PhysicalAddressBits = (UINT8) RegEax;\r
+\r
+ mValidMtrrBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;\r
+ mValidMtrrAddressMask = mValidMtrrBitsMask & 0xfffffffffffff000ULL;\r
+ } else {\r
+ mValidMtrrBitsMask = MTRR_LIB_MSR_VALID_MASK;\r
+ mValidMtrrAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;\r
+ }\r
+}\r
+\r
+/**\r
+ Gets GCD Mem Space type from MTRR Type\r
+\r
+ This function gets GCD Mem Space type from MTRR Type\r
+\r
+ @param MtrrAttribute MTRR memory type\r
+\r
+ @return GCD Mem Space type\r
+\r
+**/\r
+UINT64\r
+GetMemorySpaceAttributeFromMtrrType (\r
+ IN UINT8 MtrrAttributes\r
+ )\r
+{\r
+ switch (MtrrAttributes) {\r
+ case MTRR_CACHE_UNCACHEABLE:\r
+ return EFI_MEMORY_UC;\r
+ case MTRR_CACHE_WRITE_COMBINING:\r
+ return EFI_MEMORY_WC;\r
+ case MTRR_CACHE_WRITE_THROUGH:\r
+ return EFI_MEMORY_WT;\r
+ case MTRR_CACHE_WRITE_PROTECTED:\r
+ return EFI_MEMORY_WP;\r
+ case MTRR_CACHE_WRITE_BACK:\r
+ return EFI_MEMORY_WB;\r
+ default:\r
+ return 0;\r
+ }\r
+}\r
+\r
+/**\r
+ Searches memory descriptors covered by given memory range.\r
+\r
+ This function searches into the Gcd Memory Space for descriptors\r
+ (from StartIndex to EndIndex) that contains the memory range\r
+ specified by BaseAddress and Length.\r
+\r
+ @param MemorySpaceMap Gcd Memory Space Map as array.\r
+ @param NumberOfDescriptors Number of descriptors in map.\r
+ @param BaseAddress BaseAddress for the requested range.\r
+ @param Length Length for the requested range.\r
+ @param StartIndex Start index into the Gcd Memory Space Map.\r
+ @param EndIndex End index into the Gcd Memory Space Map.\r
+\r
+ @retval EFI_SUCCESS Search successfully.\r
+ @retval EFI_NOT_FOUND The requested descriptors does not exist.\r
+\r
+**/\r
+EFI_STATUS\r
+SearchGcdMemorySpaces (\r
+ IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,\r
+ IN UINTN NumberOfDescriptors,\r
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length,\r
+ OUT UINTN *StartIndex,\r
+ OUT UINTN *EndIndex\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ *StartIndex = 0;\r
+ *EndIndex = 0;\r
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
+ if (BaseAddress >= MemorySpaceMap[Index].BaseAddress &&\r
+ BaseAddress < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {\r
+ *StartIndex = Index;\r
+ }\r
+ if (BaseAddress + Length - 1 >= MemorySpaceMap[Index].BaseAddress &&\r
+ BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {\r
+ *EndIndex = Index;\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+ Sets the attributes for a specified range in Gcd Memory Space Map.\r
+\r
+ This function sets the attributes for a specified range in\r
+ Gcd Memory Space Map.\r
+\r
+ @param MemorySpaceMap Gcd Memory Space Map as array\r
+ @param NumberOfDescriptors Number of descriptors in map\r
+ @param BaseAddress BaseAddress for the range\r
+ @param Length Length for the range\r
+ @param Attributes Attributes to set\r
+\r
+ @retval EFI_SUCCESS Memory attributes set successfully\r
+ @retval EFI_NOT_FOUND The specified range does not exist in Gcd Memory Space\r
+\r
+**/\r
+EFI_STATUS\r
+SetGcdMemorySpaceAttributes (\r
+ IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,\r
+ IN UINTN NumberOfDescriptors,\r
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length,\r
+ IN UINT64 Attributes\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ UINTN StartIndex;\r
+ UINTN EndIndex;\r
+ EFI_PHYSICAL_ADDRESS RegionStart;\r
+ UINT64 RegionLength;\r
+\r
+ //\r
+ // Get all memory descriptors covered by the memory range\r
+ //\r
+ Status = SearchGcdMemorySpaces (\r
+ MemorySpaceMap,\r
+ NumberOfDescriptors,\r
+ BaseAddress,\r
+ Length,\r
+ &StartIndex,\r
+ &EndIndex\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Go through all related descriptors and set attributes accordingly\r
+ //\r
+ for (Index = StartIndex; Index <= EndIndex; Index++) {\r
+ if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {\r
+ continue;\r
+ }\r
+ //\r
+ // Calculate the start and end address of the overlapping range\r
+ //\r
+ if (BaseAddress >= MemorySpaceMap[Index].BaseAddress) {\r
+ RegionStart = BaseAddress;\r
+ } else {\r
+ RegionStart = MemorySpaceMap[Index].BaseAddress;\r
+ }\r
+ if (BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {\r
+ RegionLength = BaseAddress + Length - RegionStart;\r
+ } else {\r
+ RegionLength = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - RegionStart;\r
+ }\r
+ //\r
+ // Set memory attributes according to MTRR attribute and the original attribute of descriptor\r
+ //\r
+ gDS->SetMemorySpaceAttributes (\r
+ RegionStart,\r
+ RegionLength,\r
+ (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) | (MemorySpaceMap[Index].Capabilities & Attributes)\r
+ );\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Refreshes the GCD Memory Space attributes according to MTRRs.\r
+\r
+ This function refreshes the GCD Memory Space attributes according to MTRRs.\r
+\r
+**/\r
+VOID\r
+RefreshGcdMemoryAttributes (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ UINTN SubIndex;\r
+ UINT64 RegValue;\r
+ EFI_PHYSICAL_ADDRESS BaseAddress;\r
+ UINT64 Length;\r
+ UINT64 Attributes;\r
+ UINT64 CurrentAttributes;\r
+ UINT8 MtrrType;\r
+ UINTN NumberOfDescriptors;\r
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;\r
+ UINT64 DefaultAttributes;\r
+ VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+ MTRR_FIXED_SETTINGS MtrrFixedSettings;\r
+\r
+// mIsFlushingGCD = TRUE;\r
+ mIsFlushingGCD = FALSE;\r
+ MemorySpaceMap = NULL;\r
+\r
+ //\r
+ // Initialize the valid bits mask and valid address mask for MTRRs\r
+ //\r
+ InitializeMtrrMask ();\r
+\r
+ //\r
+ // Get the memory attribute of variable MTRRs\r
+ //\r
+ MtrrGetMemoryAttributeInVariableMtrr (\r
+ mValidMtrrBitsMask,\r
+ mValidMtrrAddressMask,\r
+ VariableMtrr\r
+ );\r
+\r
+ //\r
+ // Get the memory space map from GCD\r
+ //\r
+ Status = gDS->GetMemorySpaceMap (\r
+ &NumberOfDescriptors,\r
+ &MemorySpaceMap\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ DefaultAttributes = GetMemorySpaceAttributeFromMtrrType (mDefaultMemoryType);\r
+\r
+ //\r
+ // Set default attributes to all spaces.\r
+ //\r
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
+ if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {\r
+ continue;\r
+ }\r
+ gDS->SetMemorySpaceAttributes (\r
+ MemorySpaceMap[Index].BaseAddress,\r
+ MemorySpaceMap[Index].Length,\r
+ (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) |\r
+ (MemorySpaceMap[Index].Capabilities & DefaultAttributes)\r
+ );\r
+ }\r
+\r
+ //\r
+ // Go for variable MTRRs with WB attribute\r
+ //\r
+ for (Index = 0; Index < FIRMWARE_VARIABLE_MTRR_NUMBER; Index++) {\r
+ if (VariableMtrr[Index].Valid &&\r
+ VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) {\r
+ SetGcdMemorySpaceAttributes (\r
+ MemorySpaceMap,\r
+ NumberOfDescriptors,\r
+ VariableMtrr[Index].BaseAddress,\r
+ VariableMtrr[Index].Length,\r
+ EFI_MEMORY_WB\r
+ );\r
+ }\r
+ }\r
+ //\r
+ // Go for variable MTRRs with Non-WB attribute\r
+ //\r
+ for (Index = 0; Index < FIRMWARE_VARIABLE_MTRR_NUMBER; Index++) {\r
+ if (VariableMtrr[Index].Valid &&\r
+ VariableMtrr[Index].Type != MTRR_CACHE_WRITE_BACK) {\r
+ Attributes = GetMemorySpaceAttributeFromMtrrType ((UINT8) VariableMtrr[Index].Type);\r
+ SetGcdMemorySpaceAttributes (\r
+ MemorySpaceMap,\r
+ NumberOfDescriptors,\r
+ VariableMtrr[Index].BaseAddress,\r
+ VariableMtrr[Index].Length,\r
+ Attributes\r
+ );\r
+ }\r
+ }\r
+\r
+ //\r
+ // Go for fixed MTRRs\r
+ //\r
+ Attributes = 0;\r
+ BaseAddress = 0;\r
+ Length = 0;\r
+ MtrrGetFixedMtrr (&MtrrFixedSettings);\r
+ for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+ RegValue = MtrrFixedSettings.Mtrr[Index];\r
+ //\r
+ // Check for continuous fixed MTRR sections\r
+ //\r
+ for (SubIndex = 0; SubIndex < 8; SubIndex++) {\r
+ MtrrType = (UINT8) RShiftU64 (RegValue, SubIndex * 8);\r
+ CurrentAttributes = GetMemorySpaceAttributeFromMtrrType (MtrrType);\r
+ if (Length == 0) {\r
+ //\r
+ // A new MTRR attribute begins\r
+ //\r
+ Attributes = CurrentAttributes;\r
+ } else {\r
+ //\r
+ // If fixed MTRR attribute changed, then set memory attribute for previous atrribute\r
+ //\r
+ if (CurrentAttributes != Attributes) {\r
+ SetGcdMemorySpaceAttributes (\r
+ MemorySpaceMap,\r
+ NumberOfDescriptors,\r
+ BaseAddress,\r
+ Length,\r
+ Attributes\r
+ );\r
+ BaseAddress = mFixedMtrrTable[Index].BaseAddress + mFixedMtrrTable[Index].Length * SubIndex;\r
+ Length = 0;\r
+ Attributes = CurrentAttributes;\r
+ }\r
+ }\r
+ Length += mFixedMtrrTable[Index].Length;\r
+ }\r
+ }\r
+ //\r
+ // Handle the last fixed MTRR region\r
+ //\r
+ SetGcdMemorySpaceAttributes (\r
+ MemorySpaceMap,\r
+ NumberOfDescriptors,\r
+ BaseAddress,\r
+ Length,\r
+ Attributes\r
+ );\r
+\r
+ //\r
+ // Free memory space map allocated by GCD service GetMemorySpaceMap ()\r
+ //\r
+ if (MemorySpaceMap != NULL) {\r
+ FreePool (MemorySpaceMap);\r
+ }\r
+\r
+ mIsFlushingGCD = FALSE;\r
+}\r
+\r
+\r
+/**\r
+ Initialize Interrupt Descriptor Table for interrupt handling.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+InitInterruptDescriptorTable (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *IdtPtrAlignmentBuffer;\r
+ IA32_DESCRIPTOR *IdtPtr;\r
+ UINTN Index;\r
+ UINTN CurrentHandler;\r
+\r
+ SetMem (ExternalVectorTable, sizeof(ExternalVectorTable), 0);\r
+\r
+ //\r
+ // Intialize IDT\r
+ //\r
+ CurrentHandler = (UINTN)AsmIdtVector00;\r
+ for (Index = 0; Index < INTERRUPT_VECTOR_NUMBER; Index ++, CurrentHandler += 0x08) {\r
+ gIdtTable[Index].Bits.OffsetLow = (UINT16)CurrentHandler;\r
+ gIdtTable[Index].Bits.Selector = AsmReadCs();\r
+ gIdtTable[Index].Bits.Reserved_0 = 0;\r
+ gIdtTable[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;\r
+ gIdtTable[Index].Bits.OffsetHigh = (UINT16)(CurrentHandler >> 16);\r
+#if defined (MDE_CPU_X64)\r
+ gIdtTable[Index].Bits.OffsetUpper = (UINT32)(CurrentHandler >> 32);\r
+ gIdtTable[Index].Bits.Reserved_1 = 0;\r
+#endif\r
+ }\r
+\r
+ //\r
+ // Load IDT Pointer\r
+ //\r
+ IdtPtrAlignmentBuffer = AllocatePool (sizeof (*IdtPtr) + 16);\r
+ IdtPtr = ALIGN_POINTER (IdtPtrAlignmentBuffer, 16);\r
+ IdtPtr->Base = (UINT32)(((UINTN)(VOID*) gIdtTable) & (BASE_4GB-1));\r
+ IdtPtr->Limit = sizeof (gIdtTable) - 1;\r
+ AsmWriteIdtr (IdtPtr);\r
+ FreePool (IdtPtrAlignmentBuffer);\r
+\r
+ //\r
+ // Initialize Exception Handlers\r
+ //\r
+ for (Index = 0; Index < 32; Index++) {\r
+ Status = CpuRegisterInterruptHandler (&gCpu, Index, CommonExceptionHandler);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ //\r
+ // Set the pointer to the array of C based exception handling routines.\r
+ //\r
+ InitializeExternalVectorTablePtr (ExternalVectorTable);\r
+\r
+}\r
+\r
+\r
+/**\r
+ Initialize the state information for the CPU Architectural Protocol.\r
+\r
+ @param ImageHandle Image handle this driver.\r
+ @param SystemTable Pointer to the System Table.\r
+\r
+ @retval EFI_SUCCESS Thread can be successfully created\r
+ @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure\r
+ @retval EFI_DEVICE_ERROR Cannot create the thread\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeCpu (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Make sure interrupts are disabled\r
+ //\r
+ DisableInterrupts ();\r
+\r
+ //\r
+ // Init GDT for DXE\r
+ //\r
+ InitGlobalDescriptorTable ();\r
+\r
+ //\r
+ // Setup IDT pointer, IDT and interrupt entry points\r
+ //\r
+ InitInterruptDescriptorTable ();\r
+\r
+ //\r
+ // Install CPU Architectural Protocol\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &mCpuHandle,\r
+ &gEfiCpuArchProtocolGuid, &gCpu,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Refresh GCD memory space map according to MTRR value.\r
+ //\r
+ RefreshGcdMemoryAttributes ();\r
+\r
+ return Status;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+ CPU DXE Module.\r
+\r
+ Copyright (c) 2008 - 2009, Intel Corporation\r
+ All rights reserved. This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _CPU_DXE_H\r
+#define _CPU_DXE_H\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <Protocol/Cpu.h>\r
+\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/CpuLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/MtrrLib.h>\r
+\r
+//\r
+//\r
+//\r
+#define INTERRUPT_VECTOR_NUMBER 256\r
+\r
+#define EFI_MEMORY_CACHETYPE_MASK (EFI_MEMORY_UC | \\r
+ EFI_MEMORY_WC | \\r
+ EFI_MEMORY_WT | \\r
+ EFI_MEMORY_WB | \\r
+ EFI_MEMORY_UCE \\r
+ )\r
+\r
+\r
+//\r
+// Function declarations\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+CpuFlushCpuDataCache (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ IN EFI_PHYSICAL_ADDRESS Start,\r
+ IN UINT64 Length,\r
+ IN EFI_CPU_FLUSH_TYPE FlushType\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+CpuEnableInterrupt (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+CpuDisableInterrupt (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+CpuGetInterruptState (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ OUT BOOLEAN *State\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+CpuInit (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ IN EFI_CPU_INIT_TYPE InitType\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+CpuRegisterInterruptHandler (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ IN EFI_EXCEPTION_TYPE InterruptType,\r
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+CpuGetTimerValue (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ IN UINT32 TimerIndex,\r
+ OUT UINT64 *TimerValue,\r
+ OUT UINT64 *TimerPeriod OPTIONAL\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+CpuSetMemoryAttributes (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length,\r
+ IN UINT64 Attributes\r
+ );\r
+\r
+VOID\r
+EFIAPI\r
+AsmIdtVector00 (\r
+ VOID\r
+ );\r
+\r
+VOID\r
+EFIAPI\r
+InitializeExternalVectorTablePtr (\r
+ EFI_CPU_INTERRUPT_HANDLER *VectorTable\r
+ );\r
+\r
+VOID\r
+InitGlobalDescriptorTable (\r
+ VOID\r
+ );\r
+\r
+VOID\r
+EFIAPI\r
+SetCodeSelector (\r
+ UINT16 Selector\r
+ );\r
+\r
+VOID\r
+EFIAPI\r
+SetDataSelectors (\r
+ UINT16 Selector\r
+ );\r
+\r
+\r
+#endif\r
+\r
--- /dev/null
+#/** @file\r
+#\r
+# Component description file for simple CPU driver\r
+#\r
+# Copyright (c) 2008 - 2009, Intel Corporation. <BR>\r
+# All rights reserved. This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#**/\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = CpuDxe\r
+ FILE_GUID = 62D171CB-78CD-4480-8678-C6A2A797A8DE\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ EDK_RELEASE_VERSION = 0x00020000\r
+ EFI_SPECIFICATION_VERSION = 0x0002000A\r
+\r
+ ENTRY_POINT = InitializeCpu\r
+\r
+[Packages]\r
+ OvmfPkg/OvmfPkg.dec\r
+ MdePkg/MdePkg.dec\r
+ UefiCpuPkg/UefiCpuPkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseLib\r
+ BaseMemoryLib\r
+ CpuLib\r
+ DebugLib\r
+ DxeServicesTableLib\r
+ MemoryAllocationLib\r
+ MtrrLib\r
+ UefiBootServicesTableLib\r
+ UefiDriverEntryPoint\r
+\r
+[Sources]\r
+ CpuDxe.c\r
+ CpuDxe.h\r
+ CpuGdt.c\r
+\r
+ Ia32/IvtAsm.asm | MSFT\r
+ Ia32/IvtAsm.asm | INTEL\r
+ Ia32/IvtAsm.S | GCC\r
+\r
+[Sources.IA32]\r
+ Ia32/CpuAsm.asm | MSFT\r
+ Ia32/CpuAsm.asm | INTEL\r
+ Ia32/CpuAsm.S | GCC\r
+\r
+[Sources.X64]\r
+ X64/CpuAsm.asm | MSFT\r
+ X64/CpuAsm.asm | INTEL\r
+ X64/CpuAsm.S | GCC\r
+\r
+[Protocols]\r
+ gEfiCpuArchProtocolGuid\r
+\r
+[Depex]\r
+ TRUE\r
+\r
--- /dev/null
+/** @file\r
+ C based implemention of IA32 interrupt handling only\r
+ requiring a minimal assembly interrupt entry point.\r
+\r
+ Copyright (c) 2006 - 2009, Intel Corporation\r
+ All rights reserved. This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "CpuDxe.h"\r
+\r
+\r
+//\r
+// Local structure definitions\r
+//\r
+\r
+#pragma pack (1)\r
+\r
+//\r
+// Global Descriptor Entry structures\r
+//\r
+\r
+typedef\r
+struct _GDT_ENTRY {\r
+ UINT16 limit15_0;\r
+ UINT16 base15_0;\r
+ UINT8 base23_16;\r
+ UINT8 type;\r
+ UINT8 limit19_16_and_flags;\r
+ UINT8 base31_24;\r
+} GDT_ENTRY;\r
+\r
+typedef\r
+struct _GDT_ENTRIES {\r
+ GDT_ENTRY Null;\r
+ GDT_ENTRY Linear;\r
+ GDT_ENTRY LinearCode;\r
+ GDT_ENTRY SysData;\r
+ GDT_ENTRY SysCode;\r
+ GDT_ENTRY LinearCode64;\r
+ GDT_ENTRY Spare4;\r
+ GDT_ENTRY Spare5;\r
+} GDT_ENTRIES;\r
+\r
+#define NULL_SEL OFFSET_OF (GDT_ENTRIES, Null)\r
+#define LINEAR_SEL OFFSET_OF (GDT_ENTRIES, Linear)\r
+#define LINEAR_CODE_SEL OFFSET_OF (GDT_ENTRIES, LinearCode)\r
+#define SYS_DATA_SEL OFFSET_OF (GDT_ENTRIES, SysData)\r
+#define SYS_CODE_SEL OFFSET_OF (GDT_ENTRIES, SysCode)\r
+#define LINEAR_CODE64_SEL OFFSET_OF (GDT_ENTRIES, LinearCode64)\r
+#define SPARE4_SEL OFFSET_OF (GDT_ENTRIES, Spare4)\r
+#define SPARE5_SEL OFFSET_OF (GDT_ENTRIES, Spare5)\r
+\r
+#if defined (MDE_CPU_IA32)\r
+#define CPU_CODE_SEL LINEAR_CODE_SEL\r
+#define CPU_DATA_SEL LINEAR_SEL\r
+#elif defined (MDE_CPU_X64)\r
+#define CPU_CODE_SEL LINEAR_CODE64_SEL\r
+#define CPU_DATA_SEL LINEAR_SEL\r
+#else\r
+#error CPU type not supported for CPU GDT initialization!\r
+#endif\r
+\r
+//\r
+// Global descriptor table (GDT) Template\r
+//\r
+STATIC GDT_ENTRIES GdtTemplate = {\r
+ //\r
+ // NULL_SEL\r
+ //\r
+ {\r
+ 0x0, // limit 15:0\r
+ 0x0, // base 15:0\r
+ 0x0, // base 23:16\r
+ 0x0, // type\r
+ 0x0, // limit 19:16, flags\r
+ 0x0, // base 31:24\r
+ },\r
+ //\r
+ // LINEAR_SEL\r
+ //\r
+ {\r
+ 0x0FFFF, // limit 0xFFFFF\r
+ 0x0, // base 0\r
+ 0x0,\r
+ 0x092, // present, ring 0, data, expand-up, writable\r
+ 0x0CF, // page-granular, 32-bit\r
+ 0x0,\r
+ },\r
+ //\r
+ // LINEAR_CODE_SEL\r
+ //\r
+ {\r
+ 0x0FFFF, // limit 0xFFFFF\r
+ 0x0, // base 0\r
+ 0x0,\r
+ 0x09A, // present, ring 0, data, expand-up, writable\r
+ 0x0CF, // page-granular, 32-bit\r
+ 0x0,\r
+ },\r
+ //\r
+ // SYS_DATA_SEL\r
+ //\r
+ {\r
+ 0x0FFFF, // limit 0xFFFFF\r
+ 0x0, // base 0\r
+ 0x0,\r
+ 0x092, // present, ring 0, data, expand-up, writable\r
+ 0x0CF, // page-granular, 32-bit\r
+ 0x0,\r
+ },\r
+ //\r
+ // SYS_CODE_SEL\r
+ //\r
+ {\r
+ 0x0FFFF, // limit 0xFFFFF\r
+ 0x0, // base 0\r
+ 0x0,\r
+ 0x09A, // present, ring 0, data, expand-up, writable\r
+ 0x0CF, // page-granular, 32-bit\r
+ 0x0,\r
+ },\r
+ //\r
+ // LINEAR_CODE64_SEL\r
+ //\r
+ {\r
+ 0x0FFFF, // limit 0xFFFFF\r
+ 0x0, // base 0\r
+ 0x0,\r
+ 0x09B, // present, ring 0, code, expand-up, writable\r
+ 0x0AF, // LimitHigh (CS.L=1, CS.D=0)\r
+ 0x0, // base (high)\r
+ },\r
+ //\r
+ // SPARE4_SEL\r
+ //\r
+ {\r
+ 0x0, // limit 0\r
+ 0x0, // base 0\r
+ 0x0,\r
+ 0x0, // present, ring 0, data, expand-up, writable\r
+ 0x0, // page-granular, 32-bit\r
+ 0x0,\r
+ },\r
+ //\r
+ // SPARE5_SEL\r
+ //\r
+ {\r
+ 0x0, // limit 0\r
+ 0x0, // base 0\r
+ 0x0,\r
+ 0x0, // present, ring 0, data, expand-up, writable\r
+ 0x0, // page-granular, 32-bit\r
+ 0x0,\r
+ },\r
+};\r
+\r
+/**\r
+ Initialize Global Descriptor Table\r
+\r
+**/\r
+VOID\r
+InitGlobalDescriptorTable (\r
+ )\r
+{\r
+ GDT_ENTRIES *gdt;\r
+ IA32_DESCRIPTOR gdtPtr;\r
+\r
+ //\r
+ // Allocate Runtime Data for the GDT\r
+ //\r
+ gdt = AllocateRuntimePool (sizeof (GdtTemplate) + 8);\r
+ ASSERT (gdt != NULL);\r
+ gdt = ALIGN_POINTER (gdt, 8);\r
+\r
+ //\r
+ // Initialize all GDT entries\r
+ //\r
+ CopyMem (gdt, &GdtTemplate, sizeof (GdtTemplate));\r
+\r
+ //\r
+ // Write GDT register\r
+ //\r
+ gdtPtr.Base = (UINT32)(UINTN)(VOID*) gdt;\r
+ gdtPtr.Limit = sizeof (GdtTemplate) - 1;\r
+ AsmWriteGdtr (&gdtPtr);\r
+\r
+ //\r
+ // Update selector (segment) registers base on new GDT\r
+ //\r
+ SetCodeSelector ((UINT16)CPU_CODE_SEL);\r
+ SetDataSelectors ((UINT16)CPU_DATA_SEL);\r
+}\r
+\r
--- /dev/null
+#
+# ConvertAsm.py: Automatically generated from CpuAsm.asm
+#
+# TITLE CpuAsm.asm:
+
+#------------------------------------------------------------------------------
+#*
+#* Copyright 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.
+#*
+#* 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
+
+.intel_syntax
+ASM_GLOBAL ASM_PFX(InitializeExternalVectorTablePtr)
+ASM_PFX(InitializeExternalVectorTablePtr):
+ mov eax, [esp+4]
+ mov ExternalVectorTablePtr, eax
+ ret
+
+#------------------------------------------------------------------------------
+# VOID
+# SetCodeSelector (
+# UINT16 Selector
+# );
+#------------------------------------------------------------------------------
+.intel_syntax
+ASM_GLOBAL ASM_PFX(SetCodeSelector)
+ASM_PFX(SetCodeSelector):
+ 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
+
+#------------------------------------------------------------------------------
+# VOID
+# SetDataSelectors (
+# UINT16 Selector
+# );
+#------------------------------------------------------------------------------
+.intel_syntax
+ASM_GLOBAL ASM_PFX(SetDataSelectors)
+ASM_PFX(SetDataSelectors):
+ mov %ecx, [%esp+4]
+ mov %ss, %cx
+ mov %ds, %cx
+ mov %es, %cx
+ mov %fs, %cx
+ mov %gs, %cx
+ ret
+
+#---------------------------------------;
+# CommonInterruptEntry ;
+#---------------------------------------;
+# The follow algorithm is used for the common interrupt routine.
+
+.intel_syntax
+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.
+ #
+ xchg ecx, [esp]
+ mov cx, [ecx]
+ and ecx, 0x0FFFF
+ cmp ecx, 32 # Intel reserved vector for exceptions?
+ jae NoErrorCode
+ bt ASM_PFX(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]
+
+ #
+ # Fall through to join main routine code
+ # at ErrorCodeAndVectorOnStack
+ #
+CommonInterruptEntry_al_0000:
+ jmp CommonInterruptEntry_al_0000
+
+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, 0x0fffffff0
+ 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, 0x0FFFF
+ mov [esp+4], eax
+
+ sub esp, 8
+ sgdt [esp]
+ mov eax, [esp + 2]
+ xchg eax, [esp]
+ and eax, 0x0FFFF
+ 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, 0x208
+ 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
+#; clear Dr7 while executing debugger itself
+ xor eax, eax
+ mov dr7, eax
+
+ mov eax, dr6
+ push eax
+#; insure all status bits in dr6 are clear...
+ xor eax, eax
+ mov dr6, 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
+ .byte 0x0f, 0x0ae, 0x07 #fxsave [edi]
+
+#; 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
+ .byte 0x0f, 0x0ae, 0x0e # fxrstor [esi]
+ add esp, 512
+
+#; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ pop eax
+ mov dr0, eax
+ pop eax
+ mov dr1, eax
+ pop eax
+ mov dr2, eax
+ pop eax
+ mov dr3, eax
+#; skip restore of dr6. We cleared dr6 during the context save.
+ add esp, 4
+ pop eax
+ mov dr7, eax
+
+#; 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
+
+
+#END
+
--- /dev/null
+ TITLE CpuAsm.asm:\r
+;------------------------------------------------------------------------------\r
+;*\r
+;* Copyright 2006 - 2009, Intel Corporation\r
+;* All rights reserved. This program and the accompanying materials\r
+;* are licensed and made available under the terms and conditions of the BSD License\r
+;* which accompanies this distribution. The full text of the license may be found at\r
+;* http://opensource.org/licenses/bsd-license.php\r
+;*\r
+;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+;*\r
+;* CpuAsm.asm\r
+;*\r
+;* Abstract:\r
+;*\r
+;------------------------------------------------------------------------------\r
+\r
+ .686\r
+ .model flat,C\r
+ .code\r
+\r
+EXTRN mErrorCodeFlag:DWORD ; Error code flags for exceptions\r
+\r
+;\r
+; point to the external interrupt vector table\r
+;\r
+ExternalVectorTablePtr DWORD 0\r
+\r
+InitializeExternalVectorTablePtr PROC PUBLIC\r
+ mov eax, [esp+4]\r
+ mov ExternalVectorTablePtr, eax\r
+ ret\r
+InitializeExternalVectorTablePtr ENDP\r
+\r
+;------------------------------------------------------------------------------\r
+; VOID\r
+; SetCodeSelector (\r
+; UINT16 Selector\r
+; );\r
+;------------------------------------------------------------------------------\r
+SetCodeSelector PROC PUBLIC\r
+ mov ecx, [esp+4]\r
+ sub esp, 0x10\r
+ lea eax, setCodeSelectorLongJump\r
+ mov [esp], eax\r
+ mov [esp+4], cx\r
+ jmp fword ptr [esp]\r
+setCodeSelectorLongJump:\r
+ add esp, 0x10\r
+ ret\r
+SetCodeSelector ENDP\r
+\r
+;------------------------------------------------------------------------------\r
+; VOID\r
+; SetDataSelectors (\r
+; UINT16 Selector\r
+; );\r
+;------------------------------------------------------------------------------\r
+SetDataSelectors PROC PUBLIC\r
+ mov ecx, [esp+4]\r
+ mov ss, cx\r
+ mov ds, cx\r
+ mov es, cx\r
+ mov fs, cx\r
+ mov gs, cx\r
+ ret\r
+SetDataSelectors ENDP\r
+\r
+;---------------------------------------;\r
+; CommonInterruptEntry ;\r
+;---------------------------------------;\r
+; The follow algorithm is used for the common interrupt routine.\r
+\r
+CommonInterruptEntry PROC PUBLIC\r
+ cli\r
+ ;\r
+ ; All interrupt handlers are invoked through interrupt gates, so\r
+ ; IF flag automatically cleared at the entry point\r
+ ;\r
+\r
+ ;\r
+ ; Calculate vector number\r
+ ;\r
+ ; Get the return address of call, actually, it is the\r
+ ; address of vector number.\r
+ ;\r
+ xchg ecx, [esp]\r
+ mov cx, [ecx]\r
+ and ecx, 0FFFFh\r
+ cmp ecx, 32 ; Intel reserved vector for exceptions?\r
+ jae NoErrorCode\r
+ bt mErrorCodeFlag, ecx\r
+ jc HasErrorCode\r
+\r
+NoErrorCode:\r
+\r
+ ;\r
+ ; Stack:\r
+ ; +---------------------+\r
+ ; + EFlags +\r
+ ; +---------------------+\r
+ ; + CS +\r
+ ; +---------------------+\r
+ ; + EIP +\r
+ ; +---------------------+\r
+ ; + ECX +\r
+ ; +---------------------+ <-- ESP\r
+ ;\r
+ ; Registers:\r
+ ; ECX - Vector Number\r
+ ;\r
+\r
+ ;\r
+ ; Put Vector Number on stack\r
+ ;\r
+ push ecx\r
+\r
+ ;\r
+ ; Put 0 (dummy) error code on stack, and restore ECX\r
+ ;\r
+ xor ecx, ecx ; ECX = 0\r
+ xchg ecx, [esp+4]\r
+\r
+ jmp ErrorCodeAndVectorOnStack\r
+\r
+HasErrorCode:\r
+\r
+ ;\r
+ ; Stack:\r
+ ; +---------------------+\r
+ ; + EFlags +\r
+ ; +---------------------+\r
+ ; + CS +\r
+ ; +---------------------+\r
+ ; + EIP +\r
+ ; +---------------------+\r
+ ; + Error Code +\r
+ ; +---------------------+\r
+ ; + ECX +\r
+ ; +---------------------+ <-- ESP\r
+ ;\r
+ ; Registers:\r
+ ; ECX - Vector Number\r
+ ;\r
+\r
+ ;\r
+ ; Put Vector Number on stack and restore ECX\r
+ ;\r
+ xchg ecx, [esp]\r
+\r
+ ;\r
+ ; Fall through to join main routine code\r
+ ; at ErrorCodeAndVectorOnStack\r
+ ;\r
+@@:\r
+ jmp @B\r
+\r
+ErrorCodeAndVectorOnStack:\r
+ push ebp\r
+ mov ebp, esp\r
+\r
+ ;\r
+ ; Stack:\r
+ ; +---------------------+\r
+ ; + EFlags +\r
+ ; +---------------------+\r
+ ; + CS +\r
+ ; +---------------------+\r
+ ; + EIP +\r
+ ; +---------------------+\r
+ ; + Error Code +\r
+ ; +---------------------+\r
+ ; + Vector Number +\r
+ ; +---------------------+\r
+ ; + EBP +\r
+ ; +---------------------+ <-- EBP\r
+ ;\r
+\r
+ ;\r
+ ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32\r
+ ; is 16-byte aligned\r
+ ;\r
+ and esp, 0fffffff0h\r
+ sub esp, 12\r
+\r
+;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;\r
+ push eax\r
+ push ecx\r
+ push edx\r
+ push ebx\r
+ lea ecx, [ebp + 6 * 4]\r
+ push ecx ; ESP\r
+ push dword ptr [ebp] ; EBP\r
+ push esi\r
+ push edi\r
+\r
+;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;\r
+ mov eax, ss\r
+ push eax\r
+ movzx eax, word ptr [ebp + 4 * 4]\r
+ push eax\r
+ mov eax, ds\r
+ push eax\r
+ mov eax, es\r
+ push eax\r
+ mov eax, fs\r
+ push eax\r
+ mov eax, gs\r
+ push eax\r
+\r
+;; UINT32 Eip;\r
+ mov eax, [ebp + 3 * 4]\r
+ push eax\r
+\r
+;; UINT32 Gdtr[2], Idtr[2];\r
+ sub esp, 8\r
+ sidt [esp]\r
+ mov eax, [esp + 2]\r
+ xchg eax, [esp]\r
+ and eax, 0FFFFh\r
+ mov [esp+4], eax\r
+\r
+ sub esp, 8\r
+ sgdt [esp]\r
+ mov eax, [esp + 2]\r
+ xchg eax, [esp]\r
+ and eax, 0FFFFh\r
+ mov [esp+4], eax\r
+\r
+;; UINT32 Ldtr, Tr;\r
+ xor eax, eax\r
+ str ax\r
+ push eax\r
+ sldt ax\r
+ push eax\r
+\r
+;; UINT32 EFlags;\r
+ mov eax, [ebp + 5 * 4]\r
+ push eax\r
+\r
+;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;\r
+ mov eax, cr4\r
+ or eax, 208h\r
+ mov cr4, eax\r
+ push eax\r
+ mov eax, cr3\r
+ push eax\r
+ mov eax, cr2\r
+ push eax\r
+ xor eax, eax\r
+ push eax\r
+ mov eax, cr0\r
+ push eax\r
+\r
+;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;\r
+ mov eax, dr7\r
+ push eax\r
+;; clear Dr7 while executing debugger itself\r
+ xor eax, eax\r
+ mov dr7, eax\r
+\r
+ mov eax, dr6\r
+ push eax\r
+;; insure all status bits in dr6 are clear...\r
+ xor eax, eax\r
+ mov dr6, eax\r
+\r
+ mov eax, dr3\r
+ push eax\r
+ mov eax, dr2\r
+ push eax\r
+ mov eax, dr1\r
+ push eax\r
+ mov eax, dr0\r
+ push eax\r
+\r
+;; FX_SAVE_STATE_IA32 FxSaveState;\r
+ sub esp, 512\r
+ mov edi, esp\r
+ db 0fh, 0aeh, 07h ;fxsave [edi]\r
+\r
+;; UINT32 ExceptionData;\r
+ push dword ptr [ebp + 2 * 4]\r
+\r
+;; call into exception handler\r
+ mov eax, ExternalVectorTablePtr ; get the interrupt vectors base\r
+ or eax, eax ; NULL?\r
+ jz nullExternalExceptionHandler\r
+\r
+ mov ecx, [ebp + 4]\r
+ mov eax, [eax + ecx * 4]\r
+ or eax, eax ; NULL?\r
+ jz nullExternalExceptionHandler\r
+\r
+;; Prepare parameter and call\r
+ mov edx, esp\r
+ push edx\r
+ mov edx, dword ptr [ebp + 1 * 4]\r
+ push edx\r
+\r
+ ;\r
+ ; Call External Exception Handler\r
+ ;\r
+ call eax\r
+ add esp, 8\r
+\r
+nullExternalExceptionHandler:\r
+\r
+ cli\r
+;; UINT32 ExceptionData;\r
+ add esp, 4\r
+\r
+;; FX_SAVE_STATE_IA32 FxSaveState;\r
+ mov esi, esp\r
+ db 0fh, 0aeh, 0eh ; fxrstor [esi]\r
+ add esp, 512\r
+\r
+;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;\r
+ pop eax\r
+ mov dr0, eax\r
+ pop eax\r
+ mov dr1, eax\r
+ pop eax\r
+ mov dr2, eax\r
+ pop eax\r
+ mov dr3, eax\r
+;; skip restore of dr6. We cleared dr6 during the context save.\r
+ add esp, 4\r
+ pop eax\r
+ mov dr7, eax\r
+\r
+;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;\r
+ pop eax\r
+ mov cr0, eax\r
+ add esp, 4 ; not for Cr1\r
+ pop eax\r
+ mov cr2, eax\r
+ pop eax\r
+ mov cr3, eax\r
+ pop eax\r
+ mov cr4, eax\r
+\r
+;; UINT32 EFlags;\r
+ pop dword ptr [ebp + 5 * 4]\r
+\r
+;; UINT32 Ldtr, Tr;\r
+;; UINT32 Gdtr[2], Idtr[2];\r
+;; Best not let anyone mess with these particular registers...\r
+ add esp, 24\r
+\r
+;; UINT32 Eip;\r
+ pop dword ptr [ebp + 3 * 4]\r
+\r
+;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;\r
+;; NOTE - modified segment registers could hang the debugger... We\r
+;; could attempt to insulate ourselves against this possibility,\r
+;; but that poses risks as well.\r
+;;\r
+ pop gs\r
+ pop fs\r
+ pop es\r
+ pop ds\r
+ pop dword ptr [ebp + 4 * 4]\r
+ pop ss\r
+\r
+;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;\r
+ pop edi\r
+ pop esi\r
+ add esp, 4 ; not for ebp\r
+ add esp, 4 ; not for esp\r
+ pop ebx\r
+ pop edx\r
+ pop ecx\r
+ pop eax\r
+\r
+ mov esp, ebp\r
+ pop ebp\r
+ add esp, 8\r
+ iretd\r
+\r
+CommonInterruptEntry ENDP\r
+\r
+END\r
--- /dev/null
+#------------------------------------------------------------------------------
+#
+# 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
+#
+
+.macro SingleIdtVectorMacro vectorNum
+ .intel_syntax
+ call ASM_PFX(CommonInterruptEntry)
+ .short \vectorNum
+ nop
+.endm
+
+.macro EightIdtVectors firstVectorNum
+ SingleIdtVectorMacro \firstVectorNum
+ SingleIdtVectorMacro "(\firstVectorNum+1)"
+ SingleIdtVectorMacro "(\firstVectorNum+2)"
+ SingleIdtVectorMacro "(\firstVectorNum+3)"
+ SingleIdtVectorMacro "(\firstVectorNum+4)"
+ SingleIdtVectorMacro "(\firstVectorNum+5)"
+ SingleIdtVectorMacro "(\firstVectorNum+6)"
+ SingleIdtVectorMacro "(\firstVectorNum+7)"
+.endm
+
+.macro SixtyFourIdtVectors firstVectorNum
+ EightIdtVectors \firstVectorNum
+ EightIdtVectors "(\firstVectorNum+0x08)"
+ EightIdtVectors "(\firstVectorNum+0x10)"
+ EightIdtVectors "(\firstVectorNum+0x18)"
+ EightIdtVectors "(\firstVectorNum+0x20)"
+ EightIdtVectors "(\firstVectorNum+0x28)"
+ EightIdtVectors "(\firstVectorNum+0x30)"
+ EightIdtVectors "(\firstVectorNum+0x38)"
+.endm
+
+ASM_GLOBAL ASM_PFX(AsmIdtVector00)
+.align 8
+ASM_PFX(AsmIdtVector00):
+ SixtyFourIdtVectors 0x00
+ SixtyFourIdtVectors 0x40
+ SixtyFourIdtVectors 0x80
+ SixtyFourIdtVectors 0xC0
+ASM_GLOBAL ASM_PFX(AsmCommonIdtEnd)
+ASM_PFX(AsmCommonIdtEnd):
+ .byte 0
+
+
--- /dev/null
+ TITLE IvtAsm.asm:\r
+;------------------------------------------------------------------------------\r
+;*\r
+;* Copyright 2008 - 2009, Intel Corporation\r
+;* All rights reserved. This program and the accompanying materials\r
+;* are licensed and made available under the terms and conditions of the BSD License\r
+;* which accompanies this distribution. The full text of the license may be found at\r
+;* http://opensource.org/licenses/bsd-license.php\r
+;*\r
+;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+;*\r
+;* IvtAsm.asm\r
+;*\r
+;* Abstract:\r
+;*\r
+;------------------------------------------------------------------------------\r
+\r
+#include <Base.h>\r
+\r
+#ifdef MDE_CPU_IA32\r
+ .686\r
+ .model flat,C\r
+#endif\r
+ .code\r
+\r
+;------------------------------------------------------------------------------\r
+; Generic IDT Vector Handlers for the Host. They are all the same so they\r
+; will compress really well.\r
+;\r
+; By knowing the return address for Vector 00 you can can calculate the\r
+; vector number by looking at the call CommonInterruptEntry return address.\r
+; (return address - (AsmIdtVector00 + 5))/8 == IDT index\r
+;\r
+;------------------------------------------------------------------------------\r
+\r
+EXTRN CommonInterruptEntry:PROC\r
+\r
+ALIGN 8\r
+\r
+PUBLIC AsmIdtVector00\r
+\r
+AsmIdtVector00 LABEL BYTE\r
+REPEAT 256\r
+ call CommonInterruptEntry\r
+ dw ($ - AsmIdtVector00 - 5) / 8 ; vector number\r
+ nop\r
+ENDM\r
+\r
+END\r
+\r
--- /dev/null
+# TITLE CpuAsm.asm:
+
+#------------------------------------------------------------------------------
+#*
+#* Copyright 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.
+#*
+#* 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
+
+.intel_syntax
+ASM_GLOBAL ASM_PFX(InitializeExternalVectorTablePtr)
+ASM_PFX(InitializeExternalVectorTablePtr):
+ lea %rax, [%rip+ExternalVectorTablePtr] # save vector number
+ mov [%rax], %rcx
+ ret
+
+
+#------------------------------------------------------------------------------
+# VOID
+# SetCodeSelector (
+# UINT16 Selector
+# );
+#------------------------------------------------------------------------------
+.intel_syntax
+ASM_GLOBAL ASM_PFX(SetCodeSelector)
+ASM_PFX(SetCodeSelector):
+ sub %rsp, 0x10
+ lea %rax, [%rip+setCodeSelectorLongJump]
+ mov [%rsp], %rax
+ mov [%rsp+4], %cx
+ jmp fword ptr [%rsp]
+setCodeSelectorLongJump:
+ add %rsp, 0x10
+ ret
+
+#------------------------------------------------------------------------------
+# VOID
+# SetDataSelectors (
+# UINT16 Selector
+# );
+#------------------------------------------------------------------------------
+.intel_syntax
+ASM_GLOBAL ASM_PFX(SetDataSelectors)
+ASM_PFX(SetDataSelectors):
+ mov %ss, %cx
+ mov %ds, %cx
+ mov %es, %cx
+ mov %fs, %cx
+ mov %gs, %cx
+ ret
+
+#---------------------------------------;
+# CommonInterruptEntry ;
+#---------------------------------------;
+# The follow algorithm is used for the common interrupt routine.
+
+.intel_syntax
+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
+ #
+ 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
+ push %rax
+ lea %rax, [%rip+ASM_PFX(mErrorCodeFlag)]
+ bt dword ptr [%rax], %ecx
+ pop %rax
+ jc CommonInterruptEntry_al_0000
+
+NoErrorCode:
+
+ #
+ # Push a dummy error code on the stack
+ # to maintain coherent stack map
+ #
+ push [%rsp]
+ mov qword ptr [%rsp + 8], 0
+CommonInterruptEntry_al_0000:
+ 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, 0x208
+ mov %cr4, %rax
+ push %rax
+ mov %rax, %cr3
+ push %rax
+ mov %rax, %cr2
+ push %rax
+ xor %rax, %rax
+ push %rax
+ mov %rax, %cr0
+ push %rax
+
+#; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ mov %rax, %dr7
+ push %rax
+#; clear Dr7 while executing debugger itself
+ xor %rax, %rax
+ mov %dr7, %rax
+
+ mov %rax, %dr6
+ push %rax
+#; insure all status bits in dr6 are clear...
+ xor %rax, %rax
+ mov %dr6, %rax
+
+ mov %rax, %dr3
+ push %rax
+ mov %rax, %dr2
+ push %rax
+ mov %rax, %dr1
+ push %rax
+ mov %rax, %dr0
+ push %rax
+
+#; FX_SAVE_STATE_X64 FxSaveState;
+ sub %rsp, 512
+ mov %rdi, %rsp
+ .byte 0x0f, 0x0ae, 0x07 #fxsave [rdi]
+
+#; UINT32 ExceptionData;
+ push qword ptr [%rbp + 16]
+
+#; call into exception handler
+ mov %rcx, [%rbp + 8]
+ lea %rax, [%rip+ExternalVectorTablePtr]
+ mov %eax, [%eax]
+ 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
+ .byte 0x0f, 0x0ae, 0x0E # fxrstor [rsi]
+ add %rsp, 512
+
+#; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ pop %rax
+ mov %dr0, %rax
+ pop %rax
+ mov %dr1, %rax
+ pop %rax
+ mov %dr2, %rax
+ pop %rax
+ mov %dr3, %rax
+#; skip restore of dr6. We cleared dr6 during the context save.
+ add %rsp, 8
+ pop %rax
+ mov %dr7, %rax
+
+#; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
+ pop %rax
+ mov %cr0, %rax
+ add %rsp, 8 # not for Cr1
+ pop %rax
+ mov %cr2, %rax
+ pop %rax
+ mov %cr3, %rax
+ pop %rax
+ mov %cr4, %rax
+ pop %rax
+ mov %cr8, %rax
+
+#; UINT64 RFlags;
+ pop qword ptr [%rbp + 40]
+
+#; UINT64 Ldtr, Tr;
+#; UINT64 Gdtr[2], Idtr[2];
+#; Best not let anyone mess with these particular registers...
+ add %rsp, 48
+
+#; UINT64 Rip;
+ pop qword ptr [%rbp + 24]
+
+#; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
+ pop %rax
+ # mov gs, rax ; not for gs
+ pop %rax
+ # mov fs, rax ; not for fs
+ # (X64 will not use fs and gs, so we do not restore it)
+ pop %rax
+ mov %es, %rax
+ pop %rax
+ mov %ds, %rax
+ pop qword ptr [%rbp + 32] # for cs
+ pop qword ptr [%rbp + 56] # for ss
+
+#; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
+#; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
+ pop %rdi
+ pop %rsi
+ add %rsp, 8 # not for rbp
+ pop qword ptr [%rbp + 48] # for rsp
+ pop %rbx
+ pop %rdx
+ pop %rcx
+ pop %rax
+ pop %r8
+ pop %r9
+ pop %r10
+ pop %r11
+ pop %r12
+ pop %r13
+ pop %r14
+ pop %r15
+
+ mov %rsp, %rbp
+ pop %rbp
+ add %rsp, 16
+ iretq
+
+
+#text ENDS
+
+#END
+
+
--- /dev/null
+ TITLE CpuAsm.asm: \r
+;------------------------------------------------------------------------------\r
+;*\r
+;* Copyright 2008 - 2009, Intel Corporation \r
+;* All rights reserved. This program and the accompanying materials \r
+;* are licensed and made available under the terms and conditions of the BSD License \r
+;* which accompanies this distribution. The full text of the license may be found at \r
+;* http://opensource.org/licenses/bsd-license.php \r
+;* \r
+;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+;* \r
+;* CpuAsm.asm\r
+;* \r
+;* Abstract:\r
+;*\r
+;------------------------------------------------------------------------------\r
+\r
+ .code\r
+\r
+EXTRN mErrorCodeFlag:DWORD ; Error code flags for exceptions\r
+\r
+;\r
+; point to the external interrupt vector table\r
+;\r
+ExternalVectorTablePtr QWORD 0\r
+\r
+InitializeExternalVectorTablePtr PROC PUBLIC\r
+ mov ExternalVectorTablePtr, rcx\r
+ ret\r
+InitializeExternalVectorTablePtr ENDP\r
+\r
+;------------------------------------------------------------------------------\r
+; VOID\r
+; SetCodeSelector (\r
+; UINT16 Selector\r
+; );\r
+;------------------------------------------------------------------------------\r
+SetCodeSelector PROC PUBLIC\r
+ sub rsp, 0x10\r
+ lea rax, setCodeSelectorLongJump\r
+ mov [rsp], rax\r
+ mov [rsp+4], cx\r
+ jmp fword ptr [rsp]\r
+setCodeSelectorLongJump:\r
+ add rsp, 0x10\r
+ ret\r
+SetCodeSelector ENDP\r
+\r
+;------------------------------------------------------------------------------\r
+; VOID\r
+; SetDataSelectors (\r
+; UINT16 Selector\r
+; );\r
+;------------------------------------------------------------------------------\r
+SetDataSelectors PROC PUBLIC\r
+ mov ss, cx\r
+ mov ds, cx\r
+ mov es, cx\r
+ mov fs, cx\r
+ mov gs, cx\r
+ ret\r
+SetDataSelectors ENDP\r
+\r
+;---------------------------------------;\r
+; CommonInterruptEntry ;\r
+;---------------------------------------;\r
+; The follow algorithm is used for the common interrupt routine.\r
+\r
+CommonInterruptEntry PROC PUBLIC \r
+ cli\r
+ ;\r
+ ; All interrupt handlers are invoked through interrupt gates, so\r
+ ; IF flag automatically cleared at the entry point\r
+ ;\r
+ ;\r
+ ; Calculate vector number\r
+ ;\r
+ xchg rcx, [rsp] ; get the return address of call, actually, it is the address of vector number.\r
+ movzx ecx, word ptr [rcx]\r
+ cmp ecx, 32 ; Intel reserved vector for exceptions?\r
+ jae NoErrorCode\r
+ bt mErrorCodeFlag, ecx\r
+ jc @F\r
+\r
+NoErrorCode:\r
+\r
+ ;\r
+ ; Push a dummy error code on the stack\r
+ ; to maintain coherent stack map\r
+ ;\r
+ push [rsp]\r
+ mov qword ptr [rsp + 8], 0\r
+@@: \r
+ push rbp\r
+ mov rbp, rsp\r
+\r
+ ;\r
+ ; Stack:\r
+ ; +---------------------+ <-- 16-byte aligned ensured by processor\r
+ ; + Old SS +\r
+ ; +---------------------+\r
+ ; + Old RSP +\r
+ ; +---------------------+\r
+ ; + RFlags +\r
+ ; +---------------------+\r
+ ; + CS +\r
+ ; +---------------------+\r
+ ; + RIP +\r
+ ; +---------------------+\r
+ ; + Error Code +\r
+ ; +---------------------+\r
+ ; + RCX / Vector Number +\r
+ ; +---------------------+\r
+ ; + RBP +\r
+ ; +---------------------+ <-- RBP, 16-byte aligned\r
+ ;\r
+\r
+\r
+ ;\r
+ ; Since here the stack pointer is 16-byte aligned, so\r
+ ; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64\r
+ ; is 16-byte aligned\r
+ ;\r
+\r
+;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;\r
+;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;\r
+ push r15\r
+ push r14\r
+ push r13\r
+ push r12\r
+ push r11\r
+ push r10\r
+ push r9\r
+ push r8\r
+ push rax\r
+ push qword ptr [rbp + 8] ; RCX\r
+ push rdx\r
+ push rbx\r
+ push qword ptr [rbp + 48] ; RSP\r
+ push qword ptr [rbp] ; RBP\r
+ push rsi\r
+ push rdi\r
+\r
+;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero\r
+ movzx rax, word ptr [rbp + 56]\r
+ push rax ; for ss\r
+ movzx rax, word ptr [rbp + 32]\r
+ push rax ; for cs\r
+ mov rax, ds\r
+ push rax\r
+ mov rax, es\r
+ push rax\r
+ mov rax, fs\r
+ push rax\r
+ mov rax, gs\r
+ push rax\r
+\r
+ mov [rbp + 8], rcx ; save vector number\r
+\r
+;; UINT64 Rip;\r
+ push qword ptr [rbp + 24]\r
+\r
+;; UINT64 Gdtr[2], Idtr[2];\r
+ xor rax, rax\r
+ push rax\r
+ push rax\r
+ sidt [rsp]\r
+ xchg rax, [rsp + 2]\r
+ xchg rax, [rsp]\r
+ xchg rax, [rsp + 8]\r
+\r
+ xor rax, rax\r
+ push rax\r
+ push rax\r
+ sgdt [rsp]\r
+ xchg rax, [rsp + 2]\r
+ xchg rax, [rsp]\r
+ xchg rax, [rsp + 8]\r
+\r
+;; UINT64 Ldtr, Tr;\r
+ xor rax, rax\r
+ str ax\r
+ push rax\r
+ sldt ax\r
+ push rax\r
+\r
+;; UINT64 RFlags;\r
+ push qword ptr [rbp + 40]\r
+\r
+;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;\r
+ mov rax, cr8\r
+ push rax\r
+ mov rax, cr4\r
+ or rax, 208h\r
+ mov cr4, rax\r
+ push rax\r
+ mov rax, cr3\r
+ push rax\r
+ mov rax, cr2\r
+ push rax\r
+ xor rax, rax\r
+ push rax\r
+ mov rax, cr0\r
+ push rax\r
+\r
+;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;\r
+ mov rax, dr7\r
+ push rax\r
+;; clear Dr7 while executing debugger itself\r
+ xor rax, rax\r
+ mov dr7, rax\r
+\r
+ mov rax, dr6\r
+ push rax\r
+;; insure all status bits in dr6 are clear...\r
+ xor rax, rax\r
+ mov dr6, rax\r
+\r
+ mov rax, dr3\r
+ push rax\r
+ mov rax, dr2\r
+ push rax\r
+ mov rax, dr1\r
+ push rax\r
+ mov rax, dr0\r
+ push rax\r
+\r
+;; FX_SAVE_STATE_X64 FxSaveState;\r
+ sub rsp, 512\r
+ mov rdi, rsp\r
+ db 0fh, 0aeh, 07h ;fxsave [rdi]\r
+\r
+;; UINT32 ExceptionData;\r
+ push qword ptr [rbp + 16]\r
+\r
+;; call into exception handler\r
+ mov rcx, [rbp + 8]\r
+ mov rax, ExternalVectorTablePtr ; get the interrupt vectors base\r
+ mov rax, [rax + rcx * 8] \r
+ or rax, rax ; NULL?\r
+\r
+ je nonNullValue;\r
+\r
+;; Prepare parameter and call\r
+; mov rcx, [rbp + 8]\r
+ mov rdx, rsp\r
+ ;\r
+ ; Per X64 calling convention, allocate maximum parameter stack space\r
+ ; and make sure RSP is 16-byte aligned\r
+ ;\r
+ sub rsp, 4 * 8 + 8\r
+ call rax\r
+ add rsp, 4 * 8 + 8\r
+\r
+nonNullValue:\r
+ cli\r
+;; UINT64 ExceptionData;\r
+ add rsp, 8\r
+\r
+;; FX_SAVE_STATE_X64 FxSaveState;\r
+\r
+ mov rsi, rsp\r
+ db 0fh, 0aeh, 0Eh ; fxrstor [rsi]\r
+ add rsp, 512\r
+\r
+;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;\r
+ pop rax\r
+ mov dr0, rax\r
+ pop rax\r
+ mov dr1, rax\r
+ pop rax\r
+ mov dr2, rax\r
+ pop rax\r
+ mov dr3, rax\r
+;; skip restore of dr6. We cleared dr6 during the context save.\r
+ add rsp, 8\r
+ pop rax\r
+ mov dr7, rax\r
+\r
+;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;\r
+ pop rax\r
+ mov cr0, rax\r
+ add rsp, 8 ; not for Cr1\r
+ pop rax\r
+ mov cr2, rax\r
+ pop rax\r
+ mov cr3, rax\r
+ pop rax\r
+ mov cr4, rax\r
+ pop rax\r
+ mov cr8, rax\r
+\r
+;; UINT64 RFlags;\r
+ pop qword ptr [rbp + 40]\r
+\r
+;; UINT64 Ldtr, Tr;\r
+;; UINT64 Gdtr[2], Idtr[2];\r
+;; Best not let anyone mess with these particular registers...\r
+ add rsp, 48\r
+\r
+;; UINT64 Rip;\r
+ pop qword ptr [rbp + 24]\r
+\r
+;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;\r
+ pop rax\r
+ ; mov gs, rax ; not for gs\r
+ pop rax\r
+ ; mov fs, rax ; not for fs\r
+ ; (X64 will not use fs and gs, so we do not restore it)\r
+ pop rax\r
+ mov es, rax\r
+ pop rax\r
+ mov ds, rax\r
+ pop qword ptr [rbp + 32] ; for cs\r
+ pop qword ptr [rbp + 56] ; for ss\r
+\r
+;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;\r
+;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;\r
+ pop rdi\r
+ pop rsi\r
+ add rsp, 8 ; not for rbp\r
+ pop qword ptr [rbp + 48] ; for rsp\r
+ pop rbx\r
+ pop rdx\r
+ pop rcx\r
+ pop rax\r
+ pop r8\r
+ pop r9\r
+ pop r10\r
+ pop r11\r
+ pop r12\r
+ pop r13\r
+ pop r14\r
+ pop r15\r
+\r
+ mov rsp, rbp\r
+ pop rbp\r
+ add rsp, 16\r
+ iretq\r
+\r
+CommonInterruptEntry ENDP\r
+\r
+END\r
+\r