162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// Copyright (C) 2019 Jason Yan <yanaijie@huawei.com> 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/kernel.h> 662306a36Sopenharmony_ci#include <linux/errno.h> 762306a36Sopenharmony_ci#include <linux/string.h> 862306a36Sopenharmony_ci#include <linux/types.h> 962306a36Sopenharmony_ci#include <linux/mm.h> 1062306a36Sopenharmony_ci#include <linux/swap.h> 1162306a36Sopenharmony_ci#include <linux/stddef.h> 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/memblock.h> 1562306a36Sopenharmony_ci#include <linux/libfdt.h> 1662306a36Sopenharmony_ci#include <linux/crash_core.h> 1762306a36Sopenharmony_ci#include <linux/of.h> 1862306a36Sopenharmony_ci#include <linux/of_fdt.h> 1962306a36Sopenharmony_ci#include <asm/cacheflush.h> 2062306a36Sopenharmony_ci#include <asm/kdump.h> 2162306a36Sopenharmony_ci#include <mm/mmu_decl.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct regions { 2462306a36Sopenharmony_ci unsigned long pa_start; 2562306a36Sopenharmony_ci unsigned long pa_end; 2662306a36Sopenharmony_ci unsigned long kernel_size; 2762306a36Sopenharmony_ci unsigned long dtb_start; 2862306a36Sopenharmony_ci unsigned long dtb_end; 2962306a36Sopenharmony_ci unsigned long initrd_start; 3062306a36Sopenharmony_ci unsigned long initrd_end; 3162306a36Sopenharmony_ci unsigned long crash_start; 3262306a36Sopenharmony_ci unsigned long crash_end; 3362306a36Sopenharmony_ci int reserved_mem; 3462306a36Sopenharmony_ci int reserved_mem_addr_cells; 3562306a36Sopenharmony_ci int reserved_mem_size_cells; 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistruct regions __initdata regions; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic __init void kaslr_get_cmdline(void *fdt) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci early_init_dt_scan_chosen(boot_command_line); 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic unsigned long __init rotate_xor(unsigned long hash, const void *area, 4662306a36Sopenharmony_ci size_t size) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci size_t i; 4962306a36Sopenharmony_ci const unsigned long *ptr = area; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci for (i = 0; i < size / sizeof(hash); i++) { 5262306a36Sopenharmony_ci /* Rotate by odd number of bits and XOR. */ 5362306a36Sopenharmony_ci hash = (hash << ((sizeof(hash) * 8) - 7)) | (hash >> 7); 5462306a36Sopenharmony_ci hash ^= ptr[i]; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci return hash; 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* Attempt to create a simple starting entropy. This can make it defferent for 6162306a36Sopenharmony_ci * every build but it is still not enough. Stronger entropy should 6262306a36Sopenharmony_ci * be added to make it change for every boot. 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_cistatic unsigned long __init get_boot_seed(void *fdt) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci unsigned long hash = 0; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci /* build-specific string for starting entropy. */ 6962306a36Sopenharmony_ci hash = rotate_xor(hash, linux_banner, strlen(linux_banner)); 7062306a36Sopenharmony_ci hash = rotate_xor(hash, fdt, fdt_totalsize(fdt)); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci return hash; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic __init u64 get_kaslr_seed(void *fdt) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci int node, len; 7862306a36Sopenharmony_ci fdt64_t *prop; 7962306a36Sopenharmony_ci u64 ret; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci node = fdt_path_offset(fdt, "/chosen"); 8262306a36Sopenharmony_ci if (node < 0) 8362306a36Sopenharmony_ci return 0; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci prop = fdt_getprop_w(fdt, node, "kaslr-seed", &len); 8662306a36Sopenharmony_ci if (!prop || len != sizeof(u64)) 8762306a36Sopenharmony_ci return 0; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci ret = fdt64_to_cpu(*prop); 9062306a36Sopenharmony_ci *prop = 0; 9162306a36Sopenharmony_ci return ret; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic __init bool regions_overlap(u32 s1, u32 e1, u32 s2, u32 e2) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci return e1 >= s2 && e2 >= s1; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic __init bool overlaps_reserved_region(const void *fdt, u32 start, 10062306a36Sopenharmony_ci u32 end) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci int subnode, len, i; 10362306a36Sopenharmony_ci u64 base, size; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* check for overlap with /memreserve/ entries */ 10662306a36Sopenharmony_ci for (i = 0; i < fdt_num_mem_rsv(fdt); i++) { 10762306a36Sopenharmony_ci if (fdt_get_mem_rsv(fdt, i, &base, &size) < 0) 10862306a36Sopenharmony_ci continue; 10962306a36Sopenharmony_ci if (regions_overlap(start, end, base, base + size)) 11062306a36Sopenharmony_ci return true; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (regions.reserved_mem < 0) 11462306a36Sopenharmony_ci return false; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* check for overlap with static reservations in /reserved-memory */ 11762306a36Sopenharmony_ci for (subnode = fdt_first_subnode(fdt, regions.reserved_mem); 11862306a36Sopenharmony_ci subnode >= 0; 11962306a36Sopenharmony_ci subnode = fdt_next_subnode(fdt, subnode)) { 12062306a36Sopenharmony_ci const fdt32_t *reg; 12162306a36Sopenharmony_ci u64 rsv_end; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci len = 0; 12462306a36Sopenharmony_ci reg = fdt_getprop(fdt, subnode, "reg", &len); 12562306a36Sopenharmony_ci while (len >= (regions.reserved_mem_addr_cells + 12662306a36Sopenharmony_ci regions.reserved_mem_size_cells)) { 12762306a36Sopenharmony_ci base = fdt32_to_cpu(reg[0]); 12862306a36Sopenharmony_ci if (regions.reserved_mem_addr_cells == 2) 12962306a36Sopenharmony_ci base = (base << 32) | fdt32_to_cpu(reg[1]); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci reg += regions.reserved_mem_addr_cells; 13262306a36Sopenharmony_ci len -= 4 * regions.reserved_mem_addr_cells; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci size = fdt32_to_cpu(reg[0]); 13562306a36Sopenharmony_ci if (regions.reserved_mem_size_cells == 2) 13662306a36Sopenharmony_ci size = (size << 32) | fdt32_to_cpu(reg[1]); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci reg += regions.reserved_mem_size_cells; 13962306a36Sopenharmony_ci len -= 4 * regions.reserved_mem_size_cells; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (base >= regions.pa_end) 14262306a36Sopenharmony_ci continue; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci rsv_end = min(base + size, (u64)U32_MAX); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (regions_overlap(start, end, base, rsv_end)) 14762306a36Sopenharmony_ci return true; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci return false; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic __init bool overlaps_region(const void *fdt, u32 start, 15462306a36Sopenharmony_ci u32 end) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci if (regions_overlap(start, end, __pa(_stext), __pa(_end))) 15762306a36Sopenharmony_ci return true; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (regions_overlap(start, end, regions.dtb_start, 16062306a36Sopenharmony_ci regions.dtb_end)) 16162306a36Sopenharmony_ci return true; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (regions_overlap(start, end, regions.initrd_start, 16462306a36Sopenharmony_ci regions.initrd_end)) 16562306a36Sopenharmony_ci return true; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (regions_overlap(start, end, regions.crash_start, 16862306a36Sopenharmony_ci regions.crash_end)) 16962306a36Sopenharmony_ci return true; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci return overlaps_reserved_region(fdt, start, end); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic void __init get_crash_kernel(void *fdt, unsigned long size) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci#ifdef CONFIG_CRASH_CORE 17762306a36Sopenharmony_ci unsigned long long crash_size, crash_base; 17862306a36Sopenharmony_ci int ret; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci ret = parse_crashkernel(boot_command_line, size, &crash_size, 18162306a36Sopenharmony_ci &crash_base); 18262306a36Sopenharmony_ci if (ret != 0 || crash_size == 0) 18362306a36Sopenharmony_ci return; 18462306a36Sopenharmony_ci if (crash_base == 0) 18562306a36Sopenharmony_ci crash_base = KDUMP_KERNELBASE; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci regions.crash_start = (unsigned long)crash_base; 18862306a36Sopenharmony_ci regions.crash_end = (unsigned long)(crash_base + crash_size); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci pr_debug("crash_base=0x%llx crash_size=0x%llx\n", crash_base, crash_size); 19162306a36Sopenharmony_ci#endif 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic void __init get_initrd_range(void *fdt) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci u64 start, end; 19762306a36Sopenharmony_ci int node, len; 19862306a36Sopenharmony_ci const __be32 *prop; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci node = fdt_path_offset(fdt, "/chosen"); 20162306a36Sopenharmony_ci if (node < 0) 20262306a36Sopenharmony_ci return; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci prop = fdt_getprop(fdt, node, "linux,initrd-start", &len); 20562306a36Sopenharmony_ci if (!prop) 20662306a36Sopenharmony_ci return; 20762306a36Sopenharmony_ci start = of_read_number(prop, len / 4); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci prop = fdt_getprop(fdt, node, "linux,initrd-end", &len); 21062306a36Sopenharmony_ci if (!prop) 21162306a36Sopenharmony_ci return; 21262306a36Sopenharmony_ci end = of_read_number(prop, len / 4); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci regions.initrd_start = (unsigned long)start; 21562306a36Sopenharmony_ci regions.initrd_end = (unsigned long)end; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci pr_debug("initrd_start=0x%llx initrd_end=0x%llx\n", start, end); 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic __init unsigned long get_usable_address(const void *fdt, 22162306a36Sopenharmony_ci unsigned long start, 22262306a36Sopenharmony_ci unsigned long offset) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci unsigned long pa; 22562306a36Sopenharmony_ci unsigned long pa_end; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci for (pa = offset; (long)pa > (long)start; pa -= SZ_16K) { 22862306a36Sopenharmony_ci pa_end = pa + regions.kernel_size; 22962306a36Sopenharmony_ci if (overlaps_region(fdt, pa, pa_end)) 23062306a36Sopenharmony_ci continue; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci return pa; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci return 0; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic __init void get_cell_sizes(const void *fdt, int node, int *addr_cells, 23862306a36Sopenharmony_ci int *size_cells) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci const int *prop; 24162306a36Sopenharmony_ci int len; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* 24462306a36Sopenharmony_ci * Retrieve the #address-cells and #size-cells properties 24562306a36Sopenharmony_ci * from the 'node', or use the default if not provided. 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_ci *addr_cells = *size_cells = 1; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci prop = fdt_getprop(fdt, node, "#address-cells", &len); 25062306a36Sopenharmony_ci if (len == 4) 25162306a36Sopenharmony_ci *addr_cells = fdt32_to_cpu(*prop); 25262306a36Sopenharmony_ci prop = fdt_getprop(fdt, node, "#size-cells", &len); 25362306a36Sopenharmony_ci if (len == 4) 25462306a36Sopenharmony_ci *size_cells = fdt32_to_cpu(*prop); 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic unsigned long __init kaslr_legal_offset(void *dt_ptr, unsigned long index, 25862306a36Sopenharmony_ci unsigned long offset) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci unsigned long koffset = 0; 26162306a36Sopenharmony_ci unsigned long start; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci while ((long)index >= 0) { 26462306a36Sopenharmony_ci offset = memstart_addr + index * SZ_64M + offset; 26562306a36Sopenharmony_ci start = memstart_addr + index * SZ_64M; 26662306a36Sopenharmony_ci koffset = get_usable_address(dt_ptr, start, offset); 26762306a36Sopenharmony_ci if (koffset) 26862306a36Sopenharmony_ci break; 26962306a36Sopenharmony_ci index--; 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (koffset != 0) 27362306a36Sopenharmony_ci koffset -= memstart_addr; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci return koffset; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic inline __init bool kaslr_disabled(void) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci return strstr(boot_command_line, "nokaslr") != NULL; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic unsigned long __init kaslr_choose_location(void *dt_ptr, phys_addr_t size, 28462306a36Sopenharmony_ci unsigned long kernel_sz) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci unsigned long offset, random; 28762306a36Sopenharmony_ci unsigned long ram, linear_sz; 28862306a36Sopenharmony_ci u64 seed; 28962306a36Sopenharmony_ci unsigned long index; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci kaslr_get_cmdline(dt_ptr); 29262306a36Sopenharmony_ci if (kaslr_disabled()) 29362306a36Sopenharmony_ci return 0; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci random = get_boot_seed(dt_ptr); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci seed = get_tb() << 32; 29862306a36Sopenharmony_ci seed ^= get_tb(); 29962306a36Sopenharmony_ci random = rotate_xor(random, &seed, sizeof(seed)); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* 30262306a36Sopenharmony_ci * Retrieve (and wipe) the seed from the FDT 30362306a36Sopenharmony_ci */ 30462306a36Sopenharmony_ci seed = get_kaslr_seed(dt_ptr); 30562306a36Sopenharmony_ci if (seed) 30662306a36Sopenharmony_ci random = rotate_xor(random, &seed, sizeof(seed)); 30762306a36Sopenharmony_ci else 30862306a36Sopenharmony_ci pr_warn("KASLR: No safe seed for randomizing the kernel base.\n"); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci ram = min_t(phys_addr_t, __max_low_memory, size); 31162306a36Sopenharmony_ci ram = map_mem_in_cams(ram, CONFIG_LOWMEM_CAM_NUM, true, true); 31262306a36Sopenharmony_ci linear_sz = min_t(unsigned long, ram, SZ_512M); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* If the linear size is smaller than 64M, do not randomize */ 31562306a36Sopenharmony_ci if (linear_sz < SZ_64M) 31662306a36Sopenharmony_ci return 0; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* check for a reserved-memory node and record its cell sizes */ 31962306a36Sopenharmony_ci regions.reserved_mem = fdt_path_offset(dt_ptr, "/reserved-memory"); 32062306a36Sopenharmony_ci if (regions.reserved_mem >= 0) 32162306a36Sopenharmony_ci get_cell_sizes(dt_ptr, regions.reserved_mem, 32262306a36Sopenharmony_ci ®ions.reserved_mem_addr_cells, 32362306a36Sopenharmony_ci ®ions.reserved_mem_size_cells); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci regions.pa_start = memstart_addr; 32662306a36Sopenharmony_ci regions.pa_end = memstart_addr + linear_sz; 32762306a36Sopenharmony_ci regions.dtb_start = __pa(dt_ptr); 32862306a36Sopenharmony_ci regions.dtb_end = __pa(dt_ptr) + fdt_totalsize(dt_ptr); 32962306a36Sopenharmony_ci regions.kernel_size = kernel_sz; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci get_initrd_range(dt_ptr); 33262306a36Sopenharmony_ci get_crash_kernel(dt_ptr, ram); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci /* 33562306a36Sopenharmony_ci * Decide which 64M we want to start 33662306a36Sopenharmony_ci * Only use the low 8 bits of the random seed 33762306a36Sopenharmony_ci */ 33862306a36Sopenharmony_ci index = random & 0xFF; 33962306a36Sopenharmony_ci index %= linear_sz / SZ_64M; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* Decide offset inside 64M */ 34262306a36Sopenharmony_ci offset = random % (SZ_64M - kernel_sz); 34362306a36Sopenharmony_ci offset = round_down(offset, SZ_16K); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci return kaslr_legal_offset(dt_ptr, index, offset); 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci/* 34962306a36Sopenharmony_ci * To see if we need to relocate the kernel to a random offset 35062306a36Sopenharmony_ci * void *dt_ptr - address of the device tree 35162306a36Sopenharmony_ci * phys_addr_t size - size of the first memory block 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_cinotrace void __init kaslr_early_init(void *dt_ptr, phys_addr_t size) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci unsigned long tlb_virt; 35662306a36Sopenharmony_ci phys_addr_t tlb_phys; 35762306a36Sopenharmony_ci unsigned long offset; 35862306a36Sopenharmony_ci unsigned long kernel_sz; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci kernel_sz = (unsigned long)_end - (unsigned long)_stext; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci offset = kaslr_choose_location(dt_ptr, size, kernel_sz); 36362306a36Sopenharmony_ci if (offset == 0) 36462306a36Sopenharmony_ci return; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci kernstart_virt_addr += offset; 36762306a36Sopenharmony_ci kernstart_addr += offset; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci is_second_reloc = 1; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (offset >= SZ_64M) { 37262306a36Sopenharmony_ci tlb_virt = round_down(kernstart_virt_addr, SZ_64M); 37362306a36Sopenharmony_ci tlb_phys = round_down(kernstart_addr, SZ_64M); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* Create kernel map to relocate in */ 37662306a36Sopenharmony_ci create_kaslr_tlb_entry(1, tlb_virt, tlb_phys); 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci /* Copy the kernel to it's new location and run */ 38062306a36Sopenharmony_ci memcpy((void *)kernstart_virt_addr, (void *)_stext, kernel_sz); 38162306a36Sopenharmony_ci flush_icache_range(kernstart_virt_addr, kernstart_virt_addr + kernel_sz); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci reloc_kernel_entry(dt_ptr, kernstart_virt_addr); 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_civoid __init kaslr_late_init(void) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci /* If randomized, clear the original kernel */ 38962306a36Sopenharmony_ci if (kernstart_virt_addr != KERNELBASE) { 39062306a36Sopenharmony_ci unsigned long kernel_sz; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci kernel_sz = (unsigned long)_end - kernstart_virt_addr; 39362306a36Sopenharmony_ci memzero_explicit((void *)KERNELBASE, kernel_sz); 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci} 396