]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/CpuDxe/CpuDxe.c
Fix a bug about the iSCSI DHCP dependency issue.
[mirror_edk2.git] / UefiCpuPkg / CpuDxe / CpuDxe.c
index 25131febf20a0fc098ffdb98eca905e562bfa7ca..2dfde0677d88b54d5988bf974bbfa5f853dbacdc 100644 (file)
@@ -1,8 +1,8 @@
 /** @file\r
   CPU DXE Module.\r
 \r
-  Copyright (c) 2008 - 2009, Intel Corporation\r
-  All rights reserved. This program and the accompanying materials\r
+  Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
   which accompanies this distribution.  The full text of the license may be found at\r
   http://opensource.org/licenses/bsd-license.php\r
 //\r
 // Global Variables\r
 //\r
-IA32_IDT_GATE_DESCRIPTOR  gIdtTable[INTERRUPT_VECTOR_NUMBER] = { 0 };\r
+IA32_IDT_GATE_DESCRIPTOR  gIdtTable[INTERRUPT_VECTOR_NUMBER] = { { { 0 } } };\r
 \r
 EFI_CPU_INTERRUPT_HANDLER ExternalVectorTable[0x100];\r
 BOOLEAN                   InterruptState = FALSE;\r
 EFI_HANDLE                mCpuHandle = NULL;\r
 BOOLEAN                   mIsFlushingGCD;\r
-UINT8                     mDefaultMemoryType    = MTRR_CACHE_WRITE_BACK;\r
 UINT64                    mValidMtrrAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;\r
 UINT64                    mValidMtrrBitsMask    = MTRR_LIB_MSR_VALID_MASK;\r
+IA32_IDT_GATE_DESCRIPTOR  *mOrigIdtEntry        = NULL;\r
+UINT16                    mOrigIdtEntryCount    = 0;\r
 \r
 FIXED_MTRR    mFixedMtrrTable[] = {\r
   {\r
@@ -111,6 +112,23 @@ EFI_CPU_ARCH_PROTOCOL  gCpu = {
 //\r
 UINT32 mErrorCodeFlag = 0x00027d00;\r
 \r
+//\r
+// Local function prototypes\r
+//\r
+\r
+/**\r
+  Set Interrupt Descriptor Table Handler Address.\r
+\r
+  @param Index        The Index of the interrupt descriptor table handle.\r
+  @param Handler      Handler address.\r
+\r
+**/\r
+VOID\r
+SetInterruptDescriptorTableHandlerAddress (\r
+  IN UINTN Index,\r
+  IN VOID  *Handler  OPTIONAL\r
+  );\r
+\r
 //\r
 // CPU Arch Protocol Functions\r
 //\r
@@ -136,7 +154,7 @@ CommonExceptionHandler (
     "!!!! IA32 Exception Type - %08x !!!!\n",\r
     InterruptType\r
     ));\r
-  if (mErrorCodeFlag & (1 << InterruptType)) {\r
+  if ((mErrorCodeFlag & (1 << InterruptType)) != 0) {\r
     DEBUG ((\r
       EFI_D_ERROR,\r
       "ExceptionData - %08x\n",\r
@@ -217,7 +235,7 @@ CommonExceptionHandler (
     "!!!! X64 Exception Type - %016lx !!!!\n",\r
     (UINT64)InterruptType\r
     ));\r
-  if (mErrorCodeFlag & (1 << InterruptType)) {\r
+  if ((mErrorCodeFlag & (1 << InterruptType)) != 0) {\r
     DEBUG ((\r
       EFI_D_ERROR,\r
       "ExceptionData - %016lx\n",\r
@@ -504,6 +522,15 @@ CpuRegisterInterruptHandler (
     return EFI_ALREADY_STARTED;\r
   }\r
 \r
+  if (InterruptHandler != NULL) {\r
+    SetInterruptDescriptorTableHandlerAddress ((UINTN)InterruptType, NULL);\r
+  } else {\r
+    //\r
+    // Restore the original IDT handler address if InterruptHandler is NULL.\r
+    //\r
+    RestoreInterruptDescriptorTableHandlerAddress ((UINTN)InterruptType);\r
+  }\r
+\r
   ExternalVectorTable[InterruptType] = InterruptHandler;\r
   return EFI_SUCCESS;\r
 }\r
@@ -563,19 +590,28 @@ CpuGetTimerValue (
 \r
 \r
 /**\r
-  Set memory cacheability attributes for given range of memeory.\r
-\r
-  @param  This                   Protocol instance structure\r
-  @param  BaseAddress            Specifies the start address of the\r
-                                 memory range\r
-  @param  Length                 Specifies the length of the memory range\r
-  @param  Attributes             The memory cacheability for the memory range\r
-\r
-  @retval EFI_SUCCESS            If the cacheability of that memory range is\r
-                                 set successfully\r
-  @retval EFI_UNSUPPORTED        If the desired operation cannot be done\r
-  @retval EFI_INVALID_PARAMETER  The input parameter is not correct,\r
-                                 such as Length = 0\r
+  Implementation of SetMemoryAttributes() service of CPU Architecture Protocol.\r
+\r
+  This function modifies the attributes for the memory region specified by BaseAddress and\r
+  Length from their current attributes to the attributes specified by Attributes.\r
+\r
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.\r
+  @param  BaseAddress      The physical address that is the start address of a memory region.\r
+  @param  Length           The size in bytes of the memory region.\r
+  @param  Attributes       The bit mask of attributes to set for the memory region.\r
+\r
+  @retval EFI_SUCCESS           The attributes were set for the memory region.\r
+  @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by\r
+                                BaseAddress and Length cannot be modified.\r
+  @retval EFI_INVALID_PARAMETER Length is zero.\r
+                                Attributes specified an illegal combination of attributes that\r
+                                cannot be set together.\r
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of\r
+                                the memory resource range.\r
+  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory\r
+                                resource range specified by BaseAddress and Length.\r
+                                The bit mask of attributes is not support for the memory resource\r
+                                range specified by BaseAddress and Length.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -590,7 +626,9 @@ CpuSetMemoryAttributes (
   RETURN_STATUS             Status;\r
   MTRR_MEMORY_CACHE_TYPE    CacheType;\r
 \r
-  DEBUG((EFI_D_ERROR, "CpuAp: SetMemorySpaceAttributes(BA=%08x, Len=%08x, Attr=%08x)\n", BaseAddress, Length, Attributes));\r
+  if (!IsMtrrSupported ()) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
 \r
   //\r
   // If this function is called because GCD SetMemorySpaceAttributes () is called\r
@@ -599,9 +637,9 @@ CpuSetMemoryAttributes (
   // to avoid unnecessary computing.\r
   //\r
   if (mIsFlushingGCD) {\r
-    DEBUG((EFI_D_ERROR, "  Flushing GCD\n"));\r
-      return EFI_SUCCESS;\r
-    }\r
+    DEBUG((EFI_D_INFO, "  Flushing GCD\n"));\r
+    return EFI_SUCCESS;\r
+  }\r
 \r
   switch (Attributes) {\r
   case EFI_MEMORY_UC:\r
@@ -624,21 +662,24 @@ CpuSetMemoryAttributes (
     CacheType = CacheWriteBack;\r
     break;\r
 \r
-  default:\r
+  case EFI_MEMORY_UCE:\r
+  case EFI_MEMORY_RP:\r
+  case EFI_MEMORY_XP:\r
+  case EFI_MEMORY_RUNTIME:\r
     return EFI_UNSUPPORTED;\r
+\r
+  default:\r
+    return EFI_INVALID_PARAMETER;\r
   }\r
   //\r
   // call MTRR libary function\r
   //\r
-  DEBUG((EFI_D_ERROR, "  MtrrSetMemoryAttribute()\n"));\r
-  Status = MtrrSetMemoryAttribute(\r
+  Status = MtrrSetMemoryAttribute (\r
              BaseAddress,\r
              Length,\r
              CacheType\r
              );\r
 \r
-  MtrrDebugPrintAllMtrrs ();\r
-\r
   return (EFI_STATUS) Status;\r
 }\r
 \r
@@ -672,11 +713,11 @@ InitializeMtrrMask (
 }\r
 \r
 /**\r
-  Gets GCD Mem Space type from MTRR Type\r
+  Gets GCD Mem Space type from MTRR Type.\r
 \r
-  This function gets GCD Mem Space type from MTRR Type\r
+  This function gets GCD Mem Space type from MTRR Type.\r
 \r
-  @param  MtrrAttribute  MTRR memory type\r
+  @param  MtrrAttributes  MTRR memory type\r
 \r
   @return GCD Mem Space type\r
 \r
@@ -854,9 +895,17 @@ RefreshGcdMemoryAttributes (
   UINT64                              DefaultAttributes;\r
   VARIABLE_MTRR                       VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
   MTRR_FIXED_SETTINGS                 MtrrFixedSettings;\r
+  UINT32                              FirmwareVariableMtrrCount;\r
+  UINT8                               DefaultMemoryType;\r
 \r
-//  mIsFlushingGCD = TRUE;\r
-  mIsFlushingGCD = FALSE;\r
+  if (!IsMtrrSupported ()) {\r
+    return;\r
+  }\r
+\r
+  FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
+  ASSERT (FirmwareVariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+\r
+  mIsFlushingGCD = TRUE;\r
   MemorySpaceMap = NULL;\r
 \r
   //\r
@@ -882,7 +931,8 @@ RefreshGcdMemoryAttributes (
                   );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-  DefaultAttributes = GetMemorySpaceAttributeFromMtrrType (mDefaultMemoryType);\r
+  DefaultMemoryType = (UINT8) MtrrGetDefaultMemoryType ();\r
+  DefaultAttributes = GetMemorySpaceAttributeFromMtrrType (DefaultMemoryType);\r
 \r
   //\r
   // Set default attributes to all spaces.\r
@@ -902,7 +952,7 @@ RefreshGcdMemoryAttributes (
   //\r
   // Go for variable MTRRs with WB attribute\r
   //\r
-  for (Index = 0; Index < FIRMWARE_VARIABLE_MTRR_NUMBER; Index++) {\r
+  for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
     if (VariableMtrr[Index].Valid &&\r
         VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) {\r
       SetGcdMemorySpaceAttributes (\r
@@ -914,12 +964,14 @@ RefreshGcdMemoryAttributes (
         );\r
     }\r
   }\r
+\r
   //\r
-  // Go for variable MTRRs with Non-WB attribute\r
+  // Go for variable MTRRs with the attribute except for WB and UC attributes\r
   //\r
-  for (Index = 0; Index < FIRMWARE_VARIABLE_MTRR_NUMBER; Index++) {\r
+  for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
     if (VariableMtrr[Index].Valid &&\r
-        VariableMtrr[Index].Type != MTRR_CACHE_WRITE_BACK) {\r
+        VariableMtrr[Index].Type != MTRR_CACHE_WRITE_BACK &&\r
+        VariableMtrr[Index].Type != MTRR_CACHE_UNCACHEABLE) {\r
       Attributes = GetMemorySpaceAttributeFromMtrrType ((UINT8) VariableMtrr[Index].Type);\r
       SetGcdMemorySpaceAttributes (\r
         MemorySpaceMap,\r
@@ -931,6 +983,22 @@ RefreshGcdMemoryAttributes (
     }\r
   }\r
 \r
+  //\r
+  // Go for variable MTRRs with UC attribute\r
+  //\r
+  for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
+    if (VariableMtrr[Index].Valid &&\r
+        VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE) {\r
+      SetGcdMemorySpaceAttributes (\r
+        MemorySpaceMap,\r
+        NumberOfDescriptors,\r
+        VariableMtrr[Index].BaseAddress,\r
+        VariableMtrr[Index].Length,\r
+        EFI_MEMORY_UC\r
+        );\r
+    }\r
+  }\r
+\r
   //\r
   // Go for fixed MTRRs\r
   //\r
@@ -992,39 +1060,123 @@ RefreshGcdMemoryAttributes (
   mIsFlushingGCD = FALSE;\r
 }\r
 \r
+/**\r
+  Set Interrupt Descriptor Table Handler Address.\r
+\r
+  @param Index        The Index of the interrupt descriptor table handle.\r
+  @param Handler      Handler address.\r
+\r
+**/\r
+VOID\r
+SetInterruptDescriptorTableHandlerAddress (\r
+  IN UINTN Index,\r
+  IN VOID  *Handler  OPTIONAL\r
+  )\r
+{\r
+  UINTN                     UintnHandler;\r
+\r
+  if (Handler != NULL) {\r
+    UintnHandler = (UINTN) Handler;\r
+  } else {\r
+    UintnHandler = ((UINTN) AsmIdtVector00) + (8 * Index);\r
+  }\r
+\r
+  gIdtTable[Index].Bits.OffsetLow   = (UINT16)UintnHandler;\r
+  gIdtTable[Index].Bits.Reserved_0  = 0;\r
+  gIdtTable[Index].Bits.GateType    = IA32_IDT_GATE_TYPE_INTERRUPT_32;\r
+  gIdtTable[Index].Bits.OffsetHigh  = (UINT16)(UintnHandler >> 16);\r
+#if defined (MDE_CPU_X64)\r
+  gIdtTable[Index].Bits.OffsetUpper = (UINT32)(UintnHandler >> 32);\r
+  gIdtTable[Index].Bits.Reserved_1  = 0;\r
+#endif\r
+}\r
+\r
+/**\r
+  Restore original Interrupt Descriptor Table Handler Address.\r
+\r
+  @param Index        The Index of the interrupt descriptor table handle.\r
+\r
+**/\r
+VOID\r
+RestoreInterruptDescriptorTableHandlerAddress (\r
+  IN UINTN       Index\r
+  )\r
+{\r
+  if (Index < mOrigIdtEntryCount) {\r
+    gIdtTable[Index].Bits.OffsetLow   = mOrigIdtEntry[Index].Bits.OffsetLow;\r
+    gIdtTable[Index].Bits.OffsetHigh  = mOrigIdtEntry[Index].Bits.OffsetHigh;\r
+#if defined (MDE_CPU_X64)\r
+    gIdtTable[Index].Bits.OffsetUpper = mOrigIdtEntry[Index].Bits.OffsetUpper;\r
+#endif\r
+  }\r
+}\r
 \r
 /**\r
   Initialize Interrupt Descriptor Table for interrupt handling.\r
 \r
 **/\r
-STATIC\r
 VOID\r
 InitInterruptDescriptorTable (\r
   VOID\r
   )\r
 {\r
-  EFI_STATUS      Status;\r
-  VOID            *IdtPtrAlignmentBuffer;\r
-  IA32_DESCRIPTOR *IdtPtr;\r
-  UINTN           Index;\r
-  UINTN           CurrentHandler;\r
+  EFI_STATUS                Status;\r
+  IA32_DESCRIPTOR           OldIdtPtr;\r
+  IA32_IDT_GATE_DESCRIPTOR  *OldIdt;\r
+  UINTN                     OldIdtSize;\r
+  VOID                      *IdtPtrAlignmentBuffer;\r
+  IA32_DESCRIPTOR           *IdtPtr;\r
+  UINTN                     Index;\r
+  UINT16                    CurrentCs;\r
+  VOID                      *IntHandler;\r
 \r
   SetMem (ExternalVectorTable, sizeof(ExternalVectorTable), 0);\r
 \r
+  //\r
+  // Get original IDT address and size.\r
+  //\r
+  AsmReadIdtr ((IA32_DESCRIPTOR *) &OldIdtPtr);\r
+\r
+  if ((OldIdtPtr.Base != 0) && ((OldIdtPtr.Limit & 7) == 7)) {\r
+    OldIdt = (IA32_IDT_GATE_DESCRIPTOR*) OldIdtPtr.Base;\r
+    OldIdtSize = (OldIdtPtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);\r
+    //\r
+    // Save original IDT entry and IDT entry count.\r
+    //\r
+    mOrigIdtEntry = AllocateCopyPool (OldIdtPtr.Limit + 1, (VOID *) OldIdtPtr.Base);\r
+    ASSERT (mOrigIdtEntry != NULL);\r
+    mOrigIdtEntryCount = (UINT16) OldIdtSize;\r
+  } else {\r
+    OldIdt = NULL;\r
+    OldIdtSize = 0;\r
+  }\r
+\r
   //\r
   // Intialize IDT\r
   //\r
-  CurrentHandler = (UINTN)AsmIdtVector00;\r
-  for (Index = 0; Index < INTERRUPT_VECTOR_NUMBER; Index ++, CurrentHandler += 0x08) {\r
-    gIdtTable[Index].Bits.OffsetLow   = (UINT16)CurrentHandler;\r
-    gIdtTable[Index].Bits.Selector    = AsmReadCs();\r
-    gIdtTable[Index].Bits.Reserved_0  = 0;\r
-    gIdtTable[Index].Bits.GateType    = IA32_IDT_GATE_TYPE_INTERRUPT_32;\r
-    gIdtTable[Index].Bits.OffsetHigh  = (UINT16)(CurrentHandler >> 16);\r
+  CurrentCs = AsmReadCs();\r
+  for (Index = 0; Index < INTERRUPT_VECTOR_NUMBER; Index ++) {\r
+    //\r
+    // If the old IDT had a handler for this interrupt, then\r
+    // preserve it.\r
+    //\r
+    if (Index < OldIdtSize) {\r
+      IntHandler =\r
+        (VOID*) (\r
+          OldIdt[Index].Bits.OffsetLow +\r
+          (((UINTN) OldIdt[Index].Bits.OffsetHigh) << 16)\r
 #if defined (MDE_CPU_X64)\r
-    gIdtTable[Index].Bits.OffsetUpper = (UINT32)(CurrentHandler >> 32);\r
-    gIdtTable[Index].Bits.Reserved_1  = 0;\r
+            + (((UINTN) OldIdt[Index].Bits.OffsetUpper) << 32)\r
 #endif\r
+          );\r
+    } else {\r
+      IntHandler = NULL;\r
+    }\r
+\r
+    gIdtTable[Index].Bits.Selector    = CurrentCs;\r
+    gIdtTable[Index].Bits.Reserved_0  = 0;\r
+    gIdtTable[Index].Bits.GateType    = IA32_IDT_GATE_TYPE_INTERRUPT_32;\r
+    SetInterruptDescriptorTableHandlerAddress (Index, IntHandler);\r
   }\r
 \r
   //\r
@@ -1033,14 +1185,16 @@ InitInterruptDescriptorTable (
   IdtPtrAlignmentBuffer = AllocatePool (sizeof (*IdtPtr) + 16);\r
   IdtPtr = ALIGN_POINTER (IdtPtrAlignmentBuffer, 16);\r
   IdtPtr->Base = (UINT32)(((UINTN)(VOID*) gIdtTable) & (BASE_4GB-1));\r
-  IdtPtr->Limit = sizeof (gIdtTable) - 1;\r
+  IdtPtr->Limit = (UINT16) (sizeof (gIdtTable) - 1);\r
+\r
   AsmWriteIdtr (IdtPtr);\r
+\r
   FreePool (IdtPtrAlignmentBuffer);\r
 \r
   //\r
   // Initialize Exception Handlers\r
   //\r
-  for (Index = 0; Index < 32; Index++) {\r
+  for (Index = OldIdtSize; Index < 32; Index++) {\r
     Status = CpuRegisterInterruptHandler (&gCpu, Index, CommonExceptionHandler);\r
     ASSERT_EFI_ERROR (Status);\r
   }\r
@@ -1053,6 +1207,25 @@ InitInterruptDescriptorTable (
 }\r
 \r
 \r
+/**\r
+  Callback function for idle events.\r
+\r
+  @param  Event                 Event whose notification function is being invoked.\r
+  @param  Context               The pointer to the notification function's context,\r
+                                which is implementation-dependent.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+IdleLoopEventCallback (\r
+  IN EFI_EVENT                Event,\r
+  IN VOID                     *Context\r
+  )\r
+{\r
+  CpuSleep ();\r
+}\r
+\r
+\r
 /**\r
   Initialize the state information for the CPU Architectural Protocol.\r
 \r
@@ -1072,6 +1245,9 @@ InitializeCpu (
   )\r
 {\r
   EFI_STATUS  Status;\r
+  EFI_EVENT   IdleLoopEvent;\r
+\r
+  InitializeFloatingPointUnits ();\r
 \r
   //\r
   // Make sure interrupts are disabled\r
@@ -1088,6 +1264,11 @@ InitializeCpu (
   //\r
   InitInterruptDescriptorTable ();\r
 \r
+  //\r
+  // Enable the local APIC for Virtual Wire Mode.\r
+  //\r
+  ProgramVirtualWireMode ();\r
+\r
   //\r
   // Install CPU Architectural Protocol\r
   //\r
@@ -1103,6 +1284,19 @@ InitializeCpu (
   //\r
   RefreshGcdMemoryAttributes ();\r
 \r
+  //\r
+  // Setup a callback for idle events\r
+  //\r
+  Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  IdleLoopEventCallback,\r
+                  NULL,\r
+                  &gIdleLoopEventGuid,\r
+                  &IdleLoopEvent\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
   return Status;\r
 }\r
 \r