1b2d24b97SGerald Schaefer // SPDX-License-Identifier: GPL-2.0 2b2d24b97SGerald Schaefer /* 3b2d24b97SGerald Schaefer * Copyright IBM Corp. 2019 4b2d24b97SGerald Schaefer */ 5b2d24b97SGerald Schaefer #include <asm/mem_detect.h> 6b2d24b97SGerald Schaefer #include <asm/cpacf.h> 7b2d24b97SGerald Schaefer #include <asm/timex.h> 8b2d24b97SGerald Schaefer #include <asm/sclp.h> 9b2d24b97SGerald Schaefer #include "compressed/decompressor.h" 10b2d24b97SGerald Schaefer 11b2d24b97SGerald Schaefer #define PRNG_MODE_TDES 1 12b2d24b97SGerald Schaefer #define PRNG_MODE_SHA512 2 13b2d24b97SGerald Schaefer #define PRNG_MODE_TRNG 3 14b2d24b97SGerald Schaefer 15b2d24b97SGerald Schaefer struct prno_parm { 16b2d24b97SGerald Schaefer u32 res; 17b2d24b97SGerald Schaefer u32 reseed_counter; 18b2d24b97SGerald Schaefer u64 stream_bytes; 19b2d24b97SGerald Schaefer u8 V[112]; 20b2d24b97SGerald Schaefer u8 C[112]; 21b2d24b97SGerald Schaefer }; 22b2d24b97SGerald Schaefer 23b2d24b97SGerald Schaefer struct prng_parm { 24b2d24b97SGerald Schaefer u8 parm_block[32]; 25b2d24b97SGerald Schaefer u32 reseed_counter; 26b2d24b97SGerald Schaefer u64 byte_counter; 27b2d24b97SGerald Schaefer }; 28b2d24b97SGerald Schaefer 29b2d24b97SGerald Schaefer static int check_prng(void) 30b2d24b97SGerald Schaefer { 31b2d24b97SGerald Schaefer if (!cpacf_query_func(CPACF_KMC, CPACF_KMC_PRNG)) { 32b2d24b97SGerald Schaefer sclp_early_printk("KASLR disabled: CPU has no PRNG\n"); 33b2d24b97SGerald Schaefer return 0; 34b2d24b97SGerald Schaefer } 35b2d24b97SGerald Schaefer if (cpacf_query_func(CPACF_PRNO, CPACF_PRNO_TRNG)) 36b2d24b97SGerald Schaefer return PRNG_MODE_TRNG; 37b2d24b97SGerald Schaefer if (cpacf_query_func(CPACF_PRNO, CPACF_PRNO_SHA512_DRNG_GEN)) 38b2d24b97SGerald Schaefer return PRNG_MODE_SHA512; 39b2d24b97SGerald Schaefer else 40b2d24b97SGerald Schaefer return PRNG_MODE_TDES; 41b2d24b97SGerald Schaefer } 42b2d24b97SGerald Schaefer 43b2d24b97SGerald Schaefer static unsigned long get_random(unsigned long limit) 44b2d24b97SGerald Schaefer { 45b2d24b97SGerald Schaefer struct prng_parm prng = { 46b2d24b97SGerald Schaefer /* initial parameter block for tdes mode, copied from libica */ 47b2d24b97SGerald Schaefer .parm_block = { 48b2d24b97SGerald Schaefer 0x0F, 0x2B, 0x8E, 0x63, 0x8C, 0x8E, 0xD2, 0x52, 49b2d24b97SGerald Schaefer 0x64, 0xB7, 0xA0, 0x7B, 0x75, 0x28, 0xB8, 0xF4, 50b2d24b97SGerald Schaefer 0x75, 0x5F, 0xD2, 0xA6, 0x8D, 0x97, 0x11, 0xFF, 51b2d24b97SGerald Schaefer 0x49, 0xD8, 0x23, 0xF3, 0x7E, 0x21, 0xEC, 0xA0 52b2d24b97SGerald Schaefer }, 53b2d24b97SGerald Schaefer }; 54b2d24b97SGerald Schaefer unsigned long seed, random; 55b2d24b97SGerald Schaefer struct prno_parm prno; 56b2d24b97SGerald Schaefer __u64 entropy[4]; 57b2d24b97SGerald Schaefer int mode, i; 58b2d24b97SGerald Schaefer 59b2d24b97SGerald Schaefer mode = check_prng(); 60b2d24b97SGerald Schaefer seed = get_tod_clock_fast(); 61b2d24b97SGerald Schaefer switch (mode) { 62b2d24b97SGerald Schaefer case PRNG_MODE_TRNG: 63b2d24b97SGerald Schaefer cpacf_trng(NULL, 0, (u8 *) &random, sizeof(random)); 64b2d24b97SGerald Schaefer break; 65b2d24b97SGerald Schaefer case PRNG_MODE_SHA512: 66b2d24b97SGerald Schaefer cpacf_prno(CPACF_PRNO_SHA512_DRNG_SEED, &prno, NULL, 0, 67b2d24b97SGerald Schaefer (u8 *) &seed, sizeof(seed)); 68b2d24b97SGerald Schaefer cpacf_prno(CPACF_PRNO_SHA512_DRNG_GEN, &prno, (u8 *) &random, 69b2d24b97SGerald Schaefer sizeof(random), NULL, 0); 70b2d24b97SGerald Schaefer break; 71b2d24b97SGerald Schaefer case PRNG_MODE_TDES: 72b2d24b97SGerald Schaefer /* add entropy */ 73b2d24b97SGerald Schaefer *(unsigned long *) prng.parm_block ^= seed; 74b2d24b97SGerald Schaefer for (i = 0; i < 16; i++) { 75b2d24b97SGerald Schaefer cpacf_kmc(CPACF_KMC_PRNG, prng.parm_block, 76b2d24b97SGerald Schaefer (char *) entropy, (char *) entropy, 77b2d24b97SGerald Schaefer sizeof(entropy)); 78b2d24b97SGerald Schaefer memcpy(prng.parm_block, entropy, sizeof(entropy)); 79b2d24b97SGerald Schaefer } 80b2d24b97SGerald Schaefer random = seed; 81b2d24b97SGerald Schaefer cpacf_kmc(CPACF_KMC_PRNG, prng.parm_block, (u8 *) &random, 82b2d24b97SGerald Schaefer (u8 *) &random, sizeof(random)); 83b2d24b97SGerald Schaefer break; 84b2d24b97SGerald Schaefer default: 85b2d24b97SGerald Schaefer random = 0; 86b2d24b97SGerald Schaefer } 87b2d24b97SGerald Schaefer return random % limit; 88b2d24b97SGerald Schaefer } 89b2d24b97SGerald Schaefer 90b2d24b97SGerald Schaefer unsigned long get_random_base(unsigned long safe_addr) 91b2d24b97SGerald Schaefer { 92b2d24b97SGerald Schaefer unsigned long base, start, end, kernel_size; 93b2d24b97SGerald Schaefer unsigned long block_sum, offset; 94b2d24b97SGerald Schaefer int i; 95b2d24b97SGerald Schaefer 96b2d24b97SGerald Schaefer if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && INITRD_START && INITRD_SIZE) { 97b2d24b97SGerald Schaefer if (safe_addr < INITRD_START + INITRD_SIZE) 98b2d24b97SGerald Schaefer safe_addr = INITRD_START + INITRD_SIZE; 99b2d24b97SGerald Schaefer } 100b2d24b97SGerald Schaefer safe_addr = ALIGN(safe_addr, THREAD_SIZE); 101b2d24b97SGerald Schaefer 102b2d24b97SGerald Schaefer kernel_size = vmlinux.image_size + vmlinux.bss_size; 103b2d24b97SGerald Schaefer block_sum = 0; 104b2d24b97SGerald Schaefer for_each_mem_detect_block(i, &start, &end) { 105b2d24b97SGerald Schaefer if (memory_end_set) { 106b2d24b97SGerald Schaefer if (start >= memory_end) 107b2d24b97SGerald Schaefer break; 108b2d24b97SGerald Schaefer if (end > memory_end) 109b2d24b97SGerald Schaefer end = memory_end; 110b2d24b97SGerald Schaefer } 111b2d24b97SGerald Schaefer if (end - start < kernel_size) 112b2d24b97SGerald Schaefer continue; 113b2d24b97SGerald Schaefer block_sum += end - start - kernel_size; 114b2d24b97SGerald Schaefer } 115b2d24b97SGerald Schaefer if (!block_sum) { 116b2d24b97SGerald Schaefer sclp_early_printk("KASLR disabled: not enough memory\n"); 117b2d24b97SGerald Schaefer return 0; 118b2d24b97SGerald Schaefer } 119b2d24b97SGerald Schaefer 120b2d24b97SGerald Schaefer base = get_random(block_sum); 121b2d24b97SGerald Schaefer if (base == 0) 122b2d24b97SGerald Schaefer return 0; 123b2d24b97SGerald Schaefer if (base < safe_addr) 124b2d24b97SGerald Schaefer base = safe_addr; 125b2d24b97SGerald Schaefer block_sum = offset = 0; 126b2d24b97SGerald Schaefer for_each_mem_detect_block(i, &start, &end) { 127b2d24b97SGerald Schaefer if (memory_end_set) { 128b2d24b97SGerald Schaefer if (start >= memory_end) 129b2d24b97SGerald Schaefer break; 130b2d24b97SGerald Schaefer if (end > memory_end) 131b2d24b97SGerald Schaefer end = memory_end; 132b2d24b97SGerald Schaefer } 133b2d24b97SGerald Schaefer if (end - start < kernel_size) 134b2d24b97SGerald Schaefer continue; 135b2d24b97SGerald Schaefer block_sum += end - start - kernel_size; 136b2d24b97SGerald Schaefer if (base <= block_sum) { 137b2d24b97SGerald Schaefer base = start + base - offset; 138b2d24b97SGerald Schaefer base = ALIGN_DOWN(base, THREAD_SIZE); 139b2d24b97SGerald Schaefer break; 140b2d24b97SGerald Schaefer } 141b2d24b97SGerald Schaefer offset = block_sum; 142b2d24b97SGerald Schaefer } 143b2d24b97SGerald Schaefer return base; 144b2d24b97SGerald Schaefer } 145