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