VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.c@ 99396

Last change on this file since 99396 was 90907, checked in by vboxsync, 3 years ago

EFI/Firmware: Don't just install a static selection of ACPI tables but use the XSDT to install all pre existing ones (like for the upcoming TPM and IOMMU support or custom tables added by the user), bugref:4643 bugref:10075 bugref:9967 bugref:9654

  • Property svn:eol-style set to native
File size: 12.0 KB
Line 
1/** @file
2 Sample ACPI Platform Driver
3
4 Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7**/
8
9#include <PiDxe.h>
10
11#include <Protocol/AcpiTable.h>
12#include <Protocol/FirmwareVolume2.h>
13
14#include <Library/BaseLib.h>
15#include <Library/UefiBootServicesTableLib.h>
16#include <Library/DebugLib.h>
17#include <Library/PcdLib.h>
18
19#include <IndustryStandard/Acpi.h>
20
21/**
22 Locate the first instance of a protocol. If the protocol requested is an
23 FV protocol, then it will return the first FV that contains the ACPI table
24 storage file.
25
26 @param Instance Return pointer to the first instance of the protocol
27
28 @return EFI_SUCCESS The function completed successfully.
29 @return EFI_NOT_FOUND The protocol could not be located.
30 @return EFI_OUT_OF_RESOURCES There are not enough resources to find the protocol.
31
32**/
33EFI_STATUS
34LocateFvInstanceWithTables (
35 OUT EFI_FIRMWARE_VOLUME2_PROTOCOL **Instance
36 )
37{
38 EFI_STATUS Status;
39 EFI_HANDLE *HandleBuffer;
40 UINTN NumberOfHandles;
41 EFI_FV_FILETYPE FileType;
42 UINT32 FvStatus;
43 EFI_FV_FILE_ATTRIBUTES Attributes;
44 UINTN Size;
45 UINTN Index;
46 EFI_FIRMWARE_VOLUME2_PROTOCOL *FvInstance;
47
48 FvStatus = 0;
49
50 //
51 // Locate protocol.
52 //
53 Status = gBS->LocateHandleBuffer (
54 ByProtocol,
55 &gEfiFirmwareVolume2ProtocolGuid,
56 NULL,
57 &NumberOfHandles,
58 &HandleBuffer
59 );
60 if (EFI_ERROR (Status)) {
61 //
62 // Defined errors at this time are not found and out of resources.
63 //
64 return Status;
65 }
66
67
68
69 //
70 // Looking for FV with ACPI storage file
71 //
72
73 for (Index = 0; Index < NumberOfHandles; Index++) {
74 //
75 // Get the protocol on this handle
76 // This should not fail because of LocateHandleBuffer
77 //
78 Status = gBS->HandleProtocol (
79 HandleBuffer[Index],
80 &gEfiFirmwareVolume2ProtocolGuid,
81 (VOID**) &FvInstance
82 );
83 ASSERT_EFI_ERROR (Status);
84
85 //
86 // See if it has the ACPI storage file
87 //
88 Status = FvInstance->ReadFile (
89 FvInstance,
90 (EFI_GUID*)PcdGetPtr (PcdAcpiTableStorageFile),
91 NULL,
92 &Size,
93 &FileType,
94 &Attributes,
95 &FvStatus
96 );
97
98 //
99 // If we found it, then we are done
100 //
101 if (Status == EFI_SUCCESS) {
102 *Instance = FvInstance;
103 break;
104 }
105 }
106
107 //
108 // Our exit status is determined by the success of the previous operations
109 // If the protocol was found, Instance already points to it.
110 //
111
112 //
113 // Free any allocated buffers
114 //
115 gBS->FreePool (HandleBuffer);
116
117 return Status;
118}
119
120
121/**
122 This function calculates and updates an UINT8 checksum.
123
124 @param Buffer Pointer to buffer to checksum
125 @param Size Number of bytes to checksum
126
127**/
128VOID
129AcpiPlatformChecksum (
130 IN UINT8 *Buffer,
131 IN UINTN Size
132 )
133{
134 UINTN ChecksumOffset;
135
136 ChecksumOffset = OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum);
137
138 //
139 // Set checksum to 0 first
140 //
141 Buffer[ChecksumOffset] = 0;
142
143 //
144 // Update checksum value
145 //
146 Buffer[ChecksumOffset] = CalculateCheckSum8(Buffer, Size);
147}
148
149
150#ifdef VBOX
151
152/* Disables the old code only copying a selection of tables, missing out a bunch of things available in the XSDT/RSDT. */
153# define ACPI_NO_STATIC_TABLES_SELECTION 1
154
155# define ACPI_RSD_PTR SIGNATURE_64('R', 'S', 'D', ' ', 'P', 'T', 'R', ' ')
156# define EBDA_BASE (0x9FC0 << 4)
157
158VOID *
159FindAcpiRsdPtr(VOID)
160{
161 UINTN Address;
162 UINTN Index;
163
164 //
165 // First Search 0x0e0000 - 0x0fffff for RSD Ptr
166 //
167 for (Address = 0xe0000; Address < 0xfffff; Address += 0x10) {
168 if (*(UINT64 *)(Address) == ACPI_RSD_PTR) {
169 return (VOID *)Address;
170 }
171 }
172
173 //
174 // Search EBDA
175 //
176 Address = EBDA_BASE;
177 for (Index = 0; Index < 0x400 ; Index += 16) {
178 if (*(UINT64 *)(Address + Index) == ACPI_RSD_PTR) {
179 return (VOID *)Address;
180 }
181 }
182 return NULL;
183}
184
185#ifndef ACPI_NO_STATIC_TABLES_SELECTION
186VOID *FindSignature(VOID* Start, UINT32 Signature, BOOLEAN NoChecksum)
187{
188 UINT8 *Ptr = (UINT8*)Start;
189 UINT32 Count = 0x10000; // 16 pages
190
191 while (Count-- > 0) {
192 if ( *(UINT32*)Ptr == Signature
193 && ((EFI_ACPI_DESCRIPTION_HEADER *)Ptr)->Length <= Count
194 && (NoChecksum ||
195 CalculateCheckSum8(Ptr, ((EFI_ACPI_DESCRIPTION_HEADER *)Ptr)->Length) == 0
196 )) {
197 return Ptr;
198 }
199
200 Ptr++;
201 }
202 return NULL;
203}
204#endif
205
206VOID
207FillSysTablesInfo(VOID **Tables, UINT32 TablesSize)
208{
209 UINT32 Table = 0;
210 EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *RsdPtr;
211#ifndef ACPI_NO_STATIC_TABLES_SELECTION
212 VOID *TablesPage;
213#else
214 EFI_ACPI_DESCRIPTION_HEADER *RsdtTbl;
215#endif
216 UINT64 *PtrTbl;
217 UINT32 Index;
218
219 RsdPtr = (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER*)FindAcpiRsdPtr();
220 ASSERT(RsdPtr != NULL);
221
222#ifndef ACPI_NO_STATIC_TABLES_SELECTION
223#define FLAG_OPTIONAL 1<<0
224#define FLAG_NO_CHECKSUM 1<<1
225 static struct {
226 UINT32 Signature;
227 UINT32 Flags;
228 CHAR8* Name;
229 } TableInfo[] = {
230 // MADT, optional
231 { SIGNATURE_32('A', 'P', 'I', 'C'), FLAG_OPTIONAL, "MADT"},
232 // FACP (also called FADT)
233 { SIGNATURE_32('F', 'A', 'C', 'P'), 0, "FADT"},
234 // FACS, according 5.2.9 of ACPI v2. spec FACS doesn't have checksum field
235 { SIGNATURE_32('F', 'A', 'C', 'S'), FLAG_NO_CHECKSUM, "FACS"},
236 // DSDT
237 { SIGNATURE_32('D', 'S', 'D', 'T'), 0, "DSDT"},
238 // SSDT
239 { SIGNATURE_32('S', 'S', 'D', 'T'), FLAG_OPTIONAL, "SSDT"},
240 // HPET
241 { SIGNATURE_32('H', 'P', 'E', 'T'), FLAG_OPTIONAL, "HPET"},
242 // MCFG
243 { SIGNATURE_32('M', 'C', 'F', 'G'), FLAG_OPTIONAL, "MCFG"}
244 };
245
246 TablesPage = (VOID *)(UINTN)((RsdPtr->RsdtAddress) & ~0xfff);
247 DEBUG((DEBUG_INFO, "TablesPage:%p\n", TablesPage));
248
249 for (Index = 0; Index < sizeof TableInfo / sizeof TableInfo[0]; Index++)
250 {
251 VOID *Ptr = FindSignature(TablesPage, TableInfo[Index].Signature,
252 (BOOLEAN)((TableInfo[Index].Flags & FLAG_NO_CHECKSUM) != 0));
253 if (TableInfo[Index].Signature == SIGNATURE_32('F', 'A', 'C', 'P'))
254 {
255 // we actually have 2 FADTs, see https://xtracker.innotek.de/index.php?bug=4082
256 Ptr = FindSignature((UINT8*)Ptr+32, SIGNATURE_32('F', 'A', 'C', 'P'), FALSE);
257 }
258 if (!(TableInfo[Index].Flags & FLAG_OPTIONAL))
259 {
260 if (!Ptr)
261 DEBUG((EFI_D_ERROR, "%a: isn't optional %p\n", TableInfo[Index].Name, Ptr));
262 ASSERT(Ptr != NULL);
263 }
264 DEBUG((EFI_D_ERROR, "%a: %p\n", TableInfo[Index].Name, Ptr));
265 if (Ptr)
266 Tables[Table++] = Ptr;
267 }
268#else
269 RsdtTbl = (EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)RsdPtr->XsdtAddress;
270 DEBUG((DEBUG_INFO, "RsdtTbl:%p\n", RsdtTbl));
271
272 PtrTbl = (UINT64 *)(RsdtTbl + 1);
273 for (Index = 0; Index < (RsdtTbl->Length - sizeof(*RsdtTbl)) / sizeof(UINT64); Index++)
274 {
275 EFI_ACPI_DESCRIPTION_HEADER *Header = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)*PtrTbl++;
276 DEBUG ((DEBUG_VERBOSE, "Table %p found \"%-4.4a\" size 0x%x\n", Header, (CONST CHAR8 *)&Header->Signature, Header->Length));
277
278 if (Header->Signature == SIGNATURE_32('F', 'A', 'C', 'P'))
279 {
280 /* Add the DSDT pointer from there. */
281 EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *)Header;
282 DEBUG((DEBUG_INFO, "Found FACP: DSDT 0x%x FACS 0x%x XDsdt %p XFacs %p\n", Fadt->Dsdt, Fadt->FirmwareCtrl, Fadt->XDsdt, Fadt->XFirmwareCtrl));
283 Tables[Table++] = (VOID *)(UINTN)Fadt->FirmwareCtrl;
284 Tables[Table++] = (VOID *)(UINTN)Fadt->Dsdt;
285 }
286
287 Tables[Table++] = Header;
288 }
289#endif
290
291#if 0
292 // RSDT
293 ASSERT(Table < TablesSize);
294 Tables[Table] = FindSignature(TablesPage, SIGNATURE_32('R', 'S', 'D', 'T'));
295 DEBUG ((EFI_D_ERROR, "RSDT: %p\n", Tables[Table]));
296 ASSERT(Tables[Table] != NULL);
297 Table++;
298
299 // XSDT
300 ASSERT(Table < TablesSize);
301 Tables[Table] = FindSignature(TablesPage, SIGNATURE_32('X', 'S', 'D', 'T'));
302 DEBUG ((EFI_D_ERROR, "XSDT: %p\n", Tables[Table]));
303 ASSERT(Tables[Table] != NULL);
304 Table++;
305#endif
306
307 DEBUG((DEBUG_INFO, "We found %d tables (max allowed %d)\n", Table, TablesSize));
308 Tables[Table] = NULL;
309}
310
311#endif /* VBOX */
312
313
314/**
315 Entrypoint of Acpi Platform driver.
316
317 @param ImageHandle
318 @param SystemTable
319
320 @return EFI_SUCCESS
321 @return EFI_LOAD_ERROR
322 @return EFI_OUT_OF_RESOURCES
323
324**/
325EFI_STATUS
326EFIAPI
327AcpiPlatformEntryPoint (
328 IN EFI_HANDLE ImageHandle,
329 IN EFI_SYSTEM_TABLE *SystemTable
330 )
331{
332 EFI_STATUS Status;
333 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
334#ifdef VBOX
335# ifndef ACPI_NO_STATIC_TABLES_SELECTION
336 VOID *VBoxTables[10];
337# else
338 VOID *VBoxTables[128];
339# endif
340#else
341 EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
342#endif
343 INTN Instance;
344 EFI_ACPI_COMMON_HEADER *CurrentTable;
345 UINTN TableHandle;
346#ifndef VBOX
347 UINT32 FvStatus;
348#endif
349 UINTN TableSize;
350 UINTN Size;
351
352 Instance = 0;
353 CurrentTable = NULL;
354 TableHandle = 0;
355
356 //
357 // Find the AcpiTable protocol
358 //
359 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID**)&AcpiTable);
360 if (EFI_ERROR (Status)) {
361 return EFI_ABORTED;
362 }
363
364#ifdef VBOX
365 //
366 // VBOX already has tables prepared in memory - just reuse them.
367 //
368 FillSysTablesInfo(VBoxTables, sizeof(VBoxTables)/sizeof(VBoxTables[0]));
369#else
370 //
371 //
372 // Locate the firmware volume protocol
373 //
374 Status = LocateFvInstanceWithTables (&FwVol);
375 if (EFI_ERROR (Status)) {
376 return EFI_ABORTED;
377 }
378#endif
379 //
380 // Read tables from the storage file.
381 //
382 while (Status == EFI_SUCCESS) {
383
384#ifdef VBOX
385 CurrentTable = (EFI_ACPI_COMMON_HEADER *)VBoxTables[Instance];
386 Status = (CurrentTable == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
387 if (CurrentTable) {
388 Size = CurrentTable->Length;
389 DEBUG((EFI_D_ERROR, "adding %p %d\n", CurrentTable, Size));
390 } else
391 Size = 0; // Just to shut up the compiler.
392#else
393 Status = FwVol->ReadSection (
394 FwVol,
395 (EFI_GUID*)PcdGetPtr (PcdAcpiTableStorageFile),
396 EFI_SECTION_RAW,
397 Instance,
398 (VOID**) &CurrentTable,
399 &Size,
400 &FvStatus
401 );
402#endif
403 if (!EFI_ERROR(Status)) {
404 //
405 // Add the table
406 //
407 TableHandle = 0;
408
409 TableSize = ((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable)->Length;
410#ifdef VBOX
411 DEBUG((DEBUG_INFO, "Size:%d, TableSize:%d\n", Size, TableSize));
412#endif
413 ASSERT (Size >= TableSize);
414
415 //
416 // Checksum ACPI table
417 //
418 AcpiPlatformChecksum ((UINT8*)CurrentTable, TableSize);
419
420 //
421 // Install ACPI table
422 //
423 Status = AcpiTable->InstallAcpiTable (
424 AcpiTable,
425 CurrentTable,
426 TableSize,
427 &TableHandle
428 );
429
430#ifndef VBOX /* In case we're reading ACPI tables from memory we haven't
431 allocated this memory, so it isn't required to free it */
432 //
433 // Free memory allocated by ReadSection
434 //
435 gBS->FreePool (CurrentTable);
436
437 if (EFI_ERROR(Status)) {
438 return EFI_ABORTED;
439 }
440#endif
441
442 //
443 // Increment the instance
444 //
445 Instance++;
446 CurrentTable = NULL;
447 }
448 }
449
450 //
451 // The driver does not require to be kept loaded.
452 //
453 return EFI_REQUEST_UNLOAD_IMAGE;
454}
455
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use