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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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. /* Copy to/from base memory */
  10. static inline void copy_to_real_libkir ( uint16_t dest_seg, uint16_t dest_off,
  11. void *src, size_t n ) {
  12. __asm__ __volatile__ ( "movw %4, %%es\n\t"
  13. "cld\n\t"
  14. "rep movsb\n\t"
  15. "pushw %%ds\n\t" /* restore %es */
  16. "popw %%es\n\t"
  17. : "=S" ( src ), "=D" ( dest_off ),
  18. "=c" ( n ) /* clobbered */
  19. : "S" ( src ), "r" ( dest_seg ),
  20. "D" ( dest_off ), "c" ( n )
  21. : "memory" );
  22. }
  23. static inline void copy_from_real_libkir ( void *dest,
  24. uint16_t src_seg, uint16_t src_off,
  25. size_t n ) {
  26. __asm__ __volatile__ ( "movw %%ax, %%ds\n\t"
  27. "cld\n\t"
  28. "rep movsb\n\t"
  29. "pushw %%es\n\t" /* restore %ds */
  30. "popw %%ds\n\t"
  31. : "=S" ( src_off ), "=D" ( dest ),
  32. "=c" ( n ) /* clobbered */
  33. : "a" ( src_seg ), "S" ( src_off ),
  34. "D" ( dest ), "c" ( n )
  35. : "memory" );
  36. }
  37. #define copy_to_real copy_to_real_libkir
  38. #define copy_from_real copy_from_real_libkir
  39. /*
  40. * Transfer individual values to/from base memory. There may well be
  41. * a neater way to do this. We have two versions: one for constant
  42. * offsets (where the mov instruction must be of the form "mov
  43. * %es:123, %xx") and one for non-constant offsets (where the mov
  44. * instruction must be of the form "mov %es:(%xx), %yx". If it's
  45. * possible to incorporate both forms into one __asm__ instruction, I
  46. * don't know how to do it.
  47. *
  48. * Ideally, the mov instruction should be "mov%z0"; the "%z0" is meant
  49. * to expand to either "b", "w" or "l" depending on the size of
  50. * operand 0. This would remove the (minor) ambiguity in the mov
  51. * instruction. However, gcc on at least my system barfs with an
  52. * "internal compiler error" when confronted with %z0.
  53. *
  54. */
  55. #define put_real_kir_const_off( var, seg, off ) \
  56. __asm__ ( "movw %w1, %%es\n\t" \
  57. "mov %0, %%es:%c2\n\t" \
  58. "pushw %%ds\n\t" /* restore %es */ \
  59. "popw %%es\n\t" \
  60. : \
  61. : "r,r" ( var ), "rm,rm" ( seg ), "i,!r" ( off ) \
  62. )
  63. #define put_real_kir_nonconst_off( var, seg, off ) \
  64. __asm__ ( "movw %w1, %%es\n\t" \
  65. "mov %0, %%es:(%2)\n\t" \
  66. "pushw %%ds\n\t" /* restore %es */ \
  67. "popw %%es\n\t" \
  68. : \
  69. : "r" ( var ), "rm" ( seg ), "r" ( off ) \
  70. )
  71. #define put_real_kir( var, seg, off ) \
  72. do { \
  73. if ( __builtin_constant_p ( off ) ) \
  74. put_real_kir_const_off ( var, seg, off ); \
  75. else \
  76. put_real_kir_nonconst_off ( var, seg, off ); \
  77. } while ( 0 )
  78. #define get_real_kir_const_off( var, seg, off ) \
  79. __asm__ ( "movw %w1, %%es\n\t" \
  80. "mov %%es:%c2, %0\n\t" \
  81. "pushw %%ds\n\t" /* restore %es */ \
  82. "popw %%es\n\t" \
  83. : "=r,r" ( var ) \
  84. : "rm,rm" ( seg ), "i,!r" ( off ) \
  85. )
  86. #define get_real_kir_nonconst_off( var, seg, off ) \
  87. __asm__ ( "movw %w1, %%es\n\t" \
  88. "mov %%es:(%2), %0\n\t" \
  89. "pushw %%ds\n\t" /* restore %es */ \
  90. "popw %%es\n\t" \
  91. : "=r" ( var ) \
  92. : "rm" ( seg ), "r" ( off ) \
  93. )
  94. #define get_real_kir( var, seg, off ) \
  95. do { \
  96. if ( __builtin_constant_p ( off ) ) \
  97. get_real_kir_const_off ( var, seg, off ); \
  98. else \
  99. get_real_kir_nonconst_off ( var, seg, off ); \
  100. } while ( 0 )
  101. #define put_real put_real_kir
  102. #define get_real get_real_kir
  103. /* Place/remove parameter on real-mode stack in a way that's
  104. * compatible with libkir
  105. */
  106. #define BASEMEM_PARAMETER_INIT_LIBKIR( param ) \
  107. ( ( uint16_t ) ( ( uint32_t ) & ( param ) ) )
  108. #define BASEMEM_PARAMETER_DONE_LIBKIR( param )
  109. #define BASEMEM_PARAMETER_INIT BASEMEM_PARAMETER_INIT_LIBKIR
  110. #define BASEMEM_PARAMETER_DONE BASEMEM_PARAMETER_DONE_LIBKIR
  111. /* REAL_FRAGMENT: Declare and define a real-mode code fragment in
  112. * .text16. We don't need this for REAL_EXEC, since we can just
  113. * execute our real-mode code inline, but it's handy in case someone
  114. * genuinely wants to create a block of code that can be copied to a
  115. * specific location and then executed.
  116. *
  117. * Note that we put the code in the data segment, since otherwise we
  118. * can't (easily) access it in order to copy it to its target
  119. * location. We should never be calling any REAL_FRAGMENT routines
  120. * directly anyway.
  121. */
  122. #define REAL_FRAGMENT( name, asm_code_str ) \
  123. extern void name ( void ); \
  124. extern char name ## _size[]; \
  125. __asm__ __volatile__ ( \
  126. ".section \".data.text16\"\n\t" \
  127. ".code16\n\t" \
  128. ".arch i386\n\t" \
  129. #name ":\n\t" \
  130. asm_code_str "\n\t" \
  131. "lret\n\t" \
  132. #name "_end:\n\t" \
  133. ".equ " #name "_size, " #name "_end - " #name "\n\t" \
  134. ".code16gcc\n\t" \
  135. ".previous\n\t" \
  136. : : \
  137. )
  138. #define FRAGMENT_SIZE( fragment ) ( (size_t) fragment ## _size )
  139. /* REAL_CALL: call an external real-mode routine */
  140. #define OUT_CONSTRAINTS(...) __VA_ARGS__
  141. #define IN_CONSTRAINTS(...) "m" ( __routine ), ## __VA_ARGS__
  142. #define CLOBBER(...) __VA_ARGS__
  143. #define REAL_CALL( routine, num_out_constraints, out_constraints, \
  144. in_constraints, clobber ) \
  145. do { \
  146. segoff_t __routine = routine; \
  147. __asm__ __volatile__ ( \
  148. "pushl %" #num_out_constraints "\n\t" \
  149. ".code16\n\t" \
  150. "pushw %%gs\n\t" /* preserve segs */ \
  151. "pushw %%fs\n\t" \
  152. "pushw %%es\n\t" \
  153. "pushw %%ds\n\t" \
  154. "pushw %%cs\n\t" /* lcall to routine */ \
  155. "call 1f\n\t" \
  156. "jmp 2f\n\t" \
  157. "\n1:\n\t" \
  158. "addr32 pushl 12(%%esp)\n\t" \
  159. "lret\n\t" \
  160. "\n2:\n\t" \
  161. "popw %%ds\n\t" /* restore segs */ \
  162. "popw %%es\n\t" \
  163. "popw %%fs\n\t" \
  164. "popw %%gs\n\t" \
  165. "addw $4, %%sp\n\t" \
  166. ".code16gcc\n\t" \
  167. : out_constraints : in_constraints : clobber \
  168. ); \
  169. } while ( 0 )
  170. /* REAL_EXEC: execute some inline assembly code in a way that matches
  171. * the interface of librm
  172. */
  173. #define IN_CONSTRAINTS_NO_ROUTINE( routine, ... ) __VA_ARGS__
  174. #define REAL_EXEC( name, asm_code_str, num_out_constraints, out_constraints, \
  175. in_constraints, clobber ) \
  176. __asm__ __volatile__ ( \
  177. ".code16\n\t" \
  178. "pushw %%gs\n\t" \
  179. "pushw %%fs\n\t" \
  180. "pushw %%es\n\t" \
  181. "pushw %%ds\n\t" \
  182. "\n" #name ":\n\t" \
  183. asm_code_str \
  184. "popw %%ds\n\t" \
  185. "popw %%es\n\t" \
  186. "popw %%fs\n\t" \
  187. "popw %%gs\n\t" \
  188. ".code16gcc\n\t" \
  189. : out_constraints \
  190. : IN_CONSTRAINTS_NO_ROUTINE ( in_constraints ) \
  191. : clobber \
  192. );
  193. #endif /* ASSEMBLY */
  194. #endif /* LIBKIR_H */