relocate.c File Reference

#include <gpxe/io.h>
#include <registers.h>
#include <gpxe/memmap.h>

Go to the source code of this file.

Defines

#define max_align   ( ( unsigned int ) _max_align )
#define MAX_ADDR   (0xfff00000UL)

Functions

 FILE_LICENCE (GPL2_OR_LATER)
__asmcall void relocate (struct i386_all_regs *ix86)
 Relocate Etherboot.

Variables

char _max_align []
char _textdata []
char _etextdata []


Define Documentation

#define max_align   ( ( unsigned int ) _max_align )

Definition at line 20 of file relocate.c.

Referenced by relocate().

#define MAX_ADDR   (0xfff00000UL)

Definition at line 32 of file relocate.c.

Referenced by relocate().


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER   ) 

__asmcall void relocate ( struct i386_all_regs ix86  ) 

Relocate Etherboot.

Parameters:
ix86 x86 register dump from prefix
Return values:
ix86 x86 registers to return to prefix
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.

Definition at line 44 of file relocate.c.

References _etextdata, _textdata, memory_map::count, DBG, i386_regs::ecx, i386_regs::edi, memory_region::end, i386_regs::esi, get_memmap(), MAX_ADDR, max_align, memory_map::regions, i386_all_regs::regs, size, memory_region::start, and virt_to_phys().

00044                                                        {
00045         struct memory_map memmap;
00046         unsigned long start, end, size, padded_size;
00047         unsigned long new_start, new_end;
00048         unsigned i;
00049 
00050         /* Get memory map and current location */
00051         get_memmap ( &memmap );
00052         start = virt_to_phys ( _textdata );
00053         end = virt_to_phys ( _etextdata );
00054         size = ( end - start );
00055         padded_size = ( size + max_align - 1 );
00056 
00057         DBG ( "Relocate: currently at [%lx,%lx)\n"
00058               "...need %lx bytes for %d-byte alignment\n",
00059               start, end, padded_size, max_align );
00060 
00061         /* Walk through the memory map and find the highest address
00062          * below 4GB that etherboot will fit into.  Ensure etherboot
00063          * lies entirely within a range with A20=0.  This means that
00064          * even if something screws up the state of the A20 line, the
00065          * etherboot code is still visible and we have a chance to
00066          * diagnose the problem.
00067          */
00068         new_end = end;
00069         for ( i = 0 ; i < memmap.count ; i++ ) {
00070                 struct memory_region *region = &memmap.regions[i];
00071                 unsigned long r_start, r_end;
00072 
00073                 DBG ( "Considering [%llx,%llx)\n", region->start, region->end);
00074                 
00075                 /* Truncate block to MAX_ADDR.  This will be less than
00076                  * 4GB, which means that we can get away with using
00077                  * just 32-bit arithmetic after this stage.
00078                  */
00079                 if ( region->start > MAX_ADDR ) {
00080                         DBG ( "...starts after MAX_ADDR=%lx\n", MAX_ADDR );
00081                         continue;
00082                 }
00083                 r_start = region->start;
00084                 if ( region->end > MAX_ADDR ) {
00085                         DBG ( "...end truncated to MAX_ADDR=%lx\n", MAX_ADDR );
00086                         r_end = MAX_ADDR;
00087                 } else {
00088                         r_end = region->end;
00089                 }
00090                 
00091                 /* Shrink the range down to use only even megabytes
00092                  * (i.e. A20=0).
00093                  */
00094                 if ( ( r_end - 1 ) & 0x100000 ) {
00095                         /* If last byte that might be used (r_end-1)
00096                          * is in an odd megabyte, round down r_end to
00097                          * the top of the next even megabyte.
00098                          *
00099                          * Make sure that we don't accidentally wrap
00100                          * r_end below 0.
00101                          */
00102                         if ( r_end >= 1 ) {
00103                                 r_end = ( r_end - 1 ) & ~0xfffff;
00104                                 DBG ( "...end truncated to %lx "
00105                                       "(avoid ending in odd megabyte)\n",
00106                                       r_end );
00107                         }
00108                 } else if ( ( r_end - size ) & 0x100000 ) {
00109                         /* If the last byte that might be used
00110                          * (r_end-1) is in an even megabyte, but the
00111                          * first byte that might be used (r_end-size)
00112                          * is an odd megabyte, round down to the top
00113                          * of the next even megabyte.
00114                          * 
00115                          * Make sure that we don't accidentally wrap
00116                          * r_end below 0.
00117                          */
00118                         if ( r_end >= 0x100000 ) {
00119                                 r_end = ( r_end - 0x100000 ) & ~0xfffff;
00120                                 DBG ( "...end truncated to %lx "
00121                                       "(avoid starting in odd megabyte)\n",
00122                                       r_end );
00123                         }
00124                 }
00125 
00126                 DBG ( "...usable portion is [%lx,%lx)\n", r_start, r_end );
00127 
00128                 /* If we have rounded down r_end below r_ start, skip
00129                  * this block.
00130                  */
00131                 if ( r_end < r_start ) {
00132                         DBG ( "...truncated to negative size\n" );
00133                         continue;
00134                 }
00135 
00136                 /* Check that there is enough space to fit in Etherboot */
00137                 if ( ( r_end - r_start ) < size ) {
00138                         DBG ( "...too small (need %lx bytes)\n", size );
00139                         continue;
00140                 }
00141 
00142                 /* If the start address of the Etherboot we would
00143                  * place in this block is higher than the end address
00144                  * of the current highest block, use this block.
00145                  *
00146                  * Note that this avoids overlaps with the current
00147                  * Etherboot, as well as choosing the highest of all
00148                  * viable blocks.
00149                  */
00150                 if ( ( r_end - size ) > new_end ) {
00151                         new_end = r_end;
00152                         DBG ( "...new best block found.\n" );
00153                 }
00154         }
00155 
00156         /* Calculate new location of Etherboot, and align it to the
00157          * required alignemnt.
00158          */
00159         new_start = new_end - padded_size;
00160         new_start += ( start - new_start ) & ( max_align - 1 );
00161         new_end = new_start + size;
00162 
00163         DBG ( "Relocating from [%lx,%lx) to [%lx,%lx)\n",
00164               start, end, new_start, new_end );
00165         
00166         /* Let prefix know what to copy */
00167         ix86->regs.esi = start;
00168         ix86->regs.edi = new_start;
00169         ix86->regs.ecx = size;
00170 }


Variable Documentation

char _max_align[]

char _textdata[]

char _etextdata[]

Referenced by hide_textdata(), and relocate().


Generated on Tue Apr 6 20:01:11 2010 for gPXE by  doxygen 1.5.7.1