summaryrefslogtreecommitdiffstats
path: root/src/arch/x86/core/x86_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/x86/core/x86_io.c')
-rw-r--r--src/arch/x86/core/x86_io.c69
1 files changed, 69 insertions, 0 deletions
diff --git a/src/arch/x86/core/x86_io.c b/src/arch/x86/core/x86_io.c
index 6c6b6e1e7..270ed7bef 100644
--- a/src/arch/x86/core/x86_io.c
+++ b/src/arch/x86/core/x86_io.c
@@ -32,6 +32,69 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
+/** 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
*
@@ -101,3 +164,9 @@ PROVIDE_IOAPI_INLINE ( x86, writeq );
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 );