f4ba69f2cc0f3f8762cb0526cad54442a1c7a526
[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, 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 struct cbmem_root *root,
130 IN UINT32 TableId,
131 IN VOID** pMemTable,
132 IN UINT32* pMemTableSize
133 )
134 {
135 UINTN Idx;
136
137 if ((!root) || (!pMemTable))
138 return RETURN_INVALID_PARAMETER;
139
140 for (Idx = 0; Idx < root->num_entries; Idx++) {
141 if (root->entries[Idx].id == TableId) {
142 *pMemTable = (VOID *) (UINTN)root->entries[Idx].start;
143 if (pMemTableSize)
144 *pMemTableSize = root->entries[Idx].size;
145
146 DEBUG ((EFI_D_ERROR, "Find CbMemTable Id 0x%x, base 0x%x, size 0x%x\n", TableId, *pMemTable, *pMemTableSize));
147 return RETURN_SUCCESS;
148 }
149 }
150
151 return RETURN_NOT_FOUND;
152 }
153
154
155 /**
156 Acquire the memory information from the coreboot table in memory.
157
158 @param pLowMemorySize Pointer to the variable of low memory size
159 @param pHighMemorySize Pointer to the variable of high memory size
160
161 @retval RETURN_SUCCESS Successfully find out the memory information.
162 @retval RETURN_INVALID_PARAMETER Invalid input parameters.
163 @retval RETURN_NOT_FOUND Failed to find the memory information.
164
165 **/
166 RETURN_STATUS
167 CbParseMemoryInfo (
168 IN UINT64* pLowMemorySize,
169 IN UINT64* pHighMemorySize
170 )
171 {
172 struct cb_memory* rec;
173 struct cb_memory_range* Range;
174 UINT64 Start;
175 UINT64 Size;
176 UINTN Index;
177
178 if ((!pLowMemorySize) || (!pHighMemorySize))
179 return RETURN_INVALID_PARAMETER;
180
181 //
182 // Get the coreboot memory table
183 //
184 rec = (struct cb_memory *)FindCbTag (0, CB_TAG_MEMORY);
185 if (!rec)
186 rec = (struct cb_memory *)FindCbTag ((VOID *)(UINTN)PcdGet32 (PcdCbHeaderPointer), CB_TAG_MEMORY);
187
188 if (!rec)
189 return RETURN_NOT_FOUND;
190
191 *pLowMemorySize = 0;
192 *pHighMemorySize = 0;
193
194 for (Index = 0; Index < MEM_RANGE_COUNT(rec); Index++) {
195 Range = MEM_RANGE_PTR(rec, Index);
196 Start = cb_unpack64(Range->start);
197 Size = cb_unpack64(Range->size);
198 DEBUG ((EFI_D_ERROR, "%d. %016lx - %016lx [%02x]\n",
199 Index, Start, Start + Size - 1, Range->type));
200
201 if (Range->type != CB_MEM_RAM) {
202 continue;
203 }
204
205 if (Start + Size < 0x100000000ULL) {
206 *pLowMemorySize = Start + Size;
207 } else {
208 *pHighMemorySize = Start + Size - 0x100000000ULL;
209 }
210 }
211
212 DEBUG ((EFI_D_ERROR, "Low memory 0x%x, High Memory 0x%x\n", *pLowMemorySize, *pHighMemorySize));
213
214 return RETURN_SUCCESS;
215 }
216
217
218 /**
219 Acquire the coreboot memory table with the given table id
220
221 @param TableId Table id to be searched
222 @param pMemTable Pointer to the base address of the memory table
223 @param pMemTableSize Pointer to the size of the memory table
224
225 @retval RETURN_SUCCESS Successfully find out the memory table.
226 @retval RETURN_INVALID_PARAMETER Invalid input parameters.
227 @retval RETURN_NOT_FOUND Failed to find the memory table.
228
229 **/
230 RETURN_STATUS
231 CbParseCbMemTable (
232 IN UINT32 TableId,
233 IN VOID** pMemTable,
234 IN UINT32* pMemTableSize
235 )
236 {
237 struct cb_memory* rec;
238 struct cb_memory_range* Range;
239 UINT64 Start;
240 UINT64 Size;
241 UINTN Index;
242
243 if (!pMemTable)
244 return RETURN_INVALID_PARAMETER;
245
246 *pMemTable = NULL;
247
248 //
249 // Get the coreboot memory table
250 //
251 rec = (struct cb_memory *)FindCbTag (0, CB_TAG_MEMORY);
252 if (!rec)
253 rec = (struct cb_memory *)FindCbTag ((VOID *)(UINTN)PcdGet32 (PcdCbHeaderPointer), CB_TAG_MEMORY);
254
255 if (!rec)
256 return RETURN_NOT_FOUND;
257
258 for (Index = 0; Index < MEM_RANGE_COUNT(rec); Index++) {
259 Range = MEM_RANGE_PTR(rec, Index);
260 Start = cb_unpack64(Range->start);
261 Size = cb_unpack64(Range->size);
262
263 if ((Range->type == CB_MEM_TABLE) && (Start > 0x1000)) {
264 if (FindCbMemTable ((struct cbmem_root *)(UINTN)(Start + Size - DYN_CBMEM_ALIGN_SIZE), TableId, pMemTable, pMemTableSize) == RETURN_SUCCESS)
265 return RETURN_SUCCESS;
266 }
267 }
268
269 return RETURN_NOT_FOUND;
270 }
271
272
273 /**
274 Acquire the acpi table from coreboot
275
276 @param pMemTable Pointer to the base address of the memory table
277 @param pMemTableSize Pointer to the size of the memory table
278
279 @retval RETURN_SUCCESS Successfully find out the memory table.
280 @retval RETURN_INVALID_PARAMETER Invalid input parameters.
281 @retval RETURN_NOT_FOUND Failed to find the memory table.
282
283 **/
284 RETURN_STATUS
285 CbParseAcpiTable (
286 IN VOID* pMemTable,
287 IN UINT32* pMemTableSize
288 )
289 {
290 return CbParseCbMemTable (SIGNATURE_32 ('I', 'P', 'C', 'A'), (VOID **)pMemTable, pMemTableSize);
291 }
292
293 /**
294 Acquire the smbios table from coreboot
295
296 @param pMemTable Pointer to the base address of the memory table
297 @param pMemTableSize Pointer to the size of the memory table
298
299 @retval RETURN_SUCCESS Successfully find out the memory table.
300 @retval RETURN_INVALID_PARAMETER Invalid input parameters.
301 @retval RETURN_NOT_FOUND Failed to find the memory table.
302
303 **/
304 RETURN_STATUS
305 CbParseSmbiosTable (
306 IN VOID** pMemTable,
307 IN UINT32* pMemTableSize
308 )
309 {
310 return CbParseCbMemTable (SIGNATURE_32 ('T', 'B', 'M', 'S'), pMemTable, pMemTableSize);
311 }
312
313 /**
314 Find the required fadt information
315
316 @param pPmCtrlReg Pointer to the address of power management control register
317 @param pPmTimerReg Pointer to the address of power management timer register
318 @param pResetReg Pointer to the address of system reset register
319 @param pResetValue Pointer to the value to be writen to the system reset register
320
321 @retval RETURN_SUCCESS Successfully find out all the required fadt information.
322 @retval RETURN_NOT_FOUND Failed to find the fadt table.
323
324 **/
325 RETURN_STATUS
326 CbParseFadtInfo (
327 IN UINTN* pPmCtrlReg,
328 IN UINTN* pPmTimerReg,
329 IN UINTN* pResetReg,
330 IN UINTN* pResetValue
331 )
332 {
333 EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER* Rsdp;
334 EFI_ACPI_DESCRIPTION_HEADER* Rsdt;
335 UINT32* Entry32;
336 UINTN Entry32Num;
337 EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE* Fadt;
338 EFI_ACPI_DESCRIPTION_HEADER* Xsdt;
339 UINT64* Entry64;
340 UINTN Entry64Num;
341 UINTN Idx;
342 RETURN_STATUS Status;
343
344 Rsdp = NULL;
345 Status = RETURN_SUCCESS;
346
347 Status = CbParseAcpiTable (&Rsdp, NULL);
348 if (RETURN_ERROR(Status))
349 return Status;
350
351 if (!Rsdp)
352 return RETURN_NOT_FOUND;
353
354 DEBUG ((EFI_D_ERROR, "Find Rsdp at 0x%x\n", Rsdp));
355 DEBUG ((EFI_D_ERROR, "Find Rsdt 0x%x, Xsdt 0x%x\n", Rsdp->RsdtAddress, Rsdp->XsdtAddress));
356
357 //
358 // Search Rsdt First
359 //
360 Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)(Rsdp->RsdtAddress);
361 if (Rsdt != NULL) {
362 Entry32 = (UINT32 *)(Rsdt + 1);
363 Entry32Num = (Rsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) >> 2;
364 for (Idx = 0; Idx < Entry32Num; Idx++) {
365 if (*(UINT32 *)(UINTN)(Entry32[Idx]) == EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
366 Fadt = (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *)(UINTN)(Entry32[Idx]);
367 if (pPmCtrlReg)
368 *pPmCtrlReg = Fadt->Pm1aCntBlk;
369 DEBUG ((EFI_D_ERROR, "PmCtrl Reg 0x%x\n", Fadt->Pm1aCntBlk));
370
371 if (pPmTimerReg)
372 *pPmTimerReg = Fadt->PmTmrBlk;
373 DEBUG ((EFI_D_ERROR, "PmTimer Reg 0x%x\n", Fadt->PmTmrBlk));
374
375 if (pResetReg)
376 *pResetReg = (UINTN)Fadt->ResetReg.Address;
377 DEBUG ((EFI_D_ERROR, "Reset Reg 0x%x\n", Fadt->ResetReg.Address));
378
379 if (pResetValue)
380 *pResetValue = Fadt->ResetValue;
381 DEBUG ((EFI_D_ERROR, "Reset Value 0x%x\n", Fadt->ResetValue));
382
383 return RETURN_SUCCESS;
384 }
385 }
386 }
387
388 //
389 // Search Xsdt Second
390 //
391 Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)(Rsdp->XsdtAddress);
392 if (Xsdt != NULL) {
393 Entry64 = (UINT64 *)(Xsdt + 1);
394 Entry64Num = (Xsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) >> 3;
395 for (Idx = 0; Idx < Entry64Num; Idx++) {
396 if (*(UINT32 *)(UINTN)(Entry64[Idx]) == EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
397 Fadt = (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *)(UINTN)(Entry64[Idx]);
398 if (pPmCtrlReg)
399 *pPmCtrlReg = Fadt->Pm1aCntBlk;
400 DEBUG ((EFI_D_ERROR, "PmCtrl Reg 0x%x\n", Fadt->Pm1aCntBlk));
401
402 if (pPmTimerReg)
403 *pPmTimerReg = Fadt->PmTmrBlk;
404 DEBUG ((EFI_D_ERROR, "PmTimer Reg 0x%x\n", Fadt->PmTmrBlk));
405
406 if (pResetReg)
407 *pResetReg = (UINTN)Fadt->ResetReg.Address;
408 DEBUG ((EFI_D_ERROR, "Reset Reg 0x%x\n", Fadt->ResetReg.Address));
409
410 if (pResetValue)
411 *pResetValue = Fadt->ResetValue;
412 DEBUG ((EFI_D_ERROR, "Reset Value 0x%x\n", Fadt->ResetValue));
413
414 return RETURN_SUCCESS;
415 }
416 }
417 }
418
419 return RETURN_NOT_FOUND;
420 }
421
422 /**
423 Find the serial port information
424
425 @param pRegBase Pointer to the base address of serial port registers
426 @param pRegAccessType Pointer to the access type of serial port registers
427 @param pBaudrate Pointer to the serial port baudrate
428
429 @retval RETURN_SUCCESS Successfully find the serial port information.
430 @retval RETURN_NOT_FOUND Failed to find the serial port information .
431
432 **/
433 RETURN_STATUS
434 CbParseSerialInfo (
435 IN UINT32* pRegBase,
436 IN UINT32* pRegAccessType,
437 IN UINT32* pBaudrate
438 )
439 {
440 struct cb_serial* CbSerial;
441
442 CbSerial = FindCbTag (0, CB_TAG_SERIAL);
443 if (!CbSerial)
444 CbSerial = FindCbTag ((VOID *)(UINTN)PcdGet32 (PcdCbHeaderPointer), CB_TAG_SERIAL);
445
446 if (!CbSerial)
447 return RETURN_NOT_FOUND;
448
449 if (pRegBase)
450 *pRegBase = CbSerial->baseaddr;
451
452 if (pRegAccessType)
453 *pRegAccessType = CbSerial->type;
454
455 if (pBaudrate)
456 *pBaudrate = CbSerial->baud;
457
458 return RETURN_SUCCESS;
459 }
460
461 /**
462 Search for the coreboot table header
463
464 @param Level Level of the search depth
465 @param HeaderPtr Pointer to the pointer of coreboot table header
466
467 @retval RETURN_SUCCESS Successfully find the coreboot table header .
468 @retval RETURN_NOT_FOUND Failed to find the coreboot table header .
469
470 **/
471 RETURN_STATUS
472 CbParseGetCbHeader (
473 IN UINTN Level,
474 IN VOID** HeaderPtr
475 )
476 {
477 UINTN Index;
478 VOID* TempPtr;
479
480 if (!HeaderPtr)
481 return RETURN_NOT_FOUND;
482
483 TempPtr = NULL;
484 for (Index = 0; Index < Level; Index++) {
485 TempPtr = FindCbTag (TempPtr, CB_TAG_FORWARD);
486 if (!TempPtr)
487 break;
488 }
489
490 if ((Index >= Level) && (TempPtr != NULL)) {
491 *HeaderPtr = TempPtr;
492 return RETURN_SUCCESS;
493 }
494
495 return RETURN_NOT_FOUND;
496 }
497
498 /**
499 Find the video frame buffer information
500
501 @param pFbInfo Pointer to the FRAME_BUFFER_INFO structure
502
503 @retval RETURN_SUCCESS Successfully find the video frame buffer information.
504 @retval RETURN_NOT_FOUND Failed to find the video frame buffer information .
505
506 **/
507 RETURN_STATUS
508 CbParseFbInfo (
509 IN FRAME_BUFFER_INFO* pFbInfo
510 )
511 {
512 struct cb_framebuffer* CbFbRec;
513
514 if (!pFbInfo)
515 return RETURN_INVALID_PARAMETER;
516
517 CbFbRec = FindCbTag (0, CB_TAG_FRAMEBUFFER);
518 if (!CbFbRec)
519 CbFbRec = FindCbTag ((VOID *)(UINTN)PcdGet32 (PcdCbHeaderPointer), CB_TAG_FRAMEBUFFER);
520
521 if (!CbFbRec)
522 return RETURN_NOT_FOUND;
523
524 DEBUG ((EFI_D_ERROR, "Found coreboot video frame buffer information\n"));
525 DEBUG ((EFI_D_ERROR, "physical_address: 0x%x\n", CbFbRec->physical_address));
526 DEBUG ((EFI_D_ERROR, "x_resolution: 0x%x\n", CbFbRec->x_resolution));
527 DEBUG ((EFI_D_ERROR, "y_resolution: 0x%x\n", CbFbRec->y_resolution));
528 DEBUG ((EFI_D_ERROR, "bits_per_pixel: 0x%x\n", CbFbRec->bits_per_pixel));
529 DEBUG ((EFI_D_ERROR, "bytes_per_line: 0x%x\n", CbFbRec->bytes_per_line));
530
531 DEBUG ((EFI_D_ERROR, "red_mask_size: 0x%x\n", CbFbRec->red_mask_size));
532 DEBUG ((EFI_D_ERROR, "red_mask_pos: 0x%x\n", CbFbRec->red_mask_pos));
533 DEBUG ((EFI_D_ERROR, "green_mask_size: 0x%x\n", CbFbRec->green_mask_size));
534 DEBUG ((EFI_D_ERROR, "green_mask_pos: 0x%x\n", CbFbRec->green_mask_pos));
535 DEBUG ((EFI_D_ERROR, "blue_mask_size: 0x%x\n", CbFbRec->blue_mask_size));
536 DEBUG ((EFI_D_ERROR, "blue_mask_pos: 0x%x\n", CbFbRec->blue_mask_pos));
537 DEBUG ((EFI_D_ERROR, "reserved_mask_size: 0x%x\n", CbFbRec->reserved_mask_size));
538 DEBUG ((EFI_D_ERROR, "reserved_mask_pos: 0x%x\n", CbFbRec->reserved_mask_pos));
539
540 pFbInfo->LinearFrameBuffer = CbFbRec->physical_address;
541 pFbInfo->HorizontalResolution = CbFbRec->x_resolution;
542 pFbInfo->VerticalResolution = CbFbRec->y_resolution;
543 pFbInfo->BitsPerPixel = CbFbRec->bits_per_pixel;
544 pFbInfo->BytesPerScanLine = (UINT16)CbFbRec->bytes_per_line;
545 pFbInfo->Red.Mask = (1 << CbFbRec->red_mask_size) - 1;
546 pFbInfo->Red.Position = CbFbRec->red_mask_pos;
547 pFbInfo->Green.Mask = (1 << CbFbRec->green_mask_size) - 1;
548 pFbInfo->Green.Position = CbFbRec->green_mask_pos;
549 pFbInfo->Blue.Mask = (1 << CbFbRec->blue_mask_size) - 1;
550 pFbInfo->Blue.Position = CbFbRec->blue_mask_pos;
551 pFbInfo->Reserved.Mask = (1 << CbFbRec->reserved_mask_size) - 1;
552 pFbInfo->Reserved.Position = CbFbRec->reserved_mask_pos;
553
554 return RETURN_SUCCESS;
555 }
556
557