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.

librm.h 9.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. #ifndef LIBRM_H
  2. #define LIBRM_H
  3. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  4. /* Segment selectors as used in our protected-mode GDTs.
  5. *
  6. * Don't change these unless you really know what you're doing.
  7. */
  8. #define VIRTUAL_CS 0x08
  9. #define VIRTUAL_DS 0x10
  10. #define PHYSICAL_CS 0x18
  11. #define PHYSICAL_DS 0x20
  12. #define REAL_CS 0x28
  13. #define REAL_DS 0x30
  14. #define P2R_DS 0x38
  15. /* Calculate symbol address within VIRTUAL_CS or VIRTUAL_DS
  16. *
  17. * In a 64-bit build, we set the bases of VIRTUAL_CS and VIRTUAL_DS
  18. * such that truncating a .textdata symbol value to 32 bits gives a
  19. * valid 32-bit virtual address.
  20. *
  21. * The C code is compiled with -mcmodel=kernel and so we must place
  22. * all .textdata symbols within the negative 2GB of the 64-bit address
  23. * space. Consequently, all .textdata symbols will have the MSB set
  24. * after truncation to 32 bits. This means that a straightforward
  25. * R_X86_64_32 relocation record for the symbol will fail, since the
  26. * truncated symbol value will not correctly zero-extend to the
  27. * original 64-bit value.
  28. *
  29. * Using an R_X86_64_32S relocation record would work, but there is no
  30. * (sensible) way to generate these relocation records within 32-bit
  31. * or 16-bit code.
  32. *
  33. * The simplest solution is to generate an R_X86_64_32 relocation
  34. * record with an addend of (-0xffffffff00000000). Since all
  35. * .textdata symbols are within the negative 2GB of the 64-bit address
  36. * space, this addend acts to effectively truncate the symbol to 32
  37. * bits, thereby matching the semantics of the R_X86_64_32 relocation
  38. * records generated for 32-bit and 16-bit code.
  39. *
  40. * In a 32-bit build, this problem does not exist, and we can just use
  41. * the .textdata symbol values directly.
  42. */
  43. #ifdef __x86_64__
  44. #define VIRTUAL(address) ( (address) - 0xffffffff00000000 )
  45. #else
  46. #define VIRTUAL(address) (address)
  47. #endif
  48. #ifdef ASSEMBLY
  49. /**
  50. * Call C function from real-mode code
  51. *
  52. * @v function C function
  53. */
  54. .macro virtcall function
  55. pushl $VIRTUAL(\function)
  56. call virt_call
  57. .endm
  58. #else /* ASSEMBLY */
  59. #ifdef UACCESS_LIBRM
  60. #define UACCESS_PREFIX_librm
  61. #else
  62. #define UACCESS_PREFIX_librm __librm_
  63. #endif
  64. /**
  65. * Call C function from real-mode code
  66. *
  67. * @v function C function
  68. */
  69. #define VIRT_CALL( function ) \
  70. "pushl $( " _S2 ( VIRTUAL ( function ) ) " )\n\t" \
  71. "call virt_call\n\t"
  72. /* Variables in librm.S */
  73. extern const unsigned long virt_offset;
  74. /**
  75. * Convert physical address to user pointer
  76. *
  77. * @v phys_addr Physical address
  78. * @ret userptr User pointer
  79. */
  80. static inline __always_inline userptr_t
  81. UACCESS_INLINE ( librm, phys_to_user ) ( unsigned long phys_addr ) {
  82. /* In a 64-bit build, any valid physical address is directly
  83. * usable as a virtual address, since the low 4GB is
  84. * identity-mapped.
  85. */
  86. if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) )
  87. return phys_addr;
  88. /* In a 32-bit build, subtract virt_offset */
  89. return ( phys_addr - virt_offset );
  90. }
  91. /**
  92. * Convert user buffer to physical address
  93. *
  94. * @v userptr User pointer
  95. * @v offset Offset from user pointer
  96. * @ret phys_addr Physical address
  97. */
  98. static inline __always_inline unsigned long
  99. UACCESS_INLINE ( librm, user_to_phys ) ( userptr_t userptr, off_t offset ) {
  100. unsigned long addr = ( userptr + offset );
  101. /* In a 64-bit build, any virtual address in the low 4GB is
  102. * directly usable as a physical address, since the low 4GB is
  103. * identity-mapped.
  104. */
  105. if ( ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) &&
  106. ( addr <= 0xffffffffUL ) )
  107. return addr;
  108. /* In a 32-bit build or in a 64-bit build with a virtual
  109. * address above 4GB: add virt_offset
  110. */
  111. return ( addr + virt_offset );
  112. }
  113. static inline __always_inline userptr_t
  114. UACCESS_INLINE ( librm, virt_to_user ) ( volatile const void *addr ) {
  115. return trivial_virt_to_user ( addr );
  116. }
  117. static inline __always_inline void *
  118. UACCESS_INLINE ( librm, user_to_virt ) ( userptr_t userptr, off_t offset ) {
  119. return trivial_user_to_virt ( userptr, offset );
  120. }
  121. static inline __always_inline userptr_t
  122. UACCESS_INLINE ( librm, userptr_add ) ( userptr_t userptr, off_t offset ) {
  123. return trivial_userptr_add ( userptr, offset );
  124. }
  125. static inline __always_inline off_t
  126. UACCESS_INLINE ( librm, userptr_sub ) ( userptr_t userptr,
  127. userptr_t subtrahend ) {
  128. return trivial_userptr_sub ( userptr, subtrahend );
  129. }
  130. static inline __always_inline void
  131. UACCESS_INLINE ( librm, memcpy_user ) ( userptr_t dest, off_t dest_off,
  132. userptr_t src, off_t src_off,
  133. size_t len ) {
  134. trivial_memcpy_user ( dest, dest_off, src, src_off, len );
  135. }
  136. static inline __always_inline void
  137. UACCESS_INLINE ( librm, memmove_user ) ( userptr_t dest, off_t dest_off,
  138. userptr_t src, off_t src_off,
  139. size_t len ) {
  140. trivial_memmove_user ( dest, dest_off, src, src_off, len );
  141. }
  142. static inline __always_inline int
  143. UACCESS_INLINE ( librm, memcmp_user ) ( userptr_t first, off_t first_off,
  144. userptr_t second, off_t second_off,
  145. size_t len ) {
  146. return trivial_memcmp_user ( first, first_off, second, second_off, len);
  147. }
  148. static inline __always_inline void
  149. UACCESS_INLINE ( librm, memset_user ) ( userptr_t buffer, off_t offset,
  150. int c, size_t len ) {
  151. trivial_memset_user ( buffer, offset, c, len );
  152. }
  153. static inline __always_inline size_t
  154. UACCESS_INLINE ( librm, strlen_user ) ( userptr_t buffer, off_t offset ) {
  155. return trivial_strlen_user ( buffer, offset );
  156. }
  157. static inline __always_inline off_t
  158. UACCESS_INLINE ( librm, memchr_user ) ( userptr_t buffer, off_t offset,
  159. int c, size_t len ) {
  160. return trivial_memchr_user ( buffer, offset, c, len );
  161. }
  162. /******************************************************************************
  163. *
  164. * Access to variables in .data16 and .text16
  165. *
  166. */
  167. extern char * const data16;
  168. extern char * const text16;
  169. #define __data16( variable ) \
  170. __attribute__ (( section ( ".data16" ) )) \
  171. _data16_ ## variable __asm__ ( #variable )
  172. #define __data16_array( variable, array ) \
  173. __attribute__ (( section ( ".data16" ) )) \
  174. _data16_ ## variable array __asm__ ( #variable )
  175. #define __bss16( variable ) \
  176. __attribute__ (( section ( ".bss16" ) )) \
  177. _data16_ ## variable __asm__ ( #variable )
  178. #define __bss16_array( variable, array ) \
  179. __attribute__ (( section ( ".bss16" ) )) \
  180. _data16_ ## variable array __asm__ ( #variable )
  181. #define __text16( variable ) \
  182. __attribute__ (( section ( ".text16.data" ) )) \
  183. _text16_ ## variable __asm__ ( #variable )
  184. #define __text16_array( variable, array ) \
  185. __attribute__ (( section ( ".text16.data" ) )) \
  186. _text16_ ## variable array __asm__ ( #variable )
  187. #define __use_data16( variable ) \
  188. ( * ( ( typeof ( _data16_ ## variable ) * ) \
  189. & ( data16 [ ( size_t ) & ( _data16_ ## variable ) ] ) ) )
  190. #define __use_text16( variable ) \
  191. ( * ( ( typeof ( _text16_ ## variable ) * ) \
  192. & ( text16 [ ( size_t ) & ( _text16_ ## variable ) ] ) ) )
  193. #define __from_data16( pointer ) \
  194. ( ( unsigned int ) \
  195. ( ( ( void * ) (pointer) ) - ( ( void * ) data16 ) ) )
  196. #define __from_text16( pointer ) \
  197. ( ( unsigned int ) \
  198. ( ( ( void * ) (pointer) ) - ( ( void * ) text16 ) ) )
  199. /* Variables in librm.S, present in the normal data segment */
  200. extern uint16_t rm_sp;
  201. extern uint16_t rm_ss;
  202. extern const uint16_t __text16 ( rm_cs );
  203. #define rm_cs __use_text16 ( rm_cs )
  204. extern const uint16_t __text16 ( rm_ds );
  205. #define rm_ds __use_text16 ( rm_ds )
  206. extern uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size );
  207. extern void remove_user_from_rm_stack ( userptr_t data, size_t size );
  208. /* CODE_DEFAULT: restore default .code32/.code64 directive */
  209. #ifdef __x86_64__
  210. #define CODE_DEFAULT ".code64"
  211. #else
  212. #define CODE_DEFAULT ".code32"
  213. #endif
  214. /* TEXT16_CODE: declare a fragment of code that resides in .text16 */
  215. #define TEXT16_CODE( asm_code_str ) \
  216. ".section \".text16\", \"ax\", @progbits\n\t" \
  217. ".code16\n\t" \
  218. asm_code_str "\n\t" \
  219. CODE_DEFAULT "\n\t" \
  220. ".previous\n\t"
  221. /* REAL_CODE: declare a fragment of code that executes in real mode */
  222. #define REAL_CODE( asm_code_str ) \
  223. "push $1f\n\t" \
  224. "call real_call\n\t" \
  225. TEXT16_CODE ( "\n1:\n\t" \
  226. asm_code_str \
  227. "\n\t" \
  228. "ret\n\t" )
  229. /* PHYS_CODE: declare a fragment of code that executes in flat physical mode */
  230. #define PHYS_CODE( asm_code_str ) \
  231. "push $1f\n\t" \
  232. "call phys_call\n\t" \
  233. ".section \".text.phys\", \"ax\", @progbits\n\t"\
  234. ".code32\n\t" \
  235. "\n1:\n\t" \
  236. asm_code_str \
  237. "\n\t" \
  238. "ret\n\t" \
  239. CODE_DEFAULT "\n\t" \
  240. ".previous\n\t"
  241. /** Number of interrupts */
  242. #define NUM_INT 256
  243. /** An interrupt descriptor table register */
  244. struct idtr {
  245. /** Limit */
  246. uint16_t limit;
  247. /** Base */
  248. uint32_t base;
  249. } __attribute__ (( packed ));
  250. /** An interrupt descriptor table entry */
  251. struct interrupt_descriptor {
  252. /** Low 16 bits of address */
  253. uint16_t low;
  254. /** Code segment */
  255. uint16_t segment;
  256. /** Unused */
  257. uint8_t unused;
  258. /** Type and attributes */
  259. uint8_t attr;
  260. /** High 16 bits of address */
  261. uint16_t high;
  262. } __attribute__ (( packed ));
  263. /** Interrupt descriptor is present */
  264. #define IDTE_PRESENT 0x80
  265. /** Interrupt descriptor 32-bit interrupt gate type */
  266. #define IDTE_TYPE_IRQ32 0x0e
  267. /** An interrupt vector
  268. *
  269. * Each interrupt vector comprises an eight-byte fragment of code:
  270. *
  271. * 60 pushal
  272. * b0 xx movb $INT, %al
  273. * e9 xx xx xx xx jmp interrupt_wrapper
  274. */
  275. struct interrupt_vector {
  276. /** "pushal" instruction */
  277. uint8_t pushal;
  278. /** "movb" instruction */
  279. uint8_t movb;
  280. /** Interrupt number */
  281. uint8_t intr;
  282. /** "jmp" instruction */
  283. uint8_t jmp;
  284. /** Interrupt wrapper address offset */
  285. uint32_t offset;
  286. /** Next instruction after jump */
  287. uint8_t next[0];
  288. } __attribute__ (( packed ));
  289. /** "pushal" instruction */
  290. #define PUSHAL_INSN 0x60
  291. /** "movb" instruction */
  292. #define MOVB_INSN 0xb0
  293. /** "jmp" instruction */
  294. #define JMP_INSN 0xe9
  295. extern void set_interrupt_vector ( unsigned int intr, void *vector );
  296. #endif /* ASSEMBLY */
  297. #endif /* LIBRM_H */