1 | /* |
---|
2 | * libkir: a transition library for -DKEEP_IT_REAL |
---|
3 | * |
---|
4 | * Michael Brown <mbrown@fensystems.co.uk> |
---|
5 | * |
---|
6 | */ |
---|
7 | |
---|
8 | FILE_LICENCE ( GPL2_OR_LATER ) |
---|
9 | |
---|
10 | /**************************************************************************** |
---|
11 | * This file defines libkir: an interface between external and |
---|
12 | * internal environments when -DKEEP_IT_REAL is used, so that both |
---|
13 | * internal and external environments are in real mode. It deals with |
---|
14 | * switching data segments and the stack. It provides the following |
---|
15 | * functions: |
---|
16 | * |
---|
17 | * ext_to_kir & switch between external and internal (kir) |
---|
18 | * kir_to_ext environments, preserving all non-segment |
---|
19 | * registers |
---|
20 | * |
---|
21 | * kir_call issue a call to an internal routine from external |
---|
22 | * code |
---|
23 | * |
---|
24 | * libkir is written to avoid assuming that segments are anything |
---|
25 | * other than opaque data types, and also avoids assuming that the |
---|
26 | * stack pointer is 16-bit. This should enable it to run just as well |
---|
27 | * in 16:16 or 16:32 protected mode as in real mode. |
---|
28 | **************************************************************************** |
---|
29 | */ |
---|
30 | |
---|
31 | /* Breakpoint for when debugging under bochs */ |
---|
32 | #define BOCHSBP xchgw %bx, %bx |
---|
33 | |
---|
34 | .text |
---|
35 | .arch i386 |
---|
36 | .section ".text16", "awx", @progbits |
---|
37 | .code16 |
---|
38 | |
---|
39 | /**************************************************************************** |
---|
40 | * init_libkir (real-mode or 16:xx protected-mode far call) |
---|
41 | * |
---|
42 | * Initialise libkir ready for transitions to the kir environment |
---|
43 | * |
---|
44 | * Parameters: |
---|
45 | * %cs : .text16 segment |
---|
46 | * %ds : .data16 segment |
---|
47 | **************************************************************************** |
---|
48 | */ |
---|
49 | .globl init_libkir |
---|
50 | init_libkir: |
---|
51 | /* Record segment registers */ |
---|
52 | pushw %ds |
---|
53 | popw %cs:kir_ds |
---|
54 | lret |
---|
55 | |
---|
56 | /**************************************************************************** |
---|
57 | * ext_to_kir (real-mode or 16:xx protected-mode near call) |
---|
58 | * |
---|
59 | * Switch from external stack and segment registers to internal stack |
---|
60 | * and segment registers. %ss:sp is restored from the saved kir_ds |
---|
61 | * and kir_sp. %ds, %es, %fs and %gs are all restored from the saved |
---|
62 | * kir_ds. All other registers are preserved. |
---|
63 | * |
---|
64 | * %cs:0000 must point to the start of the runtime image code segment |
---|
65 | * on entry. |
---|
66 | * |
---|
67 | * Parameters: none |
---|
68 | **************************************************************************** |
---|
69 | */ |
---|
70 | |
---|
71 | .globl ext_to_kir |
---|
72 | ext_to_kir: |
---|
73 | /* Record external segment registers */ |
---|
74 | movw %ds, %cs:ext_ds |
---|
75 | pushw %cs |
---|
76 | popw %ds /* Set %ds = %cs for easier access to variables */ |
---|
77 | movw %es, %ds:ext_es |
---|
78 | movw %fs, %ds:ext_fs |
---|
79 | movw %gs, %ds:ext_fs |
---|
80 | |
---|
81 | /* Preserve registers */ |
---|
82 | movw %ax, %ds:save_ax |
---|
83 | |
---|
84 | /* Extract near return address from stack */ |
---|
85 | popw %ds:save_retaddr |
---|
86 | |
---|
87 | /* Record external %ss:esp */ |
---|
88 | movw %ss, %ds:ext_ss |
---|
89 | movl %esp, %ds:ext_esp |
---|
90 | |
---|
91 | /* Load internal segment registers and stack pointer */ |
---|
92 | movw %ds:kir_ds, %ax |
---|
93 | movw %ax, %ss |
---|
94 | movzwl %ds:kir_sp, %esp |
---|
95 | movw %ax, %ds |
---|
96 | movw %ax, %es |
---|
97 | movw %ax, %fs |
---|
98 | movw %ax, %gs |
---|
99 | 1: |
---|
100 | |
---|
101 | /* Place return address on new stack */ |
---|
102 | pushw %cs:save_retaddr |
---|
103 | |
---|
104 | /* Restore registers and return */ |
---|
105 | movw %cs:save_ax, %ax |
---|
106 | ret |
---|
107 | |
---|
108 | /**************************************************************************** |
---|
109 | * kir_to_ext (real-mode or 16:xx protected-mode near call) |
---|
110 | * |
---|
111 | * Switch from internal stack and segment registers to external stack |
---|
112 | * and segment registers. %ss:%esp is restored from the saved ext_ss |
---|
113 | * and ext_esp. Other segment registers are restored from the |
---|
114 | * corresponding locations. All other registers are preserved. |
---|
115 | * |
---|
116 | * Note that it is actually %ss that is recorded as kir_ds, on the |
---|
117 | * assumption that %ss == %ds when kir_to_ext is called. |
---|
118 | * |
---|
119 | * Parameters: none |
---|
120 | **************************************************************************** |
---|
121 | */ |
---|
122 | |
---|
123 | .globl kir_to_ext |
---|
124 | kir_to_ext: |
---|
125 | /* Record near return address */ |
---|
126 | pushw %cs |
---|
127 | popw %ds /* Set %ds = %cs for easier access to variables */ |
---|
128 | popw %ds:save_retaddr |
---|
129 | |
---|
130 | /* Record internal segment registers and %sp */ |
---|
131 | movw %ss, %ds:kir_ds |
---|
132 | movw %sp, %ds:kir_sp |
---|
133 | |
---|
134 | /* Load external segment registers and stack pointer */ |
---|
135 | movw %ds:ext_ss, %ss |
---|
136 | movl %ds:ext_esp, %esp |
---|
137 | movw %ds:ext_gs, %gs |
---|
138 | movw %ds:ext_fs, %fs |
---|
139 | movw %ds:ext_es, %es |
---|
140 | movw %ds:ext_ds, %ds |
---|
141 | |
---|
142 | /* Return */ |
---|
143 | pushw %cs:save_retaddr |
---|
144 | ret |
---|
145 | |
---|
146 | /**************************************************************************** |
---|
147 | * kir_call (real-mode or 16:xx protected-mode far call) |
---|
148 | * |
---|
149 | * Call a specific C function in the internal code. The prototype of |
---|
150 | * the C function must be |
---|
151 | * void function ( struct i386_all_resg *ix86 ); |
---|
152 | * ix86 will point to a struct containing the real-mode registers |
---|
153 | * at entry to kir_call. |
---|
154 | * |
---|
155 | * All registers will be preserved across kir_call(), unless the C |
---|
156 | * function explicitly overwrites values in ix86. Interrupt status |
---|
157 | * will also be preserved. |
---|
158 | * |
---|
159 | * Parameters: |
---|
160 | * function : (32-bit) virtual address of C function to call |
---|
161 | * |
---|
162 | * Example usage: |
---|
163 | * pushl $pxe_api_call |
---|
164 | * lcall $UNDI_CS, $kir_call |
---|
165 | * addw $4, %sp |
---|
166 | * to call in to the C function |
---|
167 | * void pxe_api_call ( struct i386_all_regs *ix86 ); |
---|
168 | **************************************************************************** |
---|
169 | */ |
---|
170 | |
---|
171 | .globl kir_call |
---|
172 | kir_call: |
---|
173 | /* Preserve flags. Must do this before any operation that may |
---|
174 | * affect flags. |
---|
175 | */ |
---|
176 | pushfl |
---|
177 | popl %cs:save_flags |
---|
178 | |
---|
179 | /* Disable interrupts. We do funny things with the stack, and |
---|
180 | * we're not re-entrant. |
---|
181 | */ |
---|
182 | cli |
---|
183 | |
---|
184 | /* Extract address of internal routine from stack. We must do |
---|
185 | * this without using (%bp), because we may be called with |
---|
186 | * either a 16-bit or a 32-bit stack segment. |
---|
187 | */ |
---|
188 | popl %cs:save_retaddr /* Scratch location */ |
---|
189 | popl %cs:save_function |
---|
190 | subl $8, %esp /* Restore %esp */ |
---|
191 | |
---|
192 | /* Switch to internal stack. Note that the external stack is |
---|
193 | * inaccessible once we're running internally (since we have |
---|
194 | * no concept of 48-bit far pointers) |
---|
195 | */ |
---|
196 | call ext_to_kir |
---|
197 | |
---|
198 | /* Store external registers on internal stack */ |
---|
199 | pushl %cs:save_flags |
---|
200 | pushal |
---|
201 | pushl %cs:ext_fs_and_gs |
---|
202 | pushl %cs:ext_ds_and_es |
---|
203 | pushl %cs:ext_cs_and_ss |
---|
204 | |
---|
205 | /* Push &ix86 on stack and call function */ |
---|
206 | sti |
---|
207 | pushl %esp |
---|
208 | data32 call *%cs:save_function |
---|
209 | popl %eax /* discard */ |
---|
210 | |
---|
211 | /* Restore external registers from internal stack */ |
---|
212 | popl %cs:ext_cs_and_ss |
---|
213 | popl %cs:ext_ds_and_es |
---|
214 | popl %cs:ext_fs_and_gs |
---|
215 | popal |
---|
216 | popl %cs:save_flags |
---|
217 | |
---|
218 | /* Switch to external stack */ |
---|
219 | call kir_to_ext |
---|
220 | |
---|
221 | /* Restore flags */ |
---|
222 | pushl %cs:save_flags |
---|
223 | popfl |
---|
224 | |
---|
225 | /* Return */ |
---|
226 | lret |
---|
227 | |
---|
228 | /**************************************************************************** |
---|
229 | * Stored internal and external stack and segment registers |
---|
230 | **************************************************************************** |
---|
231 | */ |
---|
232 | |
---|
233 | ext_cs_and_ss: |
---|
234 | ext_cs: .word 0 |
---|
235 | ext_ss: .word 0 |
---|
236 | ext_ds_and_es: |
---|
237 | ext_ds: .word 0 |
---|
238 | ext_es: .word 0 |
---|
239 | ext_fs_and_gs: |
---|
240 | ext_fs: .word 0 |
---|
241 | ext_gs: .word 0 |
---|
242 | ext_esp: .long 0 |
---|
243 | |
---|
244 | .globl kir_ds |
---|
245 | kir_ds: .word 0 |
---|
246 | .globl kir_sp |
---|
247 | kir_sp: .word _estack |
---|
248 | |
---|
249 | /**************************************************************************** |
---|
250 | * Temporary variables |
---|
251 | **************************************************************************** |
---|
252 | */ |
---|
253 | save_ax: .word 0 |
---|
254 | save_retaddr: .long 0 |
---|
255 | save_flags: .long 0 |
---|
256 | save_function: .long 0 |
---|