mirror of
https://github.com/ipxe/ipxe
synced 2026-02-28 03:11:18 +03:00
[riscv] Relocate to a safe physical address on startup
On startup, we may be running from read-only memory. We need to parse the devicetree to obtain the system memory map, and identify a safe location to which we can copy our own binary image along with a stashed copy of the devicetree, and then transfer execution to this new location. Parsing the system memory map realistically requires running C code. This in turn requires a small temporary stack, and some way to ensure that symbol references are valid. We first attempt to enable paging, to make the runtime virtual addresses equal to the link-time virtual addresses. If this fails, then we attempt to apply the compressed relocation records. Assuming that one of these has worked (i.e. that either the CPU supports paging or that our image started execution in writable memory), then we call fdtmem_relocate() to parse the system memory map to find a suitable relocation target address. After the copy we disable paging, jump to the relocated copy, re-enable paging, and reapply relocation records (if needed). At this point, we have a full runtime environment, and can transfer control to normal C code. Provide this functionality as part of libprefix.S, since it is likely to be shared by multiple prefixes. Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -41,6 +41,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
/** Start address of the iPXE image */
|
||||
extern char _prefix[];
|
||||
|
||||
/** Initialised-data size of the iPXE image (defined by linker) */
|
||||
extern size_t ABS_SYMBOL ( _filesz );
|
||||
static size_t filesz = ABS_VALUE_INIT ( _filesz );
|
||||
|
||||
/** In-memory size of the iPXE image (defined by linker) */
|
||||
extern size_t ABS_SYMBOL ( _memsz );
|
||||
static size_t memsz = ABS_VALUE_INIT ( _memsz );
|
||||
@@ -275,6 +279,7 @@ physaddr_t fdtmem_relocate ( struct fdt_header *hdr, size_t limit ) {
|
||||
physaddr_t new;
|
||||
physaddr_t try;
|
||||
size_t len;
|
||||
void *dest;
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
@@ -294,7 +299,6 @@ physaddr_t fdtmem_relocate ( struct fdt_header *hdr, size_t limit ) {
|
||||
/* Determine required length */
|
||||
assert ( memsz > 0 );
|
||||
assert ( ( memsz % FDT_MAX_ALIGN ) == 0 );
|
||||
assert ( ( fdt.len % FDT_MAX_ALIGN ) == 0 );
|
||||
len = ( memsz + fdt.len );
|
||||
assert ( len > 0 );
|
||||
DBGC ( colour, "FDTMEM requires %#zx + %#zx => %#zx bytes for "
|
||||
@@ -351,6 +355,14 @@ physaddr_t fdtmem_relocate ( struct fdt_header *hdr, size_t limit ) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Copy iPXE and device tree to new location */
|
||||
if ( new != old ) {
|
||||
dest = phys_to_virt ( new );
|
||||
memset ( dest, 0, len );
|
||||
memcpy ( dest, _prefix, filesz );
|
||||
memcpy ( ( dest + memsz ), hdr, fdt.len );
|
||||
}
|
||||
|
||||
DBGC ( colour, "FDTMEM relocating %#08lx => [%#08lx,%#08lx]\n",
|
||||
old, new, ( ( physaddr_t ) ( new + len - 1 ) ) );
|
||||
return new;
|
||||
|
||||
Reference in New Issue
Block a user