]> git.proxmox.com Git - mirror_edk2.git/commitdiff
Update CSM module to provide the general solution when the Timer Arch Protocol is...
authorli-elvin <li-elvin@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 30 Aug 2011 05:52:28 +0000 (05:52 +0000)
committerli-elvin <li-elvin@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 30 Aug 2011 05:52:28 +0000 (05:52 +0000)
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

IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Thunk.c

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