]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c
IntelFrameworkModulePkg/LegacyBios: Use macro to enable/disable page 0
[mirror_edk2.git] / IntelFrameworkModulePkg / Csm / LegacyBiosDxe / LegacyBios.c
index 194fee647be416b56779daca0491a53844d831ae..fca08a8fa26d4be275576f8b6156290f96a9e5fc 100644 (file)
@@ -1,6 +1,6 @@
 /** @file\r
 \r
-Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2017, 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
@@ -29,6 +29,19 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 //\r
 LEGACY_BIOS_INSTANCE  mPrivateData;\r
 \r
+//\r
+// The SMBIOS table in EfiRuntimeServicesData memory\r
+//\r
+VOID                  *mRuntimeSmbiosEntryPoint = NULL;\r
+\r
+//\r
+// The SMBIOS table in EfiReservedMemoryType memory\r
+//\r
+EFI_PHYSICAL_ADDRESS  mReserveSmbiosEntryPoint = 0;\r
+EFI_PHYSICAL_ADDRESS  mStructureTableAddress   = 0;\r
+UINTN                 mStructureTablePages     = 0;\r
+BOOLEAN               mEndOfDxe                = FALSE;\r
+\r
 /**\r
   Do an AllocatePages () of type AllocateMaxAddress for EfiBootServicesCode\r
   memory.\r
@@ -132,7 +145,7 @@ LegacyBiosGetLegacyRegion (
      );\r
 \r
   if (Regs.X.AX == 0) {\r
-    *LegacyMemoryAddress  = (VOID *) (UINTN) ((Regs.X.DS << 4) + Regs.X.BX);\r
+    *LegacyMemoryAddress  = (VOID *) (((UINTN) Regs.X.DS << 4) + Regs.X.BX);\r
     Status = EFI_SUCCESS;\r
   } else {\r
     Status = EFI_OUT_OF_RESOURCES;\r
@@ -661,6 +674,118 @@ GetPciInterfaceVersion (
   return PciInterfaceVersion;\r
 }\r
 \r
+/**\r
+  Callback function to calculate SMBIOS table size, and allocate memory for SMBIOS table.\r
+  SMBIOS table will be copied into EfiReservedMemoryType memory in legacy boot path.\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
+InstallSmbiosEventCallback (\r
+  IN EFI_EVENT                Event,\r
+  IN VOID                     *Context\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  SMBIOS_TABLE_ENTRY_POINT    *EntryPointStructure;\r
+  \r
+  //\r
+  // Get SMBIOS table from EFI configuration table\r
+  //\r
+  Status = EfiGetSystemConfigurationTable (\r
+            &gEfiSmbiosTableGuid,\r
+            &mRuntimeSmbiosEntryPoint\r
+            );\r
+  if ((EFI_ERROR (Status)) || (mRuntimeSmbiosEntryPoint == NULL)) {\r
+    return;\r
+  }\r
+  \r
+  EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *) mRuntimeSmbiosEntryPoint;\r
+\r
+  //\r
+  // Allocate memory for SMBIOS Entry Point Structure.\r
+  // CSM framework spec requires SMBIOS table below 4GB in EFI_TO_COMPATIBILITY16_BOOT_TABLE.\r
+  //\r
+  if (mReserveSmbiosEntryPoint == 0) {\r
+    //\r
+    // Entrypoint structure with fixed size is allocated only once.\r
+    //\r
+    mReserveSmbiosEntryPoint = SIZE_4GB - 1;\r
+    Status = gBS->AllocatePages (\r
+                    AllocateMaxAddress,\r
+                    EfiReservedMemoryType,\r
+                    EFI_SIZE_TO_PAGES ((UINTN) (EntryPointStructure->EntryPointLength)),\r
+                    &mReserveSmbiosEntryPoint\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      mReserveSmbiosEntryPoint = 0;\r
+      return;\r
+    }\r
+    DEBUG ((EFI_D_INFO, "Allocate memory for Smbios Entry Point Structure\n"));\r
+  }\r
+  \r
+  if ((mStructureTableAddress != 0) && \r
+      (mStructureTablePages < EFI_SIZE_TO_PAGES ((UINT32)EntryPointStructure->TableLength))) {\r
+    //\r
+    // If original buffer is not enough for the new SMBIOS table, free original buffer and re-allocate\r
+    //\r
+    gBS->FreePages (mStructureTableAddress, mStructureTablePages);\r
+    mStructureTableAddress = 0;\r
+    mStructureTablePages   = 0;\r
+    DEBUG ((EFI_D_INFO, "Original size is not enough. Re-allocate the memory.\n"));\r
+  }\r
+  \r
+  if (mStructureTableAddress == 0) {\r
+    //\r
+    // Allocate reserved memory below 4GB.\r
+    // Smbios spec requires the structure table is below 4GB.\r
+    //\r
+    mStructureTableAddress = SIZE_4GB - 1;\r
+    mStructureTablePages   = EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength);\r
+    Status = gBS->AllocatePages (\r
+                    AllocateMaxAddress,\r
+                    EfiReservedMemoryType,\r
+                    mStructureTablePages,\r
+                    &mStructureTableAddress\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      gBS->FreePages (\r
+        mReserveSmbiosEntryPoint, \r
+        EFI_SIZE_TO_PAGES ((UINTN) (EntryPointStructure->EntryPointLength))\r
+        );\r
+      mReserveSmbiosEntryPoint = 0;\r
+      mStructureTableAddress   = 0;\r
+      mStructureTablePages     = 0;\r
+      return;\r
+    }\r
+    DEBUG ((EFI_D_INFO, "Allocate memory for Smbios Structure Table\n"));\r
+  }\r
+}\r
+\r
+/**\r
+  Callback function to toggle EndOfDxe status. NULL pointer detection needs\r
+  this status to decide if it's necessary to change attributes of page 0.\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
+ToggleEndOfDxeStatus (\r
+  IN EFI_EVENT                Event,\r
+  IN VOID                     *Context\r
+  )\r
+{\r
+  mEndOfDxe = TRUE;\r
+  return;\r
+}\r
+\r
 /**\r
   Install Driver to produce Legacy BIOS protocol.\r
 \r
@@ -682,6 +807,7 @@ LegacyBiosInstall (
   LEGACY_BIOS_INSTANCE               *Private;\r
   EFI_TO_COMPATIBILITY16_INIT_TABLE  *EfiToLegacy16InitTable;\r
   EFI_PHYSICAL_ADDRESS               MemoryAddress;\r
+  EFI_PHYSICAL_ADDRESS               EbdaReservedBaseAddress;\r
   VOID                               *MemoryPtr;\r
   EFI_PHYSICAL_ADDRESS               MemoryAddressUnder1MB;\r
   UINTN                              Index;\r
@@ -695,6 +821,9 @@ LegacyBiosInstall (
   UINT32                             MemorySize;\r
   EFI_GCD_MEMORY_SPACE_DESCRIPTOR    Descriptor;\r
   UINT64                             Length;\r
+  UINT8                              *SecureBoot;\r
+  EFI_EVENT                          InstallSmbiosEvent;\r
+  EFI_EVENT                          EndOfDxeEvent;\r
 \r
   //\r
   // Load this driver's image to memory\r
@@ -704,6 +833,20 @@ LegacyBiosInstall (
     return Status;\r
   }\r
 \r
+  //\r
+  // When UEFI Secure Boot is enabled, CSM module will not start any more.\r
+  //\r
+  SecureBoot = NULL;\r
+  GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL);\r
+  if ((SecureBoot != NULL) && (*SecureBoot == SECURE_BOOT_MODE_ENABLE)) {\r
+    FreePool (SecureBoot);\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+  \r
+  if (SecureBoot != NULL) {\r
+    FreePool (SecureBoot);\r
+  }\r
+\r
   Private = &mPrivateData;\r
   ZeroMem (Private, sizeof (LEGACY_BIOS_INSTANCE));\r
 \r
@@ -843,8 +986,10 @@ LegacyBiosInstall (
   // Initialize region from 0x0000 to 4k. This initializes interrupt vector\r
   // range.\r
   //\r
-  gBS->SetMem ((VOID *) ClearPtr, 0x400, INITIAL_VALUE_BELOW_1K);\r
-  ZeroMem ((VOID *) ((UINTN)ClearPtr + 0x400), 0xC00);\r
+  ACCESS_PAGE0_CODE (\r
+    gBS->SetMem ((VOID *) ClearPtr, 0x400, INITIAL_VALUE_BELOW_1K);\r
+    ZeroMem ((VOID *) ((UINTN)ClearPtr + 0x400), 0xC00);\r
+  );\r
 \r
   //\r
   // Allocate pages for OPROM usage\r
@@ -865,17 +1010,29 @@ LegacyBiosInstall (
   //\r
   // Allocate all 32k chunks from 0x60000 ~ 0x88000 for Legacy OPROMs that\r
   // don't use PMM but look for zeroed memory. Note that various non-BBS\r
-  // SCSIs expect different areas to be free\r
+  // OpROMs expect different areas to be free\r
   //\r
-  for (MemStart = 0x60000; MemStart < 0x88000; MemStart += 0x1000) {\r
+  EbdaReservedBaseAddress = MemoryAddress;\r
+  MemoryAddress = PcdGet32 (PcdOpromReservedMemoryBase);\r
+  MemorySize    = PcdGet32 (PcdOpromReservedMemorySize);\r
+  //\r
+  // Check if base address and size for reserved memory are 4KB aligned.\r
+  //\r
+  ASSERT ((MemoryAddress & 0xFFF) == 0);\r
+  ASSERT ((MemorySize & 0xFFF) == 0);\r
+  //\r
+  // Check if the reserved memory is below EBDA reserved range.\r
+  //\r
+  ASSERT ((MemoryAddress < EbdaReservedBaseAddress) && ((MemoryAddress + MemorySize - 1) < EbdaReservedBaseAddress));\r
+  for (MemStart = MemoryAddress; MemStart < MemoryAddress + MemorySize; MemStart += 0x1000) {\r
     Status = AllocateLegacyMemory (\r
                AllocateAddress,\r
                MemStart,\r
                1,\r
-               &MemoryAddress\r
+               &StartAddress\r
                );\r
     if (!EFI_ERROR (Status)) {\r
-      MemoryPtr = (VOID *) ((UINTN) MemoryAddress);\r
+      MemoryPtr = (VOID *) ((UINTN) StartAddress);\r
       ZeroMem (MemoryPtr, 0x1000);\r
     } else {\r
       DEBUG ((EFI_D_ERROR, "WARNING: Allocate legacy memory fail for SCSI card - %x\n", MemStart));\r
@@ -922,21 +1079,32 @@ LegacyBiosInstall (
   EfiToLegacy16InitTable->LowPmmMemory            = (UINT32) MemoryAddressUnder1MB;\r
   EfiToLegacy16InitTable->LowPmmMemorySizeInBytes = MemorySize;\r
 \r
+  MemorySize = PcdGet32 (PcdHighPmmMemorySize);\r
+  ASSERT ((MemorySize & 0xFFF) == 0);\r
   //\r
   // Allocate high PMM Memory under 16 MB\r
-  //\r
-  MemorySize = PcdGet32 (PcdHighPmmMemorySize);\r
-  ASSERT ((MemorySize & 0xFFF) == 0);    \r
+  //   \r
   Status = AllocateLegacyMemory (\r
              AllocateMaxAddress,\r
              0x1000000,\r
              EFI_SIZE_TO_PAGES (MemorySize),\r
              &MemoryAddress\r
              );\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // If it fails, allocate high PMM Memory under 4GB\r
+    //   \r
+    Status = AllocateLegacyMemory (\r
+               AllocateMaxAddress,\r
+               0xFFFFFFFF,\r
+               EFI_SIZE_TO_PAGES (MemorySize),\r
+               &MemoryAddress\r
+               );    \r
+  }\r
   if (!EFI_ERROR (Status)) {\r
     EfiToLegacy16InitTable->HiPmmMemory            = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress;\r
     EfiToLegacy16InitTable->HiPmmMemorySizeInBytes = MemorySize;\r
-  }\r
+  } \r
 \r
   //\r
   //  ShutdownAPs();\r
@@ -960,16 +1128,51 @@ LegacyBiosInstall (
   //\r
   // Save Unexpected interrupt vector so can restore it just prior to boot\r
   //\r
-  BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);\r
-  Private->BiosUnexpectedInt = BaseVectorMaster[0];\r
-  IntRedirCode = (UINT32) (UINTN) Private->IntThunk->InterruptRedirectionCode;\r
-  for (Index = 0; Index < 8; Index++) {\r
-    BaseVectorMaster[Index] = (EFI_SEGMENT (IntRedirCode + Index * 4) << 16) | EFI_OFFSET (IntRedirCode + Index * 4);\r
-  }\r
+  ACCESS_PAGE0_CODE (\r
+    BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);\r
+    Private->BiosUnexpectedInt = BaseVectorMaster[0];\r
+    IntRedirCode = (UINT32) (UINTN) Private->IntThunk->InterruptRedirectionCode;\r
+    for (Index = 0; Index < 8; Index++) {\r
+      BaseVectorMaster[Index] = (EFI_SEGMENT (IntRedirCode + Index * 4) << 16) | EFI_OFFSET (IntRedirCode + Index * 4);\r
+    }\r
+  );\r
+\r
   //\r
   // Save EFI value\r
   //\r
   Private->ThunkSeg = (UINT16) (EFI_SEGMENT (IntRedirCode));\r
+  \r
+  //\r
+  // Allocate reserved memory for SMBIOS table used in legacy boot if SMBIOS table exists\r
+  //\r
+  InstallSmbiosEventCallback (NULL, NULL);\r
+\r
+  //\r
+  // Create callback function to update the size of reserved memory after LegacyBiosDxe starts\r
+  //\r
+  Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  InstallSmbiosEventCallback,\r
+                  NULL,\r
+                  &gEfiSmbiosTableGuid,\r
+                  &InstallSmbiosEvent\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);  \r
+\r
+  //\r
+  // Create callback to update status of EndOfDxe, which is needed by NULL\r
+  // pointer detection\r
+  //\r
+  Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  ToggleEndOfDxeStatus,\r
+                  NULL,\r
+                  &gEfiEndOfDxeEventGroupGuid,\r
+                  &EndOfDxeEvent\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
 \r
   //\r
   // Make a new handle and install the protocol\r