mirror of https://github.com/acidanthera/audk.git
561 lines
15 KiB
C
561 lines
15 KiB
C
/** @file
|
|
This library will parse the coreboot table in memory and extract those required
|
|
information.
|
|
|
|
Copyright (c) 2014 - 2016, 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;
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
SET_BOOTLOADER_PARAMETER ((UINT32)(UINTN)CbTablePtr);
|
|
|
|
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;
|
|
struct 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 = (struct 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
|
|
)
|
|
{
|
|
struct cb_memory *rec;
|
|
struct cb_memory_range *Range;
|
|
UINTN Index;
|
|
MEMROY_MAP_ENTRY MemoryMap;
|
|
|
|
//
|
|
// Get the coreboot memory table
|
|
//
|
|
rec = (struct 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 acpi table and smbios table from coreboot
|
|
|
|
@param SystemTableInfo Pointer to the system table info
|
|
|
|
@retval RETURN_SUCCESS Successfully find out the tables.
|
|
@retval RETURN_NOT_FOUND Failed to find the tables.
|
|
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
ParseSystemTable (
|
|
OUT SYSTEM_TABLE_INFO *SystemTableInfo
|
|
)
|
|
{
|
|
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;
|
|
}
|
|
SystemTableInfo->SmbiosTableBase = (UINT64) (UINTN)MemTable;
|
|
SystemTableInfo->SmbiosTableSize = MemTableSize;
|
|
|
|
Status = ParseCbMemTable (SIGNATURE_32 ('I', 'P', 'C', 'A'), &MemTable, &MemTableSize);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
SystemTableInfo->AcpiTableBase = (UINT64) (UINTN)MemTable;
|
|
SystemTableInfo->AcpiTableSize = MemTableSize;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Find the serial port information
|
|
|
|
@param SERIAL_PORT_INFO 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;
|
|
}
|
|
|