/** Wait for an RTC update to happen **/ VOID EFIAPI WaitForRTCUpdate ( VOID ) { UINT8 Data8; IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A); Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER); if ((Data8 & BIT7) == BIT7) { while ((Data8 & BIT7) == BIT7) { IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A); Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER); } } else { while ((Data8 & BIT7) == 0) { IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A); Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER); } while ((Data8 & BIT7) == BIT7) { IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A); Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER); } } }
EFI_STATUS AcquireBus ( UINT16 SmbusBase ) { UINT8 StsReg; StsReg = 0; StsReg = (UINT8)IoRead8(SmbusBase + R_PCH_SMBUS_HSTS); if (StsReg & B_PCH_SMBUS_IUS) { return EFI_DEVICE_ERROR; } else if (StsReg & B_PCH_SMBUS_HBSY) { // // Clear Status Register and exit // // Wait for HSTS.HBSY to be clear // do { StsReg = (UINT8) IoRead8(SmbusBase+R_PCH_SMBUS_HSTS); } while ((StsReg & B_PCH_SMBUS_HBSY) != 0); // // Clear all status bits // IoWrite8(SmbusBase+R_PCH_SMBUS_HSTS, 0xFE); return EFI_SUCCESS; } else { // // Clear out any odd status information (Will Not Clear In Use) // IoWrite8(SmbusBase+R_PCH_SMBUS_HSTS, StsReg); return EFI_SUCCESS; } }
/** I/O work flow of in 8042 data. @param Data Data value @retval EFI_SUCCESS Success to excute I/O work flow @retval EFI_TIMEOUT Keyboard controller time out. **/ EFI_STATUS In8042Data ( IN OUT UINT8 *Data ) { UINTN Delay; Delay = TIMEOUT / 50; do { // // Check keyboard controller status bit 0(output buffer status) // if ((IoRead8 (KBC_CMD_STS_PORT) & KBC_OUTB) == KBC_OUTB) { break; } gBS->Stall (50); Delay--; } while (Delay != 0); if (Delay == 0) { return EFI_TIMEOUT; } *Data = IoRead8 (KBC_DATA_PORT); return EFI_SUCCESS; }
UINT8 RtcRead ( IN UINT8 Address ) { IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8) (Address | (UINT8) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & 0x80))); return IoRead8 (PCAT_RTC_DATA_REGISTER); }
UINT16 ReadPmio16 ( IN UINT8 Index ) { UINT8 bTemp; IoWrite8 (FCH_IOMAP_REGCD6, Index); bTemp = IoRead8 (FCH_IOMAP_REGCD7); IoWrite8 (FCH_IOMAP_REGCD6, Index + 1); return (UINT16) ((IoRead8 (FCH_IOMAP_REGCD7) << 8) + bTemp); }
/** Receives data from Keyboard System Controller. @param Data Data byte received @retval EFI_SUCCESS Read success @retval EFI_DEVICE_ERROR Read error **/ EFI_STATUS ReceiveKscData ( UINT8 *Data ) { UINTN Index; UINT8 KscStatus; Index = 0; // // Wait for KSC to be ready (with a timeout) // ReceiveKscStatus (&KscStatus); while (((KscStatus & KSC_S_OBF) == 0) && (Index < KSC_TIME_OUT)) { gBS->Stall (15); ReceiveKscStatus (&KscStatus); Index++; } if (Index >= KSC_TIME_OUT) { return EFI_DEVICE_ERROR; } // // Read KSC data and return // *Data = IoRead8(KSC_D_PORT); return EFI_SUCCESS; }
/** Read from IO space Argv[0] - "ioread"[.#] # is optional width 1, 2, or 4. Default 1 Argv[1] - Hex IO address ior.4 0x3f8 ;Do a 32-bit IO Read from 0x3f8 ior 0x3f8 ;Do a 8-bit IO Read from 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 EblIoReadCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { UINTN Width; UINTN Port; UINTN Data; if (Argc < 2) { return EFI_INVALID_PARAMETER; } Port = AsciiStrHexToUintn (Argv[1]); Width = WidthFromCommandName (Argv[0], 1); if (Width == 1) { Data = IoRead8 (Port); } else if (Width == 2) { Data = IoRead16 (Port); } else if (Width == 4) { Data = IoRead32 (Port); } else { return EFI_INVALID_PARAMETER; } AsciiPrint ("0x%04x = 0x%x", Port, Data); return EFI_SUCCESS; }
/** Reads 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[out] 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 CpuIoServiceRead ( IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This, IN EFI_SMM_IO_WIDTH Width, IN UINT64 Address, IN UINTN Count, OUT VOID *Buffer ) { EFI_STATUS Status; UINT8 Stride; UINT8 *Uint8Buffer; 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 = Buffer; Count > 0; Address += Stride, Uint8Buffer += Stride, Count--) { if (Width == SMM_IO_UINT8) { *Uint8Buffer = IoRead8 ((UINTN)Address); } else if (Width == SMM_IO_UINT16) { *((UINT16 *)Uint8Buffer) = IoRead16 ((UINTN)Address); } else if (Width == SMM_IO_UINT32) { *((UINT32 *)Uint8Buffer) = IoRead32 ((UINTN)Address); } } return EFI_SUCCESS; }
/** I/O work flow to wait output buffer full in given time. @param Timeout given time @retval EFI_TIMEOUT output is not full in given time @retval EFI_SUCCESS output is full in given time. **/ EFI_STATUS WaitOutputFull ( IN UINTN Timeout ) { UINTN Delay; UINT8 Data; Delay = Timeout / 50; do { Data = IoRead8 (KBC_CMD_STS_PORT); // // Check keyboard controller status bit 0(output buffer status) // & bit5(output buffer for auxiliary device) // if ((Data & (KBC_OUTB | KBC_AUXB)) == (KBC_OUTB | KBC_AUXB)) { break; } gBS->Stall (50); Delay--; } while (Delay != 0); if (Delay == 0) { return EFI_TIMEOUT; } return EFI_SUCCESS; }
/** I/O work flow to wait input buffer empty in given time. @param Timeout Wating time. @retval EFI_TIMEOUT if input is still not empty in given time. @retval EFI_SUCCESS input is empty. **/ EFI_STATUS WaitInputEmpty ( IN UINTN Timeout ) { UINTN Delay; UINT8 Data; Delay = Timeout / 50; do { Data = IoRead8 (KBC_CMD_STS_PORT); // // Check keyboard controller status bit 1(input buffer status) // if ((Data & KBC_INPB) == 0) { break; } gBS->Stall (50); Delay--; } while (Delay != 0); if (Delay == 0) { return EFI_TIMEOUT; } return EFI_SUCCESS; }
VOID SwGetContext( IN DATABASE_RECORD *Record, OUT QNC_SMM_CONTEXT *Context ) { Context->Sw.SwSmiInputValue = IoRead8 (R_APM_CNT); }
/** Gets the software SMI data. This function tests if a software SMM interrupt happens. If a software SMI happens, it retrieves the SMM data and returns it as a non-negative value; otherwise a negative value is returned. @return Data The data retrieved from SMM data port in case of a software SMI; otherwise a negative value. **/ INTN InternalGetSwSmiData ( VOID ) { UINT8 SmiStatus; UINT8 Data; SmiStatus = IoRead8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS); if (((SmiStatus & B_QNC_GPE0BLK_SMIS_APM) != 0) && (IoRead8 (PcdGet16 (PcdSmmActivationPort)) == PcdGet8 (PcdSmmActivationData))) { Data = IoRead8 (PcdGet16 (PcdSmmDataPort)); return (INTN)(UINTN)Data; } return -1; }
VOID RtcWrite ( IN UINT8 Address, IN UINT8 Data ) { IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8) (Address | (UINT8) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & 0x80))); IoWrite8 (PCAT_RTC_DATA_REGISTER, Data); }
/** Reads 8-bits of CMOS data. Reads the 8-bits of CMOS data at the location specified by Index. The 8-bit read value is returned. @param Index The CMOS location to read. @return The value read. **/ UINT8 EFIAPI CmosRead8 ( IN UINTN Index ) { IoWrite8 (0x70, (UINT8) Index); return IoRead8 (0x71); }
/** 8-bit I/O read 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. @return An 8-bit value returned from the I/O space. **/ UINT8 EFIAPI CpuIoRead8 ( IN CONST EFI_PEI_SERVICES **PeiServices, IN CONST EFI_PEI_CPU_IO_PPI *This, IN UINT64 Address ) { return IoRead8 ((UINTN)Address); }
void Turn_On_5V_DAUL_USBKB_Power() { //Switch +5V_DAUL_USBKB to standby power UINT8 Reg = 0; IoWrite8(NCT6791D_CONFIG_INDEX, 0x87); IoWrite8(NCT6791D_CONFIG_INDEX, 0x87); IoWrite8(NCT6791D_CONFIG_INDEX, 0x07); IoWrite8(NCT6791D_CONFIG_DATA, 0x07); IoWrite8(NCT6791D_CONFIG_INDEX, 0x30); Reg = IoRead8(NCT6791D_CONFIG_DATA); Reg |= BIT1; //Active GPIO7 Group IoWrite8(NCT6791D_CONFIG_DATA, Reg); IoWrite8(NCT6791D_CONFIG_INDEX, 0xE0); Reg = IoRead8(NCT6791D_CONFIG_DATA); Reg &= ~BIT2; //Set GPIO72 to output IoWrite8(NCT6791D_CONFIG_DATA, Reg); IoWrite8(NCT6791D_CONFIG_INDEX, 0xE1); Reg = IoRead8(NCT6791D_CONFIG_DATA); Reg |= BIT2; //Set GPIO72 to output High IoWrite8(NCT6791D_CONFIG_DATA, Reg); IoWrite8(NCT6791D_CONFIG_INDEX, 0x07); IoWrite8(NCT6791D_CONFIG_DATA, 0x0F); IoWrite8(NCT6791D_CONFIG_INDEX, 0xE6); Reg = IoRead8(NCT6791D_CONFIG_DATA); Reg &= ~BIT2; //Set GPIO72 to Push-Pull IoWrite8(NCT6791D_CONFIG_DATA, Reg); IoWrite8(NCT6791D_CONFIG_INDEX, 0x1D); //SET GP54 TO PWROK Reg = IoRead8(NCT6791D_CONFIG_DATA); Reg &= ~(BIT1+BIT2+BIT3); IoWrite8(NCT6791D_CONFIG_INDEX, 0x1D); IoWrite8(NCT6791D_CONFIG_DATA, Reg|(BIT3+BIT2)); IoWrite8(NCT6791D_CONFIG_INDEX, 0xaa); }
UINT8 ReadCmosBank1Byte ( IN UINT8 Index ) { UINT8 Data; IoWrite8(0x72, Index); Data = IoRead8 (0x73); return Data; }
VOID InitializeSio ( VOID ) { UINT16 Index; UINT16 IndexPort; UINT16 DataPort; // // Super I/O initialization for Winbond WPCN381U // IndexPort = WPCN381U_CONFIG_INDEX; DataPort = WPCN381U_CONFIG_DATA; // // Check for Winbond WPCN381U // IoWrite8 (IndexPort, WPCN381U_DEV_ID_REGISTER); // Winbond WPCN381U Device ID register is 0x20 if (IoRead8 (DataPort) == WPCN381U_CHIP_ID) { // Winbond WPCN381U Device ID is 0xF4 // // Configure WPCN381U SIO // for (Index = 0; Index < sizeof (mSioTableWpcn381u) / sizeof (EFI_SIO_TABLE); Index++) { IoWrite8 (IndexPort, mSioTableWpcn381u[Index].Register); IoWrite8 (DataPort, mSioTableWpcn381u[Index].Value); } } if (IoRead8 (DataPort) == WDCP376_CHIP_ID) { // Winbond WDCP376 Device ID is 0xF1 // // Configure WDCP376 SIO // for (Index = 0; Index < sizeof (mSioTableWdcp376) / sizeof (EFI_SIO_TABLE); Index++) { IoWrite8 (IndexPort, mSioTableWdcp376[Index].Register); IoWrite8 (DataPort, mSioTableWdcp376[Index].Value); } } return; }
/** Receives status from Keyboard System Controller. @param Status Status byte to receive @retval EFI_SUCCESS Always success **/ EFI_STATUS ReceiveKscStatus ( UINT8 *KscStatus ) { // // Read and return the status // *KscStatus = IoRead8(KSC_C_PORT); return EFI_SUCCESS; }
/** Reads 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[out] 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 CpuIoServiceRead ( 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, OUT VOID *Buffer ) { EFI_STATUS Status; UINT8 InStride; UINT8 OutStride; EFI_PEI_CPU_IO_PPI_WIDTH OperationWidth; BOOLEAN Aligned; UINT8 *Uint8Buffer; 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 = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { if (OperationWidth == EfiPeiCpuIoWidthUint8) { *Uint8Buffer = IoRead8 ((UINTN)Address); } else if (OperationWidth == EfiPeiCpuIoWidthUint16) { if (Aligned) { *((UINT16 *)Uint8Buffer) = IoRead16 ((UINTN)Address); } else { WriteUnaligned16 ((UINT16 *)Uint8Buffer, IoRead16 ((UINTN)Address)); } } else if (OperationWidth == EfiPeiCpuIoWidthUint32) { if (Aligned) { *((UINT32 *)Uint8Buffer) = IoRead32 ((UINTN)Address); } else { WriteUnaligned32 ((UINT32 *)Uint8Buffer, IoRead32 ((UINTN)Address)); } } } return EFI_SUCCESS; }
/** Initialize the library. Read KSC Command port (0x66), if found 0xff means no EC exists else EC exists @return EFI_SUCCESS KscLib is successfully initialized. **/ EFI_STATUS InitializeKscLib ( VOID ) { if (IoRead8(KSC_C_PORT) == 0xff) { mDxeKscLibInitialized = FALSE; return EFI_DEVICE_ERROR; // EC Doesn't exists } mDxeKscLibInitialized = TRUE; return EFI_SUCCESS; // EC exists }
/** Check keyboard controller status, if it is output buffer full and for auxiliary device. @retval EFI_SUCCESS Keyboard controller is ready @retval EFI_NOT_READY Keyboard controller is not ready **/ EFI_STATUS CheckForInput ( VOID ) { UINT8 Data; Data = IoRead8 (KBC_CMD_STS_PORT); // // Check keyboard controller status, if it is output buffer full and for auxiliary device // if ((Data & (KBC_OUTB | KBC_AUXB)) != (KBC_OUTB | KBC_AUXB)) { return EFI_NOT_READY; } return EFI_SUCCESS; }
/** I/O work flow of in 8042 Aux data. @param Data Buffer holding return value. @retval EFI_SUCCESS Success to excute I/O work flow @retval EFI_TIMEOUT Keyboard controller time out. **/ EFI_STATUS In8042AuxData ( IN OUT UINT8 *Data ) { EFI_STATUS Status; // // wait for output data // Status = WaitOutputFull (BAT_TIMEOUT); if (EFI_ERROR (Status)) { return Status; } *Data = IoRead8 (KBC_DATA_PORT); return EFI_SUCCESS; }
/** Read data via IsaIo protocol with given number. @param Buffer Buffer receive data of mouse @param BufSize The size of buffer @param State Check input or read data @return status of reading mouse data. **/ EFI_STATUS PS2MouseRead ( OUT UINT8 *Buffer, IN OUT UINTN *BufSize, IN UINTN State ) { EFI_STATUS Status; UINTN BytesRead; Status = EFI_SUCCESS; if (State == PS2_READ_BYTE_ONE) { // // Check input for mouse // Status = CheckForInput (); if (EFI_ERROR (Status)) { return Status; } } for (BytesRead = 0; BytesRead < *BufSize; BytesRead++) { Status = WaitOutputFull (TIMEOUT); if (EFI_ERROR (Status)) { break; } Buffer[BytesRead] = IoRead8 (KBC_DATA_PORT); } // // Verify the correct number of bytes read // if (BytesRead == 0 || BytesRead != *BufSize) { Status = EFI_NOT_FOUND; } *BufSize = BytesRead; return Status; }
/** Reads 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[out] 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 CpuIoServiceRead ( IN EFI_CPU_IO2_PROTOCOL *This, IN EFI_CPU_IO_PROTOCOL_WIDTH Width, IN UINT64 Address, IN UINTN Count, OUT VOID *Buffer ) { EFI_STATUS Status; UINT8 InStride; UINT8 OutStride; EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth; UINT8 *Uint8Buffer; 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 = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { if (OperationWidth == EfiCpuIoWidthUint8) { *Uint8Buffer = IoRead8 ((UINTN)Address); } else if (OperationWidth == EfiCpuIoWidthUint16) { *((UINT16 *)Uint8Buffer) = IoRead16 ((UINTN)Address); } else if (OperationWidth == EfiCpuIoWidthUint32) { *((UINT32 *)Uint8Buffer) = IoRead32 ((UINTN)Address); } } return EFI_SUCCESS; }
BOOLEAN IsRtcUipAlwaysSet ( IN CONST EFI_PEI_SERVICES **PeiServices ) { EFI_PEI_STALL_PPI *StallPpi; UINTN Count; (**PeiServices).LocatePpi (PeiServices, &gEfiPeiStallPpiGuid, 0, NULL, (void **)&StallPpi); for (Count = 0; Count < 500; Count++) { // Maximum waiting approximates to 1.5 seconds (= 3 msec * 500) IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_REGISTERA); if ((IoRead8 (R_PCH_RTC_TARGET2) & B_PCH_RTC_REGISTERA_UIP) == 0) { return FALSE; } StallPpi->Stall (PeiServices, StallPpi, 3000); } return TRUE; }
/** 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 ; }
/** Reads 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[out] 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 CpuIoServiceRead ( 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, OUT VOID *Buffer ) { EFI_STATUS Status; UINT8 InStride; UINT8 OutStride; EFI_PEI_CPU_IO_PPI_WIDTH OperationWidth; BOOLEAN Aligned; UINT8 *Uint8Buffer; 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: IoReadFifo8 ((UINTN)Address, Count, Buffer); return EFI_SUCCESS; case EfiPeiCpuIoWidthUint16: IoReadFifo16 ((UINTN)Address, Count, Buffer); return EFI_SUCCESS; case EfiPeiCpuIoWidthUint32: IoReadFifo32 ((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 = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { if (OperationWidth == EfiPeiCpuIoWidthUint8) { *Uint8Buffer = IoRead8 ((UINTN)Address); } else if (OperationWidth == EfiPeiCpuIoWidthUint16) { if (Aligned) { *((UINT16 *)Uint8Buffer) = IoRead16 ((UINTN)Address); } else { WriteUnaligned16 ((UINT16 *)Uint8Buffer, IoRead16 ((UINTN)Address)); } } else if (OperationWidth == EfiPeiCpuIoWidthUint32) { if (Aligned) { *((UINT32 *)Uint8Buffer) = IoRead32 ((UINTN)Address); } else { WriteUnaligned32 ((UINT32 *)Uint8Buffer, IoRead32 ((UINTN)Address)); } } } return EFI_SUCCESS; }
/** The Page fault handler to save SMM profile data. @param Rip The RIP when exception happens. @param ErrorCode The Error code of exception. **/ VOID SmmProfilePFHandler ( UINTN Rip, UINTN ErrorCode ) { UINT64 *PageTable; UINT64 PFAddress; UINTN CpuIndex; UINTN Index; UINT64 InstructionAddress; UINTN MaxEntryNumber; UINTN CurrentEntryNumber; BOOLEAN IsValidPFAddress; SMM_PROFILE_ENTRY *SmmProfileEntry; UINT64 SmiCommand; EFI_STATUS Status; UINT8 SoftSmiValue; EFI_SMM_SAVE_STATE_IO_INFO IoInfo; if (!mSmmProfileStart) { // // If SMM profile does not start, call original page fault handler. // SmiDefaultPFHandler (); return; } if (mBtsSupported) { DisableBTS (); } IsValidPFAddress = FALSE; PageTable = (UINT64 *)AsmReadCr3 (); PFAddress = AsmReadCr2 (); CpuIndex = GetCpuIndex (); if (PFAddress <= 0xFFFFFFFF) { RestorePageTableBelow4G (PageTable, PFAddress, CpuIndex, ErrorCode); } else { RestorePageTableAbove4G (PageTable, PFAddress, CpuIndex, ErrorCode, &IsValidPFAddress); } if (!IsValidPFAddress) { InstructionAddress = Rip; if ((ErrorCode & IA32_PF_EC_ID) != 0 && (mBtsSupported)) { // // If it is instruction fetch failure, get the correct IP from BTS. // InstructionAddress = GetSourceFromDestinationOnBts (CpuIndex, Rip); if (InstructionAddress == 0) { // // It indicates the instruction which caused page fault is not a jump instruction, // set instruction address same as the page fault address. // InstructionAddress = PFAddress; } } // // Indicate it is not software SMI // SmiCommand = 0xFFFFFFFFFFFFFFFFULL; for (Index = 0; Index < gSmst->NumberOfCpus; Index++) { Status = SmmReadSaveState(&mSmmCpu, sizeof(IoInfo), EFI_SMM_SAVE_STATE_REGISTER_IO, Index, &IoInfo); if (EFI_ERROR (Status)) { continue; } if (IoInfo.IoPort == mSmiCommandPort) { // // A software SMI triggered by SMI command port has been found, get SmiCommand from SMI command port. // SoftSmiValue = IoRead8 (mSmiCommandPort); SmiCommand = (UINT64)SoftSmiValue; break; } } SmmProfileEntry = (SMM_PROFILE_ENTRY *)(UINTN)(mSmmProfileBase + 1); // // Check if there is already a same entry in profile data. // for (Index = 0; Index < (UINTN) mSmmProfileBase->CurDataEntries; Index++) { if ((SmmProfileEntry[Index].ErrorCode == (UINT64)ErrorCode) && (SmmProfileEntry[Index].Address == PFAddress) && (SmmProfileEntry[Index].CpuNum == (UINT64)CpuIndex) && (SmmProfileEntry[Index].Instruction == InstructionAddress) && (SmmProfileEntry[Index].SmiCmd == SmiCommand)) { // // Same record exist, need not save again. // break; } } if (Index == mSmmProfileBase->CurDataEntries) { CurrentEntryNumber = (UINTN) mSmmProfileBase->CurDataEntries; MaxEntryNumber = (UINTN) mSmmProfileBase->MaxDataEntries; if (FeaturePcdGet (PcdCpuSmmProfileRingBuffer)) { CurrentEntryNumber = CurrentEntryNumber % MaxEntryNumber; } if (CurrentEntryNumber < MaxEntryNumber) { // // Log the new entry // SmmProfileEntry[CurrentEntryNumber].SmiNum = mSmmProfileBase->NumSmis; SmmProfileEntry[CurrentEntryNumber].ErrorCode = (UINT64)ErrorCode; SmmProfileEntry[CurrentEntryNumber].ApicId = (UINT64)GetApicId (); SmmProfileEntry[CurrentEntryNumber].CpuNum = (UINT64)CpuIndex; SmmProfileEntry[CurrentEntryNumber].Address = PFAddress; SmmProfileEntry[CurrentEntryNumber].Instruction = InstructionAddress; SmmProfileEntry[CurrentEntryNumber].SmiCmd = SmiCommand; // // Update current entry index and data size in the header. // mSmmProfileBase->CurDataEntries++; mSmmProfileBase->CurDataSize = MultU64x64 (mSmmProfileBase->CurDataEntries, sizeof (SMM_PROFILE_ENTRY)); } } } // // Flush TLB // CpuFlushTlb (); if (mBtsSupported) { EnableBTS (); } }
/** 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 (); } }