]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/AcpiPlatformDxe/Qemu.c
OvmfPkg/AcpiPlatformDxe: Fix VS2012 IA32 build warning
[mirror_edk2.git] / OvmfPkg / AcpiPlatformDxe / Qemu.c
1 /** @file
2 OVMF ACPI QEMU support
3
4 Copyright (c) 2008 - 2014, 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 "QemuLoader.h"
20 #include <Library/BaseMemoryLib.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/QemuFwCfgLib.h>
23 #include <Library/DxeServicesTableLib.h>
24 #include <Library/PcdLib.h>
25 #include <Library/OrderedCollectionLib.h>
26 #include <IndustryStandard/Acpi.h>
27
28 BOOLEAN
29 QemuDetected (
30 VOID
31 )
32 {
33 if (!QemuFwCfgIsAvailable ()) {
34 return FALSE;
35 }
36
37 return TRUE;
38 }
39
40
41 STATIC
42 UINTN
43 CountBits16 (
44 UINT16 Mask
45 )
46 {
47 //
48 // For all N >= 1, N bits are enough to represent the number of bits set
49 // among N bits. It's true for N == 1. When adding a new bit (N := N+1),
50 // the maximum number of possibly set bits increases by one, while the
51 // representable maximum doubles.
52 //
53 Mask = ((Mask & 0xAAAA) >> 1) + (Mask & 0x5555);
54 Mask = ((Mask & 0xCCCC) >> 2) + (Mask & 0x3333);
55 Mask = ((Mask & 0xF0F0) >> 4) + (Mask & 0x0F0F);
56 Mask = ((Mask & 0xFF00) >> 8) + (Mask & 0x00FF);
57
58 return Mask;
59 }
60
61
62 STATIC
63 EFI_STATUS
64 EFIAPI
65 QemuInstallAcpiMadtTable (
66 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
67 IN VOID *AcpiTableBuffer,
68 IN UINTN AcpiTableBufferSize,
69 OUT UINTN *TableKey
70 )
71 {
72 UINTN CpuCount;
73 UINTN PciLinkIsoCount;
74 UINTN NewBufferSize;
75 EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *Madt;
76 EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE *LocalApic;
77 EFI_ACPI_1_0_IO_APIC_STRUCTURE *IoApic;
78 EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE *Iso;
79 EFI_ACPI_1_0_LOCAL_APIC_NMI_STRUCTURE *LocalApicNmi;
80 VOID *Ptr;
81 UINTN Loop;
82 EFI_STATUS Status;
83
84 ASSERT (AcpiTableBufferSize >= sizeof (EFI_ACPI_DESCRIPTION_HEADER));
85
86 QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount);
87 CpuCount = QemuFwCfgRead16 ();
88 ASSERT (CpuCount >= 1);
89
90 //
91 // Set Level-tiggered, Active High for these identity mapped IRQs. The bitset
92 // corresponds to the union of all possible interrupt assignments for the LNKA,
93 // LNKB, LNKC, LNKD PCI interrupt lines. See the DSDT.
94 //
95 PciLinkIsoCount = CountBits16 (PcdGet16 (Pcd8259LegacyModeEdgeLevel));
96
97 NewBufferSize = 1 * sizeof (*Madt) +
98 CpuCount * sizeof (*LocalApic) +
99 1 * sizeof (*IoApic) +
100 (1 + PciLinkIsoCount) * sizeof (*Iso) +
101 1 * sizeof (*LocalApicNmi);
102
103 Madt = AllocatePool (NewBufferSize);
104 if (Madt == NULL) {
105 return EFI_OUT_OF_RESOURCES;
106 }
107
108 CopyMem (&(Madt->Header), AcpiTableBuffer, sizeof (EFI_ACPI_DESCRIPTION_HEADER));
109 Madt->Header.Length = (UINT32) NewBufferSize;
110 Madt->LocalApicAddress = PcdGet32 (PcdCpuLocalApicBaseAddress);
111 Madt->Flags = EFI_ACPI_1_0_PCAT_COMPAT;
112 Ptr = Madt + 1;
113
114 LocalApic = Ptr;
115 for (Loop = 0; Loop < CpuCount; ++Loop) {
116 LocalApic->Type = EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC;
117 LocalApic->Length = sizeof (*LocalApic);
118 LocalApic->AcpiProcessorId = (UINT8) Loop;
119 LocalApic->ApicId = (UINT8) Loop;
120 LocalApic->Flags = 1; // enabled
121 ++LocalApic;
122 }
123 Ptr = LocalApic;
124
125 IoApic = Ptr;
126 IoApic->Type = EFI_ACPI_1_0_IO_APIC;
127 IoApic->Length = sizeof (*IoApic);
128 IoApic->IoApicId = (UINT8) CpuCount;
129 IoApic->Reserved = EFI_ACPI_RESERVED_BYTE;
130 IoApic->IoApicAddress = 0xFEC00000;
131 IoApic->SystemVectorBase = 0x00000000;
132 Ptr = IoApic + 1;
133
134 //
135 // IRQ0 (8254 Timer) => IRQ2 (PIC) Interrupt Source Override Structure
136 //
137 Iso = Ptr;
138 Iso->Type = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE;
139 Iso->Length = sizeof (*Iso);
140 Iso->Bus = 0x00; // ISA
141 Iso->Source = 0x00; // IRQ0
142 Iso->GlobalSystemInterruptVector = 0x00000002;
143 Iso->Flags = 0x0000; // Conforms to specs of the bus
144 ++Iso;
145
146 //
147 // Set Level-tiggered, Active High for all possible PCI link targets.
148 //
149 for (Loop = 0; Loop < 16; ++Loop) {
150 if ((PcdGet16 (Pcd8259LegacyModeEdgeLevel) & (1 << Loop)) == 0) {
151 continue;
152 }
153 Iso->Type = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE;
154 Iso->Length = sizeof (*Iso);
155 Iso->Bus = 0x00; // ISA
156 Iso->Source = (UINT8) Loop;
157 Iso->GlobalSystemInterruptVector = (UINT32) Loop;
158 Iso->Flags = 0x000D; // Level-tiggered, Active High
159 ++Iso;
160 }
161 ASSERT (
162 (UINTN) (Iso - (EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE *)Ptr) ==
163 1 + PciLinkIsoCount
164 );
165 Ptr = Iso;
166
167 LocalApicNmi = Ptr;
168 LocalApicNmi->Type = EFI_ACPI_1_0_LOCAL_APIC_NMI;
169 LocalApicNmi->Length = sizeof (*LocalApicNmi);
170 LocalApicNmi->AcpiProcessorId = 0xFF; // applies to all processors
171 //
172 // polarity and trigger mode of the APIC I/O input signals conform to the
173 // specifications of the bus
174 //
175 LocalApicNmi->Flags = 0x0000;
176 //
177 // Local APIC interrupt input LINTn to which NMI is connected.
178 //
179 LocalApicNmi->LocalApicInti = 0x01;
180 Ptr = LocalApicNmi + 1;
181
182 ASSERT ((UINTN) ((UINT8 *)Ptr - (UINT8 *)Madt) == NewBufferSize);
183 Status = InstallAcpiTable (AcpiProtocol, Madt, NewBufferSize, TableKey);
184
185 FreePool (Madt);
186
187 return Status;
188 }
189
190
191 #pragma pack(1)
192
193 typedef struct {
194 UINT64 Base;
195 UINT64 End;
196 UINT64 Length;
197 } PCI_WINDOW;
198
199 typedef struct {
200 PCI_WINDOW PciWindow32;
201 PCI_WINDOW PciWindow64;
202 } FIRMWARE_DATA;
203
204 typedef struct {
205 UINT8 BytePrefix;
206 UINT8 ByteValue;
207 } AML_BYTE;
208
209 typedef struct {
210 UINT8 NameOp;
211 UINT8 RootChar;
212 UINT8 NameChar[4];
213 UINT8 PackageOp;
214 UINT8 PkgLength;
215 UINT8 NumElements;
216 AML_BYTE Pm1aCntSlpTyp;
217 AML_BYTE Pm1bCntSlpTyp;
218 AML_BYTE Reserved[2];
219 } SYSTEM_STATE_PACKAGE;
220
221 #pragma pack()
222
223
224 STATIC
225 EFI_STATUS
226 EFIAPI
227 PopulateFwData(
228 OUT FIRMWARE_DATA *FwData
229 )
230 {
231 EFI_STATUS Status;
232 UINTN NumDesc;
233 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *AllDesc;
234
235 Status = gDS->GetMemorySpaceMap (&NumDesc, &AllDesc);
236 if (Status == EFI_SUCCESS) {
237 UINT64 NonMmio32MaxExclTop;
238 UINT64 Mmio32MinBase;
239 UINT64 Mmio32MaxExclTop;
240 UINTN CurDesc;
241
242 Status = EFI_UNSUPPORTED;
243
244 NonMmio32MaxExclTop = 0;
245 Mmio32MinBase = BASE_4GB;
246 Mmio32MaxExclTop = 0;
247
248 for (CurDesc = 0; CurDesc < NumDesc; ++CurDesc) {
249 CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Desc;
250 UINT64 ExclTop;
251
252 Desc = &AllDesc[CurDesc];
253 ExclTop = Desc->BaseAddress + Desc->Length;
254
255 if (ExclTop <= (UINT64) PcdGet32 (PcdOvmfFdBaseAddress)) {
256 switch (Desc->GcdMemoryType) {
257 case EfiGcdMemoryTypeNonExistent:
258 break;
259
260 case EfiGcdMemoryTypeReserved:
261 case EfiGcdMemoryTypeSystemMemory:
262 if (NonMmio32MaxExclTop < ExclTop) {
263 NonMmio32MaxExclTop = ExclTop;
264 }
265 break;
266
267 case EfiGcdMemoryTypeMemoryMappedIo:
268 if (Mmio32MinBase > Desc->BaseAddress) {
269 Mmio32MinBase = Desc->BaseAddress;
270 }
271 if (Mmio32MaxExclTop < ExclTop) {
272 Mmio32MaxExclTop = ExclTop;
273 }
274 break;
275
276 default:
277 ASSERT(0);
278 }
279 }
280 }
281
282 if (Mmio32MinBase < NonMmio32MaxExclTop) {
283 Mmio32MinBase = NonMmio32MaxExclTop;
284 }
285
286 if (Mmio32MinBase < Mmio32MaxExclTop) {
287 FwData->PciWindow32.Base = Mmio32MinBase;
288 FwData->PciWindow32.End = Mmio32MaxExclTop - 1;
289 FwData->PciWindow32.Length = Mmio32MaxExclTop - Mmio32MinBase;
290
291 FwData->PciWindow64.Base = 0;
292 FwData->PciWindow64.End = 0;
293 FwData->PciWindow64.Length = 0;
294
295 Status = EFI_SUCCESS;
296 }
297
298 FreePool (AllDesc);
299 }
300
301 DEBUG ((
302 DEBUG_INFO,
303 "ACPI PciWindow32: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
304 FwData->PciWindow32.Base,
305 FwData->PciWindow32.End,
306 FwData->PciWindow32.Length
307 ));
308 DEBUG ((
309 DEBUG_INFO,
310 "ACPI PciWindow64: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
311 FwData->PciWindow64.Base,
312 FwData->PciWindow64.End,
313 FwData->PciWindow64.Length
314 ));
315
316 return Status;
317 }
318
319
320 STATIC
321 VOID
322 EFIAPI
323 GetSuspendStates (
324 UINTN *SuspendToRamSize,
325 SYSTEM_STATE_PACKAGE *SuspendToRam,
326 UINTN *SuspendToDiskSize,
327 SYSTEM_STATE_PACKAGE *SuspendToDisk
328 )
329 {
330 STATIC CONST SYSTEM_STATE_PACKAGE Template = {
331 0x08, // NameOp
332 '\\', // RootChar
333 { '_', 'S', 'x', '_' }, // NameChar[4]
334 0x12, // PackageOp
335 0x0A, // PkgLength
336 0x04, // NumElements
337 { 0x0A, 0x00 }, // Pm1aCntSlpTyp
338 { 0x0A, 0x00 }, // Pm1bCntSlpTyp -- we don't support it
339 { // Reserved[2]
340 { 0x0A, 0x00 },
341 { 0x0A, 0x00 }
342 }
343 };
344 RETURN_STATUS Status;
345 FIRMWARE_CONFIG_ITEM FwCfgItem;
346 UINTN FwCfgSize;
347 UINT8 SystemStates[6];
348
349 //
350 // configure defaults
351 //
352 *SuspendToRamSize = sizeof Template;
353 CopyMem (SuspendToRam, &Template, sizeof Template);
354 SuspendToRam->NameChar[2] = '3'; // S3
355 SuspendToRam->Pm1aCntSlpTyp.ByteValue = 1; // PIIX4: STR
356
357 *SuspendToDiskSize = sizeof Template;
358 CopyMem (SuspendToDisk, &Template, sizeof Template);
359 SuspendToDisk->NameChar[2] = '4'; // S4
360 SuspendToDisk->Pm1aCntSlpTyp.ByteValue = 2; // PIIX4: POSCL
361
362 //
363 // check for overrides
364 //
365 Status = QemuFwCfgFindFile ("etc/system-states", &FwCfgItem, &FwCfgSize);
366 if (Status != RETURN_SUCCESS || FwCfgSize != sizeof SystemStates) {
367 DEBUG ((DEBUG_INFO, "ACPI using S3/S4 defaults\n"));
368 return;
369 }
370 QemuFwCfgSelectItem (FwCfgItem);
371 QemuFwCfgReadBytes (sizeof SystemStates, SystemStates);
372
373 //
374 // Each byte corresponds to a system state. In each byte, the MSB tells us
375 // whether the given state is enabled. If so, the three LSBs specify the
376 // value to be written to the PM control register's SUS_TYP bits.
377 //
378 if (SystemStates[3] & BIT7) {
379 SuspendToRam->Pm1aCntSlpTyp.ByteValue =
380 SystemStates[3] & (BIT2 | BIT1 | BIT0);
381 DEBUG ((DEBUG_INFO, "ACPI S3 value: %d\n",
382 SuspendToRam->Pm1aCntSlpTyp.ByteValue));
383 } else {
384 *SuspendToRamSize = 0;
385 DEBUG ((DEBUG_INFO, "ACPI S3 disabled\n"));
386 }
387
388 if (SystemStates[4] & BIT7) {
389 SuspendToDisk->Pm1aCntSlpTyp.ByteValue =
390 SystemStates[4] & (BIT2 | BIT1 | BIT0);
391 DEBUG ((DEBUG_INFO, "ACPI S4 value: %d\n",
392 SuspendToDisk->Pm1aCntSlpTyp.ByteValue));
393 } else {
394 *SuspendToDiskSize = 0;
395 DEBUG ((DEBUG_INFO, "ACPI S4 disabled\n"));
396 }
397 }
398
399
400 STATIC
401 EFI_STATUS
402 EFIAPI
403 QemuInstallAcpiSsdtTable (
404 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
405 IN VOID *AcpiTableBuffer,
406 IN UINTN AcpiTableBufferSize,
407 OUT UINTN *TableKey
408 )
409 {
410 EFI_STATUS Status;
411 FIRMWARE_DATA *FwData;
412
413 Status = EFI_OUT_OF_RESOURCES;
414
415 FwData = AllocateReservedPool (sizeof (*FwData));
416 if (FwData != NULL) {
417 UINTN SuspendToRamSize;
418 SYSTEM_STATE_PACKAGE SuspendToRam;
419 UINTN SuspendToDiskSize;
420 SYSTEM_STATE_PACKAGE SuspendToDisk;
421 UINTN SsdtSize;
422 UINT8 *Ssdt;
423
424 GetSuspendStates (&SuspendToRamSize, &SuspendToRam,
425 &SuspendToDiskSize, &SuspendToDisk);
426 SsdtSize = AcpiTableBufferSize + 17 + SuspendToRamSize + SuspendToDiskSize;
427 Ssdt = AllocatePool (SsdtSize);
428
429 if (Ssdt != NULL) {
430 Status = PopulateFwData (FwData);
431
432 if (Status == EFI_SUCCESS) {
433 UINT8 *SsdtPtr;
434
435 SsdtPtr = Ssdt;
436
437 CopyMem (SsdtPtr, AcpiTableBuffer, AcpiTableBufferSize);
438 SsdtPtr += AcpiTableBufferSize;
439
440 //
441 // build "OperationRegion(FWDT, SystemMemory, 0x12345678, 0x87654321)"
442 //
443 *(SsdtPtr++) = 0x5B; // ExtOpPrefix
444 *(SsdtPtr++) = 0x80; // OpRegionOp
445 *(SsdtPtr++) = 'F';
446 *(SsdtPtr++) = 'W';
447 *(SsdtPtr++) = 'D';
448 *(SsdtPtr++) = 'T';
449 *(SsdtPtr++) = 0x00; // SystemMemory
450 *(SsdtPtr++) = 0x0C; // DWordPrefix
451
452 //
453 // no virtual addressing yet, take the four least significant bytes
454 //
455 CopyMem(SsdtPtr, &FwData, 4);
456 SsdtPtr += 4;
457
458 *(SsdtPtr++) = 0x0C; // DWordPrefix
459
460 *(UINT32*) SsdtPtr = sizeof (*FwData);
461 SsdtPtr += 4;
462
463 //
464 // add suspend system states
465 //
466 CopyMem (SsdtPtr, &SuspendToRam, SuspendToRamSize);
467 SsdtPtr += SuspendToRamSize;
468 CopyMem (SsdtPtr, &SuspendToDisk, SuspendToDiskSize);
469 SsdtPtr += SuspendToDiskSize;
470
471 ASSERT((UINTN) (SsdtPtr - Ssdt) == SsdtSize);
472 ((EFI_ACPI_DESCRIPTION_HEADER *) Ssdt)->Length = (UINT32) SsdtSize;
473 Status = InstallAcpiTable (AcpiProtocol, Ssdt, SsdtSize, TableKey);
474 }
475
476 FreePool(Ssdt);
477 }
478
479 if (Status != EFI_SUCCESS) {
480 FreePool(FwData);
481 }
482 }
483
484 return Status;
485 }
486
487
488 EFI_STATUS
489 EFIAPI
490 QemuInstallAcpiTable (
491 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
492 IN VOID *AcpiTableBuffer,
493 IN UINTN AcpiTableBufferSize,
494 OUT UINTN *TableKey
495 )
496 {
497 EFI_ACPI_DESCRIPTION_HEADER *Hdr;
498 EFI_ACPI_TABLE_INSTALL_ACPI_TABLE TableInstallFunction;
499
500 Hdr = (EFI_ACPI_DESCRIPTION_HEADER*) AcpiTableBuffer;
501 switch (Hdr->Signature) {
502 case EFI_ACPI_1_0_APIC_SIGNATURE:
503 TableInstallFunction = QemuInstallAcpiMadtTable;
504 break;
505 case EFI_ACPI_1_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
506 TableInstallFunction = QemuInstallAcpiSsdtTable;
507 break;
508 default:
509 TableInstallFunction = InstallAcpiTable;
510 }
511
512 return TableInstallFunction (
513 AcpiProtocol,
514 AcpiTableBuffer,
515 AcpiTableBufferSize,
516 TableKey
517 );
518 }
519
520
521 //
522 // The user structure for the ordered collection that will track the fw_cfg
523 // blobs under processing.
524 //
525 typedef struct {
526 UINT8 File[QEMU_LOADER_FNAME_SIZE]; // NUL-terminated name of the fw_cfg
527 // blob. This is the ordering / search
528 // key.
529 UINTN Size; // The number of bytes in this blob.
530 UINT8 *Base; // Pointer to the blob data.
531 BOOLEAN HostsOnlyTableData; // TRUE iff the blob has been found to
532 // only contain data that is directly
533 // part of ACPI tables.
534 } BLOB;
535
536
537 /**
538 Compare a standalone key against a user structure containing an embedded key.
539
540 @param[in] StandaloneKey Pointer to the bare key.
541
542 @param[in] UserStruct Pointer to the user structure with the embedded
543 key.
544
545 @retval <0 If StandaloneKey compares less than UserStruct's key.
546
547 @retval 0 If StandaloneKey compares equal to UserStruct's key.
548
549 @retval >0 If StandaloneKey compares greater than UserStruct's key.
550 **/
551 STATIC
552 INTN
553 EFIAPI
554 BlobKeyCompare (
555 IN CONST VOID *StandaloneKey,
556 IN CONST VOID *UserStruct
557 )
558 {
559 CONST BLOB *Blob;
560
561 Blob = UserStruct;
562 return AsciiStrCmp (StandaloneKey, (CONST CHAR8 *)Blob->File);
563 }
564
565
566 /**
567 Comparator function for two user structures.
568
569 @param[in] UserStruct1 Pointer to the first user structure.
570
571 @param[in] UserStruct2 Pointer to the second user structure.
572
573 @retval <0 If UserStruct1 compares less than UserStruct2.
574
575 @retval 0 If UserStruct1 compares equal to UserStruct2.
576
577 @retval >0 If UserStruct1 compares greater than UserStruct2.
578 **/
579 STATIC
580 INTN
581 EFIAPI
582 BlobCompare (
583 IN CONST VOID *UserStruct1,
584 IN CONST VOID *UserStruct2
585 )
586 {
587 CONST BLOB *Blob1;
588
589 Blob1 = UserStruct1;
590 return BlobKeyCompare (Blob1->File, UserStruct2);
591 }
592
593
594 /**
595 Process a QEMU_LOADER_ALLOCATE command.
596
597 @param[in] Allocate The QEMU_LOADER_ALLOCATE command to process.
598
599 @param[in,out] Tracker The ORDERED_COLLECTION tracking the BLOB user
600 structures created thus far.
601
602 @retval EFI_SUCCESS An area of whole AcpiNVS pages has been
603 allocated for the blob contents, and the
604 contents have been saved. A BLOB object (user
605 structure) has been allocated from pool memory,
606 referencing the blob contents. The BLOB user
607 structure has been linked into Tracker.
608
609 @retval EFI_PROTOCOL_ERROR Malformed fw_cfg file name has been found in
610 Allocate, or the Allocate command references a
611 file that is already known by Tracker.
612
613 @retval EFI_UNSUPPORTED Unsupported alignment request has been found in
614 Allocate.
615
616 @retval EFI_OUT_OF_RESOURCES Pool allocation failed.
617
618 @return Error codes from QemuFwCfgFindFile() and
619 gBS->AllocatePages().
620 **/
621 STATIC
622 EFI_STATUS
623 EFIAPI
624 ProcessCmdAllocate (
625 IN CONST QEMU_LOADER_ALLOCATE *Allocate,
626 IN OUT ORDERED_COLLECTION *Tracker
627 )
628 {
629 FIRMWARE_CONFIG_ITEM FwCfgItem;
630 UINTN FwCfgSize;
631 EFI_STATUS Status;
632 UINTN NumPages;
633 EFI_PHYSICAL_ADDRESS Address;
634 BLOB *Blob;
635
636 if (Allocate->File[QEMU_LOADER_FNAME_SIZE - 1] != '\0') {
637 DEBUG ((EFI_D_ERROR, "%a: malformed file name\n", __FUNCTION__));
638 return EFI_PROTOCOL_ERROR;
639 }
640
641 if (Allocate->Alignment > EFI_PAGE_SIZE) {
642 DEBUG ((EFI_D_ERROR, "%a: unsupported alignment 0x%x\n", __FUNCTION__,
643 Allocate->Alignment));
644 return EFI_UNSUPPORTED;
645 }
646
647 Status = QemuFwCfgFindFile ((CHAR8 *)Allocate->File, &FwCfgItem, &FwCfgSize);
648 if (EFI_ERROR (Status)) {
649 DEBUG ((EFI_D_ERROR, "%a: QemuFwCfgFindFile(\"%a\"): %r\n", __FUNCTION__,
650 Allocate->File, Status));
651 return Status;
652 }
653
654 NumPages = EFI_SIZE_TO_PAGES (FwCfgSize);
655 Address = 0xFFFFFFFF;
656 Status = gBS->AllocatePages (AllocateMaxAddress, EfiACPIMemoryNVS, NumPages,
657 &Address);
658 if (EFI_ERROR (Status)) {
659 return Status;
660 }
661
662 Blob = AllocatePool (sizeof *Blob);
663 if (Blob == NULL) {
664 Status = EFI_OUT_OF_RESOURCES;
665 goto FreePages;
666 }
667 CopyMem (Blob->File, Allocate->File, QEMU_LOADER_FNAME_SIZE);
668 Blob->Size = FwCfgSize;
669 Blob->Base = (VOID *)(UINTN)Address;
670 Blob->HostsOnlyTableData = TRUE;
671
672 Status = OrderedCollectionInsert (Tracker, NULL, Blob);
673 if (Status == RETURN_ALREADY_STARTED) {
674 DEBUG ((EFI_D_ERROR, "%a: duplicated file \"%a\"\n", __FUNCTION__,
675 Allocate->File));
676 Status = EFI_PROTOCOL_ERROR;
677 }
678 if (EFI_ERROR (Status)) {
679 goto FreeBlob;
680 }
681
682 QemuFwCfgSelectItem (FwCfgItem);
683 QemuFwCfgReadBytes (FwCfgSize, Blob->Base);
684 ZeroMem (Blob->Base + Blob->Size, EFI_PAGES_TO_SIZE (NumPages) - Blob->Size);
685
686 DEBUG ((EFI_D_VERBOSE, "%a: File=\"%a\" Alignment=0x%x Zone=%d Size=0x%Lx "
687 "Address=0x%Lx\n", __FUNCTION__, Allocate->File, Allocate->Alignment,
688 Allocate->Zone, (UINT64)Blob->Size, (UINT64)(UINTN)Blob->Base));
689 return EFI_SUCCESS;
690
691 FreeBlob:
692 FreePool (Blob);
693
694 FreePages:
695 gBS->FreePages (Address, NumPages);
696
697 return Status;
698 }
699
700
701 /**
702 Process a QEMU_LOADER_ADD_POINTER command.
703
704 @param[in] AddPointer The QEMU_LOADER_ADD_POINTER command to process.
705
706 @param[in] Tracker The ORDERED_COLLECTION tracking the BLOB user
707 structures created thus far.
708
709 @retval EFI_PROTOCOL_ERROR Malformed fw_cfg file name(s) have been found in
710 AddPointer, or the AddPointer command references
711 a file unknown to Tracker, or the pointer to
712 relocate has invalid location, size, or value, or
713 the relocated pointer value is not representable
714 in the given pointer size.
715
716 @retval EFI_SUCCESS The pointer field inside the pointer blob has
717 been relocated.
718 **/
719 STATIC
720 EFI_STATUS
721 EFIAPI
722 ProcessCmdAddPointer (
723 IN CONST QEMU_LOADER_ADD_POINTER *AddPointer,
724 IN CONST ORDERED_COLLECTION *Tracker
725 )
726 {
727 ORDERED_COLLECTION_ENTRY *TrackerEntry, *TrackerEntry2;
728 BLOB *Blob, *Blob2;
729 UINT8 *PointerField;
730 UINT64 PointerValue;
731
732 if (AddPointer->PointerFile[QEMU_LOADER_FNAME_SIZE - 1] != '\0' ||
733 AddPointer->PointeeFile[QEMU_LOADER_FNAME_SIZE - 1] != '\0') {
734 DEBUG ((EFI_D_ERROR, "%a: malformed file name\n", __FUNCTION__));
735 return EFI_PROTOCOL_ERROR;
736 }
737
738 TrackerEntry = OrderedCollectionFind (Tracker, AddPointer->PointerFile);
739 TrackerEntry2 = OrderedCollectionFind (Tracker, AddPointer->PointeeFile);
740 if (TrackerEntry == NULL || TrackerEntry2 == NULL) {
741 DEBUG ((EFI_D_ERROR, "%a: invalid blob reference(s) \"%a\" / \"%a\"\n",
742 __FUNCTION__, AddPointer->PointerFile, AddPointer->PointeeFile));
743 return EFI_PROTOCOL_ERROR;
744 }
745
746 Blob = OrderedCollectionUserStruct (TrackerEntry);
747 Blob2 = OrderedCollectionUserStruct (TrackerEntry2);
748 if ((AddPointer->PointerSize != 1 && AddPointer->PointerSize != 2 &&
749 AddPointer->PointerSize != 4 && AddPointer->PointerSize != 8) ||
750 Blob->Size < AddPointer->PointerSize ||
751 Blob->Size - AddPointer->PointerSize < AddPointer->PointerOffset) {
752 DEBUG ((EFI_D_ERROR, "%a: invalid pointer location or size in \"%a\"\n",
753 __FUNCTION__, AddPointer->PointerFile));
754 return EFI_PROTOCOL_ERROR;
755 }
756
757 PointerField = Blob->Base + AddPointer->PointerOffset;
758 PointerValue = 0;
759 CopyMem (&PointerValue, PointerField, AddPointer->PointerSize);
760 if (PointerValue >= Blob2->Size) {
761 DEBUG ((EFI_D_ERROR, "%a: invalid pointer value in \"%a\"\n", __FUNCTION__,
762 AddPointer->PointerFile));
763 return EFI_PROTOCOL_ERROR;
764 }
765
766 //
767 // The memory allocation system ensures that the address of the byte past the
768 // last byte of any allocated object is expressible (no wraparound).
769 //
770 ASSERT ((UINTN)Blob2->Base <= MAX_ADDRESS - Blob2->Size);
771
772 PointerValue += (UINT64)(UINTN)Blob2->Base;
773 if (RShiftU64 (
774 RShiftU64 (PointerValue, AddPointer->PointerSize * 8 - 1), 1) != 0) {
775 DEBUG ((EFI_D_ERROR, "%a: relocated pointer value unrepresentable in "
776 "\"%a\"\n", __FUNCTION__, AddPointer->PointerFile));
777 return EFI_PROTOCOL_ERROR;
778 }
779
780 CopyMem (PointerField, &PointerValue, AddPointer->PointerSize);
781
782 DEBUG ((EFI_D_VERBOSE, "%a: PointerFile=\"%a\" PointeeFile=\"%a\" "
783 "PointerOffset=0x%x PointerSize=%d\n", __FUNCTION__,
784 AddPointer->PointerFile, AddPointer->PointeeFile,
785 AddPointer->PointerOffset, AddPointer->PointerSize));
786 return EFI_SUCCESS;
787 }
788
789
790 /**
791 Process a QEMU_LOADER_ADD_CHECKSUM command.
792
793 @param[in] AddChecksum The QEMU_LOADER_ADD_CHECKSUM command to process.
794
795 @param[in] Tracker The ORDERED_COLLECTION tracking the BLOB user
796 structures created thus far.
797
798 @retval EFI_PROTOCOL_ERROR Malformed fw_cfg file name has been found in
799 AddChecksum, or the AddChecksum command
800 references a file unknown to Tracker, or the
801 range to checksum is invalid.
802
803 @retval EFI_SUCCESS The requested range has been checksummed.
804 **/
805 STATIC
806 EFI_STATUS
807 EFIAPI
808 ProcessCmdAddChecksum (
809 IN CONST QEMU_LOADER_ADD_CHECKSUM *AddChecksum,
810 IN CONST ORDERED_COLLECTION *Tracker
811 )
812 {
813 ORDERED_COLLECTION_ENTRY *TrackerEntry;
814 BLOB *Blob;
815
816 if (AddChecksum->File[QEMU_LOADER_FNAME_SIZE - 1] != '\0') {
817 DEBUG ((EFI_D_ERROR, "%a: malformed file name\n", __FUNCTION__));
818 return EFI_PROTOCOL_ERROR;
819 }
820
821 TrackerEntry = OrderedCollectionFind (Tracker, AddChecksum->File);
822 if (TrackerEntry == NULL) {
823 DEBUG ((EFI_D_ERROR, "%a: invalid blob reference \"%a\"\n", __FUNCTION__,
824 AddChecksum->File));
825 return EFI_PROTOCOL_ERROR;
826 }
827
828 Blob = OrderedCollectionUserStruct (TrackerEntry);
829 if (Blob->Size <= AddChecksum->ResultOffset ||
830 Blob->Size < AddChecksum->Length ||
831 Blob->Size - AddChecksum->Length < AddChecksum->Start) {
832 DEBUG ((EFI_D_ERROR, "%a: invalid checksum range in \"%a\"\n",
833 __FUNCTION__, AddChecksum->File));
834 return EFI_PROTOCOL_ERROR;
835 }
836
837 Blob->Base[AddChecksum->ResultOffset] = CalculateCheckSum8 (
838 Blob->Base + AddChecksum->Start,
839 AddChecksum->Length
840 );
841 DEBUG ((EFI_D_VERBOSE, "%a: File=\"%a\" ResultOffset=0x%x Start=0x%x "
842 "Length=0x%x\n", __FUNCTION__, AddChecksum->File,
843 AddChecksum->ResultOffset, AddChecksum->Start, AddChecksum->Length));
844 return EFI_SUCCESS;
845 }
846
847
848 //
849 // We'll be saving the keys of installed tables so that we can roll them back
850 // in case of failure. 128 tables should be enough for anyone (TM).
851 //
852 #define INSTALLED_TABLES_MAX 128
853
854 /**
855 Process a QEMU_LOADER_ADD_POINTER command in order to see if its target byte
856 array is an ACPI table, and if so, install it.
857
858 This function assumes that the entire QEMU linker/loader command file has
859 been processed successfuly in a prior first pass.
860
861 @param[in] AddPointer The QEMU_LOADER_ADD_POINTER command to process.
862
863 @param[in] Tracker The ORDERED_COLLECTION tracking the BLOB user
864 structures.
865
866 @param[in] AcpiProtocol The ACPI table protocol used to install tables.
867
868 @param[in,out] InstalledKey On input, an array of INSTALLED_TABLES_MAX UINTN
869 elements, allocated by the caller. On output,
870 the function will have stored (appended) the
871 AcpiProtocol-internal key of the ACPI table that
872 the function has installed, if the AddPointer
873 command identified an ACPI table that is
874 different from RSDT and XSDT.
875
876 @param[in,out] NumInstalled On input, the number of entries already used in
877 InstalledKey; it must be in [0,
878 INSTALLED_TABLES_MAX] inclusive. On output, the
879 parameter is incremented if the AddPointer
880 command identified an ACPI table that is
881 different from RSDT and XSDT.
882
883 @retval EFI_INVALID_PARAMETER NumInstalled was outside the allowed range on
884 input.
885
886 @retval EFI_OUT_OF_RESOURCES The AddPointer command identified an ACPI
887 table different from RSDT and XSDT, but there
888 was no more room in InstalledKey.
889
890 @retval EFI_SUCCESS AddPointer has been processed. Either an ACPI
891 table different from RSDT and XSDT has been
892 installed (reflected by InstalledKey and
893 NumInstalled), or RSDT or XSDT has been
894 identified but not installed, or the fw_cfg
895 blob pointed-into by AddPointer has been
896 marked as hosting something else than just
897 direct ACPI table contents.
898
899 @return Error codes returned by
900 AcpiProtocol->InstallAcpiTable().
901 **/
902 STATIC
903 EFI_STATUS
904 EFIAPI
905 Process2ndPassCmdAddPointer (
906 IN CONST QEMU_LOADER_ADD_POINTER *AddPointer,
907 IN CONST ORDERED_COLLECTION *Tracker,
908 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
909 IN OUT UINTN InstalledKey[INSTALLED_TABLES_MAX],
910 IN OUT INT32 *NumInstalled
911 )
912 {
913 CONST ORDERED_COLLECTION_ENTRY *TrackerEntry;
914 CONST ORDERED_COLLECTION_ENTRY *TrackerEntry2;
915 CONST BLOB *Blob;
916 BLOB *Blob2;
917 CONST UINT8 *PointerField;
918 UINT64 PointerValue;
919 UINTN Blob2Remaining;
920 UINTN TableSize;
921 CONST EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
922 CONST EFI_ACPI_DESCRIPTION_HEADER *Header;
923 EFI_STATUS Status;
924
925 if (*NumInstalled < 0 || *NumInstalled > INSTALLED_TABLES_MAX) {
926 return EFI_INVALID_PARAMETER;
927 }
928
929 TrackerEntry = OrderedCollectionFind (Tracker, AddPointer->PointerFile);
930 TrackerEntry2 = OrderedCollectionFind (Tracker, AddPointer->PointeeFile);
931 Blob = OrderedCollectionUserStruct (TrackerEntry);
932 Blob2 = OrderedCollectionUserStruct (TrackerEntry2);
933 PointerField = Blob->Base + AddPointer->PointerOffset;
934 PointerValue = 0;
935 CopyMem (&PointerValue, PointerField, AddPointer->PointerSize);
936
937 //
938 // We assert that PointerValue falls inside Blob2's contents. This is ensured
939 // by the Blob2->Size check and later checks in ProcessCmdAddPointer().
940 //
941 Blob2Remaining = (UINTN)Blob2->Base;
942 ASSERT(PointerValue >= Blob2Remaining);
943 Blob2Remaining += Blob2->Size;
944 ASSERT (PointerValue < Blob2Remaining);
945
946 Blob2Remaining -= (UINTN) PointerValue;
947 DEBUG ((EFI_D_VERBOSE, "%a: checking for ACPI header in \"%a\" at 0x%Lx "
948 "(remaining: 0x%Lx): ", __FUNCTION__, AddPointer->PointeeFile,
949 PointerValue, (UINT64)Blob2Remaining));
950
951 TableSize = 0;
952
953 //
954 // To make our job simple, the FACS has a custom header. Sigh.
955 //
956 if (sizeof *Facs <= Blob2Remaining) {
957 Facs = (EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)PointerValue;
958
959 if (Facs->Length >= sizeof *Facs &&
960 Facs->Length <= Blob2Remaining &&
961 Facs->Signature ==
962 EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) {
963 DEBUG ((EFI_D_VERBOSE, "found \"%-4.4a\" size 0x%x\n",
964 (CONST CHAR8 *)&Facs->Signature, Facs->Length));
965 TableSize = Facs->Length;
966 }
967 }
968
969 //
970 // check for the uniform tables
971 //
972 if (TableSize == 0 && sizeof *Header <= Blob2Remaining) {
973 Header = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)PointerValue;
974
975 if (Header->Length >= sizeof *Header &&
976 Header->Length <= Blob2Remaining &&
977 CalculateSum8 ((CONST UINT8 *)Header, Header->Length) == 0) {
978 //
979 // This looks very much like an ACPI table from QEMU:
980 // - Length field consistent with both ACPI and containing blob size
981 // - checksum is correct
982 //
983 DEBUG ((EFI_D_VERBOSE, "found \"%-4.4a\" size 0x%x\n",
984 (CONST CHAR8 *)&Header->Signature, Header->Length));
985 TableSize = Header->Length;
986
987 //
988 // Skip RSDT and XSDT because those are handled by
989 // EFI_ACPI_TABLE_PROTOCOL automatically.
990 if (Header->Signature ==
991 EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE ||
992 Header->Signature ==
993 EFI_ACPI_2_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
994 return EFI_SUCCESS;
995 }
996 }
997 }
998
999 if (TableSize == 0) {
1000 DEBUG ((EFI_D_VERBOSE, "not found; marking fw_cfg blob as opaque\n"));
1001 Blob2->HostsOnlyTableData = FALSE;
1002 return EFI_SUCCESS;
1003 }
1004
1005 if (*NumInstalled == INSTALLED_TABLES_MAX) {
1006 DEBUG ((EFI_D_ERROR, "%a: can't install more than %d tables\n",
1007 __FUNCTION__, INSTALLED_TABLES_MAX));
1008 return EFI_OUT_OF_RESOURCES;
1009 }
1010
1011 Status = AcpiProtocol->InstallAcpiTable (AcpiProtocol,
1012 (VOID *)(UINTN)PointerValue, TableSize,
1013 &InstalledKey[*NumInstalled]);
1014 if (EFI_ERROR (Status)) {
1015 DEBUG ((EFI_D_ERROR, "%a: InstallAcpiTable(): %r\n", __FUNCTION__,
1016 Status));
1017 return Status;
1018 }
1019 ++*NumInstalled;
1020 return EFI_SUCCESS;
1021 }
1022
1023
1024 /**
1025 Download, process, and install ACPI table data from the QEMU loader
1026 interface.
1027
1028 @param[in] AcpiProtocol The ACPI table protocol used to install tables.
1029
1030 @retval EFI_UNSUPPORTED Firmware configuration is unavailable, or QEMU
1031 loader command with unsupported parameters
1032 has been found.
1033
1034 @retval EFI_NOT_FOUND The host doesn't export the required fw_cfg
1035 files.
1036
1037 @retval EFI_OUT_OF_RESOURCES Memory allocation failed, or more than
1038 INSTALLED_TABLES_MAX tables found.
1039
1040 @retval EFI_PROTOCOL_ERROR Found invalid fw_cfg contents.
1041
1042 @return Status codes returned by
1043 AcpiProtocol->InstallAcpiTable().
1044
1045 **/
1046 EFI_STATUS
1047 EFIAPI
1048 InstallAllQemuLinkedTables (
1049 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol
1050 )
1051 {
1052 EFI_STATUS Status;
1053 FIRMWARE_CONFIG_ITEM FwCfgItem;
1054 UINTN FwCfgSize;
1055 QEMU_LOADER_ENTRY *LoaderStart;
1056 CONST QEMU_LOADER_ENTRY *LoaderEntry, *LoaderEnd;
1057 ORDERED_COLLECTION *Tracker;
1058 UINTN *InstalledKey;
1059 INT32 Installed;
1060 ORDERED_COLLECTION_ENTRY *TrackerEntry, *TrackerEntry2;
1061
1062 Status = QemuFwCfgFindFile ("etc/table-loader", &FwCfgItem, &FwCfgSize);
1063 if (EFI_ERROR (Status)) {
1064 return Status;
1065 }
1066 if (FwCfgSize % sizeof *LoaderEntry != 0) {
1067 DEBUG ((EFI_D_ERROR, "%a: \"etc/table-loader\" has invalid size 0x%Lx\n",
1068 __FUNCTION__, (UINT64)FwCfgSize));
1069 return EFI_PROTOCOL_ERROR;
1070 }
1071
1072 LoaderStart = AllocatePool (FwCfgSize);
1073 if (LoaderStart == NULL) {
1074 return EFI_OUT_OF_RESOURCES;
1075 }
1076 QemuFwCfgSelectItem (FwCfgItem);
1077 QemuFwCfgReadBytes (FwCfgSize, LoaderStart);
1078 LoaderEnd = LoaderStart + FwCfgSize / sizeof *LoaderEntry;
1079
1080 Tracker = OrderedCollectionInit (BlobCompare, BlobKeyCompare);
1081 if (Tracker == NULL) {
1082 Status = EFI_OUT_OF_RESOURCES;
1083 goto FreeLoader;
1084 }
1085
1086 //
1087 // first pass: process the commands
1088 //
1089 for (LoaderEntry = LoaderStart; LoaderEntry < LoaderEnd; ++LoaderEntry) {
1090 switch (LoaderEntry->Type) {
1091 case QemuLoaderCmdAllocate:
1092 Status = ProcessCmdAllocate (&LoaderEntry->Command.Allocate, Tracker);
1093 break;
1094
1095 case QemuLoaderCmdAddPointer:
1096 Status = ProcessCmdAddPointer (&LoaderEntry->Command.AddPointer,
1097 Tracker);
1098 break;
1099
1100 case QemuLoaderCmdAddChecksum:
1101 Status = ProcessCmdAddChecksum (&LoaderEntry->Command.AddChecksum,
1102 Tracker);
1103 break;
1104
1105 default:
1106 DEBUG ((EFI_D_VERBOSE, "%a: unknown loader command: 0x%x\n",
1107 __FUNCTION__, LoaderEntry->Type));
1108 break;
1109 }
1110
1111 if (EFI_ERROR (Status)) {
1112 goto FreeTracker;
1113 }
1114 }
1115
1116 InstalledKey = AllocatePool (INSTALLED_TABLES_MAX * sizeof *InstalledKey);
1117 if (InstalledKey == NULL) {
1118 Status = EFI_OUT_OF_RESOURCES;
1119 goto FreeTracker;
1120 }
1121
1122 //
1123 // second pass: identify and install ACPI tables
1124 //
1125 Installed = 0;
1126 for (LoaderEntry = LoaderStart; LoaderEntry < LoaderEnd; ++LoaderEntry) {
1127 if (LoaderEntry->Type == QemuLoaderCmdAddPointer) {
1128 Status = Process2ndPassCmdAddPointer (&LoaderEntry->Command.AddPointer,
1129 Tracker, AcpiProtocol, InstalledKey, &Installed);
1130 if (EFI_ERROR (Status)) {
1131 break;
1132 }
1133 }
1134 }
1135
1136 if (EFI_ERROR (Status)) {
1137 //
1138 // roll back partial installation
1139 //
1140 while (Installed > 0) {
1141 --Installed;
1142 AcpiProtocol->UninstallAcpiTable (AcpiProtocol, InstalledKey[Installed]);
1143 }
1144 } else {
1145 DEBUG ((EFI_D_INFO, "%a: installed %d tables\n", __FUNCTION__, Installed));
1146 }
1147
1148 FreePool (InstalledKey);
1149
1150 FreeTracker:
1151 //
1152 // Tear down the tracker infrastructure. Each fw_cfg blob will be left in
1153 // place only if we're exiting with success and the blob hosts data that is
1154 // not directly part of some ACPI table.
1155 //
1156 for (TrackerEntry = OrderedCollectionMin (Tracker); TrackerEntry != NULL;
1157 TrackerEntry = TrackerEntry2) {
1158 VOID *UserStruct;
1159 BLOB *Blob;
1160
1161 TrackerEntry2 = OrderedCollectionNext (TrackerEntry);
1162 OrderedCollectionDelete (Tracker, TrackerEntry, &UserStruct);
1163 Blob = UserStruct;
1164
1165 if (EFI_ERROR (Status) || Blob->HostsOnlyTableData) {
1166 DEBUG ((EFI_D_VERBOSE, "%a: freeing \"%a\"\n", __FUNCTION__,
1167 Blob->File));
1168 gBS->FreePages ((UINTN)Blob->Base, EFI_SIZE_TO_PAGES (Blob->Size));
1169 }
1170 FreePool (Blob);
1171 }
1172 OrderedCollectionUninit (Tracker);
1173
1174 FreeLoader:
1175 FreePool (LoaderStart);
1176
1177 return Status;
1178 }