18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Entropy functions used on early boot for KASLR base and memory 48c2ecf20Sopenharmony_ci * randomization. The base randomization is done in the compressed 58c2ecf20Sopenharmony_ci * kernel and memory randomization is done early when the regular 68c2ecf20Sopenharmony_ci * kernel starts. This file is included in the compressed kernel and 78c2ecf20Sopenharmony_ci * normally linked in the regular. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci#include <asm/asm.h> 108c2ecf20Sopenharmony_ci#include <asm/kaslr.h> 118c2ecf20Sopenharmony_ci#include <asm/msr.h> 128c2ecf20Sopenharmony_ci#include <asm/archrandom.h> 138c2ecf20Sopenharmony_ci#include <asm/e820/api.h> 148c2ecf20Sopenharmony_ci#include <asm/io.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/* 178c2ecf20Sopenharmony_ci * When built for the regular kernel, several functions need to be stubbed out 188c2ecf20Sopenharmony_ci * or changed to their regular kernel equivalent. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci#ifndef KASLR_COMPRESSED_BOOT 218c2ecf20Sopenharmony_ci#include <asm/cpufeature.h> 228c2ecf20Sopenharmony_ci#include <asm/setup.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define debug_putstr(v) early_printk("%s", v) 258c2ecf20Sopenharmony_ci#define has_cpuflag(f) boot_cpu_has(f) 268c2ecf20Sopenharmony_ci#define get_boot_seed() kaslr_offset() 278c2ecf20Sopenharmony_ci#endif 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define I8254_PORT_CONTROL 0x43 308c2ecf20Sopenharmony_ci#define I8254_PORT_COUNTER0 0x40 318c2ecf20Sopenharmony_ci#define I8254_CMD_READBACK 0xC0 328c2ecf20Sopenharmony_ci#define I8254_SELECT_COUNTER0 0x02 338c2ecf20Sopenharmony_ci#define I8254_STATUS_NOTREADY 0x40 348c2ecf20Sopenharmony_cistatic inline u16 i8254(void) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci u16 status, timer; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci do { 398c2ecf20Sopenharmony_ci outb(I8254_CMD_READBACK | I8254_SELECT_COUNTER0, 408c2ecf20Sopenharmony_ci I8254_PORT_CONTROL); 418c2ecf20Sopenharmony_ci status = inb(I8254_PORT_COUNTER0); 428c2ecf20Sopenharmony_ci timer = inb(I8254_PORT_COUNTER0); 438c2ecf20Sopenharmony_ci timer |= inb(I8254_PORT_COUNTER0) << 8; 448c2ecf20Sopenharmony_ci } while (status & I8254_STATUS_NOTREADY); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci return timer; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ciunsigned long kaslr_get_random_long(const char *purpose) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 528c2ecf20Sopenharmony_ci const unsigned long mix_const = 0x5d6008cbf3848dd3UL; 538c2ecf20Sopenharmony_ci#else 548c2ecf20Sopenharmony_ci const unsigned long mix_const = 0x3f39e593UL; 558c2ecf20Sopenharmony_ci#endif 568c2ecf20Sopenharmony_ci unsigned long raw, random = get_boot_seed(); 578c2ecf20Sopenharmony_ci bool use_i8254 = true; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci debug_putstr(purpose); 608c2ecf20Sopenharmony_ci debug_putstr(" KASLR using"); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (has_cpuflag(X86_FEATURE_RDRAND)) { 638c2ecf20Sopenharmony_ci debug_putstr(" RDRAND"); 648c2ecf20Sopenharmony_ci if (rdrand_long(&raw)) { 658c2ecf20Sopenharmony_ci random ^= raw; 668c2ecf20Sopenharmony_ci use_i8254 = false; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (has_cpuflag(X86_FEATURE_TSC)) { 718c2ecf20Sopenharmony_ci debug_putstr(" RDTSC"); 728c2ecf20Sopenharmony_ci raw = rdtsc(); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci random ^= raw; 758c2ecf20Sopenharmony_ci use_i8254 = false; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (use_i8254) { 798c2ecf20Sopenharmony_ci debug_putstr(" i8254"); 808c2ecf20Sopenharmony_ci random ^= i8254(); 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* Circular multiply for better bit diffusion */ 848c2ecf20Sopenharmony_ci asm(_ASM_MUL "%3" 858c2ecf20Sopenharmony_ci : "=a" (random), "=d" (raw) 868c2ecf20Sopenharmony_ci : "a" (random), "rm" (mix_const)); 878c2ecf20Sopenharmony_ci random += raw; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci debug_putstr("...\n"); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci return random; 928c2ecf20Sopenharmony_ci} 93