2 * libkir: a transition library for -DKEEP_IT_REAL
4 * Michael Brown <mbrown@fensystems.co.uk>
8 /****************************************************************************
9 * This file defines libkir: an interface between external and
10 * internal environments when -DKEEP_IT_REAL is used, so that both
11 * internal and external environments are in real mode. It deals with
12 * switching data segments and the stack. It provides the following
15 * ext_to_kir & switch between external and internal (kir)
16 * kir_to_ext environments, preserving all non-segment
19 * kir_call issue a call to an internal routine from external
22 * libkir is written to avoid assuming that segments are anything
23 * other than opaque data types, and also avoids assuming that the
24 * stack pointer is 16-bit. This should enable it to run just as well
25 * in 16:16 or 16:32 protected mode as in real mode.
26 ****************************************************************************
29 /* Breakpoint for when debugging under bochs */
30 #define BOCHSBP xchgw %bx, %bx
34 .section ".text16", "awx", @progbits
37 /****************************************************************************
38 * init_libkir (real-mode or 16:xx protected-mode far call)
40 * Initialise libkir ready for transitions to the kir environment
43 * %cs : .text16 segment
44 * %ds : .data16 segment
45 ****************************************************************************
49 /* Record segment registers */
54 /****************************************************************************
55 * ext_to_kir (real-mode or 16:xx protected-mode near call)
57 * Switch from external stack and segment registers to internal stack
58 * and segment registers. %ss:sp is restored from the saved kir_ds
59 * and kir_sp. %ds, %es, %fs and %gs are all restored from the saved
60 * kir_ds. All other registers are preserved.
62 * %cs:0000 must point to the start of the runtime image code segment
66 ****************************************************************************
71 /* Record external segment registers */
74 popw %ds /* Set %ds = %cs for easier access to variables */
79 /* Preserve registers */
82 /* Extract near return address from stack */
85 /* Record external %ss:esp */
87 movl %esp, %ds:ext_esp
89 /* Load internal segment registers and stack pointer */
92 movzwl %ds:kir_sp, %esp
99 /* Place return address on new stack */
100 pushw %cs:save_retaddr
102 /* Restore registers and return */
103 movw %cs:save_ax, %ax
106 /****************************************************************************
107 * kir_to_ext (real-mode or 16:xx protected-mode near call)
109 * Switch from internal stack and segment registers to external stack
110 * and segment registers. %ss:%esp is restored from the saved ext_ss
111 * and ext_esp. Other segment registers are restored from the
112 * corresponding locations. All other registers are preserved.
114 * Note that it is actually %ss that is recorded as kir_ds, on the
115 * assumption that %ss == %ds when kir_to_ext is called.
118 ****************************************************************************
123 /* Record near return address */
125 popw %ds /* Set %ds = %cs for easier access to variables */
126 popw %ds:save_retaddr
128 /* Record internal segment registers and %sp */
132 /* Load external segment registers and stack pointer */
134 movl %ds:ext_esp, %esp
141 pushw %cs:save_retaddr
144 /****************************************************************************
145 * kir_call (real-mode or 16:xx protected-mode far call)
147 * Call a specific C function in the internal code. The prototype of
148 * the C function must be
149 * void function ( struct i386_all_resg *ix86 );
150 * ix86 will point to a struct containing the real-mode registers
151 * at entry to kir_call.
153 * All registers will be preserved across kir_call(), unless the C
154 * function explicitly overwrites values in ix86. Interrupt status
155 * will also be preserved.
158 * function : (32-bit) virtual address of C function to call
161 * pushl $pxe_api_call
162 * lcall $UNDI_CS, $kir_call
164 * to call in to the C function
165 * void pxe_api_call ( struct i386_all_regs *ix86 );
166 ****************************************************************************
171 /* Preserve flags. Must do this before any operation that may
177 /* Disable interrupts. We do funny things with the stack, and
178 * we're not re-entrant.
182 /* Extract address of internal routine from stack. We must do
183 * this without using (%bp), because we may be called with
184 * either a 16-bit or a 32-bit stack segment.
186 popl %cs:save_retaddr /* Scratch location */
187 popl %cs:save_function
188 subl $8, %esp /* Restore %esp */
190 /* Switch to internal stack. Note that the external stack is
191 * inaccessible once we're running internally (since we have
192 * no concept of 48-bit far pointers)
196 /* Store external registers on internal stack */
199 pushl %cs:ext_fs_and_gs
200 pushl %cs:ext_ds_and_es
201 pushl %cs:ext_cs_and_ss
203 /* Push &ix86 on stack and call function */
206 data32 call *%cs:save_function
207 popl %eax /* discard */
209 /* Restore external registers from internal stack */
210 popl %cs:ext_cs_and_ss
211 popl %cs:ext_ds_and_es
212 popl %cs:ext_fs_and_gs
216 /* Switch to external stack */
226 /****************************************************************************
227 * Stored internal and external stack and segment registers
228 ****************************************************************************
245 kir_sp: .word _estack
247 /****************************************************************************
248 * Temporary variables
249 ****************************************************************************
252 save_retaddr: .long 0
254 save_function: .long 0