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			       &regions.reserved_mem_addr_cells,
32362306a36Sopenharmony_ci			       &regions.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