You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

x86_io.h 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. #ifndef _IPXE_X86_IO_H
  2. #define _IPXE_X86_IO_H
  3. /** @file
  4. *
  5. * iPXE I/O API for x86
  6. *
  7. * x86 uses direct pointer dereferences for accesses to memory-mapped
  8. * I/O space, and the inX/outX instructions for accesses to
  9. * port-mapped I/O space.
  10. *
  11. * 64-bit atomic accesses (readq() and writeq()) use MMX instructions
  12. * under i386, and will crash original Pentium and earlier CPUs.
  13. * Fortunately, no hardware that requires atomic 64-bit accesses will
  14. * physically fit into a machine with such an old CPU anyway.
  15. */
  16. FILE_LICENCE ( GPL2_OR_LATER );
  17. #ifdef IOAPI_X86
  18. #define IOAPI_PREFIX_x86
  19. #else
  20. #define IOAPI_PREFIX_x86 __x86_
  21. #endif
  22. /*
  23. * Memory space mappings
  24. *
  25. */
  26. /*
  27. * Physical<->Bus and Bus<->I/O address mappings
  28. *
  29. */
  30. static inline __always_inline unsigned long
  31. IOAPI_INLINE ( x86, phys_to_bus ) ( unsigned long phys_addr ) {
  32. return phys_addr;
  33. }
  34. static inline __always_inline unsigned long
  35. IOAPI_INLINE ( x86, bus_to_phys ) ( unsigned long bus_addr ) {
  36. return bus_addr;
  37. }
  38. static inline __always_inline void *
  39. IOAPI_INLINE ( x86, ioremap ) ( unsigned long bus_addr, size_t len __unused ) {
  40. return ( bus_addr ? phys_to_virt ( bus_addr ) : NULL );
  41. }
  42. static inline __always_inline void
  43. IOAPI_INLINE ( x86, iounmap ) ( volatile const void *io_addr __unused ) {
  44. /* Nothing to do */
  45. }
  46. static inline __always_inline unsigned long
  47. IOAPI_INLINE ( x86, io_to_bus ) ( volatile const void *io_addr ) {
  48. return virt_to_phys ( io_addr );
  49. }
  50. /*
  51. * MMIO reads and writes up to native word size
  52. *
  53. */
  54. #define X86_READX( _api_func, _type ) \
  55. static inline __always_inline _type \
  56. IOAPI_INLINE ( x86, _api_func ) ( volatile _type *io_addr ) { \
  57. return *io_addr; \
  58. }
  59. X86_READX ( readb, uint8_t );
  60. X86_READX ( readw, uint16_t );
  61. X86_READX ( readl, uint32_t );
  62. #ifdef __x86_64__
  63. X86_READX ( readq, uint64_t );
  64. #endif
  65. #define X86_WRITEX( _api_func, _type ) \
  66. static inline __always_inline void \
  67. IOAPI_INLINE ( x86, _api_func ) ( _type data, \
  68. volatile _type *io_addr ) { \
  69. *io_addr = data; \
  70. }
  71. X86_WRITEX ( writeb, uint8_t );
  72. X86_WRITEX ( writew, uint16_t );
  73. X86_WRITEX ( writel, uint32_t );
  74. #ifdef __x86_64__
  75. X86_WRITEX ( writeq, uint64_t );
  76. #endif
  77. /*
  78. * PIO reads and writes up to 32 bits
  79. *
  80. */
  81. #define X86_INX( _insn_suffix, _type, _reg_prefix ) \
  82. static inline __always_inline _type \
  83. IOAPI_INLINE ( x86, in ## _insn_suffix ) ( volatile _type *io_addr ) { \
  84. _type data; \
  85. __asm__ __volatile__ ( "in" #_insn_suffix " %w1, %" _reg_prefix "0" \
  86. : "=a" ( data ) : "Nd" ( io_addr ) ); \
  87. return data; \
  88. } \
  89. static inline __always_inline void \
  90. IOAPI_INLINE ( x86, ins ## _insn_suffix ) ( volatile _type *io_addr, \
  91. _type *data, \
  92. unsigned int count ) { \
  93. unsigned int discard_D; \
  94. __asm__ __volatile__ ( "rep ins" #_insn_suffix \
  95. : "=D" ( discard_D ) \
  96. : "d" ( io_addr ), "c" ( count ), \
  97. "0" ( data ) ); \
  98. }
  99. X86_INX ( b, uint8_t, "b" );
  100. X86_INX ( w, uint16_t, "w" );
  101. X86_INX ( l, uint32_t, "k" );
  102. #define X86_OUTX( _insn_suffix, _type, _reg_prefix ) \
  103. static inline __always_inline void \
  104. IOAPI_INLINE ( x86, out ## _insn_suffix ) ( _type data, \
  105. volatile _type *io_addr ) { \
  106. __asm__ __volatile__ ( "out" #_insn_suffix " %" _reg_prefix "0, %w1" \
  107. : : "a" ( data ), "Nd" ( io_addr ) ); \
  108. } \
  109. static inline __always_inline void \
  110. IOAPI_INLINE ( x86, outs ## _insn_suffix ) ( volatile _type *io_addr, \
  111. const _type *data, \
  112. unsigned int count ) { \
  113. unsigned int discard_S; \
  114. __asm__ __volatile__ ( "rep outs" #_insn_suffix \
  115. : "=S" ( discard_S ) \
  116. : "d" ( io_addr ), "c" ( count ), \
  117. "0" ( data ) ); \
  118. }
  119. X86_OUTX ( b, uint8_t, "b" );
  120. X86_OUTX ( w, uint16_t, "w" );
  121. X86_OUTX ( l, uint32_t, "k" );
  122. /*
  123. * Slow down I/O
  124. *
  125. */
  126. static inline __always_inline void
  127. IOAPI_INLINE ( x86, iodelay ) ( void ) {
  128. __asm__ __volatile__ ( "outb %al, $0x80" );
  129. }
  130. /*
  131. * Memory barrier
  132. *
  133. */
  134. static inline __always_inline void
  135. IOAPI_INLINE ( x86, mb ) ( void ) {
  136. __asm__ __volatile__ ( "lock; addl $0, 0(%%esp)" : : : "memory" );
  137. }
  138. #endif /* _IPXE_X86_IO_H */