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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  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. /** Page shift */
  27. #define PAGE_SHIFT 12
  28. /*
  29. * Physical<->Bus and Bus<->I/O address mappings
  30. *
  31. */
  32. static inline __always_inline unsigned long
  33. IOAPI_INLINE ( x86, phys_to_bus ) ( unsigned long phys_addr ) {
  34. return phys_addr;
  35. }
  36. static inline __always_inline unsigned long
  37. IOAPI_INLINE ( x86, bus_to_phys ) ( unsigned long bus_addr ) {
  38. return bus_addr;
  39. }
  40. static inline __always_inline void *
  41. IOAPI_INLINE ( x86, ioremap ) ( unsigned long bus_addr, size_t len __unused ) {
  42. return ( bus_addr ? phys_to_virt ( bus_addr ) : NULL );
  43. }
  44. static inline __always_inline void
  45. IOAPI_INLINE ( x86, iounmap ) ( volatile const void *io_addr __unused ) {
  46. /* Nothing to do */
  47. }
  48. static inline __always_inline unsigned long
  49. IOAPI_INLINE ( x86, io_to_bus ) ( volatile const void *io_addr ) {
  50. return virt_to_phys ( io_addr );
  51. }
  52. /*
  53. * MMIO reads and writes up to native word size
  54. *
  55. */
  56. #define X86_READX( _api_func, _type ) \
  57. static inline __always_inline _type \
  58. IOAPI_INLINE ( x86, _api_func ) ( volatile _type *io_addr ) { \
  59. return *io_addr; \
  60. }
  61. X86_READX ( readb, uint8_t );
  62. X86_READX ( readw, uint16_t );
  63. X86_READX ( readl, uint32_t );
  64. #ifdef __x86_64__
  65. X86_READX ( readq, uint64_t );
  66. #endif
  67. #define X86_WRITEX( _api_func, _type ) \
  68. static inline __always_inline void \
  69. IOAPI_INLINE ( x86, _api_func ) ( _type data, \
  70. volatile _type *io_addr ) { \
  71. *io_addr = data; \
  72. }
  73. X86_WRITEX ( writeb, uint8_t );
  74. X86_WRITEX ( writew, uint16_t );
  75. X86_WRITEX ( writel, uint32_t );
  76. #ifdef __x86_64__
  77. X86_WRITEX ( writeq, uint64_t );
  78. #endif
  79. /*
  80. * PIO reads and writes up to 32 bits
  81. *
  82. */
  83. #define X86_INX( _insn_suffix, _type, _reg_prefix ) \
  84. static inline __always_inline _type \
  85. IOAPI_INLINE ( x86, in ## _insn_suffix ) ( volatile _type *io_addr ) { \
  86. _type data; \
  87. __asm__ __volatile__ ( "in" #_insn_suffix " %w1, %" _reg_prefix "0" \
  88. : "=a" ( data ) : "Nd" ( io_addr ) ); \
  89. return data; \
  90. } \
  91. static inline __always_inline void \
  92. IOAPI_INLINE ( x86, ins ## _insn_suffix ) ( volatile _type *io_addr, \
  93. _type *data, \
  94. unsigned int count ) { \
  95. unsigned int discard_D; \
  96. __asm__ __volatile__ ( "rep ins" #_insn_suffix \
  97. : "=D" ( discard_D ) \
  98. : "d" ( io_addr ), "c" ( count ), \
  99. "0" ( data ) ); \
  100. }
  101. X86_INX ( b, uint8_t, "b" );
  102. X86_INX ( w, uint16_t, "w" );
  103. X86_INX ( l, uint32_t, "k" );
  104. #define X86_OUTX( _insn_suffix, _type, _reg_prefix ) \
  105. static inline __always_inline void \
  106. IOAPI_INLINE ( x86, out ## _insn_suffix ) ( _type data, \
  107. volatile _type *io_addr ) { \
  108. __asm__ __volatile__ ( "out" #_insn_suffix " %" _reg_prefix "0, %w1" \
  109. : : "a" ( data ), "Nd" ( io_addr ) ); \
  110. } \
  111. static inline __always_inline void \
  112. IOAPI_INLINE ( x86, outs ## _insn_suffix ) ( volatile _type *io_addr, \
  113. const _type *data, \
  114. unsigned int count ) { \
  115. unsigned int discard_S; \
  116. __asm__ __volatile__ ( "rep outs" #_insn_suffix \
  117. : "=S" ( discard_S ) \
  118. : "d" ( io_addr ), "c" ( count ), \
  119. "0" ( data ) ); \
  120. }
  121. X86_OUTX ( b, uint8_t, "b" );
  122. X86_OUTX ( w, uint16_t, "w" );
  123. X86_OUTX ( l, uint32_t, "k" );
  124. /*
  125. * Slow down I/O
  126. *
  127. */
  128. static inline __always_inline void
  129. IOAPI_INLINE ( x86, iodelay ) ( void ) {
  130. __asm__ __volatile__ ( "outb %al, $0x80" );
  131. }
  132. /*
  133. * Memory barrier
  134. *
  135. */
  136. static inline __always_inline void
  137. IOAPI_INLINE ( x86, mb ) ( void ) {
  138. __asm__ __volatile__ ( "lock; addl $0, 0(%%esp)" : : : "memory" );
  139. }
  140. #endif /* _IPXE_X86_IO_H */