diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/UefiPayloadPkg/Library/CbParseLib/CbParseLib.c')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/UefiPayloadPkg/Library/CbParseLib/CbParseLib.c | 560 |
1 files changed, 560 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/UefiPayloadPkg/Library/CbParseLib/CbParseLib.c b/src/VBox/Devices/EFI/Firmware/UefiPayloadPkg/Library/CbParseLib/CbParseLib.c new file mode 100644 index 00000000..463274d4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/UefiPayloadPkg/Library/CbParseLib/CbParseLib.c @@ -0,0 +1,560 @@ +/** @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; +} + |