5 * Originally by Eric Biederman
7 * Heavily modified by Michael Brown
11 FILE_LICENCE ( GPL2_OR_LATER );
14 * The linker passes in the symbol _max_align, which is the alignment
15 * that we must preserve, in bytes.
18 extern char _max_align[];
19 #define max_align ( ( unsigned int ) _max_align )
22 extern char _textdata[];
23 extern char _etextdata[];
25 /* within 1MB of 4GB is too close.
26 * MAX_ADDR is the maximum address we can easily do DMA to.
28 * Not sure where this constraint comes from, but kept it from Eric's
31 #define MAX_ADDR (0xfff00000UL)
36 * @v ebp Maximum address to use for relocation
37 * @ret esi Current physical address
38 * @ret edi New physical address
39 * @ret ecx Length to copy
41 * This finds a suitable location for iPXE near the top of 32-bit
42 * address space, and returns the physical address of the new location
43 * to the prefix in %edi.
45 __asmcall void relocate ( struct i386_all_regs *ix86 ) {
46 struct memory_map memmap;
47 unsigned long start, end, size, padded_size, max;
48 unsigned long new_start, new_end;
51 /* Get memory map and current location */
52 get_memmap ( &memmap );
53 start = virt_to_phys ( _textdata );
54 end = virt_to_phys ( _etextdata );
55 size = ( end - start );
56 padded_size = ( size + max_align - 1 );
58 DBG ( "Relocate: currently at [%lx,%lx)\n"
59 "...need %lx bytes for %d-byte alignment\n",
60 start, end, padded_size, max_align );
62 /* Determine maximum usable address */
64 if ( ix86->regs.ebp < max ) {
66 DBG ( "Limiting relocation to [0,%lx)\n", max );
69 /* Walk through the memory map and find the highest address
70 * below 4GB that iPXE will fit into.
73 for ( i = 0 ; i < memmap.count ; i++ ) {
74 struct memory_region *region = &memmap.regions[i];
75 unsigned long r_start, r_end;
77 DBG ( "Considering [%llx,%llx)\n", region->start, region->end);
79 /* Truncate block to maximum address. This will be
80 * less than 4GB, which means that we can get away
81 * with using just 32-bit arithmetic after this stage.
83 if ( region->start > max ) {
84 DBG ( "...starts after max=%lx\n", max );
87 r_start = region->start;
88 if ( region->end > max ) {
89 DBG ( "...end truncated to max=%lx\n", max );
94 DBG ( "...usable portion is [%lx,%lx)\n", r_start, r_end );
96 /* If we have rounded down r_end below r_ start, skip
99 if ( r_end < r_start ) {
100 DBG ( "...truncated to negative size\n" );
104 /* Check that there is enough space to fit in iPXE */
105 if ( ( r_end - r_start ) < size ) {
106 DBG ( "...too small (need %lx bytes)\n", size );
110 /* If the start address of the iPXE we would
111 * place in this block is higher than the end address
112 * of the current highest block, use this block.
114 * Note that this avoids overlaps with the current
115 * iPXE, as well as choosing the highest of all viable
118 if ( ( r_end - size ) > new_end ) {
120 DBG ( "...new best block found.\n" );
124 /* Calculate new location of iPXE, and align it to the
125 * required alignemnt.
127 new_start = new_end - padded_size;
128 new_start += ( start - new_start ) & ( max_align - 1 );
129 new_end = new_start + size;
131 DBG ( "Relocating from [%lx,%lx) to [%lx,%lx)\n",
132 start, end, new_start, new_end );
134 /* Let prefix know what to copy */
135 ix86->regs.esi = start;
136 ix86->regs.edi = new_start;
137 ix86->regs.ecx = size;