diff options
| author | Simon Rettberg | 2026-01-28 12:53:53 +0100 |
|---|---|---|
| committer | Simon Rettberg | 2026-01-28 12:53:53 +0100 |
| commit | 8e82785c584dc13e20f9229decb95bd17bbe9cd1 (patch) | |
| tree | a8b359e59196be5b2e3862bed189107f4bc9975f /src/arch/x86/core/x86_io.c | |
| parent | Merge branch 'master' into openslx (diff) | |
| parent | [prefix] Make unlzma.S compatible with 386 class CPUs (diff) | |
| download | ipxe-openslx.tar.gz ipxe-openslx.tar.xz ipxe-openslx.zip | |
Merge branch 'master' into openslxopenslx
Diffstat (limited to 'src/arch/x86/core/x86_io.c')
| -rw-r--r-- | src/arch/x86/core/x86_io.c | 69 |
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 ); |
