summaryrefslogtreecommitdiff
path: root/gpxe/src/arch/i386/include/gpxe/x86_io.h
blob: beb5b22a6e8bfa3250894dfff1ab3aabbb5b2473 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#ifndef _GPXE_X86_IO_H
#define _GPXE_X86_IO_H

/** @file
 *
 * gPXE I/O API for x86
 *
 * i386 uses direct pointer dereferences for accesses to memory-mapped
 * I/O space, and the inX/outX instructions for accesses to
 * port-mapped I/O space.
 *
 * 64-bit atomic accesses (readq() and writeq()) use MMX instructions,
 * and will crash original Pentium and earlier CPUs.  Fortunately, no
 * hardware that requires atomic 64-bit accesses will physically fit
 * into a machine with such an old CPU anyway.
 */

FILE_LICENCE ( GPL2_OR_LATER );

#ifdef IOAPI_X86
#define IOAPI_PREFIX_x86
#else
#define IOAPI_PREFIX_x86 __x86_
#endif

/*
 * Memory space mappings
 *
 */

/*
 * Physical<->Bus and Bus<->I/O address mappings
 *
 */

static inline __always_inline unsigned long
IOAPI_INLINE ( x86, phys_to_bus ) ( unsigned long phys_addr ) {
	return phys_addr;
}

static inline __always_inline unsigned long
IOAPI_INLINE ( x86, bus_to_phys ) ( unsigned long bus_addr ) {
	return bus_addr;
}

static inline __always_inline void *
IOAPI_INLINE ( x86, ioremap ) ( unsigned long bus_addr, size_t len __unused ) {
	return phys_to_virt ( bus_addr );
}

static inline __always_inline void
IOAPI_INLINE ( x86, iounmap ) ( volatile const void *io_addr __unused ) {
	/* Nothing to do */
}

static inline __always_inline unsigned long
IOAPI_INLINE ( x86, io_to_bus ) ( volatile const void *io_addr ) {
	return virt_to_phys ( io_addr );
}

/*
 * MMIO reads and writes up to 32 bits
 *
 */

#define X86_READX( _api_func, _type )					      \
static inline __always_inline _type					      \
IOAPI_INLINE ( x86, _api_func ) ( volatile _type *io_addr ) {		      \
	return *io_addr;						      \
}
X86_READX ( readb, uint8_t );
X86_READX ( readw, uint16_t );
X86_READX ( readl, uint32_t );

#define X86_WRITEX( _api_func, _type )					      \
static inline __always_inline void					      \
IOAPI_INLINE ( x86, _api_func ) ( _type data,				      \
				  volatile _type *io_addr ) {		      \
	*io_addr = data;						      \
}
X86_WRITEX ( writeb, uint8_t );
X86_WRITEX ( writew, uint16_t );
X86_WRITEX ( writel, uint32_t );

/*
 * PIO reads and writes up to 32 bits
 *
 */

#define X86_INX( _insn_suffix, _type, _reg_prefix )			      \
static inline __always_inline _type					      \
IOAPI_INLINE ( x86, in ## _insn_suffix ) ( volatile _type *io_addr ) {	      \
	_type data;							      \
	__asm__ __volatile__ ( "in" #_insn_suffix " %w1, %" _reg_prefix "0"   \
			       : "=a" ( data ) : "Nd" ( io_addr ) );	      \
	return data;							      \
}									      \
static inline __always_inline void					      \
IOAPI_INLINE ( x86, ins ## _insn_suffix ) ( volatile _type *io_addr,	      \
					    _type *data,		      \
					    unsigned int count ) {	      \
	unsigned int discard_D;						      \
	__asm__ __volatile__ ( "rep ins" #_insn_suffix			      \
			       : "=D" ( discard_D )			      \
			       : "d" ( io_addr ), "c" ( count ),	      \
				 "0" ( data ) );			      \
}
X86_INX ( b, uint8_t, "b" );
X86_INX ( w, uint16_t, "w" );
X86_INX ( l, uint32_t, "k" );

#define X86_OUTX( _insn_suffix, _type, _reg_prefix )			      \
static inline __always_inline void					      \
IOAPI_INLINE ( x86, out ## _insn_suffix ) ( _type data,			      \
					    volatile _type *io_addr ) {	      \
	__asm__ __volatile__ ( "out" #_insn_suffix " %" _reg_prefix "0, %w1"  \
			       : : "a" ( data ), "Nd" ( io_addr ) );	      \
}									      \
static inline __always_inline void					      \
IOAPI_INLINE ( x86, outs ## _insn_suffix ) ( volatile _type *io_addr,	      \
					     const _type *data,		      \
					     unsigned int count ) {	      \
	unsigned int discard_S;						      \
	__asm__ __volatile__ ( "rep outs" #_insn_suffix			      \
			       : "=S" ( discard_S )			      \
			       : "d" ( io_addr ), "c" ( count ),	      \
				 "0" ( data ) );			      \
}
X86_OUTX ( b, uint8_t, "b" );
X86_OUTX ( w, uint16_t, "w" );
X86_OUTX ( l, uint32_t, "k" );

/*
 * Slow down I/O
 *
 */

static inline __always_inline void
IOAPI_INLINE ( x86, iodelay ) ( void ) {
	__asm__ __volatile__ ( "outb %al, $0x80" );
}

/*
 * Memory barrier
 *
 */

static inline __always_inline void
IOAPI_INLINE ( x86, mb ) ( void ) {
	__asm__ __volatile__ ( "lock; addl $0, 0(%%esp)" : : : "memory" );
}

#endif /* _GPXE_X86_IO_H */