/** This function scan PCI bus. @param VtdIndex VTd engine index @param Bus Pci bus @retval EFI_SUCCESS scan PCI bus successfully. **/ EFI_STATUS ScanPciBus ( IN UINTN VtdIndex, IN UINT8 Bus ) { UINT8 Device; UINT8 Function; UINT8 SecondaryBusNumber; UINT8 HeaderType; UINT8 BaseClass; UINT8 SubClass; UINT32 MaxFunction; UINT16 VendorID; UINT16 DeviceID; EFI_STATUS Status; // Scan the PCI bus for devices for (Device = 0; Device < PCI_MAX_DEVICE + 1; Device++) { HeaderType = PciRead8 (PCI_LIB_ADDRESS(Bus, Device, 0, PCI_HEADER_TYPE_OFFSET)); MaxFunction = PCI_MAX_FUNC + 1; if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00) { MaxFunction = 1; } for (Function = 0; Function < MaxFunction; Function++) { VendorID = PciRead16 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_VENDOR_ID_OFFSET)); DeviceID = PciRead16 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_DEVICE_ID_OFFSET)); if (VendorID == 0xFFFF && DeviceID == 0xFFFF) { continue; } Status = RegisterPciDevice (VtdIndex, Bus, Device, Function, FALSE); if (EFI_ERROR (Status)) { return Status; } BaseClass = PciRead8 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2)); if (BaseClass == PCI_CLASS_BRIDGE) { SubClass = PciRead8 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1)); if (SubClass == PCI_CLASS_BRIDGE_P2P) { SecondaryBusNumber = PciRead8 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET)); DEBUG ((EFI_D_INFO," ScanPciBus: PCI bridge B%02x D%02x F%02x (SecondBus:%02x)\n", Bus, Device, Function, SecondaryBusNumber)); if (SecondaryBusNumber != 0) { ScanPciBus (VtdIndex, SecondaryBusNumber); } } } } } 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 ) { 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; }
ACPI_STATUS AcpiOsReadPciConfiguration ( ACPI_PCI_ID *PciId, UINT32 Register, UINT64 *Value, UINT32 Width) { UINT32 devfn = ((PciId->Device & 0x1f)<<3)|(PciId->Function & 0x07); switch (Width) { case 8: *(UINT8 *)Value = PciRead8(PciId->Bus,devfn,Register); break; case 16: *(UINT16 *)Value = PciRead16(PciId->Bus,devfn,Register); break; case 32: *(UINT32 *)Value = PciRead32(PciId->Bus,devfn,Register); break; default: dbgprintf("AcpiOsReadPciConfiguration unhandled value width: %u\n", Width); return AE_ERROR; } return (AE_OK); }
VOID GetQncName ( VOID ) { DEBUG ((EFI_D_INFO, "QNC Name: ")); switch (PciRead16 (PCI_LIB_ADDRESS (MC_BUS, MC_DEV, MC_FUN, PCI_DEVICE_ID_OFFSET))) { case QUARK_MC_DEVICE_ID: DEBUG ((EFI_D_INFO, "Quark")); break; case QUARK2_MC_DEVICE_ID: DEBUG ((EFI_D_INFO, "Quark2")); break; default: DEBUG ((EFI_D_INFO, "Unknown")); } // // Revision // switch (PciRead8 (PCI_LIB_ADDRESS (MC_BUS, MC_DEV, MC_FUN, PCI_REVISION_ID_OFFSET))) { case QNC_MC_REV_ID_A0: DEBUG ((EFI_D_INFO, " - A0 stepping\n")); break; default: DEBUG ((EFI_D_INFO, " - xx\n")); } return; }
/** 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; }
/** Reads an 8-bit PCI configuration register and saves the value in the S3 script to be replayed on S3 resume. Reads and returns the 8-bit PCI configuration register specified by Address. 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. @return The read value from the PCI configuration register. **/ UINT8 EFIAPI S3PciRead8 ( IN UINTN Address ) { return InternalSavePciWrite8ValueToBootScript (Address, PciRead8 (Address)); }
/** Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value. Reads the 8-bit PCI configuration register specified by Address, performs a bitwise AND between the read result and the value specified by AndData, 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 The address that encodes the PCI Bus, Device, Function and Register. @param AndData The value to AND with the PCI configuration register. @return The value written back to the PCI configuration register. **/ UINT8 EFIAPI PciAnd8 ( IN UINTN Address, IN UINT8 AndData ) { return PciWrite8 (Address, (UINT8) (PciRead8 (Address) & AndData)); }
/* Helpers */ uint32_t PciDeviceRead(PciDevice_t *Device, uint32_t Register, uint32_t Length) { if (Length == 1) return (uint32_t)PciRead8(Device->PciBus, Device->Bus, Device->Device, Device->Function, Register); else if (Length == 2) return (uint32_t)PciRead16(Device->PciBus, Device->Bus, Device->Device, Device->Function, Register); else return PciRead32(Device->PciBus, Device->Bus, Device->Device, Device->Function, Register); }
/** Performs a bitwise OR of an 8-bit PCI configuration register with an 8-bit value. 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 The 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 PciOr8 ( IN UINTN Address, IN UINT8 OrData ) { return PciWrite8 (Address, (UINT8) (PciRead8 (Address) | OrData)); }
/** Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value, followed a bitwise OR with another 8-bit value. Reads the 8-bit PCI configuration register specified by Address, performs a bitwise AND between the read result and the value specified by AndData, performs a bitwise OR between the result of the AND operation 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 The address that encodes the PCI Bus, Device, Function and Register. @param AndData The value to AND with the PCI configuration register. @param OrData The value to OR with the result of the AND operation. @return The value written back to the PCI configuration register. **/ UINT8 EFIAPI PciAndThenOr8 ( IN UINTN Address, IN UINT8 AndData, IN UINT8 OrData ) { return PciWrite8 (Address, (UINT8) ((PciRead8 (Address) & AndData) | OrData)); }
/** Reads a bit field of a PCI configuration register. Reads the bit field in an 8-bit PCI configuration register. The bit field is specified by the StartBit and the EndBit. The value of the bit field is returned. If Address > 0x0FFFFFFF, then ASSERT(). If StartBit is greater than 7, then ASSERT(). If EndBit is greater than 7, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). @param Address The PCI configuration register to read. @param StartBit The ordinal of the least significant bit in the bit field. Range 0..7. @param EndBit The ordinal of the most significant bit in the bit field. Range 0..7. @return The value of the bit field read from the PCI configuration register. **/ UINT8 EFIAPI PciBitFieldRead8 ( IN UINTN Address, IN UINTN StartBit, IN UINTN EndBit ) { return BitFieldRead8 (PciRead8 (Address), StartBit, EndBit); }
/** Reads an 8-bit PCI configuration register. Reads and returns the 8-bit PCI configuration register specified by Address. This function must guarantee that all PCI read and write operations are serialized. If any reserved bits in Address are set, then ASSERT(). @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register. @return The 8-bit PCI configuration register specified by Address. **/ UINT8 EFIAPI PciSegmentRead8 ( IN UINT64 Address ) { ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0); return PciRead8 (PCI_SEGMENT_TO_PCI_ADDRESS (Address)); }
/** Reads from a given location in the PCI configuration space. @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation. @param This Pointer to local data for the interface. @param Width The width of the access. Enumerated in bytes. See EFI_PEI_PCI_CFG_PPI_WIDTH above. @param Address The physical address of the access. The format of the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS. @param Buffer A pointer to the buffer of data. @retval EFI_SUCCESS The function completed successfully. @retval EFI_INVALID_PARAMETER The invalid access width. **/ EFI_STATUS EFIAPI PciCfg2Read ( IN CONST EFI_PEI_SERVICES **PeiServices, IN CONST EFI_PEI_PCI_CFG2_PPI *This, IN EFI_PEI_PCI_CFG_PPI_WIDTH Width, IN UINT64 Address, IN OUT VOID *Buffer ) { UINTN PciLibAddress; PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *) &Address); if (Width == EfiPeiPciCfgWidthUint8) { *((UINT8 *) Buffer) = PciRead8 (PciLibAddress); } else if (Width == EfiPeiPciCfgWidthUint16) { if ((PciLibAddress & 0x01) == 0) { // // Aligned Pci address access // WriteUnaligned16 (((UINT16 *) Buffer), PciRead16 (PciLibAddress)); } else { // // Unaligned Pci address access, break up the request into byte by byte. // *((UINT8 *) Buffer) = PciRead8 (PciLibAddress); *((UINT8 *) Buffer + 1) = PciRead8 (PciLibAddress + 1); } } else if (Width == EfiPeiPciCfgWidthUint32) { if ((PciLibAddress & 0x03) == 0) { // // Aligned Pci address access // WriteUnaligned32 (((UINT32 *) Buffer), PciRead32 (PciLibAddress)); } else if ((PciLibAddress & 0x01) == 0) { // // Unaligned Pci address access, break up the request into word by word. // WriteUnaligned16 (((UINT16 *) Buffer), PciRead16 (PciLibAddress)); WriteUnaligned16 (((UINT16 *) Buffer + 1), PciRead16 (PciLibAddress + 2)); } else { // // Unaligned Pci address access, break up the request into byte by byte. // *((UINT8 *) Buffer) = PciRead8 (PciLibAddress); *((UINT8 *) Buffer + 1) = PciRead8 (PciLibAddress + 1); *((UINT8 *) Buffer + 2) = PciRead8 (PciLibAddress + 2); *((UINT8 *) Buffer + 3) = PciRead8 (PciLibAddress + 3); } } else { return EFI_INVALID_PARAMETER; } return EFI_SUCCESS; }
/* PciDeviceRead * Reads a value of the given length from the given register * and this function takes care of the rest */ uint32_t PciDeviceRead(PciDevice_t *Device, size_t Register, size_t Length) { if (Length == 1) { return (uint32_t)PciRead8(Device->BusIo, Device->Bus, Device->Slot, Device->Function, Register); } else if (Length == 2) { return (uint32_t)PciRead16(Device->BusIo, Device->Bus, Device->Slot, Device->Function, Register); } else { return PciRead32(Device->BusIo, Device->Bus, Device->Slot, Device->Function, Register); } }
/** 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; }
/** Writes a bit field to a PCI configuration register. Writes Value to the bit field of the PCI configuration register. The bit field is specified by the StartBit and the EndBit. All other bits in the destination PCI configuration register are preserved. The new value of the 8-bit register is returned. If Address > 0x0FFFFFFF, then ASSERT(). If StartBit is greater than 7, then ASSERT(). If EndBit is greater than 7, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Address The PCI configuration register to write. @param StartBit The ordinal of the least significant bit in the bit field. Range 0..7. @param EndBit The ordinal of the most significant bit in the bit field. Range 0..7. @param Value The new value of the bit field. @return The value written back to the PCI configuration register. **/ UINT8 EFIAPI PciBitFieldWrite8 ( IN UINTN Address, IN UINTN StartBit, IN UINTN EndBit, IN UINT8 Value ) { return PciWrite8 ( Address, BitFieldWrite8 (PciRead8 (Address), StartBit, EndBit, Value) ); }
/** Reads a bit field in an 8-bit PCI configuration register, performs a bitwise AND, and writes the result back to the bit field in the 8-bit register. Reads the 8-bit PCI configuration register specified by Address, performs a bitwise AND between the read result and the value specified by AndData, 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. Extra left bits in AndData are stripped. If Address > 0x0FFFFFFF, then ASSERT(). If StartBit is greater than 7, then ASSERT(). If EndBit is greater than 7, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Address The PCI configuration register to write. @param StartBit The ordinal of the least significant bit in the bit field. Range 0..7. @param EndBit The ordinal of the most significant bit in the bit field. Range 0..7. @param AndData The value to AND with the PCI configuration register. @return The value written back to the PCI configuration register. **/ UINT8 EFIAPI PciBitFieldAnd8 ( IN UINTN Address, IN UINTN StartBit, IN UINTN EndBit, IN UINT8 AndData ) { return PciWrite8 ( Address, BitFieldAnd8 (PciRead8 (Address), StartBit, EndBit, AndData) ); }
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); } }
/** 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; }
/** Extract device info from the input device path. @param[in] DevicePath Device path info for the device. @param[in,out] Dev The device which new inputed. **/ VOID ExtractDeviceInfoFromDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN OUT OPAL_SMM_DEVICE *Dev ) { EFI_DEVICE_PATH_PROTOCOL *TmpDevPath; EFI_DEVICE_PATH_PROTOCOL *TmpDevPath2; PCI_DEVICE_PATH *PciDevPath; SATA_DEVICE_PATH *SataDevPath; NVME_NAMESPACE_DEVICE_PATH *NvmeDevPath; UINTN BusNum; TmpDevPath = DevicePath; Dev->DeviceType = OPAL_DEVICE_TYPE_UNKNOWN; while (!IsDevicePathEnd(TmpDevPath)) { if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_SATA_DP) { // // SATA // SataDevPath = ( SATA_DEVICE_PATH* )TmpDevPath; Dev->SataPort = SataDevPath->HBAPortNumber; Dev->SataPortMultiplierPort = SataDevPath->PortMultiplierPortNumber; Dev->DeviceType = OPAL_DEVICE_TYPE_SATA; break; } else if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_NVME_NAMESPACE_DP) { // // NVMe // NvmeDevPath = ( NVME_NAMESPACE_DEVICE_PATH* )TmpDevPath; Dev->NvmeNamespaceId = NvmeDevPath->NamespaceId; Dev->DeviceType = OPAL_DEVICE_TYPE_NVME; break; } TmpDevPath = NextDevicePathNode (TmpDevPath); } // // Get bridge node info for the nvme device. // BusNum = 0; TmpDevPath = DevicePath; TmpDevPath2 = NextDevicePathNode (DevicePath); while (!IsDevicePathEnd(TmpDevPath2)) { if (TmpDevPath->Type == HARDWARE_DEVICE_PATH && TmpDevPath->SubType == HW_PCI_DP) { PciDevPath = (PCI_DEVICE_PATH *) TmpDevPath; if ((TmpDevPath2->Type == MESSAGING_DEVICE_PATH && TmpDevPath2->SubType == MSG_NVME_NAMESPACE_DP)|| (TmpDevPath2->Type == MESSAGING_DEVICE_PATH && TmpDevPath2->SubType == MSG_SATA_DP)) { Dev->BusNum = (UINT32)BusNum; Dev->DevNum = PciDevPath->Device; Dev->FuncNum = PciDevPath->Function; } else { AddPciDeviceNode((UINT32)BusNum, PciDevPath->Device, PciDevPath->Function, Dev); if (TmpDevPath2->Type == HARDWARE_DEVICE_PATH && TmpDevPath2->SubType == HW_PCI_DP) { BusNum = PciRead8 (PCI_LIB_ADDRESS (BusNum, PciDevPath->Device, PciDevPath->Function, NVME_PCIE_SEC_BNUM)); } } } TmpDevPath = NextDevicePathNode (TmpDevPath); TmpDevPath2 = NextDevicePathNode (TmpDevPath2); } }
/** Install the VBE Info and VBE Mode Info structures, and the VBE service handler routine in the C segment. Point the real-mode Int10h interrupt vector to the handler. The only advertised mode is 1024x768x32. @param[in] CardName Name of the video card to be exposed in the Product Name field of the VBE Info structure. The parameter must originate from a QEMU_VIDEO_CARD.Name field. @param[in] FrameBufferBase Guest-physical base address of the video card's frame buffer. **/ VOID InstallVbeShim ( IN CONST CHAR16 *CardName, IN EFI_PHYSICAL_ADDRESS FrameBufferBase ) { EFI_PHYSICAL_ADDRESS Segment0, SegmentC, SegmentF; UINTN Segment0Pages; IVT_ENTRY *Int0x10; EFI_STATUS Status; UINTN Pam1Address; UINT8 Pam1; UINTN SegmentCPages; VBE_INFO *VbeInfoFull; VBE_INFO_BASE *VbeInfo; UINT8 *Ptr; UINTN Printed; VBE_MODE_INFO *VbeModeInfo; Segment0 = 0x00000; SegmentC = 0xC0000; SegmentF = 0xF0000; // // Attempt to cover the real mode IVT with an allocation. This is a UEFI // driver, hence the arch protocols have been installed previously. Among // those, the CPU arch protocol has configured the IDT, so we can overwrite // the IVT used in real mode. // // The allocation request may fail, eg. if LegacyBiosDxe has already run. // Segment0Pages = 1; Int0x10 = (IVT_ENTRY *)(UINTN)Segment0 + 0x10; Status = gBS->AllocatePages (AllocateAddress, EfiBootServicesCode, Segment0Pages, &Segment0); if (EFI_ERROR (Status)) { EFI_PHYSICAL_ADDRESS Handler; // // Check if a video BIOS handler has been installed previously -- we // shouldn't override a real video BIOS with our shim, nor our own shim if // it's already present. // Handler = (Int0x10->Segment << 4) + Int0x10->Offset; if (Handler >= SegmentC && Handler < SegmentF) { DEBUG ((EFI_D_VERBOSE, "%a: Video BIOS handler found at %04x:%04x\n", __FUNCTION__, Int0x10->Segment, Int0x10->Offset)); return; } // // Otherwise we'll overwrite the Int10h vector, even though we may not own // the page at zero. // DEBUG ((EFI_D_VERBOSE, "%a: failed to allocate page at zero: %r\n", __FUNCTION__, Status)); } else { // // We managed to allocate the page at zero. SVN r14218 guarantees that it // is NUL-filled. // ASSERT (Int0x10->Segment == 0x0000); ASSERT (Int0x10->Offset == 0x0000); } // // Put the shim in place first. // Pam1Address = PCI_LIB_ADDRESS (0, 0, 0, 0x5A); // // low nibble covers 0xC0000 to 0xC3FFF // high nibble covers 0xC4000 to 0xC7FFF // bit1 in each nibble is Write Enable // bit0 in each nibble is Read Enable // Pam1 = PciRead8 (Pam1Address); PciWrite8 (Pam1Address, Pam1 | (BIT1 | BIT0)); // // We never added memory space durig PEI or DXE for the C segment, so we // don't need to (and can't) allocate from there. Also, guest operating // systems will see a hole in the UEFI memory map there. // SegmentCPages = 4; ASSERT (sizeof mVbeShim <= EFI_PAGES_TO_SIZE (SegmentCPages)); CopyMem ((VOID *)(UINTN)SegmentC, mVbeShim, sizeof mVbeShim); // // Fill in the VBE INFO structure. // VbeInfoFull = (VBE_INFO *)(UINTN)SegmentC; VbeInfo = &VbeInfoFull->Base; Ptr = VbeInfoFull->Buffer; CopyMem (VbeInfo->Signature, "VESA", 4); VbeInfo->VesaVersion = 0x0300; VbeInfo->OemNameAddress = (UINT32)(SegmentC << 12 | (UINT16)(UINTN)Ptr); CopyMem (Ptr, "QEMU", 5); Ptr += 5; VbeInfo->Capabilities = BIT0; // DAC can be switched into 8-bit mode VbeInfo->ModeListAddress = (UINT32)(SegmentC << 12 | (UINT16)(UINTN)Ptr); *(UINT16*)Ptr = 0x00f1; // mode number Ptr += 2; *(UINT16*)Ptr = 0xFFFF; // mode list terminator Ptr += 2; VbeInfo->VideoMem64K = (UINT16)((1024 * 768 * 4 + 65535) / 65536); VbeInfo->OemSoftwareVersion = 0x0000; VbeInfo->VendorNameAddress = (UINT32)(SegmentC << 12 | (UINT16)(UINTN)Ptr); CopyMem (Ptr, "OVMF", 5); Ptr += 5; VbeInfo->ProductNameAddress = (UINT32)(SegmentC << 12 | (UINT16)(UINTN)Ptr); Printed = AsciiSPrint ((CHAR8 *)Ptr, sizeof VbeInfoFull->Buffer - (Ptr - VbeInfoFull->Buffer), "%s", CardName); Ptr += Printed + 1; VbeInfo->ProductRevAddress = (UINT32)(SegmentC << 12 | (UINT16)(UINTN)Ptr); CopyMem (Ptr, mProductRevision, sizeof mProductRevision); Ptr += sizeof mProductRevision; ASSERT (sizeof VbeInfoFull->Buffer >= Ptr - VbeInfoFull->Buffer); ZeroMem (Ptr, sizeof VbeInfoFull->Buffer - (Ptr - VbeInfoFull->Buffer)); // // Fil in the VBE MODE INFO structure. // VbeModeInfo = (VBE_MODE_INFO *)(VbeInfoFull + 1); // // bit0: mode supported by present hardware configuration // bit1: optional information available (must be =1 for VBE v1.2+) // bit3: set if color, clear if monochrome // bit4: set if graphics mode, clear if text mode // bit5: mode is not VGA-compatible // bit7: linear framebuffer mode supported // VbeModeInfo->ModeAttr = BIT7 | BIT5 | BIT4 | BIT3 | BIT1 | BIT0; // // bit0: exists // bit1: bit1: readable // bit2: writeable // VbeModeInfo->WindowAAttr = BIT2 | BIT1 | BIT0; VbeModeInfo->WindowBAttr = 0x00; VbeModeInfo->WindowGranularityKB = 0x0040; VbeModeInfo->WindowSizeKB = 0x0040; VbeModeInfo->WindowAStartSegment = 0xA000; VbeModeInfo->WindowBStartSegment = 0x0000; VbeModeInfo->WindowPositioningAddress = 0x0000; VbeModeInfo->BytesPerScanLine = 1024 * 4; VbeModeInfo->Width = 1024; VbeModeInfo->Height = 768; VbeModeInfo->CharCellWidth = 8; VbeModeInfo->CharCellHeight = 16; VbeModeInfo->NumPlanes = 1; VbeModeInfo->BitsPerPixel = 32; VbeModeInfo->NumBanks = 1; VbeModeInfo->MemoryModel = 6; // direct color VbeModeInfo->BankSizeKB = 0; VbeModeInfo->NumImagePagesLessOne = 0; VbeModeInfo->Vbe3 = 0x01; VbeModeInfo->RedMaskSize = 8; VbeModeInfo->RedMaskPos = 16; VbeModeInfo->GreenMaskSize = 8; VbeModeInfo->GreenMaskPos = 8; VbeModeInfo->BlueMaskSize = 8; VbeModeInfo->BlueMaskPos = 0; VbeModeInfo->ReservedMaskSize = 8; VbeModeInfo->ReservedMaskPos = 24; // // bit1: Bytes in reserved field may be used by application // VbeModeInfo->DirectColorModeInfo = BIT1; VbeModeInfo->LfbAddress = (UINT32)FrameBufferBase; VbeModeInfo->OffScreenAddress = 0; VbeModeInfo->OffScreenSizeKB = 0; VbeModeInfo->BytesPerScanLineLinear = 1024 * 4; VbeModeInfo->NumImagesLessOneBanked = 0; VbeModeInfo->NumImagesLessOneLinear = 0; VbeModeInfo->RedMaskSizeLinear = 8; VbeModeInfo->RedMaskPosLinear = 16; VbeModeInfo->GreenMaskSizeLinear = 8; VbeModeInfo->GreenMaskPosLinear = 8; VbeModeInfo->BlueMaskSizeLinear = 8; VbeModeInfo->BlueMaskPosLinear = 0; VbeModeInfo->ReservedMaskSizeLinear = 8; VbeModeInfo->ReservedMaskPosLinear = 24; VbeModeInfo->MaxPixelClockHz = 0; ZeroMem (VbeModeInfo->Reserved, sizeof VbeModeInfo->Reserved); // // Clear Write Enable (bit1), keep Read Enable (bit0) set // PciWrite8 (Pam1Address, (Pam1 & ~BIT1) | BIT0); // // Second, point the Int10h vector at the shim. // Int0x10->Segment = SegmentC >> 4; Int0x10->Offset = (EFI_PHYSICAL_ADDRESS)(UINTN)(VbeModeInfo + 1) - SegmentC; DEBUG ((EFI_D_INFO, "%a: VBE shim installed\n", __FUNCTION__)); }
/** 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; }
/** Calculate the usb debug port bar address. @param DebugPortOffset Get usb debug port offset in the usb debug port memory space. @param DebugPortBarNumbar Get the bar number at which usb debug port is located. @retval RETURN_UNSUPPORTED The usb host controller does not supported usb debug port capability. @retval RETURN_SUCCESS Get bar and offset successfully. **/ RETURN_STATUS EFIAPI CalculateUsbDebugPortBar ( OUT UINT16 *DebugPortOffset, OUT UINT8 *DebugPortBarNumbar ) { UINT16 PciStatus; UINT16 VendorId; UINT16 DeviceId; UINT8 ProgInterface; UINT8 SubClassCode; UINT8 BaseCode; UINT8 CapabilityPtr; UINT8 CapabilityId; VendorId = PciRead16 (PcdGet32(PcdUsbEhciPciAddress) + PCI_VENDOR_ID_OFFSET); DeviceId = PciRead16 (PcdGet32(PcdUsbEhciPciAddress) + PCI_DEVICE_ID_OFFSET); if ((VendorId == 0xFFFF) || (DeviceId == 0xFFFF)) { return RETURN_UNSUPPORTED; } ProgInterface = PciRead8 (PcdGet32(PcdUsbEhciPciAddress) + PCI_CLASSCODE_OFFSET); SubClassCode = PciRead8 (PcdGet32(PcdUsbEhciPciAddress) + PCI_CLASSCODE_OFFSET + 1); BaseCode = PciRead8 (PcdGet32(PcdUsbEhciPciAddress) + PCI_CLASSCODE_OFFSET + 2); if ((ProgInterface != PCI_IF_EHCI) || (SubClassCode != PCI_CLASS_SERIAL_USB) || (BaseCode != PCI_CLASS_SERIAL)) { return RETURN_UNSUPPORTED; } // // Enable Ehci Host Controller MMIO Space. // PciStatus = PciRead16 (PcdGet32(PcdUsbEhciPciAddress) + PCI_PRIMARY_STATUS_OFFSET); if ((PciStatus & EFI_PCI_STATUS_CAPABILITY) == 0) { // // The Pci Device Doesn't Support Capability Pointer. // return RETURN_UNSUPPORTED; } // // Get Pointer To Capability List // CapabilityPtr = PciRead8(PcdGet32(PcdUsbEhciPciAddress) + PCI_CAPBILITY_POINTER_OFFSET); // // Find Capability ID 0xA, Which Is For Debug Port // while (CapabilityPtr != 0) { CapabilityId = PciRead8(PcdGet32(PcdUsbEhciPciAddress) + CapabilityPtr); if (CapabilityId == PCI_CAPABILITY_ID_DEBUG_PORT) { break; } CapabilityPtr = PciRead8(PcdGet32(PcdUsbEhciPciAddress) + CapabilityPtr + 1); } // // No Debug Port Capability Found // if (CapabilityPtr == 0) { return RETURN_UNSUPPORTED; } // // Get The Base Address Of Debug Port Register In Debug Port Capability Register // *DebugPortOffset = (UINT16)(PciRead16(PcdGet32(PcdUsbEhciPciAddress) + CapabilityPtr + 2) & 0x1FFF); *DebugPortBarNumbar = (UINT8)((PciRead16(PcdGet32(PcdUsbEhciPciAddress) + CapabilityPtr + 2) >> 13) - 1); 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 user code starts with this function. @param FileHandle Handle of the file being invoked. @param PeiServices Describes the list of possible PEI Services. @retval EFI_SUCCESS The driver is successfully initialized. @retval Others Can't initialize the driver. **/ EFI_STATUS EFIAPI InitializeSdMmcHcPeim ( IN EFI_PEI_FILE_HANDLE FileHandle, IN CONST EFI_PEI_SERVICES **PeiServices ) { EFI_BOOT_MODE BootMode; EFI_STATUS Status; UINT16 Bus; UINT16 Device; UINT16 Function; UINT32 Size; UINT64 MmioSize; UINT8 SubClass; UINT8 BaseClass; UINT8 SlotInfo; UINT8 SlotNum; UINT8 FirstBar; UINT8 Index; UINT8 Slot; UINT32 BarAddr; SD_MMC_HC_PEI_PRIVATE_DATA *Private; // // Shadow this PEIM to run from memory // if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) { return EFI_SUCCESS; } Status = PeiServicesGetBootMode (&BootMode); /// /// We do not expose this in S3 boot path, because it is only for recovery. /// if (BootMode == BOOT_ON_S3_RESUME) { return EFI_SUCCESS; } Private = (SD_MMC_HC_PEI_PRIVATE_DATA *) AllocateZeroPool (sizeof (SD_MMC_HC_PEI_PRIVATE_DATA)); if (Private == NULL) { DEBUG ((EFI_D_ERROR, "Failed to allocate memory for SD_MMC_HC_PEI_PRIVATE_DATA! \n")); return EFI_OUT_OF_RESOURCES; } Private->Signature = SD_MMC_HC_PEI_SIGNATURE; Private->SdMmcHostControllerPpi = mSdMmcHostControllerPpi; Private->PpiList = mPpiList; Private->PpiList.Ppi = &Private->SdMmcHostControllerPpi; BarAddr = PcdGet32 (PcdSdMmcPciHostControllerMmioBase); for (Bus = 0; Bus < 256; Bus++) { for (Device = 0; Device < 32; Device++) { for (Function = 0; Function < 8; Function++) { SubClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0A)); BaseClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0B)); if ((SubClass == PCI_SUBCLASS_SD_HOST_CONTROLLER) && (BaseClass == PCI_CLASS_SYSTEM_PERIPHERAL)) { // // Get the SD/MMC Pci host controller's Slot Info. // SlotInfo = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, SD_MMC_HC_PEI_SLOT_OFFSET)); FirstBar = (*(SD_MMC_HC_PEI_SLOT_INFO*)&SlotInfo).FirstBar; SlotNum = (*(SD_MMC_HC_PEI_SLOT_INFO*)&SlotInfo).SlotNum + 1; ASSERT ((FirstBar + SlotNum) < MAX_SD_MMC_SLOTS); for (Index = 0, Slot = FirstBar; Slot < (FirstBar + SlotNum); Index++, Slot++) { // // Get the SD/MMC Pci host controller's MMIO region size. // PciAnd16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (UINT16)~(EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE)); PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot), 0xFFFFFFFF); Size = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot)); switch (Size & 0x07) { case 0x0: // // Memory space: anywhere in 32 bit address space // MmioSize = (~(Size & 0xFFFFFFF0)) + 1; break; case 0x4: // // Memory space: anywhere in 64 bit address space // MmioSize = Size & 0xFFFFFFF0; PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4), 0xFFFFFFFF); Size = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4)); // // Fix the length to support some spefic 64 bit BAR // Size |= ((UINT32)(-1) << HighBitSet32 (Size)); // // Calculate the size of 64bit bar // MmioSize |= LShiftU64 ((UINT64) Size, 32); MmioSize = (~(MmioSize)) + 1; // // Clean the high 32bits of this 64bit BAR to 0 as we only allow a 32bit BAR. // PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot + 4), 0); break; default: // // Unknown BAR type // ASSERT (FALSE); continue; }; // // Assign resource to the SdMmc Pci host controller's MMIO BAR. // Enable the SdMmc Pci host controller by setting BME and MSE bits of PCI_CMD register. // PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot), BarAddr); PciOr16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE)); // // Record the allocated Mmio base address. // Private->MmioBar[Private->TotalSdMmcHcs].SlotNum++; Private->MmioBar[Private->TotalSdMmcHcs].MmioBarAddr[Index] = BarAddr; BarAddr += (UINT32)MmioSize; } Private->TotalSdMmcHcs++; ASSERT (Private->TotalSdMmcHcs < MAX_SD_MMC_HCS); } } } } /// /// Install SdMmc Host Controller PPI /// Status = PeiServicesInstallPpi (&Private->PpiList); ASSERT_EFI_ERROR (Status); return Status; }
/** Dispatch function for a Software SMI handler. @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). @param[in] RegisterContext Points to an optional handler context which was specified when the handler was registered. @param[in, out] CommBuffer A pointer to a collection of Data in memory that will be conveyed from a non-SMM environment into an SMM environment. @param[in, out] CommBufferSize The Size of the CommBuffer. @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers should still be called. @retval Others Other execution results. **/ EFI_STATUS EFIAPI SmmUnlockOpalPassword ( IN EFI_HANDLE DispatchHandle, IN CONST VOID *RegisterContext, IN OUT VOID *CommBuffer, IN OUT UINTN *CommBufferSize ) { EFI_STATUS Status; OPAL_SMM_DEVICE *OpalDev; LIST_ENTRY *Entry; UINT8 BaseClassCode; UINT8 SubClassCode; UINT8 ProgInt; TCG_RESULT Result; UINT8 SataCmdSt; UINT8 *StorePcieConfDataList[16]; UINTN RpBase; UINTN MemoryBase; UINTN MemoryLength; OPAL_SESSION Session; BOOLEAN BlockSidSupport; ZeroMem (StorePcieConfDataList, sizeof (StorePcieConfDataList)); Status = EFI_DEVICE_ERROR; // // try to unlock all locked hdd disks. // for (Entry = mSmmDeviceList.ForwardLink; Entry != &mSmmDeviceList; Entry = Entry->ForwardLink) { OpalDev = BASE_CR(Entry, OPAL_SMM_DEVICE, Link); RpBase = 0; SataCmdSt = 0; /// /// Configure RootPort for PCIe AHCI/NVME devices. /// if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { /// /// Save original RootPort configuration space to heap /// RpBase = SaveRestoreRootportConfSpace ( OpalDev, TRUE, StorePcieConfDataList ); MemoryBase = mNvmeContext.Nbar; MemoryLength = 0; ConfigureRootPortForPcieNand (RpBase, OpalDev->BusNum, (UINT32) MemoryBase, (UINT32) MemoryLength); /// /// Enable PCIE decode for RootPort /// SataCmdSt = PciRead8 (RpBase + NVME_PCIE_PCICMD); PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0x6); } else { SataCmdSt = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD)); PciWrite8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD), 0x6); } BaseClassCode = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0B)); SubClassCode = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0A)); ProgInt = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x09)); if (BaseClassCode != PCI_CLASS_MASS_STORAGE) { Status = EFI_INVALID_PARAMETER; break; } Status = EFI_DEVICE_ERROR; if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_SATA) { if ((SubClassCode == PCI_CLASS_MASS_STORAGE_AHCI) || (SubClassCode == PCI_CLASS_MASS_STORAGE_RAID)) { Status = GetAhciBaseAddress (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "GetAhciBaseAddress error, Status: %r\n", Status)); goto done; } Status = AhciModeInitialize ((UINT8)OpalDev->SataPort); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "AhciModeInitialize error, Status: %r\n", Status)); goto done; } } else { DEBUG ((DEBUG_ERROR, "SubClassCode not support for SATA device\n")); } } else if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { if (SubClassCode == PCI_CLASS_MASS_STORAGE_NVM) { if (ProgInt != PCI_IF_NVMHCI) { DEBUG ((DEBUG_ERROR, "PI not support, skipped\n")); Status = EFI_NOT_FOUND; goto done; } mNvmeContext.PciBase = PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0); mNvmeContext.NvmeInitWaitTime = 0; mNvmeContext.Nsid = OpalDev->NvmeNamespaceId; Status = NvmeControllerInit (&mNvmeContext); } else { DEBUG ((DEBUG_ERROR, "SubClassCode not support for NVME device\n")); } } else { DEBUG ((DEBUG_ERROR, "Invalid Devicetype\n")); goto done; } Status = EFI_DEVICE_ERROR; BlockSidSupport = FALSE; if (IsOpalDeviceLocked (OpalDev, &BlockSidSupport)) { ZeroMem(&Session, sizeof(Session)); Session.Sscp = &OpalDev->Sscp; Session.MediaId = 0; Session.OpalBaseComId = OpalDev->OpalBaseComId; Result = OpalSupportUnlock (&Session, OpalDev->Password, OpalDev->PasswordLength, NULL); if (Result == TcgResultSuccess) { Status = EFI_SUCCESS; } } if (mSendBlockSID && BlockSidSupport) { Result = OpalBlockSid (&Session, TRUE); if (Result != TcgResultSuccess) { break; } } if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { if (SubClassCode == PCI_CLASS_MASS_STORAGE_NVM) { Status = NvmeControllerExit (&mNvmeContext); } } done: if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { ASSERT (RpBase != 0); PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0); RpBase = SaveRestoreRootportConfSpace ( OpalDev, FALSE, // restore StorePcieConfDataList ); PciWrite8 (RpBase + NVME_PCIE_PCICMD, SataCmdSt); } else { PciWrite8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD), SataCmdSt); } if (EFI_ERROR (Status)) { break; } } return Status; }
/** Reads a range of PCI configuration registers into a caller supplied buffer. Reads the range of PCI configuration registers specified by StartAddress and Size into the buffer specified by Buffer. This function only allows the PCI configuration registers from a single PCI function to be read. Size is returned. When possible 32-bit PCI configuration read cycles are used to read from StartAdress to StartAddress + Size. Due to alignment restrictions, 8-bit and 16-bit PCI configuration read cycles may be used at the beginning and the end of the range. If StartAddress > 0x0FFFFFFF, then ASSERT(). If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT(). If Size > 0 and Buffer is NULL, then ASSERT(). @param StartAddress The starting address that encodes the PCI Bus, Device, Function and Register. @param Size The size in bytes of the transfer. @param Buffer The pointer to a buffer receiving the data read. @return Size **/ UINTN EFIAPI PciReadBuffer ( IN UINTN StartAddress, IN UINTN Size, OUT VOID *Buffer ) { UINTN ReturnValue; ASSERT_INVALID_PCI_ADDRESS (StartAddress, 0); ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000); if (Size == 0) { return Size; } ASSERT (Buffer != NULL); // // Save Size for return // ReturnValue = Size; if ((StartAddress & BIT0) != 0) { // // Read a byte if StartAddress is byte aligned // *(volatile UINT8 *)Buffer = PciRead8 (StartAddress); StartAddress += sizeof (UINT8); Size -= sizeof (UINT8); Buffer = (UINT8*)Buffer + 1; } if (Size >= sizeof (UINT16) && (StartAddress & BIT1) != 0) { // // Read a word if StartAddress is word aligned // WriteUnaligned16 (Buffer, PciRead16 (StartAddress)); StartAddress += sizeof (UINT16); Size -= sizeof (UINT16); Buffer = (UINT16*)Buffer + 1; } while (Size >= sizeof (UINT32)) { // // Read as many double words as possible // WriteUnaligned32 (Buffer, PciRead32 (StartAddress)); StartAddress += sizeof (UINT32); Size -= sizeof (UINT32); Buffer = (UINT32*)Buffer + 1; } if (Size >= sizeof (UINT16)) { // // Read the last remaining word if exist // WriteUnaligned16 (Buffer, PciRead16 (StartAddress)); StartAddress += sizeof (UINT16); Size -= sizeof (UINT16); Buffer = (UINT16*)Buffer + 1; } if (Size >= sizeof (UINT8)) { // // Read the last remaining byte if exist // *(volatile UINT8 *)Buffer = PciRead8 (StartAddress); } return ReturnValue; }