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