1*bbcb478eSHarald Freudenberger /* 2*bbcb478eSHarald Freudenberger * s390 TRNG device driver 3*bbcb478eSHarald Freudenberger * 4*bbcb478eSHarald Freudenberger * Driver for the TRNG (true random number generation) command 5*bbcb478eSHarald Freudenberger * available via CPACF extension MSA 7 on the s390 arch. 6*bbcb478eSHarald Freudenberger 7*bbcb478eSHarald Freudenberger * Copyright IBM Corp. 2017 8*bbcb478eSHarald Freudenberger * Author(s): Harald Freudenberger <freude@de.ibm.com> 9*bbcb478eSHarald Freudenberger * 10*bbcb478eSHarald Freudenberger * This program is free software; you can redistribute it and/or modify 11*bbcb478eSHarald Freudenberger * it under the terms of the GNU General Public License (version 2 only) 12*bbcb478eSHarald Freudenberger * as published by the Free Software Foundation. 13*bbcb478eSHarald Freudenberger * 14*bbcb478eSHarald Freudenberger */ 15*bbcb478eSHarald Freudenberger 16*bbcb478eSHarald Freudenberger #define KMSG_COMPONENT "trng" 17*bbcb478eSHarald Freudenberger #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 18*bbcb478eSHarald Freudenberger 19*bbcb478eSHarald Freudenberger #include <linux/hw_random.h> 20*bbcb478eSHarald Freudenberger #include <linux/kernel.h> 21*bbcb478eSHarald Freudenberger #include <linux/module.h> 22*bbcb478eSHarald Freudenberger #include <linux/cpufeature.h> 23*bbcb478eSHarald Freudenberger #include <linux/miscdevice.h> 24*bbcb478eSHarald Freudenberger #include <linux/debugfs.h> 25*bbcb478eSHarald Freudenberger #include <linux/atomic.h> 26*bbcb478eSHarald Freudenberger #include <linux/random.h> 27*bbcb478eSHarald Freudenberger #include <linux/sched/signal.h> 28*bbcb478eSHarald Freudenberger #include <asm/debug.h> 29*bbcb478eSHarald Freudenberger #include <asm/cpacf.h> 30*bbcb478eSHarald Freudenberger 31*bbcb478eSHarald Freudenberger MODULE_LICENSE("GPL v2"); 32*bbcb478eSHarald Freudenberger MODULE_AUTHOR("IBM Corporation"); 33*bbcb478eSHarald Freudenberger MODULE_DESCRIPTION("s390 CPACF TRNG device driver"); 34*bbcb478eSHarald Freudenberger 35*bbcb478eSHarald Freudenberger 36*bbcb478eSHarald Freudenberger /* trng related debug feature things */ 37*bbcb478eSHarald Freudenberger 38*bbcb478eSHarald Freudenberger static debug_info_t *debug_info; 39*bbcb478eSHarald Freudenberger 40*bbcb478eSHarald Freudenberger #define DEBUG_DBG(...) debug_sprintf_event(debug_info, 6, ##__VA_ARGS__) 41*bbcb478eSHarald Freudenberger #define DEBUG_INFO(...) debug_sprintf_event(debug_info, 5, ##__VA_ARGS__) 42*bbcb478eSHarald Freudenberger #define DEBUG_WARN(...) debug_sprintf_event(debug_info, 4, ##__VA_ARGS__) 43*bbcb478eSHarald Freudenberger #define DEBUG_ERR(...) debug_sprintf_event(debug_info, 3, ##__VA_ARGS__) 44*bbcb478eSHarald Freudenberger 45*bbcb478eSHarald Freudenberger 46*bbcb478eSHarald Freudenberger /* trng helpers */ 47*bbcb478eSHarald Freudenberger 48*bbcb478eSHarald Freudenberger static atomic64_t trng_dev_counter = ATOMIC64_INIT(0); 49*bbcb478eSHarald Freudenberger static atomic64_t trng_hwrng_counter = ATOMIC64_INIT(0); 50*bbcb478eSHarald Freudenberger 51*bbcb478eSHarald Freudenberger 52*bbcb478eSHarald Freudenberger /* file io functions */ 53*bbcb478eSHarald Freudenberger 54*bbcb478eSHarald Freudenberger static int trng_open(struct inode *inode, struct file *file) 55*bbcb478eSHarald Freudenberger { 56*bbcb478eSHarald Freudenberger return nonseekable_open(inode, file); 57*bbcb478eSHarald Freudenberger } 58*bbcb478eSHarald Freudenberger 59*bbcb478eSHarald Freudenberger static ssize_t trng_read(struct file *file, char __user *ubuf, 60*bbcb478eSHarald Freudenberger size_t nbytes, loff_t *ppos) 61*bbcb478eSHarald Freudenberger { 62*bbcb478eSHarald Freudenberger u8 buf[32]; 63*bbcb478eSHarald Freudenberger u8 *p = buf; 64*bbcb478eSHarald Freudenberger unsigned int n; 65*bbcb478eSHarald Freudenberger ssize_t ret = 0; 66*bbcb478eSHarald Freudenberger 67*bbcb478eSHarald Freudenberger /* 68*bbcb478eSHarald Freudenberger * use buf for requests <= sizeof(buf), 69*bbcb478eSHarald Freudenberger * otherwise allocate one page and fetch 70*bbcb478eSHarald Freudenberger * pagewise. 71*bbcb478eSHarald Freudenberger */ 72*bbcb478eSHarald Freudenberger 73*bbcb478eSHarald Freudenberger if (nbytes > sizeof(buf)) { 74*bbcb478eSHarald Freudenberger p = (u8 *) __get_free_page(GFP_KERNEL); 75*bbcb478eSHarald Freudenberger if (!p) 76*bbcb478eSHarald Freudenberger return -ENOMEM; 77*bbcb478eSHarald Freudenberger } 78*bbcb478eSHarald Freudenberger 79*bbcb478eSHarald Freudenberger while (nbytes) { 80*bbcb478eSHarald Freudenberger if (need_resched()) { 81*bbcb478eSHarald Freudenberger if (signal_pending(current)) { 82*bbcb478eSHarald Freudenberger if (ret == 0) 83*bbcb478eSHarald Freudenberger ret = -ERESTARTSYS; 84*bbcb478eSHarald Freudenberger break; 85*bbcb478eSHarald Freudenberger } 86*bbcb478eSHarald Freudenberger schedule(); 87*bbcb478eSHarald Freudenberger } 88*bbcb478eSHarald Freudenberger n = nbytes > PAGE_SIZE ? PAGE_SIZE : nbytes; 89*bbcb478eSHarald Freudenberger cpacf_trng(NULL, 0, p, n); 90*bbcb478eSHarald Freudenberger atomic64_add(n, &trng_dev_counter); 91*bbcb478eSHarald Freudenberger if (copy_to_user(ubuf, p, n)) { 92*bbcb478eSHarald Freudenberger ret = -EFAULT; 93*bbcb478eSHarald Freudenberger break; 94*bbcb478eSHarald Freudenberger } 95*bbcb478eSHarald Freudenberger nbytes -= n; 96*bbcb478eSHarald Freudenberger ubuf += n; 97*bbcb478eSHarald Freudenberger ret += n; 98*bbcb478eSHarald Freudenberger } 99*bbcb478eSHarald Freudenberger 100*bbcb478eSHarald Freudenberger if (p != buf) 101*bbcb478eSHarald Freudenberger free_page((unsigned long) p); 102*bbcb478eSHarald Freudenberger 103*bbcb478eSHarald Freudenberger DEBUG_DBG("trng_read()=%zd\n", ret); 104*bbcb478eSHarald Freudenberger return ret; 105*bbcb478eSHarald Freudenberger } 106*bbcb478eSHarald Freudenberger 107*bbcb478eSHarald Freudenberger 108*bbcb478eSHarald Freudenberger /* sysfs */ 109*bbcb478eSHarald Freudenberger 110*bbcb478eSHarald Freudenberger static ssize_t trng_counter_show(struct device *dev, 111*bbcb478eSHarald Freudenberger struct device_attribute *attr, char *buf) 112*bbcb478eSHarald Freudenberger { 113*bbcb478eSHarald Freudenberger u64 dev_counter = atomic64_read(&trng_dev_counter); 114*bbcb478eSHarald Freudenberger u64 hwrng_counter = atomic64_read(&trng_hwrng_counter); 115*bbcb478eSHarald Freudenberger #if IS_ENABLED(CONFIG_ARCH_RANDOM) 116*bbcb478eSHarald Freudenberger u64 arch_counter = atomic64_read(&s390_arch_random_counter); 117*bbcb478eSHarald Freudenberger 118*bbcb478eSHarald Freudenberger return snprintf(buf, PAGE_SIZE, 119*bbcb478eSHarald Freudenberger "trng: %llu\n" 120*bbcb478eSHarald Freudenberger "hwrng: %llu\n" 121*bbcb478eSHarald Freudenberger "arch: %llu\n" 122*bbcb478eSHarald Freudenberger "total: %llu\n", 123*bbcb478eSHarald Freudenberger dev_counter, hwrng_counter, arch_counter, 124*bbcb478eSHarald Freudenberger dev_counter + hwrng_counter + arch_counter); 125*bbcb478eSHarald Freudenberger #else 126*bbcb478eSHarald Freudenberger return snprintf(buf, PAGE_SIZE, 127*bbcb478eSHarald Freudenberger "trng: %llu\n" 128*bbcb478eSHarald Freudenberger "hwrng: %llu\n" 129*bbcb478eSHarald Freudenberger "total: %llu\n", 130*bbcb478eSHarald Freudenberger dev_counter, hwrng_counter, 131*bbcb478eSHarald Freudenberger dev_counter + hwrng_counter); 132*bbcb478eSHarald Freudenberger #endif 133*bbcb478eSHarald Freudenberger } 134*bbcb478eSHarald Freudenberger static DEVICE_ATTR(byte_counter, 0444, trng_counter_show, NULL); 135*bbcb478eSHarald Freudenberger 136*bbcb478eSHarald Freudenberger static struct attribute *trng_dev_attrs[] = { 137*bbcb478eSHarald Freudenberger &dev_attr_byte_counter.attr, 138*bbcb478eSHarald Freudenberger NULL 139*bbcb478eSHarald Freudenberger }; 140*bbcb478eSHarald Freudenberger 141*bbcb478eSHarald Freudenberger static const struct attribute_group trng_dev_attr_group = { 142*bbcb478eSHarald Freudenberger .attrs = trng_dev_attrs 143*bbcb478eSHarald Freudenberger }; 144*bbcb478eSHarald Freudenberger 145*bbcb478eSHarald Freudenberger static const struct attribute_group *trng_dev_attr_groups[] = { 146*bbcb478eSHarald Freudenberger &trng_dev_attr_group, 147*bbcb478eSHarald Freudenberger NULL 148*bbcb478eSHarald Freudenberger }; 149*bbcb478eSHarald Freudenberger 150*bbcb478eSHarald Freudenberger static const struct file_operations trng_fops = { 151*bbcb478eSHarald Freudenberger .owner = THIS_MODULE, 152*bbcb478eSHarald Freudenberger .open = &trng_open, 153*bbcb478eSHarald Freudenberger .release = NULL, 154*bbcb478eSHarald Freudenberger .read = &trng_read, 155*bbcb478eSHarald Freudenberger .llseek = noop_llseek, 156*bbcb478eSHarald Freudenberger }; 157*bbcb478eSHarald Freudenberger 158*bbcb478eSHarald Freudenberger static struct miscdevice trng_dev = { 159*bbcb478eSHarald Freudenberger .name = "trng", 160*bbcb478eSHarald Freudenberger .minor = MISC_DYNAMIC_MINOR, 161*bbcb478eSHarald Freudenberger .mode = 0444, 162*bbcb478eSHarald Freudenberger .fops = &trng_fops, 163*bbcb478eSHarald Freudenberger .groups = trng_dev_attr_groups, 164*bbcb478eSHarald Freudenberger }; 165*bbcb478eSHarald Freudenberger 166*bbcb478eSHarald Freudenberger 167*bbcb478eSHarald Freudenberger /* hwrng_register */ 168*bbcb478eSHarald Freudenberger 169*bbcb478eSHarald Freudenberger static inline void _trng_hwrng_read(u8 *buf, size_t len) 170*bbcb478eSHarald Freudenberger { 171*bbcb478eSHarald Freudenberger cpacf_trng(NULL, 0, buf, len); 172*bbcb478eSHarald Freudenberger atomic64_add(len, &trng_hwrng_counter); 173*bbcb478eSHarald Freudenberger } 174*bbcb478eSHarald Freudenberger 175*bbcb478eSHarald Freudenberger static int trng_hwrng_data_read(struct hwrng *rng, u32 *data) 176*bbcb478eSHarald Freudenberger { 177*bbcb478eSHarald Freudenberger size_t len = sizeof(*data); 178*bbcb478eSHarald Freudenberger 179*bbcb478eSHarald Freudenberger _trng_hwrng_read((u8 *) data, len); 180*bbcb478eSHarald Freudenberger 181*bbcb478eSHarald Freudenberger DEBUG_DBG("trng_hwrng_data_read()=%zu\n", len); 182*bbcb478eSHarald Freudenberger 183*bbcb478eSHarald Freudenberger return len; 184*bbcb478eSHarald Freudenberger } 185*bbcb478eSHarald Freudenberger 186*bbcb478eSHarald Freudenberger static int trng_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) 187*bbcb478eSHarald Freudenberger { 188*bbcb478eSHarald Freudenberger size_t len = max <= PAGE_SIZE ? max : PAGE_SIZE; 189*bbcb478eSHarald Freudenberger 190*bbcb478eSHarald Freudenberger _trng_hwrng_read((u8 *) data, len); 191*bbcb478eSHarald Freudenberger 192*bbcb478eSHarald Freudenberger DEBUG_DBG("trng_hwrng_read()=%zu\n", len); 193*bbcb478eSHarald Freudenberger 194*bbcb478eSHarald Freudenberger return len; 195*bbcb478eSHarald Freudenberger } 196*bbcb478eSHarald Freudenberger 197*bbcb478eSHarald Freudenberger /* 198*bbcb478eSHarald Freudenberger * hwrng register struct 199*bbcb478eSHarald Freudenberger * The trng is suppost to have 100% entropy, and thus 200*bbcb478eSHarald Freudenberger * we register with a very high quality value. 201*bbcb478eSHarald Freudenberger */ 202*bbcb478eSHarald Freudenberger static struct hwrng trng_hwrng_dev = { 203*bbcb478eSHarald Freudenberger .name = "s390-trng", 204*bbcb478eSHarald Freudenberger .data_read = trng_hwrng_data_read, 205*bbcb478eSHarald Freudenberger .read = trng_hwrng_read, 206*bbcb478eSHarald Freudenberger .quality = 999, 207*bbcb478eSHarald Freudenberger }; 208*bbcb478eSHarald Freudenberger 209*bbcb478eSHarald Freudenberger 210*bbcb478eSHarald Freudenberger /* init and exit */ 211*bbcb478eSHarald Freudenberger 212*bbcb478eSHarald Freudenberger static void __init trng_debug_init(void) 213*bbcb478eSHarald Freudenberger { 214*bbcb478eSHarald Freudenberger debug_info = debug_register("trng", 1, 1, 4 * sizeof(long)); 215*bbcb478eSHarald Freudenberger debug_register_view(debug_info, &debug_sprintf_view); 216*bbcb478eSHarald Freudenberger debug_set_level(debug_info, 3); 217*bbcb478eSHarald Freudenberger } 218*bbcb478eSHarald Freudenberger 219*bbcb478eSHarald Freudenberger static void trng_debug_exit(void) 220*bbcb478eSHarald Freudenberger { 221*bbcb478eSHarald Freudenberger debug_unregister(debug_info); 222*bbcb478eSHarald Freudenberger } 223*bbcb478eSHarald Freudenberger 224*bbcb478eSHarald Freudenberger static int __init trng_init(void) 225*bbcb478eSHarald Freudenberger { 226*bbcb478eSHarald Freudenberger int ret; 227*bbcb478eSHarald Freudenberger 228*bbcb478eSHarald Freudenberger trng_debug_init(); 229*bbcb478eSHarald Freudenberger 230*bbcb478eSHarald Freudenberger /* check if subfunction CPACF_PRNO_TRNG is available */ 231*bbcb478eSHarald Freudenberger if (!cpacf_query_func(CPACF_PRNO, CPACF_PRNO_TRNG)) { 232*bbcb478eSHarald Freudenberger DEBUG_INFO("trng_init CPACF_PRNO_TRNG not available\n"); 233*bbcb478eSHarald Freudenberger ret = -ENODEV; 234*bbcb478eSHarald Freudenberger goto out_dbg; 235*bbcb478eSHarald Freudenberger } 236*bbcb478eSHarald Freudenberger 237*bbcb478eSHarald Freudenberger ret = misc_register(&trng_dev); 238*bbcb478eSHarald Freudenberger if (ret) { 239*bbcb478eSHarald Freudenberger DEBUG_WARN("trng_init misc_register() failed rc=%d\n", ret); 240*bbcb478eSHarald Freudenberger goto out_dbg; 241*bbcb478eSHarald Freudenberger } 242*bbcb478eSHarald Freudenberger 243*bbcb478eSHarald Freudenberger ret = hwrng_register(&trng_hwrng_dev); 244*bbcb478eSHarald Freudenberger if (ret) { 245*bbcb478eSHarald Freudenberger DEBUG_WARN("trng_init hwrng_register() failed rc=%d\n", ret); 246*bbcb478eSHarald Freudenberger goto out_misc; 247*bbcb478eSHarald Freudenberger } 248*bbcb478eSHarald Freudenberger 249*bbcb478eSHarald Freudenberger DEBUG_DBG("trng_init successful\n"); 250*bbcb478eSHarald Freudenberger 251*bbcb478eSHarald Freudenberger return 0; 252*bbcb478eSHarald Freudenberger 253*bbcb478eSHarald Freudenberger out_misc: 254*bbcb478eSHarald Freudenberger misc_deregister(&trng_dev); 255*bbcb478eSHarald Freudenberger out_dbg: 256*bbcb478eSHarald Freudenberger trng_debug_exit(); 257*bbcb478eSHarald Freudenberger return ret; 258*bbcb478eSHarald Freudenberger } 259*bbcb478eSHarald Freudenberger 260*bbcb478eSHarald Freudenberger static void __exit trng_exit(void) 261*bbcb478eSHarald Freudenberger { 262*bbcb478eSHarald Freudenberger hwrng_unregister(&trng_hwrng_dev); 263*bbcb478eSHarald Freudenberger misc_deregister(&trng_dev); 264*bbcb478eSHarald Freudenberger trng_debug_exit(); 265*bbcb478eSHarald Freudenberger } 266*bbcb478eSHarald Freudenberger 267*bbcb478eSHarald Freudenberger module_cpu_feature_match(MSA, trng_init); 268*bbcb478eSHarald Freudenberger module_exit(trng_exit); 269