summaryrefslogtreecommitdiffstats
path: root/DuetPkg/CpuDxe
diff options
context:
space:
mode:
Diffstat (limited to 'DuetPkg/CpuDxe')
-rw-r--r--DuetPkg/CpuDxe/Cpu.c1151
-rw-r--r--DuetPkg/CpuDxe/Cpu.dxs25
-rw-r--r--DuetPkg/CpuDxe/Cpu.inf53
-rw-r--r--DuetPkg/CpuDxe/CpuDxe.h148
-rw-r--r--DuetPkg/CpuDxe/Ia32/CpuInterrupt.asm835
-rw-r--r--DuetPkg/CpuDxe/x64/CpuInterrupt.asm949
6 files changed, 3161 insertions, 0 deletions
diff --git a/DuetPkg/CpuDxe/Cpu.c b/DuetPkg/CpuDxe/Cpu.c
new file mode 100644
index 0000000000..1390a89d57
--- /dev/null
+++ b/DuetPkg/CpuDxe/Cpu.c
@@ -0,0 +1,1151 @@
+/*++
+
+Copyright (c) 2006, 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:
+ Cpu.c
+
+Abstract:
+
+--*/
+
+#include "CpuDxe.h"
+
+//
+// Global Variables
+//
+
+BOOLEAN mInterruptState = FALSE;
+extern UINT32 mExceptionCodeSize;
+UINTN mTimerVector = 0;
+volatile EFI_CPU_INTERRUPT_HANDLER mTimerHandler = NULL;
+EFI_LEGACY_8259_PROTOCOL *gLegacy8259 = NULL;
+
+//
+// The Cpu Architectural Protocol that this Driver produces
+//
+EFI_HANDLE mHandle = NULL;
+EFI_CPU_ARCH_PROTOCOL mCpu = {
+ CpuFlushCpuDataCache,
+ CpuEnableInterrupt,
+ CpuDisableInterrupt,
+ CpuGetInterruptState,
+ CpuInit,
+ CpuRegisterInterruptHandler,
+ CpuGetTimerValue,
+ CpuSetMemoryAttributes,
+ 1, // NumberOfTimers
+ 4, // DmaBufferAlignment
+};
+
+EFI_STATUS
+EFIAPI
+CpuFlushCpuDataCache (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 Length,
+ IN EFI_CPU_FLUSH_TYPE FlushType
+ )
+/*++
+
+Routine Description:
+ Flush CPU data cache. If the instruction cache is fully coherent
+ with all DMA operations then function can just return EFI_SUCCESS.
+
+Arguments:
+ This - Protocol instance structure
+ Start - Physical address to start flushing from.
+ Length - Number of bytes to flush. Round up to chipset
+ granularity.
+ FlushType - Specifies the type of flush operation to perform.
+
+Returns:
+
+ EFI_SUCCESS - If cache was flushed
+ EFI_UNSUPPORTED - If flush type is not supported.
+ EFI_DEVICE_ERROR - If requested range could not be flushed.
+
+--*/
+{
+ if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) {
+ AsmWbinvd ();
+ return EFI_SUCCESS;
+ } else if (FlushType == EfiCpuFlushTypeInvalidate) {
+ AsmInvd ();
+ return EFI_SUCCESS;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+}
+
+
+EFI_STATUS
+EFIAPI
+CpuEnableInterrupt (
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ )
+/*++
+
+Routine Description:
+ Enables CPU interrupts.
+
+Arguments:
+ This - Protocol instance structure
+
+Returns:
+ EFI_SUCCESS - If interrupts were enabled in the CPU
+ EFI_DEVICE_ERROR - If interrupts could not be enabled on the CPU.
+
+--*/
+{
+ EnableInterrupts ();
+
+ mInterruptState = TRUE;
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+CpuDisableInterrupt (
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ )
+/*++
+
+Routine Description:
+ Disables CPU interrupts.
+
+Arguments:
+ This - Protocol instance structure
+
+Returns:
+ EFI_SUCCESS - If interrupts were disabled in the CPU.
+ EFI_DEVICE_ERROR - If interrupts could not be disabled on the CPU.
+
+--*/
+{
+ DisableInterrupts ();
+
+ mInterruptState = FALSE;
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+CpuGetInterruptState (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ OUT BOOLEAN *State
+ )
+/*++
+
+Routine Description:
+ Return the state of interrupts.
+
+Arguments:
+ This - Protocol instance structure
+ State - Pointer to the CPU's current interrupt state
+
+Returns:
+ EFI_SUCCESS - If interrupts were disabled in the CPU.
+ EFI_INVALID_PARAMETER - State is NULL.
+
+--*/
+{
+ if (State == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *State = mInterruptState;
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+CpuInit (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_CPU_INIT_TYPE InitType
+ )
+
+/*++
+
+Routine Description:
+ Generates an INIT to the CPU
+
+Arguments:
+ This - Protocol instance structure
+ InitType - Type of CPU INIT to perform
+
+Returns:
+ EFI_SUCCESS - If CPU INIT occurred. This value should never be
+ seen.
+ EFI_DEVICE_ERROR - If CPU INIT failed.
+ EFI_NOT_SUPPORTED - Requested type of CPU INIT not supported.
+
+--*/
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+EFI_STATUS
+EFIAPI
+CpuRegisterInterruptHandler (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+/*++
+
+Routine Description:
+ Registers a function to be called from the CPU interrupt handler.
+
+Arguments:
+ This - Protocol instance structure
+ InterruptType - Defines which interrupt to hook. IA-32 valid range
+ is 0x00 through 0xFF
+ 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.
+
+Returns:
+ EFI_SUCCESS - If handler installed or uninstalled.
+ EFI_ALREADY_STARTED - InterruptHandler is not NULL, and a handler for
+ InterruptType was previously installed
+ EFI_INVALID_PARAMETER - InterruptHandler is NULL, and a handler for
+ InterruptType was not previously installed.
+ EFI_UNSUPPORTED - The interrupt specified by InterruptType is not
+ supported.
+
+--*/
+{
+ if ((InterruptType < 0) || (InterruptType >= INTERRUPT_VECTOR_NUMBER)) {
+ return EFI_UNSUPPORTED;
+ }
+ if ((UINTN)(UINT32)InterruptType != mTimerVector) {
+ return EFI_UNSUPPORTED;
+ }
+ if ((mTimerHandler == NULL) && (InterruptHandler == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ } else if ((mTimerHandler != NULL) && (InterruptHandler != NULL)) {
+ return EFI_ALREADY_STARTED;
+ }
+ mTimerHandler = InterruptHandler;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+CpuGetTimerValue (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN UINT32 TimerIndex,
+ OUT UINT64 *TimerValue,
+ OUT UINT64 *TimerPeriod OPTIONAL
+ )
+/*++
+
+Routine Description:
+ 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.
+
+Arguments:
+ This - Protocol instance structure
+ TimerIndex - Specifies which CPU timer ie requested
+ TimerValue - Pointer to the returned timer value
+ TimerPeriod -
+
+Returns:
+ EFI_SUCCESS - If the CPU timer count was returned.
+ EFI_UNSUPPORTED - If the CPU does not have any readable timers
+ EFI_DEVICE_ERROR - If an error occurred reading the timer.
+ EFI_INVALID_PARAMETER - TimerIndex is not valid
+
+--*/
+{
+ if (TimerValue == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (TimerIndex == 0) {
+ *TimerValue = AsmReadTsc ();
+ if (TimerPeriod != NULL) {
+ //
+ // BugBug: Hard coded. Don't know how to do this generically
+ //
+ *TimerPeriod = 1000000000;
+ }
+ return EFI_SUCCESS;
+ }
+ return EFI_INVALID_PARAMETER;
+}
+
+EFI_STATUS
+EFIAPI
+CpuSetMemoryAttributes (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ )
+/*++
+
+Routine Description:
+ Set memory cacheability attributes for given range of memeory
+
+Arguments:
+ This - Protocol instance structure
+ BaseAddress - Specifies the start address of the memory range
+ Length - Specifies the length of the memory range
+ Attributes - The memory cacheability for the memory range
+
+Returns:
+ EFI_SUCCESS - If the cacheability of that memory range is set successfully
+ EFI_UNSUPPORTED - If the desired operation cannot be done
+ EFI_INVALID_PARAMETER - The input parameter is not correct, such as Length = 0
+
+--*/
+{
+ return EFI_UNSUPPORTED;
+}
+
+#if CPU_EXCEPTION_DEBUG_OUTPUT
+STATIC
+VOID
+DumpExceptionDataDebugOut (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINT32 ErrorCodeFlag;
+
+ ErrorCodeFlag = 0x00027d00;
+
+#ifdef EFI32
+ DEBUG ((
+ EFI_D_ERROR,
+ "!!!! IA32 Exception Type - %08x !!!!\n",
+ InterruptType
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "EIP - %08x, CS - %08x, EFLAGS - %08x\n",
+ SystemContext.SystemContextIa32->Eip,
+ SystemContext.SystemContextIa32->Cs,
+ SystemContext.SystemContextIa32->Eflags
+ ));
+ if (ErrorCodeFlag & (1 << InterruptType)) {
+ DEBUG ((
+ EFI_D_ERROR,
+ "ExceptionData - %08x\n",
+ SystemContext.SystemContextIa32->ExceptionData
+ ));
+ }
+ DEBUG ((
+ EFI_D_ERROR,
+ "EAX - %08x, ECX - %08x, EDX - %08x, EBX - %08x\n",
+ SystemContext.SystemContextIa32->Eax,
+ SystemContext.SystemContextIa32->Ecx,
+ SystemContext.SystemContextIa32->Edx,
+ SystemContext.SystemContextIa32->Ebx
+ ));
+ 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,
+ "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
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "GDTR - %08x %08x, IDTR - %08x %08x\n",
+ SystemContext.SystemContextIa32->Gdtr[0],
+ SystemContext.SystemContextIa32->Gdtr[1],
+ SystemContext.SystemContextIa32->Idtr[0],
+ SystemContext.SystemContextIa32->Idtr[1]
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "LDTR - %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
+ ));
+#else
+ DEBUG ((
+ EFI_D_ERROR,
+ "!!!! X64 Exception Type - %016lx !!!!\n",
+ (UINT64)InterruptType
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "RIP - %016lx, CS - %016lx, RFLAGS - %016lx\n",
+ SystemContext.SystemContextX64->Rip,
+ SystemContext.SystemContextX64->Cs,
+ SystemContext.SystemContextX64->Rflags
+ ));
+ if (ErrorCodeFlag & (1 << InterruptType)) {
+ DEBUG ((
+ EFI_D_ERROR,
+ "ExceptionData - %016lx\n",
+ SystemContext.SystemContextX64->ExceptionData
+ ));
+ }
+ DEBUG ((
+ EFI_D_ERROR,
+ "RAX - %016lx, RCX - %016lx, RDX - %016lx\n",
+ SystemContext.SystemContextX64->Rax,
+ SystemContext.SystemContextX64->Rcx,
+ SystemContext.SystemContextX64->Rdx
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "RBX - %016lx, RSP - %016lx, RBP - %016lx\n",
+ SystemContext.SystemContextX64->Rbx,
+ SystemContext.SystemContextX64->Rsp,
+ SystemContext.SystemContextX64->Rbp
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "RSI - %016lx, RDI - %016lx\n",
+ SystemContext.SystemContextX64->Rsi,
+ SystemContext.SystemContextX64->Rdi
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "R8 - %016lx, R9 - %016lx, R10 - %016lx\n",
+ SystemContext.SystemContextX64->R8,
+ SystemContext.SystemContextX64->R9,
+ SystemContext.SystemContextX64->R10
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "R11 - %016lx, R12 - %016lx, R13 - %016lx\n",
+ SystemContext.SystemContextX64->R11,
+ SystemContext.SystemContextX64->R12,
+ SystemContext.SystemContextX64->R13
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "R14 - %016lx, R15 - %016lx\n",
+ SystemContext.SystemContextX64->R14,
+ SystemContext.SystemContextX64->R15
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "DS - %016lx, ES - %016lx, FS - %016lx\n",
+ SystemContext.SystemContextX64->Ds,
+ SystemContext.SystemContextX64->Es,
+ SystemContext.SystemContextX64->Fs
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "GS - %016lx, SS - %016lx\n",
+ SystemContext.SystemContextX64->Gs,
+ SystemContext.SystemContextX64->Ss
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "GDTR - %016lx %016lx, LDTR - %016lx\n",
+ SystemContext.SystemContextX64->Gdtr[0],
+ SystemContext.SystemContextX64->Gdtr[1],
+ SystemContext.SystemContextX64->Ldtr
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "IDTR - %016lx %016lx, TR - %016lx\n",
+ SystemContext.SystemContextX64->Idtr[0],
+ SystemContext.SystemContextX64->Idtr[1],
+ SystemContext.SystemContextX64->Tr
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "CR0 - %016lx, CR2 - %016lx, CR3 - %016lx\n",
+ SystemContext.SystemContextX64->Cr0,
+ SystemContext.SystemContextX64->Cr2,
+ SystemContext.SystemContextX64->Cr3
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "CR4 - %016lx, CR8 - %016lx\n",
+ SystemContext.SystemContextX64->Cr4,
+ SystemContext.SystemContextX64->Cr8
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "DR0 - %016lx, DR1 - %016lx, DR2 - %016lx\n",
+ SystemContext.SystemContextX64->Dr0,
+ SystemContext.SystemContextX64->Dr1,
+ SystemContext.SystemContextX64->Dr2
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "DR3 - %016lx, DR6 - %016lx, DR7 - %016lx\n",
+ SystemContext.SystemContextX64->Dr3,
+ SystemContext.SystemContextX64->Dr6,
+ SystemContext.SystemContextX64->Dr7
+ ));
+#endif
+ return ;
+}
+#endif
+
+STATIC
+UINTN
+SPrint (
+ IN OUT CHAR16 *Buffer,
+ IN CONST CHAR16 *Format,
+ ...
+ )
+{
+ VA_LIST Marker;
+ UINTN Index;
+ UINTN Flags;
+ UINTN Width;
+ UINT64 Value;
+
+ VA_START (Marker, Format);
+
+ //
+ // Process the format string. Stop if Buffer is over run.
+ //
+
+ for (Index = 0; *Format != 0; Format++) {
+ if (*Format != L'%') {
+ Buffer[Index++] = *Format;
+ } else {
+
+ //
+ // Now it's time to parse what follows after %
+ // Support: % [ 0 width ] [ l ] x
+ // width - fill 0, to ensure the width of x will be "width"
+ // l - UINT64 instead of UINT32
+ //
+ Width = 0;
+ Flags = 0;
+ Format ++;
+
+ if (*Format == L'0') {
+ Flags |= PREFIX_ZERO;
+ do {
+ Width += Width * 10 + (*Format - L'0');
+ Format ++;
+ } while (*Format >= L'1' && *Format <= L'9');
+ }
+
+ if (*Format == L'l') {
+ Flags |= LONG_TYPE;
+ Format ++;
+ }
+
+
+ switch (*Format) {
+ case 'X':
+ Flags |= PREFIX_ZERO;
+ Width = sizeof (UINT64) * 2;
+ //
+ // break skiped on purpose
+ //
+ case 'x':
+ if ((Flags & LONG_TYPE) == LONG_TYPE) {
+ Value = VA_ARG (Marker, UINT64);
+ } else {
+ Value = VA_ARG (Marker, UINTN);
+ }
+
+ UnicodeValueToString (Buffer+Index, Flags, Value, Width);
+
+ for ( ; Buffer[Index] != L'\0'; Index ++) {
+ }
+
+ break;
+
+ default:
+ //
+ // if the type is unknown print it to the screen
+ //
+ Buffer[Index++] = *Format;
+ }
+ }
+ }
+ Buffer[Index++] = '\0';
+
+ VA_END (Marker);
+ return Index;
+}
+
+STATIC
+VOID
+DumpExceptionDataVgaOut (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN COLUMN_MAX;
+ UINTN ROW_MAX;
+ UINT32 ErrorCodeFlag;
+ CHAR16 *VideoBufferBase;
+ CHAR16 *VideoBuffer;
+ UINTN Index;
+
+ COLUMN_MAX = 80;
+ ROW_MAX = 25;
+ ErrorCodeFlag = 0x00027d00;
+ VideoBufferBase = (CHAR16 *) (UINTN) 0xb8000;
+ VideoBuffer = (CHAR16 *) (UINTN) 0xb8000;
+
+#ifdef EFI32
+ SPrint (
+ VideoBuffer,
+ L"!!!! IA32 Exception Type - %08x !!!!",
+ InterruptType
+ );
+ VideoBuffer += COLUMN_MAX;
+ SPrint (
+ VideoBuffer,
+ L"EIP - %08x, CS - %08x, EFLAGS - %08x",
+ SystemContext.SystemContextIa32->Eip,
+ SystemContext.SystemContextIa32->Cs,
+ SystemContext.SystemContextIa32->Eflags
+ );
+ VideoBuffer += COLUMN_MAX;
+ if (ErrorCodeFlag & (1 << InterruptType)) {
+ SPrint (
+ VideoBuffer,
+ L"ExceptionData - %08x",
+ SystemContext.SystemContextIa32->ExceptionData
+ );
+ VideoBuffer += COLUMN_MAX;
+ }
+ SPrint (
+ VideoBuffer,
+ L"EAX - %08x, ECX - %08x, EDX - %08x, EBX - %08x",
+ SystemContext.SystemContextIa32->Eax,
+ SystemContext.SystemContextIa32->Ecx,
+ SystemContext.SystemContextIa32->Edx,
+ SystemContext.SystemContextIa32->Ebx
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ SPrint (
+ VideoBuffer,
+ L"ESP - %08x, EBP - %08x, ESI - %08x, EDI - %08x",
+ SystemContext.SystemContextIa32->Esp,
+ SystemContext.SystemContextIa32->Ebp,
+ SystemContext.SystemContextIa32->Esi,
+ SystemContext.SystemContextIa32->Edi
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ SPrint (
+ VideoBuffer,
+ L"DS - %08x, ES - %08x, FS - %08x, GS - %08x, SS - %08x",
+ SystemContext.SystemContextIa32->Ds,
+ SystemContext.SystemContextIa32->Es,
+ SystemContext.SystemContextIa32->Fs,
+ SystemContext.SystemContextIa32->Gs,
+ SystemContext.SystemContextIa32->Ss
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ SPrint (
+ VideoBuffer,
+ L"GDTR - %08x %08x, IDTR - %08x %08x",
+ SystemContext.SystemContextIa32->Gdtr[0],
+ SystemContext.SystemContextIa32->Gdtr[1],
+ SystemContext.SystemContextIa32->Idtr[0],
+ SystemContext.SystemContextIa32->Idtr[1]
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ SPrint (
+ VideoBuffer,
+ L"LDTR - %08x, TR - %08x",
+ SystemContext.SystemContextIa32->Ldtr,
+ SystemContext.SystemContextIa32->Tr
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ SPrint (
+ VideoBuffer,
+ L"CR0 - %08x, CR2 - %08x, CR3 - %08x, CR4 - %08x",
+ SystemContext.SystemContextIa32->Cr0,
+ SystemContext.SystemContextIa32->Cr2,
+ SystemContext.SystemContextIa32->Cr3,
+ SystemContext.SystemContextIa32->Cr4
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ SPrint (
+ VideoBuffer,
+ L"DR0 - %08x, DR1 - %08x, DR2 - %08x, DR3 - %08x",
+ SystemContext.SystemContextIa32->Dr0,
+ SystemContext.SystemContextIa32->Dr1,
+ SystemContext.SystemContextIa32->Dr2,
+ SystemContext.SystemContextIa32->Dr3
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ SPrint (
+ VideoBuffer,
+ L"DR6 - %08x, DR7 - %08x",
+ SystemContext.SystemContextIa32->Dr6,
+ SystemContext.SystemContextIa32->Dr7
+ );
+ VideoBuffer += COLUMN_MAX;
+#else
+ SPrint (
+ VideoBuffer,
+ L"!!!! X64 Exception Type - %016lx !!!!",
+ (UINT64)InterruptType
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ SPrint (
+ VideoBuffer,
+ L"RIP - %016lx, CS - %016lx, RFLAGS - %016lx",
+ SystemContext.SystemContextX64->Rip,
+ SystemContext.SystemContextX64->Cs,
+ SystemContext.SystemContextX64->Rflags
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ if (ErrorCodeFlag & (1 << InterruptType)) {
+ SPrint (
+ VideoBuffer,
+ L"ExceptionData - %016lx",
+ SystemContext.SystemContextX64->ExceptionData
+ );
+ VideoBuffer += COLUMN_MAX;
+ }
+
+ SPrint (
+ VideoBuffer,
+ L"RAX - %016lx, RCX - %016lx, RDX - %016lx",
+ SystemContext.SystemContextX64->Rax,
+ SystemContext.SystemContextX64->Rcx,
+ SystemContext.SystemContextX64->Rdx
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ SPrint (
+ VideoBuffer,
+ L"RBX - %016lx, RSP - %016lx, RBP - %016lx",
+ SystemContext.SystemContextX64->Rbx,
+ SystemContext.SystemContextX64->Rsp,
+ SystemContext.SystemContextX64->Rbp
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ SPrint (
+ VideoBuffer,
+ L"RSI - %016lx, RDI - %016lx",
+ SystemContext.SystemContextX64->Rsi,
+ SystemContext.SystemContextX64->Rdi
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ SPrint (
+ VideoBuffer,
+ L"R8 - %016lx, R9 - %016lx, R10 - %016lx",
+ SystemContext.SystemContextX64->R8,
+ SystemContext.SystemContextX64->R9,
+ SystemContext.SystemContextX64->R10
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ SPrint (
+ VideoBuffer,
+ L"R11 - %016lx, R12 - %016lx, R13 - %016lx",
+ SystemContext.SystemContextX64->R11,
+ SystemContext.SystemContextX64->R12,
+ SystemContext.SystemContextX64->R13
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ SPrint (
+ VideoBuffer,
+ L"R14 - %016lx, R15 - %016lx",
+ SystemContext.SystemContextX64->R14,
+ SystemContext.SystemContextX64->R15
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ SPrint (
+ VideoBuffer,
+ L"DS - %016lx, ES - %016lx, FS - %016lx",
+ SystemContext.SystemContextX64->Ds,
+ SystemContext.SystemContextX64->Es,
+ SystemContext.SystemContextX64->Fs
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ SPrint (
+ VideoBuffer,
+ L"GS - %016lx, SS - %016lx",
+ SystemContext.SystemContextX64->Gs,
+ SystemContext.SystemContextX64->Ss
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ SPrint (
+ VideoBuffer,
+ L"GDTR - %016lx %016lx, LDTR - %016lx",
+ SystemContext.SystemContextX64->Gdtr[0],
+ SystemContext.SystemContextX64->Gdtr[1],
+ SystemContext.SystemContextX64->Ldtr
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ SPrint (
+ VideoBuffer,
+ L"IDTR - %016lx %016lx, TR - %016lx",
+ SystemContext.SystemContextX64->Idtr[0],
+ SystemContext.SystemContextX64->Idtr[1],
+ SystemContext.SystemContextX64->Tr
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ SPrint (
+ VideoBuffer,
+ L"CR0 - %016lx, CR2 - %016lx, CR3 - %016lx",
+ SystemContext.SystemContextX64->Cr0,
+ SystemContext.SystemContextX64->Cr2,
+ SystemContext.SystemContextX64->Cr3
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ SPrint (
+ VideoBuffer,
+ L"CR4 - %016lx, CR8 - %016lx",
+ SystemContext.SystemContextX64->Cr4,
+ SystemContext.SystemContextX64->Cr8
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ SPrint (
+ VideoBuffer,
+ L"DR0 - %016lx, DR1 - %016lx, DR2 - %016lx",
+ SystemContext.SystemContextX64->Dr0,
+ SystemContext.SystemContextX64->Dr1,
+ SystemContext.SystemContextX64->Dr2
+ );
+ VideoBuffer += COLUMN_MAX;
+
+ SPrint (
+ VideoBuffer,
+ L"DR3 - %016lx, DR6 - %016lx, DR7 - %016lx",
+ SystemContext.SystemContextX64->Dr3,
+ SystemContext.SystemContextX64->Dr6,
+ SystemContext.SystemContextX64->Dr7
+ );
+ VideoBuffer += COLUMN_MAX;
+#endif
+
+ for (Index = 0; Index < COLUMN_MAX * ROW_MAX; Index ++) {
+ if (Index > (UINTN)(VideoBuffer - VideoBufferBase)) {
+ VideoBufferBase[Index] = 0x0c20;
+ } else {
+ VideoBufferBase[Index] |= 0x0c00;
+ }
+ }
+
+ return ;
+}
+
+#if CPU_EXCEPTION_VGA_SWITCH
+STATIC
+UINT16
+SwitchVideoMode (
+ UINT16 NewVideoMode
+ )
+/*++
+Description
+ Switch Video Mode from current mode to new mode, and return the old mode.
+ Use Thuink
+
+Arguments
+ NewVideoMode - new video mode want to set
+
+Return
+ UINT16 - (UINT16) -1 indicates failure
+ Other value indicates the old mode, which can be used for restore later
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_THUNK_PROTOCOL *LegacyBios;
+ EFI_IA32_REGISTER_SET Regs;
+ UINT16 OriginalVideoMode = (UINT16) -1;
+
+ //
+ // See if the Legacy BIOS Protocol is available
+ //
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosThunkProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return OriginalVideoMode;
+ }
+
+ //
+ // VESA SuperVGA BIOS - GET CURRENT VIDEO MODE
+ // AX = 4F03h
+ // Return:AL = 4Fh if function supported
+ // AH = status 00h successful
+ // BX = video mode (see #0082,#0083)
+ //
+ gBS->SetMem (&Regs, sizeof (Regs), 0);
+ Regs.X.AX = 0x4F03;
+ LegacyBios->Int86 (LegacyBios, 0x10, &Regs);
+ if (Regs.X.AX == 0x004F) {
+ OriginalVideoMode = Regs.X.BX;
+ } else {
+ //
+ // VIDEO - GET CURRENT VIDEO MODE
+ // AH = 0Fh
+ // Return:AH = number of character columns
+ // AL = display mode (see #0009 at AH=00h)
+ // BH = active page (see AH=05h)
+ //
+ gBS->SetMem (&Regs, sizeof (Regs), 0);
+ Regs.H.AH = 0x0F;
+ LegacyBios->Int86 (LegacyBios, 0x10, &Regs);
+ OriginalVideoMode = Regs.H.AL;
+ }
+
+ //
+ // Set new video mode
+ //
+ if (NewVideoMode < 0x100) {
+ //
+ // Set the 80x25 Text VGA Mode: Assume successful always
+ //
+ // VIDEO - SET VIDEO MODE
+ // AH = 00h
+ // AL = desired video mode (see #0009)
+ // Return:AL = video mode flag (Phoenix, AMI BIOS)
+ // 20h mode > 7
+ // 30h modes 0-5 and 7
+ // 3Fh mode 6
+ // AL = CRT controller mode byte (Phoenix 386 BIOS v1.10)
+ //
+ gBS->SetMem (&Regs, sizeof (Regs), 0);
+ Regs.H.AH = 0x00;
+ Regs.H.AL = (UINT8) NewVideoMode;
+ LegacyBios->Int86 (LegacyBios, 0x10, &Regs);
+
+ //
+ // VIDEO - TEXT-MODE CHARGEN - LOAD ROM 8x16 CHARACTER SET (VGA)
+ // AX = 1114h
+ // BL = block to load
+ // Return:Nothing
+ //
+ gBS->SetMem (&Regs, sizeof (Regs), 0);
+ Regs.H.AH = 0x11;
+ Regs.H.AL = 0x14;
+ Regs.H.BL = 0;
+ LegacyBios->Int86 (LegacyBios, 0x10, &Regs);
+ } else {
+ //
+ // VESA SuperVGA BIOS - SET SuperVGA VIDEO MODE
+ // AX = 4F02h
+ // BX = mode (see #0082,#0083)
+ // bit 15 set means don't clear video memory
+ // bit 14 set means enable linear framebuffer mode (VBE v2.0+)
+ // Return:AL = 4Fh if function supported
+ // AH = status
+ // 00h successful
+ // 01h failed
+ //
+ gBS->SetMem (&Regs, sizeof (Regs), 0);
+ Regs.X.AX = 0x4F02;
+ Regs.X.BX = NewVideoMode;
+ LegacyBios->Int86 (LegacyBios, 0x10, &Regs);
+ if (Regs.X.AX != 0x004F) {
+ DEBUG ((EFI_D_ERROR, "SORRY: Cannot set to video mode: 0x%04X!\n", NewVideoMode));
+ return (UINT16) -1;
+ }
+ }
+
+ return OriginalVideoMode;
+}
+#endif
+
+VOID
+ExceptionHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+#if CPU_EXCEPTION_VGA_SWITCH
+ UINT16 VideoMode;
+#endif
+
+#if CPU_EXCEPTION_DEBUG_OUTPUT
+ DumpExceptionDataDebugOut (InterruptType, SystemContext);
+#endif
+
+#if CPU_EXCEPTION_VGA_SWITCH
+ //
+ // Switch to text mode for RED-SCREEN output
+ //
+ VideoMode = SwitchVideoMode (0x83);
+ if (VideoMode == (UINT16) -1) {
+ DEBUG ((EFI_D_ERROR, "Video Mode Unknown!\n"));
+ }
+#endif
+
+ DumpExceptionDataVgaOut (InterruptType, SystemContext);
+
+ //
+ // Use this macro to hang so that the compiler does not optimize out
+ // the following RET instructions. This allows us to return if we
+ // have a debugger attached.
+ //
+ CpuDeadLoop ();
+
+#if CPU_EXCEPTION_VGA_SWITCH
+ //
+ // Switch back to the old video mode
+ //
+ if (VideoMode != (UINT16)-1) {
+ SwitchVideoMode (VideoMode);
+ }
+#endif
+
+ return ;
+}
+
+VOID
+TimerHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ if (mTimerHandler != NULL) {
+ mTimerHandler (InterruptType, SystemContext);
+ }
+}
+
+EFI_STATUS
+EFIAPI
+InitializeCpu (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+/*++
+
+Routine Description:
+ Initialize the state information for the CPU Architectural Protocol
+
+Arguments:
+ ImageHandle of the loaded driver
+ Pointer to the System Table
+
+Returns:
+ EFI_SUCCESS - thread can be successfully created
+ EFI_OUT_OF_RESOURCES - cannot allocate protocol data structure
+ EFI_DEVICE_ERROR - cannot create the thread
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_8259_IRQ Irq;
+ UINT32 InterruptVector;
+
+ //
+ // Find the Legacy8259 protocol.
+ //
+ Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &gLegacy8259);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Get the interrupt vector number corresponding to IRQ0 from the 8259 driver
+ //
+ Status = gLegacy8259->GetVector (gLegacy8259, Efi8259Irq0, (UINT8 *) &mTimerVector);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Reload GDT, IDT
+ //
+ InitDescriptor ();
+
+ //
+ // Install Exception Handler (0x00 ~ 0x1F)
+ //
+ for (InterruptVector = 0; InterruptVector < 0x20; InterruptVector++) {
+ InstallInterruptHandler (
+ InterruptVector,
+ (VOID (*)(VOID))(UINTN)((UINTN)SystemExceptionHandler + mExceptionCodeSize * InterruptVector)
+ );
+ }
+
+ //
+ // Install Timer Handler
+ //
+ InstallInterruptHandler (mTimerVector, SystemTimerHandler);
+
+ //
+ // BUGBUG: We add all other interrupt vector
+ //
+ for (Irq = Efi8259Irq1; Irq <= Efi8259Irq15; Irq++) {
+ InterruptVector = 0;
+ Status = gLegacy8259->GetVector (gLegacy8259, Irq, (UINT8 *) &InterruptVector);
+ ASSERT_EFI_ERROR (Status);
+ InstallInterruptHandler (InterruptVector, SystemTimerHandler);
+ }
+
+ //
+ // Install CPU Architectural Protocol and the thunk protocol
+ //
+ mHandle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEfiCpuArchProtocolGuid,
+ &mCpu,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/DuetPkg/CpuDxe/Cpu.dxs b/DuetPkg/CpuDxe/Cpu.dxs
new file mode 100644
index 0000000000..b07f51b159
--- /dev/null
+++ b/DuetPkg/CpuDxe/Cpu.dxs
@@ -0,0 +1,25 @@
+/*++
+
+Copyright (c) 2006, 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:
+ Cpu.dxs
+
+Abstract:
+ Dependency expression source file.
+
+--*/
+
+#include "EfiDepex.h"
+#include EFI_PROTOCOL_DEFINITION (Legacy8259)
+
+DEPENDENCY_START
+ EFI_LEGACY_8259_PROTOCOL_GUID
+DEPENDENCY_END
diff --git a/DuetPkg/CpuDxe/Cpu.inf b/DuetPkg/CpuDxe/Cpu.inf
new file mode 100644
index 0000000000..8483aca65a
--- /dev/null
+++ b/DuetPkg/CpuDxe/Cpu.inf
@@ -0,0 +1,53 @@
+#/*++
+#
+# Copyright (c) 2006, 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:
+# Cpu.inf
+#
+# Abstract:
+#
+#--*/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Cpu
+ FILE_GUID = 10527025-78B2-4d3e-A9DF-41E75C220F5A
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+
+ ENTRY_POINT = InitializeCpu
+
+[Packages]
+ DuetPkg/DuetPkg.dec
+ MdePkg/MdePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ PrintLib
+ UefiBootServicesTableLib
+
+[Sources.IA32]
+ IA32/CpuInterrupt.asm
+
+[Sources.X64]
+ X64/CpuInterrupt.asm
+
+[Sources.common]
+ Cpu.c
+ CpuDxe.h
+
+[Protocols]
+ gEfiCpuArchProtocolGuid
+ gEfiLegacyBiosThunkProtocolGuid
+ gEfiLegacy8259ProtocolGuid
diff --git a/DuetPkg/CpuDxe/CpuDxe.h b/DuetPkg/CpuDxe/CpuDxe.h
new file mode 100644
index 0000000000..5bca0ca10c
--- /dev/null
+++ b/DuetPkg/CpuDxe/CpuDxe.h
@@ -0,0 +1,148 @@
+/*++
+
+Copyright (c) 2006, 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:
+ CpuDxe.h
+
+Abstract:
+
+--*/
+#ifndef _CPU_DXE_H
+#define _CPU_DXE_H
+
+#include <PiDxe.h>
+
+#include <Protocol/Cpu.h>
+#include <Protocol/Legacy8259.h>
+
+#include <Protocol/LegacyBios.h>
+#include <Protocol/LegacyBiosThunk.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#define CPU_EXCEPTION_DEBUG_OUTPUT 1
+#define CPU_EXCEPTION_VGA_SWITCH 1
+
+#define INTERRUPT_VECTOR_NUMBER 0x100
+
+//
+// Print primitives
+//
+//#define LEFT_JUSTIFY 0x01
+#define PREFIX_SIGN 0x02
+#define PREFIX_BLANK 0x04
+//#define COMMA_TYPE 0x08
+#define LONG_TYPE 0x10
+//#define PREFIX_ZERO 0x20
+#define OUTPUT_UNICODE 0x40
+//#define RADIX_HEX 0x80
+#define FORMAT_UNICODE 0x100
+#define PAD_TO_WIDTH 0x200
+#define ARGUMENT_UNICODE 0x400
+#define PRECISION 0x800
+#define ARGUMENT_REVERSED 0x1000
+
+//
+// Function declarations
+//
+EFI_STATUS
+EFIAPI
+InitializeCpu (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+EFI_STATUS
+EFIAPI
+CpuFlushCpuDataCache (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 Length,
+ IN EFI_CPU_FLUSH_TYPE FlushType
+ );
+
+EFI_STATUS
+EFIAPI
+CpuEnableInterrupt (
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ );
+
+EFI_STATUS
+EFIAPI
+CpuDisableInterrupt (
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ );
+
+EFI_STATUS
+EFIAPI
+CpuGetInterruptState (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ OUT BOOLEAN *State
+ );
+
+EFI_STATUS
+EFIAPI
+CpuInit (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_CPU_INIT_TYPE InitType
+ );
+
+EFI_STATUS
+EFIAPI
+CpuRegisterInterruptHandler (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ );
+
+EFI_STATUS
+EFIAPI
+CpuGetTimerValue (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN UINT32 TimerIndex,
+ OUT UINT64 *TimerValue,
+ OUT UINT64 *TimerPeriod OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+CpuSetMemoryAttributes(
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ );
+
+VOID
+InstallInterruptHandler (
+ UINTN Vector,
+ VOID (*Handler)(VOID)
+ );
+
+VOID
+SystemExceptionHandler (
+ VOID
+ );
+
+VOID
+SystemTimerHandler (
+ VOID
+ );
+
+VOID
+InitDescriptor (
+ VOID
+ );
+
+#endif
diff --git a/DuetPkg/CpuDxe/Ia32/CpuInterrupt.asm b/DuetPkg/CpuDxe/Ia32/CpuInterrupt.asm
new file mode 100644
index 0000000000..cc1402cd9b
--- /dev/null
+++ b/DuetPkg/CpuDxe/Ia32/CpuInterrupt.asm
@@ -0,0 +1,835 @@
+ TITLE CpuInterrupt.asm:
+;------------------------------------------------------------------------------
+;*
+;* Copyright 2006, 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.
+;*
+;* CpuInterrupt.asm
+;*
+;* Abstract:
+;*
+;------------------------------------------------------------------------------
+
+.686p
+.model flat, C
+
+PUBLIC SystemTimerHandler
+PUBLIC SystemExceptionHandler
+EXTERNDEF mExceptionCodeSize:DWORD
+
+.code
+.stack
+.MMX
+.XMM
+
+EXTERN TimerHandler: NEAR
+EXTERN ExceptionHandler: NEAR
+EXTERN mTimerVector: DWORD
+
+mExceptionCodeSize DD 9
+
+InitDescriptor PROC C
+ lea eax, [GDT_BASE] ; EAX=PHYSICAL address of gdt
+ mov dword ptr [gdtr + 2],eax ; Put address of gdt into the gdtr
+ lgdt fword ptr [gdtr]
+ lea eax, [IDT_BASE] ; EAX=PHYSICAL address of idt
+ mov dword ptr [idtr + 2],eax ; Put address of idt into the idtr
+ lidt fword ptr [idtr]
+ ret
+InitDescriptor ENDP
+
+; VOID
+; InstallInterruptHandler (
+; UINTN Vector,
+; VOID (*Handler)(VOID)
+; )
+InstallInterruptHandler PROC C \
+ Vector:DWORD, \
+ Handler:DWORD
+
+ push edi
+ pushfd ; save eflags
+ cli ; turn off interrupts
+ sub esp, 6 ; open some space on the stack
+ mov edi, esp
+ sidt es:[edi] ; get fword address of IDT
+ mov edi, es:[edi+2] ; move offset of IDT into EDI
+ add esp, 6 ; correct stack
+ mov eax, Vector ; Get vector number
+ shl eax, 3 ; multiply by 8 to get offset
+ add edi, eax ; add to IDT base to get entry
+ mov eax, Handler ; load new address into IDT entry
+ mov word ptr es:[edi], ax ; write bits 15..0 of offset
+ shr eax, 16 ; use ax to copy 31..16 to descriptors
+ mov word ptr es:[edi+6], ax ; write bits 31..16 of offset
+ popfd ; restore flags (possible enabling interrupts)
+ pop edi
+ ret
+
+InstallInterruptHandler ENDP
+
+JmpCommonIdtEntry macro
+ ; jmp commonIdtEntry - this must be hand coded to keep the assembler from
+ ; using a 8 bit reletive jump when the entries are
+ ; within 255 bytes of the common entry. This must
+ ; be done to maintain the consistency of the size
+ ; of entry points...
+ db 0e9h ; jmp 16 bit reletive
+ dd commonIdtEntry - $ - 4 ; offset to jump to
+endm
+
+ align 02h
+SystemExceptionHandler PROC
+INT0:
+ push 0h ; push error code place holder on the stack
+ push 0h
+ JmpCommonIdtEntry
+; db 0e9h ; jmp 16 bit reletive
+; dd commonIdtEntry - $ - 4 ; offset to jump to
+
+INT1:
+ push 0h ; push error code place holder on the stack
+ push 1h
+ JmpCommonIdtEntry
+
+INT2:
+ push 0h ; push error code place holder on the stack
+ push 2h
+ JmpCommonIdtEntry
+
+INT3:
+ push 0h ; push error code place holder on the stack
+ push 3h
+ JmpCommonIdtEntry
+
+INT4:
+ push 0h ; push error code place holder on the stack
+ push 4h
+ JmpCommonIdtEntry
+
+INT5:
+ push 0h ; push error code place holder on the stack
+ push 5h
+ JmpCommonIdtEntry
+
+INT6:
+ push 0h ; push error code place holder on the stack
+ push 6h
+ JmpCommonIdtEntry
+
+INT7:
+ push 0h ; push error code place holder on the stack
+ push 7h
+ JmpCommonIdtEntry
+
+INT8:
+; Double fault causes an error code to be pushed so no phony push necessary
+ nop
+ nop
+ push 8h
+ JmpCommonIdtEntry
+
+INT9:
+ push 0h ; push error code place holder on the stack
+ push 9h
+ JmpCommonIdtEntry
+
+INT10:
+; Invalid TSS causes an error code to be pushed so no phony push necessary
+ nop
+ nop
+ push 10
+ JmpCommonIdtEntry
+
+INT11:
+; Segment Not Present causes an error code to be pushed so no phony push necessary
+ nop
+ nop
+ push 11
+ JmpCommonIdtEntry
+
+INT12:
+; Stack fault causes an error code to be pushed so no phony push necessary
+ nop
+ nop
+ push 12
+ JmpCommonIdtEntry
+
+INT13:
+; GP fault causes an error code to be pushed so no phony push necessary
+ nop
+ nop
+ push 13
+ JmpCommonIdtEntry
+
+INT14:
+; Page fault causes an error code to be pushed so no phony push necessary
+ nop
+ nop
+ push 14
+ JmpCommonIdtEntry
+
+INT15:
+ push 0h ; push error code place holder on the stack
+ push 15
+ JmpCommonIdtEntry
+
+INT16:
+ push 0h ; push error code place holder on the stack
+ push 16
+ JmpCommonIdtEntry
+
+INT17:
+; Alignment check causes an error code to be pushed so no phony push necessary
+ nop
+ nop
+ push 17
+ JmpCommonIdtEntry
+
+INT18:
+ push 0h ; push error code place holder on the stack
+ push 18
+ JmpCommonIdtEntry
+
+INT19:
+ push 0h ; push error code place holder on the stack
+ push 19
+ JmpCommonIdtEntry
+
+INTUnknown:
+REPEAT (32 - 20)
+ push 0h ; push error code place holder on the stack
+; push xxh ; push vector number
+ db 06ah
+ db ( $ - INTUnknown - 3 ) / 9 + 20 ; vector number
+ JmpCommonIdtEntry
+ENDM
+SystemExceptionHandler ENDP
+
+SystemTimerHandler PROC
+ push 0
+ push mTimerVector
+ JmpCommonIdtEntry
+SystemTimerHandler ENDP
+
+commonIdtEntry:
+; +---------------------+
+; + EFlags +
+; +---------------------+
+; + CS +
+; +---------------------+
+; + EIP +
+; +---------------------+
+; + Error Code +
+; +---------------------+
+; + Vector Number +
+; +---------------------+
+; + EBP +
+; +---------------------+ <-- EBP
+
+ cli
+ push ebp
+ mov ebp, esp
+
+ ;
+ ; 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;
+ push dword ptr [ebp + 3 * 4]
+
+;; UINT32 Gdtr[2], Idtr[2];
+ sub esp, 8
+ sidt fword ptr [esp]
+ sub esp, 8
+ sgdt fword ptr [esp]
+
+;; UINT32 Ldtr, Tr;
+ xor eax, eax
+ str ax
+ push eax
+ sldt ax
+ push eax
+
+;; UINT32 EFlags;
+ push dword ptr [ebp + 5 * 4]
+
+;; 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
+;; 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
+ db 0fh, 0aeh, 00000111y ;fxsave [edi]
+
+;; UINT32 ExceptionData;
+ push dword ptr [ebp + 2 * 4]
+
+;; Prepare parameter and call
+ mov edx, esp
+ push edx
+ mov eax, dword ptr [ebp + 1 * 4]
+ push eax
+ cmp eax, 32
+ jb CallException
+ call TimerHandler
+ jmp ExceptionDone
+CallException:
+ call ExceptionHandler
+ExceptionDone:
+ add esp, 8
+
+ cli
+;; UINT32 ExceptionData;
+ add esp, 4
+
+;; FX_SAVE_STATE_IA32 FxSaveState;
+ mov esi, esp
+ db 0fh, 0aeh, 00001110y ; 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
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; data
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ align 02h
+
+gdtr dw GDT_END - GDT_BASE - 1 ; GDT limit
+ dd 0 ; (GDT base gets set above)
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; global descriptor table (GDT)
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ align 02h
+
+public GDT_BASE
+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 ; type
+ db 0 ; limit 19:16, flags
+ db 0 ; base 31:24
+
+; linear data segment descriptor
+LINEAR_SEL equ $-GDT_BASE
+ dw 0FFFFh ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 092h ; present, ring 0, data, expand-up, writable
+ db 0CFh ; page-granular, 32-bit
+ db 0
+
+; linear code segment descriptor
+LINEAR_CODE_SEL equ $-GDT_BASE
+ dw 0FFFFh ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 09Ah ; present, ring 0, data, expand-up, writable
+ db 0CFh ; page-granular, 32-bit
+ db 0
+
+; system data segment descriptor
+SYS_DATA_SEL equ $-GDT_BASE
+ dw 0FFFFh ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 092h ; present, ring 0, data, expand-up, writable
+ db 0CFh ; page-granular, 32-bit
+ db 0
+
+; system code segment descriptor
+SYS_CODE_SEL equ $-GDT_BASE
+ dw 0FFFFh ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 09Ah ; present, ring 0, data, expand-up, writable
+ db 0CFh ; page-granular, 32-bit
+ db 0
+
+; spare segment descriptor
+SPARE3_SEL equ $-GDT_BASE
+ dw 0 ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 0 ; present, ring 0, data, expand-up, writable
+ db 0 ; page-granular, 32-bit
+ db 0
+
+; spare segment descriptor
+SPARE4_SEL equ $-GDT_BASE
+ dw 0 ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 0 ; present, ring 0, data, expand-up, writable
+ db 0 ; page-granular, 32-bit
+ db 0
+
+; spare segment descriptor
+SPARE5_SEL equ $-GDT_BASE
+ dw 0 ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 0 ; present, ring 0, data, expand-up, writable
+ db 0 ; page-granular, 32-bit
+ db 0
+
+GDT_END:
+
+ align 02h
+
+
+
+idtr dw IDT_END - IDT_BASE - 1 ; IDT limit
+ dd 0 ; (IDT base gets set above)
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; interrupt descriptor table (IDT)
+;
+; Note: The hardware IRQ's specified in this table are the normal PC/AT IRQ
+; mappings. This implementation only uses the system timer and all other
+; IRQs will remain masked. The descriptors for vectors 33+ are provided
+; for convenience.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;idt_tag db "IDT",0
+ align 02h
+
+public IDT_BASE
+IDT_BASE:
+; divide by zero (INT 0)
+DIV_ZERO_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; debug exception (INT 1)
+DEBUG_EXCEPT_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; NMI (INT 2)
+NMI_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; soft breakpoint (INT 3)
+BREAKPOINT_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; overflow (INT 4)
+OVERFLOW_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; bounds check (INT 5)
+BOUNDS_CHECK_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; invalid opcode (INT 6)
+INVALID_OPCODE_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; device not available (INT 7)
+DEV_NOT_AVAIL_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; double fault (INT 8)
+DOUBLE_FAULT_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; Coprocessor segment overrun - reserved (INT 9)
+RSVD_INTR_SEL1 equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; invalid TSS (INT 0ah)
+INVALID_TSS_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; segment not present (INT 0bh)
+SEG_NOT_PRESENT_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; stack fault (INT 0ch)
+STACK_FAULT_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; general protection (INT 0dh)
+GP_FAULT_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; page fault (INT 0eh)
+PAGE_FAULT_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; Intel reserved - do not use (INT 0fh)
+RSVD_INTR_SEL2 equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; floating point error (INT 10h)
+FLT_POINT_ERR_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; alignment check (INT 11h)
+ALIGNMENT_CHECK_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; machine check (INT 12h)
+MACHINE_CHECK_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; SIMD floating-point exception (INT 13h)
+SIMD_EXCEPTION_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+REPEAT (32 - 20)
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ENDM
+
+; 72 unspecified descriptors
+ db (72 * 8) dup(0)
+
+; IRQ 0 (System timer) - (INT 68h)
+IRQ0_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; IRQ 1 (8042 Keyboard controller) - (INT 69h)
+IRQ1_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; Reserved - IRQ 2 redirect (IRQ 2) - DO NOT USE!!! - (INT 6ah)
+IRQ2_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; IRQ 3 (COM 2) - (INT 6bh)
+IRQ3_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; IRQ 4 (COM 1) - (INT 6ch)
+IRQ4_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; IRQ 5 (LPT 2) - (INT 6dh)
+IRQ5_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; IRQ 6 (Floppy controller) - (INT 6eh)
+IRQ6_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; IRQ 7 (LPT 1) - (INT 6fh)
+IRQ7_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; IRQ 8 (RTC Alarm) - (INT 70h)
+IRQ8_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; IRQ 9 - (INT 71h)
+IRQ9_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; IRQ 10 - (INT 72h)
+IRQ10_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; IRQ 11 - (INT 73h)
+IRQ11_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; IRQ 12 (PS/2 mouse) - (INT 74h)
+IRQ12_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; IRQ 13 (Floating point error) - (INT 75h)
+IRQ13_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; IRQ 14 (Secondary IDE) - (INT 76h)
+IRQ14_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+; IRQ 15 (Primary IDE) - (INT 77h)
+IRQ15_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+
+ db (1 * 8) dup(0)
+
+IDT_END:
+
+END
diff --git a/DuetPkg/CpuDxe/x64/CpuInterrupt.asm b/DuetPkg/CpuDxe/x64/CpuInterrupt.asm
new file mode 100644
index 0000000000..acf86059c4
--- /dev/null
+++ b/DuetPkg/CpuDxe/x64/CpuInterrupt.asm
@@ -0,0 +1,949 @@
+ TITLE CpuInterrupt.asm:
+;------------------------------------------------------------------------------
+;*
+;* Copyright 2006, 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.
+;*
+;* CpuInterrupt.asm
+;*
+;* Abstract:
+;*
+;------------------------------------------------------------------------------
+
+EXTERNDEF mExceptionCodeSize:DWORD
+
+.code
+
+EXTERN TimerHandler: FAR
+EXTERN ExceptionHandler: NEAR
+EXTERN mTimerVector: QWORD
+
+mExceptionCodeSize DD 9
+
+InitDescriptor PROC
+ lea rax, [GDT_BASE] ; RAX=PHYSICAL address of gdt
+ mov qword ptr [gdtr + 2], rax ; Put address of gdt into the gdtr
+ lgdt fword ptr [gdtr]
+ mov rax, 18h
+ mov gs, rax
+ mov fs, rax
+ lea rax, [IDT_BASE] ; RAX=PHYSICAL address of idt
+ mov qword ptr [idtr + 2], rax ; Put address of idt into the idtr
+ lidt fword ptr [idtr]
+ ret
+InitDescriptor ENDP
+
+; VOID
+; InstallInterruptHandler (
+; UINTN Vector, // rcx
+; void (*Handler)(void) // rdx
+; )
+InstallInterruptHandler PROC
+ push rbx
+ pushfq ; save eflags
+ cli ; turn off interrupts
+ sub rsp, 10h ; open some space on the stack
+ mov rbx, rsp
+ sidt [rbx] ; get fword address of IDT
+ mov rbx, [rbx+2] ; move offset of IDT into RBX
+ add rsp, 10h ; correct stack
+ mov rax, rcx ; Get vector number
+ shl rax, 4 ; multiply by 16 to get offset
+ add rbx, rax ; add to IDT base to get entry
+ mov rax, rdx ; load new address into IDT entry
+ mov word ptr [rbx], ax ; write bits 15..0 of offset
+ shr rax, 16 ; use ax to copy 31..16 to descriptors
+ mov word ptr [rbx+6], ax ; write bits 31..16 of offset
+ shr rax, 16 ; use eax to copy 63..32 to descriptors
+ mov dword ptr [rbx+8], eax ; write bits 63..32 of offset
+ popfq ; restore flags (possible enabling interrupts)
+ pop rbx
+ ret
+
+InstallInterruptHandler ENDP
+
+JmpCommonIdtEntry macro
+ ; jmp commonIdtEntry - this must be hand coded to keep the assembler from
+ ; using a 8 bit reletive jump when the entries are
+ ; within 255 bytes of the common entry. This must
+ ; be done to maintain the consistency of the size
+ ; of entry points...
+ db 0e9h ; jmp 16 bit reletive
+ dd commonIdtEntry - $ - 4 ; offset to jump to
+endm
+
+ align 02h
+SystemExceptionHandler PROC
+INT0:
+ push 0h ; push error code place holder on the stack
+ push 0h
+ JmpCommonIdtEntry
+; db 0e9h ; jmp 16 bit reletive
+; dd commonIdtEntry - $ - 4 ; offset to jump to
+
+INT1:
+ push 0h ; push error code place holder on the stack
+ push 1h
+ JmpCommonIdtEntry
+
+INT2:
+ push 0h ; push error code place holder on the stack
+ push 2h
+ JmpCommonIdtEntry
+
+INT3:
+ push 0h ; push error code place holder on the stack
+ push 3h
+ JmpCommonIdtEntry
+
+INT4:
+ push 0h ; push error code place holder on the stack
+ push 4h
+ JmpCommonIdtEntry
+
+INT5:
+ push 0h ; push error code place holder on the stack
+ push 5h
+ JmpCommonIdtEntry
+
+INT6:
+ push 0h ; push error code place holder on the stack
+ push 6h
+ JmpCommonIdtEntry
+
+INT7:
+ push 0h ; push error code place holder on the stack
+ push 7h
+ JmpCommonIdtEntry
+
+INT8:
+; Double fault causes an error code to be pushed so no phony push necessary
+ nop
+ nop
+ push 8h
+ JmpCommonIdtEntry
+
+INT9:
+ push 0h ; push error code place holder on the stack
+ push 9h
+ JmpCommonIdtEntry
+
+INT10:
+; Invalid TSS causes an error code to be pushed so no phony push necessary
+ nop
+ nop
+ push 10
+ JmpCommonIdtEntry
+
+INT11:
+; Segment Not Present causes an error code to be pushed so no phony push necessary
+ nop
+ nop
+ push 11
+ JmpCommonIdtEntry
+
+INT12:
+; Stack fault causes an error code to be pushed so no phony push necessary
+ nop
+ nop
+ push 12
+ JmpCommonIdtEntry
+
+INT13:
+; GP fault causes an error code to be pushed so no phony push necessary
+ nop
+ nop
+ push 13
+ JmpCommonIdtEntry
+
+INT14:
+; Page fault causes an error code to be pushed so no phony push necessary
+ nop
+ nop
+ push 14
+ JmpCommonIdtEntry
+
+INT15:
+ push 0h ; push error code place holder on the stack
+ push 15
+ JmpCommonIdtEntry
+
+INT16:
+ push 0h ; push error code place holder on the stack
+ push 16
+ JmpCommonIdtEntry
+
+INT17:
+; Alignment check causes an error code to be pushed so no phony push necessary
+ nop
+ nop
+ push 17
+ JmpCommonIdtEntry
+
+INT18:
+ push 0h ; push error code place holder on the stack
+ push 18
+ JmpCommonIdtEntry
+
+INT19:
+ push 0h ; push error code place holder on the stack
+ push 19
+ JmpCommonIdtEntry
+
+INTUnknown:
+REPEAT (32 - 20)
+ push 0h ; push error code place holder on the stack
+; push xxh ; push vector number
+ db 06ah
+ db ( $ - INTUnknown - 3 ) / 9 + 20 ; vector number
+ JmpCommonIdtEntry
+ENDM
+SystemExceptionHandler ENDP
+
+SystemTimerHandler PROC
+ push 0
+ push mTimerVector
+ JmpCommonIdtEntry
+SystemTimerHandler ENDP
+
+commonIdtEntry:
+; +---------------------+ <-- 16-byte aligned ensured by processor
+; + Old SS +
+; +---------------------+
+; + Old RSP +
+; +---------------------+
+; + RFlags +
+; +---------------------+
+; + CS +
+; +---------------------+
+; + RIP +
+; +---------------------+
+; + Error Code +
+; +---------------------+
+; + Vector Number +
+; +---------------------+
+; + RBP +
+; +---------------------+ <-- RBP, 16-byte aligned
+
+ cli
+ push rbp
+ mov rbp, rsp
+
+ ;
+ ; Since here the stack pointer is 16-byte aligned, so
+ ; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64
+ ; is 16-byte aligned
+ ;
+
+;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
+;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
+ push r15
+ push r14
+ push r13
+ push r12
+ push r11
+ push r10
+ push r9
+ push r8
+ push rax
+ push rcx
+ push rdx
+ push rbx
+ push qword ptr [rbp + 6 * 8] ; 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 + 7 * 8]
+ push rax ; for ss
+ movzx rax, word ptr [rbp + 4 * 8]
+ push rax ; for cs
+ mov rax, ds
+ push rax
+ mov rax, es
+ push rax
+ mov rax, fs
+ push rax
+ mov rax, gs
+ push rax
+
+;; UINT64 Rip;
+ push qword ptr [rbp + 3 * 8]
+
+;; UINT64 Gdtr[2], Idtr[2];
+ sub rsp, 16
+ sidt fword ptr [rsp]
+ sub rsp, 16
+ sgdt fword ptr [rsp]
+
+;; UINT64 Ldtr, Tr;
+ xor rax, rax
+ str ax
+ push rax
+ sldt ax
+ push rax
+
+;; UINT64 RFlags;
+ push qword ptr [rbp + 5 * 8]
+
+;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
+ mov rax, cr8
+ push rax
+ mov rax, cr4
+ or rax, 208h
+ mov cr4, rax
+ push rax
+ mov rax, cr3
+ push rax
+ mov rax, cr2
+ push rax
+ xor rax, rax
+ push rax
+ mov rax, cr0
+ push rax
+
+;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ mov rax, dr7
+ push rax
+;; clear Dr7 while executing debugger itself
+ xor rax, rax
+ mov dr7, rax
+
+ mov rax, dr6
+ push rax
+;; insure all status bits in dr6 are clear...
+ xor rax, rax
+ mov dr6, rax
+
+ mov rax, dr3
+ push rax
+ mov rax, dr2
+ push rax
+ mov rax, dr1
+ push rax
+ mov rax, dr0
+ push rax
+
+;; FX_SAVE_STATE_X64 FxSaveState;
+
+ sub rsp, 512
+ mov rdi, rsp
+ db 0fh, 0aeh, 00000111y ;fxsave [rdi]
+
+;; UINT32 ExceptionData;
+ push qword ptr [rbp + 2 * 8]
+
+;; call into exception handler
+;; Prepare parameter and call
+ mov rcx, qword ptr [rbp + 1 * 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
+ cmp rcx, 32
+ jb CallException
+ call TimerHandler
+ jmp ExceptionDone
+CallException:
+ call ExceptionHandler
+ExceptionDone:
+ add rsp, 4 * 8 + 8
+
+ cli
+;; UINT64 ExceptionData;
+ add rsp, 8
+
+;; FX_SAVE_STATE_X64 FxSaveState;
+
+ mov rsi, rsp
+ db 0fh, 0aeh, 00001110y ; fxrstor [rsi]
+ add rsp, 512
+
+;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ pop rax
+ mov dr0, rax
+ pop rax
+ mov dr1, rax
+ pop rax
+ mov dr2, rax
+ pop rax
+ mov dr3, rax
+;; skip restore of dr6. We cleared dr6 during the context save.
+ add rsp, 8
+ pop rax
+ mov dr7, rax
+
+;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
+ pop rax
+ mov cr0, rax
+ add rsp, 8 ; not for Cr1
+ pop rax
+ mov cr2, rax
+ pop rax
+ mov cr3, rax
+ pop rax
+ mov cr4, rax
+ pop rax
+ mov cr8, rax
+
+;; UINT64 RFlags;
+ pop qword ptr [rbp + 5 * 8]
+
+;; 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 + 3 * 8]
+
+;; 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 + 4 * 8] ; for cs
+ pop qword ptr [rbp + 7 * 8] ; 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 + 6 * 8] ; 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
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; data
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ align 010h
+
+gdtr dw GDT_END - GDT_BASE - 1 ; GDT limit
+ dq 0 ; (GDT base gets set above)
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; global descriptor table (GDT)
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ align 010h
+
+public GDT_BASE
+GDT_BASE:
+; null descriptor
+NULL_SEL equ $-GDT_BASE ; Selector [0x0]
+ dw 0 ; limit 15:0
+ dw 0 ; base 15:0
+ db 0 ; base 23:16
+ db 0 ; type
+ db 0 ; limit 19:16, flags
+ db 0 ; base 31:24
+
+; linear data segment descriptor
+LINEAR_SEL equ $-GDT_BASE ; Selector [0x8]
+ dw 0FFFFh ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 092h ; present, ring 0, data, expand-up, writable
+ db 0CFh ; page-granular, 32-bit
+ db 0
+
+; linear code segment descriptor
+LINEAR_CODE_SEL equ $-GDT_BASE ; Selector [0x10]
+ dw 0FFFFh ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 09Ah ; present, ring 0, data, expand-up, writable
+ db 0CFh ; page-granular, 32-bit
+ db 0
+
+; system data segment descriptor
+SYS_DATA_SEL equ $-GDT_BASE ; Selector [0x18]
+ dw 0FFFFh ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 092h ; present, ring 0, data, expand-up, writable
+ db 0CFh ; page-granular, 32-bit
+ db 0
+
+; system code segment descriptor
+SYS_CODE_SEL equ $-GDT_BASE ; Selector [0x20]
+ dw 0FFFFh ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 09Ah ; present, ring 0, data, expand-up, writable
+ db 0CFh ; page-granular, 32-bit
+ db 0
+
+; spare segment descriptor
+SPARE3_SEL equ $-GDT_BASE ; Selector [0x28]
+ dw 0 ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 0 ; present, ring 0, data, expand-up, writable
+ db 0 ; page-granular, 32-bit
+ db 0
+
+;
+; system data segment descriptor
+;
+SYS_DATA64_SEL equ $-GDT_BASE ; Selector [0x30]
+ dw 0FFFFh ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 092h ; P | DPL [1..2] | 1 | 1 | C | R | A
+ db 0CFh ; G | D | L | AVL | Segment [19..16]
+ db 0
+
+;
+; system code segment descriptor
+;
+SYS_CODE64_SEL equ $-GDT_BASE ; Selector [0x38]
+ dw 0FFFFh ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 09Ah ; P | DPL [1..2] | 1 | 1 | C | R | A
+ db 0AFh ; G | D | L | AVL | Segment [19..16]
+ db 0
+
+; spare segment descriptor
+SPARE4_SEL equ $-GDT_BASE ; Selector [0x40]
+ dw 0 ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 0 ; present, ring 0, data, expand-up, writable
+ db 0 ; page-granular, 32-bit
+ db 0
+
+GDT_END:
+
+ align 02h
+
+
+
+idtr dw IDT_END - IDT_BASE - 1 ; IDT limit
+ dq 0 ; (IDT base gets set above)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; interrupt descriptor table (IDT)
+;
+; Note: The hardware IRQ's specified in this table are the normal PC/AT IRQ
+; mappings. This implementation only uses the system timer and all other
+; IRQs will remain masked. The descriptors for vectors 33+ are provided
+; for convenience.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;idt_tag db "IDT",0
+ align 02h
+
+public IDT_BASE
+IDT_BASE:
+; divide by zero (INT 0)
+DIV_ZERO_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; debug exception (INT 1)
+DEBUG_EXCEPT_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; NMI (INT 2)
+NMI_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; soft breakpoint (INT 3)
+BREAKPOINT_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; overflow (INT 4)
+OVERFLOW_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; bounds check (INT 5)
+BOUNDS_CHECK_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; invalid opcode (INT 6)
+INVALID_OPCODE_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; device not available (INT 7)
+DEV_NOT_AVAIL_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; double fault (INT 8)
+DOUBLE_FAULT_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; Coprocessor segment overrun - reserved (INT 9)
+RSVD_INTR_SEL1 equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; invalid TSS (INT 0ah)
+INVALID_TSS_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; segment not present (INT 0bh)
+SEG_NOT_PRESENT_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; stack fault (INT 0ch)
+STACK_FAULT_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; general protection (INT 0dh)
+GP_FAULT_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; page fault (INT 0eh)
+PAGE_FAULT_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; Intel reserved - do not use (INT 0fh)
+RSVD_INTR_SEL2 equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; floating point error (INT 10h)
+FLT_POINT_ERR_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; alignment check (INT 11h)
+ALIGNMENT_CHECK_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; machine check (INT 12h)
+MACHINE_CHECK_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; SIMD floating-point exception (INT 13h)
+SIMD_EXCEPTION_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+REPEAT (32 - 20)
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+ENDM
+
+; 72 unspecified descriptors
+ db (72 * 16) dup(0)
+
+; IRQ 0 (System timer) - (INT 68h)
+IRQ0_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; IRQ 1 (8042 Keyboard controller) - (INT 69h)
+IRQ1_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; Reserved - IRQ 2 redirect (IRQ 2) - DO NOT USE!!! - (INT 6ah)
+IRQ2_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; IRQ 3 (COM 2) - (INT 6bh)
+IRQ3_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; IRQ 4 (COM 1) - (INT 6ch)
+IRQ4_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; IRQ 5 (LPT 2) - (INT 6dh)
+IRQ5_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; IRQ 6 (Floppy controller) - (INT 6eh)
+IRQ6_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; IRQ 7 (LPT 1) - (INT 6fh)
+IRQ7_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; IRQ 8 (RTC Alarm) - (INT 70h)
+IRQ8_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; IRQ 9 - (INT 71h)
+IRQ9_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; IRQ 10 - (INT 72h)
+IRQ10_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; IRQ 11 - (INT 73h)
+IRQ11_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; IRQ 12 (PS/2 mouse) - (INT 74h)
+IRQ12_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; IRQ 13 (Floating point error) - (INT 75h)
+IRQ13_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; IRQ 14 (Secondary IDE) - (INT 76h)
+IRQ14_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+; IRQ 15 (Primary IDE) - (INT 77h)
+IRQ15_SEL equ $-IDT_BASE
+ dw 0 ; offset 15:0
+ dw SYS_CODE64_SEL ; selector 15:0
+ db 0 ; 0 for interrupt gate
+ db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
+ dw 0 ; offset 31:16
+ dd 0 ; offset 63:32
+ dd 0 ; 0 for reserved
+
+ db (1 * 16) dup(0)
+
+IDT_END:
+
+ align 02h
+
+END