2 * libkir: a transition library for -DKEEP_IT_REAL
4 * Michael Brown <mbrown@fensystems.co.uk>
8 FILE_LICENCE ( GPL2_OR_LATER )
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
17 * ext_to_kir & switch between external and internal (kir)
18 * kir_to_ext environments, preserving all non-segment
21 * kir_call issue a call to an internal routine from external
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 ****************************************************************************
31 /* Breakpoint for when debugging under bochs */
32 #define BOCHSBP xchgw %bx, %bx
36 .section ".text16", "awx", @progbits
39 /****************************************************************************
40 * init_libkir (real-mode or 16:xx protected-mode far call)
42 * Initialise libkir ready for transitions to the kir environment
45 * %cs : .text16 segment
46 * %ds : .data16 segment
47 ****************************************************************************
51 /* Record segment registers */
56 /****************************************************************************
57 * ext_to_kir (real-mode or 16:xx protected-mode near call)
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.
64 * %cs:0000 must point to the start of the runtime image code segment
68 ****************************************************************************
73 /* Record external segment registers */
76 popw %ds /* Set %ds = %cs for easier access to variables */
81 /* Preserve registers */
84 /* Extract near return address from stack */
87 /* Record external %ss:esp */
89 movl %esp, %ds:ext_esp
91 /* Load internal segment registers and stack pointer */
94 movzwl %ds:kir_sp, %esp
101 /* Place return address on new stack */
102 pushw %cs:save_retaddr
104 /* Restore registers and return */
105 movw %cs:save_ax, %ax
108 /****************************************************************************
109 * kir_to_ext (real-mode or 16:xx protected-mode near call)
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.
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.
120 ****************************************************************************
125 /* Record near return address */
127 popw %ds /* Set %ds = %cs for easier access to variables */
128 popw %ds:save_retaddr
130 /* Record internal segment registers and %sp */
134 /* Load external segment registers and stack pointer */
136 movl %ds:ext_esp, %esp
143 pushw %cs:save_retaddr
146 /****************************************************************************
147 * kir_call (real-mode or 16:xx protected-mode far call)
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.
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.
160 * function : (32-bit) virtual address of C function to call
163 * pushl $pxe_api_call
164 * lcall $UNDI_CS, $kir_call
166 * to call in to the C function
167 * void pxe_api_call ( struct i386_all_regs *ix86 );
168 ****************************************************************************
173 /* Preserve flags. Must do this before any operation that may
179 /* Disable interrupts. We do funny things with the stack, and
180 * we're not re-entrant.
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.
188 popl %cs:save_retaddr /* Scratch location */
189 popl %cs:save_function
190 subl $8, %esp /* Restore %esp */
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)
198 /* Store external registers on internal stack */
201 pushl %cs:ext_fs_and_gs
202 pushl %cs:ext_ds_and_es
203 pushl %cs:ext_cs_and_ss
205 /* Push &ix86 on stack and call function */
208 data32 call *%cs:save_function
209 popl %eax /* discard */
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
218 /* Switch to external stack */
228 /****************************************************************************
229 * Stored internal and external stack and segment registers
230 ****************************************************************************
247 kir_sp: .word _estack
249 /****************************************************************************
250 * Temporary variables
251 ****************************************************************************
254 save_retaddr: .long 0
256 save_function: .long 0