]> git.proxmox.com Git - mirror_edk2.git/blob - CorebootModulePkg/Library/CbParseLib/CbParseLib.c
56c8472f6caed23d4a08da4ddc3a854f6b4ddead
[mirror_edk2.git] / CorebootModulePkg / 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 - 2015, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include <Uefi/UefiBaseType.h>
17 #include <Library/BaseLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/PcdLib.h>
21 #include <Library/CbParseLib.h>
22
23 #include <IndustryStandard/Acpi.h>
24
25 #include "Coreboot.h"
26
27 /* Helpful inlines */
28
29 static UINT64 cb_unpack64(struct cbuint64 val)
30 {
31 return LShiftU64 (val.hi, 32) | val.lo;
32 }
33
34 UINT16
35 CbCheckSum16 (
36 IN UINT16 *Buffer,
37 IN UINTN Length
38 )
39 {
40 UINT32 Sum, TmpValue;
41 UINTN Idx;
42 UINT8 *TmpPtr;
43
44 Sum = 0;
45 TmpPtr = (UINT8 *)Buffer;
46 for(Idx = 0; Idx < Length; Idx++) {
47 TmpValue = TmpPtr[Idx];
48 if (Idx % 2 == 1) {
49 TmpValue <<= 8;
50 }
51
52 Sum += TmpValue;
53
54 // Wrap
55 if (Sum >= 0x10000) {
56 Sum = (Sum + (Sum >> 16)) & 0xFFFF;
57 }
58 }
59
60 return (UINT16)((~Sum) & 0xFFFF);
61 }
62
63 VOID *
64 FindCbTag (
65 IN VOID *Start,
66 IN UINT32 Tag
67 )
68 {
69 struct cb_header *Header;
70 struct cb_record *Record;
71 UINT8 *TmpPtr;
72 UINT8 *TagPtr;
73 UINTN Idx;
74 UINT16 CheckSum;
75
76 Header = NULL;
77 TmpPtr = (UINT8 *)Start;
78 for (Idx = 0; Idx < 4096; Idx += 16, TmpPtr += 16) {
79 Header = (struct cb_header *)TmpPtr;
80 if (Header->signature == CB_HEADER_SIGNATURE) {
81 break;
82 }
83 }
84
85 if (Idx >= 4096)
86 return NULL;
87
88 if (Header == NULL || !Header->table_bytes)
89 return NULL;
90
91 //
92 // Check the checksum of the coreboot table header
93 //
94 CheckSum = CbCheckSum16 ((UINT16 *)Header, sizeof (*Header));
95 if (CheckSum != 0) {
96 DEBUG ((EFI_D_ERROR, "Invalid coreboot table header checksum\n"));
97 return NULL;
98 }
99
100 CheckSum = CbCheckSum16 ((UINT16 *)(TmpPtr + sizeof (*Header)), Header->table_bytes);
101 if (CheckSum != Header->table_checksum) {
102 DEBUG ((EFI_D_ERROR, "Incorrect checksum of all the coreboot table entries\n"));
103 return NULL;
104 }
105
106 TagPtr = NULL;
107 TmpPtr += Header->header_bytes;
108 for (Idx = 0; Idx < Header->table_entries; Idx++) {
109 Record = (struct cb_record *)TmpPtr;
110 if (Record->tag == CB_TAG_FORWARD) {
111 TmpPtr = (VOID *)(UINTN)((struct cb_forward *)(UINTN)Record)->forward;
112 if (Tag == CB_TAG_FORWARD)
113 return TmpPtr;
114 else
115 return FindCbTag (TmpPtr, Tag);
116 }
117 if (Record->tag == Tag) {
118 TagPtr = TmpPtr;
119 break;
120 }
121 TmpPtr += Record->size;
122 }
123
124 return TagPtr;
125 }
126
127 RETURN_STATUS
128 FindCbMemTable (
129 IN struct cbmem_root *Root,
130 IN UINT32 TableId,
131 OUT VOID **pMemTable,
132 OUT UINT32 *pMemTableSize
133 )
134 {
135 UINTN Idx;
136 BOOLEAN IsImdEntry;
137 struct cbmem_entry *Entries;
138
139 if ((Root == NULL) || (pMemTable == NULL)) {
140 return RETURN_INVALID_PARAMETER;
141 }
142
143 //
144 // Check if the entry is CBMEM or IMD
145 // and handle them separately
146 //
147 Entries = Root->entries;
148 if (Entries[0].magic == CBMEM_ENTRY_MAGIC) {
149 IsImdEntry = FALSE;
150 } else {
151 Entries = (struct cbmem_entry *)((struct imd_root *)Root)->entries;
152 if (Entries[0].magic == IMD_ENTRY_MAGIC) {
153 IsImdEntry = TRUE;
154 } else {
155 return RETURN_NOT_FOUND;
156 }
157 }
158
159 for (Idx = 0; Idx < Root->num_entries; Idx++) {
160 if (Entries[Idx].id == TableId) {
161 if (IsImdEntry) {
162 *pMemTable = (VOID *) ((UINTN)Entries[Idx].start + (UINTN)Root);
163 } else {
164 *pMemTable = (VOID *) (UINTN)Entries[Idx].start;
165 }
166 if (pMemTableSize != NULL) {
167 *pMemTableSize = Entries[Idx].size;
168 }
169
170 DEBUG ((EFI_D_INFO, "Find CbMemTable Id 0x%x, base %p, size 0x%x\n", TableId, *pMemTable, *pMemTableSize));
171 return RETURN_SUCCESS;
172 }
173 }
174
175 return RETURN_NOT_FOUND;
176 }
177
178
179 /**
180 Acquire the memory information from the coreboot table in memory.
181
182 @param pLowMemorySize Pointer to the variable of low memory size
183 @param pHighMemorySize Pointer to the variable of high memory size
184
185 @retval RETURN_SUCCESS Successfully find out the memory information.
186 @retval RETURN_INVALID_PARAMETER Invalid input parameters.
187 @retval RETURN_NOT_FOUND Failed to find the memory information.
188
189 **/
190 RETURN_STATUS
191 CbParseMemoryInfo (
192 IN UINT64* pLowMemorySize,
193 IN UINT64* pHighMemorySize
194 )
195 {
196 struct cb_memory* rec;
197 struct cb_memory_range* Range;
198 UINT64 Start;
199 UINT64 Size;
200 UINTN Index;
201
202 if ((!pLowMemorySize) || (!pHighMemorySize))
203 return RETURN_INVALID_PARAMETER;
204
205 //
206 // Get the coreboot memory table
207 //
208 rec = (struct cb_memory *)FindCbTag (0, CB_TAG_MEMORY);
209 if (!rec)
210 rec = (struct cb_memory *)FindCbTag ((VOID *)(UINTN)PcdGet32 (PcdCbHeaderPointer), CB_TAG_MEMORY);
211
212 if (!rec)
213 return RETURN_NOT_FOUND;
214
215 *pLowMemorySize = 0;
216 *pHighMemorySize = 0;
217
218 for (Index = 0; Index < MEM_RANGE_COUNT(rec); Index++) {
219 Range = MEM_RANGE_PTR(rec, Index);
220 Start = cb_unpack64(Range->start);
221 Size = cb_unpack64(Range->size);
222 DEBUG ((EFI_D_ERROR, "%d. %016lx - %016lx [%02x]\n",
223 Index, Start, Start + Size - 1, Range->type));
224
225 if (Range->type != CB_MEM_RAM) {
226 continue;
227 }
228
229 if (Start + Size < 0x100000000ULL) {
230 *pLowMemorySize = Start + Size;
231 } else {
232 *pHighMemorySize = Start + Size - 0x100000000ULL;
233 }
234 }
235
236 DEBUG ((EFI_D_ERROR, "Low memory 0x%lx, High Memory 0x%lx\n", *pLowMemorySize, *pHighMemorySize));
237
238 return RETURN_SUCCESS;
239 }
240
241
242 /**
243 Acquire the coreboot memory table with the given table id
244
245 @param TableId Table id to be searched
246 @param pMemTable Pointer to the base address of the memory table
247 @param pMemTableSize Pointer to the size of the memory table
248
249 @retval RETURN_SUCCESS Successfully find out the memory table.
250 @retval RETURN_INVALID_PARAMETER Invalid input parameters.
251 @retval RETURN_NOT_FOUND Failed to find the memory table.
252
253 **/
254 RETURN_STATUS
255 CbParseCbMemTable (
256 IN UINT32 TableId,
257 IN VOID** pMemTable,
258 IN UINT32* pMemTableSize
259 )
260 {
261 struct cb_memory* rec;
262 struct cb_memory_range* Range;
263 UINT64 Start;
264 UINT64 Size;
265 UINTN Index;
266
267 if (!pMemTable)
268 return RETURN_INVALID_PARAMETER;
269
270 *pMemTable = NULL;
271
272 //
273 // Get the coreboot memory table
274 //
275 rec = (struct cb_memory *)FindCbTag (0, CB_TAG_MEMORY);
276 if (!rec)
277 rec = (struct cb_memory *)FindCbTag ((VOID *)(UINTN)PcdGet32 (PcdCbHeaderPointer), CB_TAG_MEMORY);
278
279 if (!rec)
280 return RETURN_NOT_FOUND;
281
282 for (Index = 0; Index < MEM_RANGE_COUNT(rec); Index++) {
283 Range = MEM_RANGE_PTR(rec, Index);
284 Start = cb_unpack64(Range->start);
285 Size = cb_unpack64(Range->size);
286
287 if ((Range->type == CB_MEM_TABLE) && (Start > 0x1000)) {
288 if (FindCbMemTable ((struct cbmem_root *)(UINTN)(Start + Size - DYN_CBMEM_ALIGN_SIZE), TableId, pMemTable, pMemTableSize) == RETURN_SUCCESS)
289 return RETURN_SUCCESS;
290 }
291 }
292
293 return RETURN_NOT_FOUND;
294 }
295
296
297 /**
298 Acquire the acpi table from coreboot
299
300 @param pMemTable Pointer to the base address of the memory table
301 @param pMemTableSize Pointer to the size of the memory table
302
303 @retval RETURN_SUCCESS Successfully find out the memory table.
304 @retval RETURN_INVALID_PARAMETER Invalid input parameters.
305 @retval RETURN_NOT_FOUND Failed to find the memory table.
306
307 **/
308 RETURN_STATUS
309 CbParseAcpiTable (
310 IN VOID* pMemTable,
311 IN UINT32* pMemTableSize
312 )
313 {
314 return CbParseCbMemTable (SIGNATURE_32 ('I', 'P', 'C', 'A'), (VOID **)pMemTable, pMemTableSize);
315 }
316
317 /**
318 Acquire the smbios table from coreboot
319
320 @param pMemTable Pointer to the base address of the memory table
321 @param pMemTableSize Pointer to the size of the memory table
322
323 @retval RETURN_SUCCESS Successfully find out the memory table.
324 @retval RETURN_INVALID_PARAMETER Invalid input parameters.
325 @retval RETURN_NOT_FOUND Failed to find the memory table.
326
327 **/
328 RETURN_STATUS
329 CbParseSmbiosTable (
330 IN VOID** pMemTable,
331 IN UINT32* pMemTableSize
332 )
333 {
334 return CbParseCbMemTable (SIGNATURE_32 ('T', 'B', 'M', 'S'), pMemTable, pMemTableSize);
335 }
336
337 /**
338 Find the required fadt information
339
340 @param pPmCtrlReg Pointer to the address of power management control register
341 @param pPmTimerReg Pointer to the address of power management timer register
342 @param pResetReg Pointer to the address of system reset register
343 @param pResetValue Pointer to the value to be writen to the system reset register
344
345 @retval RETURN_SUCCESS Successfully find out all the required fadt information.
346 @retval RETURN_NOT_FOUND Failed to find the fadt table.
347
348 **/
349 RETURN_STATUS
350 CbParseFadtInfo (
351 IN UINTN* pPmCtrlReg,
352 IN UINTN* pPmTimerReg,
353 IN UINTN* pResetReg,
354 IN UINTN* pResetValue
355 )
356 {
357 EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER* Rsdp;
358 EFI_ACPI_DESCRIPTION_HEADER* Rsdt;
359 UINT32* Entry32;
360 UINTN Entry32Num;
361 EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE* Fadt;
362 EFI_ACPI_DESCRIPTION_HEADER* Xsdt;
363 UINT64* Entry64;
364 UINTN Entry64Num;
365 UINTN Idx;
366 RETURN_STATUS Status;
367
368 Rsdp = NULL;
369 Status = RETURN_SUCCESS;
370
371 Status = CbParseAcpiTable (&Rsdp, NULL);
372 if (RETURN_ERROR(Status))
373 return Status;
374
375 if (!Rsdp)
376 return RETURN_NOT_FOUND;
377
378 DEBUG ((EFI_D_ERROR, "Find Rsdp at %p\n", Rsdp));
379 DEBUG ((EFI_D_ERROR, "Find Rsdt 0x%x, Xsdt 0x%lx\n", Rsdp->RsdtAddress, Rsdp->XsdtAddress));
380
381 //
382 // Search Rsdt First
383 //
384 Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)(Rsdp->RsdtAddress);
385 if (Rsdt != NULL) {
386 Entry32 = (UINT32 *)(Rsdt + 1);
387 Entry32Num = (Rsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) >> 2;
388 for (Idx = 0; Idx < Entry32Num; Idx++) {
389 if (*(UINT32 *)(UINTN)(Entry32[Idx]) == EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
390 Fadt = (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *)(UINTN)(Entry32[Idx]);
391 if (pPmCtrlReg)
392 *pPmCtrlReg = Fadt->Pm1aCntBlk;
393 DEBUG ((EFI_D_ERROR, "PmCtrl Reg 0x%x\n", Fadt->Pm1aCntBlk));
394
395 if (pPmTimerReg)
396 *pPmTimerReg = Fadt->PmTmrBlk;
397 DEBUG ((EFI_D_ERROR, "PmTimer Reg 0x%x\n", Fadt->PmTmrBlk));
398
399 if (pResetReg)
400 *pResetReg = (UINTN)Fadt->ResetReg.Address;
401 DEBUG ((EFI_D_ERROR, "Reset Reg 0x%lx\n", Fadt->ResetReg.Address));
402
403 if (pResetValue)
404 *pResetValue = Fadt->ResetValue;
405 DEBUG ((EFI_D_ERROR, "Reset Value 0x%x\n", Fadt->ResetValue));
406
407 return RETURN_SUCCESS;
408 }
409 }
410 }
411
412 //
413 // Search Xsdt Second
414 //
415 Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)(Rsdp->XsdtAddress);
416 if (Xsdt != NULL) {
417 Entry64 = (UINT64 *)(Xsdt + 1);
418 Entry64Num = (Xsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) >> 3;
419 for (Idx = 0; Idx < Entry64Num; Idx++) {
420 if (*(UINT32 *)(UINTN)(Entry64[Idx]) == EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
421 Fadt = (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *)(UINTN)(Entry64[Idx]);
422 if (pPmCtrlReg)
423 *pPmCtrlReg = Fadt->Pm1aCntBlk;
424 DEBUG ((EFI_D_ERROR, "PmCtrl Reg 0x%x\n", Fadt->Pm1aCntBlk));
425
426 if (pPmTimerReg)
427 *pPmTimerReg = Fadt->PmTmrBlk;
428 DEBUG ((EFI_D_ERROR, "PmTimer Reg 0x%x\n", Fadt->PmTmrBlk));
429
430 if (pResetReg)
431 *pResetReg = (UINTN)Fadt->ResetReg.Address;
432 DEBUG ((EFI_D_ERROR, "Reset Reg 0x%lx\n", Fadt->ResetReg.Address));
433
434 if (pResetValue)
435 *pResetValue = Fadt->ResetValue;
436 DEBUG ((EFI_D_ERROR, "Reset Value 0x%x\n", Fadt->ResetValue));
437
438 return RETURN_SUCCESS;
439 }
440 }
441 }
442
443 return RETURN_NOT_FOUND;
444 }
445
446 /**
447 Find the serial port information
448
449 @param pRegBase Pointer to the base address of serial port registers
450 @param pRegAccessType Pointer to the access type of serial port registers
451 @param pBaudrate Pointer to the serial port baudrate
452
453 @retval RETURN_SUCCESS Successfully find the serial port information.
454 @retval RETURN_NOT_FOUND Failed to find the serial port information .
455
456 **/
457 RETURN_STATUS
458 CbParseSerialInfo (
459 IN UINT32* pRegBase,
460 IN UINT32* pRegAccessType,
461 IN UINT32* pBaudrate
462 )
463 {
464 struct cb_serial* CbSerial;
465
466 CbSerial = FindCbTag (0, CB_TAG_SERIAL);
467 if (!CbSerial)
468 CbSerial = FindCbTag ((VOID *)(UINTN)PcdGet32 (PcdCbHeaderPointer), CB_TAG_SERIAL);
469
470 if (!CbSerial)
471 return RETURN_NOT_FOUND;
472
473 if (pRegBase)
474 *pRegBase = CbSerial->baseaddr;
475
476 if (pRegAccessType)
477 *pRegAccessType = CbSerial->type;
478
479 if (pBaudrate)
480 *pBaudrate = CbSerial->baud;
481
482 return RETURN_SUCCESS;
483 }
484
485 /**
486 Search for the coreboot table header
487
488 @param Level Level of the search depth
489 @param HeaderPtr Pointer to the pointer of coreboot table header
490
491 @retval RETURN_SUCCESS Successfully find the coreboot table header .
492 @retval RETURN_NOT_FOUND Failed to find the coreboot table header .
493
494 **/
495 RETURN_STATUS
496 CbParseGetCbHeader (
497 IN UINTN Level,
498 IN VOID** HeaderPtr
499 )
500 {
501 UINTN Index;
502 VOID* TempPtr;
503
504 if (!HeaderPtr)
505 return RETURN_NOT_FOUND;
506
507 TempPtr = NULL;
508 for (Index = 0; Index < Level; Index++) {
509 TempPtr = FindCbTag (TempPtr, CB_TAG_FORWARD);
510 if (!TempPtr)
511 break;
512 }
513
514 if ((Index >= Level) && (TempPtr != NULL)) {
515 *HeaderPtr = TempPtr;
516 return RETURN_SUCCESS;
517 }
518
519 return RETURN_NOT_FOUND;
520 }
521
522 /**
523 Find the video frame buffer information
524
525 @param pFbInfo Pointer to the FRAME_BUFFER_INFO structure
526
527 @retval RETURN_SUCCESS Successfully find the video frame buffer information.
528 @retval RETURN_NOT_FOUND Failed to find the video frame buffer information .
529
530 **/
531 RETURN_STATUS
532 CbParseFbInfo (
533 IN FRAME_BUFFER_INFO* pFbInfo
534 )
535 {
536 struct cb_framebuffer* CbFbRec;
537
538 if (!pFbInfo)
539 return RETURN_INVALID_PARAMETER;
540
541 CbFbRec = FindCbTag (0, CB_TAG_FRAMEBUFFER);
542 if (!CbFbRec)
543 CbFbRec = FindCbTag ((VOID *)(UINTN)PcdGet32 (PcdCbHeaderPointer), CB_TAG_FRAMEBUFFER);
544
545 if (!CbFbRec)
546 return RETURN_NOT_FOUND;
547
548 DEBUG ((EFI_D_ERROR, "Found coreboot video frame buffer information\n"));
549 DEBUG ((EFI_D_ERROR, "physical_address: 0x%lx\n", CbFbRec->physical_address));
550 DEBUG ((EFI_D_ERROR, "x_resolution: 0x%x\n", CbFbRec->x_resolution));
551 DEBUG ((EFI_D_ERROR, "y_resolution: 0x%x\n", CbFbRec->y_resolution));
552 DEBUG ((EFI_D_ERROR, "bits_per_pixel: 0x%x\n", CbFbRec->bits_per_pixel));
553 DEBUG ((EFI_D_ERROR, "bytes_per_line: 0x%x\n", CbFbRec->bytes_per_line));
554
555 DEBUG ((EFI_D_ERROR, "red_mask_size: 0x%x\n", CbFbRec->red_mask_size));
556 DEBUG ((EFI_D_ERROR, "red_mask_pos: 0x%x\n", CbFbRec->red_mask_pos));
557 DEBUG ((EFI_D_ERROR, "green_mask_size: 0x%x\n", CbFbRec->green_mask_size));
558 DEBUG ((EFI_D_ERROR, "green_mask_pos: 0x%x\n", CbFbRec->green_mask_pos));
559 DEBUG ((EFI_D_ERROR, "blue_mask_size: 0x%x\n", CbFbRec->blue_mask_size));
560 DEBUG ((EFI_D_ERROR, "blue_mask_pos: 0x%x\n", CbFbRec->blue_mask_pos));
561 DEBUG ((EFI_D_ERROR, "reserved_mask_size: 0x%x\n", CbFbRec->reserved_mask_size));
562 DEBUG ((EFI_D_ERROR, "reserved_mask_pos: 0x%x\n", CbFbRec->reserved_mask_pos));
563
564 pFbInfo->LinearFrameBuffer = CbFbRec->physical_address;
565 pFbInfo->HorizontalResolution = CbFbRec->x_resolution;
566 pFbInfo->VerticalResolution = CbFbRec->y_resolution;
567 pFbInfo->BitsPerPixel = CbFbRec->bits_per_pixel;
568 pFbInfo->BytesPerScanLine = (UINT16)CbFbRec->bytes_per_line;
569 pFbInfo->Red.Mask = (1 << CbFbRec->red_mask_size) - 1;
570 pFbInfo->Red.Position = CbFbRec->red_mask_pos;
571 pFbInfo->Green.Mask = (1 << CbFbRec->green_mask_size) - 1;
572 pFbInfo->Green.Position = CbFbRec->green_mask_pos;
573 pFbInfo->Blue.Mask = (1 << CbFbRec->blue_mask_size) - 1;
574 pFbInfo->Blue.Position = CbFbRec->blue_mask_pos;
575 pFbInfo->Reserved.Mask = (1 << CbFbRec->reserved_mask_size) - 1;
576 pFbInfo->Reserved.Position = CbFbRec->reserved_mask_pos;
577
578 return RETURN_SUCCESS;
579 }
580
581