]> git.proxmox.com Git - mirror_edk2.git/blame - UefiPayloadPkg/Library/CbParseLib/CbParseLib.c
UefiPayloadPkg: Enhance UEFI payload for coreboot and Slim Bootloader
[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
5 Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>\r
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
143\r
144 //\r
145 // coreboot could pass coreboot table to UEFI payload\r
146 //\r
147 Header = (struct cb_header *)(UINTN)GET_BOOTLOADER_PARAMETER ();\r
148 if (IsValidCbTable (Header)) {\r
149 return Header;\r
150 }\r
151\r
152 //\r
153 // Find simplified coreboot table in memory range 0 ~ 4KB.\r
154 // Some GCC version does not allow directly access to NULL pointer,\r
155 // so start the search from 0x10 instead.\r
156 //\r
157 for (Idx = 16; Idx < 4096; Idx += 16) {\r
158 Header = (struct cb_header *)Idx;\r
159 if (Header->signature == CB_HEADER_SIGNATURE) {\r
160 break;\r
161 }\r
162 }\r
163\r
164 if (Idx >= 4096) {\r
165 return NULL;\r
166 }\r
167\r
168 //\r
169 // Check the coreboot header\r
170 //\r
171 if (!IsValidCbTable (Header)) {\r
172 return NULL;\r
173 }\r
174\r
175 //\r
176 // Find full coreboot table in high memory\r
177 //\r
178 CbTablePtr = NULL;\r
179 TmpPtr = (UINT8 *)Header + Header->header_bytes;\r
180 for (Idx = 0; Idx < Header->table_entries; Idx++) {\r
181 Record = (struct cb_record *)TmpPtr;\r
182 if (Record->tag == CB_TAG_FORWARD) {\r
183 CbTablePtr = (VOID *)(UINTN)((struct cb_forward *)(UINTN)Record)->forward;\r
184 break;\r
185 }\r
186 TmpPtr += Record->size;\r
187 }\r
188\r
189 //\r
190 // Check the coreboot header in high memory\r
191 //\r
192 if (!IsValidCbTable ((struct cb_header *)CbTablePtr)) {\r
193 return NULL;\r
194 }\r
195\r
196 SET_BOOTLOADER_PARAMETER ((UINT32)(UINTN)CbTablePtr);\r
197\r
198 return CbTablePtr;\r
199}\r
200\r
201\r
202/**\r
203 Find coreboot record with given Tag.\r
204\r
205 @param Tag The tag id to be found\r
206\r
207 @retval NULL The Tag is not found.\r
208 @retval Others The pointer to the record found.\r
209\r
210**/\r
211VOID *\r
212FindCbTag (\r
213 IN UINT32 Tag\r
214 )\r
215{\r
216 struct cb_header *Header;\r
217 struct cb_record *Record;\r
218 UINT8 *TmpPtr;\r
219 UINT8 *TagPtr;\r
220 UINTN Idx;\r
221\r
222 Header = (struct cb_header *) GetParameterBase ();\r
223\r
224 TagPtr = NULL;\r
225 TmpPtr = (UINT8 *)Header + Header->header_bytes;\r
226 for (Idx = 0; Idx < Header->table_entries; Idx++) {\r
227 Record = (struct cb_record *)TmpPtr;\r
228 if (Record->tag == Tag) {\r
229 TagPtr = TmpPtr;\r
230 break;\r
231 }\r
232 TmpPtr += Record->size;\r
233 }\r
234\r
235 return TagPtr;\r
236}\r
237\r
238\r
239/**\r
240 Find the given table with TableId from the given coreboot memory Root.\r
241\r
242 @param Root The coreboot memory table to be searched in\r
243 @param TableId Table id to be found\r
244 @param MemTable To save the base address of the memory table found\r
245 @param MemTableSize To save the size of memory table found\r
246\r
247 @retval RETURN_SUCCESS Successfully find out the memory table.\r
248 @retval RETURN_INVALID_PARAMETER Invalid input parameters.\r
249 @retval RETURN_NOT_FOUND Failed to find the memory table.\r
250\r
251**/\r
252RETURN_STATUS\r
253FindCbMemTable (\r
254 IN struct cbmem_root *Root,\r
255 IN UINT32 TableId,\r
256 OUT VOID **MemTable,\r
257 OUT UINT32 *MemTableSize\r
258 )\r
259{\r
260 UINTN Idx;\r
261 BOOLEAN IsImdEntry;\r
262 struct cbmem_entry *Entries;\r
263\r
264 if ((Root == NULL) || (MemTable == NULL)) {\r
265 return RETURN_INVALID_PARAMETER;\r
266 }\r
267 //\r
268 // Check if the entry is CBMEM or IMD\r
269 // and handle them separately\r
270 //\r
271 Entries = Root->entries;\r
272 if (Entries[0].magic == CBMEM_ENTRY_MAGIC) {\r
273 IsImdEntry = FALSE;\r
274 } else {\r
275 Entries = (struct cbmem_entry *)((struct imd_root *)Root)->entries;\r
276 if (Entries[0].magic == IMD_ENTRY_MAGIC) {\r
277 IsImdEntry = TRUE;\r
278 } else {\r
279 return RETURN_NOT_FOUND;\r
280 }\r
281 }\r
282\r
283 for (Idx = 0; Idx < Root->num_entries; Idx++) {\r
284 if (Entries[Idx].id == TableId) {\r
285 if (IsImdEntry) {\r
286 *MemTable = (VOID *) ((UINTN)Entries[Idx].start + (UINTN)Root);\r
287 } else {\r
288 *MemTable = (VOID *) (UINTN)Entries[Idx].start;\r
289 }\r
290 if (MemTableSize != NULL) {\r
291 *MemTableSize = Entries[Idx].size;\r
292 }\r
293\r
294 DEBUG ((DEBUG_INFO, "Find CbMemTable Id 0x%x, base %p, size 0x%x\n",\r
295 TableId, *MemTable, Entries[Idx].size));\r
296 return RETURN_SUCCESS;\r
297 }\r
298 }\r
299\r
300 return RETURN_NOT_FOUND;\r
301}\r
302\r
303/**\r
304 Acquire the coreboot memory table with the given table id\r
305\r
306 @param TableId Table id to be searched\r
307 @param MemTable Pointer to the base address of the memory table\r
308 @param MemTableSize Pointer to the size of the memory table\r
309\r
310 @retval RETURN_SUCCESS Successfully find out the memory table.\r
311 @retval RETURN_INVALID_PARAMETER Invalid input parameters.\r
312 @retval RETURN_NOT_FOUND Failed to find the memory table.\r
313\r
314**/\r
315RETURN_STATUS\r
316ParseCbMemTable (\r
317 IN UINT32 TableId,\r
318 OUT VOID **MemTable,\r
319 OUT UINT32 *MemTableSize\r
320 )\r
321{\r
322 EFI_STATUS Status;\r
323 struct cb_memory *rec;\r
324 struct cb_memory_range *Range;\r
325 UINT64 Start;\r
326 UINT64 Size;\r
327 UINTN Index;\r
328 struct cbmem_root *CbMemRoot;\r
329\r
330 if (MemTable == NULL) {\r
331 return RETURN_INVALID_PARAMETER;\r
332 }\r
333\r
334 *MemTable = NULL;\r
335 Status = RETURN_NOT_FOUND;\r
336\r
337 //\r
338 // Get the coreboot memory table\r
339 //\r
340 rec = (struct cb_memory *)FindCbTag (CB_TAG_MEMORY);\r
341 if (rec == NULL) {\r
342 return Status;\r
343 }\r
344\r
345 for (Index = 0; Index < MEM_RANGE_COUNT(rec); Index++) {\r
346 Range = MEM_RANGE_PTR(rec, Index);\r
347 Start = cb_unpack64(Range->start);\r
348 Size = cb_unpack64(Range->size);\r
349\r
350 if ((Range->type == CB_MEM_TABLE) && (Start > 0x1000)) {\r
351 CbMemRoot = (struct cbmem_root *)(UINTN)(Start + Size - DYN_CBMEM_ALIGN_SIZE);\r
352 Status = FindCbMemTable (CbMemRoot, TableId, MemTable, MemTableSize);\r
353 if (!EFI_ERROR (Status)) {\r
354 break;\r
355 }\r
356 }\r
357 }\r
358\r
359 return Status;\r
360}\r
361\r
362\r
363\r
364/**\r
365 Acquire the memory information from the coreboot table in memory.\r
366\r
367 @param MemInfoCallback The callback routine\r
368 @param Params Pointer to the callback routine parameter\r
369\r
370 @retval RETURN_SUCCESS Successfully find out the memory information.\r
371 @retval RETURN_NOT_FOUND Failed to find the memory information.\r
372\r
373**/\r
374RETURN_STATUS\r
375EFIAPI\r
376ParseMemoryInfo (\r
377 IN BL_MEM_INFO_CALLBACK MemInfoCallback,\r
378 IN VOID *Params\r
379 )\r
380{\r
381 struct cb_memory *rec;\r
382 struct cb_memory_range *Range;\r
383 UINTN Index;\r
384 MEMROY_MAP_ENTRY MemoryMap;\r
385\r
386 //\r
387 // Get the coreboot memory table\r
388 //\r
389 rec = (struct cb_memory *)FindCbTag (CB_TAG_MEMORY);\r
390 if (rec == NULL) {\r
391 return RETURN_NOT_FOUND;\r
392 }\r
393\r
394 for (Index = 0; Index < MEM_RANGE_COUNT(rec); Index++) {\r
395 Range = MEM_RANGE_PTR(rec, Index);\r
396 MemoryMap.Base = cb_unpack64(Range->start);\r
397 MemoryMap.Size = cb_unpack64(Range->size);\r
398 MemoryMap.Type = (UINT8)Range->type;\r
399 MemoryMap.Flag = 0;\r
400 DEBUG ((DEBUG_INFO, "%d. %016lx - %016lx [%02x]\n",\r
401 Index, MemoryMap.Base, MemoryMap.Base + MemoryMap.Size - 1, MemoryMap.Type));\r
402\r
403 MemInfoCallback (&MemoryMap, Params);\r
404 }\r
405\r
406 return RETURN_SUCCESS;\r
407}\r
408\r
409\r
410/**\r
411 Acquire acpi table and smbios table from coreboot\r
412\r
413 @param SystemTableInfo Pointer to the system table info\r
414\r
415 @retval RETURN_SUCCESS Successfully find out the tables.\r
416 @retval RETURN_NOT_FOUND Failed to find the tables.\r
417\r
418**/\r
419RETURN_STATUS\r
420EFIAPI\r
421ParseSystemTable (\r
422 OUT SYSTEM_TABLE_INFO *SystemTableInfo\r
423 )\r
424{\r
425 EFI_STATUS Status;\r
426 VOID *MemTable;\r
427 UINT32 MemTableSize;\r
428\r
429 Status = ParseCbMemTable (SIGNATURE_32 ('T', 'B', 'M', 'S'), &MemTable, &MemTableSize);\r
430 if (EFI_ERROR (Status)) {\r
431 return EFI_NOT_FOUND;\r
432 }\r
433 SystemTableInfo->SmbiosTableBase = (UINT64) (UINTN)MemTable;\r
434 SystemTableInfo->SmbiosTableSize = MemTableSize;\r
435\r
436 Status = ParseCbMemTable (SIGNATURE_32 ('I', 'P', 'C', 'A'), &MemTable, &MemTableSize);\r
437 if (EFI_ERROR (Status)) {\r
438 return EFI_NOT_FOUND;\r
439 }\r
440 SystemTableInfo->AcpiTableBase = (UINT64) (UINTN)MemTable;\r
441 SystemTableInfo->AcpiTableSize = MemTableSize;\r
442\r
443 return Status;\r
444}\r
445\r
446\r
447/**\r
448 Find the serial port information\r
449\r
450 @param SERIAL_PORT_INFO Pointer to serial port info structure\r
451\r
452 @retval RETURN_SUCCESS Successfully find the serial port information.\r
453 @retval RETURN_NOT_FOUND Failed to find the serial port information .\r
454\r
455**/\r
456RETURN_STATUS\r
457EFIAPI\r
458ParseSerialInfo (\r
459 OUT SERIAL_PORT_INFO *SerialPortInfo\r
460 )\r
461{\r
462 struct cb_serial *CbSerial;\r
463\r
464 CbSerial = FindCbTag (CB_TAG_SERIAL);\r
465 if (CbSerial == NULL) {\r
466 return RETURN_NOT_FOUND;\r
467 }\r
468\r
469 SerialPortInfo->BaseAddr = CbSerial->baseaddr;\r
470 SerialPortInfo->RegWidth = CbSerial->regwidth;\r
471 SerialPortInfo->Type = CbSerial->type;\r
472 SerialPortInfo->Baud = CbSerial->baud;\r
473 SerialPortInfo->InputHertz = CbSerial->input_hertz;\r
474 SerialPortInfo->UartPciAddr = CbSerial->uart_pci_addr;\r
475\r
476 return RETURN_SUCCESS;\r
477}\r
478\r
479/**\r
480 Find the video frame buffer information\r
481\r
482 @param GfxInfo Pointer to the EFI_PEI_GRAPHICS_INFO_HOB structure\r
483\r
484 @retval RETURN_SUCCESS Successfully find the video frame buffer information.\r
485 @retval RETURN_NOT_FOUND Failed to find the video frame buffer information .\r
486\r
487**/\r
488RETURN_STATUS\r
489EFIAPI\r
490ParseGfxInfo (\r
491 OUT EFI_PEI_GRAPHICS_INFO_HOB *GfxInfo\r
492 )\r
493{\r
494 struct cb_framebuffer *CbFbRec;\r
495 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *GfxMode;\r
496\r
497 if (GfxInfo == NULL) {\r
498 return RETURN_INVALID_PARAMETER;\r
499 }\r
500\r
501 CbFbRec = FindCbTag (CB_TAG_FRAMEBUFFER);\r
502 if (CbFbRec == NULL) {\r
503 return RETURN_NOT_FOUND;\r
504 }\r
505\r
506 DEBUG ((DEBUG_INFO, "Found coreboot video frame buffer information\n"));\r
507 DEBUG ((DEBUG_INFO, "physical_address: 0x%lx\n", CbFbRec->physical_address));\r
508 DEBUG ((DEBUG_INFO, "x_resolution: 0x%x\n", CbFbRec->x_resolution));\r
509 DEBUG ((DEBUG_INFO, "y_resolution: 0x%x\n", CbFbRec->y_resolution));\r
510 DEBUG ((DEBUG_INFO, "bits_per_pixel: 0x%x\n", CbFbRec->bits_per_pixel));\r
511 DEBUG ((DEBUG_INFO, "bytes_per_line: 0x%x\n", CbFbRec->bytes_per_line));\r
512\r
513 DEBUG ((DEBUG_INFO, "red_mask_size: 0x%x\n", CbFbRec->red_mask_size));\r
514 DEBUG ((DEBUG_INFO, "red_mask_pos: 0x%x\n", CbFbRec->red_mask_pos));\r
515 DEBUG ((DEBUG_INFO, "green_mask_size: 0x%x\n", CbFbRec->green_mask_size));\r
516 DEBUG ((DEBUG_INFO, "green_mask_pos: 0x%x\n", CbFbRec->green_mask_pos));\r
517 DEBUG ((DEBUG_INFO, "blue_mask_size: 0x%x\n", CbFbRec->blue_mask_size));\r
518 DEBUG ((DEBUG_INFO, "blue_mask_pos: 0x%x\n", CbFbRec->blue_mask_pos));\r
519 DEBUG ((DEBUG_INFO, "reserved_mask_size: 0x%x\n", CbFbRec->reserved_mask_size));\r
520 DEBUG ((DEBUG_INFO, "reserved_mask_pos: 0x%x\n", CbFbRec->reserved_mask_pos));\r
521\r
522 GfxMode = &GfxInfo->GraphicsMode;\r
523 GfxMode->Version = 0;\r
524 GfxMode->HorizontalResolution = CbFbRec->x_resolution;\r
525 GfxMode->VerticalResolution = CbFbRec->y_resolution;\r
526 GfxMode->PixelsPerScanLine = (CbFbRec->bytes_per_line << 3) / CbFbRec->bits_per_pixel;\r
527 if ((CbFbRec->red_mask_pos == 0) && (CbFbRec->green_mask_pos == 8) && (CbFbRec->blue_mask_pos == 16)) {\r
528 GfxMode->PixelFormat = PixelRedGreenBlueReserved8BitPerColor;\r
529 } else if ((CbFbRec->blue_mask_pos == 0) && (CbFbRec->green_mask_pos == 8) && (CbFbRec->red_mask_pos == 16)) {\r
530 GfxMode->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;\r
531 }\r
532 GfxMode->PixelInformation.RedMask = ((1 << CbFbRec->red_mask_size) - 1) << CbFbRec->red_mask_pos;\r
533 GfxMode->PixelInformation.GreenMask = ((1 << CbFbRec->green_mask_size) - 1) << CbFbRec->green_mask_pos;\r
534 GfxMode->PixelInformation.BlueMask = ((1 << CbFbRec->blue_mask_size) - 1) << CbFbRec->blue_mask_pos;\r
535 GfxMode->PixelInformation.ReservedMask = ((1 << CbFbRec->reserved_mask_size) - 1) << CbFbRec->reserved_mask_pos;\r
536\r
537 GfxInfo->FrameBufferBase = CbFbRec->physical_address;\r
538 GfxInfo->FrameBufferSize = CbFbRec->bytes_per_line * CbFbRec->y_resolution;\r
539\r
540 return RETURN_SUCCESS;\r
541}\r
542\r
543/**\r
544 Find the video frame buffer device information\r
545\r
546 @param GfxDeviceInfo Pointer to the EFI_PEI_GRAPHICS_DEVICE_INFO_HOB structure\r
547\r
548 @retval RETURN_SUCCESS Successfully find the video frame buffer information.\r
549 @retval RETURN_NOT_FOUND Failed to find the video frame buffer information.\r
550\r
551**/\r
552RETURN_STATUS\r
553EFIAPI\r
554ParseGfxDeviceInfo (\r
555 OUT EFI_PEI_GRAPHICS_DEVICE_INFO_HOB *GfxDeviceInfo\r
556 )\r
557{\r
558 return RETURN_NOT_FOUND;\r
559}\r
560\r