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