root/drivers/char/hw_random/s390-trng.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. trng_open
  2. trng_read
  3. trng_counter_show
  4. _trng_hwrng_read
  5. trng_hwrng_data_read
  6. trng_hwrng_read
  7. trng_debug_init
  8. trng_debug_exit
  9. trng_init
  10. trng_exit

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

/* [<][>][^][v][top][bottom][index][help] */