1 // SPDX-License-Identifier: GPL-2.0-only
3 // Copyright (C) 2019 Jason Yan <yanaijie@huawei.com>
5 #include <linux/kernel.h>
6 #include <linux/errno.h>
7 #include <linux/string.h>
8 #include <linux/types.h>
10 #include <linux/swap.h>
11 #include <linux/stddef.h>
12 #include <linux/init.h>
13 #include <linux/delay.h>
14 #include <linux/memblock.h>
15 #include <linux/libfdt.h>
16 #include <linux/crash_core.h>
18 #include <linux/of_fdt.h>
19 #include <asm/cacheflush.h>
20 #include <asm/kdump.h>
21 #include <mm/mmu_decl.h>
22 #include <generated/utsrelease.h>
25 unsigned long pa_start;
27 unsigned long kernel_size;
28 unsigned long dtb_start;
29 unsigned long dtb_end;
30 unsigned long initrd_start;
31 unsigned long initrd_end;
32 unsigned long crash_start;
33 unsigned long crash_end;
35 int reserved_mem_addr_cells;
36 int reserved_mem_size_cells;
39 struct regions __initdata regions;
41 static __init void kaslr_get_cmdline(void *fdt)
43 early_init_dt_scan_chosen(boot_command_line);
46 static unsigned long __init rotate_xor(unsigned long hash, const void *area,
50 const unsigned long *ptr = area;
52 for (i = 0; i < size / sizeof(hash); i++) {
53 /* Rotate by odd number of bits and XOR. */
54 hash = (hash << ((sizeof(hash) * 8) - 7)) | (hash >> 7);
61 /* Attempt to create a simple starting entropy. This can make it defferent for
62 * every build but it is still not enough. Stronger entropy should
63 * be added to make it change for every boot.
65 static unsigned long __init get_boot_seed(void *fdt)
67 unsigned long hash = 0;
69 /* build-specific string for starting entropy. */
70 hash = rotate_xor(hash, linux_banner, strlen(linux_banner));
71 hash = rotate_xor(hash, fdt, fdt_totalsize(fdt));
76 static __init u64 get_kaslr_seed(void *fdt)
82 node = fdt_path_offset(fdt, "/chosen");
86 prop = fdt_getprop_w(fdt, node, "kaslr-seed", &len);
87 if (!prop || len != sizeof(u64))
90 ret = fdt64_to_cpu(*prop);
95 static __init bool regions_overlap(u32 s1, u32 e1, u32 s2, u32 e2)
97 return e1 >= s2 && e2 >= s1;
100 static __init bool overlaps_reserved_region(const void *fdt, u32 start,
106 /* check for overlap with /memreserve/ entries */
107 for (i = 0; i < fdt_num_mem_rsv(fdt); i++) {
108 if (fdt_get_mem_rsv(fdt, i, &base, &size) < 0)
110 if (regions_overlap(start, end, base, base + size))
114 if (regions.reserved_mem < 0)
117 /* check for overlap with static reservations in /reserved-memory */
118 for (subnode = fdt_first_subnode(fdt, regions.reserved_mem);
120 subnode = fdt_next_subnode(fdt, subnode)) {
125 reg = fdt_getprop(fdt, subnode, "reg", &len);
126 while (len >= (regions.reserved_mem_addr_cells +
127 regions.reserved_mem_size_cells)) {
128 base = fdt32_to_cpu(reg[0]);
129 if (regions.reserved_mem_addr_cells == 2)
130 base = (base << 32) | fdt32_to_cpu(reg[1]);
132 reg += regions.reserved_mem_addr_cells;
133 len -= 4 * regions.reserved_mem_addr_cells;
135 size = fdt32_to_cpu(reg[0]);
136 if (regions.reserved_mem_size_cells == 2)
137 size = (size << 32) | fdt32_to_cpu(reg[1]);
139 reg += regions.reserved_mem_size_cells;
140 len -= 4 * regions.reserved_mem_size_cells;
142 if (base >= regions.pa_end)
145 rsv_end = min(base + size, (u64)U32_MAX);
147 if (regions_overlap(start, end, base, rsv_end))
154 static __init bool overlaps_region(const void *fdt, u32 start,
157 if (regions_overlap(start, end, __pa(_stext), __pa(_end)))
160 if (regions_overlap(start, end, regions.dtb_start,
164 if (regions_overlap(start, end, regions.initrd_start,
168 if (regions_overlap(start, end, regions.crash_start,
172 return overlaps_reserved_region(fdt, start, end);
175 static void __init get_crash_kernel(void *fdt, unsigned long size)
177 #ifdef CONFIG_CRASH_CORE
178 unsigned long long crash_size, crash_base;
181 ret = parse_crashkernel(boot_command_line, size, &crash_size,
183 if (ret != 0 || crash_size == 0)
186 crash_base = KDUMP_KERNELBASE;
188 regions.crash_start = (unsigned long)crash_base;
189 regions.crash_end = (unsigned long)(crash_base + crash_size);
191 pr_debug("crash_base=0x%llx crash_size=0x%llx\n", crash_base, crash_size);
195 static void __init get_initrd_range(void *fdt)
201 node = fdt_path_offset(fdt, "/chosen");
205 prop = fdt_getprop(fdt, node, "linux,initrd-start", &len);
208 start = of_read_number(prop, len / 4);
210 prop = fdt_getprop(fdt, node, "linux,initrd-end", &len);
213 end = of_read_number(prop, len / 4);
215 regions.initrd_start = (unsigned long)start;
216 regions.initrd_end = (unsigned long)end;
218 pr_debug("initrd_start=0x%llx initrd_end=0x%llx\n", start, end);
221 static __init unsigned long get_usable_address(const void *fdt,
223 unsigned long offset)
226 unsigned long pa_end;
228 for (pa = offset; (long)pa > (long)start; pa -= SZ_16K) {
229 pa_end = pa + regions.kernel_size;
230 if (overlaps_region(fdt, pa, pa_end))
238 static __init void get_cell_sizes(const void *fdt, int node, int *addr_cells,
245 * Retrieve the #address-cells and #size-cells properties
246 * from the 'node', or use the default if not provided.
248 *addr_cells = *size_cells = 1;
250 prop = fdt_getprop(fdt, node, "#address-cells", &len);
252 *addr_cells = fdt32_to_cpu(*prop);
253 prop = fdt_getprop(fdt, node, "#size-cells", &len);
255 *size_cells = fdt32_to_cpu(*prop);
258 static unsigned long __init kaslr_legal_offset(void *dt_ptr, unsigned long index,
259 unsigned long offset)
261 unsigned long koffset = 0;
264 while ((long)index >= 0) {
265 offset = memstart_addr + index * SZ_64M + offset;
266 start = memstart_addr + index * SZ_64M;
267 koffset = get_usable_address(dt_ptr, start, offset);
274 koffset -= memstart_addr;
279 static inline __init bool kaslr_disabled(void)
281 return strstr(boot_command_line, "nokaslr") != NULL;
284 static unsigned long __init kaslr_choose_location(void *dt_ptr, phys_addr_t size,
285 unsigned long kernel_sz)
287 unsigned long offset, random;
288 unsigned long ram, linear_sz;
292 kaslr_get_cmdline(dt_ptr);
293 if (kaslr_disabled())
296 random = get_boot_seed(dt_ptr);
298 seed = get_tb() << 32;
300 random = rotate_xor(random, &seed, sizeof(seed));
303 * Retrieve (and wipe) the seed from the FDT
305 seed = get_kaslr_seed(dt_ptr);
307 random = rotate_xor(random, &seed, sizeof(seed));
309 pr_warn("KASLR: No safe seed for randomizing the kernel base.\n");
311 ram = min_t(phys_addr_t, __max_low_memory, size);
312 ram = map_mem_in_cams(ram, CONFIG_LOWMEM_CAM_NUM, true, true);
313 linear_sz = min_t(unsigned long, ram, SZ_512M);
315 /* If the linear size is smaller than 64M, do not randomize */
316 if (linear_sz < SZ_64M)
319 /* check for a reserved-memory node and record its cell sizes */
320 regions.reserved_mem = fdt_path_offset(dt_ptr, "/reserved-memory");
321 if (regions.reserved_mem >= 0)
322 get_cell_sizes(dt_ptr, regions.reserved_mem,
323 ®ions.reserved_mem_addr_cells,
324 ®ions.reserved_mem_size_cells);
326 regions.pa_start = memstart_addr;
327 regions.pa_end = memstart_addr + linear_sz;
328 regions.dtb_start = __pa(dt_ptr);
329 regions.dtb_end = __pa(dt_ptr) + fdt_totalsize(dt_ptr);
330 regions.kernel_size = kernel_sz;
332 get_initrd_range(dt_ptr);
333 get_crash_kernel(dt_ptr, ram);
336 * Decide which 64M we want to start
337 * Only use the low 8 bits of the random seed
339 index = random & 0xFF;
340 index %= linear_sz / SZ_64M;
342 /* Decide offset inside 64M */
343 offset = random % (SZ_64M - kernel_sz);
344 offset = round_down(offset, SZ_16K);
346 return kaslr_legal_offset(dt_ptr, index, offset);
350 * To see if we need to relocate the kernel to a random offset
351 * void *dt_ptr - address of the device tree
352 * phys_addr_t size - size of the first memory block
354 notrace void __init kaslr_early_init(void *dt_ptr, phys_addr_t size)
356 unsigned long tlb_virt;
357 phys_addr_t tlb_phys;
358 unsigned long offset;
359 unsigned long kernel_sz;
361 kernel_sz = (unsigned long)_end - (unsigned long)_stext;
363 offset = kaslr_choose_location(dt_ptr, size, kernel_sz);
367 kernstart_virt_addr += offset;
368 kernstart_addr += offset;
372 if (offset >= SZ_64M) {
373 tlb_virt = round_down(kernstart_virt_addr, SZ_64M);
374 tlb_phys = round_down(kernstart_addr, SZ_64M);
376 /* Create kernel map to relocate in */
377 create_kaslr_tlb_entry(1, tlb_virt, tlb_phys);
380 /* Copy the kernel to it's new location and run */
381 memcpy((void *)kernstart_virt_addr, (void *)_stext, kernel_sz);
382 flush_icache_range(kernstart_virt_addr, kernstart_virt_addr + kernel_sz);
384 reloc_kernel_entry(dt_ptr, kernstart_virt_addr);
387 void __init kaslr_late_init(void)
389 /* If randomized, clear the original kernel */
390 if (kernstart_virt_addr != KERNELBASE) {
391 unsigned long kernel_sz;
393 kernel_sz = (unsigned long)_end - kernstart_virt_addr;
394 memzero_explicit((void *)KERNELBASE, kernel_sz);