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 7.0KB

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