diff options
Diffstat (limited to 'src/arch/i386/core/realmode.c')
-rw-r--r-- | src/arch/i386/core/realmode.c | 150 |
1 files changed, 21 insertions, 129 deletions
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; |