1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright IBM Corp. 2019 4 */ 5 #include <linux/pgtable.h> 6 #include <asm/physmem_info.h> 7 #include <asm/cpacf.h> 8 #include <asm/timex.h> 9 #include <asm/sclp.h> 10 #include <asm/kasan.h> 11 #include "decompressor.h" 12 #include "boot.h" 13 14 #define PRNG_MODE_TDES 1 15 #define PRNG_MODE_SHA512 2 16 #define PRNG_MODE_TRNG 3 17 18 struct prno_parm { 19 u32 res; 20 u32 reseed_counter; 21 u64 stream_bytes; 22 u8 V[112]; 23 u8 C[112]; 24 }; 25 26 struct prng_parm { 27 u8 parm_block[32]; 28 u32 reseed_counter; 29 u64 byte_counter; 30 }; 31 32 static int check_prng(void) 33 { 34 if (!cpacf_query_func(CPACF_KMC, CPACF_KMC_PRNG)) { 35 sclp_early_printk("KASLR disabled: CPU has no PRNG\n"); 36 return 0; 37 } 38 if (cpacf_query_func(CPACF_PRNO, CPACF_PRNO_TRNG)) 39 return PRNG_MODE_TRNG; 40 if (cpacf_query_func(CPACF_PRNO, CPACF_PRNO_SHA512_DRNG_GEN)) 41 return PRNG_MODE_SHA512; 42 else 43 return PRNG_MODE_TDES; 44 } 45 46 static int get_random(unsigned long limit, unsigned long *value) 47 { 48 struct prng_parm prng = { 49 /* initial parameter block for tdes mode, copied from libica */ 50 .parm_block = { 51 0x0F, 0x2B, 0x8E, 0x63, 0x8C, 0x8E, 0xD2, 0x52, 52 0x64, 0xB7, 0xA0, 0x7B, 0x75, 0x28, 0xB8, 0xF4, 53 0x75, 0x5F, 0xD2, 0xA6, 0x8D, 0x97, 0x11, 0xFF, 54 0x49, 0xD8, 0x23, 0xF3, 0x7E, 0x21, 0xEC, 0xA0 55 }, 56 }; 57 unsigned long seed, random; 58 struct prno_parm prno; 59 __u64 entropy[4]; 60 int mode, i; 61 62 mode = check_prng(); 63 seed = get_tod_clock_fast(); 64 switch (mode) { 65 case PRNG_MODE_TRNG: 66 cpacf_trng(NULL, 0, (u8 *) &random, sizeof(random)); 67 break; 68 case PRNG_MODE_SHA512: 69 cpacf_prno(CPACF_PRNO_SHA512_DRNG_SEED, &prno, NULL, 0, 70 (u8 *) &seed, sizeof(seed)); 71 cpacf_prno(CPACF_PRNO_SHA512_DRNG_GEN, &prno, (u8 *) &random, 72 sizeof(random), NULL, 0); 73 break; 74 case PRNG_MODE_TDES: 75 /* add entropy */ 76 *(unsigned long *) prng.parm_block ^= seed; 77 for (i = 0; i < 16; i++) { 78 cpacf_kmc(CPACF_KMC_PRNG, prng.parm_block, 79 (u8 *) entropy, (u8 *) entropy, 80 sizeof(entropy)); 81 memcpy(prng.parm_block, entropy, sizeof(entropy)); 82 } 83 random = seed; 84 cpacf_kmc(CPACF_KMC_PRNG, prng.parm_block, (u8 *) &random, 85 (u8 *) &random, sizeof(random)); 86 break; 87 default: 88 return -1; 89 } 90 *value = random % limit; 91 return 0; 92 } 93 94 unsigned long get_random_base(void) 95 { 96 unsigned long vmlinux_size = vmlinux.image_size + vmlinux.bss_size; 97 unsigned long minimal_pos = vmlinux.default_lma + vmlinux_size; 98 unsigned long random; 99 100 /* [vmlinux.default_lma + vmlinux.image_size + vmlinux.bss_size : physmem_info.usable] */ 101 if (get_random(physmem_info.usable - minimal_pos, &random)) 102 return 0; 103 104 return physmem_alloc_range(RR_VMLINUX, vmlinux_size, THREAD_SIZE, 105 vmlinux.default_lma, minimal_pos + random, false); 106 } 107