/** Calling this function causes the system to enter a power state equivalent to the ACPI G2/S5 or G3 states. System shutdown should not return, if it returns, it means the system does not support shut down reset. **/ VOID EFIAPI ResetShutdown ( VOID ) { // // Reference to QuarkNcSocId BWG // Disable RTC Alarm : (RTC Enable at PM1BLK + 02h[10])) // IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, 0); // // Firstly, GPE0_EN should be disabled to // avoid any GPI waking up the system from S5 // IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0E, 0); // // Reference to QuarkNcSocId BWG // Disable Resume Well GPIO : (GPIO bits in GPIOBASE + 34h[8:0]) // IoWrite32 (PcdGet16 (PcdGbaIoBaseAddress) + R_QNC_GPIO_RGGPE_RESUME_WELL, 0); // // No power button status bit to clear for our platform, go to next step. // // // Finally, transform system into S5 sleep state // IoAndThenOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, 0xffffc3ff, B_QNC_PM1BLK_PM1C_SLPEN | V_S5); }
/** Write I/O registers. @param[in] PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation. @param[in] This Pointer to local data for the interface. @param[in] Width The width of the access. Enumerated in bytes. @param[in] Address The physical address of the access. @param[in] Count The number of accesses to perform. @param[in] Buffer A pointer to the buffer of data. @retval EFI_SUCCESS The function completed successfully. @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system. @retval EFI_INVALID_PARAMETER Buffer is NULL. @retval EFI_UNSUPPORTED The address range specified by Address, Width, and Count is not valid for this EFI system. **/ EFI_STATUS EFIAPI CpuIoServiceWrite ( IN CONST EFI_PEI_SERVICES **PeiServices, IN CONST EFI_PEI_CPU_IO_PPI *This, IN EFI_PEI_CPU_IO_PPI_WIDTH Width, IN UINT64 Address, IN UINTN Count, IN VOID *Buffer ) { EFI_STATUS Status; UINT8 InStride; UINT8 OutStride; EFI_PEI_CPU_IO_PPI_WIDTH OperationWidth; BOOLEAN Aligned; UINT8 *Uint8Buffer; // // Make sure the parameters are valid // Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer); if (EFI_ERROR (Status)) { return Status; } // // Select loop based on the width of the transfer // InStride = mInStride[Width]; OutStride = mOutStride[Width]; OperationWidth = (EFI_PEI_CPU_IO_PPI_WIDTH) (Width & 0x03); Aligned = (BOOLEAN)(((UINTN)Buffer & (mInStride[OperationWidth] - 1)) == 0x00); for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { if (OperationWidth == EfiPeiCpuIoWidthUint8) { IoWrite8 ((UINTN)Address, *Uint8Buffer); } else if (OperationWidth == EfiPeiCpuIoWidthUint16) { if (Aligned) { IoWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer)); } else { IoWrite16 ((UINTN)Address, ReadUnaligned16 ((UINT16 *)Uint8Buffer)); } } else if (OperationWidth == EfiPeiCpuIoWidthUint32) { if (Aligned) { IoWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer)); } else { IoWrite32 ((UINTN)Address, ReadUnaligned32 ((UINT32 *)Uint8Buffer)); } } } return EFI_SUCCESS; }
/** Clear SMI related chipset status and re-enable SMI by setting the EOS bit. @retval EFI_SUCCESS The requested operation has been carried out successfully @retval EFI_DEVICE_ERROR The EOS bit could not be set. **/ EFI_STATUS SmmClear ( VOID ) { UINT16 PM1BLK_Base; UINT16 GPE0BLK_Base; // // Get PM1BLK_Base & GPE0BLK_Base // PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress); GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress); // // Clear the Power Button Override Status Bit, it gates EOS from being set. // In QuarkNcSocId - Bit is read only. Handled by external SMC, do nothing. // // // Clear the APM SMI Status Bit // IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM); // // Set the EOS Bit // IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS); return EFI_SUCCESS; }
/** Sends an 32-bit value to a POST card. Sends the 32-bit value specified by Value to a POST card, and returns Value. Some implementations of this library function may perform I/O operations directly to a POST card device. Other implementations may send Value to ReportStatusCode(), and the status code reporting mechanism will eventually display the 32-bit value on the status reporting device. PostCode() must actively prevent recursion. If PostCode() is called while processing another any other Post Code Library function, then PostCode() must return Value immediately. @param Value The 32-bit value to write to the POST card. @return The 32-bit value to write to the POST card. **/ UINT32 EFIAPI PostCode ( IN UINT32 Value ) { switch (PcdGet8 (PcdPort80DataWidth)) { case 8: IoWrite8 (0x80, (UINT8)(Value)); break; case 16: IoWrite16 (0x80, (UINT16)(Value)); break; case 32: IoWrite32 (0x80, Value); break; default: // // Assert on the invalid data width // ASSERT (FALSE); break; } return Value; }
/** Write to IO space Argv[0] - "iowrite"[.#] # is optional width 1, 2, or 4. Default 1 Argv[1] - Hex IO address Argv[2] - Hex data to write iow.4 0x3f8 af ;Do a 32-bit IO write of af to 0x3f8 iow 0x3f8 af ;Do an 8-bit IO write of af to 0x3f8 @param Argc Number of command arguments in Argv @param Argv Array of strings that represent the parsed command line. Argv[0] is the command name @return EFI_SUCCESS **/ EFI_STATUS EblIoWriteCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { UINTN Width; UINTN Port; UINTN Data; if (Argc < 3) { return EFI_INVALID_PARAMETER; } Port = AsciiStrHexToUintn (Argv[1]); Data = AsciiStrHexToUintn (Argv[2]); Width = WidthFromCommandName (Argv[0], 1); if (Width == 1) { IoWrite8 (Port, (UINT8)Data); } else if (Width == 2) { IoWrite16 (Port, (UINT16)Data); } else if (Width == 4) { IoWrite32 (Port, (UINT32)Data); } else { return EFI_INVALID_PARAMETER; } return EFI_SUCCESS; }
/** 32-bit I/O write operations. @param[in] PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation. @param[in] This Pointer to local data for the interface. @param[in] Address The physical address of the access. @param[in] Data The data to write. **/ VOID EFIAPI CpuIoWrite32 ( IN CONST EFI_PEI_SERVICES **PeiServices, IN CONST EFI_PEI_CPU_IO_PPI *This, IN UINT64 Address, IN UINT32 Data ) { IoWrite32 ((UINTN)Address, Data); }
VOID EFIAPI DisableAcpiCallback ( IN EFI_HANDLE DispatchHandle, IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext ) { UINT16 Pm1Cnt; IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, 0xffff); IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN, mPM1_SaveState16); IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_STS, 0xffffffff); IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN, mGPE_SaveState32); // // Disable SCI // Pm1Cnt = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT); Pm1Cnt &= ~B_PCH_ACPI_PM1_CNT_SCI_EN; IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT, Pm1Cnt); }
/** Triggers a run time or boot time SMI. This function triggers a software SMM interrupt and set the APMC status with an 8-bit Data. @param Data The value to set the APMC status. **/ VOID InternalTriggerSmi ( IN UINT8 Data ) { UINT16 PM1BLK_Base; UINT16 GPE0BLK_Base; UINT32 NewValue; // // Get PM1BLK_Base & GPE0BLK_Base // PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress); GPE0BLK_Base = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF); // // Enable APM SMI // IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIE), B_QNC_GPE0BLK_SMIE_APM); // // Enable SMI globally // NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC); NewValue |= SMI_EN; QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue); // // Set APM_STS // IoWrite8 (PcdGet16 (PcdSmmDataPort), Data); // // Generate the APM SMI // IoWrite8 (PcdGet16 (PcdSmmActivationPort), PcdGet8 (PcdSmmActivationData)); // // Clear the APM SMI Status Bit // IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM); // // Set the EOS Bit // IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS); }
/** Write I/O registers. The I/O operations are carried out exactly as requested. The caller is responsible for satisfying any alignment and I/O width restrictions that a PI System on a platform might require. For example on some platforms, width requests of EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will be handled by the driver. If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32, or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for each of the Count operations that is performed. If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16, EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is incremented for each of the Count operations that is performed. The read or write operation is performed Count times on the same Address. If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16, EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is incremented for each of the Count operations that is performed. The read or write operation is performed Count times from the first element of Buffer. @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance. @param[in] Width Signifies the width of the I/O or Memory operation. @param[in] Address The base address of the I/O operation. @param[in] Count The number of I/O operations to perform. The number of bytes moved is Width size * Count, starting at Address. @param[in] Buffer For read operations, the destination buffer to store the results. For write operations, the source buffer from which to write data. @retval EFI_SUCCESS The data was read from or written to the PI system. @retval EFI_INVALID_PARAMETER Width is invalid for this PI system. @retval EFI_INVALID_PARAMETER Buffer is NULL. @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. @retval EFI_UNSUPPORTED The address range specified by Address, Width, and Count is not valid for this PI system. **/ EFI_STATUS EFIAPI CpuIoServiceWrite ( IN EFI_CPU_IO2_PROTOCOL *This, IN EFI_CPU_IO_PROTOCOL_WIDTH Width, IN UINT64 Address, IN UINTN Count, IN VOID *Buffer ) { EFI_STATUS Status; UINT8 InStride; UINT8 OutStride; EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth; UINT8 *Uint8Buffer; // // Make sure the parameters are valid // Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer); if (EFI_ERROR (Status)) { return Status; } // // Select loop based on the width of the transfer // InStride = mInStride[Width]; OutStride = mOutStride[Width]; OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03); for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { if (OperationWidth == EfiCpuIoWidthUint8) { IoWrite8 ((UINTN)Address, *Uint8Buffer); } else if (OperationWidth == EfiCpuIoWidthUint16) { IoWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer)); } else if (OperationWidth == EfiCpuIoWidthUint32) { IoWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer)); } } return EFI_SUCCESS; }
VOID EFIAPI S4S5CallBack ( IN EFI_HANDLE DispatchHandle, IN EFI_SMM_SX_DISPATCH_CONTEXT *DispatchContext ) { UINT32 Data32; // // Enable/Disable USB Charging // if (mSystemConfiguration.UsbCharging == 0x01) { Data32 = IoRead32 (GPIO_BASE_ADDRESS + R_PCH_GPIO_SC_LVL); Data32 |= BIT8; IoWrite32(GPIO_BASE_ADDRESS + R_PCH_GPIO_SC_LVL, Data32); } }
EFI_STATUS RestoreState ( VOID ) /*++ Routine Description: Restore Index registers to avoid corrupting the foreground environment Arguments: None Returns: Status - EFI_SUCCESS --*/ { IoWrite32 (EFI_PCI_ADDRESS_PORT, mPciAddress); return EFI_SUCCESS; }
/** Write I/O registers. The I/O operations are carried out exactly as requested. The caller is responsible for any alignment and I/O width issues that the bus, device, platform, or type of I/O might require. @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance. @param[in] Width Signifies the width of the I/O operations. @param[in] Address The base address of the I/O operations. The caller is responsible for aligning the Address if required. @param[in] Count The number of I/O operations to perform. @param[in] Buffer For read operations, the destination buffer to store the results. For write operations, the source buffer from which to write data. @retval EFI_SUCCESS The data was read from or written to the device. @retval EFI_UNSUPPORTED The Address is not valid for this system. @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid. @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources **/ EFI_STATUS EFIAPI CpuIoServiceWrite ( IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This, IN EFI_SMM_IO_WIDTH Width, IN UINT64 Address, IN UINTN Count, IN VOID *Buffer ) { EFI_STATUS Status; UINT8 Stride; UINT8 *Uint8Buffer; // // Make sure the parameters are valid // Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer); if (EFI_ERROR (Status)) { return Status; } // // Select loop based on the width of the transfer // Stride = mStride[Width]; for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += Stride, Uint8Buffer += Stride, Count--) { if (Width == SMM_IO_UINT8) { IoWrite8 ((UINTN)Address, *Uint8Buffer); } else if (Width == SMM_IO_UINT16) { IoWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer)); } else if (Width == SMM_IO_UINT32) { IoWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer)); } } return EFI_SUCCESS; }
// // Routines local to this source module. // STATIC VOID LegacyGpioSetLevel ( IN CONST UINT32 LevelRegOffset, IN CONST UINT32 GpioNum, IN CONST BOOLEAN HighLevel ) { UINT32 RegValue; UINT32 GpioBaseAddress; UINT32 GpioNumMask; GpioBaseAddress = LpcPciCfg32 (R_QNC_LPC_GBA_BASE) & B_QNC_LPC_GPA_BASE_MASK; ASSERT (GpioBaseAddress > 0); RegValue = IoRead32 (GpioBaseAddress + LevelRegOffset); GpioNumMask = (1 << GpioNum); if (HighLevel) { RegValue |= (GpioNumMask); } else { RegValue &= ~(GpioNumMask); } IoWrite32 (GpioBaseAddress + R_QNC_GPIO_RGLVL_RESUME_WELL, RegValue); }
/** Calling this function causes the system to enter a power state for capsule update. Reset update should not return, if it returns, it means the system does not support capsule update. **/ VOID EFIAPI EnterS3WithImmediateWake ( VOID ) { UINT8 Data8; UINT16 Data16; UINT32 Data32; UINTN Eflags; UINTN RegCr0; EFI_TIME EfiTime; UINT32 SmiEnSave; Eflags = AsmReadEflags (); if ( (Eflags & 0x200) ) { DisableInterrupts (); } // // Write all cache data to memory because processor will lost power // AsmWbinvd(); RegCr0 = AsmReadCr0(); AsmWriteCr0 (RegCr0 | 0x060000000); SmiEnSave = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC); QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, (SmiEnSave & ~SMI_EN)); // // Pogram RTC alarm for immediate WAKE // // // Disable SMI sources // IoWrite16 (PcdGet16 (PcdGpe0blkIoBaseAddress) + R_QNC_GPE0BLK_SMIE, 0); // // Disable RTC alarm interrupt // IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B); Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER); IoWrite8 (PCAT_RTC_DATA_REGISTER, (Data8 & ~BIT5)); // // Clear RTC alarm if already set // IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_C); Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER); // Read clears alarm status // // Disable all WAKE events // IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, B_QNC_PM1BLK_PM1E_PWAKED); // // Clear all WAKE status bits // IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S, B_QNC_PM1BLK_PM1S_ALL); // // Avoid RTC rollover // do { WaitForRTCUpdate(); IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS); EfiTime.Second = IoRead8 (PCAT_RTC_DATA_REGISTER); } while (EfiTime.Second > PLATFORM_RTC_ROLLOVER_LIMIT); // // Read RTC time // IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOURS); EfiTime.Hour = IoRead8 (PCAT_RTC_DATA_REGISTER); IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTES); EfiTime.Minute = IoRead8 (PCAT_RTC_DATA_REGISTER); IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS); EfiTime.Second = IoRead8 (PCAT_RTC_DATA_REGISTER); // // Set RTC alarm // // // Add PLATFORM_WAKE_SECONDS_BUFFER to current EfiTime.Second // The maths is to allow for the fact we are adding to a BCD number and require the answer to be BCD (EfiTime.Second) // if ((BCD_BASE - (EfiTime.Second & 0x0F)) <= PLATFORM_WAKE_SECONDS_BUFFER) { Data8 = (((EfiTime.Second & 0xF0) + 0x10) + (PLATFORM_WAKE_SECONDS_BUFFER - (BCD_BASE - (EfiTime.Second & 0x0F)))); } else { Data8 = EfiTime.Second + PLATFORM_WAKE_SECONDS_BUFFER; } IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOURS_ALARM); IoWrite8 (PCAT_RTC_DATA_REGISTER, EfiTime.Hour); IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTES_ALARM); IoWrite8 (PCAT_RTC_DATA_REGISTER, EfiTime.Minute); IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS_ALARM); IoWrite8 (PCAT_RTC_DATA_REGISTER, Data8); // // Enable RTC alarm interrupt // IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B); Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER); IoWrite8 (PCAT_RTC_DATA_REGISTER, (Data8 | BIT5)); // // Enable RTC alarm as WAKE event // Data16 = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E); IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, (Data16 | B_QNC_PM1BLK_PM1E_RTC)); // // Enter S3 // Data32 = IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C); Data32 = (UINT32) ((Data32 & 0xffffc3fe) | V_S3 | B_QNC_PM1BLK_PM1C_SCIEN); IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Data32); Data32 = Data32 | B_QNC_PM1BLK_PM1C_SLPEN; IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Data32); // // Enable Interrupt if it's enabled before // if ( (Eflags & 0x200) ) { EnableInterrupts (); } }
VOID EFIAPI EnableAcpiCallback ( IN EFI_HANDLE DispatchHandle, IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext ) { UINT32 SmiEn; UINT16 Pm1Cnt; UINT16 wordValue; UINT32 RegData32; // // Disable SW SMI Timer // SmiEn = IoRead32(mAcpiBaseAddr + R_PCH_SMI_EN); SmiEn &= ~B_PCH_SMI_STS_SWSMI_TMR; IoWrite32(mAcpiBaseAddr + R_PCH_SMI_EN, SmiEn); wordValue = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS); if(wordValue & B_PCH_ACPI_PM1_STS_WAK) { IoWrite32((mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN), 0x0000); IoWrite32((mAcpiBaseAddr + R_PCH_ACPI_GPE0a_STS), 0xffffffff); } else { mPM1_SaveState16 = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN); // // Disable PM sources except power button // // power button is enabled only for PCAT. Disabled it on Tablet platform // IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN, B_PCH_ACPI_PM1_EN_PWRBTN); IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, 0xffff); mGPE_SaveState32 = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN); IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN, 0x0000); IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_STS, 0xffffffff); } // // Guarantee day-of-month alarm is invalid (ACPI 5.0 Section 4.8.2.4 "Real Time Clock Alarm") // Clear Status D reg VM bit, Date of month Alarm to make Data in CMOS RAM is no longer Valid // IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_D); IoWrite8 (PCAT_RTC_DATA_REGISTER, 0x0); RegData32 = IoRead32(ACPI_BASE_ADDRESS + R_PCH_ALT_GP_SMI_EN); RegData32 &= ~(BIT7); IoWrite32((ACPI_BASE_ADDRESS + R_PCH_ALT_GP_SMI_EN), RegData32); // // Enable SCI // Pm1Cnt = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT); Pm1Cnt |= B_PCH_ACPI_PM1_CNT_SCI_EN; IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT, Pm1Cnt); }
// ------------------------------------------------------------------------------------------------ void PciWrite32(uint32 id, uint32 reg, uint32 data) { uint32 address = 0x80000000 | id | (reg & 0xfc); IoWrite32(PCI_CONFIG_ADDR, address); IoWrite32(PCI_CONFIG_DATA, data); }
// ------------------------------------------------------------------------------------------------ void PciWrite16(uint32 id, uint32 reg, uint16 data) { uint32 address = 0x80000000 | id | (reg & 0xfc); IoWrite32(PCI_CONFIG_ADDR, address); outportw(PCI_CONFIG_DATA + (reg & 0x02), data); }
// ------------------------------------------------------------------------------------------------ uint32 PciRead32(uint32 id, uint32 reg) { uint32 addr = 0x80000000 | id | (reg & 0xfc); IoWrite32(PCI_CONFIG_ADDR, addr); return IoRead32(PCI_CONFIG_DATA); }
/** This function is IO instruction handler. @param Index CPU index **/ VOID IoHandler ( IN UINT32 Index ) { VM_EXIT_QUALIFICATION Qualification; UINT16 Port; UINTN *DataPtr; IO_WRITE_HANDLER_ITEM *IoWriteHandler; IO_READ_HANDLER_ITEM *IoReadHandler; UINT32 Action; UINT32 Value; UINTN LinearAddr; Qualification.UintN = VmReadN (VMCS_N_RO_EXIT_QUALIFICATION_INDEX); Port = (UINT16)Qualification.IoInstruction.PortNum; DataPtr = (UINTN *)&mGuestContextCommon.GuestContextPerCpu[Index].Register.Rax; if (Qualification.IoInstruction.Rep) { UINT64 RcxMask; RcxMask = 0xFFFFFFFFFFFFFFFFull; if ((mGuestContextCommon.GuestContextPerCpu[Index].EFER & IA32_EFER_MSR_MLA) == 0) { RcxMask = 0xFFFFFFFFull; } if ((mGuestContextCommon.GuestContextPerCpu[Index].Register.Rcx & RcxMask) == 0) { // Skip VmWriteN (VMCS_N_GUEST_RIP_INDEX, VmReadN(VMCS_N_GUEST_RIP_INDEX) + VmRead32(VMCS_32_RO_VMEXIT_INSTRUCTION_LENGTH_INDEX)); return ; } } if (Port == 0xB2) { DEBUG ((EFI_D_INFO, "(FRM) !!! SmiCmd(0xb2) - 0x%02x !!!\n", (UINT8)*DataPtr)); } if ((mHostContextCommon.ResetIoPortBaseAddress != 0) && (Port == mHostContextCommon.ResetIoPortBaseAddress) && (Qualification.IoInstruction.Direction == 0)) { IoResetHandler (Index, Port, (UINT8)*DataPtr); } else if ((Port == mHostContextCommon.AcpiPmControlIoPortBaseAddress) && (Qualification.IoInstruction.Direction == 0)) { IoAcpiHandler (Index, Port, (UINT32)*DataPtr); } if (Qualification.IoInstruction.String) { LinearAddr = VmReadN (VMCS_N_RO_GUEST_LINEAR_ADDR_INDEX); if (VmReadN (VMCS_N_GUEST_CR0_INDEX) & CR0_PG) { DataPtr = (UINTN *)(UINTN)GuestVirtualToGuestPhysical (Index, LinearAddr); } else { DataPtr = (UINTN *)LinearAddr; } if (VmReadN (VMCS_N_GUEST_RFLAGS_INDEX) & RFLAGS_DF) { if (Qualification.IoInstruction.Direction) { mGuestContextCommon.GuestContextPerCpu[Index].Register.Rdi -= Qualification.IoInstruction.Size + 1; } else { mGuestContextCommon.GuestContextPerCpu[Index].Register.Rsi -= Qualification.IoInstruction.Size + 1; } } else { if (Qualification.IoInstruction.Direction) { mGuestContextCommon.GuestContextPerCpu[Index].Register.Rdi += Qualification.IoInstruction.Size + 1; } else { mGuestContextCommon.GuestContextPerCpu[Index].Register.Rsi += Qualification.IoInstruction.Size + 1; } } } if (Qualification.IoInstruction.Direction) { // IN IoReadHandler = FindIoReadHandler (Port, Qualification.IoInstruction.Size + 1); if (IoReadHandler != NULL) { Action = IO_ACTION_NO_ACTION; Value = 0; IoReadHandler->Handler (IoReadHandler->Context, Port, &Value, &Action); if (Action == IO_ACTION_NO_ACTION) { switch (Qualification.IoInstruction.Size) { case 0: *(UINT8 *)DataPtr = (UINT8)Value; goto Ret; break; case 1: *(UINT16 *)DataPtr = (UINT16)Value; goto Ret; break; case 3: *(UINT32 *)DataPtr = Value; goto Ret; break; default: break; } goto Ret; } else { // Passthrough } } switch (Qualification.IoInstruction.Size) { case 0: *(UINT8 *)DataPtr = IoRead8 (Port); goto Ret; break; case 1: *(UINT16 *)DataPtr = IoRead16 (Port); goto Ret; break; case 3: *(UINT32 *)DataPtr = IoRead32 (Port); goto Ret; break; default: break; } } else { // OUT IoWriteHandler = FindIoWriteHandler (Port, Qualification.IoInstruction.Size + 1); if (IoWriteHandler != NULL) { Action = IO_ACTION_NO_ACTION; Value = (UINT32)*DataPtr; IoWriteHandler->Handler (IoWriteHandler->Context, Port, Value, &Action); if (Action == IO_ACTION_NO_ACTION) { goto Ret; } else { // Passthrough } } switch (Qualification.IoInstruction.Size) { case 0: IoWrite8 (Port, (UINT8)*DataPtr); goto Ret; break; case 1: IoWrite16 (Port, (UINT16)*DataPtr); goto Ret; break; case 3: IoWrite32 (Port, (UINT32)*DataPtr); goto Ret; break; default: break; } } DEBUG ((EFI_D_ERROR, "(FRM) !!!IoHandler!!!\n")); DumpVmcsAllField (); CpuDeadLoop (); Ret: if (Qualification.IoInstruction.Rep) { // replay mGuestContextCommon.GuestContextPerCpu[Index].Register.Rcx --; return ; } VmWriteN (VMCS_N_GUEST_RIP_INDEX, VmReadN(VMCS_N_GUEST_RIP_INDEX) + VmRead32(VMCS_32_RO_VMEXIT_INSTRUCTION_LENGTH_INDEX)); return ; }
EFI_STATUS ConfigureSoCGpio ( IN SYSTEM_CONFIGURATION *SystemConfiguration ) { DEBUG ((EFI_D_ERROR, "ConfigureSoCGpio------------start\n")); if (SystemConfiguration->eMMCBootMode== 1) {// Auto detection mode DEBUG ((EFI_D_ERROR, "Auto detection mode------------start\n")); // //Silicon Steppings // switch (PchStepping()) { case PchA0: // SOC A0 and A1 case PchA1: DEBUG ((EFI_D_ERROR, "SOC A0/A1: eMMC 4.41 GPIO Configuration\n")); SystemConfiguration->LpsseMMCEnabled = 1; SystemConfiguration->LpsseMMC45Enabled = 0; break; case PchB0: // SOC B0 and later default: DEBUG ((EFI_D_ERROR, "SOC B0 and later: eMMC 4.5 GPIO Configuration\n")); SystemConfiguration->LpsseMMCEnabled = 0; SystemConfiguration->LpsseMMC45Enabled = 1; break; } } else if (SystemConfiguration->eMMCBootMode == 2) { // eMMC 4.41 DEBUG ((EFI_D_ERROR, "Force to eMMC 4.41 GPIO Configuration\n")); SystemConfiguration->LpsseMMCEnabled = 1; SystemConfiguration->LpsseMMC45Enabled = 0; } else if (SystemConfiguration->eMMCBootMode == 3) { // eMMC 4.5 DEBUG ((EFI_D_ERROR, "Force to eMMC 4.5 GPIO Configuration\n")); SystemConfiguration->LpsseMMCEnabled = 0; SystemConfiguration->LpsseMMC45Enabled = 1; } else { // Disable eMMC controllers DEBUG ((EFI_D_ERROR, "Disable eMMC GPIO controllers\n")); SystemConfiguration->LpsseMMCEnabled = 0; SystemConfiguration->LpsseMMC45Enabled = 0; } /* 20.1.1 EMMC SDMMC1_CLK - write 0x2003ED01 to IOBASE + 0x03E0 SDMMC1_CMD - write 0x2003EC81 to IOBASE + 0x0390 SDMMC1_D0 - write 0x2003EC81 to IOBASE + 0x03D0 SDMMC1_D1 - write 0x2003EC81 to IOBASE + 0x0400 SDMMC1_D2 - write 0x2003EC81 to IOBASE + 0x03B0 SDMMC1_D3_CD_B - write 0x2003EC81 to IOBASE + 0x0360 MMC1_D4_SD_WE - write 0x2003EC81 to IOBASE + 0x0380 MMC1_D5 - write 0x2003EC81 to IOBASE + 0x03C0 MMC1_D6 - write 0x2003EC81 to IOBASE + 0x0370 MMC1_D7 - write 0x2003EC81 to IOBASE + 0x03F0 MMC1_RESET_B - write 0x2003ED01 to IOBASE + 0x0330 */ if (SystemConfiguration->LpsseMMCEnabled== 1) { MmioWrite32 (IO_BASE_ADDRESS + 0x03E0, 0x2003ED01); //EMMC 4.41 MmioWrite32 (IO_BASE_ADDRESS + 0x0390, 0x2003EC81); MmioWrite32 (IO_BASE_ADDRESS + 0x03D0, 0x2003EC81); MmioWrite32 (IO_BASE_ADDRESS + 0x0400, 0x2003EC81); MmioWrite32 (IO_BASE_ADDRESS + 0x03B0, 0x2003EC81); MmioWrite32 (IO_BASE_ADDRESS + 0x0360, 0x2003EC81); MmioWrite32 (IO_BASE_ADDRESS + 0x0380, 0x2003EC81); MmioWrite32 (IO_BASE_ADDRESS + 0x03C0, 0x2003EC81); MmioWrite32 (IO_BASE_ADDRESS + 0x0370, 0x2003EC81); MmioWrite32 (IO_BASE_ADDRESS + 0x03F0, 0x2003EC81); MmioWrite32 (IO_BASE_ADDRESS + 0x0330, 0x2003ED01); } /* eMMC 4.5 controller SDMMC1_CLK - write 0x2003ED03 to IOBASE + 0x03E0 SDMMC1_CMD - write 0x2003EC83 to IOBASE + 0x0390 SDMMC1_D0 - write 0x2003EC83 to IOBASE + 0x03D0 SDMMC1_D1 - write 0x2003EC83 to IOBASE + 0x0400 SDMMC1_D2 - write 0x2003EC83 to IOBASE + 0x03B0 SDMMC1_D3_CD_B - write 0x2003EC83 to IOBASE + 0x0360 MMC1_D4_SD_WE - write 0x2003EC83 to IOBASE + 0x0380 MMC1_D5 - write 0x2003EC83 to IOBASE + 0x03C0 MMC1_D6 - write 0x2003EC83 to IOBASE + 0x0370 MMC1_D7 - write 0x2003EC83 to IOBASE + 0x03F0 MMC1_RESET_B - write 0x2003ED03 to IOBASE + 0x0330 */ if (SystemConfiguration->LpsseMMC45Enabled== 1) { MmioWrite32 (IO_BASE_ADDRESS + 0x03E0, 0x2003ED03); // EMMC 4.5 MmioWrite32 (IO_BASE_ADDRESS + 0x0390, 0x2003EC83); MmioWrite32 (IO_BASE_ADDRESS + 0x03D0, 0x2003EC83); MmioWrite32 (IO_BASE_ADDRESS + 0x0400, 0x2003EC83); MmioWrite32 (IO_BASE_ADDRESS + 0x03B0, 0x2003EC83); MmioWrite32 (IO_BASE_ADDRESS + 0x0360, 0x2003EC83); MmioWrite32 (IO_BASE_ADDRESS + 0x0380, 0x2003EC83); MmioWrite32 (IO_BASE_ADDRESS + 0x03C0, 0x2003EC83); MmioWrite32 (IO_BASE_ADDRESS + 0x0370, 0x2003EC83); MmioWrite32 (IO_BASE_ADDRESS + 0x03F0, 0x2003EC83); MmioWrite32 (IO_BASE_ADDRESS + 0x0330, 0x2003ED03); } // // Change GPIOC_0 setting to allow MMIO access under Android. // IoWrite32 (GPIO_BASE_ADDRESS + R_PCH_GPIO_SC_USE_SEL, (IoRead32(GPIO_BASE_ADDRESS + R_PCH_GPIO_SC_USE_SEL) & (UINT32)~BIT0)); DEBUG ((EFI_D_ERROR, "ConfigureSoCGpio------------end\n")); return EFI_SUCCESS; }
EFI_STATUS EnableAcpiCallback ( IN EFI_HANDLE DispatchHandle, IN CONST VOID *DispatchContext, IN OUT VOID *CommBuffer, IN OUT UINTN *CommBufferSize ) /*++ Routine Description: SMI handler to enable ACPI mode Dispatched on reads from APM port with value 0xA0 Disables the SW SMI Timer. ACPI events are disabled and ACPI event status is cleared. SCI mode is then enabled. Disable SW SMI Timer Clear all ACPI event status and disable all ACPI events Disable PM sources except power button Clear status bits Disable GPE0 sources Clear status bits Disable GPE1 sources Clear status bits Guarantee day-of-month alarm is invalid (ACPI 1.0 section 4.7.2.4) Enable SCI Arguments: DispatchHandle - EFI Handle DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT Returns: Nothing --*/ { EFI_STATUS Status; UINT32 SmiEn; UINT16 Pm1Cnt; UINT8 Data8; Status = GetAllQncPmBase (gSmst); ASSERT_EFI_ERROR (Status); SmiEn = IoRead32 (mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_SMIE); // // Disable SW SMI Timer // SmiEn &= ~(B_QNC_GPE0BLK_SMIE_SWT); IoWrite32 (mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_SMIE, SmiEn); // // Guarantee day-of-month alarm is invalid (ACPI 1.0 section 4.7.2.4) // Data8 = RTC_ADDRESS_REGISTER_D; IoWrite8 (R_IOPORT_CMOS_STANDARD_INDEX, Data8); Data8 = 0x0; IoWrite8 (R_IOPORT_CMOS_STANDARD_DATA, Data8); // // Enable SCI // Pm1Cnt = IoRead16 (mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1C); Pm1Cnt |= B_QNC_PM1BLK_PM1C_SCIEN; IoWrite16 (mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1C, Pm1Cnt); // // Do platform specific stuff for ACPI enable SMI // return EFI_SUCCESS; }
/** Write I/O registers. @param[in] PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation. @param[in] This Pointer to local data for the interface. @param[in] Width The width of the access. Enumerated in bytes. @param[in] Address The physical address of the access. @param[in] Count The number of accesses to perform. @param[in] Buffer A pointer to the buffer of data. @retval EFI_SUCCESS The function completed successfully. @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system. @retval EFI_INVALID_PARAMETER Buffer is NULL. @retval EFI_UNSUPPORTED The address range specified by Address, Width, and Count is not valid for this EFI system. **/ EFI_STATUS EFIAPI CpuIoServiceWrite ( IN CONST EFI_PEI_SERVICES **PeiServices, IN CONST EFI_PEI_CPU_IO_PPI *This, IN EFI_PEI_CPU_IO_PPI_WIDTH Width, IN UINT64 Address, IN UINTN Count, IN VOID *Buffer ) { EFI_STATUS Status; UINT8 InStride; UINT8 OutStride; EFI_PEI_CPU_IO_PPI_WIDTH OperationWidth; BOOLEAN Aligned; UINT8 *Uint8Buffer; // // Make sure the parameters are valid // Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer); if (EFI_ERROR (Status)) { return Status; } // // Select loop based on the width of the transfer // InStride = mInStride[Width]; OutStride = mOutStride[Width]; OperationWidth = (EFI_PEI_CPU_IO_PPI_WIDTH) (Width & 0x03); // // Fifo operations supported for (mInStride[Width] == 0) // if (InStride == 0) { switch (OperationWidth) { case EfiPeiCpuIoWidthUint8: IoWriteFifo8 ((UINTN)Address, Count, Buffer); return EFI_SUCCESS; case EfiPeiCpuIoWidthUint16: IoWriteFifo16 ((UINTN)Address, Count, Buffer); return EFI_SUCCESS; case EfiPeiCpuIoWidthUint32: IoWriteFifo32 ((UINTN)Address, Count, Buffer); return EFI_SUCCESS; default: // // The CpuIoCheckParameter call above will ensure that this // path is not taken. // ASSERT (FALSE); break; } } Aligned = (BOOLEAN)(((UINTN)Buffer & (mInStride[OperationWidth] - 1)) == 0x00); for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { if (OperationWidth == EfiPeiCpuIoWidthUint8) { IoWrite8 ((UINTN)Address, *Uint8Buffer); } else if (OperationWidth == EfiPeiCpuIoWidthUint16) { if (Aligned) { IoWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer)); } else { IoWrite16 ((UINTN)Address, ReadUnaligned16 ((UINT16 *)Uint8Buffer)); } } else if (OperationWidth == EfiPeiCpuIoWidthUint32) { if (Aligned) { IoWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer)); } else { IoWrite32 ((UINTN)Address, ReadUnaligned32 ((UINT32 *)Uint8Buffer)); } } } return EFI_SUCCESS; }
// ------------------------------------------------------------------------------------------------ uint8 PciRead8(uint32 id, uint32 reg) { uint32 addr = 0x80000000 | id | (reg & 0xfc); IoWrite32(PCI_CONFIG_ADDR, addr); return inportb(PCI_CONFIG_DATA + (reg & 0x03)); }
/** This function is IO instruction handler for SMM. @param Index CPU index **/ VOID SmmIoHandler ( IN UINT32 Index ) { VM_EXIT_QUALIFICATION Qualification; UINT16 Port; UINTN *DataPtr; UINTN LinearAddr; X86_REGISTER *Reg; STM_RSC_IO_DESC *IoDesc; STM_RSC_PCI_CFG_DESC *PciCfgDesc; UINT32 PciAddress; STM_RSC_IO_DESC LocalIoDesc; STM_RSC_PCI_CFG_DESC *LocalPciCfgDescPtr; UINT8 LocalPciCfgDescBuf[STM_LOG_ENTRY_SIZE]; Reg = &mGuestContextCommonSmm.GuestContextPerCpu[Index].Register; Qualification.UintN = VmReadN (VMCS_N_RO_EXIT_QUALIFICATION_INDEX); if (Qualification.IoInstruction.Operand != 0) { Port = (UINT16)Qualification.IoInstruction.PortNum; } else { Port = (UINT16)Reg->Rdx; } DataPtr = (UINTN *)&Reg->Rax; // // We need handle case that CF9 is protected, but CF8, CFC need to be pass-through. // But DWORD CF8 programming will be caught here. // So add check here. CF8 will be bypassed, because it does not in CF9 scope. // IoDesc = GetStmResourceIo (mHostContextCommon.MleProtectedResource.Base, Port); if (IoDesc != NULL) { DEBUG ((EFI_D_ERROR, "IO violation!\n")); AddEventLogForResource (EvtHandledProtectionException, (STM_RSC *)IoDesc); SmmExceptionHandler (Index); CpuDeadLoop (); } IoDesc = GetStmResourceIo ((STM_RSC *)(UINTN)mGuestContextCommonSmm.BiosHwResourceRequirementsPtr, Port); if (IoDesc == NULL) { ZeroMem (&LocalIoDesc, sizeof(LocalIoDesc)); LocalIoDesc.Hdr.RscType = IO_RANGE; LocalIoDesc.Hdr.Length = sizeof(LocalIoDesc); LocalIoDesc.Base = Port; LocalIoDesc.Length = (UINT16)(Qualification.IoInstruction.Size + 1); AddEventLogForResource (EvtBiosAccessToUnclaimedResource, (STM_RSC *)&LocalIoDesc); } // // Check PCI - 0xCF8, 0xCFC~0xCFF access // if (Port == 0xCF8) { // Access PciAddress // // We need make sure PciAddress access and PciData access is atomic. // AcquireSpinLock (&mHostContextCommon.PciLock); } if ((Port >= 0xCFC) && (Port <= 0xCFF)) { // Access PciData // // AcquireLock to prevent 0xCF8 access // AcquireSpinLock (&mHostContextCommon.PciLock); PciAddress = IoRead32 (0xCF8); PciCfgDesc = GetStmResourcePci ( mHostContextCommon.MleProtectedResource.Base, BUS_FROM_CF8_ADDRESS(PciAddress), DEVICE_FROM_CF8_ADDRESS(PciAddress), FUNCTION_FROM_CF8_ADDRESS(PciAddress), REGISTER_FROM_CF8_ADDRESS(PciAddress) + (Port & 0x3), (Qualification.IoInstruction.Direction != 0) ? STM_RSC_PCI_CFG_R : STM_RSC_PCI_CFG_W ); if (PciCfgDesc != NULL) { DEBUG ((EFI_D_ERROR, "IO (PCI) violation!\n")); AddEventLogForResource (EvtHandledProtectionException, (STM_RSC *)PciCfgDesc); ReleaseSpinLock (&mHostContextCommon.PciLock); SmmExceptionHandler (Index); CpuDeadLoop (); } PciCfgDesc = GetStmResourcePci ( (STM_RSC *)(UINTN)mGuestContextCommonSmm.BiosHwResourceRequirementsPtr, BUS_FROM_CF8_ADDRESS(PciAddress), DEVICE_FROM_CF8_ADDRESS(PciAddress), FUNCTION_FROM_CF8_ADDRESS(PciAddress), REGISTER_FROM_CF8_ADDRESS(PciAddress) + (Port & 0x3), (Qualification.IoInstruction.Direction != 0) ? STM_RSC_PCI_CFG_R : STM_RSC_PCI_CFG_W ); if (PciCfgDesc == NULL) { DEBUG((EFI_D_ERROR, "Add unclaimed PCI_RSC!\n")); LocalPciCfgDescPtr = (STM_RSC_PCI_CFG_DESC *)LocalPciCfgDescBuf; ZeroMem (LocalPciCfgDescBuf, sizeof(LocalPciCfgDescBuf)); LocalPciCfgDescPtr->Hdr.RscType = PCI_CFG_RANGE; LocalPciCfgDescPtr->Hdr.Length = sizeof(STM_RSC_PCI_CFG_DESC); // BUGBUG: Just report this PCI device, it is hard to create PCI hierachy here. LocalPciCfgDescPtr->RWAttributes = (Qualification.IoInstruction.Direction != 0) ? STM_RSC_PCI_CFG_R : STM_RSC_PCI_CFG_W; LocalPciCfgDescPtr->Base = REGISTER_FROM_CF8_ADDRESS(PciAddress) + (Port & 0x3); LocalPciCfgDescPtr->Length = (UINT16)(Qualification.IoInstruction.Size + 1); LocalPciCfgDescPtr->OriginatingBusNumber = BUS_FROM_CF8_ADDRESS(PciAddress); LocalPciCfgDescPtr->LastNodeIndex = 0; LocalPciCfgDescPtr->PciDevicePath[0].Type = 1; LocalPciCfgDescPtr->PciDevicePath[0].Subtype = 1; LocalPciCfgDescPtr->PciDevicePath[0].Length = sizeof(STM_PCI_DEVICE_PATH_NODE); LocalPciCfgDescPtr->PciDevicePath[0].PciFunction = FUNCTION_FROM_CF8_ADDRESS(PciAddress); LocalPciCfgDescPtr->PciDevicePath[0].PciDevice = DEVICE_FROM_CF8_ADDRESS(PciAddress); AddEventLogForResource (EvtBiosAccessToUnclaimedResource, (STM_RSC *)LocalPciCfgDescPtr); } } if (Qualification.IoInstruction.Rep != 0) { UINT64 RcxMask; RcxMask = 0xFFFFFFFFFFFFFFFFull; if ((mGuestContextCommonSmm.GuestContextPerCpu[Index].Efer & IA32_EFER_MSR_MLA) == 0) { RcxMask = 0xFFFFFFFFull; } if ((Reg->Rcx & RcxMask) == 0) { // Skip if ((Port == 0xCF8) || ((Port >= 0xCFC) && (Port <= 0xCFF))) { ReleaseSpinLock (&mHostContextCommon.PciLock); } VmWriteN (VMCS_N_GUEST_RIP_INDEX, VmReadN(VMCS_N_GUEST_RIP_INDEX) + VmRead32(VMCS_32_RO_VMEXIT_INSTRUCTION_LENGTH_INDEX)); return ; } } if (Qualification.IoInstruction.String != 0) { LinearAddr = VmReadN (VMCS_N_RO_GUEST_LINEAR_ADDR_INDEX); if (VmReadN (VMCS_N_GUEST_CR0_INDEX) & CR0_PG) { DataPtr = (UINTN *)(UINTN)GuestLinearToHostPhysical (Index, LinearAddr); } else { DataPtr = (UINTN *)LinearAddr; } if ((VmReadN (VMCS_N_GUEST_RFLAGS_INDEX) & RFLAGS_DF) != 0) { if (Qualification.IoInstruction.Direction != 0) { Reg->Rdi -= Qualification.IoInstruction.Size + 1; } else { Reg->Rsi -= Qualification.IoInstruction.Size + 1; } } else { if (Qualification.IoInstruction.Direction != 0) { Reg->Rdi += Qualification.IoInstruction.Size + 1; } else { Reg->Rsi += Qualification.IoInstruction.Size + 1; } } } if (Qualification.IoInstruction.Direction != 0) { // IN switch (Qualification.IoInstruction.Size) { case 0: *(UINT8 *)DataPtr = IoRead8 (Port); goto Ret; break; case 1: *(UINT16 *)DataPtr = IoRead16 (Port); goto Ret; break; case 3: *(UINT32 *)DataPtr = IoRead32 (Port); goto Ret; break; default: break; } } else { // OUT switch (Qualification.IoInstruction.Size) { case 0: IoWrite8 (Port, (UINT8)*DataPtr); goto Ret; break; case 1: IoWrite16 (Port, (UINT16)*DataPtr); goto Ret; break; case 3: IoWrite32 (Port, (UINT32)*DataPtr); goto Ret; break; default: break; } } if ((Port == 0xCF8) || ((Port >= 0xCFC) && (Port <= 0xCFF))) { ReleaseSpinLock (&mHostContextCommon.PciLock); } DEBUG ((EFI_D_INFO, "!!!IoHandler!!!\n")); DumpVmcsAllField (); CpuDeadLoop (); Ret: if ((Port == 0xCF8) || ((Port >= 0xCFC) && (Port <= 0xCFF))) { ReleaseSpinLock (&mHostContextCommon.PciLock); } if (Qualification.IoInstruction.Rep != 0) { // replay Reg->Rcx --; return ; } VmWriteN (VMCS_N_GUEST_RIP_INDEX, VmReadN(VMCS_N_GUEST_RIP_INDEX) + VmRead32(VMCS_32_RO_VMEXIT_INSTRUCTION_LENGTH_INDEX)); return ; }
// ------------------------------------------------------------------------------------------------ uint16 PciRead16(uint32 id, uint32 reg) { uint32 addr = 0x80000000 | id | (reg & 0xfc); IoWrite32(PCI_CONFIG_ADDR, addr); return IoRead16(PCI_CONFIG_DATA + (reg & 0x02)); }