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.
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.
21 #define IOAPI_PREFIX_x86
23 #define IOAPI_PREFIX_x86 __x86_
27 * Memory space mappings
31 static inline __always_inline unsigned long
32 IOAPI_INLINE ( x86, virt_to_phys ) ( volatile const void *addr ) {
33 return ( ( ( unsigned long ) addr ) + virt_offset );
36 static inline __always_inline void *
37 IOAPI_INLINE ( x86, phys_to_virt ) ( unsigned long phys_addr ) {
38 return ( ( void * ) ( phys_addr - virt_offset ) );
41 static inline __always_inline unsigned long
42 IOAPI_INLINE ( x86, virt_to_bus ) ( volatile const void *addr ) {
43 return virt_to_phys ( addr );
46 static inline __always_inline void *
47 IOAPI_INLINE ( x86, bus_to_virt ) ( unsigned long bus_addr ) {
48 return phys_to_virt ( bus_addr );
51 static inline __always_inline void *
52 IOAPI_INLINE ( x86, ioremap ) ( unsigned long bus_addr, size_t len __unused ) {
53 return phys_to_virt ( bus_addr );
56 static inline __always_inline void
57 IOAPI_INLINE ( x86, iounmap ) ( volatile const void *io_addr __unused ) {
61 static inline __always_inline unsigned long
62 IOAPI_INLINE ( x86, io_to_bus ) ( volatile const void *io_addr ) {
63 return virt_to_phys ( io_addr );
67 * MMIO reads and writes up to 32 bits
71 #define X86_READX( _api_func, _type ) \
72 static inline __always_inline _type \
73 IOAPI_INLINE ( x86, _api_func ) ( volatile _type *io_addr ) { \
76 X86_READX ( readb, uint8_t );
77 X86_READX ( readw, uint16_t );
78 X86_READX ( readl, uint32_t );
80 #define X86_WRITEX( _api_func, _type ) \
81 static inline __always_inline void \
82 IOAPI_INLINE ( x86, _api_func ) ( _type data, \
83 volatile _type *io_addr ) { \
86 X86_WRITEX ( writeb, uint8_t );
87 X86_WRITEX ( writew, uint16_t );
88 X86_WRITEX ( writel, uint32_t );
91 * PIO reads and writes up to 32 bits
95 #define X86_INX( _insn_suffix, _type, _reg_prefix ) \
96 static inline __always_inline _type \
97 IOAPI_INLINE ( x86, in ## _insn_suffix ) ( volatile _type *io_addr ) { \
99 __asm__ __volatile__ ( "in" #_insn_suffix " %w1, %" _reg_prefix "0" \
100 : "=a" ( data ) : "Nd" ( io_addr ) ); \
103 static inline __always_inline void \
104 IOAPI_INLINE ( x86, ins ## _insn_suffix ) ( volatile _type *io_addr, \
106 unsigned int count ) { \
107 unsigned int discard_D; \
108 __asm__ __volatile__ ( "rep ins" #_insn_suffix \
109 : "=D" ( discard_D ) \
110 : "d" ( io_addr ), "c" ( count ), \
113 X86_INX ( b, uint8_t, "b" );
114 X86_INX ( w, uint16_t, "w" );
115 X86_INX ( l, uint32_t, "k" );
117 #define X86_OUTX( _insn_suffix, _type, _reg_prefix ) \
118 static inline __always_inline void \
119 IOAPI_INLINE ( x86, out ## _insn_suffix ) ( _type data, \
120 volatile _type *io_addr ) { \
121 __asm__ __volatile__ ( "out" #_insn_suffix " %" _reg_prefix "0, %w1" \
122 : : "a" ( data ), "Nd" ( io_addr ) ); \
124 static inline __always_inline void \
125 IOAPI_INLINE ( x86, outs ## _insn_suffix ) ( volatile _type *io_addr, \
127 unsigned int count ) { \
128 unsigned int discard_D; \
129 __asm__ __volatile__ ( "rep outs" #_insn_suffix \
130 : "=D" ( discard_D ) \
131 : "d" ( io_addr ), "c" ( count ), \
134 X86_OUTX ( b, uint8_t, "b" );
135 X86_OUTX ( w, uint16_t, "w" );
136 X86_OUTX ( l, uint32_t, "k" );
143 static inline __always_inline void
144 IOAPI_INLINE ( x86, iodelay ) ( void ) {
145 __asm__ __volatile__ ( "outb %al, $0x80" );
153 static inline __always_inline void
154 IOAPI_INLINE ( x86, mb ) ( void ) {
155 __asm__ __volatile__ ( "lock; addl $0, 0(%%esp)" : : : "memory" );
158 #endif /* _GPXE_X86_IO_H */