123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- /*
- * libkir: a transition library for -DKEEP_IT_REAL
- *
- * Michael Brown <mbrown@fensystems.co.uk>
- *
- */
-
- /****************************************************************************
- * This file defines libkir: an interface between external and
- * internal environments when -DKEEP_IT_REAL is used, so that both
- * internal and external environments are in real mode. It deals with
- * switching data segments and the stack. It provides the following
- * functions:
- *
- * ext_to_kir & switch between external and internal (kir)
- * kir_to_ext environments, preserving all non-segment
- * registers
- *
- * kir_call issue a call to an internal routine from external
- * code
- *
- * libkir is written to avoid assuming that segments are anything
- * other than opaque data types, and also avoids assuming that the
- * stack pointer is 16-bit. This should enable it to run just as well
- * in 16:16 or 16:32 protected mode as in real mode.
- ****************************************************************************
- */
-
- /* Breakpoint for when debugging under bochs */
- #define BOCHSBP xchgw %bx, %bx
-
- .text
- .arch i386
- .section ".text16", "awx", @progbits
- .code16
-
- /****************************************************************************
- * init_libkir (real-mode or 16:xx protected-mode far call)
- *
- * Initialise libkir ready for transitions to the kir environment
- *
- * Parameters:
- * %cs : .text16 segment
- * %ds : .data16 segment
- ****************************************************************************
- */
- .globl init_libkir
- init_libkir:
- /* Record segment registers */
- pushw %ds
- popw %cs:kir_ds
- lret
-
- /****************************************************************************
- * ext_to_kir (real-mode or 16:xx protected-mode near call)
- *
- * Switch from external stack and segment registers to internal stack
- * and segment registers. %ss:sp is restored from the saved kir_ds
- * and kir_sp. %ds, %es, %fs and %gs are all restored from the saved
- * kir_ds. All other registers are preserved.
- *
- * %cs:0000 must point to the start of the runtime image code segment
- * on entry.
- *
- * Parameters: none
- ****************************************************************************
- */
-
- .globl ext_to_kir
- ext_to_kir:
- /* Record external segment registers */
- movw %ds, %cs:ext_ds
- pushw %cs
- popw %ds /* Set %ds = %cs for easier access to variables */
- movw %es, %ds:ext_es
- movw %fs, %ds:ext_fs
- movw %gs, %ds:ext_fs
-
- /* Preserve registers */
- movw %ax, %ds:save_ax
-
- /* Extract near return address from stack */
- popw %ds:save_retaddr
-
- /* Record external %ss:esp */
- movw %ss, %ds:ext_ss
- movl %esp, %ds:ext_esp
-
- /* Load internal segment registers and stack pointer */
- movw %ds:kir_ds, %ax
- movw %ax, %ss
- movzwl %ds:kir_sp, %esp
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %fs
- movw %ax, %gs
- 1:
-
- /* Place return address on new stack */
- pushw %cs:save_retaddr
-
- /* Restore registers and return */
- movw %cs:save_ax, %ax
- ret
-
- /****************************************************************************
- * kir_to_ext (real-mode or 16:xx protected-mode near call)
- *
- * Switch from internal stack and segment registers to external stack
- * and segment registers. %ss:%esp is restored from the saved ext_ss
- * and ext_esp. Other segment registers are restored from the
- * corresponding locations. All other registers are preserved.
- *
- * Note that it is actually %ss that is recorded as kir_ds, on the
- * assumption that %ss == %ds when kir_to_ext is called.
- *
- * Parameters: none
- ****************************************************************************
- */
-
- .globl kir_to_ext
- kir_to_ext:
- /* Record near return address */
- pushw %cs
- popw %ds /* Set %ds = %cs for easier access to variables */
- popw %ds:save_retaddr
-
- /* Record internal segment registers and %sp */
- movw %ss, %ds:kir_ds
- movw %sp, %ds:kir_sp
-
- /* Load external segment registers and stack pointer */
- movw %ds:ext_ss, %ss
- movl %ds:ext_esp, %esp
- movw %ds:ext_gs, %gs
- movw %ds:ext_fs, %fs
- movw %ds:ext_es, %es
- movw %ds:ext_ds, %ds
-
- /* Return */
- pushw %cs:save_retaddr
- ret
-
- /****************************************************************************
- * kir_call (real-mode or 16:xx protected-mode far call)
- *
- * Call a specific C function in the internal code. The prototype of
- * the C function must be
- * void function ( struct i386_all_resg *ix86 );
- * ix86 will point to a struct containing the real-mode registers
- * at entry to kir_call.
- *
- * All registers will be preserved across kir_call(), unless the C
- * function explicitly overwrites values in ix86. Interrupt status
- * will also be preserved.
- *
- * Parameters:
- * function : (32-bit) virtual address of C function to call
- *
- * Example usage:
- * pushl $pxe_api_call
- * lcall $UNDI_CS, $kir_call
- * addw $4, %sp
- * to call in to the C function
- * void pxe_api_call ( struct i386_all_regs *ix86 );
- ****************************************************************************
- */
-
- .globl kir_call
- kir_call:
- /* Preserve flags. Must do this before any operation that may
- * affect flags.
- */
- pushfl
- popl %cs:save_flags
-
- /* Disable interrupts. We do funny things with the stack, and
- * we're not re-entrant.
- */
- cli
-
- /* Extract address of internal routine from stack. We must do
- * this without using (%bp), because we may be called with
- * either a 16-bit or a 32-bit stack segment.
- */
- popl %cs:save_retaddr /* Scratch location */
- popl %cs:save_function
- subl $8, %esp /* Restore %esp */
-
- /* Switch to internal stack. Note that the external stack is
- * inaccessible once we're running internally (since we have
- * no concept of 48-bit far pointers)
- */
- call ext_to_kir
-
- /* Store external registers on internal stack */
- pushl %cs:save_flags
- pushal
- pushl %cs:ext_fs_and_gs
- pushl %cs:ext_ds_and_es
- pushl %cs:ext_cs_and_ss
-
- /* Push &ix86 on stack and call function */
- sti
- pushl %esp
- data32 call *%cs:save_function
- popl %eax /* discard */
-
- /* Restore external registers from internal stack */
- popl %cs:ext_cs_and_ss
- popl %cs:ext_ds_and_es
- popl %cs:ext_fs_and_gs
- popal
- popl %cs:save_flags
-
- /* Switch to external stack */
- call kir_to_ext
-
- /* Restore flags */
- pushl %cs:save_flags
- popfl
-
- /* Return */
- lret
-
- /****************************************************************************
- * Stored internal and external stack and segment registers
- ****************************************************************************
- */
-
- ext_cs_and_ss:
- ext_cs: .word 0
- ext_ss: .word 0
- ext_ds_and_es:
- ext_ds: .word 0
- ext_es: .word 0
- ext_fs_and_gs:
- ext_fs: .word 0
- ext_gs: .word 0
- ext_esp: .long 0
-
- .globl kir_ds
- kir_ds: .word 0
- .globl kir_sp
- kir_sp: .word _estack
-
- /****************************************************************************
- * Temporary variables
- ****************************************************************************
- */
- save_ax: .word 0
- save_retaddr: .long 0
- save_flags: .long 0
- save_function: .long 0
|