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
1 changed files with 78 additions and 31 deletions

View File

@ -111,6 +111,15 @@ EFI_CPU_ARCH_PROTOCOL gCpu = {
//
UINT32 mErrorCodeFlag = 0x00027d00;
//
// Local function prototypes
//
VOID
SetInterruptDescriptorTableHandlerAddress (
IN UINTN Index,
IN VOID *Handler OPTIONAL
);
//
// CPU Arch Protocol Functions
//
@ -504,6 +513,7 @@ CpuRegisterInterruptHandler (
return EFI_ALREADY_STARTED;
}
SetInterruptDescriptorTableHandlerAddress (InterruptType, NULL);
ExternalVectorTable[InterruptType] = InterruptHandler;
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.
@ -1014,47 +1049,59 @@ InitInterruptDescriptorTable (
VOID
)
{
EFI_STATUS Status;
VOID *IdtPtrAlignmentBuffer;
IA32_DESCRIPTOR *IdtPtr;
UINTN Index;
UINTN CurrentHandler;
IA32_DESCRIPTOR Idtr;
EFI_STATUS Status;
IA32_DESCRIPTOR OldIdtPtr;
IA32_IDT_GATE_DESCRIPTOR *OldIdt;
UINTN OldIdtSize;
VOID *IdtPtrAlignmentBuffer;
IA32_DESCRIPTOR *IdtPtr;
UINTN Index;
UINT16 CurrentCs;
VOID *IntHandler;
SetMem (ExternalVectorTable, sizeof(ExternalVectorTable), 0);
//
// 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.
//
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);
//
// Update all IDT enties to use cuurent CS value
//
for (Index = 0; Index < INTERRUPT_VECTOR_NUMBER; Index ++, CurrentHandler += 0x08) {
gIdtTable[Index].Bits.Selector = AsmReadCs();
CurrentCs = AsmReadCs();
for (Index = 0; Index < INTERRUPT_VECTOR_NUMBER; Index ++) {
//
// If the old IDT had a handler for this interrupt, then
// preserve it.
//
if (Index < OldIdtSize) {
IntHandler =
(VOID*) (
OldIdt[Index].Bits.OffsetLow +
(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
//