]> git.proxmox.com Git - mirror_edk2.git/blame - UefiPayloadPkg/Library/CbParseLib/CbParseLib.c
UefiPayloadPkg: Add PCI root bridge info hob support for SBL
[mirror_edk2.git] / UefiPayloadPkg / Library / CbParseLib / CbParseLib.c
CommitLineData
04af8bf2
DG
1/** @file\r
2 This library will parse the coreboot table in memory and extract those required\r
3 information.\r
4\r
422e5d2f 5 Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>\r
04af8bf2
DG
6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8**/\r
9\r
10#include <Uefi/UefiBaseType.h>\r
11#include <Library/BaseLib.h>\r
12#include <Library/BaseMemoryLib.h>\r
13#include <Library/DebugLib.h>\r
14#include <Library/PcdLib.h>\r
15#include <Library/IoLib.h>\r
16#include <Library/BlParseLib.h>\r
17#include <IndustryStandard/Acpi.h>\r
18#include <Coreboot.h>\r
19\r
20\r
21/**\r
22 Convert a packed value from cbuint64 to a UINT64 value.\r
23\r
24 @param val The pointer to packed data.\r
25\r
26 @return the UNIT64 value after conversion.\r
27\r
28**/\r
29UINT64\r
30cb_unpack64 (\r
31 IN struct cbuint64 val\r
32 )\r
33{\r
34 return LShiftU64 (val.hi, 32) | val.lo;\r
35}\r
36\r
37\r
38/**\r
39 Returns the sum of all elements in a buffer of 16-bit values. During\r
40 calculation, the carry bits are also been added.\r
41\r
42 @param Buffer The pointer to the buffer to carry out the sum operation.\r
43 @param Length The size, in bytes, of Buffer.\r
44\r
45 @return Sum The sum of Buffer with carry bits included during additions.\r
46\r
47**/\r
48UINT16\r
49CbCheckSum16 (\r
50 IN UINT16 *Buffer,\r
51 IN UINTN Length\r
52 )\r
53{\r
54 UINT32 Sum;\r
55 UINT32 TmpValue;\r
56 UINTN Idx;\r
57 UINT8 *TmpPtr;\r
58\r
59 Sum = 0;\r
60 TmpPtr = (UINT8 *)Buffer;\r
61 for(Idx = 0; Idx < Length; Idx++) {\r
62 TmpValue = TmpPtr[Idx];\r
63 if (Idx % 2 == 1) {\r
64 TmpValue <<= 8;\r
65 }\r
66\r
67 Sum += TmpValue;\r
68\r
69 // Wrap\r
70 if (Sum >= 0x10000) {\r
71 Sum = (Sum + (Sum >> 16)) & 0xFFFF;\r
72 }\r
73 }\r
74\r
75 return (UINT16)((~Sum) & 0xFFFF);\r
76}\r
77\r
78\r
79/**\r
80 Check the coreboot table if it is valid.\r
81\r
82 @param Header Pointer to coreboot table\r
83\r
84 @retval TRUE The coreboot table is valid.\r
85 @retval Others The coreboot table is not valid.\r
86\r
87**/\r
88BOOLEAN\r
89IsValidCbTable (\r
90 IN struct cb_header *Header\r
91 )\r
92{\r
93 UINT16 CheckSum;\r
94\r
95 if ((Header == NULL) || (Header->table_bytes == 0)) {\r
96 return FALSE;\r
97 }\r
98\r
99 if (Header->signature != CB_HEADER_SIGNATURE) {\r
100 return FALSE;\r
101 }\r
102\r
103 //\r
104 // Check the checksum of the coreboot table header\r
105 //\r
106 CheckSum = CbCheckSum16 ((UINT16 *)Header, sizeof (*Header));\r
107 if (CheckSum != 0) {\r
108 DEBUG ((DEBUG_ERROR, "Invalid coreboot table header checksum\n"));\r
109 return FALSE;\r
110 }\r
111\r
112 CheckSum = CbCheckSum16 ((UINT16 *)((UINT8 *)Header + sizeof (*Header)), Header->table_bytes);\r
113 if (CheckSum != Header->table_checksum) {\r
114 DEBUG ((DEBUG_ERROR, "Incorrect checksum of all the coreboot table entries\n"));\r
115 return FALSE;\r
116 }\r
117\r
118 return TRUE;\r
119}\r
120\r
121\r
122/**\r
123 This function retrieves the parameter base address from boot loader.\r
124\r
125 This function will get bootloader specific parameter address for UEFI payload.\r
126 e.g. HobList pointer for Slim Bootloader, and coreboot table header for Coreboot.\r
127\r
128 @retval NULL Failed to find the GUID HOB.\r
129 @retval others GUIDed HOB data pointer.\r
130\r
131**/\r
132VOID *\r
133EFIAPI\r
134GetParameterBase (\r
135 VOID\r
136 )\r
137{\r
138 struct cb_header *Header;\r
139 struct cb_record *Record;\r
140 UINT8 *TmpPtr;\r
141 UINT8 *CbTablePtr;\r
142 UINTN Idx;\r
422e5d2f 143 EFI_STATUS Status;\r
04af8bf2
DG
144\r
145 //\r
146 // coreboot could pass coreboot table to UEFI payload\r
147 //\r
148 Header = (struct cb_header *)(UINTN)GET_BOOTLOADER_PARAMETER ();\r
149 if (IsValidCbTable (Header)) {\r
150 return Header;\r
151 }\r
152\r
153 //\r
154 // Find simplified coreboot table in memory range 0 ~ 4KB.\r
155 // Some GCC version does not allow directly access to NULL pointer,\r
156 // so start the search from 0x10 instead.\r
157 //\r
158 for (Idx = 16; Idx < 4096; Idx += 16) {\r
159 Header = (struct cb_header *)Idx;\r
160 if (Header->signature == CB_HEADER_SIGNATURE) {\r
161 break;\r
162 }\r
163 }\r
164\r
165 if (Idx >= 4096) {\r
166 return NULL;\r
167 }\r
168\r
169 //\r
170 // Check the coreboot header\r
171 //\r
172 if (!IsValidCbTable (Header)) {\r
173 return NULL;\r
174 }\r
175\r
176 //\r
177 // Find full coreboot table in high memory\r
178 //\r
179 CbTablePtr = NULL;\r
180 TmpPtr = (UINT8 *)Header + Header->header_bytes;\r
181 for (Idx = 0; Idx < Header->table_entries; Idx++) {\r
182 Record = (struct cb_record *)TmpPtr;\r
183 if (Record->tag == CB_TAG_FORWARD) {\r
184 CbTablePtr = (VOID *)(UINTN)((struct cb_forward *)(UINTN)Record)->forward;\r
185 break;\r
186 }\r
187 TmpPtr += Record->size;\r
188 }\r
189\r
190 //\r
191 // Check the coreboot header in high memory\r
192 //\r
193 if (!IsValidCbTable ((struct cb_header *)CbTablePtr)) {\r
194 return NULL;\r
195 }\r
196\r
422e5d2f
GD
197 PcdSet64S (PcdBootloaderParameter, (UINTN)CbTablePtr);\r
198 ASSERT_EFI_STATUS (Status);\r
04af8bf2
DG
199\r
200 return CbTablePtr;\r
201}\r
202\r
203\r
204/**\r
205 Find coreboot record with given Tag.\r
206\r
207 @param Tag The tag id to be found\r
208\r
209 @retval NULL The Tag is not found.\r
210 @retval Others The pointer to the record found.\r
211\r
212**/\r
213VOID *\r
214FindCbTag (\r
215 IN UINT32 Tag\r
216 )\r
217{\r
218 struct cb_header *Header;\r
219 struct cb_record *Record;\r
220 UINT8 *TmpPtr;\r
221 UINT8 *TagPtr;\r
222 UINTN Idx;\r
223\r
224 Header = (struct cb_header *) GetParameterBase ();\r
225\r
226 TagPtr = NULL;\r
227 TmpPtr = (UINT8 *)Header + Header->header_bytes;\r
228 for (Idx = 0; Idx < Header->table_entries; Idx++) {\r
229 Record = (struct cb_record *)TmpPtr;\r
230 if (Record->tag == Tag) {\r
231 TagPtr = TmpPtr;\r
232 break;\r
233 }\r
234 TmpPtr += Record->size;\r
235 }\r
236\r
237 return TagPtr;\r
238}\r
239\r
240\r
241/**\r
242 Find the given table with TableId from the given coreboot memory Root.\r
243\r
244 @param Root The coreboot memory table to be searched in\r
245 @param TableId Table id to be found\r
246 @param MemTable To save the base address of the memory table found\r
247 @param MemTableSize To save the size of memory table found\r
248\r
249 @retval RETURN_SUCCESS Successfully find out the memory table.\r
250 @retval RETURN_INVALID_PARAMETER Invalid input parameters.\r
251 @retval RETURN_NOT_FOUND Failed to find the memory table.\r
252\r
253**/\r
254RETURN_STATUS\r
255FindCbMemTable (\r
256 IN struct cbmem_root *Root,\r
257 IN UINT32 TableId,\r
258 OUT VOID **MemTable,\r
259 OUT UINT32 *MemTableSize\r
260 )\r
261{\r
262 UINTN Idx;\r
263 BOOLEAN IsImdEntry;\r
264 struct cbmem_entry *Entries;\r
265\r
266 if ((Root == NULL) || (MemTable == NULL)) {\r
267 return RETURN_INVALID_PARAMETER;\r
268 }\r
269 //\r
270 // Check if the entry is CBMEM or IMD\r
271 // and handle them separately\r
272 //\r
273 Entries = Root->entries;\r
274 if (Entries[0].magic == CBMEM_ENTRY_MAGIC) {\r
275 IsImdEntry = FALSE;\r
276 } else {\r
277 Entries = (struct cbmem_entry *)((struct imd_root *)Root)->entries;\r
278 if (Entries[0].magic == IMD_ENTRY_MAGIC) {\r
279 IsImdEntry = TRUE;\r
280 } else {\r
281 return RETURN_NOT_FOUND;\r
282 }\r
283 }\r
284\r
285 for (Idx = 0; Idx < Root->num_entries; Idx++) {\r
286 if (Entries[Idx].id == TableId) {\r
287 if (IsImdEntry) {\r
288 *MemTable = (VOID *) ((UINTN)Entries[Idx].start + (UINTN)Root);\r
289 } else {\r
290 *MemTable = (VOID *) (UINTN)Entries[Idx].start;\r
291 }\r
292 if (MemTableSize != NULL) {\r
293 *MemTableSize = Entries[Idx].size;\r
294 }\r
295\r
296 DEBUG ((DEBUG_INFO, "Find CbMemTable Id 0x%x, base %p, size 0x%x\n",\r
297 TableId, *MemTable, Entries[Idx].size));\r
298 return RETURN_SUCCESS;\r
299 }\r
300 }\r
301\r
302 return RETURN_NOT_FOUND;\r
303}\r
304\r
305/**\r
306 Acquire the coreboot memory table with the given table id\r
307\r
308 @param TableId Table id to be searched\r
309 @param MemTable Pointer to the base address of the memory table\r
310 @param MemTableSize Pointer to the size of the memory table\r
311\r
312 @retval RETURN_SUCCESS Successfully find out the memory table.\r
313 @retval RETURN_INVALID_PARAMETER Invalid input parameters.\r
314 @retval RETURN_NOT_FOUND Failed to find the memory table.\r
315\r
316**/\r
317RETURN_STATUS\r
318ParseCbMemTable (\r
319 IN UINT32 TableId,\r
320 OUT VOID **MemTable,\r
321 OUT UINT32 *MemTableSize\r
322 )\r
323{\r
324 EFI_STATUS Status;\r
325 struct cb_memory *rec;\r
326 struct cb_memory_range *Range;\r
327 UINT64 Start;\r
328 UINT64 Size;\r
329 UINTN Index;\r
330 struct cbmem_root *CbMemRoot;\r
331\r
332 if (MemTable == NULL) {\r
333 return RETURN_INVALID_PARAMETER;\r
334 }\r
335\r
336 *MemTable = NULL;\r
337 Status = RETURN_NOT_FOUND;\r
338\r
339 //\r
340 // Get the coreboot memory table\r
341 //\r
342 rec = (struct cb_memory *)FindCbTag (CB_TAG_MEMORY);\r
343 if (rec == NULL) {\r
344 return Status;\r
345 }\r
346\r
347 for (Index = 0; Index < MEM_RANGE_COUNT(rec); Index++) {\r
348 Range = MEM_RANGE_PTR(rec, Index);\r
349 Start = cb_unpack64(Range->start);\r
350 Size = cb_unpack64(Range->size);\r
351\r
352 if ((Range->type == CB_MEM_TABLE) && (Start > 0x1000)) {\r
353 CbMemRoot = (struct cbmem_root *)(UINTN)(Start + Size - DYN_CBMEM_ALIGN_SIZE);\r
354 Status = FindCbMemTable (CbMemRoot, TableId, MemTable, MemTableSize);\r
355 if (!EFI_ERROR (Status)) {\r
356 break;\r
357 }\r
358 }\r
359 }\r
360\r
361 return Status;\r
362}\r
363\r
364\r
365\r
366/**\r
367 Acquire the memory information from the coreboot table in memory.\r
368\r
369 @param MemInfoCallback The callback routine\r
370 @param Params Pointer to the callback routine parameter\r
371\r
372 @retval RETURN_SUCCESS Successfully find out the memory information.\r
373 @retval RETURN_NOT_FOUND Failed to find the memory information.\r
374\r
375**/\r
376RETURN_STATUS\r
377EFIAPI\r
378ParseMemoryInfo (\r
379 IN BL_MEM_INFO_CALLBACK MemInfoCallback,\r
380 IN VOID *Params\r
381 )\r
382{\r
383 struct cb_memory *rec;\r
384 struct cb_memory_range *Range;\r
385 UINTN Index;\r
386 MEMROY_MAP_ENTRY MemoryMap;\r
387\r
388 //\r
389 // Get the coreboot memory table\r
390 //\r
391 rec = (struct cb_memory *)FindCbTag (CB_TAG_MEMORY);\r
392 if (rec == NULL) {\r
393 return RETURN_NOT_FOUND;\r
394 }\r
395\r
396 for (Index = 0; Index < MEM_RANGE_COUNT(rec); Index++) {\r
397 Range = MEM_RANGE_PTR(rec, Index);\r
398 MemoryMap.Base = cb_unpack64(Range->start);\r
399 MemoryMap.Size = cb_unpack64(Range->size);\r
400 MemoryMap.Type = (UINT8)Range->type;\r
401 MemoryMap.Flag = 0;\r
402 DEBUG ((DEBUG_INFO, "%d. %016lx - %016lx [%02x]\n",\r
403 Index, MemoryMap.Base, MemoryMap.Base + MemoryMap.Size - 1, MemoryMap.Type));\r
404\r
405 MemInfoCallback (&MemoryMap, Params);\r
406 }\r
407\r
408 return RETURN_SUCCESS;\r
409}\r
410\r
411\r
412/**\r
413 Acquire acpi table and smbios table from coreboot\r
414\r
415 @param SystemTableInfo Pointer to the system table info\r
416\r
417 @retval RETURN_SUCCESS Successfully find out the tables.\r
418 @retval RETURN_NOT_FOUND Failed to find the tables.\r
419\r
420**/\r
421RETURN_STATUS\r
422EFIAPI\r
423ParseSystemTable (\r
424 OUT SYSTEM_TABLE_INFO *SystemTableInfo\r
425 )\r
426{\r
427 EFI_STATUS Status;\r
428 VOID *MemTable;\r
429 UINT32 MemTableSize;\r
430\r
431 Status = ParseCbMemTable (SIGNATURE_32 ('T', 'B', 'M', 'S'), &MemTable, &MemTableSize);\r
432 if (EFI_ERROR (Status)) {\r
433 return EFI_NOT_FOUND;\r
434 }\r
435 SystemTableInfo->SmbiosTableBase = (UINT64) (UINTN)MemTable;\r
436 SystemTableInfo->SmbiosTableSize = MemTableSize;\r
437\r
438 Status = ParseCbMemTable (SIGNATURE_32 ('I', 'P', 'C', 'A'), &MemTable, &MemTableSize);\r
439 if (EFI_ERROR (Status)) {\r
440 return EFI_NOT_FOUND;\r
441 }\r
442 SystemTableInfo->AcpiTableBase = (UINT64) (UINTN)MemTable;\r
443 SystemTableInfo->AcpiTableSize = MemTableSize;\r
444\r
445 return Status;\r
446}\r
447\r
448\r
449/**\r
450 Find the serial port information\r
451\r
452 @param SERIAL_PORT_INFO Pointer to serial port info structure\r
453\r
454 @retval RETURN_SUCCESS Successfully find the serial port information.\r
455 @retval RETURN_NOT_FOUND Failed to find the serial port information .\r
456\r
457**/\r
458RETURN_STATUS\r
459EFIAPI\r
460ParseSerialInfo (\r
461 OUT SERIAL_PORT_INFO *SerialPortInfo\r
462 )\r
463{\r
464 struct cb_serial *CbSerial;\r
465\r
466 CbSerial = FindCbTag (CB_TAG_SERIAL);\r
467 if (CbSerial == NULL) {\r
468 return RETURN_NOT_FOUND;\r
469 }\r
470\r
471 SerialPortInfo->BaseAddr = CbSerial->baseaddr;\r
472 SerialPortInfo->RegWidth = CbSerial->regwidth;\r
473 SerialPortInfo->Type = CbSerial->type;\r
474 SerialPortInfo->Baud = CbSerial->baud;\r
475 SerialPortInfo->InputHertz = CbSerial->input_hertz;\r
476 SerialPortInfo->UartPciAddr = CbSerial->uart_pci_addr;\r
477\r
478 return RETURN_SUCCESS;\r
479}\r
480\r
481/**\r
482 Find the video frame buffer information\r
483\r
484 @param GfxInfo Pointer to the EFI_PEI_GRAPHICS_INFO_HOB structure\r
485\r
486 @retval RETURN_SUCCESS Successfully find the video frame buffer information.\r
487 @retval RETURN_NOT_FOUND Failed to find the video frame buffer information .\r
488\r
489**/\r
490RETURN_STATUS\r
491EFIAPI\r
492ParseGfxInfo (\r
493 OUT EFI_PEI_GRAPHICS_INFO_HOB *GfxInfo\r
494 )\r
495{\r
496 struct cb_framebuffer *CbFbRec;\r
497 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *GfxMode;\r
498\r
499 if (GfxInfo == NULL) {\r
500 return RETURN_INVALID_PARAMETER;\r
501 }\r
502\r
503 CbFbRec = FindCbTag (CB_TAG_FRAMEBUFFER);\r
504 if (CbFbRec == NULL) {\r
505 return RETURN_NOT_FOUND;\r
506 }\r
507\r
508 DEBUG ((DEBUG_INFO, "Found coreboot video frame buffer information\n"));\r
509 DEBUG ((DEBUG_INFO, "physical_address: 0x%lx\n", CbFbRec->physical_address));\r
510 DEBUG ((DEBUG_INFO, "x_resolution: 0x%x\n", CbFbRec->x_resolution));\r
511 DEBUG ((DEBUG_INFO, "y_resolution: 0x%x\n", CbFbRec->y_resolution));\r
512 DEBUG ((DEBUG_INFO, "bits_per_pixel: 0x%x\n", CbFbRec->bits_per_pixel));\r
513 DEBUG ((DEBUG_INFO, "bytes_per_line: 0x%x\n", CbFbRec->bytes_per_line));\r
514\r
515 DEBUG ((DEBUG_INFO, "red_mask_size: 0x%x\n", CbFbRec->red_mask_size));\r
516 DEBUG ((DEBUG_INFO, "red_mask_pos: 0x%x\n", CbFbRec->red_mask_pos));\r
517 DEBUG ((DEBUG_INFO, "green_mask_size: 0x%x\n", CbFbRec->green_mask_size));\r
518 DEBUG ((DEBUG_INFO, "green_mask_pos: 0x%x\n", CbFbRec->green_mask_pos));\r
519 DEBUG ((DEBUG_INFO, "blue_mask_size: 0x%x\n", CbFbRec->blue_mask_size));\r
520 DEBUG ((DEBUG_INFO, "blue_mask_pos: 0x%x\n", CbFbRec->blue_mask_pos));\r
521 DEBUG ((DEBUG_INFO, "reserved_mask_size: 0x%x\n", CbFbRec->reserved_mask_size));\r
522 DEBUG ((DEBUG_INFO, "reserved_mask_pos: 0x%x\n", CbFbRec->reserved_mask_pos));\r
523\r
524 GfxMode = &GfxInfo->GraphicsMode;\r
525 GfxMode->Version = 0;\r
526 GfxMode->HorizontalResolution = CbFbRec->x_resolution;\r
527 GfxMode->VerticalResolution = CbFbRec->y_resolution;\r
528 GfxMode->PixelsPerScanLine = (CbFbRec->bytes_per_line << 3) / CbFbRec->bits_per_pixel;\r
529 if ((CbFbRec->red_mask_pos == 0) && (CbFbRec->green_mask_pos == 8) && (CbFbRec->blue_mask_pos == 16)) {\r
530 GfxMode->PixelFormat = PixelRedGreenBlueReserved8BitPerColor;\r
531 } else if ((CbFbRec->blue_mask_pos == 0) && (CbFbRec->green_mask_pos == 8) && (CbFbRec->red_mask_pos == 16)) {\r
532 GfxMode->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;\r
533 }\r
534 GfxMode->PixelInformation.RedMask = ((1 << CbFbRec->red_mask_size) - 1) << CbFbRec->red_mask_pos;\r
535 GfxMode->PixelInformation.GreenMask = ((1 << CbFbRec->green_mask_size) - 1) << CbFbRec->green_mask_pos;\r
536 GfxMode->PixelInformation.BlueMask = ((1 << CbFbRec->blue_mask_size) - 1) << CbFbRec->blue_mask_pos;\r
537 GfxMode->PixelInformation.ReservedMask = ((1 << CbFbRec->reserved_mask_size) - 1) << CbFbRec->reserved_mask_pos;\r
538\r
539 GfxInfo->FrameBufferBase = CbFbRec->physical_address;\r
540 GfxInfo->FrameBufferSize = CbFbRec->bytes_per_line * CbFbRec->y_resolution;\r
541\r
542 return RETURN_SUCCESS;\r
543}\r
544\r
545/**\r
546 Find the video frame buffer device information\r
547\r
548 @param GfxDeviceInfo Pointer to the EFI_PEI_GRAPHICS_DEVICE_INFO_HOB structure\r
549\r
550 @retval RETURN_SUCCESS Successfully find the video frame buffer information.\r
551 @retval RETURN_NOT_FOUND Failed to find the video frame buffer information.\r
552\r
553**/\r
554RETURN_STATUS\r
555EFIAPI\r
556ParseGfxDeviceInfo (\r
557 OUT EFI_PEI_GRAPHICS_DEVICE_INFO_HOB *GfxDeviceInfo\r
558 )\r
559{\r
560 return RETURN_NOT_FOUND;\r
561}\r
562\r
978d428e
MM
563/**\r
564 Parse and handle the misc info provided by bootloader\r
565\r
566 @retval RETURN_SUCCESS The misc information was parsed successfully.\r
567 @retval RETURN_NOT_FOUND Could not find required misc info.\r
568 @retval RETURN_OUT_OF_RESOURCES Insufficant memory space.\r
569\r
570**/\r
571RETURN_STATUS\r
572EFIAPI\r
573ParseMiscInfo (\r
574 VOID\r
575 )\r
576{\r
577 return RETURN_SUCCESS;\r
578}\r