/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Support for Kernel relocation at boot time * * Copyright (C) 2015, Imagination Technologies Ltd. * Authors: Matt Redfearn (matt.redfearn@mips.com)
*/ #include <asm/bootinfo.h> #include <asm/cacheflush.h> #include <asm/fw/fw.h> #include <asm/sections.h> #include <asm/setup.h> #include <asm/timex.h> #include <linux/elf.h> #include <linux/kernel.h> #include <linux/libfdt.h> #include <linux/of_fdt.h> #include <linux/panic_notifier.h> #include <linux/sched/task.h> #include <linux/start_kernel.h> #include <linux/string.h> #include <linux/printk.h>
#define RELOCATED(x) ((void *)((long)x + offset))
extern u32 _relocation_start[]; /* End kernel image / start relocation table */ extern u32 _relocation_end[]; /* End relocation table */
/* * This function may be defined for a platform to perform any post-relocation * fixup necessary. * Return non-zero to abort relocation
*/ int __weak plat_post_relocation(long offset)
{ return 0;
}
res = reloc_handler(type, loc_orig, loc_new, offset); if (res) return res;
}
return 0;
}
/* * The exception table is filled in by the relocs tool after vmlinux is linked. * It must be relocated separately since there will not be any relocation * information for it filled in by the linker.
*/ staticint __init relocate_exception_table(long offset)
{ unsignedlong *etable_start, *etable_end, *e;
staticinlinevoid __init *determine_relocation_address(void)
{ /* * Choose a new address for the kernel * For now we'll hard code the destination
*/ return (void *)0xffffffff81000000;
}
#endif
staticinlineint __init relocation_addr_valid(void *loc_new)
{ if ((unsignedlong)loc_new & 0x0000ffff) { /* Inappropriately aligned new location */ return 0;
} if ((unsignedlong)loc_new < (unsignedlong)&_end) { /* New location overlaps original kernel */ return 0;
} return 1;
}
void *__init relocate_kernel(void)
{ void *loc_new; unsignedlong kernel_length; unsignedlong bss_length; long offset = 0; int res = 1; /* Default to original kernel entry point */ void *kernel_entry = start_kernel; void *fdt = NULL;
/* Get the command line */
fw_init_cmdline(); #ifdefined(CONFIG_USE_OF) /* Deal with the device tree */
fdt = plat_get_fdt();
early_init_dt_scan(fdt, __pa(fdt)); if (boot_command_line[0]) { /* Boot command line was passed in device tree */
strscpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
} #endif/* CONFIG_USE_OF */
/* * If built-in dtb is used then it will have been relocated * during kernel _text relocation. If appended DTB is used * then it will not be relocated, but it should remain * intact in the original location. If dtb is loaded by * the bootloader then it may need to be moved if it crosses * the target memory area
*/
/* Copy the kernel to its new location */
memcpy(loc_new, &_text, kernel_length);
/* Perform relocations on the new kernel */
res = do_relocations(&_text, loc_new, offset); if (res < 0) goto out;
/* Sync the caches ready for execution of new kernel */
sync_icache(loc_new, kernel_length);
res = relocate_exception_table(offset); if (res < 0) goto out;
/* * The original .bss has already been cleared, and * some variables such as command line parameters * stored to it so make a copy in the new location.
*/
memcpy(RELOCATED(&__bss_start), &__bss_start, bss_length);
/* * If fdt was stored outside of the kernel image and * had to be moved then update platform's state data * with the new fdt location
*/ if (fdt_relocated_)
fdt_relocated_(fdt);
/* * Last chance for the platform to abort relocation. * This may also be used by the platform to perform any * initialisation required now that the new kernel is * resident in memory and ready to be executed.
*/ if (plat_post_relocation(offset)) goto out;
/* The current thread is now within the relocated image */
__current_thread_info = RELOCATED(&init_thread_union);
/* Return the new kernel's entry point */
kernel_entry = RELOCATED(start_kernel);
/* Error may occur before, so keep it at last */
update_kaslr_offset(&__kaslr_offset, offset);
}
out: return kernel_entry;
}
/* * Show relocation information on panic.
*/ staticvoid show_kernel_relocation(constchar *level)
{ if (__kaslr_offset > 0) {
printk(level);
pr_cont("Kernel relocated by 0x%p\n", (void *)__kaslr_offset);
pr_cont(" .text @ 0x%p\n", _text);
pr_cont(" .data @ 0x%p\n", _sdata);
pr_cont(" .bss @ 0x%p\n", __bss_start);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.