/** The constructor function enables ACPI IO space. If ACPI I/O space not enabled, this function will enable it. It will always return RETURN_SUCCESS. @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. **/ RETURN_STATUS EFIAPI AcpiTimerLibConstructor ( VOID ) { UINT8 u8Device = 7; UINT16 u16VendorID = 0; UINT16 u16DeviceID = 0; u16VendorID = PciRead16(PCI_LIB_ADDRESS(0, u8Device, 0, 0)); u16DeviceID = PciRead16(PCI_LIB_ADDRESS(0, u8Device, 0, 2)); if ( u16VendorID != 0x8086 || u16DeviceID != 0x7113) return RETURN_ABORTED; if (PciRead8 (PCI_LIB_ADDRESS (0,u8Device,0,0x80)) & 1) { mPmba = PciRead32 (PCI_LIB_ADDRESS (0, u8Device, 0, 0x40)); ASSERT (mPmba & PCI_BAR_IO); DEBUG((DEBUG_INFO, "%a:%d mPmba:%x\n", __FUNCTION__, __LINE__, mPmba)); mPmba &= ~PCI_BAR_IO; DEBUG((DEBUG_INFO, "%a:%d mPmba:%x\n", __FUNCTION__, __LINE__, mPmba)); } else { PciAndThenOr32 (PCI_LIB_ADDRESS (0,u8Device,0,0x40), (UINT32) ~0xfc0, mPmba); PciOr8 (PCI_LIB_ADDRESS (0,u8Device,0,0x04), 0x01); DEBUG((DEBUG_INFO, "%a:%d mPmba:%x\n", __FUNCTION__, __LINE__, mPmba)); } // // ACPI Timer enable is in Bus 0, Device ?, Function 3 // PciOr8 (PCI_LIB_ADDRESS (0,u8Device,0,0x80), 0x01); return RETURN_SUCCESS; }
/** The constructor function enables ACPI IO space. If ACPI I/O space not enabled, this function will enable it. It will always return RETURN_SUCCESS. @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. **/ RETURN_STATUS EFIAPI AcpiTimerLibConstructor ( VOID ) { UINTN Bus; UINTN Device; UINTN Function; UINTN EnableRegister; UINT8 EnableMask; // // ASSERT for the invalid PCD values. They must be configured to the real value. // ASSERT (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) != 0xFFFF); ASSERT (PcdGet16 (PcdAcpiIoPortBaseAddress) != 0xFFFF); // // If the register offset to the BAR for the ACPI I/O Port Base Address is 0x0000, then // no PCI register programming is required to enable access to the the ACPI registers // specified by PcdAcpiIoPortBaseAddress // if (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) == 0x0000) { return RETURN_SUCCESS; } // // ASSERT for the invalid PCD values. They must be configured to the real value. // ASSERT (PcdGet8 (PcdAcpiIoPciDeviceNumber) != 0xFF); ASSERT (PcdGet8 (PcdAcpiIoPciFunctionNumber) != 0xFF); ASSERT (PcdGet16 (PcdAcpiIoPciEnableRegisterOffset) != 0xFFFF); // // Retrieve the PCD values for the PCI configuration space required to program the ACPI I/O Port Base Address // Bus = PcdGet8 (PcdAcpiIoPciBusNumber); Device = PcdGet8 (PcdAcpiIoPciDeviceNumber); Function = PcdGet8 (PcdAcpiIoPciFunctionNumber); EnableRegister = PcdGet16 (PcdAcpiIoPciEnableRegisterOffset); EnableMask = PcdGet8 (PcdAcpiIoBarEnableMask); // // If ACPI I/O space is not enabled yet, program ACPI I/O base address and enable it. // if ((PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, EnableRegister) & EnableMask) != EnableMask)) { PciWrite16 ( PCI_LIB_ADDRESS (Bus, Device, Function, PcdGet16 (PcdAcpiIoPciBarRegisterOffset)), PcdGet16 (PcdAcpiIoPortBaseAddress) ); PciOr8 ( PCI_LIB_ADDRESS (Bus, Device, Function, EnableRegister), EnableMask ); } return RETURN_SUCCESS; }
VOID MiscInitialization ( VOID ) { // // Disable A20 Mask // IoOr8 (0x92, BIT1); // // Build the CPU hob with 36-bit addressing and 16-bits of IO space. // BuildCpuHob (36, 16); // // If PMREGMISC/PMIOSE is set, assume the ACPI PMBA has been configured (for // example by Xen) and skip the setup here. This matches the logic in // AcpiTimerLibConstructor (). // if ((PciRead8 (PCI_LIB_ADDRESS (0, 1, 3, 0x80)) & 0x01) == 0) { // // The PEI phase should be exited with fully accessibe PIIX4 IO space: // 1. set PMBA // PciAndThenOr32 ( PCI_LIB_ADDRESS (0, 1, 3, 0x40), (UINT32) ~0xFFC0, PcdGet16 (PcdAcpiPmBaseAddress) ); // // 2. set PCICMD/IOSE // PciOr8 ( PCI_LIB_ADDRESS (0, 1, 3, PCI_COMMAND_OFFSET), EFI_PCI_COMMAND_IO_SPACE ); // // 3. set PMREGMISC/PMIOSE // PciOr8 (PCI_LIB_ADDRESS (0, 1, 3, 0x80), 0x01); } }
/** Performs a bitwise OR of an 8-bit PCI configuration register with an 8-bit value and saves the value in the S3 script to be replayed on S3 resume. Reads the 8-bit PCI configuration register specified by Address, performs a bitwise OR between the read result and the value specified by OrData, and writes the result to the 8-bit PCI configuration register specified by Address. The value written to the PCI configuration register is returned. This function must guarantee that all PCI read and write operations are serialized. If Address > 0x0FFFFFFF, then ASSERT(). @param Address Address that encodes the PCI Bus, Device, Function and Register. @param OrData The value to OR with the PCI configuration register. @return The value written back to the PCI configuration register. **/ UINT8 EFIAPI S3PciOr8 ( IN UINTN Address, IN UINT8 OrData ) { return InternalSavePciWrite8ValueToBootScript (Address, PciOr8 (Address, OrData)); }
EFI_STATUS EFIAPI PostPmInitCallBack ( IN EFI_EVENT Event, IN VOID *Context ) { UINT64 OriginalGTTMMADR; UINT32 LoGTBaseAddress; UINT32 HiGTBaseAddress; // // Enable Bus Master, I/O and Memory access on 0:2:0 // PciOr8 (PCI_LIB_ADDRESS(0, IGD_DEV, 0,IGD_R_CMD), (BIT2 | BIT1)); // // only 32bit read/write is legal for device 0:2:0 // OriginalGTTMMADR = (UINT64) PciRead32 (PCI_LIB_ADDRESS(0, IGD_DEV, 0,IGD_R_GTTMMADR)); OriginalGTTMMADR = LShiftU64 ((UINT64) PciRead32 (PCI_LIB_ADDRESS(0, IGD_DEV, 0,IGD_R_GTTMMADR + 4)), 32) | (OriginalGTTMMADR); // // 64bit GTTMADR does not work for S3 save script table since it is executed in PEIM phase // Program temporarily 32bits GTTMMADR for POST and S3 resume // LoGTBaseAddress = (UINT32) (GTTMMADR & 0xFFFFFFFF); HiGTBaseAddress = (UINT32) RShiftU64 ((GTTMMADR & 0xFFFFFFFF00000000), 32); S3PciWrite32(PCI_LIB_ADDRESS(0, IGD_DEV, 0,IGD_R_GTTMMADR), LoGTBaseAddress); S3PciWrite32(PCI_LIB_ADDRESS(0, IGD_DEV, 0,IGD_R_GTTMMADR+4), HiGTBaseAddress); // // Restore original GTTMMADR // LoGTBaseAddress = (UINT32) (OriginalGTTMMADR & 0xFFFFFFFF); HiGTBaseAddress = (UINT32) RShiftU64 ((OriginalGTTMMADR & 0xFFFFFFFF00000000), 32); S3PciWrite32(PCI_LIB_ADDRESS(0, IGD_DEV, 0,IGD_R_GTTMMADR), LoGTBaseAddress); S3PciWrite32(PCI_LIB_ADDRESS(0, IGD_DEV, 0,IGD_R_GTTMMADR+4), HiGTBaseAddress); // // Lock the following registers, GGC, BDSM, BGSM // PciOr32 (PCI_LIB_ADDRESS(0, IGD_DEV, 0,IGD_MGGC_OFFSET), LockBit); PciOr32 (PCI_LIB_ADDRESS(0, IGD_DEV, 0,IGD_BSM_OFFSET), LockBit); PciOr32 (PCI_LIB_ADDRESS(0, IGD_DEV, 0,IGD_R_BGSM), LockBit); gBS->CloseEvent (Event); // // Return final status // return EFI_SUCCESS; }
/** The constructor function enables ACPI IO space. If ACPI I/O space not enabled, this function will enable it. It will always return RETURN_SUCCESS. @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. **/ RETURN_STATUS EFIAPI AcpiTimerLibConstructor ( VOID ) { UINT16 HostBridgeDevId; UINTN Pmba; UINTN AcpiCtlReg; UINT8 AcpiEnBit; // // Query Host Bridge DID to determine platform type // HostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID); switch (HostBridgeDevId) { case INTEL_82441_DEVICE_ID: Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA); AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC); AcpiEnBit = PIIX4_PMREGMISC_PMIOSE; break; case INTEL_Q35_MCH_DEVICE_ID: Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE); AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL); AcpiEnBit = ICH9_ACPI_CNTL_ACPI_EN; break; default: DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n", __FUNCTION__, HostBridgeDevId)); ASSERT (FALSE); return RETURN_UNSUPPORTED; } // // Check to see if the Power Management Base Address is already enabled // if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) { // // If the Power Management Base Address is not programmed, // then program the Power Management Base Address from a PCD. // PciAndThenOr32 (Pmba, (UINT32) ~0xFFC0, PcdGet16 (PcdAcpiPmBaseAddress)); // // Enable PMBA I/O port decodes // PciOr8 (AcpiCtlReg, AcpiEnBit); } return RETURN_SUCCESS; }
/** The constructor function caches the ACPI tick counter address, and, if necessary, enables ACPI IO space. @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. **/ RETURN_STATUS EFIAPI AcpiTimerLibConstructor ( VOID ) { UINT16 HostBridgeDevId; UINTN Pmba; UINTN PmRegMisc; // // Query Host Bridge DID to determine platform type // HostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID); switch (HostBridgeDevId) { case INTEL_82441_DEVICE_ID: Pmba = POWER_MGMT_REGISTER_PIIX4 (0x40); PmRegMisc = POWER_MGMT_REGISTER_PIIX4 (0x80); break; case INTEL_Q35_MCH_DEVICE_ID: Pmba = POWER_MGMT_REGISTER_Q35 (0x40); PmRegMisc = POWER_MGMT_REGISTER_Q35 (0x80); break; default: DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n", __FUNCTION__, HostBridgeDevId)); ASSERT (FALSE); return RETURN_UNSUPPORTED; } mAcpiTimerIoAddr = (PciRead32 (Pmba) & ~PMBA_RTE) + ACPI_TIMER_OFFSET; // // Check to see if the Power Management Base Address is already enabled // if ((PciRead8 (PmRegMisc) & PMIOSE) == 0) { // // If the Power Management Base Address is not programmed, // then program the Power Management Base Address from a PCD. // PciAndThenOr32 (Pmba, (UINT32) ~0xFFC0, PcdGet16 (PcdAcpiPmBaseAddress)); // // Enable PMBA I/O port decodes in PMREGMISC // PciOr8 (PmRegMisc, PMIOSE); } return RETURN_SUCCESS; }
/** The constructor function enables ACPI IO space. If ACPI I/O space not enabled, this function will enable it. It will always return RETURN_SUCCESS. @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. **/ RETURN_STATUS EFIAPI AcpiTimerLibConstructor ( VOID ) { // // Check to see if the PIIX4 Power Management Base Address is already enabled // if ((PciRead8 (PMREGMISC) & PMIOSE) == 0) { // // If the PIIX4 Power Management Base Address is not programmed, // then program the PIIX4 Power Management Base Address from a PCD. // PciAndThenOr32 (PMBA, (UINT32)(~0x0000FFC0), PcdGet16 (PcdAcpiPmBaseAddress)); // // Enable PMBA I/O port decodes in PMREGMISC // PciOr8 (PMREGMISC, PMIOSE); } return RETURN_SUCCESS; }
VOID MiscInitialization ( VOID ) { UINTN PmCmd; UINTN Pmba; UINTN AcpiCtlReg; UINT8 AcpiEnBit; // // Disable A20 Mask // IoOr8 (0x92, BIT1); // // Build the CPU HOB with guest RAM size dependent address width and 16-bits // of IO space. (Side note: unlike other HOBs, the CPU HOB is needed during // S3 resume as well, so we build it unconditionally.) // BuildCpuHob (mPhysMemAddressWidth, 16); // // Determine platform type and save Host Bridge DID to PCD // switch (mHostBridgeDevId) { case INTEL_82441_DEVICE_ID: PmCmd = POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET); Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA); AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC); AcpiEnBit = PIIX4_PMREGMISC_PMIOSE; break; case INTEL_Q35_MCH_DEVICE_ID: PmCmd = POWER_MGMT_REGISTER_Q35 (PCI_COMMAND_OFFSET); Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE); AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL); AcpiEnBit = ICH9_ACPI_CNTL_ACPI_EN; break; default: DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n", __FUNCTION__, mHostBridgeDevId)); ASSERT (FALSE); return; } PcdSet16 (PcdOvmfHostBridgePciDevId, mHostBridgeDevId); // // If the appropriate IOspace enable bit is set, assume the ACPI PMBA // has been configured (e.g., by Xen) and skip the setup here. // This matches the logic in AcpiTimerLibConstructor (). // if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) { // // The PEI phase should be exited with fully accessibe ACPI PM IO space: // 1. set PMBA // PciAndThenOr32 (Pmba, (UINT32) ~0xFFC0, PcdGet16 (PcdAcpiPmBaseAddress)); // // 2. set PCICMD/IOSE // PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE); // // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN) // PciOr8 (AcpiCtlReg, AcpiEnBit); } if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) { // // Set Root Complex Register Block BAR // PciWrite32 ( POWER_MGMT_REGISTER_Q35 (ICH9_RCBA), ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN ); // // Set PCI Express Register Range Base Address // PciExBarInitialization (); } }
/** The constructor function caches the ACPI tick counter address, and, if necessary, enables ACPI IO space. @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. **/ RETURN_STATUS EFIAPI AcpiTimerLibConstructor ( VOID ) { UINT16 HostBridgeDevId; UINTN Pmba; UINT32 PmbaAndVal; UINT32 PmbaOrVal; UINTN AcpiCtlReg; UINT8 AcpiEnBit; // // Query Host Bridge DID to determine platform type // HostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID); switch (HostBridgeDevId) { case INTEL_82441_DEVICE_ID: #ifdef VBOX // HACK ALERT! There is no host bridge device in the PCIe chipset, and the same PIIX4 PM device is used. // But there might be some other device at 0:0.0. default: #endif Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA); PmbaAndVal = ~(UINT32)PIIX4_PMBA_MASK; PmbaOrVal = PIIX4_PMBA_VALUE; AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC); AcpiEnBit = PIIX4_PMREGMISC_PMIOSE; break; case INTEL_Q35_MCH_DEVICE_ID: Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE); PmbaAndVal = ~(UINT32)ICH9_PMBASE_MASK; PmbaOrVal = ICH9_PMBASE_VALUE; AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL); AcpiEnBit = ICH9_ACPI_CNTL_ACPI_EN; break; #ifndef VBOX default: DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n", __FUNCTION__, HostBridgeDevId)); ASSERT (FALSE); return RETURN_UNSUPPORTED; #endif } // // Check to see if the Power Management Base Address is already enabled // if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) { // // If the Power Management Base Address is not programmed, // then program it now. // PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal); // // Enable PMBA I/O port decodes // PciOr8 (AcpiCtlReg, AcpiEnBit); } mAcpiTimerIoAddr = (PciRead32 (Pmba) & ~PMBA_RTE) + ACPI_TIMER_OFFSET; return RETURN_SUCCESS; }
EFI_STATUS IgdPmHook ( IN EFI_HANDLE ImageHandle, IN DXE_VLV_PLATFORM_POLICY_PROTOCOL *DxePlatformSaPolicy ) { EFI_EVENT mConOutEvent; VOID *gConOutNotifyReg; EFI_STATUS Status; EFI_PHYSICAL_ADDRESS MemBaseAddress; UINT32 LoGTBaseAddress; UINT32 HiGTBaseAddress; GTTMMADR = 0; Status = EFI_SUCCESS; // // If device 0:2:0 (Internal Graphics Device, or GT) is enabled, then Program GTTMMADR, // if (PciRead16(PCI_LIB_ADDRESS(0, IGD_DEV, 0, IGD_R_VID)) != 0xFFFF) { ASSERT (gDS!=NULL); // // Enable Bus Master, I/O and Memory access on 0:2:0 // PciOr8(PCI_LIB_ADDRESS(0, IGD_DEV, 0, IGD_R_CMD), (BIT2 | BIT1 | BIT0)); // // Means Allocate 4MB for GTTMADDR // MemBaseAddress = 0x0ffffffff; Status = gDS->AllocateMemorySpace ( EfiGcdAllocateMaxAddressSearchBottomUp, EfiGcdMemoryTypeMemoryMappedIo, GTT_MEM_ALIGN, GTTMMADR_SIZE_4MB, &MemBaseAddress, ImageHandle, NULL ); ASSERT_EFI_ERROR (Status); // // Program GT PM Settings if GTTMMADR allocation is Successful // GTTMMADR = (UINTN) MemBaseAddress; LoGTBaseAddress = (UINT32) (MemBaseAddress & 0xFFFFFFFF); HiGTBaseAddress = (UINT32) RShiftU64 ((MemBaseAddress & 0xFFFFFFFF00000000), 32); PciWrite32 (PCI_LIB_ADDRESS(0, IGD_DEV, 0, IGD_R_GTTMMADR), LoGTBaseAddress); PciWrite32 (PCI_LIB_ADDRESS(0, IGD_DEV, 0, IGD_R_GTTMMADR+4), HiGTBaseAddress); S3PciRead32(PCI_LIB_ADDRESS(0, IGD_DEV, 0, IGD_R_GTTMMADR)); S3MmioRead32(IGD_R_GTTMMADR + 4); S3PciRead8(PCI_LIB_ADDRESS(0, IGD_DEV, 0, IGD_R_CMD)); // // Do POST GT PM Init Steps after VBIOS Initialization in DoPostPmInitCallBack // Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_CALLBACK, (EFI_EVENT_NOTIFY)PostPmInitCallBack, NULL, &mConOutEvent ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { return Status; } Status = gBS->RegisterProtocolNotify ( &gEfiGraphicsOutputProtocolGuid, mConOutEvent, &gConOutNotifyReg ); MmioWrite64 (IGD_R_GTTMMADR, 0); // // Free allocated resources // gDS->FreeMemorySpace ( MemBaseAddress, GTTMMADR_SIZE_4MB ); } return EFI_SUCCESS; }