iPXE
x86_io.h
Go to the documentation of this file.
00001 #ifndef _IPXE_X86_IO_H
00002 #define _IPXE_X86_IO_H
00003 
00004 /** @file
00005  *
00006  * iPXE I/O API for x86
00007  *
00008  * x86 uses direct pointer dereferences for accesses to memory-mapped
00009  * I/O space, and the inX/outX instructions for accesses to
00010  * port-mapped I/O space.
00011  *
00012  * 64-bit atomic accesses (readq() and writeq()) use MMX instructions
00013  * under i386, and will crash original Pentium and earlier CPUs.
00014  * Fortunately, no hardware that requires atomic 64-bit accesses will
00015  * physically fit into a machine with such an old CPU anyway.
00016  */
00017 
00018 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00019 
00020 #ifdef IOAPI_X86
00021 #define IOAPI_PREFIX_x86
00022 #else
00023 #define IOAPI_PREFIX_x86 __x86_
00024 #endif
00025 
00026 /*
00027  * Memory space mappings
00028  *
00029  */
00030 
00031 /** Page shift */
00032 #define PAGE_SHIFT 12
00033 
00034 /*
00035  * Physical<->Bus address mappings
00036  *
00037  */
00038 
00039 static inline __always_inline unsigned long
00040 IOAPI_INLINE ( x86, phys_to_bus ) ( unsigned long phys_addr ) {
00041         return phys_addr;
00042 }
00043 
00044 static inline __always_inline unsigned long
00045 IOAPI_INLINE ( x86, bus_to_phys ) ( unsigned long bus_addr ) {
00046         return bus_addr;
00047 }
00048 
00049 /*
00050  * MMIO reads and writes up to native word size
00051  *
00052  */
00053 
00054 #define X86_READX( _api_func, _type )                                         \
00055 static inline __always_inline _type                                           \
00056 IOAPI_INLINE ( x86, _api_func ) ( volatile _type *io_addr ) {                 \
00057         return *io_addr;                                                      \
00058 }
00059 X86_READX ( readb, uint8_t );
00060 X86_READX ( readw, uint16_t );
00061 X86_READX ( readl, uint32_t );
00062 #ifdef __x86_64__
00063 X86_READX ( readq, uint64_t );
00064 #endif
00065 
00066 #define X86_WRITEX( _api_func, _type )                                        \
00067 static inline __always_inline void                                            \
00068 IOAPI_INLINE ( x86, _api_func ) ( _type data,                                 \
00069                                   volatile _type *io_addr ) {                 \
00070         *io_addr = data;                                                      \
00071 }
00072 X86_WRITEX ( writeb, uint8_t );
00073 X86_WRITEX ( writew, uint16_t );
00074 X86_WRITEX ( writel, uint32_t );
00075 #ifdef __x86_64__
00076 X86_WRITEX ( writeq, uint64_t );
00077 #endif
00078 
00079 /*
00080  * PIO reads and writes up to 32 bits
00081  *
00082  */
00083 
00084 #define X86_INX( _insn_suffix, _type, _reg_prefix )                           \
00085 static inline __always_inline _type                                           \
00086 IOAPI_INLINE ( x86, in ## _insn_suffix ) ( volatile _type *io_addr ) {        \
00087         _type data;                                                           \
00088         __asm__ __volatile__ ( "in" #_insn_suffix " %w1, %" _reg_prefix "0"   \
00089                                : "=a" ( data ) : "Nd" ( io_addr ) );          \
00090         return data;                                                          \
00091 }                                                                             \
00092 static inline __always_inline void                                            \
00093 IOAPI_INLINE ( x86, ins ## _insn_suffix ) ( volatile _type *io_addr,          \
00094                                             _type *data,                      \
00095                                             unsigned int count ) {            \
00096         unsigned int discard_D;                                               \
00097         __asm__ __volatile__ ( "rep ins" #_insn_suffix                        \
00098                                : "=D" ( discard_D )                           \
00099                                : "d" ( io_addr ), "c" ( count ),              \
00100                                  "0" ( data ) );                              \
00101 }
00102 X86_INX ( b, uint8_t, "b" );
00103 X86_INX ( w, uint16_t, "w" );
00104 X86_INX ( l, uint32_t, "k" );
00105 
00106 #define X86_OUTX( _insn_suffix, _type, _reg_prefix )                          \
00107 static inline __always_inline void                                            \
00108 IOAPI_INLINE ( x86, out ## _insn_suffix ) ( _type data,                       \
00109                                             volatile _type *io_addr ) {       \
00110         __asm__ __volatile__ ( "out" #_insn_suffix " %" _reg_prefix "0, %w1"  \
00111                                : : "a" ( data ), "Nd" ( io_addr ) );          \
00112 }                                                                             \
00113 static inline __always_inline void                                            \
00114 IOAPI_INLINE ( x86, outs ## _insn_suffix ) ( volatile _type *io_addr,         \
00115                                              const _type *data,               \
00116                                              unsigned int count ) {           \
00117         unsigned int discard_S;                                               \
00118         __asm__ __volatile__ ( "rep outs" #_insn_suffix                       \
00119                                : "=S" ( discard_S )                           \
00120                                : "d" ( io_addr ), "c" ( count ),              \
00121                                  "0" ( data ) );                              \
00122 }
00123 X86_OUTX ( b, uint8_t, "b" );
00124 X86_OUTX ( w, uint16_t, "w" );
00125 X86_OUTX ( l, uint32_t, "k" );
00126 
00127 /*
00128  * Slow down I/O
00129  *
00130  */
00131 
00132 static inline __always_inline void
00133 IOAPI_INLINE ( x86, iodelay ) ( void ) {
00134         __asm__ __volatile__ ( "outb %al, $0x80" );
00135 }
00136 
00137 /*
00138  * Memory barrier
00139  *
00140  */
00141 
00142 static inline __always_inline void
00143 IOAPI_INLINE ( x86, mb ) ( void ) {
00144         __asm__ __volatile__ ( "lock; addl $0, 0(%%esp)" : : : "memory" );
00145 }
00146 
00147 #endif /* _IPXE_X86_IO_H */