18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Copyright (C) 2019 Jason Yan <yanaijie@huawei.com> 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <linux/kernel.h> 68c2ecf20Sopenharmony_ci#include <linux/errno.h> 78c2ecf20Sopenharmony_ci#include <linux/string.h> 88c2ecf20Sopenharmony_ci#include <linux/types.h> 98c2ecf20Sopenharmony_ci#include <linux/mm.h> 108c2ecf20Sopenharmony_ci#include <linux/swap.h> 118c2ecf20Sopenharmony_ci#include <linux/stddef.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <linux/memblock.h> 158c2ecf20Sopenharmony_ci#include <linux/libfdt.h> 168c2ecf20Sopenharmony_ci#include <linux/crash_core.h> 178c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 188c2ecf20Sopenharmony_ci#include <asm/prom.h> 198c2ecf20Sopenharmony_ci#include <asm/kdump.h> 208c2ecf20Sopenharmony_ci#include <mm/mmu_decl.h> 218c2ecf20Sopenharmony_ci#include <generated/utsrelease.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistruct regions { 248c2ecf20Sopenharmony_ci unsigned long pa_start; 258c2ecf20Sopenharmony_ci unsigned long pa_end; 268c2ecf20Sopenharmony_ci unsigned long kernel_size; 278c2ecf20Sopenharmony_ci unsigned long dtb_start; 288c2ecf20Sopenharmony_ci unsigned long dtb_end; 298c2ecf20Sopenharmony_ci unsigned long initrd_start; 308c2ecf20Sopenharmony_ci unsigned long initrd_end; 318c2ecf20Sopenharmony_ci unsigned long crash_start; 328c2ecf20Sopenharmony_ci unsigned long crash_end; 338c2ecf20Sopenharmony_ci int reserved_mem; 348c2ecf20Sopenharmony_ci int reserved_mem_addr_cells; 358c2ecf20Sopenharmony_ci int reserved_mem_size_cells; 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistruct regions __initdata regions; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic __init void kaslr_get_cmdline(void *fdt) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci int node = fdt_path_offset(fdt, "/chosen"); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci early_init_dt_scan_chosen(node, "chosen", 1, boot_command_line); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic unsigned long __init rotate_xor(unsigned long hash, const void *area, 488c2ecf20Sopenharmony_ci size_t size) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci size_t i; 518c2ecf20Sopenharmony_ci const unsigned long *ptr = area; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci for (i = 0; i < size / sizeof(hash); i++) { 548c2ecf20Sopenharmony_ci /* Rotate by odd number of bits and XOR. */ 558c2ecf20Sopenharmony_ci hash = (hash << ((sizeof(hash) * 8) - 7)) | (hash >> 7); 568c2ecf20Sopenharmony_ci hash ^= ptr[i]; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return hash; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* Attempt to create a simple starting entropy. This can make it defferent for 638c2ecf20Sopenharmony_ci * every build but it is still not enough. Stronger entropy should 648c2ecf20Sopenharmony_ci * be added to make it change for every boot. 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_cistatic unsigned long __init get_boot_seed(void *fdt) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci unsigned long hash = 0; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* build-specific string for starting entropy. */ 718c2ecf20Sopenharmony_ci hash = rotate_xor(hash, linux_banner, strlen(linux_banner)); 728c2ecf20Sopenharmony_ci hash = rotate_xor(hash, fdt, fdt_totalsize(fdt)); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return hash; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic __init u64 get_kaslr_seed(void *fdt) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci int node, len; 808c2ecf20Sopenharmony_ci fdt64_t *prop; 818c2ecf20Sopenharmony_ci u64 ret; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci node = fdt_path_offset(fdt, "/chosen"); 848c2ecf20Sopenharmony_ci if (node < 0) 858c2ecf20Sopenharmony_ci return 0; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci prop = fdt_getprop_w(fdt, node, "kaslr-seed", &len); 888c2ecf20Sopenharmony_ci if (!prop || len != sizeof(u64)) 898c2ecf20Sopenharmony_ci return 0; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci ret = fdt64_to_cpu(*prop); 928c2ecf20Sopenharmony_ci *prop = 0; 938c2ecf20Sopenharmony_ci return ret; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic __init bool regions_overlap(u32 s1, u32 e1, u32 s2, u32 e2) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci return e1 >= s2 && e2 >= s1; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic __init bool overlaps_reserved_region(const void *fdt, u32 start, 1028c2ecf20Sopenharmony_ci u32 end) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci int subnode, len, i; 1058c2ecf20Sopenharmony_ci u64 base, size; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* check for overlap with /memreserve/ entries */ 1088c2ecf20Sopenharmony_ci for (i = 0; i < fdt_num_mem_rsv(fdt); i++) { 1098c2ecf20Sopenharmony_ci if (fdt_get_mem_rsv(fdt, i, &base, &size) < 0) 1108c2ecf20Sopenharmony_ci continue; 1118c2ecf20Sopenharmony_ci if (regions_overlap(start, end, base, base + size)) 1128c2ecf20Sopenharmony_ci return true; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (regions.reserved_mem < 0) 1168c2ecf20Sopenharmony_ci return false; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* check for overlap with static reservations in /reserved-memory */ 1198c2ecf20Sopenharmony_ci for (subnode = fdt_first_subnode(fdt, regions.reserved_mem); 1208c2ecf20Sopenharmony_ci subnode >= 0; 1218c2ecf20Sopenharmony_ci subnode = fdt_next_subnode(fdt, subnode)) { 1228c2ecf20Sopenharmony_ci const fdt32_t *reg; 1238c2ecf20Sopenharmony_ci u64 rsv_end; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci len = 0; 1268c2ecf20Sopenharmony_ci reg = fdt_getprop(fdt, subnode, "reg", &len); 1278c2ecf20Sopenharmony_ci while (len >= (regions.reserved_mem_addr_cells + 1288c2ecf20Sopenharmony_ci regions.reserved_mem_size_cells)) { 1298c2ecf20Sopenharmony_ci base = fdt32_to_cpu(reg[0]); 1308c2ecf20Sopenharmony_ci if (regions.reserved_mem_addr_cells == 2) 1318c2ecf20Sopenharmony_ci base = (base << 32) | fdt32_to_cpu(reg[1]); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci reg += regions.reserved_mem_addr_cells; 1348c2ecf20Sopenharmony_ci len -= 4 * regions.reserved_mem_addr_cells; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci size = fdt32_to_cpu(reg[0]); 1378c2ecf20Sopenharmony_ci if (regions.reserved_mem_size_cells == 2) 1388c2ecf20Sopenharmony_ci size = (size << 32) | fdt32_to_cpu(reg[1]); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci reg += regions.reserved_mem_size_cells; 1418c2ecf20Sopenharmony_ci len -= 4 * regions.reserved_mem_size_cells; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (base >= regions.pa_end) 1448c2ecf20Sopenharmony_ci continue; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci rsv_end = min(base + size, (u64)U32_MAX); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (regions_overlap(start, end, base, rsv_end)) 1498c2ecf20Sopenharmony_ci return true; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci return false; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic __init bool overlaps_region(const void *fdt, u32 start, 1568c2ecf20Sopenharmony_ci u32 end) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci if (regions_overlap(start, end, __pa(_stext), __pa(_end))) 1598c2ecf20Sopenharmony_ci return true; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (regions_overlap(start, end, regions.dtb_start, 1628c2ecf20Sopenharmony_ci regions.dtb_end)) 1638c2ecf20Sopenharmony_ci return true; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (regions_overlap(start, end, regions.initrd_start, 1668c2ecf20Sopenharmony_ci regions.initrd_end)) 1678c2ecf20Sopenharmony_ci return true; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (regions_overlap(start, end, regions.crash_start, 1708c2ecf20Sopenharmony_ci regions.crash_end)) 1718c2ecf20Sopenharmony_ci return true; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return overlaps_reserved_region(fdt, start, end); 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic void __init get_crash_kernel(void *fdt, unsigned long size) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci#ifdef CONFIG_CRASH_CORE 1798c2ecf20Sopenharmony_ci unsigned long long crash_size, crash_base; 1808c2ecf20Sopenharmony_ci int ret; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci ret = parse_crashkernel(boot_command_line, size, &crash_size, 1838c2ecf20Sopenharmony_ci &crash_base); 1848c2ecf20Sopenharmony_ci if (ret != 0 || crash_size == 0) 1858c2ecf20Sopenharmony_ci return; 1868c2ecf20Sopenharmony_ci if (crash_base == 0) 1878c2ecf20Sopenharmony_ci crash_base = KDUMP_KERNELBASE; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci regions.crash_start = (unsigned long)crash_base; 1908c2ecf20Sopenharmony_ci regions.crash_end = (unsigned long)(crash_base + crash_size); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci pr_debug("crash_base=0x%llx crash_size=0x%llx\n", crash_base, crash_size); 1938c2ecf20Sopenharmony_ci#endif 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic void __init get_initrd_range(void *fdt) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci u64 start, end; 1998c2ecf20Sopenharmony_ci int node, len; 2008c2ecf20Sopenharmony_ci const __be32 *prop; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci node = fdt_path_offset(fdt, "/chosen"); 2038c2ecf20Sopenharmony_ci if (node < 0) 2048c2ecf20Sopenharmony_ci return; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci prop = fdt_getprop(fdt, node, "linux,initrd-start", &len); 2078c2ecf20Sopenharmony_ci if (!prop) 2088c2ecf20Sopenharmony_ci return; 2098c2ecf20Sopenharmony_ci start = of_read_number(prop, len / 4); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci prop = fdt_getprop(fdt, node, "linux,initrd-end", &len); 2128c2ecf20Sopenharmony_ci if (!prop) 2138c2ecf20Sopenharmony_ci return; 2148c2ecf20Sopenharmony_ci end = of_read_number(prop, len / 4); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci regions.initrd_start = (unsigned long)start; 2178c2ecf20Sopenharmony_ci regions.initrd_end = (unsigned long)end; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci pr_debug("initrd_start=0x%llx initrd_end=0x%llx\n", start, end); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic __init unsigned long get_usable_address(const void *fdt, 2238c2ecf20Sopenharmony_ci unsigned long start, 2248c2ecf20Sopenharmony_ci unsigned long offset) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci unsigned long pa; 2278c2ecf20Sopenharmony_ci unsigned long pa_end; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci for (pa = offset; (long)pa > (long)start; pa -= SZ_16K) { 2308c2ecf20Sopenharmony_ci pa_end = pa + regions.kernel_size; 2318c2ecf20Sopenharmony_ci if (overlaps_region(fdt, pa, pa_end)) 2328c2ecf20Sopenharmony_ci continue; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci return pa; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci return 0; 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic __init void get_cell_sizes(const void *fdt, int node, int *addr_cells, 2408c2ecf20Sopenharmony_ci int *size_cells) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci const int *prop; 2438c2ecf20Sopenharmony_ci int len; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* 2468c2ecf20Sopenharmony_ci * Retrieve the #address-cells and #size-cells properties 2478c2ecf20Sopenharmony_ci * from the 'node', or use the default if not provided. 2488c2ecf20Sopenharmony_ci */ 2498c2ecf20Sopenharmony_ci *addr_cells = *size_cells = 1; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci prop = fdt_getprop(fdt, node, "#address-cells", &len); 2528c2ecf20Sopenharmony_ci if (len == 4) 2538c2ecf20Sopenharmony_ci *addr_cells = fdt32_to_cpu(*prop); 2548c2ecf20Sopenharmony_ci prop = fdt_getprop(fdt, node, "#size-cells", &len); 2558c2ecf20Sopenharmony_ci if (len == 4) 2568c2ecf20Sopenharmony_ci *size_cells = fdt32_to_cpu(*prop); 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic unsigned long __init kaslr_legal_offset(void *dt_ptr, unsigned long index, 2608c2ecf20Sopenharmony_ci unsigned long offset) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci unsigned long koffset = 0; 2638c2ecf20Sopenharmony_ci unsigned long start; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci while ((long)index >= 0) { 2668c2ecf20Sopenharmony_ci offset = memstart_addr + index * SZ_64M + offset; 2678c2ecf20Sopenharmony_ci start = memstart_addr + index * SZ_64M; 2688c2ecf20Sopenharmony_ci koffset = get_usable_address(dt_ptr, start, offset); 2698c2ecf20Sopenharmony_ci if (koffset) 2708c2ecf20Sopenharmony_ci break; 2718c2ecf20Sopenharmony_ci index--; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (koffset != 0) 2758c2ecf20Sopenharmony_ci koffset -= memstart_addr; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci return koffset; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic inline __init bool kaslr_disabled(void) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci return strstr(boot_command_line, "nokaslr") != NULL; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic unsigned long __init kaslr_choose_location(void *dt_ptr, phys_addr_t size, 2868c2ecf20Sopenharmony_ci unsigned long kernel_sz) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci unsigned long offset, random; 2898c2ecf20Sopenharmony_ci unsigned long ram, linear_sz; 2908c2ecf20Sopenharmony_ci u64 seed; 2918c2ecf20Sopenharmony_ci unsigned long index; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci kaslr_get_cmdline(dt_ptr); 2948c2ecf20Sopenharmony_ci if (kaslr_disabled()) 2958c2ecf20Sopenharmony_ci return 0; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci random = get_boot_seed(dt_ptr); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci seed = get_tb() << 32; 3008c2ecf20Sopenharmony_ci seed ^= get_tb(); 3018c2ecf20Sopenharmony_ci random = rotate_xor(random, &seed, sizeof(seed)); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* 3048c2ecf20Sopenharmony_ci * Retrieve (and wipe) the seed from the FDT 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_ci seed = get_kaslr_seed(dt_ptr); 3078c2ecf20Sopenharmony_ci if (seed) 3088c2ecf20Sopenharmony_ci random = rotate_xor(random, &seed, sizeof(seed)); 3098c2ecf20Sopenharmony_ci else 3108c2ecf20Sopenharmony_ci pr_warn("KASLR: No safe seed for randomizing the kernel base.\n"); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci ram = min_t(phys_addr_t, __max_low_memory, size); 3138c2ecf20Sopenharmony_ci ram = map_mem_in_cams(ram, CONFIG_LOWMEM_CAM_NUM, true); 3148c2ecf20Sopenharmony_ci linear_sz = min_t(unsigned long, ram, SZ_512M); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci /* If the linear size is smaller than 64M, do not randmize */ 3178c2ecf20Sopenharmony_ci if (linear_sz < SZ_64M) 3188c2ecf20Sopenharmony_ci return 0; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* check for a reserved-memory node and record its cell sizes */ 3218c2ecf20Sopenharmony_ci regions.reserved_mem = fdt_path_offset(dt_ptr, "/reserved-memory"); 3228c2ecf20Sopenharmony_ci if (regions.reserved_mem >= 0) 3238c2ecf20Sopenharmony_ci get_cell_sizes(dt_ptr, regions.reserved_mem, 3248c2ecf20Sopenharmony_ci ®ions.reserved_mem_addr_cells, 3258c2ecf20Sopenharmony_ci ®ions.reserved_mem_size_cells); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci regions.pa_start = memstart_addr; 3288c2ecf20Sopenharmony_ci regions.pa_end = memstart_addr + linear_sz; 3298c2ecf20Sopenharmony_ci regions.dtb_start = __pa(dt_ptr); 3308c2ecf20Sopenharmony_ci regions.dtb_end = __pa(dt_ptr) + fdt_totalsize(dt_ptr); 3318c2ecf20Sopenharmony_ci regions.kernel_size = kernel_sz; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci get_initrd_range(dt_ptr); 3348c2ecf20Sopenharmony_ci get_crash_kernel(dt_ptr, ram); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* 3378c2ecf20Sopenharmony_ci * Decide which 64M we want to start 3388c2ecf20Sopenharmony_ci * Only use the low 8 bits of the random seed 3398c2ecf20Sopenharmony_ci */ 3408c2ecf20Sopenharmony_ci index = random & 0xFF; 3418c2ecf20Sopenharmony_ci index %= linear_sz / SZ_64M; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* Decide offset inside 64M */ 3448c2ecf20Sopenharmony_ci offset = random % (SZ_64M - kernel_sz); 3458c2ecf20Sopenharmony_ci offset = round_down(offset, SZ_16K); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci return kaslr_legal_offset(dt_ptr, index, offset); 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci/* 3518c2ecf20Sopenharmony_ci * To see if we need to relocate the kernel to a random offset 3528c2ecf20Sopenharmony_ci * void *dt_ptr - address of the device tree 3538c2ecf20Sopenharmony_ci * phys_addr_t size - size of the first memory block 3548c2ecf20Sopenharmony_ci */ 3558c2ecf20Sopenharmony_cinotrace void __init kaslr_early_init(void *dt_ptr, phys_addr_t size) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci unsigned long tlb_virt; 3588c2ecf20Sopenharmony_ci phys_addr_t tlb_phys; 3598c2ecf20Sopenharmony_ci unsigned long offset; 3608c2ecf20Sopenharmony_ci unsigned long kernel_sz; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci kernel_sz = (unsigned long)_end - (unsigned long)_stext; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci offset = kaslr_choose_location(dt_ptr, size, kernel_sz); 3658c2ecf20Sopenharmony_ci if (offset == 0) 3668c2ecf20Sopenharmony_ci return; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci kernstart_virt_addr += offset; 3698c2ecf20Sopenharmony_ci kernstart_addr += offset; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci is_second_reloc = 1; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (offset >= SZ_64M) { 3748c2ecf20Sopenharmony_ci tlb_virt = round_down(kernstart_virt_addr, SZ_64M); 3758c2ecf20Sopenharmony_ci tlb_phys = round_down(kernstart_addr, SZ_64M); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci /* Create kernel map to relocate in */ 3788c2ecf20Sopenharmony_ci create_kaslr_tlb_entry(1, tlb_virt, tlb_phys); 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* Copy the kernel to it's new location and run */ 3828c2ecf20Sopenharmony_ci memcpy((void *)kernstart_virt_addr, (void *)_stext, kernel_sz); 3838c2ecf20Sopenharmony_ci flush_icache_range(kernstart_virt_addr, kernstart_virt_addr + kernel_sz); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci reloc_kernel_entry(dt_ptr, kernstart_virt_addr); 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_civoid __init kaslr_late_init(void) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci /* If randomized, clear the original kernel */ 3918c2ecf20Sopenharmony_ci if (kernstart_virt_addr != KERNELBASE) { 3928c2ecf20Sopenharmony_ci unsigned long kernel_sz; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci kernel_sz = (unsigned long)_end - kernstart_virt_addr; 3958c2ecf20Sopenharmony_ci memzero_explicit((void *)KERNELBASE, kernel_sz); 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci} 398