1 /** @file
2   OVMF ACPI Xen support
3 
4   Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
5   Copyright (c) 2012, Bei Guan <gbtju85@gmail.com>
6 
7   SPDX-License-Identifier: BSD-2-Clause-Patent
8 
9 **/
10 
11 #include "AcpiPlatform.h"
12 #include <Library/BaseLib.h>
13 
14 #define XEN_ACPI_PHYSICAL_ADDRESS         0x000EA020
15 #define XEN_BIOS_PHYSICAL_END             0x000FFFFF
16 
17 EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER  *XenAcpiRsdpStructurePtr = NULL;
18 
19 /**
20   Get the address of Xen ACPI Root System Description Pointer (RSDP)
21   structure.
22 
23   @param  RsdpStructurePtr   Return pointer to RSDP structure
24 
25   @return EFI_SUCCESS        Find Xen RSDP structure successfully.
26   @return EFI_NOT_FOUND      Don't find Xen RSDP structure.
27   @return EFI_ABORTED        Find Xen RSDP structure, but it's not integrated.
28 
29 **/
30 EFI_STATUS
31 EFIAPI
32 GetXenAcpiRsdp (
33   OUT   EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER   **RsdpPtr
34   )
LLVMRemarkStreamer(remarks::RemarkStreamer & RS)35 {
36   EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER   *RsdpStructurePtr;
37   UINT8                                          *XenAcpiPtr;
38   UINT8                                          Sum;
39   EFI_XEN_INFO                                   *XenInfo;
40 
41   //
42   // Detect the RSDP structure
43   //
44 
45   //
46   // First look for PVH one
47   //
48   XenInfo = XenGetInfoHOB ();
49   ASSERT (XenInfo != NULL);
50   if (XenInfo->RsdpPvh != NULL) {
51     DEBUG ((DEBUG_INFO, "%a: Use ACPI RSDP table at 0x%p\n",
52       gEfiCallerBaseName, XenInfo->RsdpPvh));
53     *RsdpPtr = XenInfo->RsdpPvh;
54     return EFI_SUCCESS;
55   }
56 
57   //
58   // Otherwise, look for the HVM one
59   //
60   for (XenAcpiPtr = (UINT8*)(UINTN) XEN_ACPI_PHYSICAL_ADDRESS;
61        XenAcpiPtr < (UINT8*)(UINTN) XEN_BIOS_PHYSICAL_END;
62        XenAcpiPtr += 0x10) {
63 
64     RsdpStructurePtr = (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)
65                          (UINTN) XenAcpiPtr;
66 
67     if (!AsciiStrnCmp ((CHAR8 *) &RsdpStructurePtr->Signature, "RSD PTR ", 8)) {
68       //
69       // RSDP ACPI 1.0 checksum for 1.0/2.0/3.0 table.
70       // This is only the first 20 bytes of the structure
71       //
72       Sum = CalculateSum8 (
73               (CONST UINT8 *)RsdpStructurePtr,
74               sizeof (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER)
75               );
76       if (Sum != 0) {
77         return EFI_ABORTED;
78       }
79 
80       if (RsdpStructurePtr->Revision >= 2) {
81         //
82         // RSDP ACPI 2.0/3.0 checksum, this is the entire table
83         //
84         Sum = CalculateSum8 (
85                 (CONST UINT8 *)RsdpStructurePtr,
86                 sizeof (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER)
87                 );
88         if (Sum != 0) {
89           return EFI_ABORTED;
90         }
91       }
92       *RsdpPtr = RsdpStructurePtr;
93       return EFI_SUCCESS;
94     }
95   }
96 
97   return EFI_NOT_FOUND;
98 }
99 
100 /**
101   Get Xen Acpi tables from the RSDP structure. And installs Xen ACPI tables
102   into the RSDT/XSDT using InstallAcpiTable. Some signature of the installed
103   ACPI tables are: FACP, APIC, HPET, WAET, SSDT, FACS, DSDT.
104 
105   @param  AcpiProtocol           Protocol instance pointer.
106 
107   @return EFI_SUCCESS            The table was successfully inserted.
108   @return EFI_INVALID_PARAMETER  Either AcpiTableBuffer is NULL, TableHandle is
109                                  NULL, or AcpiTableBufferSize and the size
110                                  field embedded in the ACPI table pointed to
111                                  by AcpiTableBuffer are not in sync.
112   @return EFI_OUT_OF_RESOURCES   Insufficient resources exist to complete the request.
113 
114 **/
115 EFI_STATUS
116 EFIAPI
117 InstallXenTables (
118   IN   EFI_ACPI_TABLE_PROTOCOL       *AcpiProtocol
119   )
120 {
121   EFI_STATUS                                       Status;
122   UINTN                                            TableHandle;
123 
124   EFI_ACPI_DESCRIPTION_HEADER                      *Rsdt;
125   EFI_ACPI_DESCRIPTION_HEADER                      *Xsdt;
126   VOID                                             *CurrentTableEntry;
127   UINTN                                            CurrentTablePointer;
128   EFI_ACPI_DESCRIPTION_HEADER                      *CurrentTable;
129   UINTN                                            Index;
130   UINTN                                            NumberOfTableEntries;
131   EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE        *Fadt2Table;
132   EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE        *Fadt1Table;
133   EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE     *Facs2Table;
134   EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE     *Facs1Table;
135   EFI_ACPI_DESCRIPTION_HEADER                      *DsdtTable;
136 
137   Fadt2Table  = NULL;
138   Fadt1Table  = NULL;
139   Facs2Table  = NULL;
140   Facs1Table  = NULL;
141   DsdtTable   = NULL;
142   TableHandle = 0;
143   NumberOfTableEntries = 0;
144 
145   //
146   // Try to find Xen ACPI tables
147   //
148   Status = GetXenAcpiRsdp (&XenAcpiRsdpStructurePtr);
149   if (EFI_ERROR (Status)) {
150     return Status;
151   }
152 
153   //
154   // If XSDT table is find, just install its tables.
155   // Otherwise, try to find and install the RSDT tables.
156   //
157   if (XenAcpiRsdpStructurePtr->XsdtAddress) {
158     //
159     // Retrieve the addresses of XSDT and
160     // calculate the number of its table entries.
161     //
162     Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN)
163              XenAcpiRsdpStructurePtr->XsdtAddress;
164     NumberOfTableEntries = (Xsdt->Length -
165                              sizeof (EFI_ACPI_DESCRIPTION_HEADER)) /
166                              sizeof (UINT64);
167 
168     //
169     // Install ACPI tables found in XSDT.
170     //
171     for (Index = 0; Index < NumberOfTableEntries; Index++) {
172       //
173       // Get the table entry from XSDT
174       //
175       CurrentTableEntry = (VOID *) ((UINT8 *) Xsdt +
176                             sizeof (EFI_ACPI_DESCRIPTION_HEADER) +
177                             Index * sizeof (UINT64));
178       CurrentTablePointer = (UINTN) *(UINT64 *)CurrentTableEntry;
179       CurrentTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTablePointer;
180 
181       //
182       // Install the XSDT tables
183       //
184       Status = InstallAcpiTable (
185                  AcpiProtocol,
186                  CurrentTable,
187                  CurrentTable->Length,
188                  &TableHandle
189                  );
190 
191       if (EFI_ERROR (Status)) {
192         return Status;
193       }
194 
195       //
196       // Get the FACS and DSDT table address from the table FADT
197       //
198       if (!AsciiStrnCmp ((CHAR8 *) &CurrentTable->Signature, "FACP", 4)) {
199         Fadt2Table = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *)
200                        (UINTN) CurrentTablePointer;
201         Facs2Table = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)
202                        (UINTN) Fadt2Table->FirmwareCtrl;
203         DsdtTable  = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Fadt2Table->Dsdt;
204       }
205     }
206   }
207   else if (XenAcpiRsdpStructurePtr->RsdtAddress) {
208     //
209     // Retrieve the addresses of RSDT and
210     // calculate the number of its table entries.
211     //
212     Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN)
213              XenAcpiRsdpStructurePtr->RsdtAddress;
214     NumberOfTableEntries = (Rsdt->Length -
215                              sizeof (EFI_ACPI_DESCRIPTION_HEADER)) /
216                              sizeof (UINT32);
217 
218     //
219     // Install ACPI tables found in XSDT.
220     //
221     for (Index = 0; Index < NumberOfTableEntries; Index++) {
222       //
223       // Get the table entry from RSDT
224       //
225       CurrentTableEntry = (UINT32 *) ((UINT8 *) Rsdt +
226                             sizeof (EFI_ACPI_DESCRIPTION_HEADER) +
227                             Index * sizeof (UINT32));
228       CurrentTablePointer = *(UINT32 *)CurrentTableEntry;
229       CurrentTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTablePointer;
230 
231       //
232       // Install the RSDT tables
233       //
234       Status = InstallAcpiTable (
235                  AcpiProtocol,
236                  CurrentTable,
237                  CurrentTable->Length,
238                  &TableHandle
239                  );
240 
241       if (EFI_ERROR (Status)) {
242         return Status;
243       }
244 
245       //
246       // Get the FACS and DSDT table address from the table FADT
247       //
248       if (!AsciiStrnCmp ((CHAR8 *) &CurrentTable->Signature, "FACP", 4)) {
249         Fadt1Table = (EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE *)
250                        (UINTN) CurrentTablePointer;
251         Facs1Table = (EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)
252                        (UINTN) Fadt1Table->FirmwareCtrl;
253         DsdtTable  = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Fadt1Table->Dsdt;
254       }
255     }
256   }
257 
258   //
259   // Install the FACS table.
260   //
261   if (Fadt2Table) {
262     //
263     // FACS 2.0
264     //
265     Status = InstallAcpiTable (
266                AcpiProtocol,
267                Facs2Table,
268                Facs2Table->Length,
269                &TableHandle
270                );
271     if (EFI_ERROR (Status)) {
272       return Status;
273     }
274   }
275   else if (Fadt1Table) {
276     //
277     // FACS 1.0
278     //
279     Status = InstallAcpiTable (
280                AcpiProtocol,
281                Facs1Table,
282                Facs1Table->Length,
283                &TableHandle
284                );
285     if (EFI_ERROR (Status)) {
286       return Status;
287     }
288   }
289 
290   //
291   // Install DSDT table. If we reached this point without finding the DSDT,
292   // then we're out of sync with the hypervisor, and cannot continue.
293   //
294   if (DsdtTable == NULL) {
295     DEBUG ((DEBUG_ERROR, "%a: no DSDT found\n", __FUNCTION__));
296     ASSERT (FALSE);
297     CpuDeadLoop ();
298   }
299 
300   Status = InstallAcpiTable (
301              AcpiProtocol,
302              DsdtTable,
303              DsdtTable->Length,
304              &TableHandle
305              );
306   if (EFI_ERROR (Status)) {
307     return Status;
308   }
309 
310   return EFI_SUCCESS;
311 }
312 
313