2 This library will parse the coreboot table in memory and extract those required
5 Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <Uefi/UefiBaseType.h>
11 #include <Library/BaseLib.h>
12 #include <Library/BaseMemoryLib.h>
13 #include <Library/DebugLib.h>
14 #include <Library/PcdLib.h>
15 #include <Library/IoLib.h>
16 #include <Library/CbParseLib.h>
18 #include <IndustryStandard/Acpi.h>
24 Convert a packed value from cbuint64 to a UINT64 value.
26 @param val The pointer to packed data.
28 @return the UNIT64 value after conversion.
33 IN
struct cbuint64 val
36 return LShiftU64 (val
.hi
, 32) | val
.lo
;
41 Returns the sum of all elements in a buffer of 16-bit values. During
42 calculation, the carry bits are also been added.
44 @param Buffer The pointer to the buffer to carry out the sum operation.
45 @param Length The size, in bytes, of Buffer.
47 @return Sum The sum of Buffer with carry bits included during additions.
61 TmpPtr
= (UINT8
*)Buffer
;
62 for(Idx
= 0; Idx
< Length
; Idx
++) {
63 TmpValue
= TmpPtr
[Idx
];
72 Sum
= (Sum
+ (Sum
>> 16)) & 0xFFFF;
76 return (UINT16
)((~Sum
) & 0xFFFF);
81 Find coreboot record with given Tag from the memory Start in 4096
84 @param Start The start memory to be searched in
85 @param Tag The tag id to be found
87 @retval NULL The Tag is not found.
88 @retval Others The pointer to the record found.
98 struct cb_header
*Header
;
99 struct cb_record
*Record
;
106 TmpPtr
= (UINT8
*)Start
;
107 for (Idx
= 0; Idx
< 4096; Idx
+= 16, TmpPtr
+= 16) {
108 Header
= (struct cb_header
*)TmpPtr
;
109 if (Header
->signature
== CB_HEADER_SIGNATURE
) {
118 if ((Header
== NULL
) || (Header
->table_bytes
== 0)) {
123 // Check the checksum of the coreboot table header
125 CheckSum
= CbCheckSum16 ((UINT16
*)Header
, sizeof (*Header
));
127 DEBUG ((EFI_D_ERROR
, "Invalid coreboot table header checksum\n"));
131 CheckSum
= CbCheckSum16 ((UINT16
*)(TmpPtr
+ sizeof (*Header
)), Header
->table_bytes
);
132 if (CheckSum
!= Header
->table_checksum
) {
133 DEBUG ((EFI_D_ERROR
, "Incorrect checksum of all the coreboot table entries\n"));
138 TmpPtr
+= Header
->header_bytes
;
139 for (Idx
= 0; Idx
< Header
->table_entries
; Idx
++) {
140 Record
= (struct cb_record
*)TmpPtr
;
141 if (Record
->tag
== CB_TAG_FORWARD
) {
142 TmpPtr
= (VOID
*)(UINTN
)((struct cb_forward
*)(UINTN
)Record
)->forward
;
143 if (Tag
== CB_TAG_FORWARD
) {
146 return FindCbTag (TmpPtr
, Tag
);
149 if (Record
->tag
== Tag
) {
153 TmpPtr
+= Record
->size
;
161 Find the given table with TableId from the given coreboot memory Root.
163 @param Root The coreboot memory table to be searched in
164 @param TableId Table id to be found
165 @param pMemTable To save the base address of the memory table found
166 @param pMemTableSize To save the size of memory table found
168 @retval RETURN_SUCCESS Successfully find out the memory table.
169 @retval RETURN_INVALID_PARAMETER Invalid input parameters.
170 @retval RETURN_NOT_FOUND Failed to find the memory table.
176 IN
struct cbmem_root
*Root
,
178 OUT VOID
**pMemTable
,
179 OUT UINT32
*pMemTableSize
184 struct cbmem_entry
*Entries
;
186 if ((Root
== NULL
) || (pMemTable
== NULL
)) {
187 return RETURN_INVALID_PARAMETER
;
190 // Check if the entry is CBMEM or IMD
191 // and handle them separately
193 Entries
= Root
->entries
;
194 if (Entries
[0].magic
== CBMEM_ENTRY_MAGIC
) {
197 Entries
= (struct cbmem_entry
*)((struct imd_root
*)Root
)->entries
;
198 if (Entries
[0].magic
== IMD_ENTRY_MAGIC
) {
201 return RETURN_NOT_FOUND
;
205 for (Idx
= 0; Idx
< Root
->num_entries
; Idx
++) {
206 if (Entries
[Idx
].id
== TableId
) {
208 *pMemTable
= (VOID
*) ((UINTN
)Entries
[Idx
].start
+ (UINTN
)Root
);
210 *pMemTable
= (VOID
*) (UINTN
)Entries
[Idx
].start
;
212 if (pMemTableSize
!= NULL
) {
213 *pMemTableSize
= Entries
[Idx
].size
;
216 DEBUG ((EFI_D_INFO
, "Find CbMemTable Id 0x%x, base %p, size 0x%x\n",
217 TableId
, *pMemTable
, Entries
[Idx
].size
));
218 return RETURN_SUCCESS
;
222 return RETURN_NOT_FOUND
;
227 Acquire the memory information from the coreboot table in memory.
229 @param MemInfoCallback The callback routine
230 @param pParam Pointer to the callback routine parameter
232 @retval RETURN_SUCCESS Successfully find out the memory information.
233 @retval RETURN_NOT_FOUND Failed to find the memory information.
239 IN CB_MEM_INFO_CALLBACK MemInfoCallback
,
243 struct cb_memory
*rec
;
244 struct cb_memory_range
*Range
;
250 // Get the coreboot memory table
252 rec
= (struct cb_memory
*)FindCbTag (0, CB_TAG_MEMORY
);
254 rec
= (struct cb_memory
*)FindCbTag ((VOID
*)(UINTN
)PcdGet32 (PcdCbHeaderPointer
), CB_TAG_MEMORY
);
258 return RETURN_NOT_FOUND
;
261 for (Index
= 0; Index
< MEM_RANGE_COUNT(rec
); Index
++) {
262 Range
= MEM_RANGE_PTR(rec
, Index
);
263 Start
= cb_unpack64(Range
->start
);
264 Size
= cb_unpack64(Range
->size
);
265 DEBUG ((EFI_D_INFO
, "%d. %016lx - %016lx [%02x]\n",
266 Index
, Start
, Start
+ Size
- 1, Range
->type
));
268 MemInfoCallback (Start
, Size
, Range
->type
, pParam
);
271 return RETURN_SUCCESS
;
276 Acquire the coreboot memory table with the given table id
278 @param TableId Table id to be searched
279 @param pMemTable Pointer to the base address of the memory table
280 @param pMemTableSize Pointer to the size of the memory table
282 @retval RETURN_SUCCESS Successfully find out the memory table.
283 @retval RETURN_INVALID_PARAMETER Invalid input parameters.
284 @retval RETURN_NOT_FOUND Failed to find the memory table.
291 OUT VOID
**pMemTable
,
292 OUT UINT32
*pMemTableSize
295 struct cb_memory
*rec
;
296 struct cb_memory_range
*Range
;
301 if (pMemTable
== NULL
) {
302 return RETURN_INVALID_PARAMETER
;
307 // Get the coreboot memory table
309 rec
= (struct cb_memory
*)FindCbTag (0, CB_TAG_MEMORY
);
311 rec
= (struct cb_memory
*)FindCbTag ((VOID
*)(UINTN
)PcdGet32 (PcdCbHeaderPointer
), CB_TAG_MEMORY
);
315 return RETURN_NOT_FOUND
;
318 for (Index
= 0; Index
< MEM_RANGE_COUNT(rec
); Index
++) {
319 Range
= MEM_RANGE_PTR(rec
, Index
);
320 Start
= cb_unpack64(Range
->start
);
321 Size
= cb_unpack64(Range
->size
);
323 if ((Range
->type
== CB_MEM_TABLE
) && (Start
> 0x1000)) {
324 if (FindCbMemTable ((struct cbmem_root
*)(UINTN
)(Start
+ Size
- DYN_CBMEM_ALIGN_SIZE
), TableId
, pMemTable
, pMemTableSize
) == RETURN_SUCCESS
)
325 return RETURN_SUCCESS
;
329 return RETURN_NOT_FOUND
;
334 Acquire the acpi table from coreboot
336 @param pMemTable Pointer to the base address of the memory table
337 @param pMemTableSize Pointer to the size of the memory table
339 @retval RETURN_SUCCESS Successfully find out the memory table.
340 @retval RETURN_INVALID_PARAMETER Invalid input parameters.
341 @retval RETURN_NOT_FOUND Failed to find the memory table.
347 OUT VOID
**pMemTable
,
348 OUT UINT32
*pMemTableSize
351 return CbParseCbMemTable (SIGNATURE_32 ('I', 'P', 'C', 'A'), pMemTable
, pMemTableSize
);
355 Acquire the smbios table from coreboot
357 @param pMemTable Pointer to the base address of the memory table
358 @param pMemTableSize Pointer to the size of the memory table
360 @retval RETURN_SUCCESS Successfully find out the memory table.
361 @retval RETURN_INVALID_PARAMETER Invalid input parameters.
362 @retval RETURN_NOT_FOUND Failed to find the memory table.
368 OUT VOID
**pMemTable
,
369 OUT UINT32
*pMemTableSize
372 return CbParseCbMemTable (SIGNATURE_32 ('T', 'B', 'M', 'S'), pMemTable
, pMemTableSize
);
376 Find the required fadt information
378 @param pPmCtrlReg Pointer to the address of power management control register
379 @param pPmTimerReg Pointer to the address of power management timer register
380 @param pResetReg Pointer to the address of system reset register
381 @param pResetValue Pointer to the value to be written to the system reset register
382 @param pPmEvtReg Pointer to the address of power management event register
383 @param pPmGpeEnReg Pointer to the address of power management GPE enable register
385 @retval RETURN_SUCCESS Successfully find out all the required fadt information.
386 @retval RETURN_NOT_FOUND Failed to find the fadt table.
392 OUT UINTN
*pPmCtrlReg
,
393 OUT UINTN
*pPmTimerReg
,
394 OUT UINTN
*pResetReg
,
395 OUT UINTN
*pResetValue
,
396 OUT UINTN
*pPmEvtReg
,
397 OUT UINTN
*pPmGpeEnReg
400 EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER
*Rsdp
;
401 EFI_ACPI_DESCRIPTION_HEADER
*Rsdt
;
404 EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE
*Fadt
;
405 EFI_ACPI_DESCRIPTION_HEADER
*Xsdt
;
409 RETURN_STATUS Status
;
412 Status
= RETURN_SUCCESS
;
414 Status
= CbParseAcpiTable ((VOID
**)&Rsdp
, NULL
);
415 if (RETURN_ERROR(Status
)) {
420 return RETURN_NOT_FOUND
;
423 DEBUG ((EFI_D_INFO
, "Find Rsdp at %p\n", Rsdp
));
424 DEBUG ((EFI_D_INFO
, "Find Rsdt 0x%x, Xsdt 0x%lx\n", Rsdp
->RsdtAddress
, Rsdp
->XsdtAddress
));
429 Rsdt
= (EFI_ACPI_DESCRIPTION_HEADER
*)(UINTN
)(Rsdp
->RsdtAddress
);
431 Entry32
= (UINT32
*)(Rsdt
+ 1);
432 Entry32Num
= (Rsdt
->Length
- sizeof(EFI_ACPI_DESCRIPTION_HEADER
)) >> 2;
433 for (Idx
= 0; Idx
< Entry32Num
; Idx
++) {
434 if (*(UINT32
*)(UINTN
)(Entry32
[Idx
]) == EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE
) {
435 Fadt
= (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE
*)(UINTN
)(Entry32
[Idx
]);
436 if (pPmCtrlReg
!= NULL
) {
437 *pPmCtrlReg
= Fadt
->Pm1aCntBlk
;
439 DEBUG ((EFI_D_INFO
, "PmCtrl Reg 0x%x\n", Fadt
->Pm1aCntBlk
));
441 if (pPmTimerReg
!= NULL
) {
442 *pPmTimerReg
= Fadt
->PmTmrBlk
;
444 DEBUG ((EFI_D_INFO
, "PmTimer Reg 0x%x\n", Fadt
->PmTmrBlk
));
446 if (pResetReg
!= NULL
) {
447 *pResetReg
= (UINTN
)Fadt
->ResetReg
.Address
;
449 DEBUG ((EFI_D_INFO
, "Reset Reg 0x%lx\n", Fadt
->ResetReg
.Address
));
451 if (pResetValue
!= NULL
) {
452 *pResetValue
= Fadt
->ResetValue
;
454 DEBUG ((EFI_D_INFO
, "Reset Value 0x%x\n", Fadt
->ResetValue
));
456 if (pPmEvtReg
!= NULL
) {
457 *pPmEvtReg
= Fadt
->Pm1aEvtBlk
;
458 DEBUG ((EFI_D_INFO
, "PmEvt Reg 0x%x\n", Fadt
->Pm1aEvtBlk
));
461 if (pPmGpeEnReg
!= NULL
) {
462 *pPmGpeEnReg
= Fadt
->Gpe0Blk
+ Fadt
->Gpe0BlkLen
/ 2;
463 DEBUG ((EFI_D_INFO
, "PmGpeEn Reg 0x%x\n", *pPmGpeEnReg
));
467 // Verify values for proper operation
469 ASSERT(Fadt
->Pm1aCntBlk
!= 0);
470 ASSERT(Fadt
->PmTmrBlk
!= 0);
471 ASSERT(Fadt
->ResetReg
.Address
!= 0);
472 ASSERT(Fadt
->Pm1aEvtBlk
!= 0);
473 ASSERT(Fadt
->Gpe0Blk
!= 0);
479 // Check the consistency of SCI enabling
485 if (Fadt
->Pm1CntLen
== 4) {
486 SciEnabled
= (IoRead32 (Fadt
->Pm1aCntBlk
) & BIT0
)? TRUE
: FALSE
;
489 // if (Pm1CntLen == 2), use 16 bit IO read;
490 // if (Pm1CntLen != 2 && Pm1CntLen != 4), use 16 bit IO read as a fallback
492 SciEnabled
= (IoRead16 (Fadt
->Pm1aCntBlk
) & BIT0
)? TRUE
: FALSE
;
495 if (!(Fadt
->Flags
& EFI_ACPI_5_0_HW_REDUCED_ACPI
) &&
496 (Fadt
->SmiCmd
== 0) &&
499 // The ACPI enabling status is inconsistent: SCI is not enabled but ACPI
500 // table does not provide a means to enable it through FADT->SmiCmd
502 DEBUG ((DEBUG_ERROR
, "ERROR: The ACPI enabling status is inconsistent: SCI is not"
503 " enabled but the ACPI table does not provide a means to enable it through FADT->SmiCmd."
504 " This may cause issues in OS.\n"));
508 return RETURN_SUCCESS
;
514 // Search Xsdt Second
516 Xsdt
= (EFI_ACPI_DESCRIPTION_HEADER
*)(UINTN
)(Rsdp
->XsdtAddress
);
518 Entry64
= (UINT64
*)(Xsdt
+ 1);
519 Entry64Num
= (Xsdt
->Length
- sizeof(EFI_ACPI_DESCRIPTION_HEADER
)) >> 3;
520 for (Idx
= 0; Idx
< Entry64Num
; Idx
++) {
521 if (*(UINT32
*)(UINTN
)(Entry64
[Idx
]) == EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE
) {
522 Fadt
= (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE
*)(UINTN
)(Entry64
[Idx
]);
524 *pPmCtrlReg
= Fadt
->Pm1aCntBlk
;
525 DEBUG ((EFI_D_ERROR
, "PmCtrl Reg 0x%x\n", Fadt
->Pm1aCntBlk
));
528 *pPmTimerReg
= Fadt
->PmTmrBlk
;
529 DEBUG ((EFI_D_ERROR
, "PmTimer Reg 0x%x\n", Fadt
->PmTmrBlk
));
532 *pResetReg
= (UINTN
)Fadt
->ResetReg
.Address
;
533 DEBUG ((EFI_D_ERROR
, "Reset Reg 0x%lx\n", Fadt
->ResetReg
.Address
));
536 *pResetValue
= Fadt
->ResetValue
;
537 DEBUG ((EFI_D_ERROR
, "Reset Value 0x%x\n", Fadt
->ResetValue
));
539 if (pPmEvtReg
!= NULL
) {
540 *pPmEvtReg
= Fadt
->Pm1aEvtBlk
;
541 DEBUG ((EFI_D_INFO
, "PmEvt Reg 0x%x\n", Fadt
->Pm1aEvtBlk
));
544 if (pPmGpeEnReg
!= NULL
) {
545 *pPmGpeEnReg
= Fadt
->Gpe0Blk
+ Fadt
->Gpe0BlkLen
/ 2;
546 DEBUG ((EFI_D_INFO
, "PmGpeEn Reg 0x%x\n", *pPmGpeEnReg
));
548 return RETURN_SUCCESS
;
553 return RETURN_NOT_FOUND
;
557 Find the serial port information
559 @param pRegBase Pointer to the base address of serial port registers
560 @param pRegAccessType Pointer to the access type of serial port registers
561 @param pRegWidth Pointer to the register width in bytes
562 @param pBaudrate Pointer to the serial port baudrate
563 @param pInputHertz Pointer to the input clock frequency
564 @param pUartPciAddr Pointer to the UART PCI bus, dev and func address
566 @retval RETURN_SUCCESS Successfully find the serial port information.
567 @retval RETURN_NOT_FOUND Failed to find the serial port information .
573 OUT UINT32
*pRegBase
,
574 OUT UINT32
*pRegAccessType
,
575 OUT UINT32
*pRegWidth
,
576 OUT UINT32
*pBaudrate
,
577 OUT UINT32
*pInputHertz
,
578 OUT UINT32
*pUartPciAddr
581 struct cb_serial
*CbSerial
;
583 CbSerial
= FindCbTag (0, CB_TAG_SERIAL
);
584 if (CbSerial
== NULL
) {
585 CbSerial
= FindCbTag ((VOID
*)(UINTN
)PcdGet32 (PcdCbHeaderPointer
), CB_TAG_SERIAL
);
588 if (CbSerial
== NULL
) {
589 return RETURN_NOT_FOUND
;
592 if (pRegBase
!= NULL
) {
593 *pRegBase
= CbSerial
->baseaddr
;
596 if (pRegWidth
!= NULL
) {
597 *pRegWidth
= CbSerial
->regwidth
;
600 if (pRegAccessType
!= NULL
) {
601 *pRegAccessType
= CbSerial
->type
;
604 if (pBaudrate
!= NULL
) {
605 *pBaudrate
= CbSerial
->baud
;
608 if (pInputHertz
!= NULL
) {
609 *pInputHertz
= CbSerial
->input_hertz
;
612 if (pUartPciAddr
!= NULL
) {
613 *pUartPciAddr
= CbSerial
->uart_pci_addr
;
616 return RETURN_SUCCESS
;
620 Search for the coreboot table header
622 @param Level Level of the search depth
623 @param HeaderPtr Pointer to the pointer of coreboot table header
625 @retval RETURN_SUCCESS Successfully find the coreboot table header .
626 @retval RETURN_NOT_FOUND Failed to find the coreboot table header .
639 if (HeaderPtr
== NULL
) {
640 return RETURN_NOT_FOUND
;
644 for (Index
= 0; Index
< Level
; Index
++) {
645 TempPtr
= FindCbTag (TempPtr
, CB_TAG_FORWARD
);
646 if (TempPtr
== NULL
) {
651 if ((Index
>= Level
) && (TempPtr
!= NULL
)) {
652 *HeaderPtr
= TempPtr
;
653 return RETURN_SUCCESS
;
656 return RETURN_NOT_FOUND
;
660 Find the video frame buffer information
662 @param pFbInfo Pointer to the FRAME_BUFFER_INFO structure
664 @retval RETURN_SUCCESS Successfully find the video frame buffer information.
665 @retval RETURN_NOT_FOUND Failed to find the video frame buffer information .
671 OUT FRAME_BUFFER_INFO
*pFbInfo
674 struct cb_framebuffer
*CbFbRec
;
676 if (pFbInfo
== NULL
) {
677 return RETURN_INVALID_PARAMETER
;
680 CbFbRec
= FindCbTag (0, CB_TAG_FRAMEBUFFER
);
681 if (CbFbRec
== NULL
) {
682 CbFbRec
= FindCbTag ((VOID
*)(UINTN
)PcdGet32 (PcdCbHeaderPointer
), CB_TAG_FRAMEBUFFER
);
685 if (CbFbRec
== NULL
) {
686 return RETURN_NOT_FOUND
;
689 DEBUG ((EFI_D_INFO
, "Found coreboot video frame buffer information\n"));
690 DEBUG ((EFI_D_INFO
, "physical_address: 0x%lx\n", CbFbRec
->physical_address
));
691 DEBUG ((EFI_D_INFO
, "x_resolution: 0x%x\n", CbFbRec
->x_resolution
));
692 DEBUG ((EFI_D_INFO
, "y_resolution: 0x%x\n", CbFbRec
->y_resolution
));
693 DEBUG ((EFI_D_INFO
, "bits_per_pixel: 0x%x\n", CbFbRec
->bits_per_pixel
));
694 DEBUG ((EFI_D_INFO
, "bytes_per_line: 0x%x\n", CbFbRec
->bytes_per_line
));
696 DEBUG ((EFI_D_INFO
, "red_mask_size: 0x%x\n", CbFbRec
->red_mask_size
));
697 DEBUG ((EFI_D_INFO
, "red_mask_pos: 0x%x\n", CbFbRec
->red_mask_pos
));
698 DEBUG ((EFI_D_INFO
, "green_mask_size: 0x%x\n", CbFbRec
->green_mask_size
));
699 DEBUG ((EFI_D_INFO
, "green_mask_pos: 0x%x\n", CbFbRec
->green_mask_pos
));
700 DEBUG ((EFI_D_INFO
, "blue_mask_size: 0x%x\n", CbFbRec
->blue_mask_size
));
701 DEBUG ((EFI_D_INFO
, "blue_mask_pos: 0x%x\n", CbFbRec
->blue_mask_pos
));
702 DEBUG ((EFI_D_INFO
, "reserved_mask_size: 0x%x\n", CbFbRec
->reserved_mask_size
));
703 DEBUG ((EFI_D_INFO
, "reserved_mask_pos: 0x%x\n", CbFbRec
->reserved_mask_pos
));
705 pFbInfo
->LinearFrameBuffer
= CbFbRec
->physical_address
;
706 pFbInfo
->HorizontalResolution
= CbFbRec
->x_resolution
;
707 pFbInfo
->VerticalResolution
= CbFbRec
->y_resolution
;
708 pFbInfo
->BitsPerPixel
= CbFbRec
->bits_per_pixel
;
709 pFbInfo
->BytesPerScanLine
= (UINT16
)CbFbRec
->bytes_per_line
;
710 pFbInfo
->Red
.Mask
= (1 << CbFbRec
->red_mask_size
) - 1;
711 pFbInfo
->Red
.Position
= CbFbRec
->red_mask_pos
;
712 pFbInfo
->Green
.Mask
= (1 << CbFbRec
->green_mask_size
) - 1;
713 pFbInfo
->Green
.Position
= CbFbRec
->green_mask_pos
;
714 pFbInfo
->Blue
.Mask
= (1 << CbFbRec
->blue_mask_size
) - 1;
715 pFbInfo
->Blue
.Position
= CbFbRec
->blue_mask_pos
;
716 pFbInfo
->Reserved
.Mask
= (1 << CbFbRec
->reserved_mask_size
) - 1;
717 pFbInfo
->Reserved
.Position
= CbFbRec
->reserved_mask_pos
;
719 return RETURN_SUCCESS
;