summaryrefslogtreecommitdiffstats
path: root/src/arch/i386/core
diff options
context:
space:
mode:
authorMichael Brown2005-04-08 17:01:17 +0200
committerMichael Brown2005-04-08 17:01:17 +0200
commit0ff80b477dcff0726ebdbed95e8a93971e59e82b (patch)
tree860b7150212a07c24a9529ea072f3fb12700974c /src/arch/i386/core
parentMerged this file into HEAD (diff)
downloadipxe-0ff80b477dcff0726ebdbed95e8a93971e59e82b.tar.gz
ipxe-0ff80b477dcff0726ebdbed95e8a93971e59e82b.tar.xz
ipxe-0ff80b477dcff0726ebdbed95e8a93971e59e82b.zip
Merged mcb30-realmode-redesign back to HEAD
Diffstat (limited to 'src/arch/i386/core')
-rw-r--r--src/arch/i386/core/callbacks.c1
-rw-r--r--src/arch/i386/core/cpu.c4
-rw-r--r--src/arch/i386/core/elf.c1
-rw-r--r--src/arch/i386/core/hooks.c108
-rw-r--r--src/arch/i386/core/i386_timer.c7
-rw-r--r--src/arch/i386/core/init.S305
-rw-r--r--src/arch/i386/core/pxe_callbacks.c27
-rw-r--r--src/arch/i386/core/realmode.c150
-rw-r--r--src/arch/i386/core/realmode_asm.S564
-rw-r--r--src/arch/i386/core/setjmp.S40
-rw-r--r--src/arch/i386/core/setup.S158
-rw-r--r--src/arch/i386/core/start16.S285
-rw-r--r--src/arch/i386/core/start32.S453
-rw-r--r--src/arch/i386/core/tagged_loader.c1
-rw-r--r--src/arch/i386/core/video_subr.c22
-rw-r--r--src/arch/i386/core/virtaddr.S317
16 files changed, 674 insertions, 1769 deletions
diff --git a/src/arch/i386/core/callbacks.c b/src/arch/i386/core/callbacks.c
index d45e63e2..8818e146 100644
--- a/src/arch/i386/core/callbacks.c
+++ b/src/arch/i386/core/callbacks.c
@@ -9,7 +9,6 @@
#include "etherboot.h"
#include "callbacks.h"
#include "realmode.h"
-#include "segoff.h"
#include <stdarg.h>
/* Maximum amount of stack data that prefix may request to be passed
diff --git a/src/arch/i386/core/cpu.c b/src/arch/i386/core/cpu.c
index 8a0f7333..7b2533f4 100644
--- a/src/arch/i386/core/cpu.c
+++ b/src/arch/i386/core/cpu.c
@@ -2,6 +2,7 @@
#include "stdint.h"
#include "string.h"
#include "bits/cpu.h"
+#include "init.h"
/* Standard macro to see if a specific flag is changeable */
@@ -83,4 +84,7 @@ void cpu_setup(void)
{
identify_cpu(&cpu_info);
}
+
+INIT_FN ( INIT_CPU, cpu_setup, NULL, NULL );
+
#endif /* CONFIG_X86_64 */
diff --git a/src/arch/i386/core/elf.c b/src/arch/i386/core/elf.c
index 6ef78c71..40a18a1f 100644
--- a/src/arch/i386/core/elf.c
+++ b/src/arch/i386/core/elf.c
@@ -1,5 +1,6 @@
#include "etherboot.h"
#include "elf.h"
+#include "memsizes.h"
#define NAME "Etherboot"
diff --git a/src/arch/i386/core/hooks.c b/src/arch/i386/core/hooks.c
index 9ca6f480..32a137b1 100644
--- a/src/arch/i386/core/hooks.c
+++ b/src/arch/i386/core/hooks.c
@@ -1,35 +1,93 @@
-#include "etherboot.h"
-#include "callbacks.h"
-#include <stdarg.h>
-
-void arch_main ( in_call_data_t *data __unused, va_list params __unused )
-{
-#ifdef PCBIOS
- /* Deallocate base memory used for the prefix, if applicable
- */
- forget_prefix_base_memory();
+#include "stdint.h"
+#include "stddef.h"
+#include "registers.h"
+#include "string.h"
+#include "hooks.h"
+#include "init.h"
+#include "main.h"
+#ifdef REALMODE
+#include "realmode.h"
#endif
-}
+/* Symbols defined by the linker */
+extern char _bss[], _ebss[];
+
+/*
+ * This file provides the basic entry points from assembly code. See
+ * README.i386 for a description of the entry code path.
+ *
+ * This file is compiled to two different object files: hooks.o and
+ * hooks_rm.o. REALMODE is defined when compiling hooks_rm.o
+ *
+ */
-void arch_relocated_from (unsigned long old_addr )
+/*
+ * arch_initialise(): perform any required initialisation such as
+ * setting up the console device and relocating to high memory. Note
+ * that if we relocate to high memory and the prefix is in base
+ * memory, then we will need to install a copy of librm in base memory
+ * and adjust retaddr so that we return to the installed copy.
+ *
+ */
+#ifdef REALMODE
+void arch_rm_initialise ( struct i386_all_regs *regs,
+ void (*retaddr) (void) )
+#else /* REALMODE */
+void arch_initialise ( struct i386_all_regs *regs,
+ void (*retaddr) (void) __unused )
+#endif /* REALMODE */
{
+ /* Zero the BSS */
+ memset ( _bss, 0, _ebss - _bss );
-#ifdef PCBIOS
- /* Deallocate base memory used for the Etherboot runtime,
- * if applicable
+ /* Call all registered initialisation functions.
*/
- forget_runtime_base_memory( old_addr );
-#endif
-
+ call_init_fns ();
}
-void arch_on_exit ( int exit_status __unused )
-{
-#ifdef PCBIOS
- /* Deallocate the real-mode stack now. We will reallocate
- * the stack if are going to use it after this point.
+#ifdef REALMODE
+
+/*
+ * arch_rm_main() : call main() and then exit via whatever exit mechanism
+ * the prefix requested.
+ *
+ */
+void arch_rm_main ( struct i386_all_regs *regs ) {
+ struct i386_all_regs regs_copy;
+ void (*exit_fn) ( struct i386_all_regs *regs );
+
+ /* Take a copy of the registers, because the memory holding
+ * them will probably be trashed by the time main() returns.
*/
- forget_real_mode_stack();
-#endif
+ regs_copy = *regs;
+ exit_fn = ( typeof ( exit_fn ) ) regs_copy.eax;
+
+ /* Call to main() */
+ regs_copy.eax = main();
+
+ /* Call registered per-object exit functions */
+ call_exit_fns ();
+
+ if ( exit_fn ) {
+ /* Prefix requested that we use a particular function
+ * as the exit path, so we call this function, which
+ * must not return.
+ */
+ exit_fn ( &regs_copy );
+ }
}
+
+#else /* REALMODE */
+
+/*
+ * arch_main() : call main() and return
+ *
+ */
+void arch_main ( struct i386_all_regs *regs ) {
+ regs->eax = main();
+
+ /* Call registered per-object exit functions */
+ call_exit_fns ();
+};
+
+#endif /* REALMODE */
diff --git a/src/arch/i386/core/i386_timer.c b/src/arch/i386/core/i386_timer.c
index 531183d4..c9aa406f 100644
--- a/src/arch/i386/core/i386_timer.c
+++ b/src/arch/i386/core/i386_timer.c
@@ -10,6 +10,7 @@
#include "etherboot.h"
#include "timer.h"
#include "latch.h"
+#include "init.h"
void __load_timer2(unsigned int ticks)
{
@@ -40,7 +41,7 @@ static int __timer2_running(void)
}
#if !defined(CONFIG_TSC_CURRTICKS)
-void setup_timers(void)
+static void setup_timers(void)
{
return;
}
@@ -126,7 +127,7 @@ bad_ctc:
}
static unsigned long clocks_per_tick;
-void setup_timers(void)
+static void setup_timers(void)
{
if (!clocks_per_tick) {
clocks_per_tick = calibrate_tsc();
@@ -189,3 +190,5 @@ int timer2_running(void)
}
#endif /* RTC_CURRTICKS */
+
+INIT_FN ( INIT_TIMERS, setup_timers, NULL, NULL );
diff --git a/src/arch/i386/core/init.S b/src/arch/i386/core/init.S
deleted file mode 100644
index 71717c25..00000000
--- a/src/arch/i386/core/init.S
+++ /dev/null
@@ -1,305 +0,0 @@
-#include "callbacks.h"
- .equ CR0_PE, 1
-
- .text
- .arch i386
- .section ".prefix", "ax", @progbits
-
-#undef CODE16
-#if defined(PCBIOS)
-#define CODE16
-#endif
-
-/* We have two entry points: "conventional" (at the start of the file)
- * and "callback" (at _entry, 2 bytes in). The "callback" entry
- * should be used if the caller wishes to provide a specific opcode.
- * It is equivalent to a call to in_call. Using the "conventional"
- * entry point is equivalent to using the "callback" entry point with
- * an opcode of EB_OPCODE_MAIN.
- *
- * Both entry points can be called in either 16-bit real or 32-bit
- * protected mode with flat physical addresses. We detect which mode
- * the processor is in and call either in_call or rm_in_call as
- * appropriate. Note that the mode detection code must therefore be
- * capable of doing the same thing in either mode, even though the
- * machine code instructions will be interpreted differently.
- *
- * The decompressor will be invoked if necessary to decompress
- * Etherboot before attempting to jump to it.
- */
-
-/******************************************************************************
- * Entry points and mode detection code
- ******************************************************************************
- */
-
- .code32
-/* "Conventional" entry point: caller provides no opcode */
- .globl _start
-_start:
- /* Set flag to indicate conventional entry point used */
- pushl $0 /* "pushw $0" in 16-bit code */
- /* Fall through to "callback" entry point */
-
-/* "Callback" entry point */
- .globl _entry
-_entry:
-
-#ifdef CODE16
- /* CPU mode detection code */
- pushl %eax /* "pushw %ax" in 16-bit code */
- pushw %ax /* "pushl %eax" in 16-bit code */
- movl %cr0, %eax /* Test protected mode bit */
- testb $CR0_PE, %al
- popw %ax /* "popl %eax" in 16-bit code */
- popl %eax /* "popw %eax" in 16-bit code */
- jz rmode
-#endif /* CODE16 */
-
-/******************************************************************************
- * Entered in protected mode
- ******************************************************************************
- */
-
- .code32
-pmode:
- cmpl $0, 0(%esp) /* Conventional entry point used? */
- jne 1f
- /* Entered via conventional entry point: set up stack */
- xchgl %eax, 4(%esp) /* %eax = return addr, store %eax */
- movl %eax, 0(%esp) /* 0(%esp) = return address */
- movl $(EB_OPCODE_MAIN|EB_USE_INTERNAL_STACK|EB_SKIP_OPCODE), %eax
- xchgl %eax, 4(%esp) /* 4(%esp) = opcode, restore %eax */
-1:
- /* Run decompressor if necessary */
- pushl %eax
- movl $decompress, %eax
- testl %eax, %eax
- jz 1f
- call decompress
-1: popl %eax
-
- /* Make in_call to Etherboot */
- jmp _prefix_in_call
-
-/******************************************************************************
- * Entered in real mode
- ******************************************************************************
- */
-
-#ifdef CODE16
- .code16
-rmode:
- pushw %ax /* Padding */
- pushw %bp
- movw %sp, %bp
- cmpw $0, 6(%bp) /* Conventional entry point used? */
- jne 1f
- /* Entered via conventional entry point: set up stack */
- pushw %ax
- movw 6(%bp), %ax
- movw %ax, 2(%bp) /* Move return address down */
- movl $(EB_OPCODE_MAIN|EB_USE_INTERNAL_STACK|EB_SKIP_OPCODE), 4(%bp)
- popw %ax
- popw %bp
- jmp 2f
-1: /* Entered via callback entry point: do nothing */
- popw %bp
- popw %ax
-2:
- /* Preserve registers */
- pushw %ds
- pushl %eax
-
- /* Run decompressor if necessary. Decompressor is 32-bit
- * code, so we must switch to pmode first. Save and restore
- * GDT over transition to pmode.
- */
- movl $decompress, %eax
- testl %eax, %eax
- jz 1f
- pushw %ds
- pushw %es
- pushw %fs
- pushw %gs
- subw $8, %sp
- pushw %bp
- movw %sp, %bp
- sgdt 2(%bp)
- pushw %ss /* Store params for _prot_to_real */
- pushw %cs
- call _prefix_real_to_prot
- .code32
- call decompress
- call _prefix_prot_to_real
- .code16
- popw %ax /* skip */
- popw %ax /* skip */
- lgdt 2(%bp)
- popw %bp
- addw $8, %sp
- popw %gs
- popw %fs
- popw %es
- popw %ds
-1:
-
- /* Set rm_etherboot_location */
- xorl %eax, %eax
- movw %cs, %ax
- movw %ax, %ds
- shll $4, %eax
- addl $_prefix_size, %eax
- movl %eax, _prefix_rm_etherboot_location
-
- /* Restore registers */
- popl %eax
- popw %ds
-
- /* Make real-mode in_call to Etherboot */
- jmp _prefix_rm_in_call
-#endif /* CODE16 */
-
-/******************************************************************************
- * Utility routines that can be called by the "prefix".
- ******************************************************************************
- */
-
-#ifdef CODE16
-
-/* Prelocate code: either to an area at the top of free base memory.
- * Switch stacks to use the stack within the resulting
- * Etherboot image.
- *
- * On entry, %cs:0000 must be the start of the prefix: this is used to
- * locate the code to be copied.
- *
- * This routine takes a single word parameter: the number of bytes to
- * be transferred from the old stack to the new stack (excluding the
- * return address and this parameter itself, which will always be
- * copied). If this value is negative, the stacks will not be
- * switched.
- *
- * Control will "return" to the appropriate point in the relocated
- * image.
- */
-
-#define PRELOC_PRESERVE ( 20 )
-#define PRELOC_OFFSET_RETADDR ( PRELOC_PRESERVE )
-#define PRELOC_OFFSET_RETADDR_E ( PRELOC_OFFSET_RETADDR + 4 )
-#define PRELOC_OFFSET_COPY ( PRELOC_OFFSET_RETADDR_E )
-#define PRELOC_OFFSET_COPY_E ( PRELOC_OFFSET_COPY + 2 )
-
-#define PRELOC_ALWAYS_COPY ( PRELOC_OFFSET_COPY_E )
-
- .code16
- .globl prelocate
-prelocate:
- /* Pad to allow for expansion of return address */
- pushw %ax
-
- /* Preserve registers */
- pushaw
- pushw %ds
- pushw %es
-
- /* Claim an area of base memory from the BIOS and put the
- * payload there.
- */
- movw $0x40, %bx
- movw %bx, %es
- movw %es:(0x13), %bx /* FBMS in kb to %ax */
- shlw $6, %bx /* ... in paragraphs */
- subw $_image_size_pgh, %bx /* Subtract space for image */
- shrw $6, %bx /* Round down to nearest kb */
- movw %bx, %es:(0x13) /* ...and claim memory from BIOS */
- shlw $6, %bx
-
- /* At this point %bx contains the segment address for the
- * start of the image (image = prefix + runtime).
- */
-
- /* Switch stacks */
- movw %ss, %ax
- movw %ax, %ds
- movw %sp, %si /* %ds:si = current %ss:sp */
- movw %ss:PRELOC_OFFSET_COPY(%si), %cx
- testw %cx, %cx
- js 1f
- leaw _stack_offset_pgh(%bx), %ax /* %ax = new %ss */
- movw %ax, %es
- movw $_stack_size, %di
- addw $PRELOC_ALWAYS_COPY, %cx
- subw %cx, %di /* %es:di = new %ss:sp */
- movw %ax, %ss /* Set new %ss:sp */
- movw %di, %sp
- cld
- rep movsb /* Copy stack contents */
-1:
-
- /* Do the image copy backwards, since if there's overlap with
- * a forward copy then it means we're going to get trashed
- * during the copy anyway...
- */
- pushal /* Preserve 32-bit registers */
- movw %bx, %es /* Destination base for copy */
- pushw %cs
- popw %ds /* Source base for copy */
- movl $_verbatim_size-1, %ecx /* Offset to last byte */
- movl %ecx, %esi
- movl %ecx, %edi
- incl %ecx /* Length */
- std /* Backwards copy of binary */
- ADDR32 rep movsb
- cld
- popal /* Restore 32-bit registers */
-
- /* Store (%bx<<4) as image_basemem to be picked up by
- * basemem.c. Also store image_size, since there's no other
- * way that we can later know how much memory we allocated.
- * (_zfile_size is unavailable when rt2 is linked).
- */
- pushl %eax
- xorl %eax, %eax
- movw %bx, %ax
- shll $4, %eax
- movl %eax, %es:_prefix_image_basemem
- movl $_image_size, %es:_prefix_image_basemem_size
- popl %eax
-
- /* Expand original near return address into far return to new
- * code location.
- */
- movw %sp, %bp
- xchgw %bx, (PRELOC_OFFSET_RETADDR+2)(%bp)
- movw %bx, (PRELOC_OFFSET_RETADDR+0)(%bp)
-
- /* Restore registers and return */
- popw %es
- popw %ds
- popaw
- lret /* Jump to relocated code */
-
- /* Utility routine to free base memory allocated by prelocate.
- * Ensure that said memory is not in use (e.g. for the CPU
- * stack) before calling this routine.
- */
- .globl deprelocate
-deprelocate:
- /* Claim an area of base memory from the BIOS and put the
- * payload there.
- */
- pushw %ax
- pushw %es
- movw $0x40, %ax
- movw %ax, %es
- movw %es:(0x13), %ax /* FBMS in kb to %ax */
- shlw $6, %ax /* ... in paragraphs */
- addw $_image_size_pgh+0x40-1, %ax /* Add space for image and... */
- shrw $6, %ax /* ...round up to nearest kb */
- movw %ax, %es:(0x13) /* Give memory back to BIOS */
- popw %es
- popw %ax
- ret
-
-#endif /* CODE16 */
diff --git a/src/arch/i386/core/pxe_callbacks.c b/src/arch/i386/core/pxe_callbacks.c
index 344d34fe..df522329 100644
--- a/src/arch/i386/core/pxe_callbacks.c
+++ b/src/arch/i386/core/pxe_callbacks.c
@@ -3,6 +3,31 @@
* an NBP to the PXE stack and for starting an NBP from the PXE stack.
*/
+#warning "pxe_callbacks.c is temporarily broken"
+
+void xstartpxe ( void ) {
+}
+
+void install_pxe_stack ( void ) {
+}
+
+void remove_pxe_stack ( void ) {
+}
+
+void hook_pxe_stack ( void ) {
+}
+
+void unhook_pxe_stack ( void ) {
+}
+
+void pxe_in_call ( void ) {
+}
+
+void use_undi_ds_for_rm_stack ( void ) {
+}
+
+#if 0
+
#ifdef PXE_EXPORT
#include "etherboot.h"
@@ -362,3 +387,5 @@ __asm__ ( ".globl _pxe_stack_t_size" );
__asm__ ( ".equ _pxe_stack_t_size, 0" );
#endif /* PXE_EXPORT */
+
+#endif /* 0 */
diff --git a/src/arch/i386/core/realmode.c b/src/arch/i386/core/realmode.c
index ef4ede86..32252bd3 100644
--- a/src/arch/i386/core/realmode.c
+++ b/src/arch/i386/core/realmode.c
@@ -3,146 +3,38 @@
* Initial version by Michael Brown <mbrown@fensystems.co.uk>, January 2004.
*/
-#include "etherboot.h"
#include "realmode.h"
-#include "segoff.h"
-#define RM_STACK_SIZE ( 0x1000 )
-
-/* gcc won't let us use extended asm outside a function (compiler
- * bug), ao we have to put these asm statements inside a dummy
- * function.
- */
-static void work_around_gcc_bug ( void ) __attribute__ ((used));
-static void work_around_gcc_bug ( void ) {
- /* Export _real_mode_stack_size as absolute linker symbol */
- __asm__ ( ".globl _real_mode_stack_size" );
- __asm__ ( ".equ _real_mode_stack_size, %c0" : : "i" (RM_STACK_SIZE) );
-}
-
-/* While Etherboot remains in base memory the real-mode stack is
- * placed in the Etherboot main stack. The first allocation or
- * deallocation of base memory will cause a 'proper' real-mode stack
- * to be allocated. This will happen before Etherboot is relocated to
- * high memory.
- */
-uint32_t real_mode_stack = 0;
-size_t real_mode_stack_size = RM_STACK_SIZE;
-int lock_real_mode_stack = 0; /* Set to make stack immobile */
-
-/* Make a call to a real-mode code block.
- */
-
-/* These is the structure that exists on the stack as the paramters
- * passed in to _real_call. We pass a pointer to this struct to
- * prepare_real_call(), to save stack space.
+/*
+ * Copy data to/from base memory.
+ *
*/
-typedef struct {
- void *fragment;
- int fragment_len;
- void *in_stack;
- int in_stack_len;
- void *out_stack;
- int out_stack_len;
-} real_call_params_t;
-uint32_t prepare_real_call ( real_call_params_t *p,
- int local_stack_len, char *local_stack ) {
- char *stack_base;
- char *stack_end;
- char *stack;
- char *s;
- prot_to_real_params_t *p2r_params;
- real_to_prot_params_t *r2p_params;
+#ifdef KEEP_IT_REAL
- /* Work out where we're putting the stack */
- if ( virt_to_phys(local_stack) < 0xa0000 ) {
- /* Current stack is in base memory. We can therefore
- * use it directly, with a constraint on the size that
- * we don't know; assume that we can use up to
- * real_mode_stack_size. (Not a valid assumption, but
- * it will do).
- */
- stack_end = local_stack + local_stack_len;
- stack_base = stack_end - real_mode_stack_size;
- } else {
- if (!real_mode_stack) {
- allot_real_mode_stack();
- }
- /* Use the allocated real-mode stack in base memory.
- * This has fixed start and end points.
- */
- stack_base = phys_to_virt(real_mode_stack);
- stack_end = stack_base + real_mode_stack_size;
- }
- s = stack = stack_end - local_stack_len;
+void memcpy_to_real ( segoff_t dest, void *src, size_t n ) {
- /* Compile input stack and trampoline code to stack */
- if ( p->in_stack_len ) {
- memcpy ( s, p->in_stack, p->in_stack_len );
- s += p->in_stack_len;
- }
- memcpy ( s, _prot_to_real_prefix, prot_to_real_prefix_size );
- s += prot_to_real_prefix_size;
- p2r_params = (prot_to_real_params_t*) ( s - sizeof(*p2r_params) );
- memcpy ( s, p->fragment, p->fragment_len );
- s += p->fragment_len;
- memcpy ( s, _real_to_prot_suffix, real_to_prot_suffix_size );
- s += real_to_prot_suffix_size;
- r2p_params = (real_to_prot_params_t*) ( s - sizeof(*r2p_params) );
+}
- /* Set parameters within compiled stack */
- p2r_params->ss = p2r_params->cs = SEGMENT ( stack_base );
- p2r_params->esp = virt_to_phys ( stack );
- p2r_params->r2p_params = virt_to_phys ( r2p_params );
- r2p_params->out_stack = ( p->out_stack == NULL ) ?
- 0 : virt_to_phys ( p->out_stack );
- r2p_params->out_stack_len = p->out_stack_len;
+void memcpy_from_real ( void *dest, segoff_t src, size_t n ) {
- return virt_to_phys ( stack + p->in_stack_len );
}
+#endif /* KEEP_IT_REAL */
-/* Parameters are not genuinely unused; they are passed to
- * prepare_real_call() as part of a real_call_params_t struct.
- */
-uint16_t _real_call ( void *fragment, int fragment_len,
- void *in_stack __unused, int in_stack_len,
- void *out_stack __unused, int out_stack_len __unused ) {
- uint16_t retval;
- /* This code is basically equivalent to
- *
- * uint32_t trampoline;
- * char local_stack[ in_stack_len + prot_to_real_prefix_size +
- * fragment_len + real_to_prot_suffix_size ];
- * trampoline = prepare_real_call ( &fragment, local_stack );
- * __asm__ ( "call _virt_to_phys\n\t"
- * "call %%eax\n\t"
- * "call _phys_to_virt\n\t"
- * : "=a" (retval) : "0" (trampoline) );
- *
- * but implemented in assembly to avoid problems with not
- * being certain exactly how gcc handles %esp.
- */
+#define RM_STACK_SIZE ( 0x1000 )
- __asm__ ( "pushl %%ebp\n\t"
- "movl %%esp, %%ebp\n\t" /* %esp preserved via %ebp */
- "subl %%ecx, %%esp\n\t" /* space for inline RM stack */
- "pushl %%esp\n\t" /* set up RM stack */
- "pushl %%ecx\n\t"
- "pushl %%eax\n\t"
- "call prepare_real_call\n\t" /* %eax = trampoline addr */
- "addl $12, %%esp\n\t"
- "call _virt_to_phys\n\t" /* switch to phys addr */
- "call *%%eax\n\t" /* call to trampoline */
- "call _phys_to_virt\n\t" /* switch to virt addr */
- "movl %%ebp, %%esp\n\t" /* restore %esp & %ebp */
- "popl %%ebp\n\t"
- : "=a" ( retval )
- : "0" ( &fragment )
- , "c" ( ( ( in_stack_len + prot_to_real_prefix_size +
- fragment_len + real_to_prot_suffix_size )
- + 0x3 ) & ~0x3 ) );
- return retval;
+/* gcc won't let us use extended asm outside a function (compiler
+ * bug), ao we have to put these asm statements inside a dummy
+ * function.
+ */
+static void work_around_gcc_bug ( void ) __attribute__ ((used));
+static void work_around_gcc_bug ( void ) {
+ /* Export _real_mode_stack_size as absolute linker symbol */
+ __asm__ ( ".globl real_mode_stack_size" );
+ __asm__ ( ".equ real_mode_stack_size, %c0" : : "i" (RM_STACK_SIZE) );
}
+
+char *real_mode_stack;
+int lock_real_mode_stack;
diff --git a/src/arch/i386/core/realmode_asm.S b/src/arch/i386/core/realmode_asm.S
index 28a5bfed..db8bc22b 100644
--- a/src/arch/i386/core/realmode_asm.S
+++ b/src/arch/i386/core/realmode_asm.S
@@ -31,570 +31,6 @@
#define LJMPI(x) ljmp x
#endif
-/****************************************************************************
- * REAL-MODE CALLBACK INTERFACE
- *
- * This must be copied down to base memory in order for external
- * programs to be able to make calls in to Etherboot. Store the
- * current physical address of Etherboot (i.e. virt_to_phys(_text)) in
- * (uint32_t)rm_etherboot_location, then copy
- * (uint16_t)rm_callback_interface_size bytes starting at
- * &((void)rm_callback_interface).
- *
- * There are two defined entry points:
- * Offset RM_IN_CALL = 0 Near call entry point
- * Offset RM_IN_CALL_FAR = 2 Far call entry point
- *
- * Note that the routines _prot_to_real and _real_to_prot double as
- * trampoline fragments for external calls (calls from Etherboot to
- * real-mode code). _prot_to_real does not automatically re-enable
- * interrupts; this is to allow for the potential of using Etherboot
- * code as an ISR. _real_to_prot does automatically disable
- * interrupts, since we don't have a protected-mode IDT.
- ****************************************************************************
- */
-
- .globl rm_callback_interface
- .code16
-rm_callback_interface:
- .globl _rm_in_call
-_rm_in_call:
- jmp _real_in_call
- .globl _rm_in_call_far
-_rm_in_call_far:
- jmp _real_in_call_far
-
-/****************************************************************************
- * _real_in_call
- *
- * Parameters:
- * 16-bit real-mode near/far return address (implicit from [l]call
- * to routine) Other parameters as for _in_call_far().
- *
- * This routine will convert the 16-bit real-mode far return address
- * to a 32-bit real-mode far return address, switch to protected mode
- * using _real_to_prot and call in to _in_call_far.
- ****************************************************************************
- */
-
-#define RIC_PRESERVE ( 8 )
-#define RIC_OFFSET_CALLADDR ( RIC_PRESERVE )
-#define RIC_OFFSET_CALLADDR_E ( RIC_OFFSET_CALLADDR + 4 )
-#define RIC_OFFSET_CONTADDR ( RIC_OFFSET_CALLADDR_E )
-#define RIC_OFFSET_CONTADDR_E ( RIC_OFFSET_CONTADDR + 4 )
-#define RIC_OFFSET_OPCODE ( RIC_OFFSET_CONTADDR_E )
-#define RIC_OFFSET_OPCODE_E ( RIC_OFFSET_OPCODE + 4 )
-#define RIC_OFFSET_SEG_REGS ( RIC_OFFSET_OPCODE_E )
-#define RIC_OFFSET_SEG_REGS_E ( RIC_OFFSET_SEG_REGS + ( NUM_SEG_REGS * 2 ) )
-#define RIC_OFFSET_PAD ( RIC_OFFSET_SEG_REGS_E )
-#define RIC_OFFSET_PAD_E ( RIC_OFFSET_PAD + 2 )
-#define RIC_OFFSET_FLAGS ( RIC_OFFSET_PAD_E )
-#define RIC_OFFSET_FLAGS_E ( RIC_OFFSET_FLAGS + 2 )
-#define RIC_OFFSET_RETADDR ( RIC_OFFSET_FLAGS_E )
-#define RIC_OFFSET_RETADDR_E ( RIC_OFFSET_RETADDR + 4 )
-#define RIC_OFFSET_ORIG_OPCODE ( RIC_OFFSET_RETADDR_E )
-#define RIC_INSERT_LENGTH ( RIC_OFFSET_OPCODE_E - RIC_OFFSET_CALLADDR )
-
- .code16
-_real_in_call:
- /* Expand near return address to far return address
- */
- pushw %ax /* Extend stack, store %ax */
- pushfw
- pushw %bp
- movw %sp, %bp
- movw %cs, %ax
- xchgw %ax, 6(%bp)
- xchgw %ax, 4(%bp) /* also restores %ax */
- popw %bp
- popfw
- /* Fall through to _real_in_call_far */
-
-_real_in_call_far:
- /* Store flags and pad */
- pushfw
- pushw %ax
-
- /* Store segment registers. Order matches that of seg_regs_t */
- pushw %gs
- pushw %fs
- pushw %es
- pushw %ds
- pushw %ss
- pushw %cs
-
- /* Switch to protected mode */
- call _real_to_prot
- .code32
-
- /* Allow space for expanded stack */
- subl $RIC_INSERT_LENGTH, %esp
-
- /* Store temporary registers */
- pushl %ebp
- pushl %eax
-
- /* Copy opcode, set EB_CALL_FROM_REAL_MODE and EP_SKIP_OPCODE.
- * Copy it because _in_call() and i386_in_call() expect it at
- * a fixed position, not as part of the va_list.
- */
- movl RIC_OFFSET_ORIG_OPCODE(%esp), %eax
- orl $(EB_CALL_FROM_REAL_MODE|EB_SKIP_OPCODE), %eax
- movl %eax, RIC_OFFSET_OPCODE(%esp)
-
- /* Set up call and return addresses */
- call 1f
-1: popl %ebp
- subl $1b, %ebp /* %ebp = offset */
- movl rm_etherboot_location(%ebp), %eax /* Etherboot phys addr */
- subl $_text, %eax
- addl $_in_call, %eax /* _in_call phys addr */
- movl %eax, RIC_OFFSET_CALLADDR(%esp)
- leal 2f(%ebp), %eax /* continuation address */
- movl %eax, RIC_OFFSET_CONTADDR(%esp)
-
- /* Restore temporary registers */
- popl %eax
- popl %ebp
-
- /* Call to _in_call */
- ret
- /* opcode will be popped automatically thanks to EB_SKIP_OPCODE */
-
-2: /* Continuation point */
- call _prot_to_real /* Return to real mode */
- /* Note: the first two words of our segment register store
- * happens to be exactly what we need to pass as parameters to
- * _prot_to_real.
- */
- .code16
- popw %ds /* Restore segment registers */
- popw %ds /* (skip cs&ss since these */
- popw %ds /* have already been set by */
- popw %es /* _prot_to_real */
- popw %fs
- popw %gs
- addw $2, %sp /* skip pad */
-
- /* Check for EB_SKIP_OPCODE */
- pushw %bp
- movw %sp, %bp
- testl $EB_SKIP_OPCODE, 6(%bp)
- popw %bp
- jnz 1f
- /* Normal return */
- popfw /* Restore interrupt status */
- lret /* Back to caller */
-1: /* Return and skip opcode */
- popfw
- lret $4
-
-/****************************************************************************
- * rm_etherboot_location: the current physical location of Etherboot.
- * Needed so that real-mode callback routines can locate Etherboot.
- ****************************************************************************
- */
- .globl rm_etherboot_location
-rm_etherboot_location: .long 0
-
-/****************************************************************************
- * _prot_to_real_prefix
- *
- * Trampoline fragment. Switch from 32-bit protected mode with flat
- * physical addresses to 16-bit real mode. Store registers in the
- * trampoline for restoration by _real_to_prot_suffix. Switch to
- * stack in base memory.
- ****************************************************************************
- */
-
- .globl _prot_to_real_prefix
- .code32
-_prot_to_real_prefix:
- /* Registers to preserve */
- pushl %ebx
- pushl %esi
- pushl %edi
- pushl %ebp
-
- /* Calculate offset */
- call 1f
-1: popl %ebp
- subl $1b, %ebp /* %ebp = offset for labels in p2r*/
-
- /* Preserve registers and return address in r2p_params */
- movl p2r_r2p_params(%ebp), %ebx
- subl $r2p_params, %ebx /* %ebx = offset for labels in r2p */
- popl r2p_ebp(%ebx)
- popl r2p_edi(%ebx)
- popl r2p_esi(%ebx)
- popl r2p_ebx(%ebx)
- popl r2p_ret_addr(%ebx)
- movl %esp, r2p_esp(%ebx)
-
- /* Switch stacks */
- movl p2r_esp(%ebp), %esp
-
- /* Switch to real mode */
- pushl p2r_segments(%ebp)
- call _prot_to_real
- .code16
- addw $4, %sp
-
- /* Fall through to next trampoline fragment */
- jmp _prot_to_real_prefix_end
-
-/****************************************************************************
- * _prot_to_real
- *
- * Switch from 32-bit protected mode with flat physical addresses to
- * 16-bit real mode. Stack and code must be in base memory when
- * called. %cs, %ss, %eip, %esp are changed to real-mode values,
- * other segment registers are destroyed, all other registers are
- * preserved. Interrupts are *not* enabled.
- *
- * Parameters:
- * %cs Real-mode code segment (word)
- * %ss Real-mode stack segment (word)
- ****************************************************************************
- */
-
-#define P2R_PRESERVE ( 12 )
-#define P2R_OFFSET_RETADDR ( P2R_PRESERVE )
-#define P2R_OFFSET_RETADDR_E ( P2R_OFFSET_RETADDR + 4 )
-#define P2R_OFFSET_CS ( P2R_OFFSET_RETADDR_E )
-#define P2R_OFFSET_CS_E ( P2R_OFFSET_CS + 2 )
-#define P2R_OFFSET_SS ( P2R_OFFSET_CS_E )
-#define P2R_OFFSET_SS_E ( P2R_OFFSET_SS + 2 )
-
- .globl _prot_to_real
- .code32
-_prot_to_real:
- /* Preserve registers */
- pushl %ebp
- pushl %ebx
- pushl %eax
-
- /* Calculate offset */
- call 1f
-1: popl %ebp
- subl $1b, %ebp /* %ebp = offset for labels in p2r*/
-
- /* Set up GDT with real-mode limits and appropriate bases for
- * real-mode %cs and %ss. Set up protected-mode continuation
- * point on stack.
- */
- /* Fixup GDT */
- leal p2r_gdt(%ebp), %eax
- movl %eax, p2r_gdt_addr(%ebp)
-
- /* Calculate CS base address: set GDT code segment, adjust
- * return address, set up continuation address on stack.
- */
- movzwl P2R_OFFSET_CS(%esp), %eax
- shll $4, %eax
- /* Change return address to real-mode far address */
- subl %eax, P2R_OFFSET_RETADDR(%esp)
- movl %eax, %ebx
- shrl $4, %ebx
- movw %bx, (P2R_OFFSET_RETADDR+2)(%esp)
- /* First real mode address */
- movl %eax, %ebx
- shrl $4, %ebx
- pushw %bx
- leal 3f(%ebp), %ebx
- subl %eax, %ebx
- pushw %bx
- /* Continuation address */
- pushl $(p2r_rmcs - p2r_gdt)
- leal 2f(%ebp), %ebx
- subl %eax, %ebx
- pushl %ebx
- /* Code segment in GDT */
- movw %ax, (p2r_rmcs+2)(%ebp)
- shrl $16, %eax /* Remainder of cs base addr */
- movb %al, (p2r_rmcs+4)(%ebp)
- movb %ah, (p2r_rmcs+7)(%ebp)
-
- /* Calculate SS base address: set GDT data segment, retain to
- * use for adjusting %esp.
- */
- movzwl (12+P2R_OFFSET_SS)(%esp), %eax /* Set ss base address */
- shll $4, %eax
- movw %ax, (p2r_rmds+2)(%ebp)
- movl %eax, %ebx
- shrl $16, %ebx
- movb %bl, (p2r_rmds+4)(%ebp)
- movb %bh, (p2r_rmds+7)(%ebp)
-
- /* Load GDT */
- lgdt p2r_gdt(%ebp)
- /* Reload all segment registers and adjust %esp */
- movw $(p2r_rmds - p2r_gdt), %bx /* Pmode DS */
- movw %bx, %ss
- subl %eax, %esp /* %esp now less than 0x10000 */
- movw %bx, %ds
- movw %bx, %es
- movw %bx, %fs
- movw %bx, %gs
- lret /* %cs:eip */
-2: /* Segment registers now have 16-bit limits. */
- .code16
-
- /* Switch to real mode */
- movl %cr0, %ebx
- andb $0!CR0_PE, %bl
- movl %ebx, %cr0
-
- /* Make intersegment jmp to flush the processor pipeline
- * and reload %cs:%eip (to clear upper 16 bits of %eip).
- */
- lret
-3:
-
- /* Load real-mode segment value to %ss. %sp already OK */
- shrl $4, %eax
- movw %ax, %ss
-
- /* Restore registers */
- popl %eax
- popl %ebx
- popl %ebp
-
- /* Return to caller in real-mode */
- lret
-
-#ifdef FLATTEN_REAL_MODE
-#define RM_LIMIT_16_19__AVL__SIZE__GRANULARITY 0x8f
-#else
-#define RM_LIMIT_16_19__AVL__SIZE__GRANULARITY 0x00
-#endif
-
-p2r_gdt:
-p2r_gdtarg:
-p2r_gdt_limit: .word p2r_gdt_end - p2r_gdt - 1
-p2r_gdt_addr: .long 0
-p2r_gdt_padding: .word 0
-p2r_rmcs:
- /* 16 bit real mode code segment */
- .word 0xffff,(0&0xffff)
- .byte (0>>16),0x9b,RM_LIMIT_16_19__AVL__SIZE__GRANULARITY,(0>>24)
-p2r_rmds:
- /* 16 bit real mode data segment */
- .word 0xffff,(0&0xffff)
- .byte (0>>16),0x93,RM_LIMIT_16_19__AVL__SIZE__GRANULARITY,(0>>24)
-p2r_gdt_end:
-
- /* This is the end of the trampoline prefix code. When used
- * as a prefix, fall through to the following code in the
- * trampoline.
- */
-p2r_params: /* Structure must match prot_to_real_params_t in realmode.h */
-p2r_esp: .long 0
-p2r_segments:
-p2r_cs: .word 0
-p2r_ss: .word 0
-p2r_r2p_params: .long 0
- .globl _prot_to_real_prefix_end
-_prot_to_real_prefix_end:
-
- .globl _prot_to_real_prefix_size
- .equ _prot_to_real_prefix_size, _prot_to_real_prefix_end - _prot_to_real_prefix
- .globl prot_to_real_prefix_size
-prot_to_real_prefix_size:
- .word _prot_to_real_prefix_size
-
-/****************************************************************************
- * _real_to_prot_suffix
- *
- * Trampoline fragment. Switch from 16-bit real-mode to 32-bit
- * protected mode with flat physical addresses. Copy returned stack
- * parameters to output_stack. Restore registers preserved by
- * _prot_to_real_prefix. Restore stack to previous location.
- ****************************************************************************
- */
-
- .globl _real_to_prot_suffix
- .code16
-_real_to_prot_suffix:
-
- /* Switch to protected mode */
- call _real_to_prot
- .code32
-
- /* Calculate offset */
- call 1f
-1: popl %ebp
- subl $1b, %ebp /* %ebp = offset for labels in r2p */
-
- /* Copy stack to out_stack */
- movl r2p_out_stack(%ebp), %edi
- movl r2p_out_stack_len(%ebp), %ecx
- movl %esp, %esi
- cld
- rep movsb
-
- /* Switch back to original stack */
- movl r2p_esp(%ebp), %esp
-
- /* Restore registers and return */
- pushl r2p_ret_addr(%ebp) /* Set up return address on stack */
- movl r2p_ebx(%ebp), %ebx
- movl r2p_esi(%ebp), %esi
- movl r2p_edi(%ebp), %edi
- movl r2p_ebp(%ebp), %ebp
- ret
-
-/****************************************************************************
- * _real_to_prot
- *
- * Switch from 16-bit real-mode to 32-bit protected mode with flat
- * physical addresses. All segment registers are destroyed, %eip and
- * %esp are changed to flat physical values, all other registers are
- * preserved. Interrupts are disabled.
- *
- * Parameters: none
- ****************************************************************************
- */
-
-#define R2P_PRESERVE ( 12 )
-#define R2P_OFFSET_RETADDR ( R2P_PRESERVE )
-#define R2P_OFFSET_ORIG_RETADDR ( R2P_OFFSET_RETADDR + 2 )
-
- .globl _real_to_prot
- .code16
-_real_to_prot:
- /* Disable interrupts */
- cli
- /* zero extend the return address */
- pushw $0
-
- /* Preserve registers */
- pushl %ebp
- pushl %ebx
- pushl %eax
-
- /* Convert 16-bit real-mode near return address to
- * 32-bit pmode physical near return address
- */
- movw %sp, %bp
- xorl %ebx, %ebx
- push %cs
- popw %bx
- movw %bx, %ds
- shll $4, %ebx
- movzwl %ss:R2P_OFFSET_ORIG_RETADDR(%bp), %eax
- addl %ebx, %eax
- movl %eax, %ss:(R2P_OFFSET_RETADDR)(%bp)
-
- /* Store the code segment physical base address in %ebp */
- movl %ebx, %ebp
-
- /* Find the offset within the code segment that I am running at */
- xorl %ebx, %ebx
- call 1f
-1: popw %bx
-
- /* Set up GDT */
- leal (r2p_gdt-1b)(%bx), %eax /* %ds:ebx = %ds:bx = &(r2p_gdt) */
- addl %ebp, %eax /* %eax = &r2p_gdt (physical) */
- movl %eax, %ds:(r2p_gdt-1b+2)(%bx) /* Set phys. addr. in r2p_gdt */
-
- /* Compute the first protected mode physical address */
- leal (2f-1b)(%bx), %eax
- addl %ebp, %eax
- movl %eax, %ds:(r2p_paddr-1b)(%bx)
-
- /* Calculate new %esp */
- xorl %eax, %eax
- push %ss
- popw %ax
- shll $4, %eax
- movzwl %sp, %ebp
- addl %eax, %ebp /* %ebp = new %esp */
-
- /* Load GDT */
- DATA32 lgdt %ds:(r2p_gdt-1b)(%bx) /* Load GDT */
-
- /* Switch to protected mode */
- movl %cr0, %eax
- orb $CR0_PE, %al
- movl %eax, %cr0
-
- /* flush prefetch queue, and reload %cs:%eip */
- DATA32 ljmp %ds:(r2p_paddr-1b)(%bx)
- .code32
-2:
-
- /* Load segment registers, adjust %esp */
- movw $(r2p_pmds-r2p_gdt), %ax
- movw %ax, %ss
- movl %ebp, %esp
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %fs
- movw %ax, %gs
-
- /* Restore registers */
- popl %eax
- popl %ebx
- popl %ebp
-
- /* return to caller */
- ret
-
-r2p_gdt:
- .word r2p_gdt_end - r2p_gdt - 1 /* limit */
- .long 0 /* addr */
- .word 0
-r2p_pmcs:
- /* 32 bit protected mode code segment, physical addresses */
- .word 0xffff, 0
- .byte 0, 0x9f, 0xcf, 0
-r2p_pmds:
- /* 32 bit protected mode data segment, physical addresses */
- .word 0xffff,0
- .byte 0,0x93,0xcf,0
-r2p_gdt_end:
-
-r2p_paddr:
- .long 2b
- .word r2p_pmcs - r2p_gdt, 0
-
-
- /* This is the end of the trampoline suffix code.
- */
-r2p_params: /* Structure must match real_to_prot_params_t in realmode.h */
-r2p_ret_addr: .long 0
-r2p_esp: .long 0
-r2p_ebx: .long 0
-r2p_esi: .long 0
-r2p_edi: .long 0
-r2p_ebp: .long 0
-r2p_out_stack: .long 0
-r2p_out_stack_len: .long 0
- .globl _real_to_prot_suffix_end
-_real_to_prot_suffix_end:
-
- .globl _real_to_prot_suffix_size
- .equ _real_to_prot_suffix_size, _real_to_prot_suffix_end - _real_to_prot_suffix
- .globl real_to_prot_suffix_size
-real_to_prot_suffix_size:
- .word _real_to_prot_suffix_size
-
-rm_callback_interface_end:
-
- .globl _rm_callback_interface_size
- .equ _rm_callback_interface_size, rm_callback_interface_end - rm_callback_interface
- .globl rm_callback_interface_size
-rm_callback_interface_size:
- .word _rm_callback_interface_size
-
-/****************************************************************************
- * END OF REAL-MODE CALLBACK INTERFACE
- ****************************************************************************
- */
-
-
#ifdef PXE_EXPORT
/****************************************************************************
* PXE CALLBACK INTERFACE
diff --git a/src/arch/i386/core/setjmp.S b/src/arch/i386/core/setjmp.S
new file mode 100644
index 00000000..59a1b7cb
--- /dev/null
+++ b/src/arch/i386/core/setjmp.S
@@ -0,0 +1,40 @@
+/* setjmp and longjmp. Use of these functions is deprecated. */
+
+ .text
+ .arch i386
+ .code32
+
+/**************************************************************************
+SETJMP - Save stack context for non-local goto
+**************************************************************************/
+ .globl setjmp
+setjmp:
+ movl 4(%esp),%ecx /* jmpbuf */
+ movl 0(%esp),%edx /* return address */
+ movl %edx,0(%ecx)
+ movl %ebx,4(%ecx)
+ movl %esp,8(%ecx)
+ movl %ebp,12(%ecx)
+ movl %esi,16(%ecx)
+ movl %edi,20(%ecx)
+ movl $0,%eax
+ ret
+
+/**************************************************************************
+LONGJMP - Non-local jump to a saved stack context
+**************************************************************************/
+ .globl longjmp
+longjmp:
+ movl 4(%esp),%edx /* jumpbuf */
+ movl 8(%esp),%eax /* result */
+ movl 0(%edx),%ecx
+ movl 4(%edx),%ebx
+ movl 8(%edx),%esp
+ movl 12(%edx),%ebp
+ movl 16(%edx),%esi
+ movl 20(%edx),%edi
+ cmpl $0,%eax
+ jne 1f
+ movl $1,%eax
+1: movl %ecx,0(%esp)
+ ret
diff --git a/src/arch/i386/core/setup.S b/src/arch/i386/core/setup.S
new file mode 100644
index 00000000..b2dd3b16
--- /dev/null
+++ b/src/arch/i386/core/setup.S
@@ -0,0 +1,158 @@
+/****************************************************************************
+ * This file provides the setup() and setup16() functions. The
+ * purpose of these functions is to set up the internal environment so
+ * that C code can execute. This includes setting up the internal
+ * stack and (where applicable) setting up a GDT for virtual
+ * addressing.
+ *
+ * These functions are designed to be called by the prefix.
+ *
+ * The same basic assembly code is used to compile both setup()
+ * and setup16().
+ ****************************************************************************
+ */
+
+ .text
+ .arch i386
+
+#ifdef CODE16
+/****************************************************************************
+ * setup16 (real-mode far call)
+ *
+ * This function can be called by a 16-bit prefix in order to set up
+ * the internal (either 16-bit or 32-bit) environment.
+ *
+ * Parameters: none
+ *
+ * %cs:0000, %ds:0000 and %es:0000 must point to the start of the
+ * (decompressed) runtime image.
+ *
+ * If KEEP_IT_REAL is defined, then %ds:0000 may instead point to the
+ * start of the (decompressed) data segment portion of the runtime
+ * image. If %ds==%cs, then it will be assumed that the data segment
+ * follows immediately after the code segment.
+ ****************************************************************************
+ */
+
+#ifdef KEEP_IT_REAL
+
+#define ENTER_FROM_EXTERNAL call ext_to_kir
+#define RETURN_TO_EXTERNAL call kir_to_ext
+#define ENTRY_POINT kir_call
+
+#else /* KEEP_IT_REAL */
+
+#define ENTER_FROM_EXTERNAL \
+ pushw %cs ; \
+ call real_to_prot ; \
+ .code32
+#define RETURN_TO_EXTERNAL \
+ call prot_to_real ; \
+ .code16
+#define ENTRY_POINT _prot_call /* _prot_call = OFFSET ( prot_call ) in librm */
+
+#endif /* KEEP_IT_REAL */
+
+#define ENTRY_POINT_REGISTER di
+
+ .section ".text16"
+ .code16
+ .globl setup16
+setup16:
+
+#else /* CODE16 */
+
+/****************************************************************************
+ * setup (32-bit protected-mode near call)
+ *
+ * This function can be called by a 32-bit prefix in order to set up
+ * the internal 32-bit environment.
+ *
+ * Parameters: none
+ ****************************************************************************
+ */
+
+#define ENTER_FROM_EXTERNAL call ext_to_int
+#define RETURN_TO_EXTERNAL call int_to_ext
+#define ENTRY_POINT int_call
+#define ENTRY_POINT_REGISTER edi
+
+ .section ".text"
+ .code32
+ .globl setup
+setup:
+
+#endif /* CODE16 */
+
+ /* Preserve flags (including interrupt status) */
+ pushfl
+
+ /* Switch to (uninitialised) internal environment. This will
+ * preserve the external environment for when we call
+ * RETURN_TO_EXTERNAL.
+ */
+ ENTER_FROM_EXTERNAL
+ /* NOTE: We may have only four bytes of stack at this point */
+
+#if defined(CODE16) && defined(KEEP_IT_REAL)
+
+ /* If %ds == %cs, then the data segment is located immediately
+ * after the code segment.
+ */
+ pushw %ax
+ pushw %bx
+ movw %cs, %ax
+ movw %ds, %bx
+ cmpw %ax, %bx
+ jne 1f
+ addw $_text_load_size_pgh, %ax
+ movw %ax, %ds
+1: popw %bx
+ popw %ax
+
+ /* Switch to internal stack */
+ pushw %ds
+ popw %ss
+ movl $_estack, %esp
+
+#else /* CODE16 && KEEP_IT_REAL */
+
+ /* Work out where we're running */
+ call 1f
+1: popl %ebp
+
+ /* Switch to internal pmode stack */
+ leal (_estack-1b)(%ebp), %esp
+
+ /* Set up GDT for virtual addressing */
+ call run_here
+
+#endif /* CODE16 && KEEP_IT_REAL */
+
+ /* Switch back to external environment. This will preserve
+ * the internal environment ready for the next call.
+ */
+ RETURN_TO_EXTERNAL
+
+ /* Pass pointer to entry-point function back to prefix. %es
+ * may, by now, have been destroyed, so we re-initialise it
+ * from %cs.
+ */
+ pushw %cs
+ popw %es
+ mov $ENTRY_POINT, %ENTRY_POINT_REGISTER
+
+ /* Restore flags (including interrupt status) */
+ popfl
+
+ lret
+
+/****************************************************************************
+ * Internal stack
+ ****************************************************************************
+ */
+ .section ".stack"
+ .align 8
+_stack:
+ .space 4096
+_estack:
diff --git a/src/arch/i386/core/start16.S b/src/arch/i386/core/start16.S
deleted file mode 100644
index 72fcfbfb..00000000
--- a/src/arch/i386/core/start16.S
+++ /dev/null
@@ -1,285 +0,0 @@
-/*****************************************************************************
- *
- * THIS FILE IS NOW OBSOLETE.
- *
- * The functions of this file are now placed in init.S.
- *
- *****************************************************************************
- */
-
-#ifndef PCBIOS
-#error "16bit code is only supported with the PCBIOS"
-#endif
-
-#define CODE_SEG 0x08
-#define DATA_SEG 0x10
-
-#define EXEC_IN_SITU_MAGIC 0x45524548 /* 'HERE' */
-
- .equ CR0_PE, 1
-
-#ifdef GAS291
-#define DATA32 data32;
-#define ADDR32 addr32;
-#define LJMPI(x) ljmp x
-#else
-#define DATA32 data32
-#define ADDR32 addr32
-/* newer GAS295 require #define LJMPI(x) ljmp *x */
-#define LJMPI(x) ljmp x
-#endif
-
-/*****************************************************************************
- *
- * start16 : move payload to desired area of memory, set up for exit
- * back to prefix, set up for 32-bit code.
- *
- * Enter (from prefix) with es:di = 0x4552:0x4548 if you want to
- * prevent start16 from moving the payload. There are three
- * motivations for moving the payload:
- *
- * 1. It may be in ROM, in which case we need to move it to RAM.
- * 2. Whatever loaded us probably didn't know about our memory usage
- * beyond the end of the image file. We should claim this memory
- * before using it.
- *
- * Unless the prefix instructs us otherwise we will move the payload to:
- *
- * An area of memory claimed from the BIOS via 40:13.
- *
- * We use the main Etherboot stack (within the image target) as our
- * stack; we don't rely on the prefix passing us a stack usable for
- * anything other than the prefix's return address. The (first 512
- * bytes of the) prefix code segment is copied to a safe archive
- * location.
- *
- * When we return to the prefix (from start32), we copy this code back
- * to a new area of memory, restore the prefix's ss:sp and ljmp back
- * to the copy of the prefix. The prefix will see a return from
- * start16 *but* may be executing at a new location. Code following
- * the lcall to start16 must therefore be position-independent and
- * must also be within [cs:0000,cs:01ff]. We make absolutely no
- * guarantees about the stack contents when the prefix regains
- * control.
- *
- * Trashes just about all registers, including all the segment
- * registers.
- *
- *****************************************************************************
- */
-
- .text
- .code16
- .arch i386
- .org 0
- .globl _start16
-_start16:
-
-/*****************************************************************************
- * Work out where we are going to place our image (image = optional
- * decompressor + runtime). Exit this stage with %ax containing the
- * runtime target address divided by 16 (i.e. a real-mode segment
- * address).
- *****************************************************************************
- */
- movw %es, %ax
- cmpw $(EXEC_IN_SITU_MAGIC >> 16), %ax
- jne exec_moved
- cmpw $(EXEC_IN_SITU_MAGIC & 0xffff), %di
- jne exec_moved
-exec_in_situ:
- /* Prefix has warned us not to move the payload. Simply
- * calculate where the image is going to end up, so we can
- * work out where to put our stack.
- */
- movw %cs, %ax
- addw $((payload-_start16)/16), %ax
- jmp 99f
-exec_moved:
- /* Claim an area of base memory from the BIOS and put the
- * payload there. arch_relocated_to() will deal with freeing
- * up this memory once we've relocated to high memory.
- */
- movw $0x40, %ax
- movw %ax, %es
- movw %es:(0x13), %ax /* FBMS in kb to %ax */
- shlw $6, %ax /* ... in paragraphs */
- subw $__image_size_pgh, %ax /* Subtract space for image */
- shrw $6, %ax /* Round down to nearest kb */
- movw %ax, %es:(0x13) /* ...and claim memory from BIOS */
- shlw $6, %ax
-99:
- /* At this point %ax contains the segment address for the
- * start of the image (image = optional decompressor + runtime).
- */
-
-/*****************************************************************************
- * Set up stack in start32's stack space within the place we're going
- * to copy Etherboot to, reserve space for GDT, copy return address
- * from prefix stack, store prefix stack address
- *****************************************************************************
- */
- popl %esi /* Return address */
- mov %ss, %bx /* %es:di = prefix stack address */
- mov %bx, %es /* (*after* pop of return address) */
- movw %sp, %di
- movw $__offset_stack_pgh, %bx /* Set up Etherboot stack */
- addw %ax, %bx
- movw %bx, %ss
- movw $__stack_size, %sp
- subw $(_gdt_end - _gdt), %sp /* Reserve space for GDT */
- movw %sp, %bp /* Record GDT location */
- /* Set up i386_rm_in_call_data_t structure on stack. This is
- * the same structure as is set up by rm_in_call.
- */
- pushl $0 /* Dummy opcode */
- pushl %esi /* Prefix return address */
- pushfw /* Flags */
- pushw %di /* Prefix %sp */
- pushw %gs /* Segment registers */
- pushw %fs
- pushw %es
- pushw %ds
- pushw %es /* Prefix %ss */
- pushw %cs
- /* Stack is now 32-bit aligned */
-
- /* %ax still contains image target segment address */
-
-/*****************************************************************************
- * Calculate image target and prefix code physical addresses, store on stack
- * for use in copy routine.
- *****************************************************************************
- */
- movzwl %es:-2(%di), %ebx /* Prefix code segment */
- shll $4, %ebx
- pushl %ebx /* Prefix code physical address */
- movzwl %ax, %edi /* Image target segment */
- shll $4, %edi
- pushl %edi /* Image target physical address */
-
-/*****************************************************************************
- * Transition to 32-bit protected mode. Set up all segment
- * descriptors to use flat physical addresses.
- *****************************************************************************
- */
- /* Copy gdt to area reserved on stack
- */
- push %cs /* GDT source location -> %ds:%si */
- pop %ds
- mov $(_gdt - _start16), %si
- push %ss /* GDT target location -> %es:%di */
- pop %es
- mov %bp, %di
- mov $(_gdt_end - _gdt), %cx
- cld
- rep movsb /* Copy GDT to stack */
- movl %ss, %eax
- shll $4, %eax
- movzwl %bp, %ebx
- addl %eax, %ebx /* Physical addr of GDT copy -> %ebx */
- movl %ebx, 2(%bp) /* Fill in addr field in GDT */
-
- /* Compute the offset I am running at.
- */
- movl %cs, %ebx
- shll $4, %ebx /* %ebx = offset for start16 symbols */
-
- /* Switch to 32bit protected mode.
- */
- cli /* Disable interrupts */
- lgdt (%bp) /* Load GDT from stack */
- movl %cr0, %eax /* Set protected mode bit */
- orb $CR0_PE, %al
- movl %eax, %cr0
- movl %ss, %eax /* Convert stack pointer to 32bit */
- shll $4, %eax
- movzwl %sp, %esp
- addl %eax, %esp
- movl $DATA_SEG, %eax /* Reload the segment registers */
- movl %eax, %ds
- movl %eax, %es
- movl %eax, %ss
- movl %eax, %fs
- movl %eax, %gs
- /* Flush prefetch queue, and reload %cs:%eip by effectively ljmping
- * to code32_start. Do the jump via pushl and lret because the text
- * may not be writable/
- */
- pushl $CODE_SEG
- ADDR32 leal (code32_start-_start16)(%ebx), %eax
- pushl %eax
- DATA32 lret /* DATA32 needed, because we're still in 16-bit mode */
-
-_gdt:
-gdtarg:
- .word _gdt_end - _gdt - 1 /* limit */
- .long 0 /* addr */
- .word 0
-_pmcs:
- /* 32 bit protected mode code segment */
- .word 0xffff, 0
- .byte 0, 0x9f, 0xcf, 0
-_pmds:
- /* 32 bit protected mode data segment */
- .word 0xffff,0
- .byte 0,0x93,0xcf,0
-_gdt_end:
-
- .code32
-code32_start:
-
-/*****************************************************************************
- * Copy payload to target location. Do the copy backwards, since if
- * there's overlap with a forward copy then it means start16 is going
- * to get trashed during the copy anyway...
- *****************************************************************************
- */
- popl %edi /* Image target physical address */
- pushl %edi
- leal (payload-_start16)(%ebx), %esi /* Image source physical addr */
- movl $__payload_size, %ecx /* Payload size (not image size) */
- addl %ecx, %edi /* Start at last byte (length - 1) */
- decl %edi
- addl %ecx, %esi
- decl %esi
- std /* Backward copy of image */
- rep movsb
- cld
- popl %edi /* Restore image target physical address */
- leal __decompressor_uncompressed(%edi), %ebx
- subl $_text, %ebx /* %ebx = offset for runtime symbols */
-
-/*****************************************************************************
- * Copy prefix to storage area within Etherboot image.
- *****************************************************************************
- */
- popl %esi /* Prefix source physical address */
- pushl %edi
- leal _prefix_copy(%ebx), %edi /* Prefix copy phys. addr. */
- leal _eprefix_copy(%ebx), %ecx
- subl %edi, %ecx /* Prefix copy size */
- rep movsb /* Forward copy of prefix */
- popl %edi /* Restore image target physical address */
-
-/*****************************************************************************
- * Record base memory used by Etherboot image
- *****************************************************************************
- */
- movl %edi, _prefix_image_basemem (%ebx)
-
-/*****************************************************************************
- * Jump to start of the image (i.e. the decompressor, or start32 if
- * non-compressed).
- *****************************************************************************
- */
- pushl $0 /* Inform start32 that exit path is 16-bit */
- jmpl *%edi /* Jump to image */
-
- .balign 16
- /* Etherboot needs to be 16byte aligned or data that
- * is virtually aligned is no longer physically aligned
- * which is just nasty in general. 16byte alignment
- * should be sufficient though.
- */
-payload:
diff --git a/src/arch/i386/core/start32.S b/src/arch/i386/core/start32.S
index 6dc3f203..e82454bb 100644
--- a/src/arch/i386/core/start32.S
+++ b/src/arch/i386/core/start32.S
@@ -1,18 +1,5 @@
-/* #defines because ljmp wants a number, probably gas bug */
-/* .equ KERN_CODE_SEG,_pmcs-_gdt */
-#define KERN_CODE_SEG 0x08
- .equ KERN_DATA_SEG,_pmds-_gdt
-/* .equ REAL_CODE_SEG,_rmcs-_gdt */
-#define REAL_CODE_SEG 0x18
- .equ REAL_DATA_SEG,_rmds-_gdt
- .equ FLAT_CODE_SEG,_pmcs2-_gdt
- .equ FLAT_DATA_SEG,_pmds2-_gdt
- .equ CR0_PE,1
-#ifdef CONFIG_X86_64
- .equ LM_CODE_SEG, _lmcs-_gdt
- .equ LM_DATA_SEG, _lmds-_gdt
-#endif
-
+#include "virtaddr.h"
+
.equ MSR_K6_EFER, 0xC0000080
.equ EFER_LME, 0x00000100
.equ X86_CR4_PAE, 0x00000020
@@ -29,12 +16,6 @@
#define LJMPI(x) ljmp x
#endif
-#define BOCHSBP xchgw %bx, %bx
-
-#include "callbacks.h"
-#define NUM_PUSHA_REGS (8)
-#define NUM_SEG_REGS (6)
-
/*
* NOTE: if you write a subroutine that is called from C code (gcc/egcs),
* then you only have to take care of %ebx, %esi, %edi and %ebp. These
@@ -54,227 +35,11 @@
* deal correctly with 16 bit return addresses. I tried it, but failed.
*/
-/**************************************************************************
- * START
- *
- * This file is no longer enterered from the top. init.S will jump to
- * either _in_call or _rm_in_call, depending on the processor mode
- * when init.S was entered.
- **************************************************************************/
.text
.arch i386
.code32
/**************************************************************************
-_IN_CALL - make a call in to Etherboot.
-**************************************************************************/
-
-/* There are two 32-bit entry points: _in_call and _in_call_far, for
- * near calls and far calls respectively. Both should be called with
- * flat physical addresses. They will result in a call to the C
- * routine in_call(); see there for API details.
- *
- * Note that this routine makes fairly heavy use of the stack and no
- * use of fixed data areas. This is because it must be re-entrant;
- * there may be more than one concurrent call in to Etherboot.
- */
-
-#define IC_OFFSET_VA_LIST_PTR ( 0 )
-#define IC_OFFSET_VA_LIST_PTR_E ( IC_OFFSET_VA_LIST_PTR + 4 )
-#define IC_OFFSET_REGISTERS ( IC_OFFSET_VA_LIST_PTR_E )
-#define IC_OFFSET_REGISTERS_E ( IC_OFFSET_REGISTERS + ( NUM_PUSHA_REGS * 4 ) )
-#define IC_OFFSET_SEG_REGS ( IC_OFFSET_REGISTERS_E )
-#define IC_OFFSET_SEG_REGS_E ( IC_OFFSET_SEG_REGS + ( NUM_SEG_REGS * 2 ) )
-#define IC_OFFSET_GDT ( IC_OFFSET_SEG_REGS_E )
-#define IC_OFFSET_GDT_E ( IC_OFFSET_GDT + 8 )
-#define IC_OFFSET_FLAGS ( IC_OFFSET_GDT_E )
-#define IC_OFFSET_FLAGS_E ( IC_OFFSET_FLAGS + 4 )
-#define IC_OFFSET_RETADDR ( IC_OFFSET_FLAGS_E )
-#define IC_OFFSET_RETADDR_E ( IC_OFFSET_RETADDR + 8 )
-#define IC_OFFSET_ORIG_STACK ( IC_OFFSET_RETADDR )
-#define IC_OFFSET_OPCODE ( IC_OFFSET_ORIG_STACK + 8 )
-#define IC_OFFSET_OPCODE_E ( IC_OFFSET_OPCODE + 4 )
-#define IC_OFFSET_VA_LIST ( IC_OFFSET_OPCODE_E )
-
- .code32
- .globl _in_call
- .globl _in_call_far
-_in_call:
- /* Expand to far return address */
- pushl %eax /* Store %eax */
- xorl %eax, %eax
- movw %cs, %ax
- xchgl %eax, 4(%esp) /* 4(%esp) = %cs, %eax = ret addr */
- xchgl %eax, 0(%esp) /* 0(%esp) = ret addr, restore %eax */
-_in_call_far:
- /* Store flags */
- pushfl
- /* Store the GDT */
- subl $8, %esp
- sgdt 0(%esp)
- /* Store segment register values */
- pushw %gs
- pushw %fs
- pushw %es
- pushw %ds
- pushw %ss
- pushw %cs
- /* Store general-purpose register values */
- pushal
- /* Replace %esp in store with physical %esp value on entry */
- leal (IC_OFFSET_ORIG_STACK - IC_OFFSET_REGISTERS)(%esp), %eax
- movl %eax, (IC_OFFSET_REGISTERS - IC_OFFSET_REGISTERS + 12)(%esp)
- /* Store va_list pointer (physical address) */
- leal (IC_OFFSET_VA_LIST - IC_OFFSET_VA_LIST_PTR_E)(%esp), %eax
- pushl %eax
- /* IC_OFFSET_*(%esp) are now valid */
-
- /* Switch to virtual addresses */
- call _phys_to_virt
-
- /* Fixup the va_list pointer */
- movl virt_offset, %ebp
- subl %ebp, IC_OFFSET_VA_LIST_PTR(%esp)
-
- /* Check opcode for EB_USE_INTERNAL_STACK flag */
- movl IC_OFFSET_OPCODE(%esp), %eax
- testl $EB_USE_INTERNAL_STACK, %eax
- je 2f
- /* Use internal stack flag set */
- /* Check %esp is not already in internal stack range */
- leal _stack, %esi /* %esi = bottom of internal stack */
- leal _estack, %edi /* %edi = top of internal stack */
- cmpl %esi, %esp
- jb 1f
- cmpl %edi, %esp
- jbe 2f
-1: /* %esp not currently in internal stack range */
- movl %esp, %esi /* %esi = original stack */
- movl $IC_OFFSET_OPCODE_E, %ecx /* %ecx = length to transfer */
- subl %ecx, %edi /* %edi = internal stack pos */
- movl %edi, %esp /* = new %esp */
- rep movsb /* Copy data to internal stack */
-2:
-
- /* Call to C code */
- call i386_in_call
-
- /* Set %eax (return code from C) in registers structure on
- * stack, so that we return it to the caller.
- */
- movl %eax, (IC_OFFSET_REGISTERS + 28)(%esp)
-
- /* Calculate physical continuation address */
- movl virt_offset, %ebp
- movzwl (IC_OFFSET_SEG_REGS + 0)(%esp), %eax /* %cs */
- movzwl (IC_OFFSET_SEG_REGS + 2)(%esp), %ebx /* %ss */
- pushl %eax /* Continuation segment */
- leal 1f(%ebp), %eax
- pushl %eax /* Continuation offset */
-
- /* Restore caller's GDT */
- cli /* Temporarily disable interrupts */
- lgdt (8+IC_OFFSET_GDT)(%esp)
- /* Reset %ss and adjust %esp */
- movw %bx, %ss
- addl %ebp, %esp
- lret /* Reload %cs:eip, flush prefetch */
-1:
-
- /* Skip va_list ptr */
- popl %eax
- /* Reload general-purpose registers to be returned */
- popal
- /* Reload segment registers as passed in from caller */
- popw %gs
- popw %fs
- popw %es
- popw %ds
- addl $(4+8), %esp /* Skip %cs, %ss and GDT (already reloaded) */
- /* Restore flags (including revert of interrupt status) */
- popfl
-
- /* Restore physical %esp from entry. It will only be
- * different if EB_USE_INTERNAL_STACK was specified.
- */
- movl ( 12 + IC_OFFSET_REGISTERS - IC_OFFSET_RETADDR )(%esp), %esp
-
- /* Check for EB_SKIP_OPCODE */
- pushfl
- testl $EB_SKIP_OPCODE, 12(%esp)
- jnz 1f
- /* Normal return */
- popfl
- lret
-1: /* Return and skip opcode */
- popfl
- lret $4
-
-/**************************************************************************
-RELOCATE_TO - relocate etherboot to the specified address
-**************************************************************************/
- .globl relocate_to
-relocate_to:
- /* Save the callee save registers */
- pushl %ebp
- pushl %esi
- pushl %edi
-
- /* Compute the virtual destination address */
- movl 16(%esp), %edi # dest
- subl virt_offset, %edi
-
-
- /* Compute the new value of virt_offset */
- movl 16(%esp), %ebp # virt_offset
- subl $_text, %ebp
-
- /* Fixup the gdt */
- pushl $_pmcs
- pushl %ebp # virt_offset
- call set_seg_base
- addl $8, %esp
-
- /* Fixup gdtarg */
- leal _gdt(%ebp), %eax
- movl %eax, gdtarg +2
-
- /* Fixup virt_offset */
- movl %ebp, virt_offset
-
- /* Load the move parameters */
- movl $_text, %esi
- movl $_end, %ecx
- subl %esi, %ecx
-
- /* Move etherboot uses %esi, %edi, %ecx */
- rep
- movsb
-
- /* Reload the gdt */
- cs
- lgdt gdtarg
-
- /* Reload %cs */
- ljmp $KERN_CODE_SEG, $1f
-1:
- /* reload other segment registers */
- movl $KERN_DATA_SEG, %eax
- movl %eax,%ds
- movl %eax,%es
- movl %eax,%ss
- movl %eax,%fs
- movl %eax,%gs
-
- /* Restore the callee save registers */
- popl %edi
- popl %esi
- popl %ebp
-
- /* return */
- ret
-
-/**************************************************************************
XSTART32 - Transfer control to the kernel just loaded
**************************************************************************/
.globl xstart32
@@ -301,7 +66,7 @@ xstart32:
pushl %ebx
/* Store the destination address on the stack */
- pushl $FLAT_CODE_SEG
+ pushl $PHYSICAL_CS
pushl %ecx
/* Cache virt_offset */
@@ -536,218 +301,6 @@ end_lm:
.arch i386
#endif /* CONFIG_X86_64 */
-/**************************************************************************
-SETJMP - Save stack context for non-local goto
-**************************************************************************/
- .globl setjmp
-setjmp:
- movl 4(%esp),%ecx /* jmpbuf */
- movl 0(%esp),%edx /* return address */
- movl %edx,0(%ecx)
- movl %ebx,4(%ecx)
- movl %esp,8(%ecx)
- movl %ebp,12(%ecx)
- movl %esi,16(%ecx)
- movl %edi,20(%ecx)
- movl $0,%eax
- ret
-
-/**************************************************************************
-LONGJMP - Non-local jump to a saved stack context
-**************************************************************************/
- .globl longjmp
-longjmp:
- movl 4(%esp),%edx /* jumpbuf */
- movl 8(%esp),%eax /* result */
- movl 0(%edx),%ecx
- movl 4(%edx),%ebx
- movl 8(%edx),%esp
- movl 12(%edx),%ebp
- movl 16(%edx),%esi
- movl 20(%edx),%edi
- cmpl $0,%eax
- jne 1f
- movl $1,%eax
-1: movl %ecx,0(%esp)
- ret
-
-/**************************************************************************
-_VIRT_TO_PHYS - Transition from virtual to physical addresses
- Preserves all preservable registers and flags
-**************************************************************************/
- .globl _virt_to_phys
-_virt_to_phys:
- pushfl
- pushl %ebp
- pushl %eax
- movl virt_offset, %ebp /* Load virt_offset */
- addl %ebp, 12(%esp) /* Adjust the return address */
-
- /* reload the code segment */
- pushl $FLAT_CODE_SEG
- leal 1f(%ebp), %eax
- pushl %eax
- lret
-
-1:
- /* reload other segment registers */
- movl $FLAT_DATA_SEG, %eax
- movl %eax, %ds
- movl %eax, %es
- movl %eax, %ss
- addl %ebp, %esp /* Adjust the stack pointer */
- movl %eax, %fs
- movl %eax, %gs
-
- popl %eax
- popl %ebp
- popfl
- ret
-
-
-/**************************************************************************
-_PHYS_TO_VIRT - Transition from using physical to virtual addresses
- Preserves all preservable registers and flags
-**************************************************************************/
- .globl _phys_to_virt
-_phys_to_virt:
- pushfl
- pushl %ebp
- pushl %eax
-
- call 1f
-1: popl %ebp
- subl $1b, %ebp
- movl %ebp, virt_offset(%ebp)
-
- /* Fixup the gdt */
- leal _pmcs(%ebp), %eax
- pushl %eax
- pushl %ebp
- call set_seg_base
- addl $8, %esp
-
- /* Fixup gdtarg */
- leal _gdt(%ebp), %eax
- movl %eax, (gdtarg+2)(%ebp)
-
- /* Load the global descriptor table */
- cli
- lgdt %cs:gdtarg(%ebp)
- ljmp $KERN_CODE_SEG, $1f
-1:
- /* reload other segment regsters */
- movl $KERN_DATA_SEG, %eax
- movl %eax, %ds
- movl %eax, %es
- movl %eax, %ss
- subl %ebp, %esp /* Adjust the stack pointer */
- movl %eax, %fs
- movl %eax, %gs
-
- subl %ebp, 12(%esp) /* Adjust the return address */
- popl %eax
- popl %ebp
- popfl
- ret
-
-
-/**************************************************************************
-SET_SEG_BASE - Set the base address of a segment register
-**************************************************************************/
- .globl set_seg_base
-set_seg_base:
- pushl %eax
- pushl %ebx
- movl 12(%esp), %eax /* %eax = base address */
- movl 16(%esp), %ebx /* %ebx = &code_descriptor */
- movw %ax, (0+2)(%ebx) /* CS base bits 0-15 */
- movw %ax, (8+2)(%ebx) /* DS base bits 0-15 */
- shrl $16, %eax
- movb %al, (0+4)(%ebx) /* CS base bits 16-23 */
- movb %al, (8+4)(%ebx) /* DS base bits 16-23 */
- movb %ah, (0+7)(%ebx) /* CS base bits 24-31 */
- movb %ah, (8+7)(%ebx) /* DS base bits 24-31 */
- popl %ebx
- popl %eax
- ret
-
-/**************************************************************************
-GLOBAL DESCRIPTOR TABLE
-**************************************************************************/
- .data
- .align 4
-
- .globl _gdt
- .globl gdtarg
-_gdt:
-gdtarg:
- .word _gdt_end - _gdt - 1 /* limit */
- .long _gdt /* addr */
- .word 0
-
- .globl _pmcs
-_pmcs:
- /* 32 bit protected mode code segment */
- .word 0xffff,0
- .byte 0,0x9f,0xcf,0
-
-_pmds:
- /* 32 bit protected mode data segment */
- .word 0xffff,0
- .byte 0,0x93,0xcf,0
-
-_rmcs:
- /* 16 bit real mode code segment */
- .word 0xffff,(0&0xffff)
- .byte (0>>16),0x9b,0x00,(0>>24)
-
-_rmds:
- /* 16 bit real mode data segment */
- .word 0xffff,(0&0xffff)
- .byte (0>>16),0x93,0x00,(0>>24)
-
-_pmcs2:
- /* 32 bit protected mode code segment, base 0 */
- .word 0xffff,0
- .byte 0,0x9f,0xcf,0
-
-_pmds2:
- /* 32 bit protected mode data segment, base 0 */
- .word 0xffff,0
- .byte 0,0x93,0xcf,0
-
-#ifdef CONFIG_X86_64
-_lmcs:
- /* 64bit long mode code segment, base 0 */
- .word 0xffff, 0
- .byte 0x00, 0x9f, 0xaf , 0x00
-_lmds:
- /* 64bit long mode data segment, base 0 */
- .word 0xffff, 0
- .byte 0x00, 0x93, 0xcf, 0x00
-#endif
-_gdt_end:
-
- /* The initial register contents */
- .balign 4
- .globl initial_regs
-initial_regs:
- .fill 8, 4, 0
-
- /* The virtual address offset */
- .globl virt_offset
-virt_offset:
- .long 0
-
- .section ".stack"
- .p2align 3
- /* allocate a 4K stack in the stack segment */
- .globl _stack
-_stack:
- .space 4096
- .globl _estack
-_estack:
#ifdef CONFIG_X86_64
.section ".bss"
.p2align 12
diff --git a/src/arch/i386/core/tagged_loader.c b/src/arch/i386/core/tagged_loader.c
index 9c6d6c25..8955b0f8 100644
--- a/src/arch/i386/core/tagged_loader.c
+++ b/src/arch/i386/core/tagged_loader.c
@@ -1,5 +1,4 @@
#include "realmode.h"
-#include "segoff.h"
struct segheader
{
diff --git a/src/arch/i386/core/video_subr.c b/src/arch/i386/core/video_subr.c
index dccdd97c..dbcfc73d 100644
--- a/src/arch/i386/core/video_subr.c
+++ b/src/arch/i386/core/video_subr.c
@@ -5,10 +5,14 @@
*
*/
-#ifdef CONSOLE_DIRECT_VGA
+#include "stddef.h"
+#include "string.h"
+#include "io.h"
+#include "console.h"
+#include "init.h"
+#include "vga.h"
-#include <etherboot.h>
-#include <vga.h>
+static struct console_driver vga_console;
static char *vidmem; /* The video buffer */
static int video_line, video_col;
@@ -17,7 +21,7 @@ static int video_line, video_col;
static void memsetw(void *s, int c, unsigned int n)
{
- int i;
+ unsigned int i;
u16 *ss = (u16 *) s;
for (i = 0; i < n; i++) {
@@ -25,7 +29,7 @@ static void memsetw(void *s, int c, unsigned int n)
}
}
-void video_init(void)
+static void video_init(void)
{
static int inited=0;
@@ -50,7 +54,7 @@ static void video_scroll(void)
vidmem[i] = ' ';
}
-void vga_putc(unsigned char byte)
+static void vga_putc(int byte)
{
if (byte == '\n') {
video_line++;
@@ -90,5 +94,9 @@ void vga_putc(unsigned char byte)
write_crtc((video_col + (video_line *COLS)) & 0x0ff, CRTC_CURSOR_LO);
}
-#endif
+static struct console_driver vga_console __console_driver = {
+ .putchar = vga_putc,
+ .disabled = 1,
+};
+INIT_FN ( INIT_CONSOLE, video_init, NULL, NULL );
diff --git a/src/arch/i386/core/virtaddr.S b/src/arch/i386/core/virtaddr.S
new file mode 100644
index 00000000..ed495c35
--- /dev/null
+++ b/src/arch/i386/core/virtaddr.S
@@ -0,0 +1,317 @@
+/*
+ * Functions to support the virtual addressing method of relocation
+ * that Etherboot uses.
+ *
+ */
+
+#include "virtaddr.h"
+
+ .arch i386
+
+/****************************************************************************
+ * GDT for initial transition to protected mode
+ *
+ * The segment values, PHYSICAL_CS et al, are defined in an external
+ * header file virtaddr.h, since they need to be shared with librm.
+ ****************************************************************************
+ */
+ .data
+ .align 16
+
+gdt:
+gdt_limit: .word gdt_length - 1
+gdt_addr: .long 0
+ .word 0 /* padding */
+
+ .org gdt + PHYSICAL_CS
+physical_cs:
+ /* 32 bit protected mode code segment, physical addresses */
+ .word 0xffff,0
+ .byte 0,0x9f,0xcf,0
+
+ .org gdt + PHYSICAL_DS
+physical_ds:
+ /* 32 bit protected mode data segment, physical addresses */
+ .word 0xffff,0
+ .byte 0,0x93,0xcf,0
+
+ .org gdt + VIRTUAL_CS
+virtual_cs:
+ /* 32 bit protected mode code segment, virtual addresses */
+ .word 0xffff,0
+ .byte 0,0x9f,0xcf,0
+
+ .org gdt + VIRTUAL_DS
+virtual_ds:
+ /* 32 bit protected mode data segment, virtual addresses */
+ .word 0xffff,0
+ .byte 0,0x93,0xcf,0
+
+#ifdef CONFIG_X86_64
+
+ .org gdt + LONG_CS
+long_cs:
+ /* 64bit long mode code segment, base 0 */
+ .word 0xffff, 0
+ .byte 0x00, 0x9f, 0xaf , 0x00
+
+ .org gdt + LONG_DS
+long_ds:
+ /* 64bit long mode data segment, base 0 */
+ .word 0xffff, 0
+ .byte 0x00, 0x93, 0xcf, 0x00
+
+#endif /* CONFIG_X86_64 */
+
+gdt_end:
+ .equ gdt_length, gdt_end - gdt
+
+ /* The virtual address offset */
+ .globl virt_offset
+virt_offset: .long 0
+
+ .text
+ .code32
+
+/****************************************************************************
+ * run_here (flat physical addressing, position-independent)
+ *
+ * Set up a GDT to run Etherboot at the current location with virtual
+ * addressing. This call does not switch to virtual addresses or move
+ * the stack pointer. The GDT will be located within the copy of
+ * Etherboot. All registers are preserved.
+ *
+ * This gets called at startup and at any subsequent relocation of
+ * Etherboot.
+ *
+ * Parameters: none
+ ****************************************************************************
+ */
+ .globl run_here
+run_here:
+ /* Preserve registers */
+ pushl %eax
+ pushl %ebp
+
+ /* Find out where we're running */
+ call 1f
+1: popl %ebp
+ subl $1b, %ebp
+
+ /* Store as virt_offset */
+ movl %ebp, virt_offset(%ebp)
+
+ /* Set segment base addresses in GDT */
+ leal virtual_cs(%ebp), %eax
+ pushl %eax
+ pushl %ebp
+ call set_seg_base
+ popl %eax /* discard */
+ popl %eax /* discard */
+
+ /* Set physical location of GDT */
+ leal gdt(%ebp), %eax
+ movl %eax, gdt_addr(%ebp)
+
+ /* Load the new GDT */
+ lgdt gdt(%ebp)
+
+ /* Reload new flat physical segment registers */
+ movl $PHYSICAL_DS, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %fs
+ movl %eax, %gs
+ movl %eax, %ss
+
+ /* Restore registers, convert return address to far return
+ * address.
+ */
+ popl %ebp
+ movl $PHYSICAL_CS, %eax
+ xchgl %eax, 4(%esp) /* cs now on stack, ret offset now in eax */
+ xchgl %eax, 0(%esp) /* ret offset now on stack, eax restored */
+
+ /* Return to caller, reloading %cs with new value */
+ lret
+
+/****************************************************************************
+ * set_seg_base (any addressing, position-independent)
+ *
+ * Set the base address of a pair of segments in the GDT. This relies
+ * on the layout of the GDT being (CS,DS) pairs.
+ *
+ * Parameters:
+ * uint32_t base_address
+ * struct gdt_entry * code_segment
+ * Returns:
+ * none
+ ****************************************************************************
+ */
+ .globl set_seg_base
+set_seg_base:
+ pushl %eax
+ pushl %ebx
+ movl 12(%esp), %eax /* %eax = base address */
+ movl 16(%esp), %ebx /* %ebx = &code_descriptor */
+ movw %ax, (0+2)(%ebx) /* CS base bits 0-15 */
+ movw %ax, (8+2)(%ebx) /* DS base bits 0-15 */
+ shrl $16, %eax
+ movb %al, (0+4)(%ebx) /* CS base bits 16-23 */
+ movb %al, (8+4)(%ebx) /* DS base bits 16-23 */
+ movb %ah, (0+7)(%ebx) /* CS base bits 24-31 */
+ movb %ah, (8+7)(%ebx) /* DS base bits 24-31 */
+ popl %ebx
+ popl %eax
+ ret
+
+/****************************************************************************
+ * _virt_to_phys (virtual addressing)
+ *
+ * Switch from virtual to flat physical addresses. %esp is adjusted
+ * to a physical value. Segment registers are set to flat physical
+ * selectors. All other registers are preserved. Flags are
+ * preserved.
+ *
+ * Parameters: none
+ * Returns: none
+ ****************************************************************************
+ */
+ .globl _virt_to_phys
+_virt_to_phys:
+ /* Preserve registers and flags */
+ pushfl
+ pushl %eax
+ pushl %ebp
+
+ /* Change return address to a physical address */
+ movl virt_offset, %ebp
+ addl %ebp, 12(%esp)
+
+ /* Switch to physical code segment */
+ pushl $PHYSICAL_CS
+ leal 1f(%ebp), %eax
+ pushl %eax
+ lret
+1:
+ /* Reload other segment registers and adjust %esp */
+ movl $PHYSICAL_DS, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %fs
+ movl %eax, %gs
+ movl %eax, %ss
+ addl %ebp, %esp
+
+ /* Restore registers and flags, and return */
+ popl %ebp
+ popl %eax
+ popfl
+ ret
+
+/****************************************************************************
+ * _phys_to_virt (flat physical addressing)
+ *
+ * Switch from flat physical to virtual addresses. %esp is adjusted
+ * to a virtual value. Segment registers are set to virtual
+ * selectors. All other registers are preserved. Flags are
+ * preserved.
+ *
+ * Note that this depends on the GDT already being correctly set up
+ * (e.g. by a call to run_here()).
+ *
+ * Parameters: none
+ * Returns: none
+ ****************************************************************************
+ */
+ .globl _phys_to_virt
+_phys_to_virt:
+ /* Preserve registers and flags */
+ pushfl
+ pushl %eax
+ pushl %ebp
+
+ /* Switch to virtual code segment */
+ ljmp $VIRTUAL_CS, $1f
+1:
+ /* Reload data segment registers */
+ movl $VIRTUAL_DS, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %fs
+ movl %eax, %gs
+
+ /* Reload stack segment and adjust %esp */
+ movl virt_offset, %ebp
+ movl %eax, %ss
+ subl %ebp, %esp
+
+ /* Change the return address to a virtual address */
+ subl %ebp, 12(%esp)
+
+ /* Restore registers and flags, and return */
+ popl %ebp
+ popl %eax
+ popfl
+ ret
+
+/****************************************************************************
+ * relocate_to (virtual addressing)
+ *
+ * Relocate Etherboot to the specified address. The runtime image
+ * (excluding the prefix, decompressor and compressed image) is copied
+ * to a new location, and execution continues in the new copy. This
+ * routine is designed to be called from C code.
+ *
+ * Parameters:
+ * uint32_t new_phys_addr
+ ****************************************************************************
+ */
+ .globl relocate_to
+relocate_to:
+ /* Save the callee save registers */
+ pushl %ebp
+ pushl %esi
+ pushl %edi
+
+ /* Compute the physical source address and data length */
+ movl $_text, %esi
+ movl $_end, %ecx
+ subl %esi, %ecx
+ addl virt_offset, %esi
+
+ /* Compute the physical destination address */
+ movl 16(%esp), %edi
+
+ /* Switch to flat physical addressing */
+ call _virt_to_phys
+
+ /* Do the copy */
+ cld
+ rep movsb
+
+ /* Calculate offset to new image */
+ subl %esi, %edi
+
+ /* Switch to executing in new image */
+ call 1f
+1: popl %ebp
+ leal (2f-1b)(%ebp,%edi), %eax
+ jmpl *%eax
+2:
+ /* Switch to stack in new image */
+ addl %edi, %esp
+
+ /* Call run_here() to set up GDT */
+ call run_here
+
+ /* Switch to virtual addressing */
+ call _phys_to_virt
+
+ /* Restore the callee save registers */
+ popl %edi
+ popl %esi
+ popl %ebp
+
+ /* return */
+ ret