2 * librm: a library for interfacing to real-mode code
4 * Michael Brown <mbrown@fensystems.co.uk>
8 FILE_LICENCE ( GPL2_OR_LATER );
11 #include <ipxe/profile.h>
16 * This file provides functions for managing librm.
20 /** The interrupt wrapper */
21 extern char interrupt_wrapper[];
23 /** The interrupt vectors */
24 static struct interrupt_vector intr_vec[NUM_INT];
26 /** The interrupt descriptor table */
27 struct interrupt_descriptor idt[NUM_INT] __attribute__ (( aligned ( 16 ) ));
29 /** The interrupt descriptor table register */
31 .limit = ( sizeof ( idt ) - 1 ),
34 /** Timer interrupt profiler */
35 static struct profiler timer_irq_profiler __profiler = { .name = "irq.timer" };
37 /** Other interrupt profiler */
38 static struct profiler other_irq_profiler __profiler = { .name = "irq.other" };
41 * Allocate space on the real-mode stack and copy data there from a
45 * @v size Size of stack data
46 * @ret sp New value of real-mode stack pointer
48 uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) {
51 rm_stack = real_to_user ( rm_ss, rm_sp );
52 memcpy_user ( rm_stack, 0, data, 0, size );
57 * Deallocate space on the real-mode stack, optionally copying back
58 * data to a user buffer.
61 * @v size Size of stack data
63 void remove_user_from_rm_stack ( userptr_t data, size_t size ) {
65 userptr_t rm_stack = real_to_user ( rm_ss, rm_sp );
66 memcpy_user ( rm_stack, 0, data, 0, size );
72 * Set interrupt vector
74 * @v intr Interrupt number
75 * @v vector Interrupt vector, or NULL to disable
77 void set_interrupt_vector ( unsigned int intr, void *vector ) {
78 struct interrupt_descriptor *idte;
81 idte->segment = VIRTUAL_CS;
82 idte->attr = ( vector ? ( IDTE_PRESENT | IDTE_TYPE_IRQ32 ) : 0 );
83 idte->low = ( ( ( uint32_t ) vector ) & 0xffff );
84 idte->high = ( ( ( uint32_t ) vector ) >> 16 );
88 * Initialise interrupt descriptor table
91 void init_idt ( void ) {
92 struct interrupt_vector *vec;
95 /* Initialise the interrupt descriptor table and interrupt vectors */
96 for ( intr = 0 ; intr < NUM_INT ; intr++ ) {
97 vec = &intr_vec[intr];
98 vec->pushal = PUSHAL_INSN;
99 vec->movb = MOVB_INSN;
102 vec->offset = ( ( uint32_t ) interrupt_wrapper -
103 ( uint32_t ) vec->next );
104 set_interrupt_vector ( intr, vec );
106 DBGC ( &intr_vec[0], "INTn vector at %p+%xn (phys %#lx+%xn)\n",
107 intr_vec, sizeof ( intr_vec[0] ),
108 virt_to_phys ( intr_vec ), sizeof ( intr_vec[0] ) );
110 /* Initialise the interrupt descriptor table register */
111 idtr.base = virt_to_phys ( idt );
115 * Determine interrupt profiler (for debugging)
117 * @v intr Interrupt number
118 * @ret profiler Profiler
120 static struct profiler * interrupt_profiler ( int intr ) {
124 return &timer_irq_profiler;
126 return &other_irq_profiler;
133 * @v intr Interrupt number
135 void __attribute__ (( cdecl, regparm ( 1 ) )) interrupt ( int intr ) {
136 struct profiler *profiler = interrupt_profiler ( intr );
137 uint32_t discard_eax;
139 /* Reissue interrupt in real mode */
140 profile_start ( profiler );
141 __asm__ __volatile__ ( REAL_CODE ( "movb %%al, %%cs:(1f + 1)\n\t"
144 : "=a" ( discard_eax ) : "0" ( intr ) );
145 profile_stop ( profiler );
146 profile_exclude ( profiler );
149 PROVIDE_UACCESS_INLINE ( librm, phys_to_user );
150 PROVIDE_UACCESS_INLINE ( librm, user_to_phys );
151 PROVIDE_UACCESS_INLINE ( librm, virt_to_user );
152 PROVIDE_UACCESS_INLINE ( librm, user_to_virt );
153 PROVIDE_UACCESS_INLINE ( librm, userptr_add );
154 PROVIDE_UACCESS_INLINE ( librm, memcpy_user );
155 PROVIDE_UACCESS_INLINE ( librm, memmove_user );
156 PROVIDE_UACCESS_INLINE ( librm, memset_user );
157 PROVIDE_UACCESS_INLINE ( librm, strlen_user );
158 PROVIDE_UACCESS_INLINE ( librm, memchr_user );