Towards a(nother) new real-mode infrastructure, in which we take
authorMichael Brown <mcb30@etherboot.org>
Tue, 2 May 2006 15:41:21 +0000 (15:41 +0000)
committerMichael Brown <mcb30@etherboot.org>
Tue, 2 May 2006 15:41:21 +0000 (15:41 +0000)
advantage of the fact that we have to have a permanently-resident block
in base memory.

src/arch/i386/core/relocate.c
src/arch/i386/core/virtaddr.S
src/arch/i386/include/librm.h
src/arch/i386/include/realmode.h
src/arch/i386/include/virtaddr.h
src/arch/i386/prefix/dskprefix.S
src/arch/i386/scripts/i386.lds
src/arch/i386/transitions/librm.S
src/arch/i386/transitions/librm_mgmt.c
src/include/osdep.h

index 7d5ba32..a51d515 100644 (file)
@@ -1,30 +1,11 @@
-#include "virtaddr.h"
-#include "memsizes.h"
-#include "osdep.h"
-#include "etherboot.h"
-#include <gpxe/init.h>
-#include "relocate.h"
-
-#ifndef KEEP_IT_REAL
-
-/* by Eric Biederman */
-
-/* On some platforms etherboot is compiled as a shared library, and we use
- * the ELF pic support to make it relocateable.  This works very nicely
- * for code, but since no one has implemented PIC data yet pointer
- * values in variables are a a problem.  Global variables are a
- * pain but the return addresses on the stack are the worst.  On these
- * platforms relocate_to will restart etherboot, to ensure the stack
- * is reinitialize and hopefully get the global variables
- * appropriately reinitialized as well.
- * 
- */
+#include <virtaddr.h>
+#include <registers.h>
+#include <memsizes.h>
 
 /*
- * relocate() must be called without any hardware resources pointing
- * at the current copy of Etherboot.  The easiest way to achieve this
- * is to call relocate() from within arch_initialise(), before the NIC
- * gets touched in any way.
+ * Originally by Eric Biederman
+ *
+ * Heavily modified by Michael Brown 
  *
  */
 
@@ -40,14 +21,27 @@ extern char _max_align[];
 extern char _text[];
 extern char _end[];
 
-/* Post-relocation function table */
-static struct post_reloc_fn post_reloc_fns[0] __table_start(post_reloc_fn);
-static struct post_reloc_fn post_reloc_fns_end[0] __table_end(post_reloc_fn);
+/* within 1MB of 4GB is too close. 
+ * MAX_ADDR is the maximum address we can easily do DMA to.
+ *
+ * Not sure where this constraint comes from, but kept it from Eric's
+ * old code - mcb30
+ */
+#define MAX_ADDR (0xfff00000UL)
 
-static void relocate ( void ) {
+/**
+ * Relocate Etherboot
+ *
+ * @v ix86             x86 register dump from prefix
+ * @ret ix86           x86 registers to return to prefix
+ *
+ * This copies Etherboot to a suitable location near the top of 32-bit
+ * address space, and returns the physical address of the new location
+ * to the prefix in %edi.
+ */
+void relocate ( struct i386_all_regs *ix86 ) {
        unsigned long addr, eaddr, size;
        unsigned i;
-       struct post_reloc_fn *post_reloc_fn;
 
        /* Walk through the memory map and find the highest address
         * below 4GB that etherboot will fit into.  Ensure etherboot
@@ -183,25 +177,9 @@ static void relocate ( void ) {
                      virt_to_phys ( _text ), virt_to_phys ( _end ),
                      addr, addr + _end - _text );
 
-               relocate_to ( addr );
-               /* Note that we cannot make real-mode calls
-                * (e.g. printf) at this point, because librm has just
-                * been moved to high memory.
-                */
-
-               /* Call any registered post-relocation functions.
-                * librm has a post-relocation function to install a
-                * new librm into base memory.
-                */
-               for ( post_reloc_fn = post_reloc_fns;
-                     post_reloc_fn < post_reloc_fns_end ; post_reloc_fn++ ) {
-                       if ( post_reloc_fn->post_reloc )
-                               post_reloc_fn->post_reloc ();
-               }
-               
+               memcpy ( phys_to_virt ( addr ), _text, _end - _text );
        }
+       
+       /* Let prefix know where the new copy is */
+       ix86->regs.edi = addr;
 }
-
-INIT_FN ( INIT_RELOCATE, relocate, NULL, NULL );
-
-#endif /* ! KEEP_IT_REAL */
index ed495c3..5d76237 100644 (file)
@@ -7,164 +7,9 @@
 #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)
  *
@@ -254,64 +99,3 @@ _phys_to_virt:
        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
index 1b82a98..7171448 100644 (file)
  *
  */
 
-/* Real-mode call parameter block, as passed to real_call */
-struct real_call_params {
-       struct i386_seg_regs segs;
-       struct i386_regs regs;
-       segoff_t rm_code;
-       segoff_t reserved;
-} PACKED;
-
-/* Current location of librm in base memory */
-extern char *installed_librm;
-
-/* Start and size of our source copy of librm (i.e. the one that we
- * can install by copying it to base memory and setting
- * installed_librm)
- */
-extern char librm[];
-extern size_t _librm_size[];
-
-/* Linker symbols for offsets within librm.  Other symbols should
- * almost certainly not be referred to from C code.
- */
-extern void (*_real_to_prot[]) ( void );
-extern void (*_prot_to_real[]) ( void );
-extern void (*_prot_call[]) ( void );
-extern void (*_real_call[]) ( void );
-extern uint32_t _librm_base[];
-extern segoff_t _rm_stack[];
-extern uint32_t _pm_stack[];
-extern char _librm_ref_count[];
-
-/* Symbols within current installation of librm */
-#define LIBRM_VAR( sym ) \
-       ( * ( ( typeof ( * _ ## sym ) * ) \
-             & ( installed_librm [ (int) _ ## sym ] ) ) )
-#define LIBRM_FN( sym ) \
-        ( ( typeof ( * _ ## sym ) ) \
-             & ( installed_librm [ (int) _ ## sym ] ) )
-#define LIBRM_CONSTANT( sym ) \
-       ( ( typeof ( * _ ## sym ) ) ( _ ## sym ) )
-#define inst_real_to_prot      LIBRM_FN ( real_to_prot )
-#define inst_prot_to_real      LIBRM_FN ( prot_to_real )
-#define inst_prot_call         LIBRM_FN ( prot_call )
-#define inst_real_call         LIBRM_FN ( real_call )
-#define inst_librm_base                LIBRM_VAR ( librm_base )
-#define inst_rm_stack          LIBRM_VAR ( rm_stack )
-#define inst_pm_stack          LIBRM_VAR ( pm_stack )
-#define inst_librm_ref_count   LIBRM_VAR ( librm_ref_count )
-#define librm_size             LIBRM_CONSTANT ( librm_size )
-
-/* Symbols within local (uninstalled) copy of librm */
-extern uint32_t librm_base;
+/* Variables in librm.S, present in the normal data segment */
+extern uint16_t rm_sp;
+extern uint16_t rm_ss;
+extern uint16_t rm_cs;
+extern uint32_t pm_esp;
 
 /* Functions that librm expects to be able to link to.  Included here
  * so that the compiler will catch prototype mismatches.
  */
-extern void _phys_to_virt ( void );
-extern void _virt_to_phys ( void );
 extern void gateA20_set ( void );
 
 /*
@@ -132,7 +84,7 @@ extern void remove_from_rm_stack ( void *data, size_t size );
                ".arch i386\n\t"                                        \
                #name ":\n\t"                                           \
                asm_code_str "\n\t"                                     \
-               "lret\n\t"                                              \
+               "ret\n\t"                                               \
                #name "_end:\n\t"                                       \
                ".equ " #name "_size, " #name "_end - " #name "\n\t"    \
                ".code32\n\t"                                           \
@@ -143,26 +95,19 @@ extern void remove_from_rm_stack ( void *data, size_t size );
 
 /* REAL_CALL: call a real-mode routine via librm */
 #define OUT_CONSTRAINTS(...) __VA_ARGS__
-#define IN_CONSTRAINTS(...) "m" ( __routine ), ## __VA_ARGS__
+#define IN_CONSTRAINTS(...) __VA_ARGS__
 #define CLOBBER(...) __VA_ARGS__
-#define REAL_CALL( routine, num_out_constraints, out_constraints,           \
-                  in_constraints, clobber )                                 \
-       do {                                                                 \
-               segoff_t __routine = routine;                                \
-               __asm__ __volatile__ (                                       \
-                                     "pushl %" #num_out_constraints "\n\t"  \
-                                     "call 1f\n\t"                          \
-                                     "jmp 2f\n\t"                           \
-                                     "\n1:\n\t"                             \
-                                     "pushl installed_librm\n\t"            \
-                                     "addl $_real_call, 0(%%esp)\n\t"       \
-                                     "ret\n\t"                              \
-                                     "\n2:\n\t"                             \
-                                     "addl $4, %%esp\n\t"                   \
-                                     : out_constraints                      \
-                                     : in_constraints                       \
-                                     : clobber                              \
-                                     );                                     \
+#define REAL_CALL( routine, num_out_constraints, out_constraints,      \
+                  in_constraints, clobber )                            \
+       do {                                                            \
+               __asm__ __volatile__ (                                  \
+                                     "pushl $" #routine "\n\t"         \
+                                     "call real_call\n\t"              \
+                                     "addl $4, %%esp\n\t"              \
+                                     : out_constraints                 \
+                                     : in_constraints                  \
+                                     : clobber                         \
+                                     );                                \
        } while ( 0 )
 
 /* REAL_EXEC: combine RM_FRAGMENT and REAL_CALL into one handy unit */
@@ -170,20 +115,12 @@ extern void remove_from_rm_stack ( void *data, size_t size );
 #define REAL_EXEC( name, asm_code_str, num_out_constraints, out_constraints, \
                   in_constraints, clobber )                                 \
        do {                                                                 \
-               segoff_t fragment;                                           \
-                                                                            \
                REAL_FRAGMENT ( name, asm_code_str );                        \
                                                                             \
-               fragment.segment = inst_rm_stack.segment;                    \
-               fragment.offset =                                            \
-                       copy_to_rm_stack ( name, FRAGMENT_SIZE ( name ) );   \
-                                                                            \
-               REAL_CALL ( fragment, num_out_constraints,                   \
+               REAL_CALL ( name, num_out_constraints,                       \
                            PASSTHRU ( out_constraints ),                    \
                            PASSTHRU ( in_constraints ),                     \
                            PASSTHRU ( clobber ) );                          \
-                                                                            \
-               remove_from_rm_stack ( NULL, FRAGMENT_SIZE ( name ) );       \
        } while ( 0 )
 
 #endif /* ASSEMBLY */
index fe01118..f14aae2 100644 (file)
@@ -18,7 +18,7 @@
 typedef struct {
        uint16_t offset;
        uint16_t segment;
-} segoff_t PACKED;
+} __attribute__ (( packed )) segoff_t;
 
 /* Macro hackery needed to stringify bits of inline assembly */
 #define RM_XSTR(x) #x
index 4d248b0..f2ffa2a 100644 (file)
@@ -5,12 +5,17 @@
  *
  * Don't change these unless you really know what you're doing.
  */
-#define PHYSICAL_CS 0x08
-#define PHYSICAL_DS 0x10
-#define VIRTUAL_CS 0x18
-#define VIRTUAL_DS 0x20
-#define LONG_CS 0x28
-#define LONG_DS 0x30
+
+#define VIRTUAL_CS 0x08
+#define VIRTUAL_DS 0x10
+#define PHYSICAL_CS 0x18
+#define PHYSICAL_DS 0x20
+#define REAL_CS 0x28
+#define REAL_DS 0x30
+#if 0
+#define LONG_CS 0x38
+#define LONG_DS 0x40
+#endif
 
 #ifndef ASSEMBLY
 
index 62b8f5f..05bf45b 100644 (file)
@@ -3,7 +3,8 @@
  *
  * SYS_SIZE is the number of clicks (16 bytes) to be loaded.
  */
-.equ   SYSSIZE, 8192   # 8192 * 16 bytes = 128kB maximum size of .ROM file
+.globl SYSSIZE
+.equ   SYSSIZE, _load_size_pgh
 
 /*     floppyload.S Copyright (C) 1991, 1992 Linus Torvalds
  *     modified by Drew Eckhardt
@@ -143,36 +144,8 @@ got_sectors:
         * start of loaded image.
         */
 
-start_runtime:
-
-#ifdef COMPRESS
-       /* Decompress runtime image.  %es:0000 points to decompressed
-        * image on exit.
-        */
-       lcall   $SYSSEG, $decompress16
-#endif
-       
-       /* Set up internal environment.  Address of entry-point
-        * function is returned in %es:di.
-        */
-       pushw   %es             /* setup16 says %ds:0000 must point to image */
-       popw    %ds
-       movw    $setup16, %di
-       pushw   %cs
-       call    ljmp_to_es_di
-
-       /* Call to arch_main.  Register INT19 as an exit path.  This
-        * call will never return.
-        */
-       movl    $exit_via_int19, %eax
-       pushl   $arch_main
-       pushl   %eax            /* Dummy return address */
-
-       /* Do the equivalent of ljmp *%es:di */
-ljmp_to_es_di: 
-       pushw   %es
-       pushw   %di
-       lret
+       /* Jump to loaded copy */
+       ljmp    $SYSSEG, $start_runtime
 
 /* This routine loads the system at address SYSSEG<<4, making sure no 64kB
  * boundaries are crossed. We try to load it as fast as possible, loading whole
@@ -181,7 +154,7 @@ ljmp_to_es_di:
  * in: es - starting address segment (normally SYSSEG)
  */
 read_it: 
-       movw    $1,sread                /* don't reload the prefix */
+       movw    $0,sread                /* load whole image including prefix */
        movw    %es,%ax
        testw   $0x0fff, %ax
 die:   jne     die                     /* es must be at 64kB boundary */
@@ -374,3 +347,29 @@ msg1end:
        .org 510, 0
        .word 0xAA55
 
+start_runtime:
+       /* Install .text16 and .data16 to top of base memory */
+       call    alloc_basemem
+       call    install_basemem
+
+       /* Install .text and .data to 2MB mark */
+       movl    $(2<<20), %edi
+       call    install_highmem
+
+       /* Jump to .text16 segment */
+       pushw   %ax
+       pushw   $1f
+       lret
+       .section ".text16", "awx", @progbits
+1:
+       call    init_gdt
+       pushl   $initialise
+       data32 call     prot_call
+       popl    %eax /* discard */
+       pushl   $main
+       data32 call     prot_call
+       popl    %eax /* discard */
+
+       /* Boot next device */
+       int $0x18
+
index 4329164..71a7f74 100644 (file)
@@ -15,14 +15,12 @@ SECTIONS {
      * addresses, but may have individual link addresses depending on
      * the memory model being used.
      *
-     * The linker symbols {prefix,decompress,text,data}_link_addr,
-     * load_addr, and _max_align may be specified explicitly.  If not
-     * specified, they will default to:
+     * The linker symbols {prefix,text}_link_addr, load_addr, and
+     * _max_align may be specified explicitly.  If not specified, they
+     * will default to:
      *
      *   _prefix_link_addr     = 0
-     *   _decompress_link_addr = 0
      *   _text_link_addr       = 0
-     *   _data_link_addr       = _text_link_addr + sizeof ( text sections )
      *   _load_addr            = 0
      *   _max_align            = 16
      * 
@@ -39,24 +37,6 @@ SECTIONS {
      * >16-byte alignment of physical addresses when -DKEEP_IT_REAL is
      * used (though virtual addresses will still be fully aligned).
      *
-     * The real-mode prefixes rely on _text_link_addr and
-     * _decompress_link_addr being 0, since they issue far calls into
-     * those sections, thus requiring that symbol_value ==
-     * symbol_offset therein.  Using the linker to calculate
-     * e.g. offset_setup16=setup16-_text will not work, since you then
-     * cannot use the reference from the prefix to setup16 to drag in
-     * setup16.o.  Life is hard.
-     *
-     * If librm is included, then it must go at offset 0 within the
-     * text section.  This is because librm is dual-usage: it is
-     * called from setup16 with %cs:0000 pointing to the start of the
-     * text section, and later it will be copied to base memory and
-     * called with %cs:0000 pointing to the start of librm.
-     *
-     * The decompressor is designed to decompress in-place.  After
-     * calling the decompressor, the image will look exactly the same
-     * as the uncompressed image; the compressed data and the
-     * decompressor code itself will have been overwritten.
      */
 
     /*
@@ -72,48 +52,66 @@ SECTIONS {
        _entry = .;
        *(.prefix)
        *(.prefix.*)
+       _eprefix_progbits = .;
     }
     
     _eprefix = .;
 
     /*
-     * The decompressor (may be absent)
+     * The 16-bit sections, if present
      */
 
-    _decompress_link_addr = DEFINED ( _decompress_link_addr ) ?
-                             _decompress_link_addr : 0;
-    . = _decompress_link_addr;
-    _decompress = .;
+    _text16_link_addr = 0;
+    . = _text16_link_addr;
+    _text16 = .;
+
+    .text16 : AT ( _text16_load_offset + __text16 ) {
+       __text16 = .;
+       *(.text16)
+       *(.text16.*)
+       _etext16_progbits = .;
+    } = 0x9090
+
+    _etext16 = .;
+
+    _data16_link_addr = 0;
+    . = _data16_link_addr;
+    _data16 = .;
 
-    .decompress : AT ( _decompress_load_offset + __decompress ) {
-           __decompress = .;
-           *(.decompress)
-           *(.decompress.*)
+    .rodata16 : AT ( _data16_load_offset + __rodata16 ) {
+       __rodata16 = .;
+       *(.rodata16)
+       *(.rodata16.*)
+    }
+    .data16 : AT ( _data16_load_offset + __data16 ) {
+       __data16 = .;
+       *(.data16)
+       *(.data16.*)
+       _edata16_progbits = .;
+    }
+    .bss16 : AT ( _data16_load_offset + __bss16 ) {
+       __bss16 = .;
+       _bss16 = .;
+       *(.bss16)
+       *(.bss16.*)
+       _ebss16 = .;
+    }
+    .stack16 : AT ( _data16_load_offset + __stack16 ) {
+       __stack16 = .;
+       *(.stack16)
+       *(.stack16.*)
     }
 
-    _edecompress = .;
+    _edata16 = .;
 
     /*
-     * The text sections
+     * The 32-bit sections
      */
 
     _text_link_addr = DEFINED ( _text_link_addr ) ? _text_link_addr : 0;
     . = _text_link_addr;
     _text = .;
 
-    .text16 : AT ( _text_load_offset + __text16 ) {
-       __text16 = .;
-
-       /* librm is a special case; it must go at the start of the
-        * text section if it is included.
-        */
-       _assert = ASSERT ( ( . == _text_link_addr ), "librm cannot go first" );
-       *(.librm)
-
-       *(.text16)
-       *(.text16.*)
-    } = 0x9090
-
     .text : AT ( _text_load_offset + __text ) {
        __text = .;
        *(.text)
@@ -122,29 +120,21 @@ SECTIONS {
 
     _etext = .;
 
-    /*
-     * The data sections
-     */
-
-    _data_link_addr = DEFINED ( _data_link_addr ) ? _data_link_addr : .;
-    . = _data_link_addr;
     _data = .;
 
-    .rodata : AT ( _data_load_offset + __rodata ) {
+    .rodata : AT ( _text_load_offset + __rodata ) {
        __rodata = .;
        *(.rodata)
        *(.rodata.*)
     }
-
-    .data : AT ( _data_load_offset + __data ) {
+    .data : AT ( _text_load_offset + __data ) {
        __data = .;
        *(.data)
        *(.data.*)
        *(SORT(.tbl.*))         /* Various tables.  See include/tables.h */
-       _progbits_end = .;
+       _etext_progbits = .;
     }
-
-    .bss : AT ( _data_load_offset + __bss ) {
+    .bss : AT ( _text_load_offset + __bss ) {
        __bss = .;
        _bss = .;
        *(.bss)
@@ -152,8 +142,7 @@ SECTIONS {
        *(COMMON)
        _ebss = .;
     }
-
-    .stack : AT ( _data_load_offset + __stack ) {
+    .stack : AT ( _text_load_offset + __stack ) {
        __stack = .;
        *(.stack)
        *(.stack.*)
@@ -188,25 +177,33 @@ SECTIONS {
     _prefix_load_offset            = ALIGN ( _max_align );
     _prefix_load_addr      = _prefix_link_addr + _prefix_load_offset;
     _prefix_size           = _eprefix - _prefix;
-    .                      = _prefix_load_addr + _prefix_size;
-
-    .                     -= _decompress_link_addr;
-    _decompress_load_offset = ALIGN ( _max_align );
-    _decompress_load_addr   = _decompress_link_addr + _decompress_load_offset;
-    _decompress_size       = _edecompress - _decompress;
-    .                      = _decompress_load_addr + _decompress_size;
+    _prefix_progbits_size   = _eprefix_progbits - _prefix;
+    .                      = _prefix_load_addr + _prefix_progbits_size;
+
+    .                     -= _text16_link_addr;
+    _text16_load_offset            = ALIGN ( _max_align );
+    _text16_load_addr      = _text16_link_addr + _text16_load_offset;
+    _text16_size           = _etext16 - _text16;
+    _text16_progbits_size   = _etext16_progbits - _text16;
+    .                      = _text16_load_addr + _text16_progbits_size;
+
+    .                     -= _data16_link_addr;
+    _data16_load_offset            = ALIGN ( _max_align );
+    _data16_load_addr      = _data16_link_addr + _data16_load_offset;
+    _data16_size           = _edata16 - _data16;
+    _data16_progbits_size   = _edata16_progbits - _data16;
+    .                      = _data16_load_addr + _data16_progbits_size;
 
     .                     -= _text_link_addr;
     _text_load_offset      = ALIGN ( _max_align );
     _text_load_addr        = _text_link_addr + _text_load_offset;
     _text_size             = _etext - _text;
-    .                      = _text_load_addr + _text_size;
+    _text_progbits_size            = _etext_progbits - _text;
+    .                      = _text_load_addr + _text_progbits_size;
+
+    .                      = ALIGN ( _max_align );
 
-    .                     -= _data_link_addr;
-    _data_load_offset      = ALIGN ( _max_align );
-    _data_load_addr        = _data_link_addr + _data_load_offset;
-    _data_size             = _edata - _data;
-    .                      = _data_load_addr + _data_size;
+    _load_size             = . - _load_addr;
 
     /*
      * Alignment checks.  ALIGN() can only operate on the location
@@ -218,34 +215,20 @@ SECTIONS {
     _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
                       "_prefix is badly aligned" );
 
-    . = _decompress_load_addr - _prefix_link_addr;
+    . = _text16_load_addr - _text16_link_addr;
     _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
-                      "_decompress is badly aligned" );
+                      "_text16 is badly aligned" );
 
-    . = _text_load_addr - _text_link_addr;
+    . = _data16_load_addr - _data16_link_addr;
     _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
-                      "_text is badly aligned" );
+                      "_data16 is badly aligned" );
 
-    . = _data_load_addr - _data_link_addr;
+    . = _text_load_addr - _text_link_addr;
     _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
-                      "_data is badly aligned" );
-
-    /*
-     * setup16 needs to know this when KEEP_IT_REAL is used.  There
-     * are no harmful side-effects of calculating it all the time.
-     */
-    _text_load_size_pgh = ( _data_load_addr - _text_load_addr ) / 16 ;
+                      "_text is badly aligned" );
 
     /*
-     * Useful-to-know values.
+     * Values calculated to save code from doing it
      */
-
-    /* Size of the decompressed runtime image */
-    _runtime_size = _edata - _text;
-    /* Size of the initialised-contents portion of the runtime image */
-    _runtime_progbits_size = _progbits_end - _text;
-    /* Size of the (non-compressed) binary file */
-    _file_size = _prefix_size + _runtime_progbits_size;
-    /* Size of the non-compressed portion of the compressed binary file */
-    _zfile_noncompressed_size = _prefix_size + _decompress_size;
+    _load_size_pgh     = ( _load_size / 16 );
 }
index 9d55cff..2fbffb9 100644 (file)
@@ -8,98 +8,6 @@
 /* Drag in local definitions */
 #include "librm.h"
 
-/* Drag in FREE_BASEMEM_HEADER_SIZE */
-#include "basemem.h"
-
-/****************************************************************************
- * This file defines librm: a block of code that is designed to reside
- * permanently in base memory and provide the interface between
- * real-mode code running in base memory and protected-mode code
- * running in high memory.  It provides the following functions:
- *
- *   real_to_prot &    switch between real and protected mode 
- *   prot_to_real      while running in base memory, preserving 
- *                     all non-segment registers
- *
- *   real_call         issue a call to a real-mode routine from
- *                     protected-mode code running in high memory
- *
- *   prot_call         issue a call to a protected-mode routine from
- *                     real-mode code running in base memory
- *
- * librm requires the following functions to be present in the
- * protected-mode code:
- *
- *   _phys_to_virt     Switch from physical to virtual addressing.  This
- *                     routine must be position-independent and must
- *                     *not* assume that it is genuinely running with
- *                     flat physical addresses
- *
- *   _virt_to_phys     Switch from virtual to physical addresses.
- *
- *   gateA20_set       Enable the A20 line to permit access to the odd
- *                     megabytes of RAM.  (This function will be called
- *                     with virtual addresses set up).
- *
- * librm needs to be linked against the protected-mode binary so that
- * it can import the symbols for these functions.
- *
- * librm requires that the protected-mode code set up the following
- * segments:
- *
- *   PHYSICAL_CS       32-bit pmode code and data segments with flat
- *   PHYSICAL_DS       physical addresses.
- *
- *   VIRTUAL_CS                32-bit pmode code segment with virtual
- *                     addressing, such that a protected-mode routine
- *                     can always be found at $VIRTUAL_CS:routine.
- *
- * These segments must be set as #define constants when compiling
- * librm.  Edit librm.h to change the values.
- *
- * librm does not know the location of the code executing in high
- * memory.  It relies on the code running in high memory setting up a
- * GDT such that the high-memory code is accessible at virtual
- * addresses fixed at compile-time.
- *
- * librm symbols are exported as absolute values and represent offsets
- * into librm.  This is the most useful form of the symbols, since
- * librm is basically a binary blob that you place somewhere in base
- * memory.
- *
- * librm.h provides convenient ways to use these symbols: you simply
- * set the pointer ( char * ) installed_librm to point to wherever
- * librm is installed, and can then use e.g. inst_rm_stack just like
- * any other variable and have it automatically refer to the value of
- * rm_stack in the installed librm.  Macro trickery makes this
- * completely transparent, and the resulting assembler code is
- * amazingly efficient.
- *
- * Note that librm must be called in genuine real mode, not 16:16 or
- * 16:32 protected mode.  It makes the assumption that
- * physical_address = 16*segment+offset, and also that it can use
- * OFFSET(%bp) to access stack variables.  The former assumption will
- * break in either protected mode, the latter may break in 16:32
- * protected mode.
- ****************************************************************************
- */
-
-/*
- * Default values for pmode segments if not defined
- */
-#ifndef PHYSICAL_CS
-#warning "Assuming PHYSICAL_CS = 0x08"
-#define PHYSICAL_CS 0x08
-#endif
-#ifndef PHYSICAL_DS
-#warning "Assuming PHYSICAL_DS = 0x10"
-#define PHYSICAL_DS 0x10
-#endif
-#ifndef VIRTUAL_CS
-#warning "Assuming VIRTUAL_CS = 0x18"
-#define VIRTUAL_CS 0x18
-#endif
-
 /* For switches to/from protected mode */
 #define CR0_PE 1
 
 #define SIZEOF_REAL_MODE_REGS  ( SIZEOF_I386_SEG_REGS + SIZEOF_I386_REGS )
 #define SIZEOF_I386_FLAGS      4
 #define SIZEOF_I386_ALL_REGS   ( SIZEOF_REAL_MODE_REGS + SIZEOF_I386_FLAGS )
-#define SIZEOF_SEGOFF_T                4
-#define SIZEOF_REAL_CALL_PARAMS ( SIZEOF_REAL_MODE_REGS + 2 * SIZEOF_SEGOFF_T )
        
-       .text
        .arch i386
-       .section ".librm", "awx", @progbits
-       .align 16
-
-       .globl  librm
-librm:
-       
-_librm_start:
-
-#undef OFFSET
-#define OFFSET(sym) ( sym - _librm_start )
-
-#undef EXPORT
-#define EXPORT(sym) \
-       .globl sym ; \
-       .globl _ ## sym ;  \
-       .equ _ ## sym, OFFSET(sym) ; \
-       sym
+       .section ".text16", "awx", @progbits
 
 /****************************************************************************
- * Note that the first sizeof(struct free_base_memory_header) bytes of
- * librm will get vapourised by free_base_memory().  Since we need
- * librm to continue working even when this happens, we put some
- * padding here.
+ * Global descriptor table
  *
- * We must also ensure that the total size of librm is <1kB, otherwise
- * free_base_memory() will stomp somewhere in the middle of us as
- * well...
- ****************************************************************************
- */
-       .fill FREE_BASEMEM_HEADER_SIZE, 1, 0
-
-/****************************************************************************
- * Record of the current physical location of the installed copy.
- * Used by prot_call in order to return via the current installed copy
- * even if Etherboot has been relocated during the protected-mode
- * call.
- ****************************************************************************
- */
-EXPORT(librm_base):
-librm_base:    .long 0
-               
-/****************************************************************************
- * GDT for initial transition to protected mode
+ * Call init_gdt to set up the GDT before attempting to use any
+ * protected-mode code.
  *
- * PHYSICAL_CS and PHYSICAL_DS are defined in an external header file.
- * We use only those selectors, and construct our GDT to match the
- * selector values we're asked to use.  Use PHYSICAL_CS=0x08 and
- * PHYSICAL_DS=0x10 to minimise the space occupied by this GDT.
- *
- * Note: pm_gdt is also used to store the location of the
- * protected-mode GDT as recorded on entry to prot_to_real.
- ****************************************************************************
- */
-       .align 16
-pm_gdt:
-pm_gdt_limit:          .word pm_gdt_length - 1
-pm_gdt_addr:           .long 0
-                       .word 0 /* padding */
-       
-       .org    pm_gdt + PHYSICAL_CS
-pm_gdt_pm_cs:
-       /* 32 bit protected mode code segment, physical addresses */
-       .word   0xffff, 0
-       .byte   0, 0x9f, 0xcf, 0
-       
-       .org    pm_gdt + PHYSICAL_DS
-pm_gdt_pm_ds:
-       /* 32 bit protected mode data segment, physical addresses */
-       .word   0xffff,0
-       .byte   0,0x93,0xcf,0
-       
-pm_gdt_end:            
-       .equ    pm_gdt_length, pm_gdt_end - pm_gdt
-
-/****************************************************************************
- * GDT for transition to real mode
- *
- * This is used primarily to set 64kB segment limits.  Define
- * FLATTEN_REAL_MODE if you want to use so-called "flat real mode"
- * with 4GB limits instead.  The base address of each of the segments
- * will be adjusted at run-time.
+ * Define FLATTEN_REAL_MODE if you want to use so-called "flat real
+ * mode" with 4GB limits instead.
  *
  * NOTE: This must be located before prot_to_real, otherwise gas
  * throws a "can't handle non absolute segment in `ljmp'" error due to
- * not knowing the value of RM_CS when the ljmp is encountered.
+ * not knowing the value of REAL_CS when the ljmp is encountered.
  *
- * Note also that putting ".word rm_gdt_end - rm_gdt - 1" directly
- * into rm_gdt_limit, rather than going via rm_gdt_length, will also
- * produce the "non absolute segment" error.  This is most probably a
- * bug in gas.
+ * Note also that putting ".word gdt_end - gdt - 1" directly into
+ * gdt_limit, rather than going via gdt_length, will also produce the
+ * "non absolute segment" error.  This is most probably a bug in gas.
  ****************************************************************************
  */
        
@@ -212,252 +45,242 @@ pm_gdt_end:
 #else
 #define RM_LIMIT_16_19__AVL__SIZE__GRANULARITY 0x00
 #endif
+       .section ".text16"
        .align 16
-rm_gdt:
-rm_gdt_limit:          .word rm_gdt_length - 1
-rm_gdt_base:           .long 0
+gdt:
+gdt_limit:             .word gdt_length - 1
+gdt_base:              .long 0
                        .word 0 /* padding */
+
+       .org    gdt + VIRTUAL_CS, 0
+virtual_cs:    /* 32 bit protected mode code segment, virtual addresses */
+       .word   0xffff, 0
+       .byte   0, 0x9f, 0xcf, 0
+
+       .org    gdt + VIRTUAL_DS, 0
+virtual_ds:    /* 32 bit protected mode data segment, virtual addresses */
+       .word   0xffff, 0
+       .byte   0, 0x93, 0xcf, 0
        
-rm_gdt_rm_cs:  /* 16 bit real mode code segment */
-       .equ    RM_CS, rm_gdt_rm_cs - rm_gdt
-       .word   0xffff,(0&0xffff)
-       .byte   (0>>16),0x9b,RM_LIMIT_16_19__AVL__SIZE__GRANULARITY,(0>>24)
-       
-rm_gdt_rm_ds:  /* 16 bit real mode data segment */
-       .equ    RM_DS, rm_gdt_rm_ds - rm_gdt
-       .word   0xffff,(0&0xffff)
-       .byte   (0>>16),0x93,RM_LIMIT_16_19__AVL__SIZE__GRANULARITY,(0>>24)
+       .org    gdt + PHYSICAL_CS, 0
+physical_cs:   /* 32 bit protected mode code segment, physical addresses */
+       .word   0xffff, 0
+       .byte   0, 0x9f, 0xcf, 0
+
+       .org    gdt + PHYSICAL_DS, 0
+physical_ds:   /* 32 bit protected mode data segment, physical addresses */
+       .word   0xffff, 0
+       .byte   0, 0x93, 0xcf, 0        
+
+       .org    gdt + REAL_CS, 0
+real_cs:       /* 16 bit real mode code segment */
+       .word   0xffff, 0
+       .byte   0, 0x9b, RM_LIMIT_16_19__AVL__SIZE__GRANULARITY, 0
+
+       .org    gdt + REAL_DS   
+real_ds:       /* 16 bit real mode data segment */
+       .word   0xffff, 0
+       .byte   0, 0x93, RM_LIMIT_16_19__AVL__SIZE__GRANULARITY, 0
        
-rm_gdt_end:
-       .equ    rm_gdt_length, rm_gdt_end - rm_gdt
+gdt_end:
+       .equ    gdt_length, gdt_end - gdt
 
 /****************************************************************************
- * real_to_prot (real-mode far call)
- *
- * Switch from 16-bit real-mode to 32-bit protected mode with flat
- * physical addresses.  %esp is restored from the saved pm_esp.  All
- * segment registers are set to flat physical-mode values.  All other
- * registers are preserved.  Interrupts are disabled.
+ * init_gdt (real-mode near call, 16-bit real-mode return address)
  *
- * Note that this routine can be called *without* having first set up
- * a stored pm_esp or stored GDT.  If you do this, real_to_prot will
- * return with a temporary stack that is only *FOUR BYTES* in size.
- * This is just enough to enable you to do a "call 1f; popl %ebp"
- * sequence in order to find out your physical address and then load a
- * proper 32-bit protected-mode stack pointer.  Do *NOT* use more than
- * four bytes since this will overwrite code in librm!
+ * Initialise the GDT ready for transitions to protected mode.
  *
- * Parameters: none
+ * Parameters: 
+ *   %edi : Physical base of protected-mode code
  ****************************************************************************
  */
+       .section ".text16"
+       .code16
+       .globl init_gdt
+init_gdt:
+       /* Preserve registers */
+       pushl   %eax
+       pushw   %bx
 
-       .code16         
-EXPORT(real_to_prot):
-       /* Disable interrupts */
-       cli
+       /* Record virt_offset */
+       movl    %edi, %cs:virt_offset_rm_copy
 
-       /* Set %ds = %cs, for easier access to variables */
-       pushw   %cs
-       popw    %ds
-       
-       /* Preserve registers */
-       movl    %eax, %ds:OFFSET(save_eax)
-       movl    %ebx, %ds:OFFSET(save_ebx)
+       /* Set virtual_cs and virtual_ds base */
+       movl    %edi, %eax
+       movw    $virtual_cs, %bx
+       call    set_seg_base
 
-       /* Extract real-mode far return address from stack */
-       popl    %ds:OFFSET(save_retaddr)
+       /* Set real_cs and real_ds base, and GDT base */
+       movw    $real_cs, %bx
+       xorl    %eax, %eax
+       movw    %cs, %ax
+       shll    $4, %eax
+       call    set_seg_base
+       addl    $gdt, %eax
+       movl    %eax, %cs:gdt_base
 
-       /* Record real-mode stack pointer */
-       movw    %sp, %ds:OFFSET(rm_sp)
-       pushw   %ss
-       popw    %ds:OFFSET(rm_ss)
-
-       /* Physical base address of librm to %ebx */
-       xorl    %ebx, %ebx
-       movw    %cs, %bx
-       shll    $4, %ebx
-
-       /* Record physical base address of librm */
-       movl    %ebx, %ds:OFFSET(librm_base)
-               
-       /* Check base address of stored protected-mode GDT.  If it's
-        * zero, set it up to use our internal GDT (with physical
-        * segments only).
-        */
-       movl    %ds:OFFSET(pm_gdt_addr), %eax
-       testl   %eax, %eax
-       jnz     1f
-       /* Use internal GDT */
-       movl    %ebx, %eax
-       addl    $OFFSET(pm_gdt), %eax
-       movl    %eax, %ds:OFFSET(pm_gdt_addr)
-1:     
-       
-       /* Set up protected-mode continuation address on real-mode stack */
-       pushl   $PHYSICAL_CS
-       movl    %ebx, %eax
-       addl    $OFFSET(1f), %eax
+       /* Restore registers */
+       popw    %bx
+       popl    %eax
+       ret
+
+       .section ".text16"
+       .code16
+set_seg_base:
        pushl   %eax
+       movw    %ax, %cs:(0+2)(%bx)
+       movw    %ax, %cs:(8+2)(%bx)
+       shrl    $16, %eax
+       movb    %al, %cs:(0+4)(%bx)
+       movb    %al, %cs:(8+4)(%bx)
+       movb    %ah, %cs:(0+7)(%bx)
+       movb    %ah, %cs:(8+7)(%bx)
+       popl    %eax
+       ret
        
-       /* Restore protected-mode GDT */
-       data32 lgdt     %ds:OFFSET(pm_gdt)
+/****************************************************************************
+ * real_to_prot (real-mode near call, 32-bit virtual return address)
+ *
+ * Switch from 16-bit real-mode to 32-bit protected mode with virtual
+ * addresses.  The real-mode %ss:sp is stored in rm_ss and rm_sp, and
+ * the protected-mode %esp is restored from the saved pm_esp.
+ * Interrupts are disabled.  All other registers may be destroyed.
+ *
+ * The return address for this function should be a 32-bit virtual
+ * address.
+ *
+ * Parameters: 
+ *   %ecx : number of bytes to move from RM stack to PM stack
+ *
+ ****************************************************************************
+ */
+       .section ".text16"
+       .code16
+real_to_prot:
+       /* Protected-mode return address => %ebx */
+       popl    %ebx
+
+       /* Real-mode %cs => %dx, %ss => %bp */
+       movw    %cs, %dx
+       movw    %ss, %bp
+
+       /* virt_offset => %edi */
+       movl    %cs:virt_offset_rm_copy, %edi
 
        /* Switch to protected mode */
+       cli
+       data32 lgdt     %cs:gdt
        movl    %cr0, %eax
        orb     $CR0_PE, %al
        movl    %eax, %cr0
-
-       /* Flush prefetch queue and reload %cs:eip */
-       data32 lret
-1:     .code32
-
-       /* Set up protected-mode stack and data segments */
-       movw    $PHYSICAL_DS, %ax
+       data32 ljmp     $VIRTUAL_CS, $1f
+       .section ".text"
+       .code32
+1:
+       /* Set up protected-mode data segments */
+       movw    $VIRTUAL_DS, %ax
        movw    %ax, %ds
        movw    %ax, %es
        movw    %ax, %fs
        movw    %ax, %gs
+
+       /* Record virt_offset */
+       movl    %edi, virt_offset
+
+       /* Move data from RM stack to PM stack and set up PM stack */
+       movzwl  %sp, %esi
+       movl    pm_esp, %esp
+       subl    %ecx, %esp
+       movl    %esp, %edi
+       rep ss movsb
        movw    %ax, %ss
 
-       /* Switch to saved protected-mode stack.  Note that there may
-        * not actually *be* a saved protected-mode stack.
-        */
-       movl    OFFSET(pm_esp)(%ebx), %esp
-       testl   %esp, %esp
-       jnz     1f
-       /* No stack - use save_retaddr as a 4-byte temporary stack */
-       leal    OFFSET(save_retaddr+4)(%ebx), %esp
-1:     
-       
-       /* Convert real-mode far return address to physical address
-        * and place on stack
-        */
-       pushl   OFFSET(save_retaddr)(%ebx)
-       xorl    %eax, %eax
-       xchgw   2(%esp), %ax
-       shll    $4, %eax
-       addl    %eax, 0(%esp)
+       /* Record real-mode %cs and %ss:sp */
+       movw    %dx, rm_cs
+       movw    %bp, rm_ss
+       movw    %si, rm_sp
 
-       /* Restore registers and return */
-       movl    OFFSET(save_eax)(%ebx), %eax
-       movl    OFFSET(save_ebx)(%ebx), %ebx
-       ret
+       /* Return to virtual address */
+       jmp     *%ebx
 
 /****************************************************************************
- * prot_to_real (protected-mode near call, physical addresses)
+ * prot_to_real (protected-mode near call, 32-bit real-mode return address)
  *
- * Switch from 32-bit protected mode with flat physical addresses to
- * 16-bit real mode.  %ss:sp is restored from the saved rm_ss and
- * rm_sp.  %cs is set such that %cs:0000 is the start of librm.  All
- * other segment registers are set to %ss.  All other registers are
- * preserved.  Interrupts are *not* enabled, since we want to be able
- * to use this routine inside an ISR.
+ * Switch from 32-bit protected mode with virtual addresses to 16-bit
+ * real mode.  The protected-mode %esp is stored in pm_esp and the
+ * real-mode %ss:sp is restored from the saved rm_ss and rm_sp.  All
+ * real-mode data segment registers are set equal to %ss.  Interrupts
+ * are *not* enabled, since we want to be able to use prot_to_real in
+ * an ISR.  All other registers may be destroyed.
  *
- * Note that since %cs:0000 points to the start of librm on exit, it
- * follows that the code calling prot_to_real must be located within
- * 64kB of the start of librm.
+ * The return address for this function should be a 32-bit (sic)
+ * real-mode offset within .code16.
+ *
+ * Parameters: 
+ *   %ecx : number of bytes to move from PM stack to RM stack
  *
- * Parameters: none
  ****************************************************************************
  */
-
+       .section ".text"
        .code32
-EXPORT(prot_to_real):
-       /* Calculate physical base address of librm in %ebx, preserve
-        * original %eax and %ebx in save_eax and save_ebx
-        */
-       pushl   %ebx
-       call    1f
-1:     popl    %ebx
-       subl    $OFFSET(1b), %ebx
-       popl    OFFSET(save_ebx)(%ebx)
-       movl    %eax, OFFSET(save_eax)(%ebx)
-
-       /* Record physical base address of librm */
-       movl    %ebx, OFFSET(librm_base)(%ebx)
-
-       /* Extract return address from the stack, convert to offset
-        * within librm and save in save_retaddr
-        */
-       popl    %eax
-       subl    %ebx, %eax
-       movl    %eax, OFFSET(save_retaddr)(%ebx)
-
-       /* Record protected-mode stack pointer */
-       movl    %esp, OFFSET(pm_esp)(%ebx)
-
-       /* Record protected-mode GDT */
-       sgdt    OFFSET(pm_gdt)(%ebx)
-
-       /* Set up real-mode GDT */
-       leal    OFFSET(rm_gdt)(%ebx), %eax
-       movl    %eax, OFFSET(rm_gdt_base)(%ebx)
-       movl    %ebx, %eax
-       rorl    $16, %eax
-       movw    %bx, OFFSET(rm_gdt_rm_cs+2)(%ebx)
-       movb    %al, OFFSET(rm_gdt_rm_cs+4)(%ebx)
-       movw    %bx, OFFSET(rm_gdt_rm_ds+2)(%ebx)
-       movb    %al, OFFSET(rm_gdt_rm_ds+4)(%ebx)
+prot_to_real:
+       /* Real-mode return address => %ebx */
+       popl    %ebx
        
-       /* Switch to real-mode GDT and reload segment registers to get
-        * 64kB limits.  Stack is invalidated by this process.
-        */
-       lgdt    OFFSET(rm_gdt)(%ebx)
-       ljmp    $RM_CS, $1f
-1:     .code16
-       movw    $RM_DS, %ax
+       /* Real-mode %ss:sp => %ebp:edx */
+       movzwl  rm_ss, %ebp
+       movzwl  rm_sp, %edx
+       subl    %ecx, %edx
+       
+       /* Copy data from PM stack to RM stack */
+       movl    %ebp, %eax
+       shll    $4, %eax
+       leal    (%eax,%edx), %edi
+       subl    virt_offset, %edi
+       movl    %esp, %esi
+       rep movsb
+       
+       /* Record protected-mode %esp */
+       movl    %esi, pm_esp
+
+       /* Real-mode %cs => %di */
+       movw    rm_cs, %di
+
+       /* Load real-mode segment limits */
+       movw    $REAL_DS, %ax
        movw    %ax, %ds
        movw    %ax, %es
        movw    %ax, %fs
        movw    %ax, %gs
        movw    %ax, %ss
-
-       /* Calculate real-mode code segment in %ax and store in ljmp
-        * instruction
-        */
-       movl    %ebx, %eax
-       shrl    $4, %eax
-       movw    %ax, OFFSET(p2r_ljmp) + 3
-
+       ljmp    $REAL_CS, $1f
+       .section ".text16"
+       .code16
+1:
+       /* Set up real-mode ljmp instruction */
+       movw    %di, %ds:(p2r_ljmp + 3)
+       
        /* Switch to real mode */
-       movl    %cr0, %ebx
-       andb    $0!CR0_PE, %bl
-       movl    %ebx, %cr0
-
-       /* Intersegment jump to flush prefetch queue and reload
-        * %cs:eip.  The segment gets filled in by the above code.  We
-        * can't just use lret to achieve this, because we have no
-        * stack at the moment.
-        */
-p2r_ljmp:
-       ljmp    $0, $OFFSET(1f)
-1:     
-
-       /* Set %ds to point to code segment for easier data access */
-       movw    %ax, %ds
-                       
-       /* Restore registers */
-       movl    OFFSET(save_eax), %eax
-       movl    OFFSET(save_ebx), %ebx
-
-       /* Set up real-mode data segments and stack */
-       movw    OFFSET(rm_ss), %ss
-       movw    OFFSET(rm_sp), %sp
-       pushw   %ss
-       pushw   %ss
-       pushw   %ss
-       pushw   %ss
-       popw    %ds
-       popw    %es
-       popw    %fs
-       popw    %gs
-
-       /* Set up return address on stack and return */
-       pushw   %cs:OFFSET(save_retaddr)
-       ret
+       movl    %cr0, %eax
+       andb    $0!CR0_PE, %al
+       movl    %eax, %cr0
 
+p2r_ljmp:
+       ljmp    $0, $1f /* Segment is filled in by above code */
+1:
+       /* Set up real-mode stack and data segments, and stack pointer */
+       movw    %bp, %ds
+       movw    %bp, %es
+       movw    %bp, %fs
+       movw    %bp, %gs
+       movw    %bp, %ss
+       movw    %dx, %sp
+
+       /* Return to real-mode address */
+       jmp     *%bx
+       
 /****************************************************************************
- * prot_call (real-mode far call)
+ * prot_call (real-mode near call, 32-bit real-mode return address)
  *
  * Call a specific C function in the protected-mode code.  The
  * prototype of the C function must be
@@ -469,30 +292,12 @@ p2r_ljmp:
  * function explicitly overwrites values in ix86.  Interrupt status
  * will also be preserved.  Gate A20 will be enabled.
  *
- * The protected-mode code may install librm to a new location.  If it
- * does so, it must update librm_base in *this* copy of librm to point
- * to the new physical location.  prot_call will then return via the
- * newly installed copy.
- *
- * Note that when Etherboot performs its initial relocation, "*this*"
- * copy in the above paragraph will refer to the "master" copy, since
- * that is the initial installed copy.  Etherboot will return to
- * prot_call using a virtual address, so will return to the master
- * copy in high memory (rather than the original copy in base memory).
- * The master copy in high memory will have the physical address of
- * the newly installed copy in librm_base, since install_librm()
- * writes it there.  Thus, Etherboot's initialise() function will
- * return to the master copy of prot_call(), which will then jump to
- * the installed copy.
- *
- * It works, trust me.
- *
  * Parameters:
  *   function : virtual address of protected-mode function to call
  *
  * Example usage:
  *     pushl   $pxe_api_call
- *     lcall   $LIBRM_SEGMENT, $prot_call
+ *     call    prot_call
  *     addw    $4, %sp
  * to call in to the C function
  *      void pxe_api_call ( struct i386_all_regs *ix86 );
@@ -502,10 +307,13 @@ p2r_ljmp:
 #define PC_OFFSET_IX86 ( 0 )
 #define PC_OFFSET_RETADDR ( PC_OFFSET_IX86 + SIZEOF_I386_ALL_REGS )
 #define PC_OFFSET_FUNCTION ( PC_OFFSET_RETADDR + 4 )
-       
+#define PC_OFFSET_END ( PC_OFFSET_FUNCTION + 4 )
+
+       .section ".text16"
        .code16
-EXPORT(prot_call):
-       /* Preserve registers and flags on RM stack */
+       .globl prot_call
+prot_call:
+       /* Preserve registers and flags on external RM stack */
        pushfl
        pushal
        pushw   %gs
@@ -513,101 +321,46 @@ EXPORT(prot_call):
        pushw   %es
        pushw   %ds
        pushw   %ss
-       pushw   %cs     
-       
-       /* Record RM stack pointer */
-       xorl    %ebp, %ebp
-       movw    %sp, %bp
-       
-       /* Physical address of RM stack pointer to %esi */
-       xorl    %esi, %esi
-       pushw   %ss
-       popw    %si
-       shll    $4, %esi
-       addl    %ebp, %esi
-
-       /* Address of pmode function to %ebx */
-       movl    %ss:(PC_OFFSET_FUNCTION)(%bp), %ebx
-       
-       /* Switch to protected mode */
        pushw   %cs
-       call    real_to_prot
-       .code32
 
-       /* Copy ix86 from RM stack to PM stack */
-       movl    $SIZEOF_I386_ALL_REGS, %ecx
-       subl    %ecx, %esp
-       movl    %esp, %edi
-       pushl   %esi
+       /* For sanity's sake, clear the direction flag as soon as possible */
        cld
-       rep movsb
-       popl    %edi            /* %edi = phys addr of RM copy of ix86 */
-       
-       /* Switch to virtual addresses. */
-       call    1f
-       jmp     2f
-1:     ljmp    $VIRTUAL_CS, $_phys_to_virt
-2:     
 
-       /* Enable A20 line */
-       pushal
-       lcall   $VIRTUAL_CS, $gateA20_set
-       popl    %eax    /* discard */
-       popal
+       /* Switch to protected mode and move register dump to PM stack */
+       movl    $PC_OFFSET_END, %ecx
+       pushl   $1f
+       jmp     real_to_prot
+       .section ".text"
+       .code32
+1:
+       /* Set up environment expected by C code */
+       call    gateA20_set
 
-       /* Push &ix86 on the stack, and call function */
+       /* Call function */
        pushl   %esp
-       call    *%ebx
+       call    *(PC_OFFSET_FUNCTION+4)(%esp)
        popl    %eax /* discard */
 
-       /* Switch to physical addresses, discard PM register store */
-       lcall   $VIRTUAL_CS, $_virt_to_phys
-       popl    %eax /* discard */
-
-       /* Copy ix86 from PM stack to RM stack, and remove ix86
-        * from PM stack.  (%edi still contains physical address of
-        * ix86 on RM stack from earlier, since C code preserves
-        * %edi).
-        */
-       movl    %esp, %esi
-       movl    $SIZEOF_I386_ALL_REGS, %ecx
-       cld
-       rep movsb
-       movl    %esi, %esp      /* remove ix86 from PM stack */
-
-       /* Obtain physical base address of installed copy of librm in
-        * %ebx.  (It's possible that this *isn't* the physical base
-        * address of the copy we're currently executing in, because
-        * the protected-mode call could have moved librm.  If it does
-        * so, it must update librm_base in our copy to reflect the
-        * new location.
-        */
-       call    1f
-1:     popl    %ebp
-       movl    (librm_base-1b)(%ebp), %ebx
-       
-       /* Jump to running in installed copy of librm */
-       addl    $OFFSET(1f), %ebx
-       jmp     *%ebx
-1:     
-       
-       /* Switch to real mode */
-       call    prot_to_real
+       /* Switch to real mode and move register dump back to RM stack */
+       movl    $PC_OFFSET_END, %ecx
+       pushl   $1f
+       jmp     prot_to_real
+       .section ".text16"
        .code16
-
-       /* Restore registers and flags, and return */
-       popw    %ax     /* skip %cs */
-       popw    %ax     /* skip %ss */
+1:     
+       /* Restore registers and flags and return */
+       popw    %ax     /* skip %cs - it is already set */
+       popw    %ax     /* skip %ss - it is already set */
        popw    %ds
        popw    %es
        popw    %fs
        popw    %gs
        popal
        popfl
-       lret
+       ret
 
 /****************************************************************************
- * real_call (protected-mode near call, virtual addresses)
+ * real_call (protected-mode near call, 32-bit virtual return address)
  *
  * Call a real-mode function from protected-mode code.
  *
@@ -625,80 +378,58 @@ EXPORT(prot_call):
  * and examples.
  *
  * Parameters:
- *   far pointer to real-mode function to call
+ *   (32-bit) near pointer to real-mode function to call
  *
  * Returns: none
  ****************************************************************************
  */
 
 #define RC_OFFSET_PRESERVE_REGS ( 0 )
-#define RC_OFFSET_RETADDR ( RC_OFFSET_PRESERVE_REGS + 8 )
-#define RC_OFFSET_RM_FUNCTION ( RC_OFFSET_RETADDR + 4 )
-       
-       .code32
-EXPORT(real_call):
-       /* Preserve registers */
-       pushl   %ebp
-       pushl   %eax
-       
-       /* Switch to physical addresses */
-       lcall   $VIRTUAL_CS, $_virt_to_phys
-       addl    $4, %esp
-
-       /* Extract real-mode function address and store in ljmp instruction */
-       call    1f
-1:     popl    %ebp
-       movl    RC_OFFSET_RM_FUNCTION(%esp), %eax
-       movl    %eax, (rc_ljmp + 1 - 1b)(%ebp)
+#define RC_OFFSET_RETADDR ( RC_OFFSET_PRESERVE_REGS + SIZEOF_I386_REGS )
+#define RC_OFFSET_FUNCTION ( RC_OFFSET_RETADDR + 4 )
+#define RC_OFFSET_END ( RC_OFFSET_FUNCTION + 4 )
 
-       /* Restore registers */
-       popl    %eax
-       popl    %ebp
+       .section ".text"
+       .code32
+       .globl real_call
+real_call:
+       /* Create register dump on PM stack */
+       pushal
 
-       /* Switch to real mode, preserving non-segment registers */
-       call    prot_to_real
+       /* Switch to real mode and move register dump to RM stack */
+       movl    $RC_OFFSET_END, %ecx
+       pushl   $1f
+       jmp     prot_to_real
+       .section ".text16"
        .code16
+1:
+       /* Construct call to real-mode function */
+       movw    %sp, %bp
+       movw    RC_OFFSET_FUNCTION(%bp), %ax
+       movw    %ax, %cs:rc_function
 
-       /* Far call to real-mode routine */
-       pushw   %cs
-       call    rc_ljmp
-       jmp     2f
-rc_ljmp:       
-       ljmp    $0, $0  /* address filled in by above code */
-2:     
-       
-       /* Switch to protected mode */
-       pushw   %cs
-       call    real_to_prot
-       .code32
+       /* Call real-mode function */
+       popal
+       call    *%cs:rc_function
+       pushal
 
-       /* Switch to virtual addresses */
-       call    1f
-       jmp     2f
-1:     ljmp    $VIRTUAL_CS, $_phys_to_virt
-2:     
+       /* Switch to protected mode and move register dump back to PM stack */
+       movl    $RC_OFFSET_END, %ecx
+       pushl   $1f
+       jmp     real_to_prot
+       .section ".text"
+       .code32
+1:
+       /* Set up environment expected by C code */
+       call    gateA20_set
 
-       /* Enable A20 line */
-       pushal
-       lcall   $VIRTUAL_CS, $gateA20_set
-       popl    %eax    /* discard */
+       /* Restore registers and return */
        popal
-
-       /* Return */
        ret
-       
-/****************************************************************************
- * Relocation lock counter
- *
- * librm may be moved in base memory only when this counter is zero.
- * The counter gets incremented whenever a reference to librm is
- * generated (e.g. a real_call is made, resulting in a return address
- * pointing to librm being placed on the stack), and decremented when
- * the reference goes out of scope (e.g. the real_call returns).
- ****************************************************************************
- */
-EXPORT(librm_ref_count):       .byte 0
 
+       .section ".text16"
+rc_function:   .word 0
+       
 /****************************************************************************
  * Stored real-mode and protected-mode stack pointers
  *
@@ -734,25 +465,18 @@ EXPORT(librm_ref_count):  .byte 0
  ****************************************************************************
  */
 
-EXPORT(rm_stack):      /* comprises rm_ss and rm_sp */
-rm_sp:         .word 0
-rm_ss:         .word 0
-
-EXPORT(pm_stack):
-pm_esp:                .long 0
-
-/****************************************************************************
- * Temporary variables
- ****************************************************************************
- */
-save_eax:      .long 0
-save_ebx:      .long 0
-save_retaddr:  .long 0
-       
-/****************************************************************************
- * End of librm
- ****************************************************************************
- */
-_librm_end:
-       .globl _librm_size
-       .equ _librm_size, _librm_end - _librm_start
+       .section ".data"
+       .globl rm_sp
+rm_sp: .word 0
+       .globl rm_ss
+rm_ss: .word 0
+       .globl rm_cs
+rm_cs: .word 0
+       .globl pm_esp
+pm_esp:        .long _estack
+
+       .section ".text16"
+virt_offset_rm_copy:   .long 0
+       .section ".data"
+       .globl virt_offset
+virt_offset:           .long 0 
index 6780fdc..d0ff4ea 100644 (file)
@@ -9,44 +9,28 @@
 /* Build a null object under -DKEEP_IT_REAL */
 #else
 
-#include "stdint.h"
-#include "stddef.h"
-#include "string.h"
-#include "basemem.h"
-#include "relocate.h"
-#include <gpxe/init.h>
-#include "librm.h"
+#include <stdint.h>
+#include <librm.h>
 
 /*
  * This file provides functions for managing librm.
  *
  */
 
-/* Current location of librm in base memory */
-char *installed_librm = librm;
-
-/* Whether or not we have base memory currently allocated for librm.
- * Note that we *can* have a working librm present in unallocated base
- * memory; this is the situation at startup for all real-mode
- * prefixes.
- */
-static int allocated_librm = 0;
-
 /*
  * Allocate space on the real-mode stack and copy data there.
  *
  */
 uint16_t copy_to_rm_stack ( void *data, size_t size ) {
 #ifdef DEBUG_LIBRM
-       if ( inst_rm_stack.offset <= size ) {
+       if ( rm_sp <= size ) {
                printf ( "librm: out of space in RM stack\n" );
                lockup();
        }
 #endif
-       inst_rm_stack.offset -= size;
-       copy_to_real ( inst_rm_stack.segment, inst_rm_stack.offset,
-                      data, size );
-       return inst_rm_stack.offset;
+       rm_sp -= size;
+       copy_to_real ( rm_ss, rm_sp, data, size );
+       return rm_sp;
 };
 
 /*
@@ -56,120 +40,9 @@ uint16_t copy_to_rm_stack ( void *data, size_t size ) {
  */
 void remove_from_rm_stack ( void *data, size_t size ) {
        if ( data ) {
-               copy_from_real ( data,
-                                inst_rm_stack.segment, inst_rm_stack.offset,
-                                size );
+               copy_from_real ( data, rm_ss, rm_sp, size );
        }
-       inst_rm_stack.offset += size;
+       rm_sp += size;
 };
 
-/*
- * Install librm to base memory
- *
- */
-static void install_librm ( char *addr ) {
-       librm_base = virt_to_phys ( addr );
-       memcpy ( addr, librm, librm_size );
-       installed_librm = addr;
-}
-
-/*
- * Uninstall librm from base memory.  This copies librm back to the
- * "master" copy, so that it can be reinstalled to a new location,
- * preserving the values for rm_ss and rm_sp from the old installed
- * copy.
- *
- * We deliberately leave the old copy intact and effectively installed
- * (apart from being in unallocated memory) so that we can use it for
- * any real-mode calls required when allocating memory for the new
- * copy, or for the real-mode exit path.
- */
-static void uninstall_librm ( void ) {
-
-       /* Copy installed librm back to master copy */
-       memcpy ( librm, installed_librm, librm_size );
-
-       /* Free but do not zero the base memory */
-       if ( allocated_librm ) {
-               free_base_memory ( installed_librm, librm_size );
-               allocated_librm = 0;
-       }
-}
-
-/*
- * If librm isn't installed (i.e. if we have librm, but weren't
- * entered via it), then install librm and a real-mode stack to a
- * fixed temporary location, just so that we can e.g. issue printf()
- *
- * [ If we were entered via librm, then the real_to_prot call will
- * have filled in librm_base. ]
- */
-static void librm_init ( void ) {
-       if ( ! librm_base ) {
-               install_librm ( phys_to_virt ( 0x7c00 ) );
-               inst_rm_stack.segment = 0x7c0;
-               inst_rm_stack.offset = 0x1000;
-       }
-}
-
-/*
- * librm_post_reloc gets called immediately after relocation.
- *
- */
-static void librm_post_reloc ( void ) {
-       /* Point installed_librm back at last known physical location.
-        */
-       installed_librm = phys_to_virt ( librm_base );
-
-       /* Allocate base memory for librm and place a copy there */
-       if ( ! allocated_librm ) {
-               char *new_librm = alloc_base_memory ( librm_size );
-               uninstall_librm ();
-               install_librm ( new_librm );
-               allocated_librm = 1;
-       }
-}
-
-INIT_FN ( INIT_LIBRM, librm_init, NULL, uninstall_librm );
-POST_RELOC_FN ( POST_RELOC_LIBRM, librm_post_reloc );
-
-/*
- * Wrapper for initialise() when librm is being used.  We have to
- * install a copy of librm to allocated base memory and return the
- * pointer to this new librm's entry point via es:di.
- *
- */
-void initialise_via_librm ( struct i386_all_regs *ix86 ) {
-       /* Hand off to initialise() */
-       initialise ();
-
-       /* Point es:di to new librm's entry point.  Fortunately, di is
-        * already set up by setup16, so all we need to do is point
-        * es:0000 to the start of the new librm.
-        */
-       ix86->segs.es = librm_base >> 4;
-}
-
-/*
- * Increment lock count of librm
- *
- */
-void lock_librm ( void ) {
-       inst_librm_ref_count++;
-}
-
-/*
- * Decrement lock count of librm
- *
- */
-void unlock_librm ( void ) {
-#ifdef DEBUG_LIBRM
-       if ( inst_librm_ref_count == 0 ) {
-               printf ( "librm: ref count gone negative\n" );
-               lockup();
-       }
-#endif
-       inst_librm_ref_count--;
-}
-
 #endif /* KEEP_IT_REAL */
index 262c2d9..bc1f166 100644 (file)
 #include "setjmp.h"
 #include "latch.h"
 
-/* within 1MB of 4GB is too close. 
- * MAX_ADDR is the maximum address we can easily do DMA to.
- */
-#define MAX_ADDR (0xfff00000UL)
-
 typedef        unsigned long Address;
 
 /* ANSI prototyping macro */