kaslr_early.c 1.5 KB

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