1 #ifndef _GPXE_X86_IO_H 2 #define _GPXE_X86_IO_H 3 4 /** @file 5 * 6 * gPXE I/O API for x86 7 * 8 * i386 uses direct pointer dereferences for accesses to memory-mapped 9 * I/O space, and the inX/outX instructions for accesses to 10 * port-mapped I/O space. 11 * 12 * 64-bit atomic accesses (readq() and writeq()) use MMX instructions, 13 * and will crash original Pentium and earlier CPUs. Fortunately, no 14 * hardware that requires atomic 64-bit accesses will physically fit 15 * into a machine with such an old CPU anyway. 16 */ 17 18 FILE_LICENCE ( GPL2_OR_LATER ); 19 20 #ifdef IOAPI_X86 21 #define IOAPI_PREFIX_x86 22 #else 23 #define IOAPI_PREFIX_x86 __x86_ 24 #endif 25 26 /* 27 * Memory space mappings 28 * 29 */ 30 31 /* 32 * Physical<->Bus and Bus<->I/O address mappings 33 * 34 */ 35 36 static inline __always_inline unsigned long 37 IOAPI_INLINE ( x86, phys_to_bus ) ( unsigned long phys_addr ) { 38 return phys_addr; 39 } 40 41 static inline __always_inline unsigned long 42 IOAPI_INLINE ( x86, bus_to_phys ) ( unsigned long bus_addr ) { 43 return bus_addr; 44 } 45 46 static inline __always_inline void * 47 IOAPI_INLINE ( x86, ioremap ) ( unsigned long bus_addr, size_t len __unused ) { 48 return phys_to_virt ( bus_addr ); 49 } 50 51 static inline __always_inline void 52 IOAPI_INLINE ( x86, iounmap ) ( volatile const void *io_addr __unused ) { 53 /* Nothing to do */ 54 } 55 56 static inline __always_inline unsigned long 57 IOAPI_INLINE ( x86, io_to_bus ) ( volatile const void *io_addr ) { 58 return virt_to_phys ( io_addr ); 59 } 60 61 /* 62 * MMIO reads and writes up to 32 bits 63 * 64 */ 65 66 #define X86_READX( _api_func, _type ) \ 67 static inline __always_inline _type \ 68 IOAPI_INLINE ( x86, _api_func ) ( volatile _type *io_addr ) { \ 69 return *io_addr; \ 70 } 71 X86_READX ( readb, uint8_t ); 72 X86_READX ( readw, uint16_t ); 73 X86_READX ( readl, uint32_t ); 74 75 #define X86_WRITEX( _api_func, _type ) \ 76 static inline __always_inline void \ 77 IOAPI_INLINE ( x86, _api_func ) ( _type data, \ 78 volatile _type *io_addr ) { \ 79 *io_addr = data; \ 80 } 81 X86_WRITEX ( writeb, uint8_t ); 82 X86_WRITEX ( writew, uint16_t ); 83 X86_WRITEX ( writel, uint32_t ); 84 85 /* 86 * PIO reads and writes up to 32 bits 87 * 88 */ 89 90 #define X86_INX( _insn_suffix, _type, _reg_prefix ) \ 91 static inline __always_inline _type \ 92 IOAPI_INLINE ( x86, in ## _insn_suffix ) ( volatile _type *io_addr ) { \ 93 _type data; \ 94 __asm__ __volatile__ ( "in" #_insn_suffix " %w1, %" _reg_prefix "0" \ 95 : "=a" ( data ) : "Nd" ( io_addr ) ); \ 96 return data; \ 97 } \ 98 static inline __always_inline void \ 99 IOAPI_INLINE ( x86, ins ## _insn_suffix ) ( volatile _type *io_addr, \ 100 _type *data, \ 101 unsigned int count ) { \ 102 unsigned int discard_D; \ 103 __asm__ __volatile__ ( "rep ins" #_insn_suffix \ 104 : "=D" ( discard_D ) \ 105 : "d" ( io_addr ), "c" ( count ), \ 106 "0" ( data ) ); \ 107 } 108 X86_INX ( b, uint8_t, "b" ); 109 X86_INX ( w, uint16_t, "w" ); 110 X86_INX ( l, uint32_t, "k" ); 111 112 #define X86_OUTX( _insn_suffix, _type, _reg_prefix ) \ 113 static inline __always_inline void \ 114 IOAPI_INLINE ( x86, out ## _insn_suffix ) ( _type data, \ 115 volatile _type *io_addr ) { \ 116 __asm__ __volatile__ ( "out" #_insn_suffix " %" _reg_prefix "0, %w1" \ 117 : : "a" ( data ), "Nd" ( io_addr ) ); \ 118 } \ 119 static inline __always_inline void \ 120 IOAPI_INLINE ( x86, outs ## _insn_suffix ) ( volatile _type *io_addr, \ 121 const _type *data, \ 122 unsigned int count ) { \ 123 unsigned int discard_S; \ 124 __asm__ __volatile__ ( "rep outs" #_insn_suffix \ 125 : "=S" ( discard_S ) \ 126 : "d" ( io_addr ), "c" ( count ), \ 127 "0" ( data ) ); \ 128 } 129 X86_OUTX ( b, uint8_t, "b" ); 130 X86_OUTX ( w, uint16_t, "w" ); 131 X86_OUTX ( l, uint32_t, "k" ); 132 133 /* 134 * Slow down I/O 135 * 136 */ 137 138 static inline __always_inline void 139 IOAPI_INLINE ( x86, iodelay ) ( void ) { 140 __asm__ __volatile__ ( "outb %al, $0x80" ); 141 } 142 143 /* 144 * Memory barrier 145 * 146 */ 147 148 static inline __always_inline void 149 IOAPI_INLINE ( x86, mb ) ( void ) { 150 __asm__ __volatile__ ( "lock; addl $0, 0(%%esp)" : : : "memory" ); 151 } 152 153 #endif /* _GPXE_X86_IO_H */ 154