0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #define KMSG_COMPONENT "trng"
0013 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
0014
0015 #include <linux/hw_random.h>
0016 #include <linux/kernel.h>
0017 #include <linux/module.h>
0018 #include <linux/cpufeature.h>
0019 #include <linux/miscdevice.h>
0020 #include <linux/debugfs.h>
0021 #include <linux/atomic.h>
0022 #include <linux/random.h>
0023 #include <linux/sched/signal.h>
0024 #include <asm/debug.h>
0025 #include <asm/cpacf.h>
0026
0027 MODULE_LICENSE("GPL v2");
0028 MODULE_AUTHOR("IBM Corporation");
0029 MODULE_DESCRIPTION("s390 CPACF TRNG device driver");
0030
0031
0032
0033
0034 static debug_info_t *debug_info;
0035
0036 #define DEBUG_DBG(...) debug_sprintf_event(debug_info, 6, ##__VA_ARGS__)
0037 #define DEBUG_INFO(...) debug_sprintf_event(debug_info, 5, ##__VA_ARGS__)
0038 #define DEBUG_WARN(...) debug_sprintf_event(debug_info, 4, ##__VA_ARGS__)
0039 #define DEBUG_ERR(...) debug_sprintf_event(debug_info, 3, ##__VA_ARGS__)
0040
0041
0042
0043
0044 static atomic64_t trng_dev_counter = ATOMIC64_INIT(0);
0045 static atomic64_t trng_hwrng_counter = ATOMIC64_INIT(0);
0046
0047
0048
0049
0050 static int trng_open(struct inode *inode, struct file *file)
0051 {
0052 return nonseekable_open(inode, file);
0053 }
0054
0055 static ssize_t trng_read(struct file *file, char __user *ubuf,
0056 size_t nbytes, loff_t *ppos)
0057 {
0058 u8 buf[32];
0059 u8 *p = buf;
0060 unsigned int n;
0061 ssize_t ret = 0;
0062
0063
0064
0065
0066
0067
0068
0069 if (nbytes > sizeof(buf)) {
0070 p = (u8 *) __get_free_page(GFP_KERNEL);
0071 if (!p)
0072 return -ENOMEM;
0073 }
0074
0075 while (nbytes) {
0076 if (need_resched()) {
0077 if (signal_pending(current)) {
0078 if (ret == 0)
0079 ret = -ERESTARTSYS;
0080 break;
0081 }
0082 schedule();
0083 }
0084 n = nbytes > PAGE_SIZE ? PAGE_SIZE : nbytes;
0085 cpacf_trng(NULL, 0, p, n);
0086 atomic64_add(n, &trng_dev_counter);
0087 if (copy_to_user(ubuf, p, n)) {
0088 ret = -EFAULT;
0089 break;
0090 }
0091 nbytes -= n;
0092 ubuf += n;
0093 ret += n;
0094 }
0095
0096 if (p != buf)
0097 free_page((unsigned long) p);
0098
0099 DEBUG_DBG("trng_read()=%zd\n", ret);
0100 return ret;
0101 }
0102
0103
0104
0105
0106 static ssize_t trng_counter_show(struct device *dev,
0107 struct device_attribute *attr, char *buf)
0108 {
0109 u64 dev_counter = atomic64_read(&trng_dev_counter);
0110 u64 hwrng_counter = atomic64_read(&trng_hwrng_counter);
0111 u64 arch_counter = atomic64_read(&s390_arch_random_counter);
0112
0113 return sysfs_emit(buf,
0114 "trng: %llu\n"
0115 "hwrng: %llu\n"
0116 "arch: %llu\n"
0117 "total: %llu\n",
0118 dev_counter, hwrng_counter, arch_counter,
0119 dev_counter + hwrng_counter + arch_counter);
0120 }
0121 static DEVICE_ATTR(byte_counter, 0444, trng_counter_show, NULL);
0122
0123 static struct attribute *trng_dev_attrs[] = {
0124 &dev_attr_byte_counter.attr,
0125 NULL
0126 };
0127
0128 static const struct attribute_group trng_dev_attr_group = {
0129 .attrs = trng_dev_attrs
0130 };
0131
0132 static const struct attribute_group *trng_dev_attr_groups[] = {
0133 &trng_dev_attr_group,
0134 NULL
0135 };
0136
0137 static const struct file_operations trng_fops = {
0138 .owner = THIS_MODULE,
0139 .open = &trng_open,
0140 .release = NULL,
0141 .read = &trng_read,
0142 .llseek = noop_llseek,
0143 };
0144
0145 static struct miscdevice trng_dev = {
0146 .name = "trng",
0147 .minor = MISC_DYNAMIC_MINOR,
0148 .mode = 0444,
0149 .fops = &trng_fops,
0150 .groups = trng_dev_attr_groups,
0151 };
0152
0153
0154
0155
0156 static inline void _trng_hwrng_read(u8 *buf, size_t len)
0157 {
0158 cpacf_trng(NULL, 0, buf, len);
0159 atomic64_add(len, &trng_hwrng_counter);
0160 }
0161
0162 static int trng_hwrng_data_read(struct hwrng *rng, u32 *data)
0163 {
0164 size_t len = sizeof(*data);
0165
0166 _trng_hwrng_read((u8 *) data, len);
0167
0168 DEBUG_DBG("trng_hwrng_data_read()=%zu\n", len);
0169
0170 return len;
0171 }
0172
0173 static int trng_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
0174 {
0175 size_t len = max <= PAGE_SIZE ? max : PAGE_SIZE;
0176
0177 _trng_hwrng_read((u8 *) data, len);
0178
0179 DEBUG_DBG("trng_hwrng_read()=%zu\n", len);
0180
0181 return len;
0182 }
0183
0184
0185
0186
0187
0188
0189
0190 static struct hwrng trng_hwrng_dev = {
0191 .name = "s390-trng",
0192 .data_read = trng_hwrng_data_read,
0193 .read = trng_hwrng_read,
0194 .quality = 1024,
0195 };
0196
0197
0198
0199
0200 static void __init trng_debug_init(void)
0201 {
0202 debug_info = debug_register("trng", 1, 1, 4 * sizeof(long));
0203 debug_register_view(debug_info, &debug_sprintf_view);
0204 debug_set_level(debug_info, 3);
0205 }
0206
0207 static void trng_debug_exit(void)
0208 {
0209 debug_unregister(debug_info);
0210 }
0211
0212 static int __init trng_init(void)
0213 {
0214 int ret;
0215
0216 trng_debug_init();
0217
0218
0219 if (!cpacf_query_func(CPACF_PRNO, CPACF_PRNO_TRNG)) {
0220 DEBUG_INFO("trng_init CPACF_PRNO_TRNG not available\n");
0221 ret = -ENODEV;
0222 goto out_dbg;
0223 }
0224
0225 ret = misc_register(&trng_dev);
0226 if (ret) {
0227 DEBUG_WARN("trng_init misc_register() failed rc=%d\n", ret);
0228 goto out_dbg;
0229 }
0230
0231 ret = hwrng_register(&trng_hwrng_dev);
0232 if (ret) {
0233 DEBUG_WARN("trng_init hwrng_register() failed rc=%d\n", ret);
0234 goto out_misc;
0235 }
0236
0237 DEBUG_DBG("trng_init successful\n");
0238
0239 return 0;
0240
0241 out_misc:
0242 misc_deregister(&trng_dev);
0243 out_dbg:
0244 trng_debug_exit();
0245 return ret;
0246 }
0247
0248 static void __exit trng_exit(void)
0249 {
0250 hwrng_unregister(&trng_hwrng_dev);
0251 misc_deregister(&trng_dev);
0252 trng_debug_exit();
0253 }
0254
0255 module_cpu_feature_match(S390_CPU_FEATURE_MSA, trng_init);
0256 module_exit(trng_exit);