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.

libkir.h 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. #ifndef LIBKIR_H
  2. #define LIBKIR_H
  3. #include "realmode.h"
  4. #ifndef ASSEMBLY
  5. /*
  6. * Full API documentation for these functions is in realmode.h.
  7. *
  8. */
  9. /* Access to variables in .data16 and .text16 in a way compatible with librm */
  10. #define __data16( variable ) variable
  11. #define __data16_array( variable, array ) variable array
  12. #define __bss16( variable ) variable
  13. #define __bss16_array( variable, array ) variable array
  14. #define __text16( variable ) variable
  15. #define __text16_array( variable,array ) variable array
  16. #define __use_data16( variable ) variable
  17. #define __use_text16( variable ) variable
  18. #define __from_data16( pointer ) pointer
  19. #define __from_text16( pointer ) pointer
  20. /* Real-mode data and code segments */
  21. static inline __attribute__ (( always_inline )) unsigned int _rm_cs ( void ) {
  22. uint16_t cs;
  23. __asm__ __volatile__ ( "movw %%cs, %w0" : "=r" ( cs ) );
  24. return cs;
  25. }
  26. static inline __attribute__ (( always_inline )) unsigned int _rm_ds ( void ) {
  27. uint16_t ds;
  28. __asm__ __volatile__ ( "movw %%ds, %w0" : "=r" ( ds ) );
  29. return ds;
  30. }
  31. #define rm_cs ( _rm_cs() )
  32. #define rm_ds ( _rm_ds() )
  33. /* Copy to/from base memory */
  34. static inline void copy_to_real_libkir ( unsigned int dest_seg,
  35. unsigned int dest_off,
  36. const void *src, size_t n ) {
  37. unsigned int discard_D, discard_S, discard_c;
  38. __asm__ __volatile__ ( "pushw %%es\n\t"
  39. "movw %3, %%es\n\t"
  40. "rep movsb\n\t"
  41. "popw %%es\n\t"
  42. : "=D" ( discard_D ), "=S" ( discard_S ),
  43. "=c" ( discard_c )
  44. : "r" ( dest_seg ), "D" ( dest_off ),
  45. "S" ( src ),
  46. "c" ( n )
  47. : "memory" );
  48. }
  49. static inline void copy_from_real_libkir ( void *dest,
  50. unsigned int src_seg,
  51. unsigned int src_off,
  52. size_t n ) {
  53. unsigned int discard_D, discard_S, discard_c;
  54. __asm__ __volatile__ ( "pushw %%ds\n\t"
  55. "movw %4, %%ds\n\t"
  56. "rep movsb\n\t"
  57. "popw %%ds\n\t"
  58. : "=D" ( discard_D ), "=S" ( discard_S ),
  59. "=c" ( discard_c )
  60. : "D" ( dest ),
  61. "r" ( src_seg ), "S" ( src_off ),
  62. "c" ( n )
  63. : "memory" );
  64. }
  65. #define copy_to_real copy_to_real_libkir
  66. #define copy_from_real copy_from_real_libkir
  67. /*
  68. * Transfer individual values to/from base memory. There may well be
  69. * a neater way to do this. We have two versions: one for constant
  70. * offsets (where the mov instruction must be of the form "mov
  71. * %es:123, %xx") and one for non-constant offsets (where the mov
  72. * instruction must be of the form "mov %es:(%xx), %yx". If it's
  73. * possible to incorporate both forms into one __asm__ instruction, I
  74. * don't know how to do it.
  75. *
  76. * Ideally, the mov instruction should be "mov%z0"; the "%z0" is meant
  77. * to expand to either "b", "w" or "l" depending on the size of
  78. * operand 0. This would remove the (minor) ambiguity in the mov
  79. * instruction. However, gcc on at least my system barfs with an
  80. * "internal compiler error" when confronted with %z0.
  81. *
  82. */
  83. #define put_real_kir_const_off( var, seg, off ) \
  84. __asm__ ( "movw %w1, %%es\n\t" \
  85. "mov %0, %%es:%c2\n\t" \
  86. "pushw %%ds\n\t" /* restore %es */ \
  87. "popw %%es\n\t" \
  88. : \
  89. : "r,r" ( var ), "rm,rm" ( seg ), "i,!r" ( off ) \
  90. )
  91. #define put_real_kir_nonconst_off( var, seg, off ) \
  92. __asm__ ( "movw %w1, %%es\n\t" \
  93. "mov %0, %%es:(%2)\n\t" \
  94. "pushw %%ds\n\t" /* restore %es */ \
  95. "popw %%es\n\t" \
  96. : \
  97. : "r" ( var ), "rm" ( seg ), "r" ( off ) \
  98. )
  99. #define put_real_kir( var, seg, off ) \
  100. do { \
  101. if ( __builtin_constant_p ( off ) ) \
  102. put_real_kir_const_off ( var, seg, off ); \
  103. else \
  104. put_real_kir_nonconst_off ( var, seg, off ); \
  105. } while ( 0 )
  106. #define get_real_kir_const_off( var, seg, off ) \
  107. __asm__ ( "movw %w1, %%es\n\t" \
  108. "mov %%es:%c2, %0\n\t" \
  109. "pushw %%ds\n\t" /* restore %es */ \
  110. "popw %%es\n\t" \
  111. : "=r,r" ( var ) \
  112. : "rm,rm" ( seg ), "i,!r" ( off ) \
  113. )
  114. #define get_real_kir_nonconst_off( var, seg, off ) \
  115. __asm__ ( "movw %w1, %%es\n\t" \
  116. "mov %%es:(%2), %0\n\t" \
  117. "pushw %%ds\n\t" /* restore %es */ \
  118. "popw %%es\n\t" \
  119. : "=r" ( var ) \
  120. : "rm" ( seg ), "r" ( off ) \
  121. )
  122. #define get_real_kir( var, seg, off ) \
  123. do { \
  124. if ( __builtin_constant_p ( off ) ) \
  125. get_real_kir_const_off ( var, seg, off ); \
  126. else \
  127. get_real_kir_nonconst_off ( var, seg, off ); \
  128. } while ( 0 )
  129. #define put_real put_real_kir
  130. #define get_real get_real_kir
  131. /**
  132. * A pointer to a user buffer
  133. *
  134. * This is actually a struct segoff, but encoded as a uint32_t to
  135. * ensure that gcc passes it around efficiently.
  136. */
  137. typedef uint32_t userptr_t;
  138. /**
  139. * Copy data to user buffer
  140. *
  141. * @v buffer User buffer
  142. * @v offset Offset within user buffer
  143. * @v src Source
  144. * @v len Length
  145. */
  146. static inline __attribute__ (( always_inline )) void
  147. copy_to_user ( userptr_t buffer, off_t offset, const void *src, size_t len ) {
  148. copy_to_real ( ( buffer >> 16 ), ( ( buffer & 0xffff ) + offset ),
  149. src, len );
  150. }
  151. /**
  152. * Copy data from user buffer
  153. *
  154. * @v dest Destination
  155. * @v buffer User buffer
  156. * @v offset Offset within user buffer
  157. * @v len Length
  158. */
  159. static inline __attribute__ (( always_inline )) void
  160. copy_from_user ( void *dest, userptr_t buffer, off_t offset, size_t len ) {
  161. copy_from_real ( dest, ( buffer >> 16 ),
  162. ( ( buffer & 0xffff ) + offset ), len );
  163. }
  164. /**
  165. * Convert segment:offset address to user buffer
  166. *
  167. * @v segment Real-mode segment
  168. * @v offset Real-mode offset
  169. * @ret buffer User buffer
  170. */
  171. static inline __attribute__ (( always_inline )) userptr_t
  172. real_to_user ( unsigned int segment, unsigned int offset ) {
  173. return ( ( segment << 16 ) | offset );
  174. }
  175. /**
  176. * Convert virtual address to user buffer
  177. *
  178. * @v virtual Virtual address
  179. * @ret buffer User buffer
  180. *
  181. * This constructs a user buffer from an ordinary pointer. Use it
  182. * when you need to pass a pointer to an internal buffer to a function
  183. * that expects a @c userptr_t.
  184. */
  185. static inline __attribute__ (( always_inline )) userptr_t
  186. virt_to_user ( void * virtual ) {
  187. return real_to_user ( rm_ds, ( intptr_t ) virtual );
  188. }
  189. /* TEXT16_CODE: declare a fragment of code that resides in .text16 */
  190. #define TEXT16_CODE( asm_code_str ) \
  191. ".section \".text16\", \"ax\", @progbits\n\t" \
  192. ".code16\n\t" \
  193. ".arch i386\n\t" \
  194. asm_code_str "\n\t" \
  195. ".code16gcc\n\t" \
  196. ".previous\n\t"
  197. /* REAL_CODE: declare a fragment of code that executes in real mode */
  198. #define REAL_CODE( asm_code_str ) \
  199. ".code16\n\t" \
  200. asm_code_str "\n\t" \
  201. ".code16gcc\n\t"
  202. #endif /* ASSEMBLY */
  203. #endif /* LIBKIR_H */