//************************************************************************* //************************************************************************* //** ** //** (C)Copyright 1985-2009, American Megatrends, Inc. ** //** ** //** All Rights Reserved. ** //** ** //** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** //** ** //** Phone: (770)-246-8600 ** //** ** //************************************************************************* //************************************************************************* //************************************************************************* // $Header: /Alaska/SOURCE/Core/Library/IO.c 4 7/10/09 3:49p Felixp $ // // $Revision: 4 $ // // $Date: 7/10/09 3:49p $ //************************************************************************* // Revision History // ---------------- // $Log: /Alaska/SOURCE/Core/Library/IO.c $ // // 4 7/10/09 3:49p Felixp // Function headers added // // 3 8/24/06 9:26a Felixp // Preliminary x64 support (work in progress): // 1. Processor architecture specific functions moved to a processor // library // 2. Makefile removed (AmiLib files are build by the AmiPeiLib and // AmeDxeLib makefile) // 3. Tokens.c added // // 2 1/18/05 3:22p Felixp // PrintDebugMessage renamed to Trace // // 1 12/23/04 9:42a Felixp // // 7 4/09/04 12:47p Markw // Fixed IoWrites. // // 6 3/23/04 4:56p Felixp // // 5 3/08/04 5:44p Markw // // // 4 3/05/04 5:48p Markw // Added IoRead, IoWrite, IoRead, MemRead, MemWrite, MemReadWrite to // support BootScript. // // 3 2/20/04 11:37a Felixp // read functions simplified (return value passed via eax) // // 2 2/19/04 1:27p Markw // Added include // // 1 2/19/04 12:54p Markw // //************************************************************************* // // // Name: IO.c // // Description: // Contains generic I/O read/write functions. // // //************************************************************************* #include //************************************************************************* // // // Name: IO_Read_Write_Functions // // Description: // Generic I/O read/write functions. // // Fields: Header Function Description // ------------------------------------------------------------------ // AmiLib IoRead Read value(s) from an I/O address or an entire region. // AmiLib IoRead8 Read 8-bit value from an I/O address. // AmiLib IoRead16 Read 16-bit value from an I/O address. // AmiLib IoRead32 Read 32-bit value from an I/O address. // AmiLib IoReadWrite Read value from an I/O address then write back a value. // AmiLib IoWrite Write buffer to an I/O address or region. // AmiLib IoWrite8 Write 8-bit value to an I/O address. // AmiLib IoWrite16 Write 16-bit value to an I/O address. // AmiLib IoWrite32 Write 32-bit value to an I/O address. // AmiLib MemRead Read value(s) from a memory mapped I/O address or an entire region. // AmiLib MemReadWrite Read value from a memory mapped I/O address then write back a value. // AmiLib MemWrite Write buffer to an I/O address or region. // // Notes: // Header details which header file contains the function prototype for // the above functions. Append .h to the given name. // // //************************************************************************* //************************************************************************* // // // Name: IoRead // // Description: // EFI_STATUS IoRead(IN CPU_IO_WIDTH Width, IN UINT64 Address, // IN UINTN Count, OUT VOID *Buffer) performs Count I/O reads of the defined // Width at the Address and stores the result in Buffer. After every I/O // operation, Address and Buffer are updated according to the Width. See // notes for details. // // Input: // IN CPU_IO_WIDTH Width // Number of bits to read from I/O. Supports at most 32-bits. // // IN UINT64 Address // I/O address to read from. // // IN UINTN Count // Number of reads to perform. // // OUT VOID *Buffer // Buffer where the read results will be stored. User is responsible for // properly allocating the necessary memory resources. // // Output: // EFI_INVALID_PARAMETER, if Count = 0, Width > 32-bits, or the range of // Address > 0xffff. // Otherwise, EFI_SUCCESS. // // Modified: // // Referrals: // IoRead8 // IoRead16 // IoRead32 // // Notes: // Address and Buffer are updated according to the Width as follows: // CpuIoWidthUint8 - Both Address and Buffer are incremented by 1. // CpuIoWidthUint16 - Both Address and Buffer are incremented by 2. // CpuIoWidthUint32 - Both Address and Buffer are incremented by 4. // CpuIoWidthFifoUint8 - Only Buffer is incremented by 1. // CpuIoWidthFifoUint16 - Only Buffer is incremented by 2. // CpuIoWidthFifoUint32 - Only Buffer is incremented by 4. // CpuIoWidthFillUint8 - Only Address is incremented by 1. // CpuIoWidthFillUint16 - Only Address is incremented by 2. // CpuIoWidthFillUint32 - Only Address is incremented by 4. // // //************************************************************************* EFI_STATUS IoRead( IN CPU_IO_WIDTH Width, IN UINT64 Address, IN UINTN Count, IN VOID *Buffer ) { UINT8 ValueWidth = 1 << (Width & 3); UINT8 AddrInc, BuffInc; UINTN AddrCount; AddrInc = BuffInc = ValueWidth; switch (Width & ~3) { case CpuIoWidthFifoUint8: AddrInc = 0; break; case CpuIoWidthFillUint8: BuffInc = 0; break; } AddrCount = (Count-1) * AddrInc + ValueWidth; //---Validate Inputs--- if (!Count) return EFI_INVALID_PARAMETER; if (Address + AddrCount > 0xffff) return EFI_INVALID_PARAMETER; if ((Width & 3) > CpuIoWidthUint32) return EFI_INVALID_PARAMETER; while (Count--) { switch(Width & 3) { case CpuIoWidthUint8: *(UINT8*)Buffer = IoRead8((UINT16)Address); break; case CpuIoWidthUint16: *(UINT16*)Buffer = IoRead16((UINT16)Address); break; default: *(UINT32*)Buffer = IoRead32((UINT16)Address); } Address = Address + AddrInc; Buffer = (UINT8*) Buffer + BuffInc; } return EFI_SUCCESS; } //************************************************************************* // // // Name: IoWrite // // Description: // EFI_STATUS IoWrite(IN CPU_IO_WIDTH Width, IN UINT64 Address, // IN UINTN Count, IN VOID *Buffer) performs Count I/O writes of the defined // Width at the Address from the Buffer. After every I/O operation, Address // and Buffer are updated according to the Width. See notes for details. // // Input: // IN CPU_IO_WIDTH Width // Number of bits to read from I/O. Supports at most 32-bits. // // IN UINT64 Address // I/O address to write to. // // IN UINTN Count // Number of writes to perform. // // IN VOID *Buffer // Buffer where the data to be written is located. // // Output: // EFI_INVALID_PARAMETER, if Count = 0, Width > 32-bits, or the range of // Address > 0xffff. // Otherwise, EFI_SUCCESS. // // Modified: // // Referrals: // IoWrite8 // IoWrite16 // IoWrite32 // // Notes: // Address and Buffer are updated according to the Width as follows: // CpuIoWidthUint8 - Both Address and Buffer are incremented by 1. // CpuIoWidthUint16 - Both Address and Buffer are incremented by 2. // CpuIoWidthUint32 - Both Address and Buffer are incremented by 4. // CpuIoWidthFifoUint8 - Only Buffer is incremented by 1. // CpuIoWidthFifoUint16 - Only Buffer is incremented by 2. // CpuIoWidthFifoUint32 - Only Buffer is incremented by 4. // CpuIoWidthFillUint8 - Only Address is incremented by 1. // CpuIoWidthFillUint16 - Only Address is incremented by 2. // CpuIoWidthFillUint32 - Only Address is incremented by 4. // // //************************************************************************* EFI_STATUS IoWrite( IN CPU_IO_WIDTH Width, IN UINT64 Address, IN UINTN Count, OUT VOID *Buffer ) { UINT8 ValueWidth = 1 << (Width & 3); UINT8 AddrInc, BuffInc; UINTN AddrCount; AddrInc = BuffInc = ValueWidth; switch (Width & ~3) { case CpuIoWidthFifoUint8: AddrInc = 0; break; case CpuIoWidthFillUint8: BuffInc = 0; break; } AddrCount = (Count-1) * AddrInc + ValueWidth; //---Validate Inputs--- if (!Count) return EFI_INVALID_PARAMETER; if (Address + AddrCount > 0xffff) return EFI_INVALID_PARAMETER; if ((Width & 3) > CpuIoWidthUint32) return EFI_INVALID_PARAMETER; while (Count--) { switch(Width & 3) { case CpuIoWidthUint8: IoWrite8((UINT16)Address, *(UINT8*) Buffer); break; case CpuIoWidthUint16: IoWrite16((UINT16)Address, *(UINT16*) Buffer); break; default: IoWrite32((UINT16)Address, *(UINT32*) Buffer); } Address = Address + AddrInc; Buffer = (UINT8*) Buffer + BuffInc; } return EFI_SUCCESS; } //************************************************************************* // // // Name: IoReadWrite // // Description: // EFI_STATUS IoReadWrite(IN CPU_IO_WIDTH Width, IN UINT64 Address, // IN VOID *DataValue, IN VOID *DataMask) reads the specified I/O Address, // ANDs the result with DataMask, then ORs the modified result with DataValue // and writes the value back to Address. // // Input: // IN CPU_IO_WIDTH Width // Number of bits to read/write from I/O. Only supports: CpuIoWidthUint8, // CpuIoWidthUint16, and CpuIoWidthUint32. // // IN UINT64 Address // I/O address to read and write to. // // IN VOID *DataValue // UINT32 OR mask value. // // IN VOID *DataMask // UINT32 AND mask value. // // Output: // EFI_INVALID_PARAMETER, if Width not supported, or the range of // Address > 0xffff. // Otherwise, EFI_SUCCESS. // // Modified: // // Referrals: // IoWrite // IoRead // // Notes: // // //************************************************************************* EFI_STATUS IoReadWrite( IN CPU_IO_WIDTH Width, IN UINT64 Address, IN VOID *DataValue, IN VOID *DataMask ) { EFI_STATUS Status; UINT32 Value32; UINT32 Mask; UINT32 Data; #if defined(EFI64) || defined(EFIx64) //In case of aligment issues. Mask = *((UINT8*)DataMask + 3) + *((UINT8*)DataMask + 2) + *((UINT8*)DataMask + 1) + *(UINT8*)DataMask; Data = *((UINT8*)DataValue + 3) + *((UINT8*)DataValue + 2) + *((UINT8*)DataValue + 1) + *(UINT8*)DataValue; ///////////////////////////// #else Mask = *(UINT32*)DataMask; Data = *(UINT32*)DataValue; #endif if ((Width & ~3) != CpuIoWidthUint8) return EFI_INVALID_PARAMETER; //Only CpuIoWidthUintxx Supported if ((Status = IoRead(Width, Address, 1, &Value32) != EFI_SUCCESS)) return Status; Value32 &= Mask; Value32 |= Data; return IoWrite(Width,Address,1,&Value32); } //************************************************************************* // // // Name: MemRead // // Description: // EFI_STATUS MemRead(IN CPU_IO_WIDTH Width, IN UINT64 Address, // IN UINTN Count, IN VOID *Buffer) performs Count MMIO reads of the size // Width at the Address and stores the result in Buffer. After every MMIO // operation, Address and Buffer are updated according to Width. // // Input: // IN CPU_IO_WIDTH Width // The width of the access. // // IN UINT64 Address // The physical address of the access. // // IN UINTN Count // The number of accesses to perform. // // IN VOID *Buffer // A pointer to the buffer of data. User is responsible for allocating the // necessary memory resources. // // Output: // EFI_INVALID_PARAMETER, if Count = 0, Width not supported, or the range of // Address overflows the bounds of memory. // Otherwise, EFI_SUCCESS. // // Modified: // // Referrals: // // Notes: // Address and Buffer are updated according to Width as follows: // CpuIoWidthUint8 - Both Address and Buffer are incremented by 1. // CpuIoWidthUint16 - Both Address and Buffer are incremented by 2. // CpuIoWidthUint32 - Both Address and Buffer are incremented by 4. // CpuIoWidthUint64 - Both Address and Buffer are incremented by 8. // CpuIoWidthFifoUint8 - Only Buffer is incremented by 1. // CpuIoWidthFifoUint16 - Only Buffer is incremented by 2. // CpuIoWidthFifoUint32 - Only Buffer is incremented by 4. // CpuIoWidthFifoUint64 - Only Buffer is incremented by 8. // CpuIoWidthFillUint8 - Only Address is incremented by 1. // CpuIoWidthFillUint16 - Only Address is incremented by 2. // CpuIoWidthFillUint32 - Only Address is incremented by 4. // CpuIoWidthFillUint64 - Only Address is incremented by 8. // // //************************************************************************* EFI_STATUS MemRead( IN CPU_IO_WIDTH Width, IN UINT64 Address, IN UINTN Count, IN VOID *Buffer ) { UINT8 ValueWidth = 1 << (Width & 3); UINT8 AddrInc, BuffInc; UINTN AddrCount; AddrInc = BuffInc = ValueWidth; switch (Width & ~3) { case CpuIoWidthFifoUint8: AddrInc = 0; break; case CpuIoWidthFillUint8: BuffInc = 0; break; } AddrCount = (Count-1) * AddrInc + ValueWidth; //---Validate Inputs--- if (!Count) return EFI_INVALID_PARAMETER; #if defined(EFI64) || defined(EFIx64) if (Address + AddrCount < Address) return EFI_INVALID_PARAMETER; //Overflow #else if (Address + AddrCount > 0xffffffff) return EFI_INVALID_PARAMETER; if ((Width & 3) > CpuIoWidthUint32) return EFI_INVALID_PARAMETER; #endif while (Count--) { switch(Width & 3) { case CpuIoWidthUint8: *(UINT8*)Buffer = *(UINT8*)Address; break; case CpuIoWidthUint16: *(UINT16*)Buffer = *(UINT16*)Address; break; case CpuIoWidthUint32: *(UINT32*)Buffer = *(UINT32*)Address; break; default: *(UINT64*)Buffer = *(UINT64*)Address; } Address = Address + AddrInc; Buffer = (UINT8*) Buffer + BuffInc; } return EFI_SUCCESS; } //************************************************************************* // // // Name: MemWrite // // Description: // EFI_STATUS MemWrite(IN CPU_IO_WIDTH Width, IN UINT64 Address, // IN UINTN Count, OUT VOID *Buffer) performs Count MMIO writes of the size // Width at the Address using the contents of Buffer. After every MMIO // operation, Address and Buffer are updated according to Width. // // Input: // IN CPU_IO_WIDTH Width // The width of the access. // // IN UINT64 Address // The physical address of the access. // // IN UINTN Count // The number of accesses to perform. // // OUT VOID *Buffer // A pointer to the buffer of data. // // Output: // EFI_INVALID_PARAMETER, if Count = 0, Width not supported, or the range of // Address overflows the bounds of memory. // Otherwise, EFI_SUCCESS. // // Modified: // // Referrals: // // Notes: // Address and Buffer are updated according to Width as follows: // CpuIoWidthUint8 - Both Address and Buffer are incremented by 1. // CpuIoWidthUint16 - Both Address and Buffer are incremented by 2. // CpuIoWidthUint32 - Both Address and Buffer are incremented by 4. // CpuIoWidthUint64 - Both Address and Buffer are incremented by 8. // CpuIoWidthFifoUint8 - Only Buffer is incremented by 1. // CpuIoWidthFifoUint16 - Only Buffer is incremented by 2. // CpuIoWidthFifoUint32 - Only Buffer is incremented by 4. // CpuIoWidthFifoUint64 - Only Buffer is incremented by 8. // CpuIoWidthFillUint8 - Only Address is incremented by 1. // CpuIoWidthFillUint16 - Only Address is incremented by 2. // CpuIoWidthFillUint32 - Only Address is incremented by 4. // CpuIoWidthFillUint64 - Only Address is incremented by 8. // // //************************************************************************* EFI_STATUS MemWrite( IN CPU_IO_WIDTH Width, IN UINT64 Address, IN UINTN Count, OUT VOID *Buffer ) { UINT8 ValueWidth = 1 << (Width & 3); UINT8 AddrInc, BuffInc; UINTN AddrCount; AddrInc = BuffInc = ValueWidth; switch (Width & ~3) { case CpuIoWidthFifoUint8: AddrInc = 0; break; case CpuIoWidthFillUint8: BuffInc = 0; break; } AddrCount = (Count-1) * AddrInc + ValueWidth; //---Validate Inputs--- if (!Count) return EFI_INVALID_PARAMETER; #if defined(EFI64) || defined(EFIx64) if (Address + AddrCount < Address) return EFI_INVALID_PARAMETER; //Overflow #else if (Address + AddrCount > 0xffffffff) return EFI_INVALID_PARAMETER; if ((Width & 3) > CpuIoWidthUint32) return EFI_INVALID_PARAMETER; #endif while (Count--) { switch(Width & 3) { case CpuIoWidthUint8: *(UINT8*)Address = *(UINT8*)Buffer; break; case CpuIoWidthUint16: *(UINT16*)Address = *(UINT16*)Buffer; break; case CpuIoWidthUint32: *(UINT32*)Address = *(UINT32*) Buffer; break; default: *(UINT64*)Address = *(UINT64*) Buffer; } Address = Address + AddrInc; Buffer = (UINT8*) Buffer + BuffInc; } return EFI_SUCCESS; } //************************************************************************* // // // Name: MemReadWrite // // Description: // EFI_STATUS MemReadWrite(IN CPU_IO_WIDTH Width, IN UINT64 Address, // IN VOID *DataValue, IN VOID *DataMask) reads the specified physical // Address, ANDs the result with DataMask, then ORs the modified result with // DataValue and writes the value back to Address. // // Input: // IN CPU_IO_WIDTH Width // The width of the access. Only supports CpuIoWidthUintxx. // // IN UINT64 Address // The physical address of the access. // // IN VOID *DataValue // UINT64 OR mask value. // // IN VOID *DataMask // UINT64 AND mask value. // // Output: // EFI_INVALID_PARAMETER, if Width not supported, or the range of // Address overflows the bounds of memory. // Otherwise, EFI_SUCCESS. // // Modified: // // Referrals: // // Notes: // // //************************************************************************* EFI_STATUS MemReadWrite( IN CPU_IO_WIDTH Width, IN UINT64 Address, IN VOID *DataValue, IN VOID *DataMask ) { EFI_STATUS Status; UINT64 Value64; UINT64 Mask; UINT64 Data; #if defined(EFI64) || defined(EFIx64) //In case of aligment issues. Mask = *((UINT8*)DataMask + 4) + *((UINT8*)DataMask + 3) + *((UINT8*)DataMask + 2) + *((UINT8*)DataMask + 1) + *(UINT8*)DataMask; Data = *((UINT8*)DataValue + 4) + *((UINT8*)DataValue + 3) + *((UINT8*)DataValue + 2) + *((UINT8*)DataValue + 1) + *(UINT8*)DataValue; ///////////////////////////// #else Mask = *(UINT64*)DataMask; Data = *(UINT64*)DataValue; #endif if ((Width & ~3) != CpuIoWidthUint8) return EFI_INVALID_PARAMETER; //Only CpuIoWidthUintxx Supported if ((Status = MemRead(Width, Address, 1, &Value64) != EFI_SUCCESS)) return Status; Value64 &= Mask; Value64 |= Data; return MemWrite(Width,Address,1,&Value64); } //************************************************************************* //************************************************************************* //** ** //** (C)Copyright 1985-2009, American Megatrends, Inc. ** //** ** //** All Rights Reserved. ** //** ** //** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** //** ** //** Phone: (770)-246-8600 ** //** ** //************************************************************************* //*************************************************************************