diff options
author | 2015-08-28 09:58:54 +0800 | |
---|---|---|
committer | 2015-09-01 12:44:00 +0800 | |
commit | e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch) | |
tree | 66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/ipxe/src/arch/i386/core/relocate.c | |
parent | 9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (diff) |
Add qemu 2.4.0
Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5
Signed-off-by: Yang Zhang <yang.z.zhang@intel.com>
Diffstat (limited to 'qemu/roms/ipxe/src/arch/i386/core/relocate.c')
-rw-r--r-- | qemu/roms/ipxe/src/arch/i386/core/relocate.c | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/qemu/roms/ipxe/src/arch/i386/core/relocate.c b/qemu/roms/ipxe/src/arch/i386/core/relocate.c new file mode 100644 index 000000000..5fbf2d2c2 --- /dev/null +++ b/qemu/roms/ipxe/src/arch/i386/core/relocate.c @@ -0,0 +1,138 @@ +#include <ipxe/io.h> +#include <registers.h> + +/* + * Originally by Eric Biederman + * + * Heavily modified by Michael Brown + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/* + * The linker passes in the symbol _max_align, which is the alignment + * that we must preserve, in bytes. + * + */ +extern char _max_align[]; +#define max_align ( ( unsigned int ) _max_align ) + +/* Linker symbols */ +extern char _textdata[]; +extern char _etextdata[]; + +/* 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) + +/** + * Relocate iPXE + * + * @v ebp Maximum address to use for relocation + * @ret esi Current physical address + * @ret edi New physical address + * @ret ecx Length to copy + * + * This finds a suitable location for iPXE near the top of 32-bit + * address space, and returns the physical address of the new location + * to the prefix in %edi. + */ +__asmcall void relocate ( struct i386_all_regs *ix86 ) { + struct memory_map memmap; + unsigned long start, end, size, padded_size, max; + unsigned long new_start, new_end; + unsigned i; + + /* Get memory map and current location */ + get_memmap ( &memmap ); + start = virt_to_phys ( _textdata ); + end = virt_to_phys ( _etextdata ); + 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 ); + + /* Determine maximum usable address */ + max = MAX_ADDR; + if ( ix86->regs.ebp < max ) { + max = ix86->regs.ebp; + DBG ( "Limiting relocation to [0,%lx)\n", max ); + } + + /* Walk through the memory map and find the highest address + * below 4GB that iPXE will fit into. + */ + 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 [%llx,%llx)\n", region->start, region->end); + + /* Truncate block to maximum address. This will be + * less than 4GB, which means that we can get away + * with using just 32-bit arithmetic after this stage. + */ + if ( region->start > max ) { + DBG ( "...starts after max=%lx\n", max ); + continue; + } + r_start = region->start; + if ( region->end > max ) { + DBG ( "...end truncated to max=%lx\n", max ); + r_end = max; + } else { + r_end = region->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. + */ + if ( r_end < r_start ) { + DBG ( "...truncated to negative size\n" ); + continue; + } + + /* Check that there is enough space to fit in iPXE */ + if ( ( r_end - r_start ) < size ) { + DBG ( "...too small (need %lx bytes)\n", size ); + continue; + } + + /* If the start address of the iPXE we would + * place in this block is higher than the end address + * of the current highest block, use this block. + * + * Note that this avoids overlaps with the current + * iPXE, as well as choosing the highest of all viable + * blocks. + */ + if ( ( r_end - size ) > new_end ) { + new_end = r_end; + DBG ( "...new best block found.\n" ); + } + } + + /* Calculate new location of iPXE, and align it to the + * required alignemnt. + */ + new_start = new_end - padded_size; + new_start += ( start - new_start ) & ( max_align - 1 ); + new_end = new_start + size; + + DBG ( "Relocating from [%lx,%lx) to [%lx,%lx)\n", + start, end, new_start, new_end ); + + /* Let prefix know what to copy */ + ix86->regs.esi = start; + ix86->regs.edi = new_start; + ix86->regs.ecx = size; +} |