]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.c
UefiPayloadPkg/UefiPayloadEntry: Improve bootloader memrange parsing
[mirror_edk2.git] / UefiPayloadPkg / UefiPayloadEntry / UefiPayloadEntry.c
index 8c6f7e326fc09ef731741b9edc4762f1c2024a89..91b3a874139dca17c52076682ea6ee7ce9d6e592 100644 (file)
 \r
 #include "UefiPayloadEntry.h"\r
 \r
+STATIC UINT32 mTopOfLowerUsableDram = 0;\r
+\r
 /**\r
    Callback function to build resource descriptor HOB\r
 \r
    This function build a HOB based on the memory map entry info.\r
+   It creates only EFI_RESOURCE_MEMORY_MAPPED_IO and EFI_RESOURCE_MEMORY_RESERVED\r
+   resources.\r
+\r
+   @param MemoryMapEntry         Memory map entry info got from bootloader.\r
+   @param Params                 A pointer to ACPI_BOARD_INFO.\r
+\r
+  @retval EFI_SUCCESS            Successfully build a HOB.\r
+  @retval EFI_INVALID_PARAMETER  Invalid parameter provided.\r
+**/\r
+EFI_STATUS\r
+MemInfoCallbackMmio (\r
+  IN MEMROY_MAP_ENTRY          *MemoryMapEntry,\r
+  IN VOID                      *Params\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS         Base;\r
+  EFI_RESOURCE_TYPE            Type;\r
+  UINT64                       Size;\r
+  EFI_RESOURCE_ATTRIBUTE_TYPE  Attribue;\r
+  ACPI_BOARD_INFO              *AcpiBoardInfo;\r
+\r
+  AcpiBoardInfo = (ACPI_BOARD_INFO *)Params;\r
+  if (AcpiBoardInfo == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Skip types already handled in MemInfoCallback\r
+  //\r
+  if (MemoryMapEntry->Type == E820_RAM || MemoryMapEntry->Type == E820_ACPI) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (MemoryMapEntry->Base == AcpiBoardInfo->PcieBaseAddress) {\r
+    //\r
+    // MMCONF is always MMIO\r
+    //\r
+    Type = EFI_RESOURCE_MEMORY_MAPPED_IO;\r
+  } else if (MemoryMapEntry->Base < mTopOfLowerUsableDram) {\r
+    //\r
+    // It's in DRAM and thus must be reserved\r
+    //\r
+    Type = EFI_RESOURCE_MEMORY_RESERVED;\r
+  } else if ((MemoryMapEntry->Base < 0x100000000ULL) && (MemoryMapEntry->Base >= mTopOfLowerUsableDram)) {\r
+    //\r
+    // It's not in DRAM, must be MMIO\r
+    //\r
+    Type = EFI_RESOURCE_MEMORY_MAPPED_IO;\r
+  } else {\r
+    Type = EFI_RESOURCE_MEMORY_RESERVED;\r
+  }\r
+\r
+  Base    = MemoryMapEntry->Base;\r
+  Size    = MemoryMapEntry->Size;\r
+\r
+  Attribue = EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
+             EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
+             EFI_RESOURCE_ATTRIBUTE_TESTED |\r
+             EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
+             EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
+             EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
+             EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE;\r
+\r
+  BuildResourceDescriptorHob (Type, Attribue, (EFI_PHYSICAL_ADDRESS)Base, Size);\r
+  DEBUG ((DEBUG_INFO , "buildhob: base = 0x%lx, size = 0x%lx, type = 0x%x\n", Base, Size, Type));\r
+\r
+  if (MemoryMapEntry->Type == E820_UNUSABLE ||\r
+    MemoryMapEntry->Type == E820_DISABLED) {\r
+    BuildMemoryAllocationHob (Base, Size, EfiUnusableMemory);\r
+  } else if (MemoryMapEntry->Type == E820_PMEM) {\r
+    BuildMemoryAllocationHob (Base, Size, EfiPersistentMemory);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+   Callback function to find TOLUD (Top of Lower Usable DRAM)\r
+\r
+   Estimate where TOLUD (Top of Lower Usable DRAM) resides. The exact position\r
+   would require platform specific code.\r
+\r
+   @param MemoryMapEntry         Memory map entry info got from bootloader.\r
+   @param Params                 Not used for now.\r
+\r
+  @retval EFI_SUCCESS            Successfully updated mTopOfLowerUsableDram.\r
+**/\r
+EFI_STATUS\r
+FindToludCallback (\r
+  IN MEMROY_MAP_ENTRY          *MemoryMapEntry,\r
+  IN VOID                      *Params\r
+  )\r
+{\r
+  //\r
+  // This code assumes that the memory map on this x86 machine below 4GiB is continous\r
+  // until TOLUD. In addition it assumes that the bootloader provided memory tables have\r
+  // no "holes" and thus the first memory range not covered by e820 marks the end of\r
+  // usable DRAM. In addition it's assumed that every reserved memory region touching\r
+  // usable RAM is also covering DRAM, everything else that is marked reserved thus must be\r
+  // MMIO not detectable by bootloader/OS\r
+  //\r
+\r
+  //\r
+  // Skip memory types not RAM or reserved\r
+  //\r
+  if ((MemoryMapEntry->Type == E820_UNUSABLE) || (MemoryMapEntry->Type == E820_DISABLED) ||\r
+    (MemoryMapEntry->Type == E820_PMEM)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Skip resources above 4GiB\r
+  //\r
+  if ((MemoryMapEntry->Base + MemoryMapEntry->Size) > 0x100000000ULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if ((MemoryMapEntry->Type == E820_RAM) || (MemoryMapEntry->Type == E820_ACPI) ||\r
+    (MemoryMapEntry->Type == E820_NVS)) {\r
+    //\r
+    // It's usable DRAM. Update TOLUD.\r
+    //\r
+    if (mTopOfLowerUsableDram < (MemoryMapEntry->Base + MemoryMapEntry->Size)) {\r
+      mTopOfLowerUsableDram = (UINT32)(MemoryMapEntry->Base + MemoryMapEntry->Size);\r
+    }\r
+  } else {\r
+    //\r
+    // It might be 'reserved DRAM' or 'MMIO'.\r
+    //\r
+    // If it touches usable DRAM at Base assume it's DRAM as well,\r
+    // as it could be bootloader installed tables, TSEG, GTT, ...\r
+    //\r
+    if (mTopOfLowerUsableDram == MemoryMapEntry->Base) {\r
+      mTopOfLowerUsableDram = (UINT32)(MemoryMapEntry->Base + MemoryMapEntry->Size);\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+   Callback function to build resource descriptor HOB\r
+\r
+   This function build a HOB based on the memory map entry info.\r
+   Only add EFI_RESOURCE_SYSTEM_MEMORY.\r
 \r
    @param MemoryMapEntry         Memory map entry info got from bootloader.\r
    @param Params                 Not used for now.\r
@@ -28,7 +177,16 @@ MemInfoCallback (
   UINT64                       Size;\r
   EFI_RESOURCE_ATTRIBUTE_TYPE  Attribue;\r
 \r
-  Type    = (MemoryMapEntry->Type == 1) ? EFI_RESOURCE_SYSTEM_MEMORY : EFI_RESOURCE_MEMORY_RESERVED;\r
+  //\r
+  // Skip everything not known to be usable DRAM.\r
+  // It will be added later.\r
+  //\r
+  if ((MemoryMapEntry->Type != E820_RAM) && (MemoryMapEntry->Type != E820_ACPI) &&\r
+    (MemoryMapEntry->Type != E820_NVS)) {\r
+    return RETURN_SUCCESS;\r
+  }\r
+\r
+  Type    = EFI_RESOURCE_SYSTEM_MEMORY;\r
   Base    = MemoryMapEntry->Base;\r
   Size    = MemoryMapEntry->Size;\r
 \r
@@ -40,7 +198,7 @@ MemInfoCallback (
              EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
              EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE;\r
 \r
-  if (Base >= BASE_4GB ) {\r
+  if (Base >= BASE_4GB) {\r
     // Remove tested attribute to avoid DXE core to dispatch driver to memory above 4GB\r
     Attribue &= ~EFI_RESOURCE_ATTRIBUTE_TESTED;\r
   }\r
@@ -48,6 +206,12 @@ MemInfoCallback (
   BuildResourceDescriptorHob (Type, Attribue, (EFI_PHYSICAL_ADDRESS)Base, Size);\r
   DEBUG ((DEBUG_INFO , "buildhob: base = 0x%lx, size = 0x%lx, type = 0x%x\n", Base, Size, Type));\r
 \r
+  if (MemoryMapEntry->Type == E820_ACPI) {\r
+    BuildMemoryAllocationHob (Base, Size, EfiACPIReclaimMemory);\r
+  } else if (MemoryMapEntry->Type == E820_NVS) {\r
+    BuildMemoryAllocationHob (Base, Size, EfiACPIMemoryNVS);\r
+  }\r
+\r
   return RETURN_SUCCESS;\r
 }\r
 \r
@@ -238,8 +402,19 @@ BuildHobFromBl (
   UNIVERSAL_PAYLOAD_ACPI_TABLE     *AcpiTableHob;\r
 \r
   //\r
-  // Parse memory info and build memory HOBs\r
+  // First find TOLUD\r
+  //\r
+  DEBUG ((DEBUG_INFO , "Guessing Top of Lower Usable DRAM:\n"));\r
+  Status = ParseMemoryInfo (FindToludCallback, NULL);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+  DEBUG ((DEBUG_INFO , "Assuming TOLUD = 0x%x\n", mTopOfLowerUsableDram));\r
+\r
+  //\r
+  // Parse memory info and build memory HOBs for Usable RAM\r
   //\r
+  DEBUG ((DEBUG_INFO , "Building ResourceDescriptorHobs for usable memory:\n"));\r
   Status = ParseMemoryInfo (MemInfoCallback, NULL);\r
   if (EFI_ERROR(Status)) {\r
     return Status;\r
@@ -310,6 +485,15 @@ BuildHobFromBl (
     DEBUG ((DEBUG_INFO, "Create acpi board info guid hob\n"));\r
   }\r
 \r
+  //\r
+  // Parse memory info and build memory HOBs for reserved DRAM and MMIO\r
+  //\r
+  DEBUG ((DEBUG_INFO , "Building ResourceDescriptorHobs for reserved memory:\n"));\r
+  Status = ParseMemoryInfo (MemInfoCallbackMmio, &AcpiBoardInfo);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
   //\r
   // Parse platform specific information.\r
   //\r