|
|
1.1 root 1: /*
2: * libkir: a transition library for -DKEEP_IT_REAL
3: *
4: * Michael Brown <[email protected]>
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.