Bindings:
 - DT schema conversions for Samsung clocks, RNG bindings, Qcom Command
   DB and rmtfs, gpio-restart, i2c-mux-gpio, i2c-mux-pinctl, Tegra I2C
   and BPMP, pwm-vibrator, Arm DSU, and Cadence macb
 
 - DT schema conversions for Broadcom platforms: interrupt controllers,
   STB GPIO, STB waketimer, STB reset, iProc MDIO mux, iProc PCIe,
   Cygnus PCIe PHY, PWM, USB BDC, BCM6328 LEDs, TMON, SYSTEMPORT, AMAC,
   Northstar 2 PCIe PHY, GENET, moca PHY, GISB arbiter, and SATA
 
 - Add binding schemas for Tegra210 EMC table, TI DC-DC converters,
 
 - Clean-ups of MDIO bus schemas to fix 'unevaluatedProperties' issues
 
 - More fixes due to 'unevaluatedProperties' enabling
 
 - Data type fixes and clean-ups of binding examples found in preparation
   to move to validating DTB files directly (instead of intermediate YAML
   representation.
 
 - Vendor prefixes for T-Head Semiconductor, OnePlus, and Sunplus
 
 - Add various new compatible strings
 
 DT core:
 - Silence a warning for overlapping reserved memory regions
 
 - Reimplement unittest overlay tracking
 
 - Fix stack frame size warning in unittest
 
 - Clean-ups of early FDT scanning functions
 
 - Fix handling of "linux,usable-memory-range" on EFI booted systems
 
 - Add support for 'fail' status on CPU nodes
 
 - Improve error message in of_phandle_iterator_next()
 
 - kbuild: Disable duplicate unit-address warnings for disabled nodes
 -----BEGIN PGP SIGNATURE-----
 
 iQJEBAABCgAuFiEEktVUI4SxYhzZyEuo+vtdtY28YcMFAmHfCdcQHHJvYmhAa2Vy
 bmVsLm9yZwAKCRD6+121jbxhw+UZD/0ZMQQ6VF20MW7Gg0bOutd8Q6Q6opjrCG5c
 nLW5mv8Q+um3sI1ZpwdMI4zAfCmTfeL13ZM9KtJKlJ0o41bgId+kZsezy4I2rN9+
 sE1CwA4TninKTJsUkmyQX4fgJRUZ95Eubryfb07sy7nbK3LZQ+t18R5tzVBDpzy4
 7hy4eM6mlMxgIJDi7EUboLZslkMM4TGGutLsk5C5T5V5lcWSt3Jj5WZtl5k4Wykq
 j4i9mU+GGTZi0nGAJQ7lNoLPatZDSVQx5tzNV/Wi8hSwZbn0Kycu+IuWZyihILz/
 9lzB/7tv8fl+xkTaJ5xxaY05HcDeX02yCLzh3PfAHRYdbQ2EkFoaKqJ81SLfAq5t
 aH87v41wFSrjzynxpppqswXOdqI/jofrHrGlQldnw0VHGTjEfDbyZGRQFPHmuzTG
 gXaSNKCxppG7ThpXarfu7D4TdYV75n+cBOsC/BBopYgIS2+xmjDA3t5Scks1/4NX
 1Hfq9IMF9iYJYc/GNXBWcOrLn9d1ILYt6HrKRQar1NIEFH1Lt0c2aw5WsyvOZ4zx
 aLHLSbEwnl+2wleyGB9YQkFaaF7N6qcid3u9KFRJP6nTojoaeQaIi3MR9F3LVReZ
 LV5YfWEcij1zc+lzwgHc6+8bbgFxrKgOC2IL/B6u93u/BO0wmF/54kbEZKaLyX8d
 a7Iii4IYFw==
 =2g8v
 -----END PGP SIGNATURE-----
Merge tag 'devicetree-for-5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux
Pull devicetree updates from Rob Herring:
 "Bindings:
   - DT schema conversions for Samsung clocks, RNG bindings, Qcom
     Command DB and rmtfs, gpio-restart, i2c-mux-gpio, i2c-mux-pinctl,
     Tegra I2C and BPMP, pwm-vibrator, Arm DSU, and Cadence macb
   - DT schema conversions for Broadcom platforms: interrupt
     controllers, STB GPIO, STB waketimer, STB reset, iProc MDIO mux,
     iProc PCIe, Cygnus PCIe PHY, PWM, USB BDC, BCM6328 LEDs, TMON,
     SYSTEMPORT, AMAC, Northstar 2 PCIe PHY, GENET, moca PHY, GISB
     arbiter, and SATA
   - Add binding schemas for Tegra210 EMC table, TI DC-DC converters,
   - Clean-ups of MDIO bus schemas to fix 'unevaluatedProperties' issues
   - More fixes due to 'unevaluatedProperties' enabling
   - Data type fixes and clean-ups of binding examples found in
     preparation to move to validating DTB files directly (instead of
     intermediate YAML representation.
   - Vendor prefixes for T-Head Semiconductor, OnePlus, and Sunplus
   - Add various new compatible strings
  DT core:
   - Silence a warning for overlapping reserved memory regions
   - Reimplement unittest overlay tracking
   - Fix stack frame size warning in unittest
   - Clean-ups of early FDT scanning functions
   - Fix handling of "linux,usable-memory-range" on EFI booted systems
   - Add support for 'fail' status on CPU nodes
   - Improve error message in of_phandle_iterator_next()
   - kbuild: Disable duplicate unit-address warnings for disabled nodes"
* tag 'devicetree-for-5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux: (114 commits)
  dt-bindings: net: mdio: Drop resets/reset-names child properties
  dt-bindings: clock: samsung: convert S5Pv210 to dtschema
  dt-bindings: clock: samsung: convert Exynos5410 to dtschema
  dt-bindings: clock: samsung: convert Exynos5260 to dtschema
  dt-bindings: clock: samsung: extend Exynos7 bindings with UFS
  dt-bindings: clock: samsung: convert Exynos7 to dtschema
  dt-bindings: clock: samsung: convert Exynos5433 to dtschema
  dt-bindings: i2c: maxim,max96712: Add bindings for Maxim Integrated MAX96712
  dt-bindings: iio: adi,ltc2983: Fix 64-bit property sizes
  dt-bindings: power: maxim,max17040: Fix incorrect type for 'maxim,rcomp'
  dt-bindings: interrupt-controller: arm,gic-v3: Fix 'interrupts' cell size in example
  dt-bindings: iio/magnetometer: yamaha,yas530: Fix invalid 'interrupts' in example
  dt-bindings: clock: imx5: Drop clock consumer node from example
  dt-bindings: Drop required 'interrupt-parent'
  dt-bindings: net: ti,dp83869: Drop value on boolean 'ti,max-output-impedance'
  dt-bindings: net: wireless: mt76: Fix 8-bit property sizes
  dt-bindings: PCI: snps,dw-pcie-ep: Drop conflicting 'max-functions' schema
  dt-bindings: i2c: st,stm32-i2c: Make each example a separate entry
  dt-bindings: net: stm32-dwmac: Make each example a separate entry
  dt-bindings: net: Cleanup MDIO node schemas
  ...
		
	
			
		
			
				
	
	
		
			400 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			400 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0-only
 | |
| //
 | |
| // Copyright (C) 2019 Jason Yan <yanaijie@huawei.com>
 | |
| 
 | |
| #include <linux/kernel.h>
 | |
| #include <linux/errno.h>
 | |
| #include <linux/string.h>
 | |
| #include <linux/types.h>
 | |
| #include <linux/mm.h>
 | |
| #include <linux/swap.h>
 | |
| #include <linux/stddef.h>
 | |
| #include <linux/init.h>
 | |
| #include <linux/delay.h>
 | |
| #include <linux/memblock.h>
 | |
| #include <linux/libfdt.h>
 | |
| #include <linux/crash_core.h>
 | |
| #include <asm/cacheflush.h>
 | |
| #include <asm/prom.h>
 | |
| #include <asm/kdump.h>
 | |
| #include <mm/mmu_decl.h>
 | |
| #include <generated/compile.h>
 | |
| #include <generated/utsrelease.h>
 | |
| 
 | |
| struct regions {
 | |
| 	unsigned long pa_start;
 | |
| 	unsigned long pa_end;
 | |
| 	unsigned long kernel_size;
 | |
| 	unsigned long dtb_start;
 | |
| 	unsigned long dtb_end;
 | |
| 	unsigned long initrd_start;
 | |
| 	unsigned long initrd_end;
 | |
| 	unsigned long crash_start;
 | |
| 	unsigned long crash_end;
 | |
| 	int reserved_mem;
 | |
| 	int reserved_mem_addr_cells;
 | |
| 	int reserved_mem_size_cells;
 | |
| };
 | |
| 
 | |
| /* Simplified build-specific string for starting entropy. */
 | |
| static const char build_str[] = UTS_RELEASE " (" LINUX_COMPILE_BY "@"
 | |
| 		LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION;
 | |
| 
 | |
| struct regions __initdata regions;
 | |
| 
 | |
| static __init void kaslr_get_cmdline(void *fdt)
 | |
| {
 | |
| 	early_init_dt_scan_chosen(boot_command_line);
 | |
| }
 | |
| 
 | |
| static unsigned long __init rotate_xor(unsigned long hash, const void *area,
 | |
| 				       size_t size)
 | |
| {
 | |
| 	size_t i;
 | |
| 	const unsigned long *ptr = area;
 | |
| 
 | |
| 	for (i = 0; i < size / sizeof(hash); i++) {
 | |
| 		/* Rotate by odd number of bits and XOR. */
 | |
| 		hash = (hash << ((sizeof(hash) * 8) - 7)) | (hash >> 7);
 | |
| 		hash ^= ptr[i];
 | |
| 	}
 | |
| 
 | |
| 	return hash;
 | |
| }
 | |
| 
 | |
| /* Attempt to create a simple starting entropy. This can make it defferent for
 | |
|  * every build but it is still not enough. Stronger entropy should
 | |
|  * be added to make it change for every boot.
 | |
|  */
 | |
| static unsigned long __init get_boot_seed(void *fdt)
 | |
| {
 | |
| 	unsigned long hash = 0;
 | |
| 
 | |
| 	hash = rotate_xor(hash, build_str, sizeof(build_str));
 | |
| 	hash = rotate_xor(hash, fdt, fdt_totalsize(fdt));
 | |
| 
 | |
| 	return hash;
 | |
| }
 | |
| 
 | |
| static __init u64 get_kaslr_seed(void *fdt)
 | |
| {
 | |
| 	int node, len;
 | |
| 	fdt64_t *prop;
 | |
| 	u64 ret;
 | |
| 
 | |
| 	node = fdt_path_offset(fdt, "/chosen");
 | |
| 	if (node < 0)
 | |
| 		return 0;
 | |
| 
 | |
| 	prop = fdt_getprop_w(fdt, node, "kaslr-seed", &len);
 | |
| 	if (!prop || len != sizeof(u64))
 | |
| 		return 0;
 | |
| 
 | |
| 	ret = fdt64_to_cpu(*prop);
 | |
| 	*prop = 0;
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| static __init bool regions_overlap(u32 s1, u32 e1, u32 s2, u32 e2)
 | |
| {
 | |
| 	return e1 >= s2 && e2 >= s1;
 | |
| }
 | |
| 
 | |
| static __init bool overlaps_reserved_region(const void *fdt, u32 start,
 | |
| 					    u32 end)
 | |
| {
 | |
| 	int subnode, len, i;
 | |
| 	u64 base, size;
 | |
| 
 | |
| 	/* check for overlap with /memreserve/ entries */
 | |
| 	for (i = 0; i < fdt_num_mem_rsv(fdt); i++) {
 | |
| 		if (fdt_get_mem_rsv(fdt, i, &base, &size) < 0)
 | |
| 			continue;
 | |
| 		if (regions_overlap(start, end, base, base + size))
 | |
| 			return true;
 | |
| 	}
 | |
| 
 | |
| 	if (regions.reserved_mem < 0)
 | |
| 		return false;
 | |
| 
 | |
| 	/* check for overlap with static reservations in /reserved-memory */
 | |
| 	for (subnode = fdt_first_subnode(fdt, regions.reserved_mem);
 | |
| 	     subnode >= 0;
 | |
| 	     subnode = fdt_next_subnode(fdt, subnode)) {
 | |
| 		const fdt32_t *reg;
 | |
| 		u64 rsv_end;
 | |
| 
 | |
| 		len = 0;
 | |
| 		reg = fdt_getprop(fdt, subnode, "reg", &len);
 | |
| 		while (len >= (regions.reserved_mem_addr_cells +
 | |
| 			       regions.reserved_mem_size_cells)) {
 | |
| 			base = fdt32_to_cpu(reg[0]);
 | |
| 			if (regions.reserved_mem_addr_cells == 2)
 | |
| 				base = (base << 32) | fdt32_to_cpu(reg[1]);
 | |
| 
 | |
| 			reg += regions.reserved_mem_addr_cells;
 | |
| 			len -= 4 * regions.reserved_mem_addr_cells;
 | |
| 
 | |
| 			size = fdt32_to_cpu(reg[0]);
 | |
| 			if (regions.reserved_mem_size_cells == 2)
 | |
| 				size = (size << 32) | fdt32_to_cpu(reg[1]);
 | |
| 
 | |
| 			reg += regions.reserved_mem_size_cells;
 | |
| 			len -= 4 * regions.reserved_mem_size_cells;
 | |
| 
 | |
| 			if (base >= regions.pa_end)
 | |
| 				continue;
 | |
| 
 | |
| 			rsv_end = min(base + size, (u64)U32_MAX);
 | |
| 
 | |
| 			if (regions_overlap(start, end, base, rsv_end))
 | |
| 				return true;
 | |
| 		}
 | |
| 	}
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| static __init bool overlaps_region(const void *fdt, u32 start,
 | |
| 				   u32 end)
 | |
| {
 | |
| 	if (regions_overlap(start, end, __pa(_stext), __pa(_end)))
 | |
| 		return true;
 | |
| 
 | |
| 	if (regions_overlap(start, end, regions.dtb_start,
 | |
| 			    regions.dtb_end))
 | |
| 		return true;
 | |
| 
 | |
| 	if (regions_overlap(start, end, regions.initrd_start,
 | |
| 			    regions.initrd_end))
 | |
| 		return true;
 | |
| 
 | |
| 	if (regions_overlap(start, end, regions.crash_start,
 | |
| 			    regions.crash_end))
 | |
| 		return true;
 | |
| 
 | |
| 	return overlaps_reserved_region(fdt, start, end);
 | |
| }
 | |
| 
 | |
| static void __init get_crash_kernel(void *fdt, unsigned long size)
 | |
| {
 | |
| #ifdef CONFIG_CRASH_CORE
 | |
| 	unsigned long long crash_size, crash_base;
 | |
| 	int ret;
 | |
| 
 | |
| 	ret = parse_crashkernel(boot_command_line, size, &crash_size,
 | |
| 				&crash_base);
 | |
| 	if (ret != 0 || crash_size == 0)
 | |
| 		return;
 | |
| 	if (crash_base == 0)
 | |
| 		crash_base = KDUMP_KERNELBASE;
 | |
| 
 | |
| 	regions.crash_start = (unsigned long)crash_base;
 | |
| 	regions.crash_end = (unsigned long)(crash_base + crash_size);
 | |
| 
 | |
| 	pr_debug("crash_base=0x%llx crash_size=0x%llx\n", crash_base, crash_size);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static void __init get_initrd_range(void *fdt)
 | |
| {
 | |
| 	u64 start, end;
 | |
| 	int node, len;
 | |
| 	const __be32 *prop;
 | |
| 
 | |
| 	node = fdt_path_offset(fdt, "/chosen");
 | |
| 	if (node < 0)
 | |
| 		return;
 | |
| 
 | |
| 	prop = fdt_getprop(fdt, node, "linux,initrd-start", &len);
 | |
| 	if (!prop)
 | |
| 		return;
 | |
| 	start = of_read_number(prop, len / 4);
 | |
| 
 | |
| 	prop = fdt_getprop(fdt, node, "linux,initrd-end", &len);
 | |
| 	if (!prop)
 | |
| 		return;
 | |
| 	end = of_read_number(prop, len / 4);
 | |
| 
 | |
| 	regions.initrd_start = (unsigned long)start;
 | |
| 	regions.initrd_end = (unsigned long)end;
 | |
| 
 | |
| 	pr_debug("initrd_start=0x%llx  initrd_end=0x%llx\n", start, end);
 | |
| }
 | |
| 
 | |
| static __init unsigned long get_usable_address(const void *fdt,
 | |
| 					       unsigned long start,
 | |
| 					       unsigned long offset)
 | |
| {
 | |
| 	unsigned long pa;
 | |
| 	unsigned long pa_end;
 | |
| 
 | |
| 	for (pa = offset; (long)pa > (long)start; pa -= SZ_16K) {
 | |
| 		pa_end = pa + regions.kernel_size;
 | |
| 		if (overlaps_region(fdt, pa, pa_end))
 | |
| 			continue;
 | |
| 
 | |
| 		return pa;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static __init void get_cell_sizes(const void *fdt, int node, int *addr_cells,
 | |
| 				  int *size_cells)
 | |
| {
 | |
| 	const int *prop;
 | |
| 	int len;
 | |
| 
 | |
| 	/*
 | |
| 	 * Retrieve the #address-cells and #size-cells properties
 | |
| 	 * from the 'node', or use the default if not provided.
 | |
| 	 */
 | |
| 	*addr_cells = *size_cells = 1;
 | |
| 
 | |
| 	prop = fdt_getprop(fdt, node, "#address-cells", &len);
 | |
| 	if (len == 4)
 | |
| 		*addr_cells = fdt32_to_cpu(*prop);
 | |
| 	prop = fdt_getprop(fdt, node, "#size-cells", &len);
 | |
| 	if (len == 4)
 | |
| 		*size_cells = fdt32_to_cpu(*prop);
 | |
| }
 | |
| 
 | |
| static unsigned long __init kaslr_legal_offset(void *dt_ptr, unsigned long index,
 | |
| 					       unsigned long offset)
 | |
| {
 | |
| 	unsigned long koffset = 0;
 | |
| 	unsigned long start;
 | |
| 
 | |
| 	while ((long)index >= 0) {
 | |
| 		offset = memstart_addr + index * SZ_64M + offset;
 | |
| 		start = memstart_addr + index * SZ_64M;
 | |
| 		koffset = get_usable_address(dt_ptr, start, offset);
 | |
| 		if (koffset)
 | |
| 			break;
 | |
| 		index--;
 | |
| 	}
 | |
| 
 | |
| 	if (koffset != 0)
 | |
| 		koffset -= memstart_addr;
 | |
| 
 | |
| 	return koffset;
 | |
| }
 | |
| 
 | |
| static inline __init bool kaslr_disabled(void)
 | |
| {
 | |
| 	return strstr(boot_command_line, "nokaslr") != NULL;
 | |
| }
 | |
| 
 | |
| static unsigned long __init kaslr_choose_location(void *dt_ptr, phys_addr_t size,
 | |
| 						  unsigned long kernel_sz)
 | |
| {
 | |
| 	unsigned long offset, random;
 | |
| 	unsigned long ram, linear_sz;
 | |
| 	u64 seed;
 | |
| 	unsigned long index;
 | |
| 
 | |
| 	kaslr_get_cmdline(dt_ptr);
 | |
| 	if (kaslr_disabled())
 | |
| 		return 0;
 | |
| 
 | |
| 	random = get_boot_seed(dt_ptr);
 | |
| 
 | |
| 	seed = get_tb() << 32;
 | |
| 	seed ^= get_tb();
 | |
| 	random = rotate_xor(random, &seed, sizeof(seed));
 | |
| 
 | |
| 	/*
 | |
| 	 * Retrieve (and wipe) the seed from the FDT
 | |
| 	 */
 | |
| 	seed = get_kaslr_seed(dt_ptr);
 | |
| 	if (seed)
 | |
| 		random = rotate_xor(random, &seed, sizeof(seed));
 | |
| 	else
 | |
| 		pr_warn("KASLR: No safe seed for randomizing the kernel base.\n");
 | |
| 
 | |
| 	ram = min_t(phys_addr_t, __max_low_memory, size);
 | |
| 	ram = map_mem_in_cams(ram, CONFIG_LOWMEM_CAM_NUM, true, true);
 | |
| 	linear_sz = min_t(unsigned long, ram, SZ_512M);
 | |
| 
 | |
| 	/* If the linear size is smaller than 64M, do not randmize */
 | |
| 	if (linear_sz < SZ_64M)
 | |
| 		return 0;
 | |
| 
 | |
| 	/* check for a reserved-memory node and record its cell sizes */
 | |
| 	regions.reserved_mem = fdt_path_offset(dt_ptr, "/reserved-memory");
 | |
| 	if (regions.reserved_mem >= 0)
 | |
| 		get_cell_sizes(dt_ptr, regions.reserved_mem,
 | |
| 			       ®ions.reserved_mem_addr_cells,
 | |
| 			       ®ions.reserved_mem_size_cells);
 | |
| 
 | |
| 	regions.pa_start = memstart_addr;
 | |
| 	regions.pa_end = memstart_addr + linear_sz;
 | |
| 	regions.dtb_start = __pa(dt_ptr);
 | |
| 	regions.dtb_end = __pa(dt_ptr) + fdt_totalsize(dt_ptr);
 | |
| 	regions.kernel_size = kernel_sz;
 | |
| 
 | |
| 	get_initrd_range(dt_ptr);
 | |
| 	get_crash_kernel(dt_ptr, ram);
 | |
| 
 | |
| 	/*
 | |
| 	 * Decide which 64M we want to start
 | |
| 	 * Only use the low 8 bits of the random seed
 | |
| 	 */
 | |
| 	index = random & 0xFF;
 | |
| 	index %= linear_sz / SZ_64M;
 | |
| 
 | |
| 	/* Decide offset inside 64M */
 | |
| 	offset = random % (SZ_64M - kernel_sz);
 | |
| 	offset = round_down(offset, SZ_16K);
 | |
| 
 | |
| 	return kaslr_legal_offset(dt_ptr, index, offset);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * To see if we need to relocate the kernel to a random offset
 | |
|  * void *dt_ptr - address of the device tree
 | |
|  * phys_addr_t size - size of the first memory block
 | |
|  */
 | |
| notrace void __init kaslr_early_init(void *dt_ptr, phys_addr_t size)
 | |
| {
 | |
| 	unsigned long tlb_virt;
 | |
| 	phys_addr_t tlb_phys;
 | |
| 	unsigned long offset;
 | |
| 	unsigned long kernel_sz;
 | |
| 
 | |
| 	kernel_sz = (unsigned long)_end - (unsigned long)_stext;
 | |
| 
 | |
| 	offset = kaslr_choose_location(dt_ptr, size, kernel_sz);
 | |
| 	if (offset == 0)
 | |
| 		return;
 | |
| 
 | |
| 	kernstart_virt_addr += offset;
 | |
| 	kernstart_addr += offset;
 | |
| 
 | |
| 	is_second_reloc = 1;
 | |
| 
 | |
| 	if (offset >= SZ_64M) {
 | |
| 		tlb_virt = round_down(kernstart_virt_addr, SZ_64M);
 | |
| 		tlb_phys = round_down(kernstart_addr, SZ_64M);
 | |
| 
 | |
| 		/* Create kernel map to relocate in */
 | |
| 		create_kaslr_tlb_entry(1, tlb_virt, tlb_phys);
 | |
| 	}
 | |
| 
 | |
| 	/* Copy the kernel to it's new location and run */
 | |
| 	memcpy((void *)kernstart_virt_addr, (void *)_stext, kernel_sz);
 | |
| 	flush_icache_range(kernstart_virt_addr, kernstart_virt_addr + kernel_sz);
 | |
| 
 | |
| 	reloc_kernel_entry(dt_ptr, kernstart_virt_addr);
 | |
| }
 | |
| 
 | |
| void __init kaslr_late_init(void)
 | |
| {
 | |
| 	/* If randomized, clear the original kernel */
 | |
| 	if (kernstart_virt_addr != KERNELBASE) {
 | |
| 		unsigned long kernel_sz;
 | |
| 
 | |
| 		kernel_sz = (unsigned long)_end - kernstart_virt_addr;
 | |
| 		memzero_explicit((void *)KERNELBASE, kernel_sz);
 | |
| 	}
 | |
| }
 |