From f767f99009995ede5f7ae808d75bcf862b692485 Mon Sep 17 00:00:00 2001 From: li-elvin Date: Tue, 30 Aug 2011 05:52:28 +0000 Subject: [PATCH] Update CSM module to provide the general solution when the Timer Arch Protocol is not 8254 timer. CSM module should set 8254 timer to 54ms for the execution in real mode. Signed-off-by: li-elvin Reviewed-by: jyao1 git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12229 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Csm/LegacyBiosDxe/LegacyBios.c | 3 + .../Csm/LegacyBiosDxe/LegacyBiosDxe.inf | 3 +- .../Csm/LegacyBiosDxe/LegacyBiosInterface.h | 21 ++- .../Csm/LegacyBiosDxe/Thunk.c | 134 +++++++++++++++++- 4 files changed, 156 insertions(+), 5 deletions(-) diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c index 75add5e39d..37f009af58 100644 --- a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c @@ -736,6 +736,9 @@ LegacyBiosInstall ( Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Private->Cpu); ASSERT_EFI_ERROR (Status); + Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **) &Private->Timer); + ASSERT_EFI_ERROR (Status); + Status = gBS->LocateProtocol (&gEfiLegacyRegion2ProtocolGuid, NULL, (VOID **) &Private->LegacyRegion); ASSERT_EFI_ERROR (Status); diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf index 593383c510..d8806a84ec 100644 --- a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf @@ -121,6 +121,7 @@ gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED gEfiPciRootBridgeIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED gEfiCpuArchProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiTimerArchProtocolGuid # PROTOCOL ALWAYS_CONSUMED gEfiIsaIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED gEfiBlockIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED gEfiPciIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED @@ -138,5 +139,5 @@ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdEbdaReservedMemorySize [Depex] - gEfiLegacyRegion2ProtocolGuid AND gEfiLegacyInterruptProtocolGuid AND gEfiLegacyBiosPlatformProtocolGuid AND gEfiLegacy8259ProtocolGuid AND gEfiGenericMemTestProtocolGuid AND gEfiCpuArchProtocolGuid + gEfiLegacyRegion2ProtocolGuid AND gEfiLegacyInterruptProtocolGuid AND gEfiLegacyBiosPlatformProtocolGuid AND gEfiLegacy8259ProtocolGuid AND gEfiGenericMemTestProtocolGuid AND gEfiCpuArchProtocolGuid AND gEfiTimerArchProtocolGuid diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h index 15b3b7048c..8ab26fe326 100644 --- a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h @@ -29,6 +29,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include #include #include #include @@ -517,6 +518,18 @@ extern UINTN mEndOpromShadowAddress; #define CMOS_31 0x31 ///< CMOS 0x18 #define CMOS_32 0x32 ///< Century byte +// +// 8254 Timer registers +// +#define TIMER0_COUNT_PORT 0x40 +#define TIMER1_COUNT_PORT 0x41 +#define TIMER2_COUNT_PORT 0x42 +#define TIMER_CONTROL_PORT 0x43 + +// +// Timer 0, Read/Write LSB then MSB, Square wave output, binary count use. +// +#define TIMER0_CONTROL_WORD 0x36 #define LEGACY_BIOS_INSTANCE_SIGNATURE SIGNATURE_32 ('L', 'B', 'I', 'T') typedef struct { @@ -532,6 +545,12 @@ typedef struct { // EFI_CPU_ARCH_PROTOCOL *Cpu; + // + // Timer Architectural Protocol + // + EFI_TIMER_ARCH_PROTOCOL *Timer; + BOOLEAN TimerUses8254; + // // Protocol to Lock and Unlock 0xc0000 - 0xfffff // @@ -543,7 +562,7 @@ typedef struct { // Interrupt control for thunk and PCI IRQ // EFI_LEGACY_8259_PROTOCOL *Legacy8259; - + // // PCI Interrupt PIRQ control // diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Thunk.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Thunk.c index c33288a2dd..9a62499f05 100644 --- a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Thunk.c +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Thunk.c @@ -1,7 +1,7 @@ /** @file Call into 16-bit BIOS code, Use AsmThunk16 function of BaseLib. -Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions @@ -18,6 +18,22 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. THUNK_CONTEXT mThunkContext; +/** + Sets the counter value for Timer #0 in a legacy 8254 timer. + + @param Count - The 16-bit counter value to program into Timer #0 of the legacy 8254 timer. + +**/ +VOID +SetPitCount ( + IN UINT16 Count + ) +{ + IoWrite8 (TIMER_CONTROL_PORT, TIMER0_CONTROL_WORD); + IoWrite8 (TIMER0_COUNT_PORT, (UINT8) (Count & 0xFF)); + IoWrite8 (TIMER0_COUNT_PORT, (UINT8) ((Count>>8) & 0xFF)); +} + /** Thunk to 16-bit real mode and execute a software interrupt with a vector of BiosInt. Regs will contain the 16-bit register context on entry and @@ -103,6 +119,23 @@ LegacyBiosFarCall86 ( return InternalLegacyBiosFarCall (This, Segment, Offset, Regs, Stack, StackSize); } +/** + Provide NULL interrupt handler which is used to check + if there is more than one HW interrupt registers with the CPU AP. + + @param InterruptType - The type of interrupt that occured + @param SystemContext - A pointer to the system context when the interrupt occured + +**/ +VOID +EFIAPI +LegacyBiosNullInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ +} + /** Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the 16-bit register context on entry and exit. Arguments can be passed on @@ -138,6 +171,7 @@ InternalLegacyBiosFarCall ( EFI_TPL OriginalTpl; IA32_REGISTER_SET ThunkRegSet; BOOLEAN InterruptState; + UINT64 TimerPeriod; Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); @@ -165,7 +199,17 @@ InternalLegacyBiosFarCall ( Stack16 = (UINT16 *)((UINT8 *) mThunkContext.RealModeBuffer + mThunkContext.RealModeBufferSize - sizeof (UINT16)); // - // Save and disable interrutp of debug timer + // Save current rate of DXE Timer + // + Private->Timer->GetTimerPeriod (Private->Timer, &TimerPeriod); + + // + // Disable DXE Timer while executing in real mode + // + Private->Timer->SetTimerPeriod (Private->Timer, 0); + + // + // Save and disable interrupt of debug timer // InterruptState = SaveAndSetDebugTimerInterrupt (FALSE); @@ -174,6 +218,40 @@ InternalLegacyBiosFarCall ( // OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); + // + // Check to see if there is more than one HW interrupt registers with the CPU AP. + // If there is, then ASSERT() since that is not compatible with the CSM because + // interupts other than the Timer interrupt that was disabled above can not be + // handled properly from real mode. + // + DEBUG_CODE ( + UINTN Vector; + UINTN Count; + + for (Vector = 0x20, Count = 0; Vector < 0x100; Vector++) { + Status = Private->Cpu->RegisterInterruptHandler (Private->Cpu, Vector, LegacyBiosNullInterruptHandler); + if (Status == EFI_ALREADY_STARTED) { + Count++; + } + if (Status == EFI_SUCCESS) { + Private->Cpu->RegisterInterruptHandler (Private->Cpu, Vector, NULL); + } + } + if (Count >= 2) { + DEBUG ((EFI_D_ERROR, "ERROR: More than one HW interrupt active with CSM enabled\n")); + } + ASSERT (Count < 2); + ); + + // + // If the Timer AP has enabled the 8254 timer IRQ and the current 8254 timer + // period is less than the CSM required rate of 54.9254, then force the 8254 + // PIT counter to 0, which is the CSM required rate of 54.9254 ms + // + if (Private->TimerUses8254 && TimerPeriod < 549254) { + SetPitCount (0); + } + if (Stack != NULL && StackSize != 0) { // // Copy Stack to low memory stack @@ -235,7 +313,12 @@ InternalLegacyBiosFarCall ( gBS->RestoreTPL (OriginalTpl); // - // Restore interrutp of debug timer + // Enable and restore rate of DXE Timer + // + Private->Timer->SetTimerPeriod (Private->Timer, TimerPeriod); + + // + // Restore interrupt of debug timer // SaveAndSetDebugTimerInterrupt (InterruptState); @@ -270,7 +353,9 @@ LegacyBiosInitializeThunk ( IN LEGACY_BIOS_INSTANCE *Private ) { + EFI_STATUS Status; EFI_PHYSICAL_ADDRESS MemoryAddress; + UINT8 TimerVector; MemoryAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) Private->IntThunk; @@ -280,5 +365,48 @@ LegacyBiosInitializeThunk ( AsmPrepareThunk16 (&mThunkContext); + // + // Get the interrupt vector number corresponding to IRQ0 from the 8259 driver + // + TimerVector = 0; + Status = Private->Legacy8259->GetVector (Private->Legacy8259, Efi8259Irq0, &TimerVector); + ASSERT_EFI_ERROR (Status); + + // + // Check to see if the Timer AP has hooked the IRQ0 from the 8254 PIT + // + Status = Private->Cpu->RegisterInterruptHandler ( + Private->Cpu, + TimerVector, + LegacyBiosNullInterruptHandler + ); + if (Status == EFI_SUCCESS) { + // + // If the Timer AP has not enabled the 8254 timer IRQ, then force the 8254 PIT + // counter to 0, which is the CSM required rate of 54.9254 ms + // + Private->Cpu->RegisterInterruptHandler ( + Private->Cpu, + TimerVector, + NULL + ); + SetPitCount (0); + + // + // Save status that the Timer AP is not using the 8254 PIT + // + Private->TimerUses8254 = FALSE; + } else if (Status == EFI_ALREADY_STARTED) { + // + // Save status that the Timer AP is using the 8254 PIT + // + Private->TimerUses8254 = TRUE; + } else { + // + // Unexpected status from CPU AP RegisterInterruptHandler() + // + ASSERT (FALSE); + } + return EFI_SUCCESS; } -- 2.39.2