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_mgmt.c 4.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /*
  2. * librm: a library for interfacing to real-mode code
  3. *
  4. * Michael Brown <mbrown@fensystems.co.uk>
  5. *
  6. */
  7. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  8. #include <stdint.h>
  9. #include <ipxe/profile.h>
  10. #include <realmode.h>
  11. #include <pic8259.h>
  12. /*
  13. * This file provides functions for managing librm.
  14. *
  15. */
  16. /** The interrupt wrapper */
  17. extern char interrupt_wrapper[];
  18. /** The interrupt vectors */
  19. static struct interrupt_vector intr_vec[NUM_INT];
  20. /** The interrupt descriptor table */
  21. struct interrupt_descriptor idt[NUM_INT] __attribute__ (( aligned ( 16 ) ));
  22. /** The interrupt descriptor table register */
  23. struct idtr idtr = {
  24. .limit = ( sizeof ( idt ) - 1 ),
  25. };
  26. /** Timer interrupt profiler */
  27. static struct profiler timer_irq_profiler __profiler = { .name = "irq.timer" };
  28. /** Other interrupt profiler */
  29. static struct profiler other_irq_profiler __profiler = { .name = "irq.other" };
  30. /**
  31. * Allocate space on the real-mode stack and copy data there from a
  32. * user buffer
  33. *
  34. * @v data User buffer
  35. * @v size Size of stack data
  36. * @ret sp New value of real-mode stack pointer
  37. */
  38. uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) {
  39. userptr_t rm_stack;
  40. rm_sp -= size;
  41. rm_stack = real_to_user ( rm_ss, rm_sp );
  42. memcpy_user ( rm_stack, 0, data, 0, size );
  43. return rm_sp;
  44. };
  45. /**
  46. * Deallocate space on the real-mode stack, optionally copying back
  47. * data to a user buffer.
  48. *
  49. * @v data User buffer
  50. * @v size Size of stack data
  51. */
  52. void remove_user_from_rm_stack ( userptr_t data, size_t size ) {
  53. if ( data ) {
  54. userptr_t rm_stack = real_to_user ( rm_ss, rm_sp );
  55. memcpy_user ( rm_stack, 0, data, 0, size );
  56. }
  57. rm_sp += size;
  58. };
  59. /**
  60. * Set interrupt vector
  61. *
  62. * @v intr Interrupt number
  63. * @v vector Interrupt vector, or NULL to disable
  64. */
  65. void set_interrupt_vector ( unsigned int intr, void *vector ) {
  66. struct interrupt_descriptor *idte;
  67. idte = &idt[intr];
  68. idte->segment = VIRTUAL_CS;
  69. idte->attr = ( vector ? ( IDTE_PRESENT | IDTE_TYPE_IRQ32 ) : 0 );
  70. idte->low = ( ( ( uint32_t ) vector ) & 0xffff );
  71. idte->high = ( ( ( uint32_t ) vector ) >> 16 );
  72. }
  73. /**
  74. * Initialise interrupt descriptor table
  75. *
  76. */
  77. void init_idt ( void ) {
  78. struct interrupt_vector *vec;
  79. unsigned int intr;
  80. /* Initialise the interrupt descriptor table and interrupt vectors */
  81. for ( intr = 0 ; intr < NUM_INT ; intr++ ) {
  82. vec = &intr_vec[intr];
  83. vec->pushal = PUSHAL_INSN;
  84. vec->movb = MOVB_INSN;
  85. vec->intr = intr;
  86. vec->jmp = JMP_INSN;
  87. vec->offset = ( ( uint32_t ) interrupt_wrapper -
  88. ( uint32_t ) vec->next );
  89. set_interrupt_vector ( intr, vec );
  90. }
  91. DBGC ( &intr_vec[0], "INTn vector at %p+%xn (phys %#lx+%xn)\n",
  92. intr_vec, sizeof ( intr_vec[0] ),
  93. virt_to_phys ( intr_vec ), sizeof ( intr_vec[0] ) );
  94. /* Initialise the interrupt descriptor table register */
  95. idtr.base = virt_to_phys ( idt );
  96. }
  97. /**
  98. * Determine interrupt profiler (for debugging)
  99. *
  100. * @v intr Interrupt number
  101. * @ret profiler Profiler
  102. */
  103. static struct profiler * interrupt_profiler ( int intr ) {
  104. switch ( intr ) {
  105. case IRQ_INT ( 0 ) :
  106. return &timer_irq_profiler;
  107. default:
  108. return &other_irq_profiler;
  109. }
  110. }
  111. /**
  112. * Interrupt handler
  113. *
  114. * @v intr Interrupt number
  115. */
  116. void __attribute__ (( cdecl, regparm ( 1 ) )) interrupt ( int intr ) {
  117. struct profiler *profiler = interrupt_profiler ( intr );
  118. uint32_t discard_eax;
  119. /* Reissue interrupt in real mode */
  120. profile_start ( profiler );
  121. __asm__ __volatile__ ( REAL_CODE ( "movb %%al, %%cs:(1f + 1)\n\t"
  122. "\n1:\n\t"
  123. "int $0x00\n\t" )
  124. : "=a" ( discard_eax ) : "0" ( intr ) );
  125. profile_stop ( profiler );
  126. profile_exclude ( profiler );
  127. }
  128. PROVIDE_UACCESS_INLINE ( librm, phys_to_user );
  129. PROVIDE_UACCESS_INLINE ( librm, user_to_phys );
  130. PROVIDE_UACCESS_INLINE ( librm, virt_to_user );
  131. PROVIDE_UACCESS_INLINE ( librm, user_to_virt );
  132. PROVIDE_UACCESS_INLINE ( librm, userptr_add );
  133. PROVIDE_UACCESS_INLINE ( librm, memcpy_user );
  134. PROVIDE_UACCESS_INLINE ( librm, memmove_user );
  135. PROVIDE_UACCESS_INLINE ( librm, memset_user );
  136. PROVIDE_UACCESS_INLINE ( librm, strlen_user );
  137. PROVIDE_UACCESS_INLINE ( librm, memchr_user );