diff --git a/include/io.h b/include/io.h new file mode 100644 index 0000000..19208fb --- /dev/null +++ b/include/io.h @@ -0,0 +1,47 @@ +/* Nadir x86 port I/O primitives (inb/outb/io_wait). + * + * Runs in 64-bit long mode at Ring 0 (CPL 0) with the stage-2 GDT. + * Privileged instructions: `in`/`out` trap with #GP(0) when CPL > IOPL, + * so these helpers are Ring 0 only and must never be exposed to + * userspace. Fault behavior: a bad port number cannot fault by itself + * (unused ports read back 0xFF or are ignored); a fault here means the + * caller programmed the wrong device, not a CPU trap. + * Interrupts stay disabled by the caller where timing matters; these + * helpers do not touch IF themselves. + */ + +#ifndef NADIR_IO_H +#define NADIR_IO_H + +#include + +/* Read one byte from ISA port `port`. + * Preconditions: CPL 0, port is a valid x86 I/O address (0-0xFFFF). + * Failure modes: none (returns bus value; 0xFF on unmapped ports). */ +static inline uint8_t inb(uint16_t port) +{ + uint8_t value; + + __asm__ volatile("inb %1, %0" : "=a"(value) : "Nd"(port)); + return value; +} + +/* Write byte `value` to ISA port `port`. + * Preconditions: CPL 0, port is writable for this device. + * Failure modes: none from the CPU; wrong port = device misbehavior. */ +static inline void outb(uint16_t port, uint8_t value) +{ + __asm__ volatile("outb %0, %1" ::"a"(value), "Nd"(port)); +} + +/* Tiny delay for legacy ISA devices (writes to unused port 0x80). + * + * WHY: the 8259 PIC and other slow devices need ~1us between back to + * back command bytes; port 0x80 is the conventional throwaway delay. + * Preconditions: CPL 0. Failure modes: none. */ +static inline void io_wait(void) +{ + outb(0x80U, 0U); +} + +#endif /* NADIR_IO_H */