iPXE
com32_call.c
Go to the documentation of this file.
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 
37 #define com32_int_vector __use_data16 ( com32_int_vector )
38 
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  DBGC ( &com32_regs, "COM32 INT%x in %#08lx out %#08lx\n",
50  interrupt, inregs_phys, outregs_phys );
51 
52  memcpy ( &com32_regs, phys_to_virt ( inregs_phys ),
53  sizeof ( com32sys_t ) );
54 
56 
58  REAL_CODE ( /* Save all registers */
59  "pushal\n\t"
60  "pushw %%ds\n\t"
61  "pushw %%es\n\t"
62  "pushw %%fs\n\t"
63  "pushw %%gs\n\t"
64  /* Mask off unsafe flags */
65  "movl (com32_regs + 40), %%eax\n\t"
66  "andl $0x200cd7, %%eax\n\t"
67  "movl %%eax, (com32_regs + 40)\n\t"
68  /* Load com32_regs into the actual registers */
69  "movw %%sp, %%ss:(com32_saved_sp)\n\t"
70  "movw $com32_regs, %%sp\n\t"
71  "popw %%gs\n\t"
72  "popw %%fs\n\t"
73  "popw %%es\n\t"
74  "popw %%ds\n\t"
75  "popal\n\t"
76  "popfl\n\t"
77  "movw %%ss:(com32_saved_sp), %%sp\n\t"
78  /* patch INT instruction */
79  "pushw %%ax\n\t"
80  "movb %%ss:(com32_int_vector), %%al\n\t"
81  "movb %%al, %%cs:(com32_intcall_instr + 1)\n\t"
82  /* perform a jump to avoid problems with cache
83  * consistency in self-modifying code on some CPUs (486)
84  */
85  "jmp 1f\n"
86  "1:\n\t"
87  "popw %%ax\n\t"
88  "com32_intcall_instr:\n\t"
89  /* INT instruction to be patched */
90  "int $0xFF\n\t"
91  /* Copy regs back to com32_regs */
92  "movw %%sp, %%ss:(com32_saved_sp)\n\t"
93  "movw $(com32_regs + 44), %%sp\n\t"
94  "pushfl\n\t"
95  "pushal\n\t"
96  "pushw %%ds\n\t"
97  "pushw %%es\n\t"
98  "pushw %%fs\n\t"
99  "pushw %%gs\n\t"
100  "movw %%ss:(com32_saved_sp), %%sp\n\t"
101  /* Restore registers */
102  "popw %%gs\n\t"
103  "popw %%fs\n\t"
104  "popw %%es\n\t"
105  "popw %%ds\n\t"
106  "popal\n\t")
107  : : );
108 
109  if ( outregs_phys ) {
110  memcpy ( phys_to_virt ( outregs_phys ),
111  &com32_regs, sizeof ( com32sys_t ) );
112  }
113 }
114 
115 /**
116  * Farcall helper
117  */
118 void __asmcall com32_farcall ( uint32_t proc, physaddr_t inregs_phys, physaddr_t outregs_phys ) {
119 
120  DBGC ( &com32_regs, "COM32 farcall %04x:%04x in %#08lx out %#08lx\n",
121  ( proc >> 16 ), ( proc & 0xffff ), inregs_phys, outregs_phys );
122 
123  memcpy ( &com32_regs, phys_to_virt ( inregs_phys ),
124  sizeof ( com32sys_t ) );
125 
126  com32_farcall_proc = proc;
127 
129  REAL_CODE ( /* Save all registers */
130  "pushal\n\t"
131  "pushw %%ds\n\t"
132  "pushw %%es\n\t"
133  "pushw %%fs\n\t"
134  "pushw %%gs\n\t"
135  /* Mask off unsafe flags */
136  "movl (com32_regs + 40), %%eax\n\t"
137  "andl $0x200cd7, %%eax\n\t"
138  "movl %%eax, (com32_regs + 40)\n\t"
139  /* Load com32_regs into the actual registers */
140  "movw %%sp, %%ss:(com32_saved_sp)\n\t"
141  "movw $com32_regs, %%sp\n\t"
142  "popw %%gs\n\t"
143  "popw %%fs\n\t"
144  "popw %%es\n\t"
145  "popw %%ds\n\t"
146  "popal\n\t"
147  "popfl\n\t"
148  "movw %%ss:(com32_saved_sp), %%sp\n\t"
149  /* Call procedure */
150  "lcall *%%ss:(com32_farcall_proc)\n\t"
151  /* Copy regs back to com32_regs */
152  "movw %%sp, %%ss:(com32_saved_sp)\n\t"
153  "movw $(com32_regs + 44), %%sp\n\t"
154  "pushfl\n\t"
155  "pushal\n\t"
156  "pushw %%ds\n\t"
157  "pushw %%es\n\t"
158  "pushw %%fs\n\t"
159  "pushw %%gs\n\t"
160  "movw %%ss:(com32_saved_sp), %%sp\n\t"
161  /* Restore registers */
162  "popw %%gs\n\t"
163  "popw %%fs\n\t"
164  "popw %%es\n\t"
165  "popw %%ds\n\t"
166  "popal\n\t")
167  : : );
168 
169  if ( outregs_phys ) {
170  memcpy ( phys_to_virt ( outregs_phys ),
171  &com32_regs, sizeof ( com32sys_t ) );
172  }
173 }
174 
175 /**
176  * CDECL farcall helper
177  */
178 int __asmcall com32_cfarcall ( uint32_t proc, physaddr_t stack, size_t stacksz ) {
179  int32_t eax;
180 
181  DBGC ( &com32_regs, "COM32 cfarcall %04x:%04x params %#08lx+%#zx\n",
182  ( proc >> 16 ), ( proc & 0xffff ), stack, stacksz );
183 
184  copy_to_rm_stack ( phys_to_virt ( stack ), stacksz );
185  com32_farcall_proc = proc;
186 
188  REAL_CODE ( "lcall *%%ss:(com32_farcall_proc)\n\t" )
189  : "=a" (eax)
190  :
191  : "ecx", "edx" );
192 
193  remove_from_rm_stack ( NULL, stacksz );
194 
195  return eax;
196 }
unsigned short uint16_t
Definition: stdint.h:11
void __asmcall com32_farcall(uint32_t proc, physaddr_t inregs_phys, physaddr_t outregs_phys)
Farcall helper.
Definition: com32_call.c:118
static com32sys_t __bss16(com32_regs)
#define com32_regs
Definition: com32_call.c:34
#define DBGC(...)
Definition: compiler.h:505
SYSLINUX COMBOOT.
int __asmcall com32_cfarcall(uint32_t proc, physaddr_t stack, size_t stacksz)
CDECL farcall helper.
Definition: com32_call.c:178
void * memcpy(void *dest, const void *src, size_t len) __nonnull
#define __asmcall
Declare a function with standard calling conventions.
Definition: compiler.h:15
Assertions.
void remove_from_rm_stack(void *data, size_t size)
Deallocate space on the real-mode stack, optionally copying back data.
Definition: librm_mgmt.c:82
Access to external ("user") memory.
uint16_t copy_to_rm_stack(const void *data, size_t size)
Allocate space on the real-mode stack and copy data there.
Definition: librm_mgmt.c:67
#define com32_farcall_proc
Definition: com32_call.c:40
__asm__ __volatile__("call *%9" :"=a"(result), "=c"(discard_ecx), "=d"(discard_edx) :"d"(0), "a"(code), "b"(0), "c"(in_phys), "D"(0), "S"(out_phys), "m"(hypercall))
uint32_t eax
Definition: string.h:234
unsigned char uint8_t
Definition: stdint.h:10
unsigned int uint32_t
Definition: stdint.h:12
FILE_LICENCE(GPL2_OR_LATER)
unsigned long physaddr_t
Definition: stdint.h:20
__asm__(".section \".rodata\", \"a\", " PROGBITS "\n\t" "\nprivate_key_data:\n\t" ".size private_key_data, ( . - private_key_data )\n\t" ".equ private_key_len, ( . - private_key_data )\n\t" ".previous\n\t")
signed int int32_t
Definition: stdint.h:17
#define REAL_CODE(asm_code_str)
Definition: libkir.h:226
#define com32_int_vector
Definition: com32_call.c:37
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
void interrupt(int intr, struct interrupt_frame32 *frame32, struct interrupt_frame64 *frame64)
Interrupt handler.
Definition: librm_mgmt.c:251
void __asmcall com32_intcall(uint8_t interrupt, physaddr_t inregs_phys, physaddr_t outregs_phys)
Interrupt call helper.
Definition: com32_call.c:47