8
* x86 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
* under i386, and will crash original Pentium and earlier CPUs.
14
* Fortunately, no hardware that requires atomic 64-bit accesses will
15
* physically fit into a machine with such an old CPU anyway.
18
FILE_LICENCE ( GPL2_OR_LATER );
21
#define IOAPI_PREFIX_x86
23
#define IOAPI_PREFIX_x86 __x86_
27
* Memory space mappings
32
* Physical<->Bus and Bus<->I/O address mappings
36
static inline __always_inline unsigned long
37
IOAPI_INLINE ( x86, phys_to_bus ) ( unsigned long phys_addr ) {
41
static inline __always_inline unsigned long
42
IOAPI_INLINE ( x86, bus_to_phys ) ( unsigned long bus_addr ) {
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 );
51
static inline __always_inline void
52
IOAPI_INLINE ( x86, iounmap ) ( volatile const void *io_addr __unused ) {
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 );
62
* MMIO reads and writes up to native word size
66
#define X86_READX( _api_func, _type ) \
67
static inline __always_inline _type \
68
IOAPI_INLINE ( x86, _api_func ) ( volatile _type *io_addr ) { \
71
X86_READX ( readb, uint8_t );
72
X86_READX ( readw, uint16_t );
73
X86_READX ( readl, uint32_t );
75
X86_READX ( readq, uint64_t );
78
#define X86_WRITEX( _api_func, _type ) \
79
static inline __always_inline void \
80
IOAPI_INLINE ( x86, _api_func ) ( _type data, \
81
volatile _type *io_addr ) { \
84
X86_WRITEX ( writeb, uint8_t );
85
X86_WRITEX ( writew, uint16_t );
86
X86_WRITEX ( writel, uint32_t );
88
X86_WRITEX ( writeq, uint64_t );
92
* PIO reads and writes up to 32 bits
96
#define X86_INX( _insn_suffix, _type, _reg_prefix ) \
97
static inline __always_inline _type \
98
IOAPI_INLINE ( x86, in ## _insn_suffix ) ( volatile _type *io_addr ) { \
100
__asm__ __volatile__ ( "in" #_insn_suffix " %w1, %" _reg_prefix "0" \
101
: "=a" ( data ) : "Nd" ( io_addr ) ); \
104
static inline __always_inline void \
105
IOAPI_INLINE ( x86, ins ## _insn_suffix ) ( volatile _type *io_addr, \
107
unsigned int count ) { \
108
unsigned int discard_D; \
109
__asm__ __volatile__ ( "rep ins" #_insn_suffix \
110
: "=D" ( discard_D ) \
111
: "d" ( io_addr ), "c" ( count ), \
114
X86_INX ( b, uint8_t, "b" );
115
X86_INX ( w, uint16_t, "w" );
116
X86_INX ( l, uint32_t, "k" );
118
#define X86_OUTX( _insn_suffix, _type, _reg_prefix ) \
119
static inline __always_inline void \
120
IOAPI_INLINE ( x86, out ## _insn_suffix ) ( _type data, \
121
volatile _type *io_addr ) { \
122
__asm__ __volatile__ ( "out" #_insn_suffix " %" _reg_prefix "0, %w1" \
123
: : "a" ( data ), "Nd" ( io_addr ) ); \
125
static inline __always_inline void \
126
IOAPI_INLINE ( x86, outs ## _insn_suffix ) ( volatile _type *io_addr, \
128
unsigned int count ) { \
129
unsigned int discard_S; \
130
__asm__ __volatile__ ( "rep outs" #_insn_suffix \
131
: "=S" ( discard_S ) \
132
: "d" ( io_addr ), "c" ( count ), \
135
X86_OUTX ( b, uint8_t, "b" );
136
X86_OUTX ( w, uint16_t, "w" );
137
X86_OUTX ( l, uint32_t, "k" );
144
static inline __always_inline void
145
IOAPI_INLINE ( x86, iodelay ) ( void ) {
146
__asm__ __volatile__ ( "outb %al, $0x80" );
154
static inline __always_inline void
155
IOAPI_INLINE ( x86, mb ) ( void ) {
156
__asm__ __volatile__ ( "lock; addl $0, 0(%%esp)" : : : "memory" );
159
#endif /* _IPXE_X86_IO_H */