--- /dev/null
+/** @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