1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright 2022 Google LLC
3 // Author: Ard Biesheuvel <ardb@google.com>
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.
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>
15 #include <asm/archrandom.h>
16 #include <asm/memory.h>
18 /* taken from lib/string.c */
19 static char *__strstr(const char *s1, const char *s2)
29 if (!memcmp(s1, s2, l2))
35 static bool cmdline_contains_nokaslr(const u8 *cmdline)
39 str = __strstr(cmdline, "nokaslr");
40 return str == cmdline || (str > cmdline && *(str - 1) == ' ');
43 static bool is_kaslr_disabled_cmdline(void *fdt)
45 if (!IS_ENABLED(CONFIG_CMDLINE_FORCE)) {
49 node = fdt_path_offset(fdt, "/chosen");
53 prop = fdt_getprop(fdt, node, "bootargs", NULL);
57 if (cmdline_contains_nokaslr(prop))
60 if (IS_ENABLED(CONFIG_CMDLINE_EXTEND))
66 return cmdline_contains_nokaslr(CONFIG_CMDLINE);
69 static u64 get_kaslr_seed(void *fdt)
75 node = fdt_path_offset(fdt, "/chosen");
79 prop = fdt_getprop_w(fdt, node, "kaslr-seed", &len);
80 if (!prop || len != sizeof(u64))
83 ret = fdt64_to_cpu(*prop);
88 asmlinkage u64 kaslr_early_init(void *fdt)
92 if (is_kaslr_disabled_cmdline(fdt))
95 seed = get_kaslr_seed(fdt);
97 if (!__early_cpu_has_rndr() ||
98 !__arm64_rndr((unsigned long *)&seed))
103 * OK, so we are proceeding with KASLR enabled. Calculate a suitable
104 * kernel image offset from the seed. Let's place the kernel in the
105 * middle half of the VMALLOC area (VA_BITS_MIN - 2), and stay clear of
106 * the lower and upper quarters to avoid colliding with other
109 return BIT(VA_BITS_MIN - 3) + (seed & GENMASK(VA_BITS_MIN - 3, 0));