#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 max_align ( ( unsigned int ) _max_align ) |
| #define MAX_ADDR (0xfff00000UL) |
| FILE_LICENCE | ( | GPL2_OR_LATER | ) |
| __asmcall void relocate | ( | struct i386_all_regs * | ix86 | ) |
Relocate Etherboot.
| ix86 | x86 register dump from prefix |
| ix86 | x86 registers to return to prefix |
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 }
| char _max_align[] |
| char _textdata[] |
Referenced by hide_etherboot(), hide_textdata(), hide_umalloc(), and relocate().
| char _etextdata[] |
Referenced by hide_textdata(), and relocate().
1.5.7.1