Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / arch / i386 / interface / syslinux / com32_call.c
1 /*
2  * Copyright (C) 2008 Daniel Verkamp <daniel@drv.nu>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  */
19
20 /**
21  * @file SYSLINUX COM32 helpers
22  *
23  */
24
25 FILE_LICENCE ( GPL2_OR_LATER );
26
27 #include <stdint.h>
28 #include <realmode.h>
29 #include <comboot.h>
30 #include <assert.h>
31 #include <ipxe/uaccess.h>
32
33 static com32sys_t __bss16 ( com32_regs );
34 #define com32_regs __use_data16 ( com32_regs )
35
36 static uint8_t __bss16 ( com32_int_vector );
37 #define com32_int_vector __use_data16 ( com32_int_vector )
38
39 static uint32_t __bss16 ( com32_farcall_proc );
40 #define com32_farcall_proc __use_data16 ( com32_farcall_proc )
41
42 uint16_t __bss16 ( com32_saved_sp );
43
44 /**
45  * Interrupt call helper
46  */
47 void __asmcall com32_intcall ( uint8_t interrupt, physaddr_t inregs_phys, physaddr_t outregs_phys ) {
48
49         memcpy_user ( virt_to_user( &com32_regs ), 0,
50                       phys_to_user ( inregs_phys ), 0,
51                       sizeof(com32sys_t) );
52
53         com32_int_vector = interrupt;
54
55         __asm__ __volatile__ (
56                 REAL_CODE ( /* Save all registers */
57                             "pushal\n\t"
58                             "pushw %%ds\n\t"
59                             "pushw %%es\n\t"
60                             "pushw %%fs\n\t"
61                             "pushw %%gs\n\t"
62                             /* Mask off unsafe flags */
63                             "movl (com32_regs + 40), %%eax\n\t"
64                             "andl $0x200cd7, %%eax\n\t"
65                             "movl %%eax, (com32_regs + 40)\n\t"
66                             /* Load com32_regs into the actual registers */
67                             "movw %%sp, %%ss:(com32_saved_sp)\n\t"
68                             "movw $com32_regs, %%sp\n\t"
69                             "popw %%gs\n\t"
70                             "popw %%fs\n\t"
71                             "popw %%es\n\t"
72                             "popw %%ds\n\t"
73                             "popal\n\t"
74                             "popfl\n\t"
75                             "movw %%ss:(com32_saved_sp), %%sp\n\t"
76                             /* patch INT instruction */
77                             "pushw %%ax\n\t"
78                             "movb %%ss:(com32_int_vector), %%al\n\t"
79                             "movb %%al, %%cs:(com32_intcall_instr + 1)\n\t" 
80                             /* perform a jump to avoid problems with cache
81                              * consistency in self-modifying code on some CPUs (486)
82                              */
83                             "jmp 1f\n"
84                             "1:\n\t"
85                             "popw %%ax\n\t"
86                             "com32_intcall_instr:\n\t"
87                             /* INT instruction to be patched */
88                             "int $0xFF\n\t"
89                             /* Copy regs back to com32_regs */
90                             "movw %%sp, %%ss:(com32_saved_sp)\n\t"
91                             "movw $(com32_regs + 44), %%sp\n\t"
92                             "pushfl\n\t"
93                             "pushal\n\t"
94                             "pushw %%ds\n\t"
95                             "pushw %%es\n\t"
96                             "pushw %%fs\n\t"
97                             "pushw %%gs\n\t"
98                             "movw %%ss:(com32_saved_sp), %%sp\n\t"
99                             /* Restore registers */
100                             "popw %%gs\n\t"
101                             "popw %%fs\n\t"
102                             "popw %%es\n\t"
103                             "popw %%ds\n\t"
104                             "popal\n\t")
105                             : : );
106
107         if ( outregs_phys ) {
108                 memcpy_user ( phys_to_user ( outregs_phys ), 0,
109                               virt_to_user( &com32_regs ), 0, 
110                               sizeof(com32sys_t) );
111         }
112 }
113
114 /**
115  * Farcall helper
116  */
117 void __asmcall com32_farcall ( uint32_t proc, physaddr_t inregs_phys, physaddr_t outregs_phys ) {
118
119         memcpy_user ( virt_to_user( &com32_regs ), 0,
120                       phys_to_user ( inregs_phys ), 0,
121                       sizeof(com32sys_t) );
122
123         com32_farcall_proc = proc;
124
125         __asm__ __volatile__ (
126                 REAL_CODE ( /* Save all registers */
127                             "pushal\n\t"
128                             "pushw %%ds\n\t"
129                             "pushw %%es\n\t"
130                             "pushw %%fs\n\t"
131                             "pushw %%gs\n\t"
132                             /* Mask off unsafe flags */
133                             "movl (com32_regs + 40), %%eax\n\t"
134                             "andl $0x200cd7, %%eax\n\t"
135                             "movl %%eax, (com32_regs + 40)\n\t"
136                             /* Load com32_regs into the actual registers */
137                             "movw %%sp, %%ss:(com32_saved_sp)\n\t"
138                             "movw $com32_regs, %%sp\n\t"
139                             "popw %%gs\n\t"
140                             "popw %%fs\n\t"
141                             "popw %%es\n\t"
142                             "popw %%ds\n\t"
143                             "popal\n\t"
144                             "popfl\n\t"
145                             "movw %%ss:(com32_saved_sp), %%sp\n\t"
146                             /* Call procedure */
147                             "lcall *%%ss:(com32_farcall_proc)\n\t"
148                             /* Copy regs back to com32_regs */
149                             "movw %%sp, %%ss:(com32_saved_sp)\n\t"
150                             "movw $(com32_regs + 44), %%sp\n\t"
151                             "pushfl\n\t"
152                             "pushal\n\t"
153                             "pushw %%ds\n\t"
154                             "pushw %%es\n\t"
155                             "pushw %%fs\n\t"
156                             "pushw %%gs\n\t"
157                             "movw %%ss:(com32_saved_sp), %%sp\n\t"
158                             /* Restore registers */
159                             "popw %%gs\n\t"
160                             "popw %%fs\n\t"
161                             "popw %%es\n\t"
162                             "popw %%ds\n\t"
163                             "popal\n\t")
164                             : : );
165
166         if ( outregs_phys ) {
167                 memcpy_user ( phys_to_user ( outregs_phys ), 0,
168                               virt_to_user( &com32_regs ), 0, 
169                               sizeof(com32sys_t) );
170         }
171 }
172
173 /**
174  * CDECL farcall helper
175  */
176 int __asmcall com32_cfarcall ( uint32_t proc, physaddr_t stack, size_t stacksz ) {
177         int32_t eax;
178
179         copy_user_to_rm_stack ( phys_to_user ( stack ), stacksz );
180         com32_farcall_proc = proc;
181
182         __asm__ __volatile__ (
183                 REAL_CODE ( "lcall *%%ss:(com32_farcall_proc)\n\t" )
184                 : "=a" (eax)
185                 : 
186                 : "ecx", "edx" );
187
188         remove_user_from_rm_stack ( 0, stacksz );
189
190         return eax;
191 }