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.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. #ifndef _IPXE_X86_IO_H
  2. #define _IPXE_X86_IO_H
  3. /** @file
  4. *
  5. * iPXE I/O API for x86
  6. *
  7. * i386 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. * and will crash original Pentium and earlier CPUs. Fortunately, no
  13. * hardware that requires atomic 64-bit accesses will physically fit
  14. * 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 phys_to_virt ( bus_addr );
  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 32 bits
  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. #define X86_WRITEX( _api_func, _type ) \
  63. static inline __always_inline void \
  64. IOAPI_INLINE ( x86, _api_func ) ( _type data, \
  65. volatile _type *io_addr ) { \
  66. *io_addr = data; \
  67. }
  68. X86_WRITEX ( writeb, uint8_t );
  69. X86_WRITEX ( writew, uint16_t );
  70. X86_WRITEX ( writel, uint32_t );
  71. /*
  72. * PIO reads and writes up to 32 bits
  73. *
  74. */
  75. #define X86_INX( _insn_suffix, _type, _reg_prefix ) \
  76. static inline __always_inline _type \
  77. IOAPI_INLINE ( x86, in ## _insn_suffix ) ( volatile _type *io_addr ) { \
  78. _type data; \
  79. __asm__ __volatile__ ( "in" #_insn_suffix " %w1, %" _reg_prefix "0" \
  80. : "=a" ( data ) : "Nd" ( io_addr ) ); \
  81. return data; \
  82. } \
  83. static inline __always_inline void \
  84. IOAPI_INLINE ( x86, ins ## _insn_suffix ) ( volatile _type *io_addr, \
  85. _type *data, \
  86. unsigned int count ) { \
  87. unsigned int discard_D; \
  88. __asm__ __volatile__ ( "rep ins" #_insn_suffix \
  89. : "=D" ( discard_D ) \
  90. : "d" ( io_addr ), "c" ( count ), \
  91. "0" ( data ) ); \
  92. }
  93. X86_INX ( b, uint8_t, "b" );
  94. X86_INX ( w, uint16_t, "w" );
  95. X86_INX ( l, uint32_t, "k" );
  96. #define X86_OUTX( _insn_suffix, _type, _reg_prefix ) \
  97. static inline __always_inline void \
  98. IOAPI_INLINE ( x86, out ## _insn_suffix ) ( _type data, \
  99. volatile _type *io_addr ) { \
  100. __asm__ __volatile__ ( "out" #_insn_suffix " %" _reg_prefix "0, %w1" \
  101. : : "a" ( data ), "Nd" ( io_addr ) ); \
  102. } \
  103. static inline __always_inline void \
  104. IOAPI_INLINE ( x86, outs ## _insn_suffix ) ( volatile _type *io_addr, \
  105. const _type *data, \
  106. unsigned int count ) { \
  107. unsigned int discard_S; \
  108. __asm__ __volatile__ ( "rep outs" #_insn_suffix \
  109. : "=S" ( discard_S ) \
  110. : "d" ( io_addr ), "c" ( count ), \
  111. "0" ( data ) ); \
  112. }
  113. X86_OUTX ( b, uint8_t, "b" );
  114. X86_OUTX ( w, uint16_t, "w" );
  115. X86_OUTX ( l, uint32_t, "k" );
  116. /*
  117. * Slow down I/O
  118. *
  119. */
  120. static inline __always_inline void
  121. IOAPI_INLINE ( x86, iodelay ) ( void ) {
  122. __asm__ __volatile__ ( "outb %al, $0x80" );
  123. }
  124. /*
  125. * Memory barrier
  126. *
  127. */
  128. static inline __always_inline void
  129. IOAPI_INLINE ( x86, mb ) ( void ) {
  130. __asm__ __volatile__ ( "lock; addl $0, 0(%%esp)" : : : "memory" );
  131. }
  132. #endif /* _IPXE_X86_IO_H */