[comboot] Add COMBOOT and COM32 support
[people/mcb30/gpxe.git] / 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., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 /**
20  * @file SYSLINUX COM32 helpers
21  *
22  */
23
24 #include <stdint.h>
25 #include <realmode.h>
26 #include <comboot.h>
27 #include <assert.h>
28 #include <gpxe/uaccess.h>
29
30 static com32sys_t __bss16 ( com32_regs );
31 #define com32_regs __use_data16 ( com32_regs )
32
33 static uint8_t __bss16 ( com32_int_vector );
34 #define com32_int_vector __use_data16 ( com32_int_vector )
35
36 static uint32_t __bss16 ( com32_farcall_proc );
37 #define com32_farcall_proc __use_data16 ( com32_farcall_proc )
38
39 uint16_t __bss16 ( com32_saved_sp );
40
41 /**
42  * Interrupt call helper
43  */
44 void __cdecl com32_intcall ( uint8_t interrupt, physaddr_t inregs_phys, physaddr_t outregs_phys ) {
45
46         memcpy_user ( virt_to_user( &com32_regs ), 0,
47                       phys_to_user ( inregs_phys ), 0,
48                       sizeof(com32sys_t) );
49
50         com32_int_vector = interrupt;
51
52         __asm__ __volatile__ (
53                 REAL_CODE ( /* Save all registers */
54                             "pushal\n\t"
55                             "pushw %%ds\n\t"
56                             "pushw %%es\n\t"
57                             "pushw %%fs\n\t"
58                             "pushw %%gs\n\t"
59                             /* Mask off unsafe flags */
60                             "movl (com32_regs + 40), %%eax\n\t"
61                             "andl $0x200cd7, %%eax\n\t"
62                             "movl %%eax, (com32_regs + 40)\n\t"
63                             /* Load com32_regs into the actual registers */
64                             "movw %%sp, %%ss:(com32_saved_sp)\n\t"
65                             "movw $com32_regs, %%sp\n\t"
66                             "popw %%gs\n\t"
67                             "popw %%fs\n\t"
68                             "popw %%es\n\t"
69                             "popw %%ds\n\t"
70                             "popal\n\t"
71                             "popfl\n\t"
72                             "movw %%ss:(com32_saved_sp), %%sp\n\t"
73                             /* patch INT instruction */
74                             "pushw %%ax\n\t"
75                             "movb %%ss:(com32_int_vector), %%al\n\t"
76                             "movb %%al, %%cs:(com32_intcall_instr + 1)\n\t" 
77                             /* perform a jump to avoid problems with cache
78                              * consistency in self-modifying code on some CPUs (486)
79                              */
80                             "jmp 1f\n"
81                             "1:\n\t"
82                             "popw %%ax\n\t"
83                             "com32_intcall_instr:\n\t"
84                             /* INT instruction to be patched */
85                             "int $0xFF\n\t"
86                             /* Copy regs back to com32_regs */
87                             "movw %%sp, %%ss:(com32_saved_sp)\n\t"
88                             "movw $(com32_regs + 44), %%sp\n\t"
89                             "pushfl\n\t"
90                             "pushal\n\t"
91                             "pushw %%ds\n\t"
92                             "pushw %%es\n\t"
93                             "pushw %%fs\n\t"
94                             "pushw %%gs\n\t"
95                             "movw %%ss:(com32_saved_sp), %%sp\n\t"
96                             /* Restore registers */
97                             "popw %%gs\n\t"
98                             "popw %%fs\n\t"
99                             "popw %%es\n\t"
100                             "popw %%ds\n\t"
101                             "popal\n\t")
102                             : : );
103
104         if ( outregs_phys ) {
105                 memcpy_user ( phys_to_user ( outregs_phys ), 0,
106                               virt_to_user( &com32_regs ), 0, 
107                               sizeof(com32sys_t) );
108         }
109 }
110
111 /**
112  * Farcall helper
113  */
114 void __cdecl com32_farcall ( uint32_t proc, physaddr_t inregs_phys, physaddr_t outregs_phys ) {
115
116         memcpy_user ( virt_to_user( &com32_regs ), 0,
117                       phys_to_user ( inregs_phys ), 0,
118                       sizeof(com32sys_t) );
119
120         com32_farcall_proc = proc;
121
122         __asm__ __volatile__ (
123                 REAL_CODE ( /* Save all registers */
124                             "pushal\n\t"
125                             "pushw %%ds\n\t"
126                             "pushw %%es\n\t"
127                             "pushw %%fs\n\t"
128                             "pushw %%gs\n\t"
129                             /* Mask off unsafe flags */
130                             "movl (com32_regs + 40), %%eax\n\t"
131                             "andl $0x200cd7, %%eax\n\t"
132                             "movl %%eax, (com32_regs + 40)\n\t"
133                             /* Load com32_regs into the actual registers */
134                             "movw %%sp, %%ss:(com32_saved_sp)\n\t"
135                             "movw $com32_regs, %%sp\n\t"
136                             "popw %%gs\n\t"
137                             "popw %%fs\n\t"
138                             "popw %%es\n\t"
139                             "popw %%ds\n\t"
140                             "popal\n\t"
141                             "popfl\n\t"
142                             "movw %%ss:(com32_saved_sp), %%sp\n\t"
143                             /* Call procedure */
144                             "lcall *%%ss:(com32_farcall_proc)\n\t"
145                             /* Copy regs back to com32_regs */
146                             "movw %%sp, %%ss:(com32_saved_sp)\n\t"
147                             "movw $(com32_regs + 44), %%sp\n\t"
148                             "pushfl\n\t"
149                             "pushal\n\t"
150                             "pushw %%ds\n\t"
151                             "pushw %%es\n\t"
152                             "pushw %%fs\n\t"
153                             "pushw %%gs\n\t"
154                             "movw %%ss:(com32_saved_sp), %%sp\n\t"
155                             /* Restore registers */
156                             "popw %%gs\n\t"
157                             "popw %%fs\n\t"
158                             "popw %%es\n\t"
159                             "popw %%ds\n\t"
160                             "popal\n\t")
161                             : : );
162
163         if ( outregs_phys ) {
164                 memcpy_user ( phys_to_user ( outregs_phys ), 0,
165                               virt_to_user( &com32_regs ), 0, 
166                               sizeof(com32sys_t) );
167         }
168 }
169
170 /**
171  * CDECL farcall helper
172  */
173 int __cdecl com32_cfarcall ( uint32_t proc, physaddr_t stack, size_t stacksz ) {
174         int32_t eax;
175
176         copy_user_to_rm_stack ( phys_to_user ( stack ), stacksz );
177         com32_farcall_proc = proc;
178
179         __asm__ __volatile__ (
180                 REAL_CODE ( "lcall *%%ss:(com32_farcall_proc)\n\t" )
181                 : "=a" (eax)
182                 : 
183                 : "ecx", "edx" );
184
185         remove_user_from_rm_stack ( 0, stacksz );
186
187         return eax;
188 }