1 /** @file 2 OVMF ACPI QEMU support 3 4 Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR> 5 6 Copyright (C) 2012-2014, Red Hat, Inc. 7 8 This program and the accompanying materials 9 are licensed and made available under the terms and conditions of the BSD License 10 which accompanies this distribution. The full text of the license may be found at 11 http://opensource.org/licenses/bsd-license.php 12 13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 15 16 **/ 17 18 #include "AcpiPlatform.h" 19 #include "QemuLoader.h" 20 #include <Library/BaseMemoryLib.h> 21 #include <Library/MemoryAllocationLib.h> 22 #include <Library/QemuFwCfgLib.h> 23 #include <Library/DxeServicesTableLib.h> 24 #include <Library/PcdLib.h> 25 #include <Library/OrderedCollectionLib.h> 26 #include <IndustryStandard/Acpi.h> 27 28 BOOLEAN 29 QemuDetected ( 30 VOID 31 ) 32 { 33 if (!QemuFwCfgIsAvailable ()) { 34 return FALSE; 35 } 36 37 return TRUE; 38 } 39 40 41 STATIC 42 UINTN 43 CountBits16 ( 44 UINT16 Mask 45 ) 46 { 47 // 48 // For all N >= 1, N bits are enough to represent the number of bits set 49 // among N bits. It's true for N == 1. When adding a new bit (N := N+1), 50 // the maximum number of possibly set bits increases by one, while the 51 // representable maximum doubles. 52 // 53 Mask = ((Mask & 0xAAAA) >> 1) + (Mask & 0x5555); 54 Mask = ((Mask & 0xCCCC) >> 2) + (Mask & 0x3333); 55 Mask = ((Mask & 0xF0F0) >> 4) + (Mask & 0x0F0F); 56 Mask = ((Mask & 0xFF00) >> 8) + (Mask & 0x00FF); 57 58 return Mask; 59 } 60 61 62 STATIC 63 EFI_STATUS 64 EFIAPI 65 QemuInstallAcpiMadtTable ( 66 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol, 67 IN VOID *AcpiTableBuffer, 68 IN UINTN AcpiTableBufferSize, 69 OUT UINTN *TableKey 70 ) 71 { 72 UINTN CpuCount; 73 UINTN PciLinkIsoCount; 74 UINTN NewBufferSize; 75 EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *Madt; 76 EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE *LocalApic; 77 EFI_ACPI_1_0_IO_APIC_STRUCTURE *IoApic; 78 EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE *Iso; 79 EFI_ACPI_1_0_LOCAL_APIC_NMI_STRUCTURE *LocalApicNmi; 80 VOID *Ptr; 81 UINTN Loop; 82 EFI_STATUS Status; 83 84 ASSERT (AcpiTableBufferSize >= sizeof (EFI_ACPI_DESCRIPTION_HEADER)); 85 86 QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount); 87 CpuCount = QemuFwCfgRead16 (); 88 ASSERT (CpuCount >= 1); 89 90 // 91 // Set Level-tiggered, Active High for these identity mapped IRQs. The bitset 92 // corresponds to the union of all possible interrupt assignments for the LNKA, 93 // LNKB, LNKC, LNKD PCI interrupt lines. See the DSDT. 94 // 95 PciLinkIsoCount = CountBits16 (PcdGet16 (Pcd8259LegacyModeEdgeLevel)); 96 97 NewBufferSize = 1 * sizeof (*Madt) + 98 CpuCount * sizeof (*LocalApic) + 99 1 * sizeof (*IoApic) + 100 (1 + PciLinkIsoCount) * sizeof (*Iso) + 101 1 * sizeof (*LocalApicNmi); 102 103 Madt = AllocatePool (NewBufferSize); 104 if (Madt == NULL) { 105 return EFI_OUT_OF_RESOURCES; 106 } 107 108 CopyMem (&(Madt->Header), AcpiTableBuffer, sizeof (EFI_ACPI_DESCRIPTION_HEADER)); 109 Madt->Header.Length = (UINT32) NewBufferSize; 110 Madt->LocalApicAddress = PcdGet32 (PcdCpuLocalApicBaseAddress); 111 Madt->Flags = EFI_ACPI_1_0_PCAT_COMPAT; 112 Ptr = Madt + 1; 113 114 LocalApic = Ptr; 115 for (Loop = 0; Loop < CpuCount; ++Loop) { 116 LocalApic->Type = EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC; 117 LocalApic->Length = sizeof (*LocalApic); 118 LocalApic->AcpiProcessorId = (UINT8) Loop; 119 LocalApic->ApicId = (UINT8) Loop; 120 LocalApic->Flags = 1; // enabled 121 ++LocalApic; 122 } 123 Ptr = LocalApic; 124 125 IoApic = Ptr; 126 IoApic->Type = EFI_ACPI_1_0_IO_APIC; 127 IoApic->Length = sizeof (*IoApic); 128 IoApic->IoApicId = (UINT8) CpuCount; 129 IoApic->Reserved = EFI_ACPI_RESERVED_BYTE; 130 IoApic->IoApicAddress = 0xFEC00000; 131 IoApic->SystemVectorBase = 0x00000000; 132 Ptr = IoApic + 1; 133 134 // 135 // IRQ0 (8254 Timer) => IRQ2 (PIC) Interrupt Source Override Structure 136 // 137 Iso = Ptr; 138 Iso->Type = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE; 139 Iso->Length = sizeof (*Iso); 140 Iso->Bus = 0x00; // ISA 141 Iso->Source = 0x00; // IRQ0 142 Iso->GlobalSystemInterruptVector = 0x00000002; 143 Iso->Flags = 0x0000; // Conforms to specs of the bus 144 ++Iso; 145 146 // 147 // Set Level-tiggered, Active High for all possible PCI link targets. 148 // 149 for (Loop = 0; Loop < 16; ++Loop) { 150 if ((PcdGet16 (Pcd8259LegacyModeEdgeLevel) & (1 << Loop)) == 0) { 151 continue; 152 } 153 Iso->Type = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE; 154 Iso->Length = sizeof (*Iso); 155 Iso->Bus = 0x00; // ISA 156 Iso->Source = (UINT8) Loop; 157 Iso->GlobalSystemInterruptVector = (UINT32) Loop; 158 Iso->Flags = 0x000D; // Level-tiggered, Active High 159 ++Iso; 160 } 161 ASSERT ( 162 (UINTN) (Iso - (EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE *)Ptr) == 163 1 + PciLinkIsoCount 164 ); 165 Ptr = Iso; 166 167 LocalApicNmi = Ptr; 168 LocalApicNmi->Type = EFI_ACPI_1_0_LOCAL_APIC_NMI; 169 LocalApicNmi->Length = sizeof (*LocalApicNmi); 170 LocalApicNmi->AcpiProcessorId = 0xFF; // applies to all processors 171 // 172 // polarity and trigger mode of the APIC I/O input signals conform to the 173 // specifications of the bus 174 // 175 LocalApicNmi->Flags = 0x0000; 176 // 177 // Local APIC interrupt input LINTn to which NMI is connected. 178 // 179 LocalApicNmi->LocalApicInti = 0x01; 180 Ptr = LocalApicNmi + 1; 181 182 ASSERT ((UINTN) ((UINT8 *)Ptr - (UINT8 *)Madt) == NewBufferSize); 183 Status = InstallAcpiTable (AcpiProtocol, Madt, NewBufferSize, TableKey); 184 185 FreePool (Madt); 186 187 return Status; 188 } 189 190 191 #pragma pack(1) 192 193 typedef struct { 194 UINT64 Base; 195 UINT64 End; 196 UINT64 Length; 197 } PCI_WINDOW; 198 199 typedef struct { 200 PCI_WINDOW PciWindow32; 201 PCI_WINDOW PciWindow64; 202 } FIRMWARE_DATA; 203 204 typedef struct { 205 UINT8 BytePrefix; 206 UINT8 ByteValue; 207 } AML_BYTE; 208 209 typedef struct { 210 UINT8 NameOp; 211 UINT8 RootChar; 212 UINT8 NameChar[4]; 213 UINT8 PackageOp; 214 UINT8 PkgLength; 215 UINT8 NumElements; 216 AML_BYTE Pm1aCntSlpTyp; 217 AML_BYTE Pm1bCntSlpTyp; 218 AML_BYTE Reserved[2]; 219 } SYSTEM_STATE_PACKAGE; 220 221 #pragma pack() 222 223 224 STATIC 225 EFI_STATUS 226 EFIAPI 227 PopulateFwData( 228 OUT FIRMWARE_DATA *FwData 229 ) 230 { 231 EFI_STATUS Status; 232 UINTN NumDesc; 233 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *AllDesc; 234 235 Status = gDS->GetMemorySpaceMap (&NumDesc, &AllDesc); 236 if (Status == EFI_SUCCESS) { 237 UINT64 NonMmio32MaxExclTop; 238 UINT64 Mmio32MinBase; 239 UINT64 Mmio32MaxExclTop; 240 UINTN CurDesc; 241 242 Status = EFI_UNSUPPORTED; 243 244 NonMmio32MaxExclTop = 0; 245 Mmio32MinBase = BASE_4GB; 246 Mmio32MaxExclTop = 0; 247 248 for (CurDesc = 0; CurDesc < NumDesc; ++CurDesc) { 249 CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Desc; 250 UINT64 ExclTop; 251 252 Desc = &AllDesc[CurDesc]; 253 ExclTop = Desc->BaseAddress + Desc->Length; 254 255 if (ExclTop <= (UINT64) PcdGet32 (PcdOvmfFdBaseAddress)) { 256 switch (Desc->GcdMemoryType) { 257 case EfiGcdMemoryTypeNonExistent: 258 break; 259 260 case EfiGcdMemoryTypeReserved: 261 case EfiGcdMemoryTypeSystemMemory: 262 if (NonMmio32MaxExclTop < ExclTop) { 263 NonMmio32MaxExclTop = ExclTop; 264 } 265 break; 266 267 case EfiGcdMemoryTypeMemoryMappedIo: 268 if (Mmio32MinBase > Desc->BaseAddress) { 269 Mmio32MinBase = Desc->BaseAddress; 270 } 271 if (Mmio32MaxExclTop < ExclTop) { 272 Mmio32MaxExclTop = ExclTop; 273 } 274 break; 275 276 default: 277 ASSERT(0); 278 } 279 } 280 } 281 282 if (Mmio32MinBase < NonMmio32MaxExclTop) { 283 Mmio32MinBase = NonMmio32MaxExclTop; 284 } 285 286 if (Mmio32MinBase < Mmio32MaxExclTop) { 287 FwData->PciWindow32.Base = Mmio32MinBase; 288 FwData->PciWindow32.End = Mmio32MaxExclTop - 1; 289 FwData->PciWindow32.Length = Mmio32MaxExclTop - Mmio32MinBase; 290 291 FwData->PciWindow64.Base = 0; 292 FwData->PciWindow64.End = 0; 293 FwData->PciWindow64.Length = 0; 294 295 Status = EFI_SUCCESS; 296 } 297 298 FreePool (AllDesc); 299 } 300 301 DEBUG (( 302 DEBUG_INFO, 303 "ACPI PciWindow32: Base=0x%08lx End=0x%08lx Length=0x%08lx\n", 304 FwData->PciWindow32.Base, 305 FwData->PciWindow32.End, 306 FwData->PciWindow32.Length 307 )); 308 DEBUG (( 309 DEBUG_INFO, 310 "ACPI PciWindow64: Base=0x%08lx End=0x%08lx Length=0x%08lx\n", 311 FwData->PciWindow64.Base, 312 FwData->PciWindow64.End, 313 FwData->PciWindow64.Length 314 )); 315 316 return Status; 317 } 318 319 320 STATIC 321 VOID 322 EFIAPI 323 GetSuspendStates ( 324 UINTN *SuspendToRamSize, 325 SYSTEM_STATE_PACKAGE *SuspendToRam, 326 UINTN *SuspendToDiskSize, 327 SYSTEM_STATE_PACKAGE *SuspendToDisk 328 ) 329 { 330 STATIC CONST SYSTEM_STATE_PACKAGE Template = { 331 0x08, // NameOp 332 '\\', // RootChar 333 { '_', 'S', 'x', '_' }, // NameChar[4] 334 0x12, // PackageOp 335 0x0A, // PkgLength 336 0x04, // NumElements 337 { 0x0A, 0x00 }, // Pm1aCntSlpTyp 338 { 0x0A, 0x00 }, // Pm1bCntSlpTyp -- we don't support it 339 { // Reserved[2] 340 { 0x0A, 0x00 }, 341 { 0x0A, 0x00 } 342 } 343 }; 344 RETURN_STATUS Status; 345 FIRMWARE_CONFIG_ITEM FwCfgItem; 346 UINTN FwCfgSize; 347 UINT8 SystemStates[6]; 348 349 // 350 // configure defaults 351 // 352 *SuspendToRamSize = sizeof Template; 353 CopyMem (SuspendToRam, &Template, sizeof Template); 354 SuspendToRam->NameChar[2] = '3'; // S3 355 SuspendToRam->Pm1aCntSlpTyp.ByteValue = 1; // PIIX4: STR 356 357 *SuspendToDiskSize = sizeof Template; 358 CopyMem (SuspendToDisk, &Template, sizeof Template); 359 SuspendToDisk->NameChar[2] = '4'; // S4 360 SuspendToDisk->Pm1aCntSlpTyp.ByteValue = 2; // PIIX4: POSCL 361 362 // 363 // check for overrides 364 // 365 Status = QemuFwCfgFindFile ("etc/system-states", &FwCfgItem, &FwCfgSize); 366 if (Status != RETURN_SUCCESS || FwCfgSize != sizeof SystemStates) { 367 DEBUG ((DEBUG_INFO, "ACPI using S3/S4 defaults\n")); 368 return; 369 } 370 QemuFwCfgSelectItem (FwCfgItem); 371 QemuFwCfgReadBytes (sizeof SystemStates, SystemStates); 372 373 // 374 // Each byte corresponds to a system state. In each byte, the MSB tells us 375 // whether the given state is enabled. If so, the three LSBs specify the 376 // value to be written to the PM control register's SUS_TYP bits. 377 // 378 if (SystemStates[3] & BIT7) { 379 SuspendToRam->Pm1aCntSlpTyp.ByteValue = 380 SystemStates[3] & (BIT2 | BIT1 | BIT0); 381 DEBUG ((DEBUG_INFO, "ACPI S3 value: %d\n", 382 SuspendToRam->Pm1aCntSlpTyp.ByteValue)); 383 } else { 384 *SuspendToRamSize = 0; 385 DEBUG ((DEBUG_INFO, "ACPI S3 disabled\n")); 386 } 387 388 if (SystemStates[4] & BIT7) { 389 SuspendToDisk->Pm1aCntSlpTyp.ByteValue = 390 SystemStates[4] & (BIT2 | BIT1 | BIT0); 391 DEBUG ((DEBUG_INFO, "ACPI S4 value: %d\n", 392 SuspendToDisk->Pm1aCntSlpTyp.ByteValue)); 393 } else { 394 *SuspendToDiskSize = 0; 395 DEBUG ((DEBUG_INFO, "ACPI S4 disabled\n")); 396 } 397 } 398 399 400 STATIC 401 EFI_STATUS 402 EFIAPI 403 QemuInstallAcpiSsdtTable ( 404 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol, 405 IN VOID *AcpiTableBuffer, 406 IN UINTN AcpiTableBufferSize, 407 OUT UINTN *TableKey 408 ) 409 { 410 EFI_STATUS Status; 411 FIRMWARE_DATA *FwData; 412 413 Status = EFI_OUT_OF_RESOURCES; 414 415 FwData = AllocateReservedPool (sizeof (*FwData)); 416 if (FwData != NULL) { 417 UINTN SuspendToRamSize; 418 SYSTEM_STATE_PACKAGE SuspendToRam; 419 UINTN SuspendToDiskSize; 420 SYSTEM_STATE_PACKAGE SuspendToDisk; 421 UINTN SsdtSize; 422 UINT8 *Ssdt; 423 424 GetSuspendStates (&SuspendToRamSize, &SuspendToRam, 425 &SuspendToDiskSize, &SuspendToDisk); 426 SsdtSize = AcpiTableBufferSize + 17 + SuspendToRamSize + SuspendToDiskSize; 427 Ssdt = AllocatePool (SsdtSize); 428 429 if (Ssdt != NULL) { 430 Status = PopulateFwData (FwData); 431 432 if (Status == EFI_SUCCESS) { 433 UINT8 *SsdtPtr; 434 435 SsdtPtr = Ssdt; 436 437 CopyMem (SsdtPtr, AcpiTableBuffer, AcpiTableBufferSize); 438 SsdtPtr += AcpiTableBufferSize; 439 440 // 441 // build "OperationRegion(FWDT, SystemMemory, 0x12345678, 0x87654321)" 442 // 443 *(SsdtPtr++) = 0x5B; // ExtOpPrefix 444 *(SsdtPtr++) = 0x80; // OpRegionOp 445 *(SsdtPtr++) = 'F'; 446 *(SsdtPtr++) = 'W'; 447 *(SsdtPtr++) = 'D'; 448 *(SsdtPtr++) = 'T'; 449 *(SsdtPtr++) = 0x00; // SystemMemory 450 *(SsdtPtr++) = 0x0C; // DWordPrefix 451 452 // 453 // no virtual addressing yet, take the four least significant bytes 454 // 455 CopyMem(SsdtPtr, &FwData, 4); 456 SsdtPtr += 4; 457 458 *(SsdtPtr++) = 0x0C; // DWordPrefix 459 460 *(UINT32*) SsdtPtr = sizeof (*FwData); 461 SsdtPtr += 4; 462 463 // 464 // add suspend system states 465 // 466 CopyMem (SsdtPtr, &SuspendToRam, SuspendToRamSize); 467 SsdtPtr += SuspendToRamSize; 468 CopyMem (SsdtPtr, &SuspendToDisk, SuspendToDiskSize); 469 SsdtPtr += SuspendToDiskSize; 470 471 ASSERT((UINTN) (SsdtPtr - Ssdt) == SsdtSize); 472 ((EFI_ACPI_DESCRIPTION_HEADER *) Ssdt)->Length = (UINT32) SsdtSize; 473 Status = InstallAcpiTable (AcpiProtocol, Ssdt, SsdtSize, TableKey); 474 } 475 476 FreePool(Ssdt); 477 } 478 479 if (Status != EFI_SUCCESS) { 480 FreePool(FwData); 481 } 482 } 483 484 return Status; 485 } 486 487 488 EFI_STATUS 489 EFIAPI 490 QemuInstallAcpiTable ( 491 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol, 492 IN VOID *AcpiTableBuffer, 493 IN UINTN AcpiTableBufferSize, 494 OUT UINTN *TableKey 495 ) 496 { 497 EFI_ACPI_DESCRIPTION_HEADER *Hdr; 498 EFI_ACPI_TABLE_INSTALL_ACPI_TABLE TableInstallFunction; 499 500 Hdr = (EFI_ACPI_DESCRIPTION_HEADER*) AcpiTableBuffer; 501 switch (Hdr->Signature) { 502 case EFI_ACPI_1_0_APIC_SIGNATURE: 503 TableInstallFunction = QemuInstallAcpiMadtTable; 504 break; 505 case EFI_ACPI_1_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE: 506 TableInstallFunction = QemuInstallAcpiSsdtTable; 507 break; 508 default: 509 TableInstallFunction = InstallAcpiTable; 510 } 511 512 return TableInstallFunction ( 513 AcpiProtocol, 514 AcpiTableBuffer, 515 AcpiTableBufferSize, 516 TableKey 517 ); 518 } 519