]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiPayloadPkg/Library/CbParseLib/CbParseLib.c
UefiPayloadPkg: Enhance UEFI payload for coreboot and Slim Bootloader
[mirror_edk2.git] / UefiPayloadPkg / Library / CbParseLib / CbParseLib.c
diff --git a/UefiPayloadPkg/Library/CbParseLib/CbParseLib.c b/UefiPayloadPkg/Library/CbParseLib/CbParseLib.c
new file mode 100644 (file)
index 0000000..4e23cff
--- /dev/null
@@ -0,0 +1,560 @@
+/** @file\r
+  This library will parse the coreboot table in memory and extract those required\r
+  information.\r
+\r
+  Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <Uefi/UefiBaseType.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/BlParseLib.h>\r
+#include <IndustryStandard/Acpi.h>\r
+#include <Coreboot.h>\r
+\r
+\r
+/**\r
+  Convert a packed value from cbuint64 to a UINT64 value.\r
+\r
+  @param  val      The pointer to packed data.\r
+\r
+  @return          the UNIT64 value after conversion.\r
+\r
+**/\r
+UINT64\r
+cb_unpack64 (\r
+  IN struct cbuint64 val\r
+  )\r
+{\r
+  return LShiftU64 (val.hi, 32) | val.lo;\r
+}\r
+\r
+\r
+/**\r
+  Returns the sum of all elements in a buffer of 16-bit values.  During\r
+  calculation, the carry bits are also been added.\r
+\r
+  @param  Buffer      The pointer to the buffer to carry out the sum operation.\r
+  @param  Length      The size, in bytes, of Buffer.\r
+\r
+  @return Sum         The sum of Buffer with carry bits included during additions.\r
+\r
+**/\r
+UINT16\r
+CbCheckSum16 (\r
+  IN UINT16   *Buffer,\r
+  IN UINTN    Length\r
+  )\r
+{\r
+  UINT32      Sum;\r
+  UINT32      TmpValue;\r
+  UINTN       Idx;\r
+  UINT8       *TmpPtr;\r
+\r
+  Sum = 0;\r
+  TmpPtr = (UINT8 *)Buffer;\r
+  for(Idx = 0; Idx < Length; Idx++) {\r
+    TmpValue  = TmpPtr[Idx];\r
+    if (Idx % 2 == 1) {\r
+      TmpValue <<= 8;\r
+    }\r
+\r
+    Sum += TmpValue;\r
+\r
+    // Wrap\r
+    if (Sum >= 0x10000) {\r
+      Sum = (Sum + (Sum >> 16)) & 0xFFFF;\r
+    }\r
+  }\r
+\r
+  return (UINT16)((~Sum) & 0xFFFF);\r
+}\r
+\r
+\r
+/**\r
+  Check the coreboot table if it is valid.\r
+\r
+  @param  Header            Pointer to coreboot table\r
+\r
+  @retval TRUE              The coreboot table is valid.\r
+  @retval Others            The coreboot table is not valid.\r
+\r
+**/\r
+BOOLEAN\r
+IsValidCbTable (\r
+  IN struct cb_header   *Header\r
+  )\r
+{\r
+  UINT16                 CheckSum;\r
+\r
+  if ((Header == NULL) || (Header->table_bytes == 0)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (Header->signature != CB_HEADER_SIGNATURE) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Check the checksum of the coreboot table header\r
+  //\r
+  CheckSum = CbCheckSum16 ((UINT16 *)Header, sizeof (*Header));\r
+  if (CheckSum != 0) {\r
+    DEBUG ((DEBUG_ERROR, "Invalid coreboot table header checksum\n"));\r
+    return FALSE;\r
+  }\r
+\r
+  CheckSum = CbCheckSum16 ((UINT16 *)((UINT8 *)Header + sizeof (*Header)), Header->table_bytes);\r
+  if (CheckSum != Header->table_checksum) {\r
+    DEBUG ((DEBUG_ERROR, "Incorrect checksum of all the coreboot table entries\n"));\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  This function retrieves the parameter base address from boot loader.\r
+\r
+  This function will get bootloader specific parameter address for UEFI payload.\r
+  e.g. HobList pointer for Slim Bootloader, and coreboot table header for Coreboot.\r
+\r
+  @retval NULL            Failed to find the GUID HOB.\r
+  @retval others          GUIDed HOB data pointer.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+GetParameterBase (\r
+  VOID\r
+  )\r
+{\r
+  struct cb_header   *Header;\r
+  struct cb_record   *Record;\r
+  UINT8              *TmpPtr;\r
+  UINT8              *CbTablePtr;\r
+  UINTN              Idx;\r
+\r
+  //\r
+  // coreboot could pass coreboot table to UEFI payload\r
+  //\r
+  Header = (struct cb_header *)(UINTN)GET_BOOTLOADER_PARAMETER ();\r
+  if (IsValidCbTable (Header)) {\r
+    return Header;\r
+  }\r
+\r
+  //\r
+  // Find simplified coreboot table in memory range 0 ~ 4KB.\r
+  // Some GCC version does not allow directly access to NULL pointer,\r
+  // so start the search from 0x10 instead.\r
+  //\r
+  for (Idx = 16; Idx < 4096; Idx += 16) {\r
+    Header = (struct cb_header *)Idx;\r
+    if (Header->signature == CB_HEADER_SIGNATURE) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Idx >= 4096) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Check the coreboot header\r
+  //\r
+  if (!IsValidCbTable (Header)) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Find full coreboot table in high memory\r
+  //\r
+  CbTablePtr = NULL;\r
+  TmpPtr = (UINT8 *)Header + Header->header_bytes;\r
+  for (Idx = 0; Idx < Header->table_entries; Idx++) {\r
+    Record = (struct cb_record *)TmpPtr;\r
+    if (Record->tag == CB_TAG_FORWARD) {\r
+      CbTablePtr = (VOID *)(UINTN)((struct cb_forward *)(UINTN)Record)->forward;\r
+      break;\r
+    }\r
+    TmpPtr += Record->size;\r
+  }\r
+\r
+  //\r
+  // Check the coreboot header in high memory\r
+  //\r
+  if (!IsValidCbTable ((struct cb_header *)CbTablePtr)) {\r
+    return NULL;\r
+  }\r
+\r
+  SET_BOOTLOADER_PARAMETER ((UINT32)(UINTN)CbTablePtr);\r
+\r
+  return CbTablePtr;\r
+}\r
+\r
+\r
+/**\r
+  Find coreboot record with given Tag.\r
+\r
+  @param  Tag                The tag id to be found\r
+\r
+  @retval NULL              The Tag is not found.\r
+  @retval Others            The pointer to the record found.\r
+\r
+**/\r
+VOID *\r
+FindCbTag (\r
+  IN  UINT32         Tag\r
+  )\r
+{\r
+  struct cb_header   *Header;\r
+  struct cb_record   *Record;\r
+  UINT8              *TmpPtr;\r
+  UINT8              *TagPtr;\r
+  UINTN              Idx;\r
+\r
+  Header = (struct cb_header *) GetParameterBase ();\r
+\r
+  TagPtr = NULL;\r
+  TmpPtr = (UINT8 *)Header + Header->header_bytes;\r
+  for (Idx = 0; Idx < Header->table_entries; Idx++) {\r
+    Record = (struct cb_record *)TmpPtr;\r
+    if (Record->tag == Tag) {\r
+      TagPtr = TmpPtr;\r
+      break;\r
+    }\r
+    TmpPtr += Record->size;\r
+  }\r
+\r
+  return TagPtr;\r
+}\r
+\r
+\r
+/**\r
+  Find the given table with TableId from the given coreboot memory Root.\r
+\r
+  @param  Root               The coreboot memory table to be searched in\r
+  @param  TableId            Table id to be found\r
+  @param  MemTable           To save the base address of the memory table found\r
+  @param  MemTableSize       To save the size of memory table found\r
+\r
+  @retval RETURN_SUCCESS            Successfully find out the memory table.\r
+  @retval RETURN_INVALID_PARAMETER  Invalid input parameters.\r
+  @retval RETURN_NOT_FOUND          Failed to find the memory table.\r
+\r
+**/\r
+RETURN_STATUS\r
+FindCbMemTable (\r
+  IN  struct cbmem_root  *Root,\r
+  IN  UINT32             TableId,\r
+  OUT VOID               **MemTable,\r
+  OUT UINT32             *MemTableSize\r
+  )\r
+{\r
+  UINTN                  Idx;\r
+  BOOLEAN                IsImdEntry;\r
+  struct cbmem_entry     *Entries;\r
+\r
+  if ((Root == NULL) || (MemTable == NULL)) {\r
+    return RETURN_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Check if the entry is CBMEM or IMD\r
+  // and handle them separately\r
+  //\r
+  Entries = Root->entries;\r
+  if (Entries[0].magic == CBMEM_ENTRY_MAGIC) {\r
+    IsImdEntry = FALSE;\r
+  } else {\r
+    Entries = (struct cbmem_entry *)((struct imd_root *)Root)->entries;\r
+    if (Entries[0].magic == IMD_ENTRY_MAGIC) {\r
+      IsImdEntry = TRUE;\r
+    } else {\r
+      return RETURN_NOT_FOUND;\r
+    }\r
+  }\r
+\r
+  for (Idx = 0; Idx < Root->num_entries; Idx++) {\r
+    if (Entries[Idx].id == TableId) {\r
+      if (IsImdEntry) {\r
+        *MemTable = (VOID *) ((UINTN)Entries[Idx].start + (UINTN)Root);\r
+      } else {\r
+        *MemTable = (VOID *) (UINTN)Entries[Idx].start;\r
+      }\r
+      if (MemTableSize != NULL) {\r
+        *MemTableSize = Entries[Idx].size;\r
+      }\r
+\r
+      DEBUG ((DEBUG_INFO, "Find CbMemTable Id 0x%x, base %p, size 0x%x\n",\r
+        TableId, *MemTable, Entries[Idx].size));\r
+      return RETURN_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return RETURN_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  Acquire the coreboot memory table with the given table id\r
+\r
+  @param  TableId            Table id to be searched\r
+  @param  MemTable           Pointer to the base address of the memory table\r
+  @param  MemTableSize       Pointer to the size of the memory table\r
+\r
+  @retval RETURN_SUCCESS     Successfully find out the memory table.\r
+  @retval RETURN_INVALID_PARAMETER  Invalid input parameters.\r
+  @retval RETURN_NOT_FOUND   Failed to find the memory table.\r
+\r
+**/\r
+RETURN_STATUS\r
+ParseCbMemTable (\r
+  IN  UINT32               TableId,\r
+  OUT VOID                 **MemTable,\r
+  OUT UINT32               *MemTableSize\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  struct cb_memory         *rec;\r
+  struct cb_memory_range   *Range;\r
+  UINT64                   Start;\r
+  UINT64                   Size;\r
+  UINTN                    Index;\r
+  struct cbmem_root        *CbMemRoot;\r
+\r
+  if (MemTable == NULL) {\r
+    return RETURN_INVALID_PARAMETER;\r
+  }\r
+\r
+  *MemTable = NULL;\r
+  Status    = RETURN_NOT_FOUND;\r
+\r
+  //\r
+  // Get the coreboot memory table\r
+  //\r
+  rec = (struct cb_memory *)FindCbTag (CB_TAG_MEMORY);\r
+  if (rec == NULL) {\r
+    return Status;\r
+  }\r
+\r
+  for (Index = 0; Index < MEM_RANGE_COUNT(rec); Index++) {\r
+    Range = MEM_RANGE_PTR(rec, Index);\r
+    Start = cb_unpack64(Range->start);\r
+    Size = cb_unpack64(Range->size);\r
+\r
+    if ((Range->type == CB_MEM_TABLE) && (Start > 0x1000)) {\r
+      CbMemRoot = (struct  cbmem_root *)(UINTN)(Start + Size - DYN_CBMEM_ALIGN_SIZE);\r
+      Status = FindCbMemTable (CbMemRoot, TableId, MemTable, MemTableSize);\r
+      if (!EFI_ERROR (Status)) {\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Acquire the memory information from the coreboot table in memory.\r
+\r
+  @param  MemInfoCallback     The callback routine\r
+  @param  Params              Pointer to the callback routine parameter\r
+\r
+  @retval RETURN_SUCCESS     Successfully find out the memory information.\r
+  @retval RETURN_NOT_FOUND   Failed to find the memory information.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+ParseMemoryInfo (\r
+  IN  BL_MEM_INFO_CALLBACK  MemInfoCallback,\r
+  IN  VOID                  *Params\r
+  )\r
+{\r
+  struct cb_memory         *rec;\r
+  struct cb_memory_range   *Range;\r
+  UINTN                    Index;\r
+  MEMROY_MAP_ENTRY         MemoryMap;\r
+\r
+  //\r
+  // Get the coreboot memory table\r
+  //\r
+  rec = (struct cb_memory *)FindCbTag (CB_TAG_MEMORY);\r
+  if (rec == NULL) {\r
+    return RETURN_NOT_FOUND;\r
+  }\r
+\r
+  for (Index = 0; Index < MEM_RANGE_COUNT(rec); Index++) {\r
+    Range = MEM_RANGE_PTR(rec, Index);\r
+    MemoryMap.Base = cb_unpack64(Range->start);\r
+    MemoryMap.Size = cb_unpack64(Range->size);\r
+    MemoryMap.Type = (UINT8)Range->type;\r
+    MemoryMap.Flag = 0;\r
+    DEBUG ((DEBUG_INFO, "%d. %016lx - %016lx [%02x]\n",\r
+            Index, MemoryMap.Base, MemoryMap.Base + MemoryMap.Size - 1, MemoryMap.Type));\r
+\r
+    MemInfoCallback (&MemoryMap, Params);\r
+  }\r
+\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Acquire acpi table and smbios table from coreboot\r
+\r
+  @param  SystemTableInfo          Pointer to the system table info\r
+\r
+  @retval RETURN_SUCCESS            Successfully find out the tables.\r
+  @retval RETURN_NOT_FOUND          Failed to find the tables.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+ParseSystemTable (\r
+  OUT SYSTEM_TABLE_INFO     *SystemTableInfo\r
+  )\r
+{\r
+  EFI_STATUS       Status;\r
+  VOID             *MemTable;\r
+  UINT32           MemTableSize;\r
+\r
+  Status = ParseCbMemTable (SIGNATURE_32 ('T', 'B', 'M', 'S'), &MemTable, &MemTableSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  SystemTableInfo->SmbiosTableBase = (UINT64) (UINTN)MemTable;\r
+  SystemTableInfo->SmbiosTableSize = MemTableSize;\r
+\r
+  Status = ParseCbMemTable (SIGNATURE_32 ('I', 'P', 'C', 'A'), &MemTable, &MemTableSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  SystemTableInfo->AcpiTableBase = (UINT64) (UINTN)MemTable;\r
+  SystemTableInfo->AcpiTableSize = MemTableSize;\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Find the serial port information\r
+\r
+  @param  SERIAL_PORT_INFO   Pointer to serial port info structure\r
+\r
+  @retval RETURN_SUCCESS     Successfully find the serial port information.\r
+  @retval RETURN_NOT_FOUND   Failed to find the serial port information .\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+ParseSerialInfo (\r
+  OUT SERIAL_PORT_INFO     *SerialPortInfo\r
+  )\r
+{\r
+  struct cb_serial          *CbSerial;\r
+\r
+  CbSerial = FindCbTag (CB_TAG_SERIAL);\r
+  if (CbSerial == NULL) {\r
+    return RETURN_NOT_FOUND;\r
+  }\r
+\r
+  SerialPortInfo->BaseAddr    = CbSerial->baseaddr;\r
+  SerialPortInfo->RegWidth    = CbSerial->regwidth;\r
+  SerialPortInfo->Type        = CbSerial->type;\r
+  SerialPortInfo->Baud        = CbSerial->baud;\r
+  SerialPortInfo->InputHertz  = CbSerial->input_hertz;\r
+  SerialPortInfo->UartPciAddr = CbSerial->uart_pci_addr;\r
+\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+  Find the video frame buffer information\r
+\r
+  @param  GfxInfo             Pointer to the EFI_PEI_GRAPHICS_INFO_HOB structure\r
+\r
+  @retval RETURN_SUCCESS     Successfully find the video frame buffer information.\r
+  @retval RETURN_NOT_FOUND   Failed to find the video frame buffer information .\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+ParseGfxInfo (\r
+  OUT EFI_PEI_GRAPHICS_INFO_HOB         *GfxInfo\r
+  )\r
+{\r
+  struct cb_framebuffer                 *CbFbRec;\r
+  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *GfxMode;\r
+\r
+  if (GfxInfo == NULL) {\r
+    return RETURN_INVALID_PARAMETER;\r
+  }\r
+\r
+  CbFbRec = FindCbTag (CB_TAG_FRAMEBUFFER);\r
+  if (CbFbRec == NULL) {\r
+    return RETURN_NOT_FOUND;\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "Found coreboot video frame buffer information\n"));\r
+  DEBUG ((DEBUG_INFO, "physical_address: 0x%lx\n", CbFbRec->physical_address));\r
+  DEBUG ((DEBUG_INFO, "x_resolution: 0x%x\n", CbFbRec->x_resolution));\r
+  DEBUG ((DEBUG_INFO, "y_resolution: 0x%x\n", CbFbRec->y_resolution));\r
+  DEBUG ((DEBUG_INFO, "bits_per_pixel: 0x%x\n", CbFbRec->bits_per_pixel));\r
+  DEBUG ((DEBUG_INFO, "bytes_per_line: 0x%x\n", CbFbRec->bytes_per_line));\r
+\r
+  DEBUG ((DEBUG_INFO, "red_mask_size: 0x%x\n", CbFbRec->red_mask_size));\r
+  DEBUG ((DEBUG_INFO, "red_mask_pos: 0x%x\n", CbFbRec->red_mask_pos));\r
+  DEBUG ((DEBUG_INFO, "green_mask_size: 0x%x\n", CbFbRec->green_mask_size));\r
+  DEBUG ((DEBUG_INFO, "green_mask_pos: 0x%x\n", CbFbRec->green_mask_pos));\r
+  DEBUG ((DEBUG_INFO, "blue_mask_size: 0x%x\n", CbFbRec->blue_mask_size));\r
+  DEBUG ((DEBUG_INFO, "blue_mask_pos: 0x%x\n", CbFbRec->blue_mask_pos));\r
+  DEBUG ((DEBUG_INFO, "reserved_mask_size: 0x%x\n", CbFbRec->reserved_mask_size));\r
+  DEBUG ((DEBUG_INFO, "reserved_mask_pos: 0x%x\n", CbFbRec->reserved_mask_pos));\r
+\r
+  GfxMode = &GfxInfo->GraphicsMode;\r
+  GfxMode->Version              = 0;\r
+  GfxMode->HorizontalResolution = CbFbRec->x_resolution;\r
+  GfxMode->VerticalResolution   = CbFbRec->y_resolution;\r
+  GfxMode->PixelsPerScanLine    = (CbFbRec->bytes_per_line << 3) / CbFbRec->bits_per_pixel;\r
+  if ((CbFbRec->red_mask_pos == 0) && (CbFbRec->green_mask_pos == 8) && (CbFbRec->blue_mask_pos == 16)) {\r
+    GfxMode->PixelFormat = PixelRedGreenBlueReserved8BitPerColor;\r
+  } else if ((CbFbRec->blue_mask_pos == 0) && (CbFbRec->green_mask_pos == 8) && (CbFbRec->red_mask_pos == 16)) {\r
+     GfxMode->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;\r
+  }\r
+  GfxMode->PixelInformation.RedMask      = ((1 << CbFbRec->red_mask_size)      - 1) << CbFbRec->red_mask_pos;\r
+  GfxMode->PixelInformation.GreenMask    = ((1 << CbFbRec->green_mask_size)    - 1) << CbFbRec->green_mask_pos;\r
+  GfxMode->PixelInformation.BlueMask     = ((1 << CbFbRec->blue_mask_size)     - 1) << CbFbRec->blue_mask_pos;\r
+  GfxMode->PixelInformation.ReservedMask = ((1 << CbFbRec->reserved_mask_size) - 1) << CbFbRec->reserved_mask_pos;\r
+\r
+  GfxInfo->FrameBufferBase = CbFbRec->physical_address;\r
+  GfxInfo->FrameBufferSize = CbFbRec->bytes_per_line *  CbFbRec->y_resolution;\r
+\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+  Find the video frame buffer device information\r
+\r
+  @param  GfxDeviceInfo      Pointer to the EFI_PEI_GRAPHICS_DEVICE_INFO_HOB structure\r
+\r
+  @retval RETURN_SUCCESS     Successfully find the video frame buffer information.\r
+  @retval RETURN_NOT_FOUND   Failed to find the video frame buffer information.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+ParseGfxDeviceInfo (\r
+  OUT EFI_PEI_GRAPHICS_DEVICE_INFO_HOB       *GfxDeviceInfo\r
+  )\r
+{\r
+  return RETURN_NOT_FOUND;\r
+}\r
+\r