Update relocate() to work with get_memmap().
authorMichael Brown <mcb30@etherboot.org>
Thu, 25 May 2006 00:04:13 +0000 (00:04 +0000)
committerMichael Brown <mcb30@etherboot.org>
Thu, 25 May 2006 00:04:13 +0000 (00:04 +0000)
Change semantics; relocate() now just finds a suitable location; it
doesn't actually perform the relocation itself.  Code in libprefix does
the copy in flat real mode.

src/arch/i386/core/relocate.c

index a51d515..c9ac7ee 100644 (file)
@@ -1,6 +1,6 @@
-#include <virtaddr.h>
+#include <io.h>
 #include <registers.h>
-#include <memsizes.h>
+#include <memmap.h>
 
 /*
  * Originally by Eric Biederman
@@ -35,14 +35,27 @@ extern char _end[];
  * @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
+ * This finds a suitable location for Etherboot 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;
+       struct memory_map memmap;
+       unsigned long start, end, size, padded_size;
+       unsigned long new_start, new_end;
        unsigned i;
 
+       /* Get memory map and current location */
+       get_memmap ( &memmap );
+       start = virt_to_phys ( _text );
+       end = virt_to_phys ( _end );
+       size = ( end - start );
+       padded_size = ( size + max_align - 1 );
+
+       DBG ( "Relocate: currently at [%lx,%lx)\n"
+             "...need %lx bytes for %d-byte alignment\n",
+             start, end, padded_size, max_align );
+
        /* Walk through the memory map and find the highest address
         * below 4GB that etherboot will fit into.  Ensure etherboot
         * lies entirely within a range with A20=0.  This means that
@@ -50,58 +63,29 @@ void relocate ( struct i386_all_regs *ix86 ) {
         * etherboot code is still visible and we have a chance to
         * diagnose the problem.
         */
-
-       /* First find the size of etherboot, including enough space to
-        * pad it to the required alignment
-        */
-       size = _end - _text + max_align - 1;
-
-       /* Current end address of Etherboot.  If the current etherboot
-        * is beyond MAX_ADDR pretend it is at the lowest possible
-        * address.
-        */
-       eaddr = virt_to_phys(_end);
-       if ( eaddr > MAX_ADDR ) {
-               eaddr = 0;
-       }
-
-       DBG ( "Relocate: currently at [%x,%x)\n"
-             "...need %x bytes for %d-byte alignment\n",
-             virt_to_phys ( _text ), eaddr, size, max_align );
-
-       for ( i = 0; i < meminfo.map_count; i++ ) {
+       new_end = end;
+       for ( i = 0 ; i < memmap.count ; i++ ) {
+               struct memory_region *region = &memmap.regions[i];
                unsigned long r_start, r_end;
 
-               DBG ( "Considering [%x%x,%x%x)\n",
-                     ( unsigned long ) ( meminfo.map[i].addr >> 32 ),
-                     ( unsigned long ) meminfo.map[i].addr,
-                     ( unsigned long )
-                      ( ( meminfo.map[i].addr + meminfo.map[i].size ) >> 32 ),
-                     ( unsigned long )
-                      ( meminfo.map[i].addr + meminfo.map[i].size ) );
+               DBG ( "Considering [%llx,%llx)\n", region->start, region->end);
                
-               /* Check block is usable memory */
-               if (meminfo.map[i].type != E820_RAM) {
-                       DBG ( "...not RAM\n" );
-                       continue;
-               }
-
                /* Truncate block to MAX_ADDR.  This will be less than
                 * 4GB, which means that we can get away with using
                 * just 32-bit arithmetic after this stage.
                 */
-               if ( meminfo.map[i].addr > MAX_ADDR ) {
-                       DBG ( "...starts after MAX_ADDR=%x\n", MAX_ADDR );
+               if ( region->start > MAX_ADDR ) {
+                       DBG ( "...starts after MAX_ADDR=%lx\n", MAX_ADDR );
                        continue;
                }
-               r_start = meminfo.map[i].addr;
-               if ( meminfo.map[i].addr + meminfo.map[i].size > MAX_ADDR ) {
+               r_start = region->start;
+               if ( region->end > MAX_ADDR ) {
+                       DBG ( "...end truncated to MAX_ADDR=%lx\n", MAX_ADDR );
                        r_end = MAX_ADDR;
-                       DBG ( "...end truncated to MAX_ADDR=%x\n", MAX_ADDR );
                } else {
-                       r_end = meminfo.map[i].addr + meminfo.map[i].size;
+                       r_end = region->end;
                }
-
+               
                /* Shrink the range down to use only even megabytes
                 * (i.e. A20=0).
                 */
@@ -111,7 +95,7 @@ void relocate ( struct i386_all_regs *ix86 ) {
                         * the top of the next even megabyte.
                         */
                        r_end = ( r_end - 1 ) & ~0xfffff;
-                       DBG ( "...end truncated to %x "
+                       DBG ( "...end truncated to %lx "
                              "(avoid ending in odd megabyte)\n",
                              r_end );
                } else if ( ( r_end - size ) & 0x100000 ) {
@@ -126,13 +110,13 @@ void relocate ( struct i386_all_regs *ix86 ) {
                         */
                        if ( r_end > 0x100000 ) {
                                r_end = ( r_end - 0x100000 ) & ~0xfffff;
-                               DBG ( "...end truncated to %x "
+                               DBG ( "...end truncated to %lx "
                                      "(avoid starting in odd megabyte)\n",
                                      r_end );
                        }
                }
 
-               DBG ( "...usable portion is [%x,%x)\n", r_start, r_end );
+               DBG ( "...usable portion is [%lx,%lx)\n", r_start, r_end );
 
                /* If we have rounded down r_end below r_ start, skip
                 * this block.
@@ -143,8 +127,8 @@ void relocate ( struct i386_all_regs *ix86 ) {
                }
 
                /* Check that there is enough space to fit in Etherboot */
-               if ( r_end - r_start < size ) {
-                       DBG ( "...too small (need %x bytes)\n", size );
+               if ( ( r_end - r_start ) < size ) {
+                       DBG ( "...too small (need %lx bytes)\n", size );
                        continue;
                }
 
@@ -156,30 +140,24 @@ void relocate ( struct i386_all_regs *ix86 ) {
                 * Etherboot, as well as choosing the highest of all
                 * viable blocks.
                 */
-               if ( r_end - size > eaddr ) {
-                       eaddr = r_end;
+               if ( ( r_end - size ) > new_end ) {
+                       new_end = r_end;
                        DBG ( "...new best block found.\n" );
                }
        }
 
-       DBG ( "New location will be in [%x,%x)\n", eaddr - size, eaddr );
-
        /* Calculate new location of Etherboot, and align it to the
         * required alignemnt.
         */
-       addr = eaddr - size;
-       addr += ( virt_to_phys ( _text ) - addr ) & ( max_align - 1 );
-       DBG ( "After alignment, new location is [%x,%x)\n",
-             addr, addr + _end - _text );
+       new_start = new_end - padded_size;
+       new_start += ( start - new_start ) & ( max_align - 1 );
+       new_end = new_start + size;
 
-       if ( addr != virt_to_phys ( _text ) ) {
-               DBG ( "Relocating _text from: [%lx,%lx) to [%lx,%lx)\n",
-                     virt_to_phys ( _text ), virt_to_phys ( _end ),
-                     addr, addr + _end - _text );
-
-               memcpy ( phys_to_virt ( addr ), _text, _end - _text );
-       }
+       DBG ( "Relocating from [%lx,%lx) to [%lx,%lx)\n",
+             start, end, new_start, new_end );
        
-       /* Let prefix know where the new copy is */
-       ix86->regs.edi = addr;
+       /* Let prefix know what to copy */
+       ix86->regs.esi = start;
+       ix86->regs.edi = new_start;
+       ix86->regs.ecx = size;
 }