*
*/
+/** Threshold for port I/O-mapped addresses
+ *
+ * On x86, port I/O instructions (inb/outb/etc) can take only an 8-bit
+ * or 16-bit address (in %dx). All I/O ports must therefore have a
+ * value in the first 64kB of the address space.
+ *
+ * Virtual addresses below 64kB can never be MMIO addresses:
+ *
+ * - In the UEFI memory model and x86_64 BIOS memory model, virtual
+ * addresses below 64kB are identity-mapped to the corresponding
+ * physical address. Since the first 64kB of address space is
+ * always RAM, no MMIO device can exist within this region.
+ *
+ * - In the i386 BIOS memory model, virtual addresses below 64kB cover
+ * the iPXE binary itself (which starts at address zero). Since the
+ * size of .textdata can never realistically be below 64kB (not
+ * least since the heap alone is 512kB), and since iPXE is placed
+ * into RAM as a contiguous block, no MMIO device can exist within
+ * this region.
+ *
+ * We therefore know that any (virtual) address returned by ioremap()
+ * must be outside the first 64kB of the address space. We can
+ * therefore use this as a threshold to determine whether a given
+ * address is a port I/O address or an MMIO address.
+ */
+#define PIO_THRESHOLD 0x10000
+
+/**
+ * Read from I/O-mapped or memory-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+#define X86_IOREADX( _api_func, _suffix, _type ) \
+static _type x86_ ## _api_func ( volatile _type *io_addr ) { \
+ if ( ( ( intptr_t ) io_addr ) < PIO_THRESHOLD ) { \
+ return in ## _suffix ( io_addr ); \
+ } else { \
+ return read ## _suffix ( io_addr ); \
+ } \
+}
+X86_IOREADX ( ioread8, b, uint8_t );
+X86_IOREADX ( ioread16, w, uint16_t );
+X86_IOREADX ( ioread32, l, uint32_t );
+
+/**
+ * Write to I/O-mapped or memory-mapped device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+#define X86_IOWRITEX( _api_func, _suffix, _type ) \
+static void x86_ ## _api_func ( _type data, volatile _type *io_addr ) { \
+ if ( ( ( intptr_t ) io_addr ) < PIO_THRESHOLD ) { \
+ out ## _suffix ( data, io_addr ); \
+ } else { \
+ write ## _suffix ( data, io_addr ); \
+ } \
+}
+X86_IOWRITEX ( iowrite8, b, uint8_t );
+X86_IOWRITEX ( iowrite16, w, uint16_t );
+X86_IOWRITEX ( iowrite32, l, uint32_t );
+
/**
* Read 64-bit qword from memory-mapped device
*
PROVIDE_IOAPI ( x86, readq, i386_readq );
PROVIDE_IOAPI ( x86, writeq, i386_writeq );
#endif
+PROVIDE_IOAPI ( x86, ioread8, x86_ioread8 );
+PROVIDE_IOAPI ( x86, ioread16, x86_ioread16 );
+PROVIDE_IOAPI ( x86, ioread32, x86_ioread32 );
+PROVIDE_IOAPI ( x86, iowrite8, x86_iowrite8 );
+PROVIDE_IOAPI ( x86, iowrite16, x86_iowrite16 );
+PROVIDE_IOAPI ( x86, iowrite32, x86_iowrite32 );
/* Do nothing */ \
}
+#define DUMMY_IOREADX( _prefix, _width, _suffix, _type ) \
+static inline __always_inline _type \
+IOAPI_INLINE ( _prefix, ioread ## _width ) ( volatile _type *io_addr ) { \
+ return IOAPI_INLINE ( _prefix, read ## _suffix ) ( io_addr ); \
+}
+
+#define DUMMY_IOWRITEX( _prefix, _width, _suffix, _type ) \
+static inline __always_inline void \
+IOAPI_INLINE ( _prefix, iowrite ## _width ) ( _type data, \
+ volatile _type *io_addr ) { \
+ IOAPI_INLINE ( _prefix, write ## _suffix ) ( data, io_addr ); \
+}
+
#define DUMMY_IODELAY( _prefix ) \
static inline __always_inline void \
IOAPI_INLINE ( _prefix, iodelay ) ( void ) { \
DUMMY_OUTX ( _prefix, b, uint8_t ); \
DUMMY_OUTX ( _prefix, w, uint16_t ); \
DUMMY_OUTX ( _prefix, l, uint32_t ); \
+ DUMMY_IOREADX ( _prefix, 8, b, uint8_t ); \
+ DUMMY_IOREADX ( _prefix, 16, w, uint16_t ); \
+ DUMMY_IOREADX ( _prefix, 32, l, uint32_t ); \
+ DUMMY_IOWRITEX ( _prefix, 8, b, uint8_t ); \
+ DUMMY_IOWRITEX ( _prefix, 16, w, uint16_t ); \
+ DUMMY_IOWRITEX ( _prefix, 32, l, uint32_t ); \
DUMMY_IODELAY ( _prefix );
#define PROVIDE_DUMMY_PIO( _prefix ) \
PROVIDE_IOAPI_INLINE ( _prefix, outb ); \
PROVIDE_IOAPI_INLINE ( _prefix, outw ); \
PROVIDE_IOAPI_INLINE ( _prefix, outl ); \
+ PROVIDE_IOAPI_INLINE ( _prefix, ioread8 ); \
+ PROVIDE_IOAPI_INLINE ( _prefix, ioread16 ); \
+ PROVIDE_IOAPI_INLINE ( _prefix, ioread32 ); \
+ PROVIDE_IOAPI_INLINE ( _prefix, iowrite8 ); \
+ PROVIDE_IOAPI_INLINE ( _prefix, iowrite16 ); \
+ PROVIDE_IOAPI_INLINE ( _prefix, iowrite32 ); \
PROVIDE_IOAPI_INLINE ( _prefix, iodelay );
#endif /* _IPXE_DUMMY_PIO_H */
#define outl( data, io_addr ) \
IOAPI_WRITE ( outl, uint32_t, data, io_addr, "IO", 8 )
+/**
+ * Read byte from I/O-mapped or memory-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+uint8_t ioread8 ( volatile uint8_t *io_addr );
+#define ioread8( io_addr ) \
+ IOAPI_READ ( ioread8, uint8_t, io_addr, "IO/MEM", 2 )
+
+/**
+ * Read 16-bit word from I/O-mapped or memory-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+uint16_t ioread16 ( volatile uint16_t *io_addr );
+#define ioread16( io_addr ) \
+ IOAPI_READ ( ioread16, uint16_t, io_addr, "IO/MEM", 4 )
+
+/**
+ * Read 32-bit dword from I/O-mapped or memory-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+uint32_t ioread32 ( volatile uint32_t *io_addr );
+#define ioread32( io_addr ) \
+ IOAPI_READ ( ioread32, uint32_t, io_addr, "IO/MEM", 8 )
+
+/**
+ * Write byte to I/O-mapped or memory-mapped device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+void iowrite8 ( uint8_t data, volatile uint8_t *io_addr );
+#define iowrite8( data, io_addr ) \
+ IOAPI_WRITE ( iowrite8, uint8_t, data, io_addr, "IO/MEM", 2 )
+
+/**
+ * Write 16-bit word to I/O-mapped or memory-mapped device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+void iowrite16 ( uint16_t data, volatile uint16_t *io_addr );
+#define iowrite16( data, io_addr ) \
+ IOAPI_WRITE ( iowrite16, uint16_t, data, io_addr, "IO/MEM", 4 )
+
+/**
+ * Write 32-bit dword to I/O-mapped or memory-mapped device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+void iowrite32 ( uint32_t data, volatile uint32_t *io_addr );
+#define iowrite32( data, io_addr ) \
+ IOAPI_WRITE ( iowrite32, uint32_t, data, io_addr, "IO/MEM", 8 )
+
/**
* Read bytes from I/O-mapped device
*