^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * License. See the file "COPYING" in the main directory of this archive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Support for Kernel relocation at boot time
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Copyright (C) 2015, Imagination Technologies Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Authors: Matt Redfearn (matt.redfearn@mips.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <asm/bootinfo.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <asm/cacheflush.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <asm/fw/fw.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <asm/sections.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <asm/setup.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <asm/timex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/elf.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/libfdt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/of_fdt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/sched/task.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/start_kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/printk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define RELOCATED(x) ((void *)((long)x + offset))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) extern u32 _relocation_start[]; /* End kernel image / start relocation table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) extern u32 _relocation_end[]; /* End relocation table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) extern long __start___ex_table; /* Start exception table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) extern long __stop___ex_table; /* End exception table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) extern void __weak plat_fdt_relocated(void *new_location);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * This function may be defined for a platform to perform any post-relocation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * fixup necessary.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * Return non-zero to abort relocation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) int __weak plat_post_relocation(long offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static inline u32 __init get_synci_step(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) u32 res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) __asm__("rdhwr %0, $1" : "=r" (res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static void __init sync_icache(void *kbase, unsigned long kernel_length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) void *kend = kbase + kernel_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) u32 step = get_synci_step();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) __asm__ __volatile__(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) "synci 0(%0)"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) : /* no output */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) : "r" (kbase));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) kbase += step;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) } while (kbase < kend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /* Completion barrier */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) __sync();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static int __init apply_r_mips_64_rel(u32 *loc_orig, u32 *loc_new, long offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) *(u64 *)loc_new += offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static int __init apply_r_mips_32_rel(u32 *loc_orig, u32 *loc_new, long offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) *loc_new += offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static int __init apply_r_mips_26_rel(u32 *loc_orig, u32 *loc_new, long offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) unsigned long target_addr = (*loc_orig) & 0x03ffffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (offset % 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) pr_err("Dangerous R_MIPS_26 REL relocation\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) return -ENOEXEC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) /* Original target address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) target_addr <<= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) target_addr += (unsigned long)loc_orig & ~0x03ffffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /* Get the new target address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) target_addr += offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if ((target_addr & 0xf0000000) != ((unsigned long)loc_new & 0xf0000000)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) pr_err("R_MIPS_26 REL relocation overflow\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return -ENOEXEC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) target_addr -= (unsigned long)loc_new & ~0x03ffffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) target_addr >>= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) *loc_new = (*loc_new & ~0x03ffffff) | (target_addr & 0x03ffffff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static int __init apply_r_mips_hi16_rel(u32 *loc_orig, u32 *loc_new, long offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) unsigned long insn = *loc_orig;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) unsigned long target = (insn & 0xffff) << 16; /* high 16bits of target */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) target += offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) *loc_new = (insn & ~0xffff) | ((target >> 16) & 0xffff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static int (*reloc_handlers_rel[]) (u32 *, u32 *, long) __initdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) [R_MIPS_64] = apply_r_mips_64_rel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) [R_MIPS_32] = apply_r_mips_32_rel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) [R_MIPS_26] = apply_r_mips_26_rel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) [R_MIPS_HI16] = apply_r_mips_hi16_rel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) int __init do_relocations(void *kbase_old, void *kbase_new, long offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) u32 *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) u32 *loc_orig;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) u32 *loc_new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) int type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) int res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) for (r = _relocation_start; r < _relocation_end; r++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) /* Sentinel for last relocation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (*r == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) type = (*r >> 24) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) loc_orig = kbase_old + ((*r & 0x00ffffff) << 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) loc_new = RELOCATED(loc_orig);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (reloc_handlers_rel[type] == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) /* Unsupported relocation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) pr_err("Unhandled relocation type %d at 0x%pK\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) type, loc_orig);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) return -ENOEXEC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) res = reloc_handlers_rel[type](loc_orig, loc_new, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) * The exception table is filled in by the relocs tool after vmlinux is linked.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * It must be relocated separately since there will not be any relocation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * information for it filled in by the linker.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) static int __init relocate_exception_table(long offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) unsigned long *etable_start, *etable_end, *e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) etable_start = RELOCATED(&__start___ex_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) etable_end = RELOCATED(&__stop___ex_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) for (e = etable_start; e < etable_end; e++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) *e += offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) #ifdef CONFIG_RANDOMIZE_BASE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) static inline __init unsigned long rotate_xor(unsigned long hash,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) const void *area, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) const typeof(hash) *ptr = PTR_ALIGN(area, sizeof(hash));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) size_t diff, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) diff = (void *)ptr - area;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (unlikely(size < diff + sizeof(hash)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) return hash;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) size = ALIGN_DOWN(size - diff, sizeof(hash));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) for (i = 0; i < size / sizeof(hash); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) /* Rotate by odd number of bits and XOR. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) hash = (hash << ((sizeof(hash) * 8) - 7)) | (hash >> 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) hash ^= ptr[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return hash;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) static inline __init unsigned long get_random_boot(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) unsigned long entropy = random_get_entropy();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) unsigned long hash = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) /* Attempt to create a simple but unpredictable starting entropy. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) hash = rotate_xor(hash, linux_banner, strlen(linux_banner));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) /* Add in any runtime entropy we can get */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) hash = rotate_xor(hash, &entropy, sizeof(entropy));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) #if defined(CONFIG_USE_OF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) /* Get any additional entropy passed in device tree */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) if (initial_boot_params) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) int node, len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) u64 *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) node = fdt_path_offset(initial_boot_params, "/chosen");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (node >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) prop = fdt_getprop_w(initial_boot_params, node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) "kaslr-seed", &len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) if (prop && (len == sizeof(u64)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) hash = rotate_xor(hash, prop, sizeof(*prop));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) #endif /* CONFIG_USE_OF */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return hash;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) static inline __init bool kaslr_disabled(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) char *str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) #if defined(CONFIG_CMDLINE_BOOL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) const char *builtin_cmdline = CONFIG_CMDLINE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) str = strstr(builtin_cmdline, "nokaslr");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) if (str == builtin_cmdline ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) (str > builtin_cmdline && *(str - 1) == ' '))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) str = strstr(arcs_cmdline, "nokaslr");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) if (str == arcs_cmdline || (str > arcs_cmdline && *(str - 1) == ' '))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) static inline void __init *determine_relocation_address(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) /* Choose a new address for the kernel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) unsigned long kernel_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) void *dest = &_text;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) unsigned long offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) if (kaslr_disabled())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) return dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) kernel_length = (long)_end - (long)(&_text);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) offset = get_random_boot() << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) offset &= (CONFIG_RANDOMIZE_BASE_MAX_OFFSET - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (offset < kernel_length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) offset += ALIGN(kernel_length, 0xffff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) return RELOCATED(dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) static inline void __init *determine_relocation_address(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) * Choose a new address for the kernel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) * For now we'll hard code the destination
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) return (void *)0xffffffff81000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) static inline int __init relocation_addr_valid(void *loc_new)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if ((unsigned long)loc_new & 0x0000ffff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) /* Inappropriately aligned new location */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) if ((unsigned long)loc_new < (unsigned long)&_end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) /* New location overlaps original kernel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) void *__init relocate_kernel(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) void *loc_new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) unsigned long kernel_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) unsigned long bss_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) long offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) int res = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) /* Default to original kernel entry point */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) void *kernel_entry = start_kernel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) void *fdt = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) /* Get the command line */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) fw_init_cmdline();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) #if defined(CONFIG_USE_OF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) /* Deal with the device tree */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) fdt = plat_get_fdt();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) early_init_dt_scan(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) if (boot_command_line[0]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) /* Boot command line was passed in device tree */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) #endif /* CONFIG_USE_OF */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) kernel_length = (long)(&_relocation_start) - (long)(&_text);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) bss_length = (long)&__bss_stop - (long)&__bss_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) loc_new = determine_relocation_address();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) /* Sanity check relocation address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) if (relocation_addr_valid(loc_new))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) offset = (unsigned long)loc_new - (unsigned long)(&_text);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) /* Reset the command line now so we don't end up with a duplicate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) arcs_cmdline[0] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) if (offset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) void (*fdt_relocated_)(void *) = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) #if defined(CONFIG_USE_OF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) unsigned long fdt_phys = virt_to_phys(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) * If built-in dtb is used then it will have been relocated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) * during kernel _text relocation. If appended DTB is used
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) * then it will not be relocated, but it should remain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) * intact in the original location. If dtb is loaded by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) * the bootloader then it may need to be moved if it crosses
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) * the target memory area
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) if (fdt_phys >= virt_to_phys(RELOCATED(&_text)) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) fdt_phys <= virt_to_phys(RELOCATED(&_end))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) void *fdt_relocated =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) RELOCATED(ALIGN((long)&_end, PAGE_SIZE));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) memcpy(fdt_relocated, fdt, fdt_totalsize(fdt));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) fdt = fdt_relocated;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) fdt_relocated_ = RELOCATED(&plat_fdt_relocated);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) #endif /* CONFIG_USE_OF */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) /* Copy the kernel to it's new location */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) memcpy(loc_new, &_text, kernel_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) /* Perform relocations on the new kernel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) res = do_relocations(&_text, loc_new, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) if (res < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) /* Sync the caches ready for execution of new kernel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) sync_icache(loc_new, kernel_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) res = relocate_exception_table(offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) if (res < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) * The original .bss has already been cleared, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) * some variables such as command line parameters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) * stored to it so make a copy in the new location.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) memcpy(RELOCATED(&__bss_start), &__bss_start, bss_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) * If fdt was stored outside of the kernel image and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) * had to be moved then update platform's state data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) * with the new fdt location
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) if (fdt_relocated_)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) fdt_relocated_(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) * Last chance for the platform to abort relocation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) * This may also be used by the platform to perform any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) * initialisation required now that the new kernel is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) * resident in memory and ready to be executed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) if (plat_post_relocation(offset))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) /* The current thread is now within the relocated image */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) __current_thread_info = RELOCATED(&init_thread_union);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) /* Return the new kernel's entry point */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) kernel_entry = RELOCATED(start_kernel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) return kernel_entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) * Show relocation information on panic.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) void show_kernel_relocation(const char *level)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) unsigned long offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) offset = __pa_symbol(_text) - __pa_symbol(VMLINUX_LOAD_ADDRESS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) if (IS_ENABLED(CONFIG_RELOCATABLE) && offset > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) printk(level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) pr_cont("Kernel relocated by 0x%pK\n", (void *)offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) pr_cont(" .text @ 0x%pK\n", _text);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) pr_cont(" .data @ 0x%pK\n", _sdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) pr_cont(" .bss @ 0x%pK\n", __bss_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) static int kernel_location_notifier_fn(struct notifier_block *self,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) unsigned long v, void *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) show_kernel_relocation(KERN_EMERG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) static struct notifier_block kernel_location_notifier = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) .notifier_call = kernel_location_notifier_fn
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) static int __init register_kernel_offset_dumper(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) atomic_notifier_chain_register(&panic_notifier_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) &kernel_location_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) __initcall(register_kernel_offset_dumper);