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