#ifndef _IPXE_IO_H #define _IPXE_IO_H /** @file * * iPXE I/O API * * The I/O API provides methods for reading from and writing to * memory-mapped and I/O-mapped devices. * * The standard methods (readl()/writel() etc.) do not strictly check * the type of the address parameter; this is because traditional * usage does not necessarily provide the correct pointer type. For * example, code written for ISA devices at fixed I/O addresses (such * as the keyboard controller) tend to use plain integer constants for * the address parameter. */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include #include /** Page size */ #define PAGE_SIZE ( 1 << PAGE_SHIFT ) /** Page mask */ #define PAGE_MASK ( PAGE_SIZE - 1 ) /** * Calculate static inline I/O API function name * * @v _prefix Subsystem prefix * @v _api_func API function * @ret _subsys_func Subsystem API function */ #define IOAPI_INLINE( _subsys, _api_func ) \ SINGLE_API_INLINE ( IOAPI_PREFIX_ ## _subsys, _api_func ) /** * Provide an I/O API implementation * * @v _prefix Subsystem prefix * @v _api_func API function * @v _func Implementing function */ #define PROVIDE_IOAPI( _subsys, _api_func, _func ) \ PROVIDE_SINGLE_API ( IOAPI_PREFIX_ ## _subsys, _api_func, _func ) /** * Provide a static inline I/O API implementation * * @v _prefix Subsystem prefix * @v _api_func API function */ #define PROVIDE_IOAPI_INLINE( _subsys, _api_func ) \ PROVIDE_SINGLE_API_INLINE ( IOAPI_PREFIX_ ## _subsys, _api_func ) /* Include all architecture-independent I/O API headers */ /* Include all architecture-dependent I/O API headers */ #include /** * Wrap an I/O read * * @v _func I/O API function * @v _type Data type * @v io_addr I/O address * @v _prefix Prefix for address in debug message * @v _ndigits Number of hex digits for this data type */ #define IOAPI_READ( _func, _type, io_addr, _prefix, _ndigits ) ( { \ volatile _type *_io_addr = \ ( ( volatile _type * ) ( intptr_t ) (io_addr) ); \ _type _data = _func ( _io_addr ); \ DBGIO ( "[" _prefix " %08lx] => %0" #_ndigits "llx\n", \ io_to_bus ( _io_addr ), ( unsigned long long ) _data ); \ _data; } ) /** * Wrap an I/O write * * @v _func I/O API function * @v _type Data type * @v data Value to write * @v io_addr I/O address * @v _prefix Prefix for address in debug message * @v _ndigits Number of hex digits for this data type */ #define IOAPI_WRITE( _func, _type, data, io_addr, _prefix, _ndigits ) do { \ volatile _type *_io_addr = \ ( ( volatile _type * ) ( intptr_t ) (io_addr) ); \ _type _data = (data); \ DBGIO ( "[" _prefix " %08lx] <= %0" #_ndigits "llx\n", \ io_to_bus ( _io_addr ), ( unsigned long long ) _data ); \ _func ( _data, _io_addr ); \ } while ( 0 ) /** * Wrap an I/O string read * * @v _func I/O API function * @v _type Data type * @v io_addr I/O address * @v data Data buffer * @v count Number of elements to read * @v _prefix Prefix for address in debug message * @v _ndigits Number of hex digits for this data type */ #define IOAPI_READS( _func, _type, io_addr, data, count, _prefix, _ndigits ) \ do { \ volatile _type *_io_addr = \ ( ( volatile _type * ) ( intptr_t ) (io_addr) ); \ void *_data_void = (data); /* Check data is a pointer */ \ _type * _data = ( ( _type * ) _data_void ); \ const _type * _dbg_data = _data; \ unsigned int _count = (count); \ unsigned int _dbg_count = _count; \ _func ( _io_addr, _data, _count ); \ DBGIO ( "[" _prefix " %08lx] =>", io_to_bus ( _io_addr ) ); \ while ( _dbg_count-- ) { \ DBGIO ( " %0" #_ndigits "llx", \ ( ( unsigned long long ) *(_dbg_data++) ) ); \ } \ DBGIO ( "\n" ); \ } while ( 0 ) /** * Wrap an I/O string write * * @v _func I/O API function * @v _type Data type * @v io_addr I/O address * @v data Data buffer * @v count Number of elements to write * @v _prefix Prefix for address in debug message * @v _ndigits Number of hex digits for this data type */ #define IOAPI_WRITES( _func, _type, io_addr, data, count, _prefix, _ndigits ) \ do { \ volatile _type *_io_addr = \ ( ( volatile _type * ) ( intptr_t ) (io_addr) ); \ const void *_data_void = (data); /* Check data is a pointer */ \ const _type * _data = ( ( const _type * ) _data_void ); \ const _type * _dbg_data = _data; \ unsigned int _count = (count); \ unsigned int _dbg_count = _count; \ DBGIO ( "[" _prefix " %08lx] <=", io_to_bus ( _io_addr ) ); \ while ( _dbg_count-- ) { \ DBGIO ( " %0" #_ndigits "llx", \ ( ( unsigned long long ) *(_dbg_data++) ) ); \ } \ DBGIO ( "\n" ); \ _func ( _io_addr, _data, _count ); \ } while ( 0 ) /** * Convert physical address to a bus address * * @v phys_addr Physical address * @ret bus_addr Bus address */ unsigned long phys_to_bus ( unsigned long phys_addr ); /** * Convert bus address to a physical address * * @v bus_addr Bus address * @ret phys_addr Physical address */ unsigned long bus_to_phys ( unsigned long bus_addr ); /** * Convert virtual address to a bus address * * @v addr Virtual address * @ret bus_addr Bus address */ static inline __always_inline unsigned long virt_to_bus ( volatile const void *addr ) { return phys_to_bus ( virt_to_phys ( addr ) ); } /** * Convert bus address to a virtual address * * @v bus_addr Bus address * @ret addr Virtual address * * This operation is not available under all memory models. */ static inline __always_inline void * bus_to_virt ( unsigned long bus_addr ) { return phys_to_virt ( bus_to_phys ( bus_addr ) ); } /** * Read byte from memory-mapped device * * @v io_addr I/O address * @ret data Value read */ uint8_t readb ( volatile uint8_t *io_addr ); #define readb( io_addr ) IOAPI_READ ( readb, uint8_t, io_addr, "MEM", 2 ) /** * Read 16-bit word from memory-mapped device * * @v io_addr I/O address * @ret data Value read */ uint16_t readw ( volatile uint16_t *io_addr ); #define readw( io_addr ) IOAPI_READ ( readw, uint16_t, io_addr, "MEM", 4 ) /** * Read 32-bit dword from memory-mapped device * * @v io_addr I/O address * @ret data Value read */ uint32_t readl ( volatile uint32_t *io_addr ); #define readl( io_addr ) IOAPI_READ ( readl, uint32_t, io_addr, "MEM", 8 ) /** * Read 64-bit qword from memory-mapped device * * @v io_addr I/O address * @ret data Value read */ uint64_t readq ( volatile uint64_t *io_addr ); #define readq( io_addr ) IOAPI_READ ( readq, uint64_t, io_addr, "MEM", 16 ) /** * Write byte to memory-mapped device * * @v data Value to write * @v io_addr I/O address */ void writeb ( uint8_t data, volatile uint8_t *io_addr ); #define writeb( data, io_addr ) \ IOAPI_WRITE ( writeb, uint8_t, data, io_addr, "MEM", 2 ) /** * Write 16-bit word to memory-mapped device * * @v data Value to write * @v io_addr I/O address */ void writew ( uint16_t data, volatile uint16_t *io_addr ); #define writew( data, io_addr ) \ IOAPI_WRITE ( writew, uint16_t, data, io_addr, "MEM", 4 ) /** * Write 32-bit dword to memory-mapped device * * @v data Value to write * @v io_addr I/O address */ void writel ( uint32_t data, volatile uint32_t *io_addr ); #define writel( data, io_addr ) \ IOAPI_WRITE ( writel, uint32_t, data, io_addr, "MEM", 8 ) /** * Write 64-bit qword to memory-mapped device * * @v data Value to write * @v io_addr I/O address */ void writeq ( uint64_t data, volatile uint64_t *io_addr ); #define writeq( data, io_addr ) \ IOAPI_WRITE ( writeq, uint64_t, data, io_addr, "MEM", 16 ) /** * Read byte from I/O-mapped device * * @v io_addr I/O address * @ret data Value read */ uint8_t inb ( volatile uint8_t *io_addr ); #define inb( io_addr ) IOAPI_READ ( inb, uint8_t, io_addr, "IO", 2 ) /** * Read 16-bit word from I/O-mapped device * * @v io_addr I/O address * @ret data Value read */ uint16_t inw ( volatile uint16_t *io_addr ); #define inw( io_addr ) IOAPI_READ ( inw, uint16_t, io_addr, "IO", 4 ) /** * Read 32-bit dword from I/O-mapped device * * @v io_addr I/O address * @ret data Value read */ uint32_t inl ( volatile uint32_t *io_addr ); #define inl( io_addr ) IOAPI_READ ( inl, uint32_t, io_addr, "IO", 8 ) /** * Write byte to I/O-mapped device * * @v data Value to write * @v io_addr I/O address */ void outb ( uint8_t data, volatile uint8_t *io_addr ); #define outb( data, io_addr ) \ IOAPI_WRITE ( outb, uint8_t, data, io_addr, "IO", 2 ) /** * Write 16-bit word to I/O-mapped device * * @v data Value to write * @v io_addr I/O address */ void outw ( uint16_t data, volatile uint16_t *io_addr ); #define outw( data, io_addr ) \ IOAPI_WRITE ( outw, uint16_t, data, io_addr, "IO", 4 ) /** * Write 32-bit dword to I/O-mapped device * * @v data Value to write * @v io_addr I/O address */ void outl ( uint32_t data, volatile uint32_t *io_addr ); #define outl( data, io_addr ) \ IOAPI_WRITE ( outl, uint32_t, data, io_addr, "IO", 8 ) /** * Read bytes from I/O-mapped device * * @v io_addr I/O address * @v data Data buffer * @v count Number of bytes to read */ void insb ( volatile uint8_t *io_addr, uint8_t *data, unsigned int count ); #define insb( io_addr, data, count ) \ IOAPI_READS ( insb, uint8_t, io_addr, data, count, "IO", 2 ) /** * Read 16-bit words from I/O-mapped device * * @v io_addr I/O address * @v data Data buffer * @v count Number of words to read */ void insw ( volatile uint16_t *io_addr, uint16_t *data, unsigned int count ); #define insw( io_addr, data, count ) \ IOAPI_READS ( insw, uint16_t, io_addr, data, count, "IO", 4 ) /** * Read 32-bit words from I/O-mapped device * * @v io_addr I/O address * @v data Data buffer * @v count Number of words to read */ void insl ( volatile uint32_t *io_addr, uint32_t *data, unsigned int count ); #define insl( io_addr, data, count ) \ IOAPI_READS ( insl, uint32_t, io_addr, data, count, "IO", 8 ) /** * Write bytes to I/O-mapped device * * @v io_addr I/O address * @v data Data buffer * @v count Number of bytes to write */ void outsb ( volatile uint8_t *io_addr, const uint8_t *data, unsigned int count ); #define outsb( io_addr, data, count ) \ IOAPI_WRITES ( outsb, uint8_t, io_addr, data, count, "IO", 2 ) /** * Write 16-bit words to I/O-mapped device * * @v io_addr I/O address * @v data Data buffer * @v count Number of words to write */ void outsw ( volatile uint16_t *io_addr, const uint16_t *data, unsigned int count ); #define outsw( io_addr, data, count ) \ IOAPI_WRITES ( outsw, uint16_t, io_addr, data, count, "IO", 4 ) /** * Write 32-bit words to I/O-mapped device * * @v io_addr I/O address * @v data Data buffer * @v count Number of words to write */ void outsl ( volatile uint32_t *io_addr, const uint32_t *data, unsigned int count ); #define outsl( io_addr, data, count ) \ IOAPI_WRITES ( outsl, uint32_t, io_addr, data, count, "IO", 8 ) /** * Slow down I/O * */ void iodelay ( void ); /** * Read value from I/O-mapped device, slowly * * @v _func Function to use to read value * @v data Value to write * @v io_addr I/O address */ #define INX_P( _func, _type, io_addr ) ( { \ _type _data = _func ( (io_addr) ); \ iodelay(); \ _data; } ) /** * Read byte from I/O-mapped device * * @v io_addr I/O address * @ret data Value read */ #define inb_p( io_addr ) INX_P ( inb, uint8_t, io_addr ) /** * Read 16-bit word from I/O-mapped device * * @v io_addr I/O address * @ret data Value read */ #define inw_p( io_addr ) INX_P ( inw, uint16_t, io_addr ) /** * Read 32-bit dword from I/O-mapped device * * @v io_addr I/O address * @ret data Value read */ #define inl_p( io_addr ) INX_P ( inl, uint32_t, io_addr ) /** * Write value to I/O-mapped device, slowly * * @v _func Function to use to write value * @v data Value to write * @v io_addr I/O address */ #define OUTX_P( _func, data, io_addr ) do { \ _func ( (data), (io_addr) ); \ iodelay(); \ } while ( 0 ) /** * Write byte to I/O-mapped device, slowly * * @v data Value to write * @v io_addr I/O address */ #define outb_p( data, io_addr ) OUTX_P ( outb, data, io_addr ) /** * Write 16-bit word to I/O-mapped device, slowly * * @v data Value to write * @v io_addr I/O address */ #define outw_p( data, io_addr ) OUTX_P ( outw, data, io_addr ) /** * Write 32-bit dword to I/O-mapped device, slowly * * @v data Value to write * @v io_addr I/O address */ #define outl_p( data, io_addr ) OUTX_P ( outl, data, io_addr ) /** * Memory barrier * */ void mb ( void ); #define rmb() mb() #define wmb() mb() /** A usable memory region */ struct memory_region { /** Physical start address */ uint64_t start; /** Physical end address */ uint64_t end; }; /** Maximum number of memory regions we expect to encounter */ #define MAX_MEMORY_REGIONS 8 /** A memory map */ struct memory_map { /** Memory regions */ struct memory_region regions[MAX_MEMORY_REGIONS]; /** Number of used regions */ unsigned int count; }; /** * Get memory map * * @v memmap Memory map to fill in */ void get_memmap ( struct memory_map *memmap ); #endif /* _IPXE_IO_H */