diff --git a/MdePkg/Include/Uefi/UefiBaseType.h b/MdePkg/Include/Uefi/UefiBaseType.h index 45e2aa63bb..084c52cd0f 100644 --- a/MdePkg/Include/Uefi/UefiBaseType.h +++ b/MdePkg/Include/Uefi/UefiBaseType.h @@ -53,6 +53,8 @@ typedef UINT64 EFI_PHYSICAL_ADDRESS; /// typedef UINT64 EFI_VIRTUAL_ADDRESS; +#define NUMERIC_VALUE_AS_POINTER(Type, Value) ((Type *) ((UINTN)(Value))) + /// /// EFI Time Abstraction: /// Year: 1900 - 9999 diff --git a/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatform.c b/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatform.c index 9ccdb4d91c..e7de6937da 100644 --- a/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatform.c +++ b/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatform.c @@ -245,6 +245,16 @@ InstallAcpiTables ( { EFI_STATUS Status; + Status = InstallBhyveTables (AcpiTable); + if (!EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + if (Status != EFI_NOT_FOUND) { + DEBUG ((DEBUG_INFO, "%a: unable to install bhyve's ACPI tables (%r)\n", + __FUNCTION__, Status)); + return Status; + } + Status = InstallOvmfFvTables (AcpiTable); return Status; diff --git a/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatform.h b/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatform.h index 994ee2c7cd..1a99838e8e 100644 --- a/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatform.h +++ b/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatform.h @@ -46,6 +46,12 @@ BhyveInstallAcpiTable( OUT UINTN *TableKey ); +EFI_STATUS +EFIAPI +InstallBhyveTables ( + IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol + ); + EFI_STATUS EFIAPI InstallXenTables ( diff --git a/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatformDxe.inf b/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatformDxe.inf index 595fd055f9..a2efa3feb1 100644 --- a/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatformDxe.inf +++ b/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatformDxe.inf @@ -37,12 +37,12 @@ [LibraryClasses] BaseLib BaseMemoryLib - BhyveFwCtlLib DebugLib DxeServicesTableLib MemoryAllocationLib OrderedCollectionLib PcdLib + QemuFwCfgLib UefiBootServicesTableLib UefiDriverEntryPoint UefiLib diff --git a/OvmfPkg/Bhyve/AcpiPlatformDxe/Bhyve.c b/OvmfPkg/Bhyve/AcpiPlatformDxe/Bhyve.c index 01ee894746..e2c543516a 100644 --- a/OvmfPkg/Bhyve/AcpiPlatformDxe/Bhyve.c +++ b/OvmfPkg/Bhyve/AcpiPlatformDxe/Bhyve.c @@ -9,8 +9,55 @@ #include "AcpiPlatform.h" #include -#include #include +#include // QemuFwCfgFindFile() + +#define BHYVE_ACPI_PHYSICAL_ADDRESS ((UINTN)0x000F2400) +#define BHYVE_BIOS_PHYSICAL_END ((UINTN)0x00100000) + +#pragma pack (1) + +typedef struct +{ + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 Tables[0]; +} EFI_ACPI_2_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE; + +#pragma pack () + +STATIC +EFI_STATUS +EFIAPI +BhyveGetCpuCount ( + OUT UINT32 *CpuCount + ) +{ + EFI_STATUS Status; + FIRMWARE_CONFIG_ITEM Item; + UINTN Size; + + if (!QemuFwCfgIsAvailable ()) { + return EFI_NOT_FOUND; + } + + // + // Get index of FW_CFG file + // + Status = QemuFwCfgFindFile ("opt/bhyve/hw.ncpu", &Item, &Size); + if (EFI_ERROR (Status)) { + return Status; + } else if (Size != sizeof (*CpuCount)) { + return EFI_BAD_BUFFER_SIZE; + } + + // + // Get data of FW_CFG file + // + QemuFwCfgSelectItem (Item); + QemuFwCfgReadBytes (Size, CpuCount); + + return EFI_SUCCESS; +} STATIC EFI_STATUS @@ -23,7 +70,6 @@ BhyveInstallAcpiMadtTable ( ) { UINT32 CpuCount; - UINTN cSize; UINTN NewBufferSize; EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *Madt; EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE *LocalApic; @@ -36,9 +82,8 @@ BhyveInstallAcpiMadtTable ( ASSERT (AcpiTableBufferSize >= sizeof (EFI_ACPI_DESCRIPTION_HEADER)); // Query the host for the number of vCPUs - CpuCount = 0; - cSize = sizeof(CpuCount); - if (BhyveFwCtlGet ("hw.ncpu", &CpuCount, &cSize) == RETURN_SUCCESS) { + Status = BhyveGetCpuCount (&CpuCount); + if (!EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "Retrieved CpuCount %d\n", CpuCount)); ASSERT (CpuCount >= 1); } else { @@ -130,3 +175,231 @@ BhyveInstallAcpiTable ( TableKey ); } + +/** + Get the address of bhyve's ACPI Root System Description Pointer (RSDP). + + @param RsdpPtr Return pointer to RSDP. + + @return EFI_SUCCESS Bhyve's RSDP successfully found. + @return EFI_NOT_FOUND Couldn't find bhyve's RSDP. + @return EFI_UNSUPPORTED Revision is lower than 2. + @return EFI_PROTOCOL_ERROR Invalid RSDP found. + +**/ +EFI_STATUS +EFIAPI +BhyveGetAcpiRsdp ( + OUT EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER **RsdpPtr + ) +{ + UINTN RsdpAddress; + EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp; + + if (RsdpPtr == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Detect the RSDP + // + for (RsdpAddress = BHYVE_ACPI_PHYSICAL_ADDRESS; + RsdpAddress < BHYVE_BIOS_PHYSICAL_END; + RsdpAddress += 0x10) { + Rsdp = NUMERIC_VALUE_AS_POINTER ( + EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER, + RsdpAddress + ); + if (Rsdp->Signature != EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE) { + continue; + } + if (Rsdp->Revision < 2) { + DEBUG ((DEBUG_INFO, "%a: unsupported RSDP found\n", __FUNCTION__)); + return EFI_UNSUPPORTED; + } + + // + // For ACPI 1.0/2.0/3.0 the checksum of first 20 bytes should be 0. + // For ACPI 2.0/3.0 the checksum of the entire table should be 0. + // + UINT8 Sum = CalculateCheckSum8 ( + (CONST UINT8 *)Rsdp, + sizeof (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER) + ); + if (Sum != 0) { + DEBUG ((DEBUG_INFO, "%a: RSDP header checksum not valid: 0x%02x\n", + __FUNCTION__, Sum)); + return EFI_PROTOCOL_ERROR; + } + Sum = CalculateCheckSum8 ( + (CONST UINT8 *)Rsdp, + sizeof (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER) + ); + if (Sum != 0) { + DEBUG ((DEBUG_INFO, "%a: RSDP table checksum not valid: 0x%02x\n", + __FUNCTION__, Sum)); + return EFI_PROTOCOL_ERROR; + } + + // + // RSDP was found and is valid + // + *RsdpPtr = Rsdp; + + return EFI_SUCCESS; + } + + DEBUG ((DEBUG_INFO, "%a: RSDP not found\n", __FUNCTION__)); + return EFI_NOT_FOUND; +} + +/** + Get bhyve's ACPI tables from the RSDP. And install bhyve's ACPI tables + into the RSDT/XSDT using InstallAcpiTable. + + @param AcpiProtocol Protocol instance pointer. + + @return EFI_SUCCESS All tables were successfully inserted. + @return EFI_UNSUPPORTED Bhyve's ACPI tables doesn't include a XSDT. + @return EFI_PROTOCOL_ERROR Invalid XSDT found. + + @return Error codes propagated from underlying functions. +**/ +EFI_STATUS +EFIAPI +InstallBhyveTables ( + IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol + ) +{ + EFI_STATUS Status; + UINTN TableHandle; + EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp; + EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs; + EFI_ACPI_DESCRIPTION_HEADER *Dsdt; + + Rsdp = NULL; + Facs = NULL; + Dsdt = NULL; + + // + // Try to find bhyve ACPI tables + // + Status = BhyveGetAcpiRsdp (&Rsdp); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "%a: can't get RSDP (%r)\n", __FUNCTION__, Status)); + return Status; + } + + // + // Bhyve should always provide a XSDT + // + EFI_ACPI_2_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE * CONST Xsdt = + NUMERIC_VALUE_AS_POINTER ( + EFI_ACPI_2_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE, + Rsdp->XsdtAddress + ); + if (Xsdt == NULL) { + DEBUG ((DEBUG_INFO, "%a: XSDT not found\n", __FUNCTION__)); + return EFI_UNSUPPORTED; + } + if (Xsdt->Header.Length < sizeof (EFI_ACPI_DESCRIPTION_HEADER)) { + DEBUG ((DEBUG_INFO, "%a: invalid XSDT length\n", __FUNCTION__)); + return EFI_PROTOCOL_ERROR; + } + + // + // Install ACPI tables + // + CONST UINTN NumberOfTableEntries = + (Xsdt->Header.Length - sizeof (Xsdt->Header)) / sizeof (UINT64); + for (UINTN Index = 0; Index < NumberOfTableEntries; Index++) { + EFI_ACPI_DESCRIPTION_HEADER * CONST CurrentTable = + NUMERIC_VALUE_AS_POINTER ( + EFI_ACPI_DESCRIPTION_HEADER, + Xsdt->Tables[Index] + ); + Status = AcpiProtocol->InstallAcpiTable ( + AcpiProtocol, + CurrentTable, + CurrentTable->Length, + &TableHandle + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "%a: failed to install ACPI table %c%c%c%c (%r)\n", + __FUNCTION__, + NUMERIC_VALUE_AS_POINTER (UINT8, CurrentTable->Signature)[0], + NUMERIC_VALUE_AS_POINTER (UINT8, CurrentTable->Signature)[1], + NUMERIC_VALUE_AS_POINTER (UINT8, CurrentTable->Signature)[2], + NUMERIC_VALUE_AS_POINTER (UINT8, CurrentTable->Signature)[3], + Status)); + return Status; + } + + if (CurrentTable->Signature == EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) { + EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE * CONST Fadt = + (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE * CONST)CurrentTable; + if (Fadt->XFirmwareCtrl) { + Facs = NUMERIC_VALUE_AS_POINTER ( + EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE, + Fadt->XFirmwareCtrl + ); + } else { + Facs = NUMERIC_VALUE_AS_POINTER ( + EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE, + Fadt->FirmwareCtrl + ); + } + if (Fadt->XDsdt) { + Dsdt = NUMERIC_VALUE_AS_POINTER ( + EFI_ACPI_DESCRIPTION_HEADER, + Fadt->XDsdt + ); + } else { + Dsdt = NUMERIC_VALUE_AS_POINTER ( + EFI_ACPI_DESCRIPTION_HEADER, + Fadt->Dsdt + ); + } + } + } + + // + // Install FACS + // + if (Facs != NULL) { + Status = AcpiProtocol->InstallAcpiTable ( + AcpiProtocol, + Facs, + Facs->Length, + &TableHandle + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "%a: failed to install FACS (%r)\n", __FUNCTION__, + Status)); + return Status; + } + } + + // + // Install DSDT + // If it's not found, something bad happened. Don't continue execution. + // + if (Dsdt == NULL) { + DEBUG ((DEBUG_ERROR, "%a: failed to find DSDT\n", __FUNCTION__)); + CpuDeadLoop (); + } + + Status = AcpiProtocol->InstallAcpiTable ( + AcpiProtocol, + Dsdt, + Dsdt->Length, + &TableHandle + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "%a: failed to install DSDT (%r)\n", __FUNCTION__, + Status)); + return Status; + } + + return EFI_SUCCESS; +} diff --git a/OvmfPkg/Bhyve/BhyveX64.dsc b/OvmfPkg/Bhyve/BhyveX64.dsc index d8fe607d1c..53f061eeb3 100644 --- a/OvmfPkg/Bhyve/BhyveX64.dsc +++ b/OvmfPkg/Bhyve/BhyveX64.dsc @@ -163,9 +163,7 @@ SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf SerializeVariablesLib|OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.inf - QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibNull.inf - QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/BaseQemuFwCfgS3LibNull.inf - BhyveFwCtlLib|OvmfPkg/Library/BhyveFwCtlLib/BhyveFwCtlLib.inf + QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxeLib.inf VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf @@ -284,6 +282,7 @@ !endif CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf + QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf @@ -354,6 +353,7 @@ !endif PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf MpInitLib|UefiCpuPkg/Library/MpInitLibUp/MpInitLibUp.inf + QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf [LibraryClasses.common.UEFI_APPLICATION] PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf @@ -416,7 +416,6 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol|TRUE [PcdsFixedAtBuild] - gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration|TRUE gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|TRUE gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1 @@ -622,10 +621,11 @@ UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf UefiCpuPkg/CpuDxe/CpuDxe.inf PcAtChipsetPkg/HpetTimerDxe/HpetTimerDxe.inf + OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf { - PciHostBridgeLib|OvmfPkg/Library/PciHostBridgeLibScan/PciHostBridgeLibScan.inf + PciHostBridgeLib|OvmfPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf PciHostBridgeUtilityLib|OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.inf NULL|OvmfPkg/Library/PlatformHasIoMmuLib/PlatformHasIoMmuLib.inf } @@ -660,6 +660,7 @@ OvmfPkg/VirtioBlkDxe/VirtioBlk.inf OvmfPkg/VirtioScsiDxe/VirtioScsi.inf OvmfPkg/VirtioRngDxe/VirtioRng.inf + OvmfPkg/PlatformGopPolicy/PlatformGopPolicy.inf MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf diff --git a/OvmfPkg/Bhyve/BhyveX64.fdf b/OvmfPkg/Bhyve/BhyveX64.fdf index b3b4d44cef..20d9aa7e6c 100644 --- a/OvmfPkg/Bhyve/BhyveX64.fdf +++ b/OvmfPkg/Bhyve/BhyveX64.fdf @@ -205,6 +205,7 @@ INF MdeModulePkg/Universal/EbcDxe/EbcDxe.inf INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf INF UefiCpuPkg/CpuDxe/CpuDxe.inf INF PcAtChipsetPkg/HpetTimerDxe/HpetTimerDxe.inf +INF OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf INF OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf @@ -217,6 +218,7 @@ INF OvmfPkg/Virtio10Dxe/Virtio10.inf INF OvmfPkg/VirtioBlkDxe/VirtioBlk.inf INF OvmfPkg/VirtioScsiDxe/VirtioScsi.inf INF OvmfPkg/VirtioRngDxe/VirtioRng.inf +INF OvmfPkg/PlatformGopPolicy/PlatformGopPolicy.inf !if $(SECURE_BOOT_ENABLE) == TRUE INF SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf diff --git a/OvmfPkg/Bhyve/PlatformPei/MemDetect.c b/OvmfPkg/Bhyve/PlatformPei/MemDetect.c index 1b556be69c..80ac24a813 100644 --- a/OvmfPkg/Bhyve/PlatformPei/MemDetect.c +++ b/OvmfPkg/Bhyve/PlatformPei/MemDetect.c @@ -30,6 +30,7 @@ Module Name: #include #include #include +#include #include #include @@ -352,6 +353,9 @@ PublishPeiMemory ( VOID ) { + EFI_E820_ENTRY64 E820Entry; + FIRMWARE_CONFIG_ITEM Item; + UINTN ItemSize; EFI_STATUS Status; EFI_PHYSICAL_ADDRESS MemoryBase; UINT64 MemorySize; @@ -407,6 +411,78 @@ PublishPeiMemory ( } } + // + // Bhyve uses an E820 table to reserve certain kinds of memory like Graphics + // Stolen Memory. These reserved memory regions could overlap with the PEI + // core memory which leads to undefined behaviour. Check the E820 table for + // a memory region starting at or below MemoryBase which is equal or larger + // than MemorySize. + // + if (!EFI_ERROR (QemuFwCfgFindFile("etc/e820", &Item, &ItemSize))) { + // + // Set a new base address based on E820 table. + // + + EFI_PHYSICAL_ADDRESS MaxAddress; + UINT64 EntryEnd; + UINT64 EndAddr; + + if (ItemSize % sizeof (E820Entry) != 0) { + DEBUG ((DEBUG_INFO, "%a: invalid E820 size\n", __FUNCTION__)); + return EFI_PROTOCOL_ERROR; + } + + QemuFwCfgSelectItem(Item); + + MaxAddress = MemoryBase + MemorySize; + MemoryBase = 0; + + for (UINTN i = 0; i < ItemSize; i += sizeof (E820Entry)) { + + QemuFwCfgReadBytes (sizeof (E820Entry), &E820Entry); + + if (E820Entry.BaseAddr > MaxAddress) { + // + // E820 is always sorted in ascending order. For that reason, BaseAddr + // will always be larger than MaxAddress for the following entries. + // + break; + } else if (E820Entry.Type != EfiAcpiAddressRangeMemory) { + continue; + } + + // + // Since MemoryBase should be at top of the memory, calculate the end + // address of the entry. Additionally, MemoryBase and MemorySize are page + // aligned. For that reason, page align EntryEnd too. + // + EntryEnd = (E820Entry.BaseAddr + E820Entry.Length) & ~EFI_PAGE_MASK; + if (E820Entry.BaseAddr > EntryEnd) { + // + // Either BaseAddr + Length overflows or the entry is smaller than a + // page. In both cases, we can't use it. + // + continue; + } + + EndAddr = MIN (EntryEnd, MaxAddress); + if (EndAddr - E820Entry.BaseAddr < MemorySize) { + // + // E820 entry is too small for the Pei core memory. + // + continue; + } + + MemoryBase = EndAddr - MemorySize; + } + + if (MemoryBase == 0) { + DEBUG ((DEBUG_ERROR, "%a: Unable to find suitable PeiCore address\n", + __FUNCTION__)); + return EFI_OUT_OF_RESOURCES; + } + } + // // Publish this memory to the PEI Core // diff --git a/OvmfPkg/Bhyve/PlatformPei/Platform.c b/OvmfPkg/Bhyve/PlatformPei/Platform.c index c23b906733..788198e70e 100644 --- a/OvmfPkg/Bhyve/PlatformPei/Platform.c +++ b/OvmfPkg/Bhyve/PlatformPei/Platform.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -487,6 +488,110 @@ DebugDumpCmos ( } +STATIC +EFI_STATUS +E820ReserveMemory ( + VOID + ) +{ + EFI_E820_ENTRY64 E820Entry; + FIRMWARE_CONFIG_ITEM Item; + UINTN Size; + EFI_STATUS Status; + + Status = QemuFwCfgFindFile ("etc/e820", &Item, &Size); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "%a: E820 not found: %r\n", __FUNCTION__, Status)); + return Status; + } + + if (Size % sizeof (E820Entry) != 0) { + DEBUG ((DEBUG_INFO, "%a: invalid E820 size\n", __FUNCTION__)); + return EFI_PROTOCOL_ERROR; + } + + QemuFwCfgSelectItem (Item); + for (UINTN i = 0; i < Size; i += sizeof (E820Entry)) { + UINT64 Base; + UINT64 End; + + QemuFwCfgReadBytes (sizeof (E820Entry), &E820Entry); + + DEBUG_CODE ( + CHAR8 *E820TypeName; + switch (E820Entry.Type) { + case EfiAcpiAddressRangeMemory: + E820TypeName = "RAM "; + break; + case EfiAcpiAddressRangeReserved: + E820TypeName = "Reserved"; + break; + case EfiAcpiAddressRangeACPI: + E820TypeName = "ACPI "; + break; + case EfiAcpiAddressRangeNVS: + E820TypeName = "NVS "; + break; + default: + E820TypeName = "Unknown "; + break; + } + DEBUG ((DEBUG_INFO, "E820 entry [ %16lx, %16lx] (%a)\n", + E820Entry.BaseAddr, E820Entry.BaseAddr + E820Entry.Length, + E820TypeName)); + ); + + // + // Round down base and round up length to page boundary + // + Base = E820Entry.BaseAddr & ~(UINT64)EFI_PAGE_MASK; + End = ALIGN_VALUE ( + E820Entry.BaseAddr + E820Entry.Length, + (UINT64)EFI_PAGE_SIZE + ); + + switch (E820Entry.Type) { + case EfiAcpiAddressRangeReserved: + BuildMemoryAllocationHob ( + Base, + End - Base, + EfiReservedMemoryType + ); + break; + + case EfiAcpiAddressRangeACPI: + BuildMemoryAllocationHob ( + Base, + End - Base, + EfiACPIReclaimMemory + ); + break; + + case EfiAcpiAddressRangeNVS: + BuildMemoryAllocationHob ( + Base, + End - Base, + EfiACPIMemoryNVS + ); + break; + + case EfiAcpiAddressRangeMemory: + // + // EfiAcpiAddressRangeMemory is usable. Do not build an Allocation HOB. + // + break; + + default: + DEBUG ((DEBUG_ERROR, "%a: Unknown E820 type %d\n", __FUNCTION__, + E820Entry.Type)); + return EFI_PROTOCOL_ERROR; + } + } + + return EFI_SUCCESS; +} + + VOID S3Verification ( VOID @@ -563,6 +668,10 @@ InitializePlatform ( IN CONST EFI_PEI_SERVICES **PeiServices ) { + EFI_STATUS Status; + FIRMWARE_CONFIG_ITEM Item; + UINTN Size; + DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n")); // @@ -575,6 +684,16 @@ InitializePlatform ( DebugDumpCmos (); + // + // If an E820 table exists, Memory should be reserved by E820. + // + if (!EFI_ERROR (QemuFwCfgFindFile("etc/e820", &Item, &Size))) { + Status = E820ReserveMemory (); + if (EFI_ERROR (Status)) { + return Status; + } + } + BootModeInitialization (); AddressWidthInitialization (); MaxCpuCountInitialization (); diff --git a/OvmfPkg/Bhyve/PlatformPei/PlatformPei.inf b/OvmfPkg/Bhyve/PlatformPei/PlatformPei.inf index 739d63098b..557a8f890e 100644 --- a/OvmfPkg/Bhyve/PlatformPei/PlatformPei.inf +++ b/OvmfPkg/Bhyve/PlatformPei/PlatformPei.inf @@ -59,6 +59,7 @@ PeiServicesLib PeiServicesTablePointerLib PcdLib + QemuFwCfgLib ResourcePublicationLib [Pcd] diff --git a/OvmfPkg/Include/IndustryStandard/IgdOpRegion.h b/OvmfPkg/Include/IndustryStandard/IgdOpRegion.h new file mode 100644 index 0000000000..4e9180c86b --- /dev/null +++ b/OvmfPkg/Include/IndustryStandard/IgdOpRegion.h @@ -0,0 +1,181 @@ +/** @file + IGD OpRegion definition from Intel Integrated Graphics Device OpRegion + Specification. + + https://01.org/sites/default/files/documentation/skl_opregion_rev0p5.pdf + + @note Fixed bug in the spec Mailbox3 - RM31 size from 0x45(69) to 0x46(70) + + Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#ifndef _IGD_OPREGION_H_ +#define _IGD_OPREGION_H_ + +#define IGD_OPREGION_HEADER_SIGN "IntelGraphicsMem" +#define IGD_OPREGION_HEADER_MBOX1 BIT0 +#define IGD_OPREGION_HEADER_MBOX2 BIT1 +#define IGD_OPREGION_HEADER_MBOX3 BIT2 +#define IGD_OPREGION_HEADER_MBOX4 BIT3 +#define IGD_OPREGION_HEADER_MBOX5 BIT4 + +#define IGD_OPREGION_VBT_SIZE_6K (6 * SIZE_1KB) + +/** + OpRegion structures: + Sub-structures define the different parts of the OpRegion followed by the + main structure representing the entire OpRegion. + + @note These structures are packed to 1 byte offsets because the exact + data location is required by the supporting design specification due to + the fact that the data is used by ASL and Graphics driver code compiled + separately. +**/ +#pragma pack(1) +/// +/// OpRegion Mailbox 0 Header structure. The OpRegion Header is used to +/// identify a block of memory as the graphics driver OpRegion. +/// Offset 0x0, Size 0x100 +/// +typedef struct { + CHAR8 SIGN[0x10]; ///< Offset 0x00 OpRegion Signature + UINT32 SIZE; ///< Offset 0x10 OpRegion Size + UINT32 OVER; ///< Offset 0x14 OpRegion Structure Version + UINT8 SVER[0x20]; ///< Offset 0x18 System BIOS Build Version + UINT8 VVER[0x10]; ///< Offset 0x38 Video BIOS Build Version + UINT8 GVER[0x10]; ///< Offset 0x48 Graphic Driver Build Version + UINT32 MBOX; ///< Offset 0x58 Supported Mailboxes + UINT32 DMOD; ///< Offset 0x5C Driver Model + UINT32 PCON; ///< Offset 0x60 Platform Configuration + CHAR16 DVER[0x10]; ///< Offset 0x64 GOP Version + UINT8 RM01[0x7C]; ///< Offset 0x84 Reserved Must be zero +} IGD_OPREGION_HEADER; + +/// +/// OpRegion Mailbox 1 - Public ACPI Methods +/// Offset 0x100, Size 0x100 +/// +typedef struct { + UINT32 DRDY; ///< Offset 0x100 Driver Readiness + UINT32 CSTS; ///< Offset 0x104 Status + UINT32 CEVT; ///< Offset 0x108 Current Event + UINT8 RM11[0x14]; ///< Offset 0x10C Reserved Must be Zero + UINT32 DIDL[8]; ///< Offset 0x120 Supported Display Devices ID List + UINT32 CPDL[8]; ///< Offset 0x140 Currently Attached Display Devices List + UINT32 CADL[8]; ///< Offset 0x160 Currently Active Display Devices List + UINT32 NADL[8]; ///< Offset 0x180 Next Active Devices List + UINT32 ASLP; ///< Offset 0x1A0 ASL Sleep Time Out + UINT32 TIDX; ///< Offset 0x1A4 Toggle Table Index + UINT32 CHPD; ///< Offset 0x1A8 Current Hotplug Enable Indicator + UINT32 CLID; ///< Offset 0x1AC Current Lid State Indicator + UINT32 CDCK; ///< Offset 0x1B0 Current Docking State Indicator + UINT32 SXSW; ///< Offset 0x1B4 Display Switch Notification on Sx State Resume + UINT32 EVTS; ///< Offset 0x1B8 Events supported by ASL + UINT32 CNOT; ///< Offset 0x1BC Current OS Notification + UINT32 NRDY; ///< Offset 0x1C0 Driver Status + UINT8 DID2[0x1C]; ///< Offset 0x1C4 Extended Supported Devices ID List (DOD) + UINT8 CPD2[0x1C]; ///< Offset 0x1E0 Extended Attached Display Devices List + UINT8 RM12[4]; ///< Offset 0x1FC - 0x1FF Reserved Must be zero +} IGD_OPREGION_MBOX1; + +/// +/// OpRegion Mailbox 2 - Software SCI Interface +/// Offset 0x200, Size 0x100 +/// +typedef struct { + UINT32 SCIC; ///< Offset 0x200 Software SCI Command / Status / Data + UINT32 PARM; ///< Offset 0x204 Software SCI Parameters + UINT32 DSLP; ///< Offset 0x208 Driver Sleep Time Out + UINT8 RM21[0xF4]; ///< Offset 0x20C - 0x2FF Reserved Must be zero +} IGD_OPREGION_MBOX2; + +/// +/// OpRegion Mailbox 3 - BIOS/Driver Notification - ASLE Support +/// Offset 0x300, Size 0x100 +/// +typedef struct { + UINT32 ARDY; ///< Offset 0x300 Driver Readiness + UINT32 ASLC; ///< Offset 0x304 ASLE Interrupt Command / Status + UINT32 TCHE; ///< Offset 0x308 Technology Enabled Indicator + UINT32 ALSI; ///< Offset 0x30C Current ALS Luminance Reading + UINT32 BCLP; ///< Offset 0x310 Requested Backlight Brightness + UINT32 PFIT; ///< Offset 0x314 Panel Fitting State or Request + UINT32 CBLV; ///< Offset 0x318 Current Brightness Level + UINT16 BCLM[0x14]; ///< Offset 0x31C Backlight Brightness Levels Duty Cycle Mapping Table + UINT32 CPFM; ///< Offset 0x344 Current Panel Fitting Mode + UINT32 EPFM; ///< Offset 0x348 Enabled Panel Fitting Modes + UINT8 PLUT[0x4A]; ///< Offset 0x34C Panel Look Up Table & Identifier + UINT32 PFMB; ///< Offset 0x396 PWM Frequency and Minimum Brightness + UINT32 CCDV; ///< Offset 0x39A Color Correction Default Values + UINT32 PCFT; ///< Offset 0x39E Power Conservation Features + UINT32 SROT; ///< Offset 0x3A2 Supported Rotation Angles + UINT32 IUER; ///< Offset 0x3A6 Intel Ultrabook(TM) Event Register + UINT64 FDSS; ///< Offset 0x3AA DSS Buffer address allocated for IFFS feature + UINT32 FDSP; ///< Offset 0x3B2 Size of DSS buffer + UINT32 STAT; ///< Offset 0x3B6 State Indicator + UINT64 RVDA; ///< Offset 0x3BA Absolute/Relative Address of Raw VBT Data from OpRegion Base + UINT32 RVDS; ///< Offset 0x3C2 Raw VBT Data Size + UINT8 RSVD3[0x3A]; ///< Offset 0x3C6 - 0x3FF Reserved Must be zero. Bug in spec 0x45(69) +} IGD_OPREGION_MBOX3; + +/// +/// OpRegion Mailbox 4 - VBT Video BIOS Table +/// Offset 0x400, Size 0x1800 +/// +typedef struct { + UINT8 RVBT[IGD_OPREGION_VBT_SIZE_6K]; ///< Offset 0x400 - 0x1BFF Raw VBT Data +} IGD_OPREGION_MBOX4; + +/// +/// OpRegion Mailbox 5 - BIOS/Driver Notification - Data storage BIOS to Driver data sync +/// Offset 0x1C00, Size 0x400 +/// +typedef struct { + UINT32 PHED; ///< Offset 0x1C00 Panel Header + UINT8 BDDC[0x100]; ///< Offset 0x1C04 Panel EDID (DDC data) + UINT8 RM51[0x2FC]; ///< Offset 0x1D04 - 0x1FFF Reserved Must be zero +} IGD_OPREGION_MBOX5; + +/// +/// IGD OpRegion Structure +/// +typedef struct { + IGD_OPREGION_HEADER Header; ///< OpRegion header (Offset 0x0, Size 0x100) + IGD_OPREGION_MBOX1 MBox1; ///< Mailbox 1: Public ACPI Methods (Offset 0x100, Size 0x100) + IGD_OPREGION_MBOX2 MBox2; ///< Mailbox 2: Software SCI Interface (Offset 0x200, Size 0x100) + IGD_OPREGION_MBOX3 MBox3; ///< Mailbox 3: BIOS to Driver Notification (Offset 0x300, Size 0x100) + IGD_OPREGION_MBOX4 MBox4; ///< Mailbox 4: Video BIOS Table (VBT) (Offset 0x400, Size 0x1800) + IGD_OPREGION_MBOX5 MBox5; ///< Mailbox 5: BIOS to Driver Notification Extension (Offset 0x1C00, Size 0x400) +} IGD_OPREGION_STRUCTURE; + +/// +/// VBT Header Structure +/// +typedef struct { + UINT8 Product_String[20]; + UINT16 Version; + UINT16 Header_Size; + UINT16 Table_Size; + UINT8 Checksum; + UINT8 Reserved1; + UINT32 Bios_Data_Offset; + UINT32 Aim_Data_Offset[4]; +} VBT_HEADER; + +typedef struct { + UINT8 BDB_Signature[16]; + UINT16 BDB_Version; + UINT16 BDB_Header_Size; + UINT16 BDB_Size; +} VBT_BIOS_DATA_HEADER; + +#pragma pack() + +#endif diff --git a/OvmfPkg/Include/Protocol/PlatformGopPolicy.h b/OvmfPkg/Include/Protocol/PlatformGopPolicy.h new file mode 100644 index 0000000000..9c3a9a07c8 --- /dev/null +++ b/OvmfPkg/Include/Protocol/PlatformGopPolicy.h @@ -0,0 +1,68 @@ +/*++ + +Copyright (c) 1999 - 2019, Intel Corporation. All rights reserved + + This program and the accompanying materials are licensed and made available under + the terms and conditions of the BSD License that accompanies this distribution. + The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +--*/ + +/** @file +**/ + +#ifndef _PLATFORM_GOP_POLICY_PROTOCOL_H_ +#define _PLATFORM_GOP_POLICY_PROTOCOL_H_ + +#define EFI_PLATFORM_GOP_POLICY_PROTOCOL_GUID \ + { 0xec2e931b, 0x3281, 0x48a5, 0x81, 0x7, 0xdf, 0x8a, 0x8b, 0xed, 0x3c, 0x5d } + +#define PLATFORM_GOP_POLICY_PROTOCOL_REVISION_01 0x01 +#define PLATFORM_GOP_POLICY_PROTOCOL_REVISION_02 x0222 + +#pragma pack(1) + +typedef enum { + LidClosed, + LidOpen, + LidStatusMax +} LID_STATUS; + +typedef enum { + Docked, + UnDocked, + DockStatusMax +} DOCK_STATUS; + +typedef +EFI_STATUS +(EFIAPI *GET_PLATFORM_LID_STATUS) ( + OUT LID_STATUS *CurrentLidStatus +); + +typedef +EFI_STATUS +(EFIAPI *GET_VBT_DATA) ( + OUT EFI_PHYSICAL_ADDRESS *VbtAddress, + OUT UINT32 *VbtSize +); + +#pragma pack() + +typedef struct _PLATFORM_GOP_POLICY_PROTOCOL { + UINT32 Revision; + GET_PLATFORM_LID_STATUS GetPlatformLidStatus; + GET_VBT_DATA GetVbtData; +} PLATFORM_GOP_POLICY_PROTOCOL; + +// +// Extern the GUID for protocol users. +// +extern EFI_GUID gPlatformGOPPolicyGuid; + +#endif diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec index 340d83f794..b4bc2355e8 100644 --- a/OvmfPkg/OvmfPkg.dec +++ b/OvmfPkg/OvmfPkg.dec @@ -148,6 +148,7 @@ gEfiLegacyInterruptProtocolGuid = {0x31ce593d, 0x108a, 0x485d, {0xad, 0xb2, 0x78, 0xf2, 0x1f, 0x29, 0x66, 0xbe}} gEfiVgaMiniPortProtocolGuid = {0xc7735a2f, 0x88f5, 0x4882, {0xae, 0x63, 0xfa, 0xac, 0x8c, 0x8b, 0x86, 0xb3}} gOvmfLoadedX86LinuxKernelProtocolGuid = {0xa3edc05d, 0xb618, 0x4ff6, {0x95, 0x52, 0x76, 0xd7, 0x88, 0x63, 0x43, 0xc8}} + gPlatformGOPPolicyGuid = {0xec2e931b, 0x3281, 0x48a5, {0x81, 0x07, 0xdf, 0x8a, 0x8b, 0xed, 0x3c, 0x5d}} [PcdsFixedAtBuild] gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase|0x0|UINT32|0 diff --git a/OvmfPkg/PlatformGopPolicy/PlatformGopPolicy.c b/OvmfPkg/PlatformGopPolicy/PlatformGopPolicy.c new file mode 100644 index 0000000000..ebff16b795 --- /dev/null +++ b/OvmfPkg/PlatformGopPolicy/PlatformGopPolicy.c @@ -0,0 +1,295 @@ +/** @file + Platform GOP Policy + + GOP drivers calls GetVbtData to get the Video BIOS Table of the Intel Graphics + Device. + + Copyright (C) 1999 - 2019, Intel Corporation. All rights reserved + Copyright (C) 2021, Beckhoff Automation GmbH & Co. KG. All rights reserved.
+ + This program and the accompanying materials are licensed and made available under + the terms and conditions of the BSD License that accompanies this distribution. + The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +**/ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +// +// IGD is always located at 0:2.0 +// +#define IGD_PCI_BUS 0 +#define IGD_PCI_SLOT 2 +#define IGD_PCI_FUNC 0 + +#define IGD_PCI_ASLS_OFFSET 0xFC + +#define IGD_PCI_VENDOR_ID 0x8086 + +PLATFORM_GOP_POLICY_PROTOCOL mPlatformGOPPolicy; +VBT_HEADER *mVbt; + +/** + The function returns the Platform Lid Status. IBV/OEM can customize this code + for their specific policy action. + + @param[out] CurrentLidStatus Current LID Status. + + @retval EFI_UNSUPPORTED Function isn't implemented yet. + +**/ +EFI_STATUS +EFIAPI +GetPlatformLidStatus ( + OUT LID_STATUS *CurrentLidStatus +) +{ + return EFI_UNSUPPORTED; +} + +/** + The function returns the Video Bios Table size and address. + + @param[out] VbtAddress Physical Address of Video BIOS Table + + @param[out] VbtSize Size of Video BIOS Table + + @retval EFI_STATUS Successfully returned Video BIOS Table address and + size. + +**/ + +EFI_STATUS +EFIAPI +GetVbtData ( + OUT EFI_PHYSICAL_ADDRESS *VbtAddress, + OUT UINT32 *VbtSize +) +{ + EFI_STATUS Status; + IGD_OPREGION_STRUCTURE *OpRegion; + VBT_HEADER *Vbt; + UINT8 CheckSum = 0; + UINT16 VersionMajor; + UINT16 VersionMinor; + UINT32 VbtSizeMax = 0; + UINT16 VendorId; + UINT32 ClassCode; + + // + // Check if vendor is Intel + // + VendorId = PciRead16 ( + PCI_LIB_ADDRESS ( + IGD_PCI_BUS, + IGD_PCI_SLOT, + IGD_PCI_FUNC, + PCI_VENDOR_ID_OFFSET + ) + ); + if (VendorId == 0xFFFF) { + return EFI_NOT_FOUND; + } else if (VendorId != IGD_PCI_VENDOR_ID) { + return EFI_UNSUPPORTED; + } + + // + // Check if class is display device + // + ClassCode = PciRead32 ( + PCI_LIB_ADDRESS ( + IGD_PCI_BUS, + IGD_PCI_SLOT, + IGD_PCI_FUNC, + PCI_CLASSCODE_OFFSET & ~0x3 + ) + ); + if (((ClassCode >> 24) & 0xFF) != PCI_CLASS_DISPLAY || + ((ClassCode >> 16) & 0xFF) != PCI_CLASS_DISPLAY_VGA || + ((ClassCode >> 8) & 0xFF) != PCI_IF_VGA_VGA) { + return EFI_UNSUPPORTED; + } + + // + // Get OpRegion. + // + OpRegion = (IGD_OPREGION_STRUCTURE *)(UINTN)PciRead32 ( + PCI_LIB_ADDRESS ( + 0, + 2, + 0, + IGD_PCI_ASLS_OFFSET + ) + ); + if (OpRegion == NULL) { + DEBUG ((EFI_D_ERROR, "%a: Failed to get OpRegion address\n", + __FUNCTION__)); + } + + // + // Check if Intel Graphics Device has an OpRegion. + // + if (!OpRegion) { + DEBUG ((EFI_D_ERROR, "%a: No OpRegion found\n", __FUNCTION__)); + return EFI_UNSUPPORTED; + } + + // + // Check OpRegion signature. + // + if (CompareMem (OpRegion->Header.SIGN, IGD_OPREGION_HEADER_SIGN, sizeof (OpRegion->Header.SIGN)) != 0) { + DEBUG ((EFI_D_ERROR, "%a: Invalid OpRegion signature (%a), expected %a\n", + __FUNCTION__, OpRegion->Header.SIGN, IGD_OPREGION_HEADER_SIGN)); + return EFI_INVALID_PARAMETER; + } + + VersionMajor = OpRegion->Header.OVER >> 24; + VersionMinor = OpRegion->Header.OVER >> 16 & 0xFF; + + // + // Only OpRegion v2.0 and higher is supported. + // + if (VersionMajor < 2) { + DEBUG ((EFI_D_ERROR, "%a: Unsupported OpRegion version %d.%d\n", __FUNCTION__, + VersionMajor, VersionMinor)); + return EFI_UNSUPPORTED; + } + + // + // If the size of the Video BIOS Table larger then 6K, the Video BIOS Table is + // stored outside the OpRegion. In that case, the address and size of the + // Video BIOS Table are stored in MailBox3 (RVDA and RVDS). When OpRegion v2.0 + // is used, RVDA is a physical address. In a virtual environment this physical + // address is invalid. For that reason, we do not support a Video BIOS Table + // which is larger than 6K for OpRegion v2.0. + // + if (VersionMajor == 2 && + VersionMinor == 0 && + OpRegion->MBox3.RVDA && + OpRegion->MBox3.RVDS) { + DEBUG ((EFI_D_ERROR, + "%a: VBT larger than 6K is unsupported for OpRegion v2.0\n", + __FUNCTION__)); + return EFI_UNSUPPORTED; + } + + // + // Get Video BIOS Table size. + // + VbtSizeMax = IGD_OPREGION_VBT_SIZE_6K; + if (OpRegion->MBox3.RVDA && OpRegion->MBox3.RVDS) { + Vbt = (VBT_HEADER *)((UINT8 *)OpRegion + OpRegion->MBox3.RVDA); + VbtSizeMax = *VbtSize; + } else { + Vbt = (VBT_HEADER *)&OpRegion->MBox4; + VbtSizeMax = IGD_OPREGION_VBT_SIZE_6K; + } + + // + // Free old Video BIOS Table. + // + if (mVbt) { + Status = gBS->FreePages ( + (EFI_PHYSICAL_ADDRESS)mVbt, + EFI_SIZE_TO_PAGES (VbtSizeMax) + ); + } + + // + // Allocate Video BIOS Table. + // + mVbt = (VBT_HEADER *)(SIZE_4GB - 1); + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiReservedMemoryType, + EFI_SIZE_TO_PAGES (VbtSizeMax), + (EFI_PHYSICAL_ADDRESS *)&mVbt + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, + "%a: AllocatePages failed for VBT size 0x%x status %d\n", __FUNCTION__, + VbtSizeMax, Status)); + return EFI_OUT_OF_RESOURCES; + } + + // + // Copy Video BIOS Table to allocated space. + // + ZeroMem ((VOID*)mVbt, VbtSizeMax); + CopyMem((VOID*)mVbt, (VOID*)Vbt, Vbt->Table_Size); + + // + // Fix checksum. + // + for (UINT32 i = 0; i < mVbt->Table_Size; i++) { + CheckSum = (CheckSum + ((UINT8*)mVbt)[i]) & 0xFF; + } + mVbt->Checksum += (0x100 - CheckSum); + + // + // Return Video BIOS Table address and size. + // + *VbtAddress = (EFI_PHYSICAL_ADDRESS)mVbt; + *VbtSize = mVbt->Table_Size; + DEBUG ((DEBUG_INFO, "%a: VBT Version %d size 0x%x\n", __FUNCTION__, + ((VBT_BIOS_DATA_HEADER*)((VOID *)mVbt + mVbt->Bios_Data_Offset))->BDB_Version, + mVbt->Table_Size)); + + return EFI_SUCCESS; +} + +/** + Entry point for the Platform GOP Policy Driver. + + @param[in] ImageHandle Image handle of this driver. + + @param[in] SystemTable Global system service table. + + @retval EFI_SUCCESS Initialization complete. + + @return Error codes propagated from underlying functions. +**/ + +EFI_STATUS +EFIAPI +PlatformGOPPolicyEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) + +{ + EFI_STATUS Status; + + gBS = SystemTable->BootServices; + + mPlatformGOPPolicy.Revision = PLATFORM_GOP_POLICY_PROTOCOL_REVISION_01; + mPlatformGOPPolicy.GetPlatformLidStatus = GetPlatformLidStatus; + mPlatformGOPPolicy.GetVbtData = GetVbtData; + + // + // Install protocol to allow access to this Policy. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gPlatformGOPPolicyGuid, + &mPlatformGOPPolicy, + NULL + ); + + return Status; +} diff --git a/OvmfPkg/PlatformGopPolicy/PlatformGopPolicy.inf b/OvmfPkg/PlatformGopPolicy/PlatformGopPolicy.inf new file mode 100644 index 0000000000..8bf6f60f8f --- /dev/null +++ b/OvmfPkg/PlatformGopPolicy/PlatformGopPolicy.inf @@ -0,0 +1,52 @@ +## @file +# Platform GOP Policy +# +# GOP drivers calls GetVbtData to get the Video BIOS Table of the Intel Graphics +# Device. +# +# Copyright (c) 1999 - 2019, Intel Corporation. All rights reserved +# Copyrigth (C) 2021, Beckhoff Automation GmbH & Co. KG. All rights reserved.
+# +# This program and the accompanying materials are licensed and made available under +# the terms and conditions of the BSD License that accompanies this distribution. +# The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PlatformGOPPolicy + FILE_GUID = 9737D7CA-D869-45e5-A5EF-75D9438688DE + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = PlatformGOPPolicyEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 +# + +[Sources.common] + PlatformGopPolicy.c + +[Packages] + MdePkg/MdePkg.dec + OvmfPkg/OvmfPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + PciLib + +[Protocols] + gPlatformGOPPolicyGuid + +[Depex] + TRUE