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