Home | History | Annotate | Download | only in transitions
      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