UefiCpuPkg CpuDxe: Fix bug with CPU Arch RegisterInterruptHandler

The change in r10765 introduced an issue where inherited interrupt
handlers would override the driver's RegisterInterruptHandler
functionality.

DUET installs a IDT with 256 entries early in it's boot.  Therefore,
no interrupt handlers could be installed with DUET while using
UefiCpuPkg/CpuDxe (instead of DuetPkg/CpuDxe).

This change forces the IDT to be modified when RegisterInterruptHandler
is called to ensure the UEFI handler will be installed properly.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10972 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
jljusten 2010-10-22 01:07:48 +00:00
parent f0384583af
commit 557b970a2f

View File

@ -111,6 +111,15 @@ EFI_CPU_ARCH_PROTOCOL gCpu = {
// //
UINT32 mErrorCodeFlag = 0x00027d00; UINT32 mErrorCodeFlag = 0x00027d00;
//
// Local function prototypes
//
VOID
SetInterruptDescriptorTableHandlerAddress (
IN UINTN Index,
IN VOID *Handler OPTIONAL
);
// //
// CPU Arch Protocol Functions // CPU Arch Protocol Functions
// //
@ -504,6 +513,7 @@ CpuRegisterInterruptHandler (
return EFI_ALREADY_STARTED; return EFI_ALREADY_STARTED;
} }
SetInterruptDescriptorTableHandlerAddress (InterruptType, NULL);
ExternalVectorTable[InterruptType] = InterruptHandler; ExternalVectorTable[InterruptType] = InterruptHandler;
return EFI_SUCCESS; return EFI_SUCCESS;
} }
@ -1005,6 +1015,31 @@ RefreshGcdMemoryAttributes (
} }
VOID
SetInterruptDescriptorTableHandlerAddress (
IN UINTN Index,
IN VOID *Handler OPTIONAL
)
{
UINTN UintnHandler;
if (Handler != NULL) {
UintnHandler = (UINTN) Handler;
} else {
UintnHandler = ((UINTN) AsmIdtVector00) + (8 * Index);
}
gIdtTable[Index].Bits.OffsetLow = (UINT16)UintnHandler;
gIdtTable[Index].Bits.Reserved_0 = 0;
gIdtTable[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
gIdtTable[Index].Bits.OffsetHigh = (UINT16)(UintnHandler >> 16);
#if defined (MDE_CPU_X64)
gIdtTable[Index].Bits.OffsetUpper = (UINT32)(UintnHandler >> 32);
gIdtTable[Index].Bits.Reserved_1 = 0;
#endif
}
/** /**
Initialize Interrupt Descriptor Table for interrupt handling. Initialize Interrupt Descriptor Table for interrupt handling.
@ -1014,47 +1049,59 @@ InitInterruptDescriptorTable (
VOID VOID
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
VOID *IdtPtrAlignmentBuffer; IA32_DESCRIPTOR OldIdtPtr;
IA32_DESCRIPTOR *IdtPtr; IA32_IDT_GATE_DESCRIPTOR *OldIdt;
UINTN Index; UINTN OldIdtSize;
UINTN CurrentHandler; VOID *IdtPtrAlignmentBuffer;
IA32_DESCRIPTOR Idtr; IA32_DESCRIPTOR *IdtPtr;
UINTN Index;
UINT16 CurrentCs;
VOID *IntHandler;
SetMem (ExternalVectorTable, sizeof(ExternalVectorTable), 0); SetMem (ExternalVectorTable, sizeof(ExternalVectorTable), 0);
//
// Intialize IDT
//
CurrentHandler = (UINTN)AsmIdtVector00;
for (Index = 0; Index < INTERRUPT_VECTOR_NUMBER; Index ++, CurrentHandler += 0x08) {
gIdtTable[Index].Bits.OffsetLow = (UINT16)CurrentHandler;
gIdtTable[Index].Bits.Reserved_0 = 0;
gIdtTable[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
gIdtTable[Index].Bits.OffsetHigh = (UINT16)(CurrentHandler >> 16);
#if defined (MDE_CPU_X64)
gIdtTable[Index].Bits.OffsetUpper = (UINT32)(CurrentHandler >> 32);
gIdtTable[Index].Bits.Reserved_1 = 0;
#endif
}
// //
// Get original IDT address and size. // Get original IDT address and size.
// //
AsmReadIdtr ((IA32_DESCRIPTOR *) &Idtr); AsmReadIdtr ((IA32_DESCRIPTOR *) &OldIdtPtr);
if ((OldIdtPtr.Base != 0) && ((OldIdtPtr.Limit & 7) == 7)) {
OldIdt = (IA32_IDT_GATE_DESCRIPTOR*) OldIdtPtr.Base;
OldIdtSize = (OldIdtPtr.Limit + 1) / 8;
} else {
OldIdt = NULL;
OldIdtSize = 0;
}
// //
// Copy original IDT entry. // Intialize IDT
// //
CopyMem (&gIdtTable[0], (VOID *) Idtr.Base, Idtr.Limit + 1); CurrentCs = AsmReadCs();
for (Index = 0; Index < INTERRUPT_VECTOR_NUMBER; Index ++) {
// //
// Update all IDT enties to use cuurent CS value // If the old IDT had a handler for this interrupt, then
// // preserve it.
for (Index = 0; Index < INTERRUPT_VECTOR_NUMBER; Index ++, CurrentHandler += 0x08) { //
gIdtTable[Index].Bits.Selector = AsmReadCs(); if (Index < OldIdtSize) {
IntHandler =
(VOID*) (
OldIdt[Index].Bits.OffsetLow +
(OldIdt[Index].Bits.OffsetHigh << 16)
#if defined (MDE_CPU_X64)
+ (((UINTN) OldIdt[Index].Bits.OffsetUpper) << 32)
#endif
);
} else {
IntHandler = NULL;
}
gIdtTable[Index].Bits.Selector = CurrentCs;
gIdtTable[Index].Bits.Reserved_0 = 0;
gIdtTable[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
SetInterruptDescriptorTableHandlerAddress (Index, IntHandler);
} }
// //
// Load IDT Pointer // Load IDT Pointer
// //