1 // SPDX-License-Identifier: GPL-2.0-only 2 // Copyright 2022 Google LLC 3 // Author: Ard Biesheuvel <ardb@google.com> 4 5 // NOTE: code in this file runs *very* early, and is not permitted to use 6 // global variables or anything that relies on absolute addressing. 7 8 #include <linux/libfdt.h> 9 #include <linux/init.h> 10 #include <linux/linkage.h> 11 #include <linux/types.h> 12 #include <linux/sizes.h> 13 #include <linux/string.h> 14 15 #include <asm/archrandom.h> 16 #include <asm/memory.h> 17 #include <asm/pgtable.h> 18 19 #include "pi.h" 20 21 extern u16 memstart_offset_seed; 22 23 static u64 __init get_kaslr_seed(void *fdt, int node) 24 { 25 static char const seed_str[] __initconst = "kaslr-seed"; 26 fdt64_t *prop; 27 u64 ret; 28 int len; 29 30 if (node < 0) 31 return 0; 32 33 prop = fdt_getprop_w(fdt, node, seed_str, &len); 34 if (!prop || len != sizeof(u64)) 35 return 0; 36 37 ret = fdt64_to_cpu(*prop); 38 *prop = 0; 39 return ret; 40 } 41 42 u64 __init kaslr_early_init(void *fdt, int chosen) 43 { 44 u64 seed, range; 45 46 if (kaslr_disabled_cmdline()) 47 return 0; 48 49 seed = get_kaslr_seed(fdt, chosen); 50 if (!seed) { 51 if (!__early_cpu_has_rndr() || 52 !__arm64_rndr((unsigned long *)&seed)) 53 return 0; 54 } 55 56 memstart_offset_seed = seed & U16_MAX; 57 58 /* 59 * OK, so we are proceeding with KASLR enabled. Calculate a suitable 60 * kernel image offset from the seed. Let's place the kernel in the 61 * 'middle' half of the VMALLOC area, and stay clear of the lower and 62 * upper quarters to avoid colliding with other allocations. 63 */ 64 range = (VMALLOC_END - KIMAGE_VADDR) / 2; 65 return range / 2 + (((__uint128_t)range * seed) >> 64); 66 } 67