12b0e86ccSJason Yan // SPDX-License-Identifier: GPL-2.0-only
22b0e86ccSJason Yan //
32b0e86ccSJason Yan // Copyright (C) 2019 Jason Yan <yanaijie@huawei.com>
42b0e86ccSJason Yan 
52b0e86ccSJason Yan #include <linux/kernel.h>
62b0e86ccSJason Yan #include <linux/errno.h>
72b0e86ccSJason Yan #include <linux/string.h>
82b0e86ccSJason Yan #include <linux/types.h>
92b0e86ccSJason Yan #include <linux/mm.h>
102b0e86ccSJason Yan #include <linux/swap.h>
112b0e86ccSJason Yan #include <linux/stddef.h>
122b0e86ccSJason Yan #include <linux/init.h>
132b0e86ccSJason Yan #include <linux/delay.h>
142b0e86ccSJason Yan #include <linux/memblock.h>
156a38ea1dSJason Yan #include <linux/libfdt.h>
166a38ea1dSJason Yan #include <linux/crash_core.h>
17cdf87d2bSYueHaibing #include <linux/of.h>
18cdf87d2bSYueHaibing #include <linux/of_fdt.h>
197e4773f7SArseny Solokha #include <asm/cacheflush.h>
206a38ea1dSJason Yan #include <asm/kdump.h>
212b0e86ccSJason Yan #include <mm/mmu_decl.h>
226a38ea1dSJason Yan 
236a38ea1dSJason Yan struct regions {
246a38ea1dSJason Yan 	unsigned long pa_start;
256a38ea1dSJason Yan 	unsigned long pa_end;
266a38ea1dSJason Yan 	unsigned long kernel_size;
276a38ea1dSJason Yan 	unsigned long dtb_start;
286a38ea1dSJason Yan 	unsigned long dtb_end;
296a38ea1dSJason Yan 	unsigned long initrd_start;
306a38ea1dSJason Yan 	unsigned long initrd_end;
316a38ea1dSJason Yan 	unsigned long crash_start;
326a38ea1dSJason Yan 	unsigned long crash_end;
336a38ea1dSJason Yan 	int reserved_mem;
346a38ea1dSJason Yan 	int reserved_mem_addr_cells;
356a38ea1dSJason Yan 	int reserved_mem_size_cells;
366a38ea1dSJason Yan };
376a38ea1dSJason Yan 
386a38ea1dSJason Yan struct regions __initdata regions;
396a38ea1dSJason Yan 
kaslr_get_cmdline(void * fdt)406a38ea1dSJason Yan static __init void kaslr_get_cmdline(void *fdt)
416a38ea1dSJason Yan {
4260f20d84SRob Herring 	early_init_dt_scan_chosen(boot_command_line);
436a38ea1dSJason Yan }
446a38ea1dSJason Yan 
rotate_xor(unsigned long hash,const void * area,size_t size)456a38ea1dSJason Yan static unsigned long __init rotate_xor(unsigned long hash, const void *area,
466a38ea1dSJason Yan 				       size_t size)
476a38ea1dSJason Yan {
486a38ea1dSJason Yan 	size_t i;
496a38ea1dSJason Yan 	const unsigned long *ptr = area;
506a38ea1dSJason Yan 
516a38ea1dSJason Yan 	for (i = 0; i < size / sizeof(hash); i++) {
526a38ea1dSJason Yan 		/* Rotate by odd number of bits and XOR. */
536a38ea1dSJason Yan 		hash = (hash << ((sizeof(hash) * 8) - 7)) | (hash >> 7);
546a38ea1dSJason Yan 		hash ^= ptr[i];
556a38ea1dSJason Yan 	}
566a38ea1dSJason Yan 
576a38ea1dSJason Yan 	return hash;
586a38ea1dSJason Yan }
596a38ea1dSJason Yan 
606a38ea1dSJason Yan /* Attempt to create a simple starting entropy. This can make it defferent for
616a38ea1dSJason Yan  * every build but it is still not enough. Stronger entropy should
626a38ea1dSJason Yan  * be added to make it change for every boot.
636a38ea1dSJason Yan  */
get_boot_seed(void * fdt)646a38ea1dSJason Yan static unsigned long __init get_boot_seed(void *fdt)
656a38ea1dSJason Yan {
666a38ea1dSJason Yan 	unsigned long hash = 0;
676a38ea1dSJason Yan 
68*7ad4bd88SMasahiro Yamada 	/* build-specific string for starting entropy. */
69*7ad4bd88SMasahiro Yamada 	hash = rotate_xor(hash, linux_banner, strlen(linux_banner));
706a38ea1dSJason Yan 	hash = rotate_xor(hash, fdt, fdt_totalsize(fdt));
716a38ea1dSJason Yan 
726a38ea1dSJason Yan 	return hash;
736a38ea1dSJason Yan }
746a38ea1dSJason Yan 
get_kaslr_seed(void * fdt)756a38ea1dSJason Yan static __init u64 get_kaslr_seed(void *fdt)
766a38ea1dSJason Yan {
776a38ea1dSJason Yan 	int node, len;
786a38ea1dSJason Yan 	fdt64_t *prop;
796a38ea1dSJason Yan 	u64 ret;
806a38ea1dSJason Yan 
816a38ea1dSJason Yan 	node = fdt_path_offset(fdt, "/chosen");
826a38ea1dSJason Yan 	if (node < 0)
836a38ea1dSJason Yan 		return 0;
846a38ea1dSJason Yan 
856a38ea1dSJason Yan 	prop = fdt_getprop_w(fdt, node, "kaslr-seed", &len);
866a38ea1dSJason Yan 	if (!prop || len != sizeof(u64))
876a38ea1dSJason Yan 		return 0;
886a38ea1dSJason Yan 
896a38ea1dSJason Yan 	ret = fdt64_to_cpu(*prop);
906a38ea1dSJason Yan 	*prop = 0;
916a38ea1dSJason Yan 	return ret;
926a38ea1dSJason Yan }
936a38ea1dSJason Yan 
regions_overlap(u32 s1,u32 e1,u32 s2,u32 e2)946a38ea1dSJason Yan static __init bool regions_overlap(u32 s1, u32 e1, u32 s2, u32 e2)
956a38ea1dSJason Yan {
966a38ea1dSJason Yan 	return e1 >= s2 && e2 >= s1;
976a38ea1dSJason Yan }
986a38ea1dSJason Yan 
overlaps_reserved_region(const void * fdt,u32 start,u32 end)996a38ea1dSJason Yan static __init bool overlaps_reserved_region(const void *fdt, u32 start,
1006a38ea1dSJason Yan 					    u32 end)
1016a38ea1dSJason Yan {
1026a38ea1dSJason Yan 	int subnode, len, i;
1036a38ea1dSJason Yan 	u64 base, size;
1046a38ea1dSJason Yan 
1056a38ea1dSJason Yan 	/* check for overlap with /memreserve/ entries */
1066a38ea1dSJason Yan 	for (i = 0; i < fdt_num_mem_rsv(fdt); i++) {
1076a38ea1dSJason Yan 		if (fdt_get_mem_rsv(fdt, i, &base, &size) < 0)
1086a38ea1dSJason Yan 			continue;
1096a38ea1dSJason Yan 		if (regions_overlap(start, end, base, base + size))
1106a38ea1dSJason Yan 			return true;
1116a38ea1dSJason Yan 	}
1126a38ea1dSJason Yan 
1136a38ea1dSJason Yan 	if (regions.reserved_mem < 0)
1146a38ea1dSJason Yan 		return false;
1156a38ea1dSJason Yan 
1166a38ea1dSJason Yan 	/* check for overlap with static reservations in /reserved-memory */
1176a38ea1dSJason Yan 	for (subnode = fdt_first_subnode(fdt, regions.reserved_mem);
1186a38ea1dSJason Yan 	     subnode >= 0;
1196a38ea1dSJason Yan 	     subnode = fdt_next_subnode(fdt, subnode)) {
1206a38ea1dSJason Yan 		const fdt32_t *reg;
1216a38ea1dSJason Yan 		u64 rsv_end;
1226a38ea1dSJason Yan 
1236a38ea1dSJason Yan 		len = 0;
1246a38ea1dSJason Yan 		reg = fdt_getprop(fdt, subnode, "reg", &len);
1256a38ea1dSJason Yan 		while (len >= (regions.reserved_mem_addr_cells +
1266a38ea1dSJason Yan 			       regions.reserved_mem_size_cells)) {
1276a38ea1dSJason Yan 			base = fdt32_to_cpu(reg[0]);
1286a38ea1dSJason Yan 			if (regions.reserved_mem_addr_cells == 2)
1296a38ea1dSJason Yan 				base = (base << 32) | fdt32_to_cpu(reg[1]);
1306a38ea1dSJason Yan 
1316a38ea1dSJason Yan 			reg += regions.reserved_mem_addr_cells;
1326a38ea1dSJason Yan 			len -= 4 * regions.reserved_mem_addr_cells;
1336a38ea1dSJason Yan 
1346a38ea1dSJason Yan 			size = fdt32_to_cpu(reg[0]);
1356a38ea1dSJason Yan 			if (regions.reserved_mem_size_cells == 2)
1366a38ea1dSJason Yan 				size = (size << 32) | fdt32_to_cpu(reg[1]);
1376a38ea1dSJason Yan 
1386a38ea1dSJason Yan 			reg += regions.reserved_mem_size_cells;
1396a38ea1dSJason Yan 			len -= 4 * regions.reserved_mem_size_cells;
1406a38ea1dSJason Yan 
1416a38ea1dSJason Yan 			if (base >= regions.pa_end)
1426a38ea1dSJason Yan 				continue;
1436a38ea1dSJason Yan 
1446a38ea1dSJason Yan 			rsv_end = min(base + size, (u64)U32_MAX);
1456a38ea1dSJason Yan 
1466a38ea1dSJason Yan 			if (regions_overlap(start, end, base, rsv_end))
1476a38ea1dSJason Yan 				return true;
1486a38ea1dSJason Yan 		}
1496a38ea1dSJason Yan 	}
1506a38ea1dSJason Yan 	return false;
1516a38ea1dSJason Yan }
1526a38ea1dSJason Yan 
overlaps_region(const void * fdt,u32 start,u32 end)1536a38ea1dSJason Yan static __init bool overlaps_region(const void *fdt, u32 start,
1546a38ea1dSJason Yan 				   u32 end)
1556a38ea1dSJason Yan {
1566a38ea1dSJason Yan 	if (regions_overlap(start, end, __pa(_stext), __pa(_end)))
1576a38ea1dSJason Yan 		return true;
1586a38ea1dSJason Yan 
1596a38ea1dSJason Yan 	if (regions_overlap(start, end, regions.dtb_start,
1606a38ea1dSJason Yan 			    regions.dtb_end))
1616a38ea1dSJason Yan 		return true;
1626a38ea1dSJason Yan 
1636a38ea1dSJason Yan 	if (regions_overlap(start, end, regions.initrd_start,
1646a38ea1dSJason Yan 			    regions.initrd_end))
1656a38ea1dSJason Yan 		return true;
1666a38ea1dSJason Yan 
1676a38ea1dSJason Yan 	if (regions_overlap(start, end, regions.crash_start,
1686a38ea1dSJason Yan 			    regions.crash_end))
1696a38ea1dSJason Yan 		return true;
1706a38ea1dSJason Yan 
1716a38ea1dSJason Yan 	return overlaps_reserved_region(fdt, start, end);
1726a38ea1dSJason Yan }
1736a38ea1dSJason Yan 
get_crash_kernel(void * fdt,unsigned long size)1746a38ea1dSJason Yan static void __init get_crash_kernel(void *fdt, unsigned long size)
1756a38ea1dSJason Yan {
1766a38ea1dSJason Yan #ifdef CONFIG_CRASH_CORE
1776a38ea1dSJason Yan 	unsigned long long crash_size, crash_base;
1786a38ea1dSJason Yan 	int ret;
1796a38ea1dSJason Yan 
1806a38ea1dSJason Yan 	ret = parse_crashkernel(boot_command_line, size, &crash_size,
1816a38ea1dSJason Yan 				&crash_base);
1826a38ea1dSJason Yan 	if (ret != 0 || crash_size == 0)
1836a38ea1dSJason Yan 		return;
1846a38ea1dSJason Yan 	if (crash_base == 0)
1856a38ea1dSJason Yan 		crash_base = KDUMP_KERNELBASE;
1866a38ea1dSJason Yan 
1876a38ea1dSJason Yan 	regions.crash_start = (unsigned long)crash_base;
1886a38ea1dSJason Yan 	regions.crash_end = (unsigned long)(crash_base + crash_size);
1896a38ea1dSJason Yan 
1906a38ea1dSJason Yan 	pr_debug("crash_base=0x%llx crash_size=0x%llx\n", crash_base, crash_size);
1916a38ea1dSJason Yan #endif
1926a38ea1dSJason Yan }
1936a38ea1dSJason Yan 
get_initrd_range(void * fdt)1946a38ea1dSJason Yan static void __init get_initrd_range(void *fdt)
1956a38ea1dSJason Yan {
1966a38ea1dSJason Yan 	u64 start, end;
1976a38ea1dSJason Yan 	int node, len;
1986a38ea1dSJason Yan 	const __be32 *prop;
1996a38ea1dSJason Yan 
2006a38ea1dSJason Yan 	node = fdt_path_offset(fdt, "/chosen");
2016a38ea1dSJason Yan 	if (node < 0)
2026a38ea1dSJason Yan 		return;
2036a38ea1dSJason Yan 
2046a38ea1dSJason Yan 	prop = fdt_getprop(fdt, node, "linux,initrd-start", &len);
2056a38ea1dSJason Yan 	if (!prop)
2066a38ea1dSJason Yan 		return;
2076a38ea1dSJason Yan 	start = of_read_number(prop, len / 4);
2086a38ea1dSJason Yan 
2096a38ea1dSJason Yan 	prop = fdt_getprop(fdt, node, "linux,initrd-end", &len);
2106a38ea1dSJason Yan 	if (!prop)
2116a38ea1dSJason Yan 		return;
2126a38ea1dSJason Yan 	end = of_read_number(prop, len / 4);
2136a38ea1dSJason Yan 
2146a38ea1dSJason Yan 	regions.initrd_start = (unsigned long)start;
2156a38ea1dSJason Yan 	regions.initrd_end = (unsigned long)end;
2166a38ea1dSJason Yan 
2176a38ea1dSJason Yan 	pr_debug("initrd_start=0x%llx  initrd_end=0x%llx\n", start, end);
2186a38ea1dSJason Yan }
2196a38ea1dSJason Yan 
get_usable_address(const void * fdt,unsigned long start,unsigned long offset)2206a38ea1dSJason Yan static __init unsigned long get_usable_address(const void *fdt,
2216a38ea1dSJason Yan 					       unsigned long start,
2226a38ea1dSJason Yan 					       unsigned long offset)
2236a38ea1dSJason Yan {
2246a38ea1dSJason Yan 	unsigned long pa;
2256a38ea1dSJason Yan 	unsigned long pa_end;
2266a38ea1dSJason Yan 
2276a38ea1dSJason Yan 	for (pa = offset; (long)pa > (long)start; pa -= SZ_16K) {
2286a38ea1dSJason Yan 		pa_end = pa + regions.kernel_size;
2296a38ea1dSJason Yan 		if (overlaps_region(fdt, pa, pa_end))
2306a38ea1dSJason Yan 			continue;
2316a38ea1dSJason Yan 
2326a38ea1dSJason Yan 		return pa;
2336a38ea1dSJason Yan 	}
2346a38ea1dSJason Yan 	return 0;
2356a38ea1dSJason Yan }
2366a38ea1dSJason Yan 
get_cell_sizes(const void * fdt,int node,int * addr_cells,int * size_cells)2376a38ea1dSJason Yan static __init void get_cell_sizes(const void *fdt, int node, int *addr_cells,
2386a38ea1dSJason Yan 				  int *size_cells)
2396a38ea1dSJason Yan {
2406a38ea1dSJason Yan 	const int *prop;
2416a38ea1dSJason Yan 	int len;
2426a38ea1dSJason Yan 
2436a38ea1dSJason Yan 	/*
2446a38ea1dSJason Yan 	 * Retrieve the #address-cells and #size-cells properties
2456a38ea1dSJason Yan 	 * from the 'node', or use the default if not provided.
2466a38ea1dSJason Yan 	 */
2476a38ea1dSJason Yan 	*addr_cells = *size_cells = 1;
2486a38ea1dSJason Yan 
2496a38ea1dSJason Yan 	prop = fdt_getprop(fdt, node, "#address-cells", &len);
2506a38ea1dSJason Yan 	if (len == 4)
2516a38ea1dSJason Yan 		*addr_cells = fdt32_to_cpu(*prop);
2526a38ea1dSJason Yan 	prop = fdt_getprop(fdt, node, "#size-cells", &len);
2536a38ea1dSJason Yan 	if (len == 4)
2546a38ea1dSJason Yan 		*size_cells = fdt32_to_cpu(*prop);
2556a38ea1dSJason Yan }
2566a38ea1dSJason Yan 
kaslr_legal_offset(void * dt_ptr,unsigned long index,unsigned long offset)2576a38ea1dSJason Yan static unsigned long __init kaslr_legal_offset(void *dt_ptr, unsigned long index,
2586a38ea1dSJason Yan 					       unsigned long offset)
2596a38ea1dSJason Yan {
2606a38ea1dSJason Yan 	unsigned long koffset = 0;
2616a38ea1dSJason Yan 	unsigned long start;
2626a38ea1dSJason Yan 
2636a38ea1dSJason Yan 	while ((long)index >= 0) {
2646a38ea1dSJason Yan 		offset = memstart_addr + index * SZ_64M + offset;
2656a38ea1dSJason Yan 		start = memstart_addr + index * SZ_64M;
2666a38ea1dSJason Yan 		koffset = get_usable_address(dt_ptr, start, offset);
2676a38ea1dSJason Yan 		if (koffset)
2686a38ea1dSJason Yan 			break;
2696a38ea1dSJason Yan 		index--;
2706a38ea1dSJason Yan 	}
2716a38ea1dSJason Yan 
2726a38ea1dSJason Yan 	if (koffset != 0)
2736a38ea1dSJason Yan 		koffset -= memstart_addr;
2746a38ea1dSJason Yan 
2756a38ea1dSJason Yan 	return koffset;
2766a38ea1dSJason Yan }
2772b0e86ccSJason Yan 
kaslr_disabled(void)2788c2ae87bSJason Yan static inline __init bool kaslr_disabled(void)
2798c2ae87bSJason Yan {
2808c2ae87bSJason Yan 	return strstr(boot_command_line, "nokaslr") != NULL;
2818c2ae87bSJason Yan }
2828c2ae87bSJason Yan 
kaslr_choose_location(void * dt_ptr,phys_addr_t size,unsigned long kernel_sz)2832b0e86ccSJason Yan static unsigned long __init kaslr_choose_location(void *dt_ptr, phys_addr_t size,
2842b0e86ccSJason Yan 						  unsigned long kernel_sz)
2852b0e86ccSJason Yan {
2866a38ea1dSJason Yan 	unsigned long offset, random;
2876a38ea1dSJason Yan 	unsigned long ram, linear_sz;
2886a38ea1dSJason Yan 	u64 seed;
2896a38ea1dSJason Yan 	unsigned long index;
2906a38ea1dSJason Yan 
2916a38ea1dSJason Yan 	kaslr_get_cmdline(dt_ptr);
2928c2ae87bSJason Yan 	if (kaslr_disabled())
2938c2ae87bSJason Yan 		return 0;
2946a38ea1dSJason Yan 
2956a38ea1dSJason Yan 	random = get_boot_seed(dt_ptr);
2966a38ea1dSJason Yan 
2976a38ea1dSJason Yan 	seed = get_tb() << 32;
2986a38ea1dSJason Yan 	seed ^= get_tb();
2996a38ea1dSJason Yan 	random = rotate_xor(random, &seed, sizeof(seed));
3006a38ea1dSJason Yan 
3016a38ea1dSJason Yan 	/*
3026a38ea1dSJason Yan 	 * Retrieve (and wipe) the seed from the FDT
3036a38ea1dSJason Yan 	 */
3046a38ea1dSJason Yan 	seed = get_kaslr_seed(dt_ptr);
3056a38ea1dSJason Yan 	if (seed)
3066a38ea1dSJason Yan 		random = rotate_xor(random, &seed, sizeof(seed));
3076a38ea1dSJason Yan 	else
3086a38ea1dSJason Yan 		pr_warn("KASLR: No safe seed for randomizing the kernel base.\n");
3096a38ea1dSJason Yan 
3106a38ea1dSJason Yan 	ram = min_t(phys_addr_t, __max_low_memory, size);
3115b548609SChristophe Leroy 	ram = map_mem_in_cams(ram, CONFIG_LOWMEM_CAM_NUM, true, true);
3126a38ea1dSJason Yan 	linear_sz = min_t(unsigned long, ram, SZ_512M);
3136a38ea1dSJason Yan 
3141fd02f66SJulia Lawall 	/* If the linear size is smaller than 64M, do not randomize */
3156a38ea1dSJason Yan 	if (linear_sz < SZ_64M)
3166a38ea1dSJason Yan 		return 0;
3176a38ea1dSJason Yan 
3186a38ea1dSJason Yan 	/* check for a reserved-memory node and record its cell sizes */
3196a38ea1dSJason Yan 	regions.reserved_mem = fdt_path_offset(dt_ptr, "/reserved-memory");
3206a38ea1dSJason Yan 	if (regions.reserved_mem >= 0)
3216a38ea1dSJason Yan 		get_cell_sizes(dt_ptr, regions.reserved_mem,
3226a38ea1dSJason Yan 			       &regions.reserved_mem_addr_cells,
3236a38ea1dSJason Yan 			       &regions.reserved_mem_size_cells);
3246a38ea1dSJason Yan 
3256a38ea1dSJason Yan 	regions.pa_start = memstart_addr;
3266a38ea1dSJason Yan 	regions.pa_end = memstart_addr + linear_sz;
3276a38ea1dSJason Yan 	regions.dtb_start = __pa(dt_ptr);
3286a38ea1dSJason Yan 	regions.dtb_end = __pa(dt_ptr) + fdt_totalsize(dt_ptr);
3296a38ea1dSJason Yan 	regions.kernel_size = kernel_sz;
3306a38ea1dSJason Yan 
3316a38ea1dSJason Yan 	get_initrd_range(dt_ptr);
3326a38ea1dSJason Yan 	get_crash_kernel(dt_ptr, ram);
3336a38ea1dSJason Yan 
3346a38ea1dSJason Yan 	/*
3356a38ea1dSJason Yan 	 * Decide which 64M we want to start
3366a38ea1dSJason Yan 	 * Only use the low 8 bits of the random seed
3376a38ea1dSJason Yan 	 */
3386a38ea1dSJason Yan 	index = random & 0xFF;
3396a38ea1dSJason Yan 	index %= linear_sz / SZ_64M;
3406a38ea1dSJason Yan 
3416a38ea1dSJason Yan 	/* Decide offset inside 64M */
3426a38ea1dSJason Yan 	offset = random % (SZ_64M - kernel_sz);
3436a38ea1dSJason Yan 	offset = round_down(offset, SZ_16K);
3446a38ea1dSJason Yan 
3456a38ea1dSJason Yan 	return kaslr_legal_offset(dt_ptr, index, offset);
3462b0e86ccSJason Yan }
3472b0e86ccSJason Yan 
3482b0e86ccSJason Yan /*
3492b0e86ccSJason Yan  * To see if we need to relocate the kernel to a random offset
3502b0e86ccSJason Yan  * void *dt_ptr - address of the device tree
3512b0e86ccSJason Yan  * phys_addr_t size - size of the first memory block
3522b0e86ccSJason Yan  */
kaslr_early_init(void * dt_ptr,phys_addr_t size)3532b0e86ccSJason Yan notrace void __init kaslr_early_init(void *dt_ptr, phys_addr_t size)
3542b0e86ccSJason Yan {
3552b0e86ccSJason Yan 	unsigned long tlb_virt;
3562b0e86ccSJason Yan 	phys_addr_t tlb_phys;
3572b0e86ccSJason Yan 	unsigned long offset;
3582b0e86ccSJason Yan 	unsigned long kernel_sz;
3592b0e86ccSJason Yan 
3602b0e86ccSJason Yan 	kernel_sz = (unsigned long)_end - (unsigned long)_stext;
3612b0e86ccSJason Yan 
3622b0e86ccSJason Yan 	offset = kaslr_choose_location(dt_ptr, size, kernel_sz);
3632b0e86ccSJason Yan 	if (offset == 0)
3642b0e86ccSJason Yan 		return;
3652b0e86ccSJason Yan 
3662b0e86ccSJason Yan 	kernstart_virt_addr += offset;
3672b0e86ccSJason Yan 	kernstart_addr += offset;
3682b0e86ccSJason Yan 
3692b0e86ccSJason Yan 	is_second_reloc = 1;
3702b0e86ccSJason Yan 
3712b0e86ccSJason Yan 	if (offset >= SZ_64M) {
3722b0e86ccSJason Yan 		tlb_virt = round_down(kernstart_virt_addr, SZ_64M);
3732b0e86ccSJason Yan 		tlb_phys = round_down(kernstart_addr, SZ_64M);
3742b0e86ccSJason Yan 
3752b0e86ccSJason Yan 		/* Create kernel map to relocate in */
3762b0e86ccSJason Yan 		create_kaslr_tlb_entry(1, tlb_virt, tlb_phys);
3772b0e86ccSJason Yan 	}
3782b0e86ccSJason Yan 
3792b0e86ccSJason Yan 	/* Copy the kernel to it's new location and run */
3802b0e86ccSJason Yan 	memcpy((void *)kernstart_virt_addr, (void *)_stext, kernel_sz);
3812b0e86ccSJason Yan 	flush_icache_range(kernstart_virt_addr, kernstart_virt_addr + kernel_sz);
3822b0e86ccSJason Yan 
3832b0e86ccSJason Yan 	reloc_kernel_entry(dt_ptr, kernstart_virt_addr);
3842b0e86ccSJason Yan }
385b3960972SJason Yan 
kaslr_late_init(void)386b3960972SJason Yan void __init kaslr_late_init(void)
387b3960972SJason Yan {
388b3960972SJason Yan 	/* If randomized, clear the original kernel */
389b3960972SJason Yan 	if (kernstart_virt_addr != KERNELBASE) {
390b3960972SJason Yan 		unsigned long kernel_sz;
391b3960972SJason Yan 
392b3960972SJason Yan 		kernel_sz = (unsigned long)_end - kernstart_virt_addr;
393b3960972SJason Yan 		memzero_explicit((void *)KERNELBASE, kernel_sz);
394b3960972SJason Yan 	}
395b3960972SJason Yan }
396