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