Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / arch / i386 / transitions / libkir.S
diff --git a/qemu/roms/ipxe/src/arch/i386/transitions/libkir.S b/qemu/roms/ipxe/src/arch/i386/transitions/libkir.S
new file mode 100644 (file)
index 0000000..1176fcc
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * libkir: a transition library for -DKEEP_IT_REAL
+ *
+ * Michael Brown <mbrown@fensystems.co.uk>
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+/****************************************************************************
+ * 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