linux/arch/x86/lib/kaslr.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Entropy functions used on early boot for KASLR base and memory
   4 * randomization. The base randomization is done in the compressed
   5 * kernel and memory randomization is done early when the regular
   6 * kernel starts. This file is included in the compressed kernel and
   7 * normally linked in the regular.
   8 */
   9#include <asm/asm.h>
  10#include <asm/kaslr.h>
  11#include <asm/msr.h>
  12#include <asm/archrandom.h>
  13#include <asm/e820/api.h>
  14#include <asm/io.h>
  15
  16/*
  17 * When built for the regular kernel, several functions need to be stubbed out
  18 * or changed to their regular kernel equivalent.
  19 */
  20#ifndef KASLR_COMPRESSED_BOOT
  21#include <asm/cpufeature.h>
  22#include <asm/setup.h>
  23
  24#define debug_putstr(v) early_printk("%s", v)
  25#define has_cpuflag(f) boot_cpu_has(f)
  26#define get_boot_seed() kaslr_offset()
  27#endif
  28
  29#define I8254_PORT_CONTROL      0x43
  30#define I8254_PORT_COUNTER0     0x40
  31#define I8254_CMD_READBACK      0xC0
  32#define I8254_SELECT_COUNTER0   0x02
  33#define I8254_STATUS_NOTREADY   0x40
  34static inline u16 i8254(void)
  35{
  36        u16 status, timer;
  37
  38        do {
  39                outb(I8254_PORT_CONTROL,
  40                     I8254_CMD_READBACK | I8254_SELECT_COUNTER0);
  41                status = inb(I8254_PORT_COUNTER0);
  42                timer  = inb(I8254_PORT_COUNTER0);
  43                timer |= inb(I8254_PORT_COUNTER0) << 8;
  44        } while (status & I8254_STATUS_NOTREADY);
  45
  46        return timer;
  47}
  48
  49unsigned long kaslr_get_random_long(const char *purpose)
  50{
  51#ifdef CONFIG_X86_64
  52        const unsigned long mix_const = 0x5d6008cbf3848dd3UL;
  53#else
  54        const unsigned long mix_const = 0x3f39e593UL;
  55#endif
  56        unsigned long raw, random = get_boot_seed();
  57        bool use_i8254 = true;
  58
  59        debug_putstr(purpose);
  60        debug_putstr(" KASLR using");
  61
  62        if (has_cpuflag(X86_FEATURE_RDRAND)) {
  63                debug_putstr(" RDRAND");
  64                if (rdrand_long(&raw)) {
  65                        random ^= raw;
  66                        use_i8254 = false;
  67                }
  68        }
  69
  70        if (has_cpuflag(X86_FEATURE_TSC)) {
  71                debug_putstr(" RDTSC");
  72                raw = rdtsc();
  73
  74                random ^= raw;
  75                use_i8254 = false;
  76        }
  77
  78        if (use_i8254) {
  79                debug_putstr(" i8254");
  80                random ^= i8254();
  81        }
  82
  83        /* Circular multiply for better bit diffusion */
  84        asm(_ASM_MUL "%3"
  85            : "=a" (random), "=d" (raw)
  86            : "a" (random), "rm" (mix_const));
  87        random += raw;
  88
  89        debug_putstr("...\n");
  90
  91        return random;
  92}
  93