]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/AcpiPlatformDxe/Qemu.c
OvmfPkg: AcpiPlatformDxe: exclude RSD PTR from QEMU's fw_cfg payload
[mirror_edk2.git] / OvmfPkg / AcpiPlatformDxe / Qemu.c
1 /** @file
2 OVMF ACPI QEMU support
3
4 Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
5
6 Copyright (C) 2012-2014, Red Hat, Inc.
7
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15
16 **/
17
18 #include "AcpiPlatform.h"
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/MemoryAllocationLib.h>
21 #include <Library/QemuFwCfgLib.h>
22 #include <Library/DxeServicesTableLib.h>
23 #include <Library/PcdLib.h>
24 #include <IndustryStandard/Acpi.h>
25
26 BOOLEAN
27 QemuDetected (
28 VOID
29 )
30 {
31 if (!QemuFwCfgIsAvailable ()) {
32 return FALSE;
33 }
34
35 return TRUE;
36 }
37
38
39 STATIC
40 UINTN
41 CountBits16 (
42 UINT16 Mask
43 )
44 {
45 //
46 // For all N >= 1, N bits are enough to represent the number of bits set
47 // among N bits. It's true for N == 1. When adding a new bit (N := N+1),
48 // the maximum number of possibly set bits increases by one, while the
49 // representable maximum doubles.
50 //
51 Mask = ((Mask & 0xAAAA) >> 1) + (Mask & 0x5555);
52 Mask = ((Mask & 0xCCCC) >> 2) + (Mask & 0x3333);
53 Mask = ((Mask & 0xF0F0) >> 4) + (Mask & 0x0F0F);
54 Mask = ((Mask & 0xFF00) >> 8) + (Mask & 0x00FF);
55
56 return Mask;
57 }
58
59
60 STATIC
61 EFI_STATUS
62 EFIAPI
63 QemuInstallAcpiMadtTable (
64 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
65 IN VOID *AcpiTableBuffer,
66 IN UINTN AcpiTableBufferSize,
67 OUT UINTN *TableKey
68 )
69 {
70 UINTN CpuCount;
71 UINTN PciLinkIsoCount;
72 UINTN NewBufferSize;
73 EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *Madt;
74 EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE *LocalApic;
75 EFI_ACPI_1_0_IO_APIC_STRUCTURE *IoApic;
76 EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE *Iso;
77 EFI_ACPI_1_0_LOCAL_APIC_NMI_STRUCTURE *LocalApicNmi;
78 VOID *Ptr;
79 UINTN Loop;
80 EFI_STATUS Status;
81
82 ASSERT (AcpiTableBufferSize >= sizeof (EFI_ACPI_DESCRIPTION_HEADER));
83
84 QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount);
85 CpuCount = QemuFwCfgRead16 ();
86 ASSERT (CpuCount >= 1);
87
88 //
89 // Set Level-tiggered, Active High for these identity mapped IRQs. The bitset
90 // corresponds to the union of all possible interrupt assignments for the LNKA,
91 // LNKB, LNKC, LNKD PCI interrupt lines. See the DSDT.
92 //
93 PciLinkIsoCount = CountBits16 (PcdGet16 (Pcd8259LegacyModeEdgeLevel));
94
95 NewBufferSize = 1 * sizeof (*Madt) +
96 CpuCount * sizeof (*LocalApic) +
97 1 * sizeof (*IoApic) +
98 (1 + PciLinkIsoCount) * sizeof (*Iso) +
99 1 * sizeof (*LocalApicNmi);
100
101 Madt = AllocatePool (NewBufferSize);
102 if (Madt == NULL) {
103 return EFI_OUT_OF_RESOURCES;
104 }
105
106 CopyMem (&(Madt->Header), AcpiTableBuffer, sizeof (EFI_ACPI_DESCRIPTION_HEADER));
107 Madt->Header.Length = (UINT32) NewBufferSize;
108 Madt->LocalApicAddress = PcdGet32 (PcdCpuLocalApicBaseAddress);
109 Madt->Flags = EFI_ACPI_1_0_PCAT_COMPAT;
110 Ptr = Madt + 1;
111
112 LocalApic = Ptr;
113 for (Loop = 0; Loop < CpuCount; ++Loop) {
114 LocalApic->Type = EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC;
115 LocalApic->Length = sizeof (*LocalApic);
116 LocalApic->AcpiProcessorId = (UINT8) Loop;
117 LocalApic->ApicId = (UINT8) Loop;
118 LocalApic->Flags = 1; // enabled
119 ++LocalApic;
120 }
121 Ptr = LocalApic;
122
123 IoApic = Ptr;
124 IoApic->Type = EFI_ACPI_1_0_IO_APIC;
125 IoApic->Length = sizeof (*IoApic);
126 IoApic->IoApicId = (UINT8) CpuCount;
127 IoApic->Reserved = EFI_ACPI_RESERVED_BYTE;
128 IoApic->IoApicAddress = 0xFEC00000;
129 IoApic->SystemVectorBase = 0x00000000;
130 Ptr = IoApic + 1;
131
132 //
133 // IRQ0 (8254 Timer) => IRQ2 (PIC) Interrupt Source Override Structure
134 //
135 Iso = Ptr;
136 Iso->Type = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE;
137 Iso->Length = sizeof (*Iso);
138 Iso->Bus = 0x00; // ISA
139 Iso->Source = 0x00; // IRQ0
140 Iso->GlobalSystemInterruptVector = 0x00000002;
141 Iso->Flags = 0x0000; // Conforms to specs of the bus
142 ++Iso;
143
144 //
145 // Set Level-tiggered, Active High for all possible PCI link targets.
146 //
147 for (Loop = 0; Loop < 16; ++Loop) {
148 if ((PcdGet16 (Pcd8259LegacyModeEdgeLevel) & (1 << Loop)) == 0) {
149 continue;
150 }
151 Iso->Type = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE;
152 Iso->Length = sizeof (*Iso);
153 Iso->Bus = 0x00; // ISA
154 Iso->Source = (UINT8) Loop;
155 Iso->GlobalSystemInterruptVector = (UINT32) Loop;
156 Iso->Flags = 0x000D; // Level-tiggered, Active High
157 ++Iso;
158 }
159 ASSERT (
160 (UINTN) (Iso - (EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE *)Ptr) ==
161 1 + PciLinkIsoCount
162 );
163 Ptr = Iso;
164
165 LocalApicNmi = Ptr;
166 LocalApicNmi->Type = EFI_ACPI_1_0_LOCAL_APIC_NMI;
167 LocalApicNmi->Length = sizeof (*LocalApicNmi);
168 LocalApicNmi->AcpiProcessorId = 0xFF; // applies to all processors
169 //
170 // polarity and trigger mode of the APIC I/O input signals conform to the
171 // specifications of the bus
172 //
173 LocalApicNmi->Flags = 0x0000;
174 //
175 // Local APIC interrupt input LINTn to which NMI is connected.
176 //
177 LocalApicNmi->LocalApicInti = 0x01;
178 Ptr = LocalApicNmi + 1;
179
180 ASSERT ((UINTN) ((UINT8 *)Ptr - (UINT8 *)Madt) == NewBufferSize);
181 Status = InstallAcpiTable (AcpiProtocol, Madt, NewBufferSize, TableKey);
182
183 FreePool (Madt);
184
185 return Status;
186 }
187
188
189 #pragma pack(1)
190
191 typedef struct {
192 UINT64 Base;
193 UINT64 End;
194 UINT64 Length;
195 } PCI_WINDOW;
196
197 typedef struct {
198 PCI_WINDOW PciWindow32;
199 PCI_WINDOW PciWindow64;
200 } FIRMWARE_DATA;
201
202 typedef struct {
203 UINT8 BytePrefix;
204 UINT8 ByteValue;
205 } AML_BYTE;
206
207 typedef struct {
208 UINT8 NameOp;
209 UINT8 RootChar;
210 UINT8 NameChar[4];
211 UINT8 PackageOp;
212 UINT8 PkgLength;
213 UINT8 NumElements;
214 AML_BYTE Pm1aCntSlpTyp;
215 AML_BYTE Pm1bCntSlpTyp;
216 AML_BYTE Reserved[2];
217 } SYSTEM_STATE_PACKAGE;
218
219 #pragma pack()
220
221
222 STATIC
223 EFI_STATUS
224 EFIAPI
225 PopulateFwData(
226 OUT FIRMWARE_DATA *FwData
227 )
228 {
229 EFI_STATUS Status;
230 UINTN NumDesc;
231 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *AllDesc;
232
233 Status = gDS->GetMemorySpaceMap (&NumDesc, &AllDesc);
234 if (Status == EFI_SUCCESS) {
235 UINT64 NonMmio32MaxExclTop;
236 UINT64 Mmio32MinBase;
237 UINT64 Mmio32MaxExclTop;
238 UINTN CurDesc;
239
240 Status = EFI_UNSUPPORTED;
241
242 NonMmio32MaxExclTop = 0;
243 Mmio32MinBase = BASE_4GB;
244 Mmio32MaxExclTop = 0;
245
246 for (CurDesc = 0; CurDesc < NumDesc; ++CurDesc) {
247 CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Desc;
248 UINT64 ExclTop;
249
250 Desc = &AllDesc[CurDesc];
251 ExclTop = Desc->BaseAddress + Desc->Length;
252
253 if (ExclTop <= (UINT64) PcdGet32 (PcdOvmfFdBaseAddress)) {
254 switch (Desc->GcdMemoryType) {
255 case EfiGcdMemoryTypeNonExistent:
256 break;
257
258 case EfiGcdMemoryTypeReserved:
259 case EfiGcdMemoryTypeSystemMemory:
260 if (NonMmio32MaxExclTop < ExclTop) {
261 NonMmio32MaxExclTop = ExclTop;
262 }
263 break;
264
265 case EfiGcdMemoryTypeMemoryMappedIo:
266 if (Mmio32MinBase > Desc->BaseAddress) {
267 Mmio32MinBase = Desc->BaseAddress;
268 }
269 if (Mmio32MaxExclTop < ExclTop) {
270 Mmio32MaxExclTop = ExclTop;
271 }
272 break;
273
274 default:
275 ASSERT(0);
276 }
277 }
278 }
279
280 if (Mmio32MinBase < NonMmio32MaxExclTop) {
281 Mmio32MinBase = NonMmio32MaxExclTop;
282 }
283
284 if (Mmio32MinBase < Mmio32MaxExclTop) {
285 FwData->PciWindow32.Base = Mmio32MinBase;
286 FwData->PciWindow32.End = Mmio32MaxExclTop - 1;
287 FwData->PciWindow32.Length = Mmio32MaxExclTop - Mmio32MinBase;
288
289 FwData->PciWindow64.Base = 0;
290 FwData->PciWindow64.End = 0;
291 FwData->PciWindow64.Length = 0;
292
293 Status = EFI_SUCCESS;
294 }
295
296 FreePool (AllDesc);
297 }
298
299 DEBUG ((
300 DEBUG_INFO,
301 "ACPI PciWindow32: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
302 FwData->PciWindow32.Base,
303 FwData->PciWindow32.End,
304 FwData->PciWindow32.Length
305 ));
306 DEBUG ((
307 DEBUG_INFO,
308 "ACPI PciWindow64: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
309 FwData->PciWindow64.Base,
310 FwData->PciWindow64.End,
311 FwData->PciWindow64.Length
312 ));
313
314 return Status;
315 }
316
317
318 STATIC
319 VOID
320 EFIAPI
321 GetSuspendStates (
322 UINTN *SuspendToRamSize,
323 SYSTEM_STATE_PACKAGE *SuspendToRam,
324 UINTN *SuspendToDiskSize,
325 SYSTEM_STATE_PACKAGE *SuspendToDisk
326 )
327 {
328 STATIC CONST SYSTEM_STATE_PACKAGE Template = {
329 0x08, // NameOp
330 '\\', // RootChar
331 { '_', 'S', 'x', '_' }, // NameChar[4]
332 0x12, // PackageOp
333 0x0A, // PkgLength
334 0x04, // NumElements
335 { 0x0A, 0x00 }, // Pm1aCntSlpTyp
336 { 0x0A, 0x00 }, // Pm1bCntSlpTyp -- we don't support it
337 { // Reserved[2]
338 { 0x0A, 0x00 },
339 { 0x0A, 0x00 }
340 }
341 };
342 RETURN_STATUS Status;
343 FIRMWARE_CONFIG_ITEM FwCfgItem;
344 UINTN FwCfgSize;
345 UINT8 SystemStates[6];
346
347 //
348 // configure defaults
349 //
350 *SuspendToRamSize = sizeof Template;
351 CopyMem (SuspendToRam, &Template, sizeof Template);
352 SuspendToRam->NameChar[2] = '3'; // S3
353 SuspendToRam->Pm1aCntSlpTyp.ByteValue = 1; // PIIX4: STR
354
355 *SuspendToDiskSize = sizeof Template;
356 CopyMem (SuspendToDisk, &Template, sizeof Template);
357 SuspendToDisk->NameChar[2] = '4'; // S4
358 SuspendToDisk->Pm1aCntSlpTyp.ByteValue = 2; // PIIX4: POSCL
359
360 //
361 // check for overrides
362 //
363 Status = QemuFwCfgFindFile ("etc/system-states", &FwCfgItem, &FwCfgSize);
364 if (Status != RETURN_SUCCESS || FwCfgSize != sizeof SystemStates) {
365 DEBUG ((DEBUG_INFO, "ACPI using S3/S4 defaults\n"));
366 return;
367 }
368 QemuFwCfgSelectItem (FwCfgItem);
369 QemuFwCfgReadBytes (sizeof SystemStates, SystemStates);
370
371 //
372 // Each byte corresponds to a system state. In each byte, the MSB tells us
373 // whether the given state is enabled. If so, the three LSBs specify the
374 // value to be written to the PM control register's SUS_TYP bits.
375 //
376 if (SystemStates[3] & BIT7) {
377 SuspendToRam->Pm1aCntSlpTyp.ByteValue =
378 SystemStates[3] & (BIT2 | BIT1 | BIT0);
379 DEBUG ((DEBUG_INFO, "ACPI S3 value: %d\n",
380 SuspendToRam->Pm1aCntSlpTyp.ByteValue));
381 } else {
382 *SuspendToRamSize = 0;
383 DEBUG ((DEBUG_INFO, "ACPI S3 disabled\n"));
384 }
385
386 if (SystemStates[4] & BIT7) {
387 SuspendToDisk->Pm1aCntSlpTyp.ByteValue =
388 SystemStates[4] & (BIT2 | BIT1 | BIT0);
389 DEBUG ((DEBUG_INFO, "ACPI S4 value: %d\n",
390 SuspendToDisk->Pm1aCntSlpTyp.ByteValue));
391 } else {
392 *SuspendToDiskSize = 0;
393 DEBUG ((DEBUG_INFO, "ACPI S4 disabled\n"));
394 }
395 }
396
397
398 STATIC
399 EFI_STATUS
400 EFIAPI
401 QemuInstallAcpiSsdtTable (
402 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
403 IN VOID *AcpiTableBuffer,
404 IN UINTN AcpiTableBufferSize,
405 OUT UINTN *TableKey
406 )
407 {
408 EFI_STATUS Status;
409 FIRMWARE_DATA *FwData;
410
411 Status = EFI_OUT_OF_RESOURCES;
412
413 FwData = AllocateReservedPool (sizeof (*FwData));
414 if (FwData != NULL) {
415 UINTN SuspendToRamSize;
416 SYSTEM_STATE_PACKAGE SuspendToRam;
417 UINTN SuspendToDiskSize;
418 SYSTEM_STATE_PACKAGE SuspendToDisk;
419 UINTN SsdtSize;
420 UINT8 *Ssdt;
421
422 GetSuspendStates (&SuspendToRamSize, &SuspendToRam,
423 &SuspendToDiskSize, &SuspendToDisk);
424 SsdtSize = AcpiTableBufferSize + 17 + SuspendToRamSize + SuspendToDiskSize;
425 Ssdt = AllocatePool (SsdtSize);
426
427 if (Ssdt != NULL) {
428 Status = PopulateFwData (FwData);
429
430 if (Status == EFI_SUCCESS) {
431 UINT8 *SsdtPtr;
432
433 SsdtPtr = Ssdt;
434
435 CopyMem (SsdtPtr, AcpiTableBuffer, AcpiTableBufferSize);
436 SsdtPtr += AcpiTableBufferSize;
437
438 //
439 // build "OperationRegion(FWDT, SystemMemory, 0x12345678, 0x87654321)"
440 //
441 *(SsdtPtr++) = 0x5B; // ExtOpPrefix
442 *(SsdtPtr++) = 0x80; // OpRegionOp
443 *(SsdtPtr++) = 'F';
444 *(SsdtPtr++) = 'W';
445 *(SsdtPtr++) = 'D';
446 *(SsdtPtr++) = 'T';
447 *(SsdtPtr++) = 0x00; // SystemMemory
448 *(SsdtPtr++) = 0x0C; // DWordPrefix
449
450 //
451 // no virtual addressing yet, take the four least significant bytes
452 //
453 CopyMem(SsdtPtr, &FwData, 4);
454 SsdtPtr += 4;
455
456 *(SsdtPtr++) = 0x0C; // DWordPrefix
457
458 *(UINT32*) SsdtPtr = sizeof (*FwData);
459 SsdtPtr += 4;
460
461 //
462 // add suspend system states
463 //
464 CopyMem (SsdtPtr, &SuspendToRam, SuspendToRamSize);
465 SsdtPtr += SuspendToRamSize;
466 CopyMem (SsdtPtr, &SuspendToDisk, SuspendToDiskSize);
467 SsdtPtr += SuspendToDiskSize;
468
469 ASSERT((UINTN) (SsdtPtr - Ssdt) == SsdtSize);
470 ((EFI_ACPI_DESCRIPTION_HEADER *) Ssdt)->Length = (UINT32) SsdtSize;
471 Status = InstallAcpiTable (AcpiProtocol, Ssdt, SsdtSize, TableKey);
472 }
473
474 FreePool(Ssdt);
475 }
476
477 if (Status != EFI_SUCCESS) {
478 FreePool(FwData);
479 }
480 }
481
482 return Status;
483 }
484
485
486 EFI_STATUS
487 EFIAPI
488 QemuInstallAcpiTable (
489 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
490 IN VOID *AcpiTableBuffer,
491 IN UINTN AcpiTableBufferSize,
492 OUT UINTN *TableKey
493 )
494 {
495 EFI_ACPI_DESCRIPTION_HEADER *Hdr;
496 EFI_ACPI_TABLE_INSTALL_ACPI_TABLE TableInstallFunction;
497
498 Hdr = (EFI_ACPI_DESCRIPTION_HEADER*) AcpiTableBuffer;
499 switch (Hdr->Signature) {
500 case EFI_ACPI_1_0_APIC_SIGNATURE:
501 TableInstallFunction = QemuInstallAcpiMadtTable;
502 break;
503 case EFI_ACPI_1_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
504 TableInstallFunction = QemuInstallAcpiSsdtTable;
505 break;
506 default:
507 TableInstallFunction = InstallAcpiTable;
508 }
509
510 return TableInstallFunction (
511 AcpiProtocol,
512 AcpiTableBuffer,
513 AcpiTableBufferSize,
514 TableKey
515 );
516 }
517
518
519 /**
520 Check if an array of bytes starts with an RSD PTR structure.
521
522 Checksum is ignored.
523
524 @param[in] Buffer The array to check.
525
526 @param[in] Size Number of bytes in Buffer.
527
528 @param[out] RsdpSize If the function returns EFI_SUCCESS, this parameter
529 contains the size of the detected RSD PTR structure.
530
531 @retval EFI_SUCCESS RSD PTR structure detected at the beginning of
532 Buffer, and its advertised size does not exceed
533 Size.
534
535 @retval EFI_PROTOCOL_ERROR RSD PTR structure detected at the beginning of
536 Buffer, but it has inconsistent size.
537
538 @retval EFI_NOT_FOUND RSD PTR structure not found.
539
540 **/
541
542 STATIC
543 EFI_STATUS
544 CheckRsdp (
545 IN CONST VOID *Buffer,
546 IN UINTN Size,
547 OUT UINTN *RsdpSize
548 )
549 {
550 CONST UINT64 *Signature;
551 CONST EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp1;
552 CONST EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp2;
553
554 if (Size < sizeof *Signature) {
555 return EFI_NOT_FOUND;
556 }
557 Signature = Buffer;
558
559 if (*Signature != EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE) {
560 return EFI_NOT_FOUND;
561 }
562
563 //
564 // Signature found -- from this point on we can only report
565 // EFI_PROTOCOL_ERROR or EFI_SUCCESS.
566 //
567 if (Size < sizeof *Rsdp1) {
568 return EFI_PROTOCOL_ERROR;
569 }
570 Rsdp1 = Buffer;
571
572 if (Rsdp1->Reserved == 0) {
573 //
574 // ACPI 1.0 doesn't include the Length field
575 //
576 *RsdpSize = sizeof *Rsdp1;
577 return EFI_SUCCESS;
578 }
579
580 if (Size < sizeof *Rsdp2) {
581 return EFI_PROTOCOL_ERROR;
582 }
583 Rsdp2 = Buffer;
584
585 if (Size < Rsdp2->Length || Rsdp2->Length < sizeof *Rsdp2) {
586 return EFI_PROTOCOL_ERROR;
587 }
588
589 *RsdpSize = Rsdp2->Length;
590 return EFI_SUCCESS;
591 }
592
593 //
594 // We'll be saving the keys of installed tables so that we can roll them back
595 // in case of failure. 128 tables should be enough for anyone (TM).
596 //
597 #define INSTALLED_TABLES_MAX 128
598
599 /**
600 Download one ACPI table data file from QEMU and interpret it.
601
602 @param[in] FwCfgFile The NUL-terminated name of the fw_cfg file to
603 download and interpret.
604
605 @param[in] AcpiProtocol The ACPI table protocol used to install tables.
606
607 @param[in,out] InstalledKey On input, an array of INSTALLED_TABLES_MAX UINTN
608 elements, allocated by the caller. On output,
609 the function will have stored (appended) the
610 AcpiProtocol-internal keys of the ACPI tables
611 that the function has installed from the fw_cfg
612 file. The array reflects installed tables even
613 if the function returns with an error.
614
615 @param[in,out] NumInstalled On input, the number of entries already used in
616 InstalledKey; it must be in [0,
617 INSTALLED_TABLES_MAX] inclusive. On output, the
618 parameter is updated to the new cumulative count
619 of the keys stored in InstalledKey; the value
620 reflects installed tables even if the function
621 returns with an error.
622
623 @retval EFI_INVALID_PARAMETER NumInstalled is outside the allowed range on
624 input.
625
626 @retval EFI_UNSUPPORTED Firmware configuration is unavailable.
627
628 @retval EFI_NOT_FOUND The host doesn't export the requested fw_cfg
629 file.
630
631 @retval EFI_OUT_OF_RESOURCES Memory allocation failed, or no more room in
632 InstalledKey.
633
634 @retval EFI_PROTOCOL_ERROR Found truncated or invalid ACPI table header
635 in the fw_cfg contents.
636
637 @return Status codes returned by
638 AcpiProtocol->InstallAcpiTable().
639
640 **/
641
642 STATIC
643 EFI_STATUS
644 InstallQemuLinkedTables (
645 IN CONST CHAR8 *FwCfgFile,
646 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
647 IN OUT UINTN InstalledKey[INSTALLED_TABLES_MAX],
648 IN OUT INT32 *NumInstalled
649 )
650 {
651 EFI_STATUS Status;
652 FIRMWARE_CONFIG_ITEM TablesFile;
653 UINTN TablesFileSize;
654 UINT8 *Tables;
655 UINTN Processed;
656
657 if (*NumInstalled < 0 || *NumInstalled > INSTALLED_TABLES_MAX) {
658 return EFI_INVALID_PARAMETER;
659 }
660
661 Status = QemuFwCfgFindFile (FwCfgFile, &TablesFile, &TablesFileSize);
662 if (EFI_ERROR (Status)) {
663 DEBUG ((EFI_D_ERROR, "%a: \"%a\" unavailable: %r\n", __FUNCTION__,
664 FwCfgFile, Status));
665 return Status;
666 }
667
668 Tables = AllocatePool (TablesFileSize);
669 if (Tables == NULL) {
670 return EFI_OUT_OF_RESOURCES;
671 }
672
673 QemuFwCfgSelectItem (TablesFile);
674 QemuFwCfgReadBytes (TablesFileSize, Tables);
675
676 Processed = 0;
677 while (Processed < TablesFileSize) {
678 UINTN Remaining;
679 UINTN RsdpSize;
680 EFI_ACPI_DESCRIPTION_HEADER *Probe;
681
682 Remaining = TablesFileSize - Processed;
683
684 //
685 // See if we're looking at an RSD PTR structure.
686 //
687 RsdpSize = 0;
688 Status = CheckRsdp (Tables + Processed, Remaining, &RsdpSize);
689 if (Status == EFI_PROTOCOL_ERROR) {
690 //
691 // RSD PTR found but its size is inconsistent; abort processing. (Note
692 // that "RSD PTR found" excludes the NUL-padding case by definition.)
693 //
694 break;
695 }
696 if (!EFI_ERROR (Status)) {
697 //
698 // Consistent RSD PTR found, skip it.
699 //
700 DEBUG ((EFI_D_VERBOSE, "%a: \"%a\" offset 0x%016Lx: RSD PTR "
701 "Length=0x%08x\n", __FUNCTION__, FwCfgFile, (UINT64)Processed,
702 (UINT32)RsdpSize));
703 Processed += RsdpSize;
704 continue;
705 }
706 ASSERT (Status == EFI_NOT_FOUND);
707
708 //
709 // What we're looking at is not an RSD PTR structure; attempt to parse it
710 // as an ACPI table.
711 //
712 if (Remaining < sizeof *Probe) {
713 Status = EFI_PROTOCOL_ERROR;
714 break;
715 }
716
717 Probe = (EFI_ACPI_DESCRIPTION_HEADER *) (Tables + Processed);
718 if (Remaining < Probe->Length || Probe->Length < sizeof *Probe) {
719 Status = EFI_PROTOCOL_ERROR;
720 break;
721 }
722
723 DEBUG ((EFI_D_VERBOSE, "%a: \"%a\" offset 0x%016Lx:"
724 " Signature=\"%-4.4a\" Length=0x%08x\n",
725 __FUNCTION__, FwCfgFile, (UINT64) Processed,
726 (CONST CHAR8 *) &Probe->Signature, Probe->Length));
727
728 //
729 // skip automatically handled "root" tables: RSDT, XSDT
730 //
731 if (Probe->Signature !=
732 EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE &&
733 Probe->Signature !=
734 EFI_ACPI_2_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
735 if (*NumInstalled == INSTALLED_TABLES_MAX) {
736 DEBUG ((EFI_D_ERROR, "%a: can't install more than %d tables\n",
737 __FUNCTION__, INSTALLED_TABLES_MAX));
738 Status = EFI_OUT_OF_RESOURCES;
739 break;
740 }
741
742 Status = AcpiProtocol->InstallAcpiTable (AcpiProtocol, Probe,
743 Probe->Length, &InstalledKey[*NumInstalled]);
744 if (EFI_ERROR (Status)) {
745 DEBUG ((EFI_D_ERROR,
746 "%a: failed to install table \"%-4.4a\" at \"%a\" offset 0x%Lx: "
747 "%r\n", __FUNCTION__, (CONST CHAR8 *)&Probe->Signature, FwCfgFile,
748 (UINT64) Processed, Status));
749 break;
750 }
751
752 ++*NumInstalled;
753 }
754
755 Processed += Probe->Length;
756 }
757
758 //
759 // NUL-padding at the end is accepted
760 //
761 if (Status == EFI_PROTOCOL_ERROR) {
762 UINTN ErrorLocation;
763
764 ErrorLocation = Processed;
765 while (Processed < TablesFileSize && Tables[Processed] == '\0') {
766 ++Processed;
767 }
768 if (Processed < TablesFileSize) {
769 DEBUG ((EFI_D_ERROR, "%a: truncated or invalid ACPI table header at "
770 "\"%a\" offset 0x%Lx\n", __FUNCTION__, FwCfgFile,
771 (UINT64)ErrorLocation));
772 }
773 }
774
775 if (Processed == TablesFileSize) {
776 Status = EFI_SUCCESS;
777 } else {
778 ASSERT (EFI_ERROR (Status));
779 }
780
781 FreePool (Tables);
782 return Status;
783 }
784
785 /**
786 Download all ACPI table data files from QEMU and interpret them.
787
788 @param[in] AcpiProtocol The ACPI table protocol used to install tables.
789
790 @retval EFI_UNSUPPORTED Firmware configuration is unavailable.
791
792 @retval EFI_NOT_FOUND The host doesn't export the required fw_cfg
793 files.
794
795 @retval EFI_OUT_OF_RESOURCES Memory allocation failed, or more than
796 INSTALLED_TABLES_MAX tables found.
797
798 @retval EFI_PROTOCOL_ERROR Found truncated or invalid ACPI table header
799 in the fw_cfg contents.
800
801 @return Status codes returned by
802 AcpiProtocol->InstallAcpiTable().
803
804 **/
805
806 EFI_STATUS
807 EFIAPI
808 InstallAllQemuLinkedTables (
809 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol
810 )
811 {
812 UINTN *InstalledKey;
813 INT32 Installed;
814 EFI_STATUS Status;
815
816 InstalledKey = AllocatePool (INSTALLED_TABLES_MAX * sizeof *InstalledKey);
817 if (InstalledKey == NULL) {
818 return EFI_OUT_OF_RESOURCES;
819 }
820 Installed = 0;
821
822 Status = InstallQemuLinkedTables ("etc/acpi/tables", AcpiProtocol,
823 InstalledKey, &Installed);
824 if (EFI_ERROR (Status)) {
825 ASSERT (Status != EFI_INVALID_PARAMETER);
826 //
827 // Roll back partial installation.
828 //
829 while (Installed > 0) {
830 --Installed;
831 AcpiProtocol->UninstallAcpiTable (AcpiProtocol, InstalledKey[Installed]);
832 }
833 } else {
834 DEBUG ((EFI_D_INFO, "%a: installed %d tables\n", __FUNCTION__, Installed));
835 }
836
837 FreePool (InstalledKey);
838 return Status;
839 }