• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
IOAPI_INLINE(x86,phys_to_bus)37 IOAPI_INLINE ( x86, phys_to_bus ) ( unsigned long phys_addr ) {
38 	return phys_addr;
39 }
40 
41 static inline __always_inline unsigned long
IOAPI_INLINE(x86,bus_to_phys)42 IOAPI_INLINE ( x86, bus_to_phys ) ( unsigned long bus_addr ) {
43 	return bus_addr;
44 }
45 
46 static inline __always_inline void *
IOAPI_INLINE(x86,ioremap)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
IOAPI_INLINE(x86,iounmap)52 IOAPI_INLINE ( x86, iounmap ) ( volatile const void *io_addr __unused ) {
53 	/* Nothing to do */
54 }
55 
56 static inline __always_inline unsigned long
IOAPI_INLINE(x86,io_to_bus)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
IOAPI_INLINE(x86,iodelay)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
IOAPI_INLINE(x86,mb)149 IOAPI_INLINE ( x86, mb ) ( void ) {
150 	__asm__ __volatile__ ( "lock; addl $0, 0(%%esp)" : : : "memory" );
151 }
152 
153 #endif /* _GPXE_X86_IO_H */
154