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   This program and the accompanying materials
8   are licensed and made available under the terms and conditions of the BSD License
9   which accompanies this distribution.  The full text of the license may be found at
10   http://opensource.org/licenses/bsd-license.php
11 
12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 #include "AcpiPlatform.h"
18 #include <Library/HobLib.h>
19 #include <Guid/XenInfo.h>
20 #include <Library/BaseLib.h>
21 
22 #define XEN_ACPI_PHYSICAL_ADDRESS         0x000EA020
23 #define XEN_BIOS_PHYSICAL_END             0x000FFFFF
24 
25 EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER  *XenAcpiRsdpStructurePtr = NULL;
26 
27 /**
28   This function detects if OVMF is running on Xen.
29 
30 **/
31 BOOLEAN
XenDetected(VOID)32 XenDetected (
33   VOID
34   )
35 {
36   EFI_HOB_GUID_TYPE         *GuidHob;
37 
38   //
39   // See if a XenInfo HOB is available
40   //
41   GuidHob = GetFirstGuidHob (&gEfiXenInfoGuid);
42   if (GuidHob == NULL) {
43     return FALSE;
44   }
45 
46   return TRUE;
47 }
48 
49 /**
50   Get the address of Xen ACPI Root System Description Pointer (RSDP)
51   structure.
52 
53   @param  RsdpStructurePtr   Return pointer to RSDP structure
54 
55   @return EFI_SUCCESS        Find Xen RSDP structure successfully.
56   @return EFI_NOT_FOUND      Don't find Xen RSDP structure.
57   @return EFI_ABORTED        Find Xen RSDP structure, but it's not integrated.
58 
59 **/
60 EFI_STATUS
61 EFIAPI
GetXenAcpiRsdp(OUT EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER ** RsdpPtr)62 GetXenAcpiRsdp (
63   OUT   EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER   **RsdpPtr
64   )
65 {
66   EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER   *RsdpStructurePtr;
67   UINT8                                          *XenAcpiPtr;
68   UINT8                                          Sum;
69 
70   //
71   // Detect the RSDP structure
72   //
73   for (XenAcpiPtr = (UINT8*)(UINTN) XEN_ACPI_PHYSICAL_ADDRESS;
74        XenAcpiPtr < (UINT8*)(UINTN) XEN_BIOS_PHYSICAL_END;
75        XenAcpiPtr += 0x10) {
76 
77     RsdpStructurePtr = (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)
78                          (UINTN) XenAcpiPtr;
79 
80     if (!AsciiStrnCmp ((CHAR8 *) &RsdpStructurePtr->Signature, "RSD PTR ", 8)) {
81       //
82       // RSDP ACPI 1.0 checksum for 1.0/2.0/3.0 table.
83       // This is only the first 20 bytes of the structure
84       //
85       Sum = CalculateSum8 (
86               (CONST UINT8 *)RsdpStructurePtr,
87               sizeof (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER)
88               );
89       if (Sum != 0) {
90         return EFI_ABORTED;
91       }
92 
93       if (RsdpStructurePtr->Revision >= 2) {
94         //
95         // RSDP ACPI 2.0/3.0 checksum, this is the entire table
96         //
97         Sum = CalculateSum8 (
98                 (CONST UINT8 *)RsdpStructurePtr,
99                 sizeof (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER)
100                 );
101         if (Sum != 0) {
102           return EFI_ABORTED;
103         }
104       }
105       *RsdpPtr = RsdpStructurePtr;
106       return EFI_SUCCESS;
107     }
108   }
109 
110   return EFI_NOT_FOUND;
111 }
112 
113 /**
114   Get Xen Acpi tables from the RSDP structure. And installs Xen ACPI tables
115   into the RSDT/XSDT using InstallAcpiTable. Some signature of the installed
116   ACPI tables are: FACP, APIC, HPET, WAET, SSDT, FACS, DSDT.
117 
118   @param  AcpiProtocol           Protocol instance pointer.
119 
120   @return EFI_SUCCESS            The table was successfully inserted.
121   @return EFI_INVALID_PARAMETER  Either AcpiTableBuffer is NULL, TableHandle is
122                                  NULL, or AcpiTableBufferSize and the size
123                                  field embedded in the ACPI table pointed to
124                                  by AcpiTableBuffer are not in sync.
125   @return EFI_OUT_OF_RESOURCES   Insufficient resources exist to complete the request.
126 
127 **/
128 EFI_STATUS
129 EFIAPI
InstallXenTables(IN EFI_ACPI_TABLE_PROTOCOL * AcpiProtocol)130 InstallXenTables (
131   IN   EFI_ACPI_TABLE_PROTOCOL       *AcpiProtocol
132   )
133 {
134   EFI_STATUS                                       Status;
135   UINTN                                            TableHandle;
136 
137   EFI_ACPI_DESCRIPTION_HEADER                      *Rsdt;
138   EFI_ACPI_DESCRIPTION_HEADER                      *Xsdt;
139   VOID                                             *CurrentTableEntry;
140   UINTN                                            CurrentTablePointer;
141   EFI_ACPI_DESCRIPTION_HEADER                      *CurrentTable;
142   UINTN                                            Index;
143   UINTN                                            NumberOfTableEntries;
144   EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE        *Fadt2Table;
145   EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE        *Fadt1Table;
146   EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE     *Facs2Table;
147   EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE     *Facs1Table;
148   EFI_ACPI_DESCRIPTION_HEADER                      *DsdtTable;
149 
150   Fadt2Table  = NULL;
151   Fadt1Table  = NULL;
152   Facs2Table  = NULL;
153   Facs1Table  = NULL;
154   DsdtTable   = NULL;
155   TableHandle = 0;
156   NumberOfTableEntries = 0;
157 
158   //
159   // Try to find Xen ACPI tables
160   //
161   Status = GetXenAcpiRsdp (&XenAcpiRsdpStructurePtr);
162   if (EFI_ERROR (Status)) {
163     return Status;
164   }
165 
166   //
167   // If XSDT table is find, just install its tables.
168   // Otherwise, try to find and install the RSDT tables.
169   //
170   if (XenAcpiRsdpStructurePtr->XsdtAddress) {
171     //
172     // Retrieve the addresses of XSDT and
173     // calculate the number of its table entries.
174     //
175     Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN)
176              XenAcpiRsdpStructurePtr->XsdtAddress;
177     NumberOfTableEntries = (Xsdt->Length -
178                              sizeof (EFI_ACPI_DESCRIPTION_HEADER)) /
179                              sizeof (UINT64);
180 
181     //
182     // Install ACPI tables found in XSDT.
183     //
184     for (Index = 0; Index < NumberOfTableEntries; Index++) {
185       //
186       // Get the table entry from XSDT
187       //
188       CurrentTableEntry = (VOID *) ((UINT8 *) Xsdt +
189                             sizeof (EFI_ACPI_DESCRIPTION_HEADER) +
190                             Index * sizeof (UINT64));
191       CurrentTablePointer = (UINTN) *(UINT64 *)CurrentTableEntry;
192       CurrentTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTablePointer;
193 
194       //
195       // Install the XSDT tables
196       //
197       Status = InstallAcpiTable (
198                  AcpiProtocol,
199                  CurrentTable,
200                  CurrentTable->Length,
201                  &TableHandle
202                  );
203 
204       if (EFI_ERROR (Status)) {
205         return Status;
206       }
207 
208       //
209       // Get the FACS and DSDT table address from the table FADT
210       //
211       if (!AsciiStrnCmp ((CHAR8 *) &CurrentTable->Signature, "FACP", 4)) {
212         Fadt2Table = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *)
213                        (UINTN) CurrentTablePointer;
214         Facs2Table = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)
215                        (UINTN) Fadt2Table->FirmwareCtrl;
216         DsdtTable  = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Fadt2Table->Dsdt;
217       }
218     }
219   }
220   else if (XenAcpiRsdpStructurePtr->RsdtAddress) {
221     //
222     // Retrieve the addresses of RSDT and
223     // calculate the number of its table entries.
224     //
225     Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN)
226              XenAcpiRsdpStructurePtr->RsdtAddress;
227     NumberOfTableEntries = (Rsdt->Length -
228                              sizeof (EFI_ACPI_DESCRIPTION_HEADER)) /
229                              sizeof (UINT32);
230 
231     //
232     // Install ACPI tables found in XSDT.
233     //
234     for (Index = 0; Index < NumberOfTableEntries; Index++) {
235       //
236       // Get the table entry from RSDT
237       //
238       CurrentTableEntry = (UINT32 *) ((UINT8 *) Rsdt +
239                             sizeof (EFI_ACPI_DESCRIPTION_HEADER) +
240                             Index * sizeof (UINT32));
241       CurrentTablePointer = *(UINT32 *)CurrentTableEntry;
242       CurrentTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTablePointer;
243 
244       //
245       // Install the RSDT tables
246       //
247       Status = InstallAcpiTable (
248                  AcpiProtocol,
249                  CurrentTable,
250                  CurrentTable->Length,
251                  &TableHandle
252                  );
253 
254       if (EFI_ERROR (Status)) {
255         return Status;
256       }
257 
258       //
259       // Get the FACS and DSDT table address from the table FADT
260       //
261       if (!AsciiStrnCmp ((CHAR8 *) &CurrentTable->Signature, "FACP", 4)) {
262         Fadt1Table = (EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE *)
263                        (UINTN) CurrentTablePointer;
264         Facs1Table = (EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)
265                        (UINTN) Fadt1Table->FirmwareCtrl;
266         DsdtTable  = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Fadt1Table->Dsdt;
267       }
268     }
269   }
270 
271   //
272   // Install the FACS table.
273   //
274   if (Fadt2Table) {
275     //
276     // FACS 2.0
277     //
278     Status = InstallAcpiTable (
279                AcpiProtocol,
280                Facs2Table,
281                Facs2Table->Length,
282                &TableHandle
283                );
284     if (EFI_ERROR (Status)) {
285       return Status;
286     }
287   }
288   else if (Fadt1Table) {
289     //
290     // FACS 1.0
291     //
292     Status = InstallAcpiTable (
293                AcpiProtocol,
294                Facs1Table,
295                Facs1Table->Length,
296                &TableHandle
297                );
298     if (EFI_ERROR (Status)) {
299       return Status;
300     }
301   }
302 
303   //
304   // Install DSDT table.
305   //
306   Status = InstallAcpiTable (
307              AcpiProtocol,
308              DsdtTable,
309              DsdtTable->Length,
310              &TableHandle
311              );
312   if (EFI_ERROR (Status)) {
313     return Status;
314   }
315 
316   return EFI_SUCCESS;
317 }
318 
319