162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Test interface for Jitter RNG. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2023, Stephan Mueller <smueller@chronox.de> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/debugfs.h> 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/uaccess.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "jitterentropy.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define JENT_TEST_RINGBUFFER_SIZE (1<<10) 1562306a36Sopenharmony_ci#define JENT_TEST_RINGBUFFER_MASK (JENT_TEST_RINGBUFFER_SIZE - 1) 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistruct jent_testing { 1862306a36Sopenharmony_ci u32 jent_testing_rb[JENT_TEST_RINGBUFFER_SIZE]; 1962306a36Sopenharmony_ci u32 rb_reader; 2062306a36Sopenharmony_ci atomic_t rb_writer; 2162306a36Sopenharmony_ci atomic_t jent_testing_enabled; 2262306a36Sopenharmony_ci spinlock_t lock; 2362306a36Sopenharmony_ci wait_queue_head_t read_wait; 2462306a36Sopenharmony_ci}; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic struct dentry *jent_raw_debugfs_root = NULL; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/*************************** Generic Data Handling ****************************/ 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* 3162306a36Sopenharmony_ci * boot variable: 3262306a36Sopenharmony_ci * 0 ==> No boot test, gathering of runtime data allowed 3362306a36Sopenharmony_ci * 1 ==> Boot test enabled and ready for collecting data, gathering runtime 3462306a36Sopenharmony_ci * data is disabled 3562306a36Sopenharmony_ci * 2 ==> Boot test completed and disabled, gathering of runtime data is 3662306a36Sopenharmony_ci * disabled 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic void jent_testing_reset(struct jent_testing *data) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci unsigned long flags; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci spin_lock_irqsave(&data->lock, flags); 4462306a36Sopenharmony_ci data->rb_reader = 0; 4562306a36Sopenharmony_ci atomic_set(&data->rb_writer, 0); 4662306a36Sopenharmony_ci spin_unlock_irqrestore(&data->lock, flags); 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic void jent_testing_data_init(struct jent_testing *data, u32 boot) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci /* 5262306a36Sopenharmony_ci * The boot time testing implies we have a running test. If the 5362306a36Sopenharmony_ci * caller wants to clear it, he has to unset the boot_test flag 5462306a36Sopenharmony_ci * at runtime via sysfs to enable regular runtime testing 5562306a36Sopenharmony_ci */ 5662306a36Sopenharmony_ci if (boot) 5762306a36Sopenharmony_ci return; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci jent_testing_reset(data); 6062306a36Sopenharmony_ci atomic_set(&data->jent_testing_enabled, 1); 6162306a36Sopenharmony_ci pr_warn("Enabling data collection\n"); 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic void jent_testing_fini(struct jent_testing *data, u32 boot) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci /* If we have boot data, we do not reset yet to allow data to be read */ 6762306a36Sopenharmony_ci if (boot) 6862306a36Sopenharmony_ci return; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci atomic_set(&data->jent_testing_enabled, 0); 7162306a36Sopenharmony_ci jent_testing_reset(data); 7262306a36Sopenharmony_ci pr_warn("Disabling data collection\n"); 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic bool jent_testing_store(struct jent_testing *data, u32 value, 7662306a36Sopenharmony_ci u32 *boot) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci unsigned long flags; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (!atomic_read(&data->jent_testing_enabled) && (*boot != 1)) 8162306a36Sopenharmony_ci return false; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci spin_lock_irqsave(&data->lock, flags); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* 8662306a36Sopenharmony_ci * Disable entropy testing for boot time testing after ring buffer 8762306a36Sopenharmony_ci * is filled. 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ci if (*boot) { 9062306a36Sopenharmony_ci if (((u32)atomic_read(&data->rb_writer)) > 9162306a36Sopenharmony_ci JENT_TEST_RINGBUFFER_SIZE) { 9262306a36Sopenharmony_ci *boot = 2; 9362306a36Sopenharmony_ci pr_warn_once("One time data collection test disabled\n"); 9462306a36Sopenharmony_ci spin_unlock_irqrestore(&data->lock, flags); 9562306a36Sopenharmony_ci return false; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (atomic_read(&data->rb_writer) == 1) 9962306a36Sopenharmony_ci pr_warn("One time data collection test enabled\n"); 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci data->jent_testing_rb[((u32)atomic_read(&data->rb_writer)) & 10362306a36Sopenharmony_ci JENT_TEST_RINGBUFFER_MASK] = value; 10462306a36Sopenharmony_ci atomic_inc(&data->rb_writer); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci spin_unlock_irqrestore(&data->lock, flags); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (wq_has_sleeper(&data->read_wait)) 10962306a36Sopenharmony_ci wake_up_interruptible(&data->read_wait); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return true; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic bool jent_testing_have_data(struct jent_testing *data) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci return ((((u32)atomic_read(&data->rb_writer)) & 11762306a36Sopenharmony_ci JENT_TEST_RINGBUFFER_MASK) != 11862306a36Sopenharmony_ci (data->rb_reader & JENT_TEST_RINGBUFFER_MASK)); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic int jent_testing_reader(struct jent_testing *data, u32 *boot, 12262306a36Sopenharmony_ci u8 *outbuf, u32 outbuflen) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci unsigned long flags; 12562306a36Sopenharmony_ci int collected_data = 0; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci jent_testing_data_init(data, *boot); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci while (outbuflen) { 13062306a36Sopenharmony_ci u32 writer = (u32)atomic_read(&data->rb_writer); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci spin_lock_irqsave(&data->lock, flags); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci /* We have no data or reached the writer. */ 13562306a36Sopenharmony_ci if (!writer || (writer == data->rb_reader)) { 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci spin_unlock_irqrestore(&data->lock, flags); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci /* 14062306a36Sopenharmony_ci * Now we gathered all boot data, enable regular data 14162306a36Sopenharmony_ci * collection. 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_ci if (*boot) { 14462306a36Sopenharmony_ci *boot = 0; 14562306a36Sopenharmony_ci goto out; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci wait_event_interruptible(data->read_wait, 14962306a36Sopenharmony_ci jent_testing_have_data(data)); 15062306a36Sopenharmony_ci if (signal_pending(current)) { 15162306a36Sopenharmony_ci collected_data = -ERESTARTSYS; 15262306a36Sopenharmony_ci goto out; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci continue; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* We copy out word-wise */ 15962306a36Sopenharmony_ci if (outbuflen < sizeof(u32)) { 16062306a36Sopenharmony_ci spin_unlock_irqrestore(&data->lock, flags); 16162306a36Sopenharmony_ci goto out; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci memcpy(outbuf, &data->jent_testing_rb[data->rb_reader], 16562306a36Sopenharmony_ci sizeof(u32)); 16662306a36Sopenharmony_ci data->rb_reader++; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci spin_unlock_irqrestore(&data->lock, flags); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci outbuf += sizeof(u32); 17162306a36Sopenharmony_ci outbuflen -= sizeof(u32); 17262306a36Sopenharmony_ci collected_data += sizeof(u32); 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ciout: 17662306a36Sopenharmony_ci jent_testing_fini(data, *boot); 17762306a36Sopenharmony_ci return collected_data; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic int jent_testing_extract_user(struct file *file, char __user *buf, 18162306a36Sopenharmony_ci size_t nbytes, loff_t *ppos, 18262306a36Sopenharmony_ci int (*reader)(u8 *outbuf, u32 outbuflen)) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci u8 *tmp, *tmp_aligned; 18562306a36Sopenharmony_ci int ret = 0, large_request = (nbytes > 256); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (!nbytes) 18862306a36Sopenharmony_ci return 0; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* 19162306a36Sopenharmony_ci * The intention of this interface is for collecting at least 19262306a36Sopenharmony_ci * 1000 samples due to the SP800-90B requirements. So, we make no 19362306a36Sopenharmony_ci * effort in avoiding allocating more memory that actually needed 19462306a36Sopenharmony_ci * by the user. Hence, we allocate sufficient memory to always hold 19562306a36Sopenharmony_ci * that amount of data. 19662306a36Sopenharmony_ci */ 19762306a36Sopenharmony_ci tmp = kmalloc(JENT_TEST_RINGBUFFER_SIZE + sizeof(u32), GFP_KERNEL); 19862306a36Sopenharmony_ci if (!tmp) 19962306a36Sopenharmony_ci return -ENOMEM; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci tmp_aligned = PTR_ALIGN(tmp, sizeof(u32)); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci while (nbytes) { 20462306a36Sopenharmony_ci int i; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (large_request && need_resched()) { 20762306a36Sopenharmony_ci if (signal_pending(current)) { 20862306a36Sopenharmony_ci if (ret == 0) 20962306a36Sopenharmony_ci ret = -ERESTARTSYS; 21062306a36Sopenharmony_ci break; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci schedule(); 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci i = min_t(int, nbytes, JENT_TEST_RINGBUFFER_SIZE); 21662306a36Sopenharmony_ci i = reader(tmp_aligned, i); 21762306a36Sopenharmony_ci if (i <= 0) { 21862306a36Sopenharmony_ci if (i < 0) 21962306a36Sopenharmony_ci ret = i; 22062306a36Sopenharmony_ci break; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci if (copy_to_user(buf, tmp_aligned, i)) { 22362306a36Sopenharmony_ci ret = -EFAULT; 22462306a36Sopenharmony_ci break; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci nbytes -= i; 22862306a36Sopenharmony_ci buf += i; 22962306a36Sopenharmony_ci ret += i; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci kfree_sensitive(tmp); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (ret > 0) 23562306a36Sopenharmony_ci *ppos += ret; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci return ret; 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci/************** Raw High-Resolution Timer Entropy Data Handling **************/ 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic u32 boot_raw_hires_test = 0; 24362306a36Sopenharmony_cimodule_param(boot_raw_hires_test, uint, 0644); 24462306a36Sopenharmony_ciMODULE_PARM_DESC(boot_raw_hires_test, 24562306a36Sopenharmony_ci "Enable gathering boot time high resolution timer entropy of the first Jitter RNG entropy events"); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic struct jent_testing jent_raw_hires = { 24862306a36Sopenharmony_ci .rb_reader = 0, 24962306a36Sopenharmony_ci .rb_writer = ATOMIC_INIT(0), 25062306a36Sopenharmony_ci .lock = __SPIN_LOCK_UNLOCKED(jent_raw_hires.lock), 25162306a36Sopenharmony_ci .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(jent_raw_hires.read_wait) 25262306a36Sopenharmony_ci}; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ciint jent_raw_hires_entropy_store(__u32 value) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci return jent_testing_store(&jent_raw_hires, value, &boot_raw_hires_test); 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ciEXPORT_SYMBOL(jent_raw_hires_entropy_store); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic int jent_raw_hires_entropy_reader(u8 *outbuf, u32 outbuflen) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci return jent_testing_reader(&jent_raw_hires, &boot_raw_hires_test, 26362306a36Sopenharmony_ci outbuf, outbuflen); 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic ssize_t jent_raw_hires_read(struct file *file, char __user *to, 26762306a36Sopenharmony_ci size_t count, loff_t *ppos) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci return jent_testing_extract_user(file, to, count, ppos, 27062306a36Sopenharmony_ci jent_raw_hires_entropy_reader); 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic const struct file_operations jent_raw_hires_fops = { 27462306a36Sopenharmony_ci .owner = THIS_MODULE, 27562306a36Sopenharmony_ci .read = jent_raw_hires_read, 27662306a36Sopenharmony_ci}; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci/******************************* Initialization *******************************/ 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_civoid jent_testing_init(void) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci jent_raw_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci debugfs_create_file_unsafe("jent_raw_hires", 0400, 28562306a36Sopenharmony_ci jent_raw_debugfs_root, NULL, 28662306a36Sopenharmony_ci &jent_raw_hires_fops); 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ciEXPORT_SYMBOL(jent_testing_init); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_civoid jent_testing_exit(void) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci debugfs_remove_recursive(jent_raw_debugfs_root); 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ciEXPORT_SYMBOL(jent_testing_exit); 295