]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Thunk.c
Fix a bug about the iSCSI DHCP dependency issue.
[mirror_edk2.git] / IntelFrameworkModulePkg / Csm / LegacyBiosDxe / Thunk.c
index c33288a2ddd9f32596ff8fb031efe0bbe55529ba..3d9a8b96490ca54794954ed31f4f51c4dc0d10a9 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
@@ -41,6 +57,8 @@ LegacyBiosInt86 (
   IN  EFI_IA32_REGISTER_SET         *Regs\r
   )\r
 {\r
+  UINT32  *VectorBase;\r
+\r
   Regs->X.Flags.Reserved1 = 1;\r
   Regs->X.Flags.Reserved2 = 0;\r
   Regs->X.Flags.Reserved3 = 0;\r
@@ -50,11 +68,16 @@ LegacyBiosInt86 (
   Regs->X.Flags.IF        = 0;\r
   Regs->X.Flags.TF        = 0;\r
   Regs->X.Flags.CF        = 0;\r
-\r
+  //\r
+  // The base address of legacy interrupt vector table is 0.\r
+  // We use this base address to get the legacy interrupt handler.\r
+  //\r
+  VectorBase              = 0;\r
+  \r
   return InternalLegacyBiosFarCall (\r
            This,\r
-           (UINT16) (((UINT32 *)NULL)[BiosInt] >> 16),\r
-           (UINT16) ((UINT32 *)NULL)[BiosInt],\r
+           (UINT16) ((VectorBase)[BiosInt] >> 16),\r
+           (UINT16) (VectorBase)[BiosInt],\r
            Regs,\r
            &Regs->X.Flags,\r
            sizeof (Regs->X.Flags)\r
@@ -103,6 +126,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 +178,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 +206,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 +225,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
@@ -229,13 +314,18 @@ InternalLegacyBiosFarCall (
 \r
   mThunkContext.RealModeState = NULL;\r
 \r
+  //\r
+  // Enable and restore rate of DXE Timer\r
+  //\r
+  Private->Timer->SetTimerPeriod (Private->Timer, TimerPeriod);\r
+\r
   //\r
   // End critical section\r
   //\r
   gBS->RestoreTPL (OriginalTpl);\r
-\r
+  \r
   //\r
-  // Restore interrutp of debug timer\r
+  // Restore interrupt of debug timer\r
   //\r
   SaveAndSetDebugTimerInterrupt (InterruptState);\r
 \r
@@ -270,7 +360,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 +372,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