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 (at) 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 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 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 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