1 /* 2 * libkir: a transition library for -DKEEP_IT_REAL 3 * 4 * Michael Brown <mbrown (at) 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 257