18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2006, 2015 48c2ecf20Sopenharmony_ci * Author(s): Jan Glauber <jan.glauber@de.ibm.com> 58c2ecf20Sopenharmony_ci * Harald Freudenberger <freude@de.ibm.com> 68c2ecf20Sopenharmony_ci * Driver for the s390 pseudo random number generator 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "prng" 108c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/fs.h> 138c2ecf20Sopenharmony_ci#include <linux/fips.h> 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/device.h> 178c2ecf20Sopenharmony_ci#include <linux/miscdevice.h> 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 208c2ecf20Sopenharmony_ci#include <linux/mutex.h> 218c2ecf20Sopenharmony_ci#include <linux/cpufeature.h> 228c2ecf20Sopenharmony_ci#include <linux/random.h> 238c2ecf20Sopenharmony_ci#include <linux/slab.h> 248c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <asm/debug.h> 278c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 288c2ecf20Sopenharmony_ci#include <asm/timex.h> 298c2ecf20Sopenharmony_ci#include <asm/cpacf.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 328c2ecf20Sopenharmony_ciMODULE_AUTHOR("IBM Corporation"); 338c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("s390 PRNG interface"); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define PRNG_MODE_AUTO 0 378c2ecf20Sopenharmony_ci#define PRNG_MODE_TDES 1 388c2ecf20Sopenharmony_ci#define PRNG_MODE_SHA512 2 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic unsigned int prng_mode = PRNG_MODE_AUTO; 418c2ecf20Sopenharmony_cimodule_param_named(mode, prng_mode, int, 0); 428c2ecf20Sopenharmony_ciMODULE_PARM_DESC(prng_mode, "PRNG mode: 0 - auto, 1 - TDES, 2 - SHA512"); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define PRNG_CHUNKSIZE_TDES_MIN 8 468c2ecf20Sopenharmony_ci#define PRNG_CHUNKSIZE_TDES_MAX (64*1024) 478c2ecf20Sopenharmony_ci#define PRNG_CHUNKSIZE_SHA512_MIN 64 488c2ecf20Sopenharmony_ci#define PRNG_CHUNKSIZE_SHA512_MAX (64*1024) 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic unsigned int prng_chunk_size = 256; 518c2ecf20Sopenharmony_cimodule_param_named(chunksize, prng_chunk_size, int, 0); 528c2ecf20Sopenharmony_ciMODULE_PARM_DESC(prng_chunk_size, "PRNG read chunk size in bytes"); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define PRNG_RESEED_LIMIT_TDES 4096 568c2ecf20Sopenharmony_ci#define PRNG_RESEED_LIMIT_TDES_LOWER 4096 578c2ecf20Sopenharmony_ci#define PRNG_RESEED_LIMIT_SHA512 100000 588c2ecf20Sopenharmony_ci#define PRNG_RESEED_LIMIT_SHA512_LOWER 10000 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic unsigned int prng_reseed_limit; 618c2ecf20Sopenharmony_cimodule_param_named(reseed_limit, prng_reseed_limit, int, 0); 628c2ecf20Sopenharmony_ciMODULE_PARM_DESC(prng_reseed_limit, "PRNG reseed limit"); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic bool trng_available; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* 678c2ecf20Sopenharmony_ci * Any one who considers arithmetical methods of producing random digits is, 688c2ecf20Sopenharmony_ci * of course, in a state of sin. -- John von Neumann 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic int prng_errorflag; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#define PRNG_GEN_ENTROPY_FAILED 1 748c2ecf20Sopenharmony_ci#define PRNG_SELFTEST_FAILED 2 758c2ecf20Sopenharmony_ci#define PRNG_INSTANTIATE_FAILED 3 768c2ecf20Sopenharmony_ci#define PRNG_SEED_FAILED 4 778c2ecf20Sopenharmony_ci#define PRNG_RESEED_FAILED 5 788c2ecf20Sopenharmony_ci#define PRNG_GEN_FAILED 6 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistruct prng_ws_s { 818c2ecf20Sopenharmony_ci u8 parm_block[32]; 828c2ecf20Sopenharmony_ci u32 reseed_counter; 838c2ecf20Sopenharmony_ci u64 byte_counter; 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistruct prno_ws_s { 878c2ecf20Sopenharmony_ci u32 res; 888c2ecf20Sopenharmony_ci u32 reseed_counter; 898c2ecf20Sopenharmony_ci u64 stream_bytes; 908c2ecf20Sopenharmony_ci u8 V[112]; 918c2ecf20Sopenharmony_ci u8 C[112]; 928c2ecf20Sopenharmony_ci}; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistruct prng_data_s { 958c2ecf20Sopenharmony_ci struct mutex mutex; 968c2ecf20Sopenharmony_ci union { 978c2ecf20Sopenharmony_ci struct prng_ws_s prngws; 988c2ecf20Sopenharmony_ci struct prno_ws_s prnows; 998c2ecf20Sopenharmony_ci }; 1008c2ecf20Sopenharmony_ci u8 *buf; 1018c2ecf20Sopenharmony_ci u32 rest; 1028c2ecf20Sopenharmony_ci u8 *prev; 1038c2ecf20Sopenharmony_ci}; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic struct prng_data_s *prng_data; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/* initial parameter block for tdes mode, copied from libica */ 1088c2ecf20Sopenharmony_cistatic const u8 initial_parm_block[32] __initconst = { 1098c2ecf20Sopenharmony_ci 0x0F, 0x2B, 0x8E, 0x63, 0x8C, 0x8E, 0xD2, 0x52, 1108c2ecf20Sopenharmony_ci 0x64, 0xB7, 0xA0, 0x7B, 0x75, 0x28, 0xB8, 0xF4, 1118c2ecf20Sopenharmony_ci 0x75, 0x5F, 0xD2, 0xA6, 0x8D, 0x97, 0x11, 0xFF, 1128c2ecf20Sopenharmony_ci 0x49, 0xD8, 0x23, 0xF3, 0x7E, 0x21, 0xEC, 0xA0 }; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/*** helper functions ***/ 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/* 1188c2ecf20Sopenharmony_ci * generate_entropy: 1198c2ecf20Sopenharmony_ci * This function fills a given buffer with random bytes. The entropy within 1208c2ecf20Sopenharmony_ci * the random bytes given back is assumed to have at least 50% - meaning 1218c2ecf20Sopenharmony_ci * a 64 bytes buffer has at least 64 * 8 / 2 = 256 bits of entropy. 1228c2ecf20Sopenharmony_ci * Within the function the entropy generation is done in junks of 64 bytes. 1238c2ecf20Sopenharmony_ci * So the caller should also ask for buffer fill in multiples of 64 bytes. 1248c2ecf20Sopenharmony_ci * The generation of the entropy is based on the assumption that every stckf() 1258c2ecf20Sopenharmony_ci * invocation produces 0.5 bits of entropy. To accumulate 256 bits of entropy 1268c2ecf20Sopenharmony_ci * at least 512 stckf() values are needed. The entropy relevant part of the 1278c2ecf20Sopenharmony_ci * stckf value is bit 51 (counting starts at the left with bit nr 0) so 1288c2ecf20Sopenharmony_ci * here we use the lower 4 bytes and exor the values into 2k of bufferspace. 1298c2ecf20Sopenharmony_ci * To be on the save side, if there is ever a problem with stckf() the 1308c2ecf20Sopenharmony_ci * other half of the page buffer is filled with bytes from urandom via 1318c2ecf20Sopenharmony_ci * get_random_bytes(), so this function consumes 2k of urandom for each 1328c2ecf20Sopenharmony_ci * requested 64 bytes output data. Finally the buffer page is condensed into 1338c2ecf20Sopenharmony_ci * a 64 byte value by hashing with a SHA512 hash. 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_cistatic int generate_entropy(u8 *ebuf, size_t nbytes) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci int n, ret = 0; 1388c2ecf20Sopenharmony_ci u8 *pg, pblock[80] = { 1398c2ecf20Sopenharmony_ci /* 8 x 64 bit init values */ 1408c2ecf20Sopenharmony_ci 0x6A, 0x09, 0xE6, 0x67, 0xF3, 0xBC, 0xC9, 0x08, 1418c2ecf20Sopenharmony_ci 0xBB, 0x67, 0xAE, 0x85, 0x84, 0xCA, 0xA7, 0x3B, 1428c2ecf20Sopenharmony_ci 0x3C, 0x6E, 0xF3, 0x72, 0xFE, 0x94, 0xF8, 0x2B, 1438c2ecf20Sopenharmony_ci 0xA5, 0x4F, 0xF5, 0x3A, 0x5F, 0x1D, 0x36, 0xF1, 1448c2ecf20Sopenharmony_ci 0x51, 0x0E, 0x52, 0x7F, 0xAD, 0xE6, 0x82, 0xD1, 1458c2ecf20Sopenharmony_ci 0x9B, 0x05, 0x68, 0x8C, 0x2B, 0x3E, 0x6C, 0x1F, 1468c2ecf20Sopenharmony_ci 0x1F, 0x83, 0xD9, 0xAB, 0xFB, 0x41, 0xBD, 0x6B, 1478c2ecf20Sopenharmony_ci 0x5B, 0xE0, 0xCD, 0x19, 0x13, 0x7E, 0x21, 0x79, 1488c2ecf20Sopenharmony_ci /* 128 bit counter total message bit length */ 1498c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1508c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 }; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* allocate one page stckf buffer */ 1538c2ecf20Sopenharmony_ci pg = (u8 *) __get_free_page(GFP_KERNEL); 1548c2ecf20Sopenharmony_ci if (!pg) { 1558c2ecf20Sopenharmony_ci prng_errorflag = PRNG_GEN_ENTROPY_FAILED; 1568c2ecf20Sopenharmony_ci return -ENOMEM; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* fill the ebuf in chunks of 64 byte each */ 1608c2ecf20Sopenharmony_ci while (nbytes) { 1618c2ecf20Sopenharmony_ci /* fill lower 2k with urandom bytes */ 1628c2ecf20Sopenharmony_ci get_random_bytes(pg, PAGE_SIZE / 2); 1638c2ecf20Sopenharmony_ci /* exor upper 2k with 512 stckf values, offset 4 bytes each */ 1648c2ecf20Sopenharmony_ci for (n = 0; n < 512; n++) { 1658c2ecf20Sopenharmony_ci int offset = (PAGE_SIZE / 2) + (n * 4) - 4; 1668c2ecf20Sopenharmony_ci u64 *p = (u64 *)(pg + offset); 1678c2ecf20Sopenharmony_ci *p ^= get_tod_clock_fast(); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci /* hash over the filled page */ 1708c2ecf20Sopenharmony_ci cpacf_klmd(CPACF_KLMD_SHA_512, pblock, pg, PAGE_SIZE); 1718c2ecf20Sopenharmony_ci n = (nbytes < 64) ? nbytes : 64; 1728c2ecf20Sopenharmony_ci memcpy(ebuf, pblock, n); 1738c2ecf20Sopenharmony_ci ret += n; 1748c2ecf20Sopenharmony_ci ebuf += n; 1758c2ecf20Sopenharmony_ci nbytes -= n; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci memzero_explicit(pblock, sizeof(pblock)); 1798c2ecf20Sopenharmony_ci memzero_explicit(pg, PAGE_SIZE); 1808c2ecf20Sopenharmony_ci free_page((unsigned long)pg); 1818c2ecf20Sopenharmony_ci return ret; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci/*** tdes functions ***/ 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic void prng_tdes_add_entropy(void) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci __u64 entropy[4]; 1908c2ecf20Sopenharmony_ci unsigned int i; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) { 1938c2ecf20Sopenharmony_ci cpacf_kmc(CPACF_KMC_PRNG, prng_data->prngws.parm_block, 1948c2ecf20Sopenharmony_ci (char *) entropy, (char *) entropy, 1958c2ecf20Sopenharmony_ci sizeof(entropy)); 1968c2ecf20Sopenharmony_ci memcpy(prng_data->prngws.parm_block, entropy, sizeof(entropy)); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic void prng_tdes_seed(int nbytes) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci char buf[16]; 2048c2ecf20Sopenharmony_ci int i = 0; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci BUG_ON(nbytes > sizeof(buf)); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci get_random_bytes(buf, nbytes); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* Add the entropy */ 2118c2ecf20Sopenharmony_ci while (nbytes >= 8) { 2128c2ecf20Sopenharmony_ci *((__u64 *)prng_data->prngws.parm_block) ^= *((__u64 *)(buf+i)); 2138c2ecf20Sopenharmony_ci prng_tdes_add_entropy(); 2148c2ecf20Sopenharmony_ci i += 8; 2158c2ecf20Sopenharmony_ci nbytes -= 8; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci prng_tdes_add_entropy(); 2188c2ecf20Sopenharmony_ci prng_data->prngws.reseed_counter = 0; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic int __init prng_tdes_instantiate(void) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci int datalen; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci pr_debug("prng runs in TDES mode with " 2278c2ecf20Sopenharmony_ci "chunksize=%d and reseed_limit=%u\n", 2288c2ecf20Sopenharmony_ci prng_chunk_size, prng_reseed_limit); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* memory allocation, prng_data struct init, mutex init */ 2318c2ecf20Sopenharmony_ci datalen = sizeof(struct prng_data_s) + prng_chunk_size; 2328c2ecf20Sopenharmony_ci prng_data = kzalloc(datalen, GFP_KERNEL); 2338c2ecf20Sopenharmony_ci if (!prng_data) { 2348c2ecf20Sopenharmony_ci prng_errorflag = PRNG_INSTANTIATE_FAILED; 2358c2ecf20Sopenharmony_ci return -ENOMEM; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci mutex_init(&prng_data->mutex); 2388c2ecf20Sopenharmony_ci prng_data->buf = ((u8 *)prng_data) + sizeof(struct prng_data_s); 2398c2ecf20Sopenharmony_ci memcpy(prng_data->prngws.parm_block, initial_parm_block, 32); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci /* initialize the PRNG, add 128 bits of entropy */ 2428c2ecf20Sopenharmony_ci prng_tdes_seed(16); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return 0; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic void prng_tdes_deinstantiate(void) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci pr_debug("The prng module stopped " 2518c2ecf20Sopenharmony_ci "after running in triple DES mode\n"); 2528c2ecf20Sopenharmony_ci kfree_sensitive(prng_data); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci/*** sha512 functions ***/ 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic int __init prng_sha512_selftest(void) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci /* NIST DRBG testvector for Hash Drbg, Sha-512, Count #0 */ 2618c2ecf20Sopenharmony_ci static const u8 seed[] __initconst = { 2628c2ecf20Sopenharmony_ci 0x6b, 0x50, 0xa7, 0xd8, 0xf8, 0xa5, 0x5d, 0x7a, 2638c2ecf20Sopenharmony_ci 0x3d, 0xf8, 0xbb, 0x40, 0xbc, 0xc3, 0xb7, 0x22, 2648c2ecf20Sopenharmony_ci 0xd8, 0x70, 0x8d, 0xe6, 0x7f, 0xda, 0x01, 0x0b, 2658c2ecf20Sopenharmony_ci 0x03, 0xc4, 0xc8, 0x4d, 0x72, 0x09, 0x6f, 0x8c, 2668c2ecf20Sopenharmony_ci 0x3e, 0xc6, 0x49, 0xcc, 0x62, 0x56, 0xd9, 0xfa, 2678c2ecf20Sopenharmony_ci 0x31, 0xdb, 0x7a, 0x29, 0x04, 0xaa, 0xf0, 0x25 }; 2688c2ecf20Sopenharmony_ci static const u8 V0[] __initconst = { 2698c2ecf20Sopenharmony_ci 0x00, 0xad, 0xe3, 0x6f, 0x9a, 0x01, 0xc7, 0x76, 2708c2ecf20Sopenharmony_ci 0x61, 0x34, 0x35, 0xf5, 0x4e, 0x24, 0x74, 0x22, 2718c2ecf20Sopenharmony_ci 0x21, 0x9a, 0x29, 0x89, 0xc7, 0x93, 0x2e, 0x60, 2728c2ecf20Sopenharmony_ci 0x1e, 0xe8, 0x14, 0x24, 0x8d, 0xd5, 0x03, 0xf1, 2738c2ecf20Sopenharmony_ci 0x65, 0x5d, 0x08, 0x22, 0x72, 0xd5, 0xad, 0x95, 2748c2ecf20Sopenharmony_ci 0xe1, 0x23, 0x1e, 0x8a, 0xa7, 0x13, 0xd9, 0x2b, 2758c2ecf20Sopenharmony_ci 0x5e, 0xbc, 0xbb, 0x80, 0xab, 0x8d, 0xe5, 0x79, 2768c2ecf20Sopenharmony_ci 0xab, 0x5b, 0x47, 0x4e, 0xdd, 0xee, 0x6b, 0x03, 2778c2ecf20Sopenharmony_ci 0x8f, 0x0f, 0x5c, 0x5e, 0xa9, 0x1a, 0x83, 0xdd, 2788c2ecf20Sopenharmony_ci 0xd3, 0x88, 0xb2, 0x75, 0x4b, 0xce, 0x83, 0x36, 2798c2ecf20Sopenharmony_ci 0x57, 0x4b, 0xf1, 0x5c, 0xca, 0x7e, 0x09, 0xc0, 2808c2ecf20Sopenharmony_ci 0xd3, 0x89, 0xc6, 0xe0, 0xda, 0xc4, 0x81, 0x7e, 2818c2ecf20Sopenharmony_ci 0x5b, 0xf9, 0xe1, 0x01, 0xc1, 0x92, 0x05, 0xea, 2828c2ecf20Sopenharmony_ci 0xf5, 0x2f, 0xc6, 0xc6, 0xc7, 0x8f, 0xbc, 0xf4 }; 2838c2ecf20Sopenharmony_ci static const u8 C0[] __initconst = { 2848c2ecf20Sopenharmony_ci 0x00, 0xf4, 0xa3, 0xe5, 0xa0, 0x72, 0x63, 0x95, 2858c2ecf20Sopenharmony_ci 0xc6, 0x4f, 0x48, 0xd0, 0x8b, 0x5b, 0x5f, 0x8e, 2868c2ecf20Sopenharmony_ci 0x6b, 0x96, 0x1f, 0x16, 0xed, 0xbc, 0x66, 0x94, 2878c2ecf20Sopenharmony_ci 0x45, 0x31, 0xd7, 0x47, 0x73, 0x22, 0xa5, 0x86, 2888c2ecf20Sopenharmony_ci 0xce, 0xc0, 0x4c, 0xac, 0x63, 0xb8, 0x39, 0x50, 2898c2ecf20Sopenharmony_ci 0xbf, 0xe6, 0x59, 0x6c, 0x38, 0x58, 0x99, 0x1f, 2908c2ecf20Sopenharmony_ci 0x27, 0xa7, 0x9d, 0x71, 0x2a, 0xb3, 0x7b, 0xf9, 2918c2ecf20Sopenharmony_ci 0xfb, 0x17, 0x86, 0xaa, 0x99, 0x81, 0xaa, 0x43, 2928c2ecf20Sopenharmony_ci 0xe4, 0x37, 0xd3, 0x1e, 0x6e, 0xe5, 0xe6, 0xee, 2938c2ecf20Sopenharmony_ci 0xc2, 0xed, 0x95, 0x4f, 0x53, 0x0e, 0x46, 0x8a, 2948c2ecf20Sopenharmony_ci 0xcc, 0x45, 0xa5, 0xdb, 0x69, 0x0d, 0x81, 0xc9, 2958c2ecf20Sopenharmony_ci 0x32, 0x92, 0xbc, 0x8f, 0x33, 0xe6, 0xf6, 0x09, 2968c2ecf20Sopenharmony_ci 0x7c, 0x8e, 0x05, 0x19, 0x0d, 0xf1, 0xb6, 0xcc, 2978c2ecf20Sopenharmony_ci 0xf3, 0x02, 0x21, 0x90, 0x25, 0xec, 0xed, 0x0e }; 2988c2ecf20Sopenharmony_ci static const u8 random[] __initconst = { 2998c2ecf20Sopenharmony_ci 0x95, 0xb7, 0xf1, 0x7e, 0x98, 0x02, 0xd3, 0x57, 3008c2ecf20Sopenharmony_ci 0x73, 0x92, 0xc6, 0xa9, 0xc0, 0x80, 0x83, 0xb6, 3018c2ecf20Sopenharmony_ci 0x7d, 0xd1, 0x29, 0x22, 0x65, 0xb5, 0xf4, 0x2d, 3028c2ecf20Sopenharmony_ci 0x23, 0x7f, 0x1c, 0x55, 0xbb, 0x9b, 0x10, 0xbf, 3038c2ecf20Sopenharmony_ci 0xcf, 0xd8, 0x2c, 0x77, 0xa3, 0x78, 0xb8, 0x26, 3048c2ecf20Sopenharmony_ci 0x6a, 0x00, 0x99, 0x14, 0x3b, 0x3c, 0x2d, 0x64, 3058c2ecf20Sopenharmony_ci 0x61, 0x1e, 0xee, 0xb6, 0x9a, 0xcd, 0xc0, 0x55, 3068c2ecf20Sopenharmony_ci 0x95, 0x7c, 0x13, 0x9e, 0x8b, 0x19, 0x0c, 0x7a, 3078c2ecf20Sopenharmony_ci 0x06, 0x95, 0x5f, 0x2c, 0x79, 0x7c, 0x27, 0x78, 3088c2ecf20Sopenharmony_ci 0xde, 0x94, 0x03, 0x96, 0xa5, 0x01, 0xf4, 0x0e, 3098c2ecf20Sopenharmony_ci 0x91, 0x39, 0x6a, 0xcf, 0x8d, 0x7e, 0x45, 0xeb, 3108c2ecf20Sopenharmony_ci 0xdb, 0xb5, 0x3b, 0xbf, 0x8c, 0x97, 0x52, 0x30, 3118c2ecf20Sopenharmony_ci 0xd2, 0xf0, 0xff, 0x91, 0x06, 0xc7, 0x61, 0x19, 3128c2ecf20Sopenharmony_ci 0xae, 0x49, 0x8e, 0x7f, 0xbc, 0x03, 0xd9, 0x0f, 3138c2ecf20Sopenharmony_ci 0x8e, 0x4c, 0x51, 0x62, 0x7a, 0xed, 0x5c, 0x8d, 3148c2ecf20Sopenharmony_ci 0x42, 0x63, 0xd5, 0xd2, 0xb9, 0x78, 0x87, 0x3a, 3158c2ecf20Sopenharmony_ci 0x0d, 0xe5, 0x96, 0xee, 0x6d, 0xc7, 0xf7, 0xc2, 3168c2ecf20Sopenharmony_ci 0x9e, 0x37, 0xee, 0xe8, 0xb3, 0x4c, 0x90, 0xdd, 3178c2ecf20Sopenharmony_ci 0x1c, 0xf6, 0xa9, 0xdd, 0xb2, 0x2b, 0x4c, 0xbd, 3188c2ecf20Sopenharmony_ci 0x08, 0x6b, 0x14, 0xb3, 0x5d, 0xe9, 0x3d, 0xa2, 3198c2ecf20Sopenharmony_ci 0xd5, 0xcb, 0x18, 0x06, 0x69, 0x8c, 0xbd, 0x7b, 3208c2ecf20Sopenharmony_ci 0xbb, 0x67, 0xbf, 0xe3, 0xd3, 0x1f, 0xd2, 0xd1, 3218c2ecf20Sopenharmony_ci 0xdb, 0xd2, 0xa1, 0xe0, 0x58, 0xa3, 0xeb, 0x99, 3228c2ecf20Sopenharmony_ci 0xd7, 0xe5, 0x1f, 0x1a, 0x93, 0x8e, 0xed, 0x5e, 3238c2ecf20Sopenharmony_ci 0x1c, 0x1d, 0xe2, 0x3a, 0x6b, 0x43, 0x45, 0xd3, 3248c2ecf20Sopenharmony_ci 0x19, 0x14, 0x09, 0xf9, 0x2f, 0x39, 0xb3, 0x67, 3258c2ecf20Sopenharmony_ci 0x0d, 0x8d, 0xbf, 0xb6, 0x35, 0xd8, 0xe6, 0xa3, 3268c2ecf20Sopenharmony_ci 0x69, 0x32, 0xd8, 0x10, 0x33, 0xd1, 0x44, 0x8d, 3278c2ecf20Sopenharmony_ci 0x63, 0xb4, 0x03, 0xdd, 0xf8, 0x8e, 0x12, 0x1b, 3288c2ecf20Sopenharmony_ci 0x6e, 0x81, 0x9a, 0xc3, 0x81, 0x22, 0x6c, 0x13, 3298c2ecf20Sopenharmony_ci 0x21, 0xe4, 0xb0, 0x86, 0x44, 0xf6, 0x72, 0x7c, 3308c2ecf20Sopenharmony_ci 0x36, 0x8c, 0x5a, 0x9f, 0x7a, 0x4b, 0x3e, 0xe2 }; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci u8 buf[sizeof(random)]; 3338c2ecf20Sopenharmony_ci struct prno_ws_s ws; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci memset(&ws, 0, sizeof(ws)); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* initial seed */ 3388c2ecf20Sopenharmony_ci cpacf_prno(CPACF_PRNO_SHA512_DRNG_SEED, 3398c2ecf20Sopenharmony_ci &ws, NULL, 0, seed, sizeof(seed)); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* check working states V and C */ 3428c2ecf20Sopenharmony_ci if (memcmp(ws.V, V0, sizeof(V0)) != 0 3438c2ecf20Sopenharmony_ci || memcmp(ws.C, C0, sizeof(C0)) != 0) { 3448c2ecf20Sopenharmony_ci pr_err("The prng self test state test " 3458c2ecf20Sopenharmony_ci "for the SHA-512 mode failed\n"); 3468c2ecf20Sopenharmony_ci prng_errorflag = PRNG_SELFTEST_FAILED; 3478c2ecf20Sopenharmony_ci return -EIO; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* generate random bytes */ 3518c2ecf20Sopenharmony_ci cpacf_prno(CPACF_PRNO_SHA512_DRNG_GEN, 3528c2ecf20Sopenharmony_ci &ws, buf, sizeof(buf), NULL, 0); 3538c2ecf20Sopenharmony_ci cpacf_prno(CPACF_PRNO_SHA512_DRNG_GEN, 3548c2ecf20Sopenharmony_ci &ws, buf, sizeof(buf), NULL, 0); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* check against expected data */ 3578c2ecf20Sopenharmony_ci if (memcmp(buf, random, sizeof(random)) != 0) { 3588c2ecf20Sopenharmony_ci pr_err("The prng self test data test " 3598c2ecf20Sopenharmony_ci "for the SHA-512 mode failed\n"); 3608c2ecf20Sopenharmony_ci prng_errorflag = PRNG_SELFTEST_FAILED; 3618c2ecf20Sopenharmony_ci return -EIO; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci return 0; 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic int __init prng_sha512_instantiate(void) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci int ret, datalen, seedlen; 3718c2ecf20Sopenharmony_ci u8 seed[128 + 16]; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci pr_debug("prng runs in SHA-512 mode " 3748c2ecf20Sopenharmony_ci "with chunksize=%d and reseed_limit=%u\n", 3758c2ecf20Sopenharmony_ci prng_chunk_size, prng_reseed_limit); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci /* memory allocation, prng_data struct init, mutex init */ 3788c2ecf20Sopenharmony_ci datalen = sizeof(struct prng_data_s) + prng_chunk_size; 3798c2ecf20Sopenharmony_ci if (fips_enabled) 3808c2ecf20Sopenharmony_ci datalen += prng_chunk_size; 3818c2ecf20Sopenharmony_ci prng_data = kzalloc(datalen, GFP_KERNEL); 3828c2ecf20Sopenharmony_ci if (!prng_data) { 3838c2ecf20Sopenharmony_ci prng_errorflag = PRNG_INSTANTIATE_FAILED; 3848c2ecf20Sopenharmony_ci return -ENOMEM; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci mutex_init(&prng_data->mutex); 3878c2ecf20Sopenharmony_ci prng_data->buf = ((u8 *)prng_data) + sizeof(struct prng_data_s); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* selftest */ 3908c2ecf20Sopenharmony_ci ret = prng_sha512_selftest(); 3918c2ecf20Sopenharmony_ci if (ret) 3928c2ecf20Sopenharmony_ci goto outfree; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci /* generate initial seed, we need at least 256 + 128 bits entropy. */ 3958c2ecf20Sopenharmony_ci if (trng_available) { 3968c2ecf20Sopenharmony_ci /* 3978c2ecf20Sopenharmony_ci * Trng available, so use it. The trng works in chunks of 3988c2ecf20Sopenharmony_ci * 32 bytes and produces 100% entropy. So we pull 64 bytes 3998c2ecf20Sopenharmony_ci * which gives us 512 bits entropy. 4008c2ecf20Sopenharmony_ci */ 4018c2ecf20Sopenharmony_ci seedlen = 2 * 32; 4028c2ecf20Sopenharmony_ci cpacf_trng(NULL, 0, seed, seedlen); 4038c2ecf20Sopenharmony_ci } else { 4048c2ecf20Sopenharmony_ci /* 4058c2ecf20Sopenharmony_ci * No trng available, so use the generate_entropy() function. 4068c2ecf20Sopenharmony_ci * This function works in 64 byte junks and produces 4078c2ecf20Sopenharmony_ci * 50% entropy. So we pull 2*64 bytes which gives us 512 bits 4088c2ecf20Sopenharmony_ci * of entropy. 4098c2ecf20Sopenharmony_ci */ 4108c2ecf20Sopenharmony_ci seedlen = 2 * 64; 4118c2ecf20Sopenharmony_ci ret = generate_entropy(seed, seedlen); 4128c2ecf20Sopenharmony_ci if (ret != seedlen) 4138c2ecf20Sopenharmony_ci goto outfree; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci /* append the seed by 16 bytes of unique nonce */ 4178c2ecf20Sopenharmony_ci get_tod_clock_ext(seed + seedlen); 4188c2ecf20Sopenharmony_ci seedlen += 16; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci /* now initial seed of the prno drng */ 4218c2ecf20Sopenharmony_ci cpacf_prno(CPACF_PRNO_SHA512_DRNG_SEED, 4228c2ecf20Sopenharmony_ci &prng_data->prnows, NULL, 0, seed, seedlen); 4238c2ecf20Sopenharmony_ci memzero_explicit(seed, sizeof(seed)); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* if fips mode is enabled, generate a first block of random 4268c2ecf20Sopenharmony_ci bytes for the FIPS 140-2 Conditional Self Test */ 4278c2ecf20Sopenharmony_ci if (fips_enabled) { 4288c2ecf20Sopenharmony_ci prng_data->prev = prng_data->buf + prng_chunk_size; 4298c2ecf20Sopenharmony_ci cpacf_prno(CPACF_PRNO_SHA512_DRNG_GEN, 4308c2ecf20Sopenharmony_ci &prng_data->prnows, 4318c2ecf20Sopenharmony_ci prng_data->prev, prng_chunk_size, NULL, 0); 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci return 0; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cioutfree: 4378c2ecf20Sopenharmony_ci kfree(prng_data); 4388c2ecf20Sopenharmony_ci return ret; 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic void prng_sha512_deinstantiate(void) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci pr_debug("The prng module stopped after running in SHA-512 mode\n"); 4458c2ecf20Sopenharmony_ci kfree_sensitive(prng_data); 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic int prng_sha512_reseed(void) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci int ret, seedlen; 4528c2ecf20Sopenharmony_ci u8 seed[64]; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci /* We need at least 256 bits of fresh entropy for reseeding */ 4558c2ecf20Sopenharmony_ci if (trng_available) { 4568c2ecf20Sopenharmony_ci /* trng produces 256 bits entropy in 32 bytes */ 4578c2ecf20Sopenharmony_ci seedlen = 32; 4588c2ecf20Sopenharmony_ci cpacf_trng(NULL, 0, seed, seedlen); 4598c2ecf20Sopenharmony_ci } else { 4608c2ecf20Sopenharmony_ci /* generate_entropy() produces 256 bits entropy in 64 bytes */ 4618c2ecf20Sopenharmony_ci seedlen = 64; 4628c2ecf20Sopenharmony_ci ret = generate_entropy(seed, seedlen); 4638c2ecf20Sopenharmony_ci if (ret != sizeof(seed)) 4648c2ecf20Sopenharmony_ci return ret; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci /* do a reseed of the prno drng with this bytestring */ 4688c2ecf20Sopenharmony_ci cpacf_prno(CPACF_PRNO_SHA512_DRNG_SEED, 4698c2ecf20Sopenharmony_ci &prng_data->prnows, NULL, 0, seed, seedlen); 4708c2ecf20Sopenharmony_ci memzero_explicit(seed, sizeof(seed)); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci return 0; 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic int prng_sha512_generate(u8 *buf, size_t nbytes) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci int ret; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci /* reseed needed ? */ 4818c2ecf20Sopenharmony_ci if (prng_data->prnows.reseed_counter > prng_reseed_limit) { 4828c2ecf20Sopenharmony_ci ret = prng_sha512_reseed(); 4838c2ecf20Sopenharmony_ci if (ret) 4848c2ecf20Sopenharmony_ci return ret; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* PRNO generate */ 4888c2ecf20Sopenharmony_ci cpacf_prno(CPACF_PRNO_SHA512_DRNG_GEN, 4898c2ecf20Sopenharmony_ci &prng_data->prnows, buf, nbytes, NULL, 0); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci /* FIPS 140-2 Conditional Self Test */ 4928c2ecf20Sopenharmony_ci if (fips_enabled) { 4938c2ecf20Sopenharmony_ci if (!memcmp(prng_data->prev, buf, nbytes)) { 4948c2ecf20Sopenharmony_ci prng_errorflag = PRNG_GEN_FAILED; 4958c2ecf20Sopenharmony_ci return -EILSEQ; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci memcpy(prng_data->prev, buf, nbytes); 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci return nbytes; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci/*** file io functions ***/ 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic int prng_open(struct inode *inode, struct file *file) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci return nonseekable_open(inode, file); 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic ssize_t prng_tdes_read(struct file *file, char __user *ubuf, 5138c2ecf20Sopenharmony_ci size_t nbytes, loff_t *ppos) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci int chunk, n, ret = 0; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci /* lock prng_data struct */ 5188c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&prng_data->mutex)) 5198c2ecf20Sopenharmony_ci return -ERESTARTSYS; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci while (nbytes) { 5228c2ecf20Sopenharmony_ci if (need_resched()) { 5238c2ecf20Sopenharmony_ci if (signal_pending(current)) { 5248c2ecf20Sopenharmony_ci if (ret == 0) 5258c2ecf20Sopenharmony_ci ret = -ERESTARTSYS; 5268c2ecf20Sopenharmony_ci break; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci /* give mutex free before calling schedule() */ 5298c2ecf20Sopenharmony_ci mutex_unlock(&prng_data->mutex); 5308c2ecf20Sopenharmony_ci schedule(); 5318c2ecf20Sopenharmony_ci /* occopy mutex again */ 5328c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&prng_data->mutex)) { 5338c2ecf20Sopenharmony_ci if (ret == 0) 5348c2ecf20Sopenharmony_ci ret = -ERESTARTSYS; 5358c2ecf20Sopenharmony_ci return ret; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci /* 5408c2ecf20Sopenharmony_ci * we lose some random bytes if an attacker issues 5418c2ecf20Sopenharmony_ci * reads < 8 bytes, but we don't care 5428c2ecf20Sopenharmony_ci */ 5438c2ecf20Sopenharmony_ci chunk = min_t(int, nbytes, prng_chunk_size); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci /* PRNG only likes multiples of 8 bytes */ 5468c2ecf20Sopenharmony_ci n = (chunk + 7) & -8; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (prng_data->prngws.reseed_counter > prng_reseed_limit) 5498c2ecf20Sopenharmony_ci prng_tdes_seed(8); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci /* if the CPU supports PRNG stckf is present too */ 5528c2ecf20Sopenharmony_ci *((unsigned long long *)prng_data->buf) = get_tod_clock_fast(); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci /* 5558c2ecf20Sopenharmony_ci * Beside the STCKF the input for the TDES-EDE is the output 5568c2ecf20Sopenharmony_ci * of the last operation. We differ here from X9.17 since we 5578c2ecf20Sopenharmony_ci * only store one timestamp into the buffer. Padding the whole 5588c2ecf20Sopenharmony_ci * buffer with timestamps does not improve security, since 5598c2ecf20Sopenharmony_ci * successive stckf have nearly constant offsets. 5608c2ecf20Sopenharmony_ci * If an attacker knows the first timestamp it would be 5618c2ecf20Sopenharmony_ci * trivial to guess the additional values. One timestamp 5628c2ecf20Sopenharmony_ci * is therefore enough and still guarantees unique input values. 5638c2ecf20Sopenharmony_ci * 5648c2ecf20Sopenharmony_ci * Note: you can still get strict X9.17 conformity by setting 5658c2ecf20Sopenharmony_ci * prng_chunk_size to 8 bytes. 5668c2ecf20Sopenharmony_ci */ 5678c2ecf20Sopenharmony_ci cpacf_kmc(CPACF_KMC_PRNG, prng_data->prngws.parm_block, 5688c2ecf20Sopenharmony_ci prng_data->buf, prng_data->buf, n); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci prng_data->prngws.byte_counter += n; 5718c2ecf20Sopenharmony_ci prng_data->prngws.reseed_counter += n; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci if (copy_to_user(ubuf, prng_data->buf, chunk)) { 5748c2ecf20Sopenharmony_ci ret = -EFAULT; 5758c2ecf20Sopenharmony_ci break; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci nbytes -= chunk; 5798c2ecf20Sopenharmony_ci ret += chunk; 5808c2ecf20Sopenharmony_ci ubuf += chunk; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci /* unlock prng_data struct */ 5848c2ecf20Sopenharmony_ci mutex_unlock(&prng_data->mutex); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci return ret; 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_cistatic ssize_t prng_sha512_read(struct file *file, char __user *ubuf, 5918c2ecf20Sopenharmony_ci size_t nbytes, loff_t *ppos) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci int n, ret = 0; 5948c2ecf20Sopenharmony_ci u8 *p; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* if errorflag is set do nothing and return 'broken pipe' */ 5978c2ecf20Sopenharmony_ci if (prng_errorflag) 5988c2ecf20Sopenharmony_ci return -EPIPE; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci /* lock prng_data struct */ 6018c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&prng_data->mutex)) 6028c2ecf20Sopenharmony_ci return -ERESTARTSYS; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci while (nbytes) { 6058c2ecf20Sopenharmony_ci if (need_resched()) { 6068c2ecf20Sopenharmony_ci if (signal_pending(current)) { 6078c2ecf20Sopenharmony_ci if (ret == 0) 6088c2ecf20Sopenharmony_ci ret = -ERESTARTSYS; 6098c2ecf20Sopenharmony_ci break; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci /* give mutex free before calling schedule() */ 6128c2ecf20Sopenharmony_ci mutex_unlock(&prng_data->mutex); 6138c2ecf20Sopenharmony_ci schedule(); 6148c2ecf20Sopenharmony_ci /* occopy mutex again */ 6158c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&prng_data->mutex)) { 6168c2ecf20Sopenharmony_ci if (ret == 0) 6178c2ecf20Sopenharmony_ci ret = -ERESTARTSYS; 6188c2ecf20Sopenharmony_ci return ret; 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci if (prng_data->rest) { 6228c2ecf20Sopenharmony_ci /* push left over random bytes from the previous read */ 6238c2ecf20Sopenharmony_ci p = prng_data->buf + prng_chunk_size - prng_data->rest; 6248c2ecf20Sopenharmony_ci n = (nbytes < prng_data->rest) ? 6258c2ecf20Sopenharmony_ci nbytes : prng_data->rest; 6268c2ecf20Sopenharmony_ci prng_data->rest -= n; 6278c2ecf20Sopenharmony_ci } else { 6288c2ecf20Sopenharmony_ci /* generate one chunk of random bytes into read buf */ 6298c2ecf20Sopenharmony_ci p = prng_data->buf; 6308c2ecf20Sopenharmony_ci n = prng_sha512_generate(p, prng_chunk_size); 6318c2ecf20Sopenharmony_ci if (n < 0) { 6328c2ecf20Sopenharmony_ci ret = n; 6338c2ecf20Sopenharmony_ci break; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci if (nbytes < prng_chunk_size) { 6368c2ecf20Sopenharmony_ci n = nbytes; 6378c2ecf20Sopenharmony_ci prng_data->rest = prng_chunk_size - n; 6388c2ecf20Sopenharmony_ci } else { 6398c2ecf20Sopenharmony_ci n = prng_chunk_size; 6408c2ecf20Sopenharmony_ci prng_data->rest = 0; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci if (copy_to_user(ubuf, p, n)) { 6448c2ecf20Sopenharmony_ci ret = -EFAULT; 6458c2ecf20Sopenharmony_ci break; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci memzero_explicit(p, n); 6488c2ecf20Sopenharmony_ci ubuf += n; 6498c2ecf20Sopenharmony_ci nbytes -= n; 6508c2ecf20Sopenharmony_ci ret += n; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci /* unlock prng_data struct */ 6548c2ecf20Sopenharmony_ci mutex_unlock(&prng_data->mutex); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci return ret; 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci/*** sysfs stuff ***/ 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic const struct file_operations prng_sha512_fops = { 6638c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 6648c2ecf20Sopenharmony_ci .open = &prng_open, 6658c2ecf20Sopenharmony_ci .release = NULL, 6668c2ecf20Sopenharmony_ci .read = &prng_sha512_read, 6678c2ecf20Sopenharmony_ci .llseek = noop_llseek, 6688c2ecf20Sopenharmony_ci}; 6698c2ecf20Sopenharmony_cistatic const struct file_operations prng_tdes_fops = { 6708c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 6718c2ecf20Sopenharmony_ci .open = &prng_open, 6728c2ecf20Sopenharmony_ci .release = NULL, 6738c2ecf20Sopenharmony_ci .read = &prng_tdes_read, 6748c2ecf20Sopenharmony_ci .llseek = noop_llseek, 6758c2ecf20Sopenharmony_ci}; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_cistatic struct miscdevice prng_sha512_dev = { 6788c2ecf20Sopenharmony_ci .name = "prandom", 6798c2ecf20Sopenharmony_ci .minor = MISC_DYNAMIC_MINOR, 6808c2ecf20Sopenharmony_ci .mode = 0644, 6818c2ecf20Sopenharmony_ci .fops = &prng_sha512_fops, 6828c2ecf20Sopenharmony_ci}; 6838c2ecf20Sopenharmony_cistatic struct miscdevice prng_tdes_dev = { 6848c2ecf20Sopenharmony_ci .name = "prandom", 6858c2ecf20Sopenharmony_ci .minor = MISC_DYNAMIC_MINOR, 6868c2ecf20Sopenharmony_ci .mode = 0644, 6878c2ecf20Sopenharmony_ci .fops = &prng_tdes_fops, 6888c2ecf20Sopenharmony_ci}; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci/* chunksize attribute (ro) */ 6928c2ecf20Sopenharmony_cistatic ssize_t prng_chunksize_show(struct device *dev, 6938c2ecf20Sopenharmony_ci struct device_attribute *attr, 6948c2ecf20Sopenharmony_ci char *buf) 6958c2ecf20Sopenharmony_ci{ 6968c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%u\n", prng_chunk_size); 6978c2ecf20Sopenharmony_ci} 6988c2ecf20Sopenharmony_cistatic DEVICE_ATTR(chunksize, 0444, prng_chunksize_show, NULL); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci/* counter attribute (ro) */ 7018c2ecf20Sopenharmony_cistatic ssize_t prng_counter_show(struct device *dev, 7028c2ecf20Sopenharmony_ci struct device_attribute *attr, 7038c2ecf20Sopenharmony_ci char *buf) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci u64 counter; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&prng_data->mutex)) 7088c2ecf20Sopenharmony_ci return -ERESTARTSYS; 7098c2ecf20Sopenharmony_ci if (prng_mode == PRNG_MODE_SHA512) 7108c2ecf20Sopenharmony_ci counter = prng_data->prnows.stream_bytes; 7118c2ecf20Sopenharmony_ci else 7128c2ecf20Sopenharmony_ci counter = prng_data->prngws.byte_counter; 7138c2ecf20Sopenharmony_ci mutex_unlock(&prng_data->mutex); 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%llu\n", counter); 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_cistatic DEVICE_ATTR(byte_counter, 0444, prng_counter_show, NULL); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci/* errorflag attribute (ro) */ 7208c2ecf20Sopenharmony_cistatic ssize_t prng_errorflag_show(struct device *dev, 7218c2ecf20Sopenharmony_ci struct device_attribute *attr, 7228c2ecf20Sopenharmony_ci char *buf) 7238c2ecf20Sopenharmony_ci{ 7248c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", prng_errorflag); 7258c2ecf20Sopenharmony_ci} 7268c2ecf20Sopenharmony_cistatic DEVICE_ATTR(errorflag, 0444, prng_errorflag_show, NULL); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci/* mode attribute (ro) */ 7298c2ecf20Sopenharmony_cistatic ssize_t prng_mode_show(struct device *dev, 7308c2ecf20Sopenharmony_ci struct device_attribute *attr, 7318c2ecf20Sopenharmony_ci char *buf) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci if (prng_mode == PRNG_MODE_TDES) 7348c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "TDES\n"); 7358c2ecf20Sopenharmony_ci else 7368c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "SHA512\n"); 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_cistatic DEVICE_ATTR(mode, 0444, prng_mode_show, NULL); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci/* reseed attribute (w) */ 7418c2ecf20Sopenharmony_cistatic ssize_t prng_reseed_store(struct device *dev, 7428c2ecf20Sopenharmony_ci struct device_attribute *attr, 7438c2ecf20Sopenharmony_ci const char *buf, size_t count) 7448c2ecf20Sopenharmony_ci{ 7458c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&prng_data->mutex)) 7468c2ecf20Sopenharmony_ci return -ERESTARTSYS; 7478c2ecf20Sopenharmony_ci prng_sha512_reseed(); 7488c2ecf20Sopenharmony_ci mutex_unlock(&prng_data->mutex); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci return count; 7518c2ecf20Sopenharmony_ci} 7528c2ecf20Sopenharmony_cistatic DEVICE_ATTR(reseed, 0200, NULL, prng_reseed_store); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci/* reseed limit attribute (rw) */ 7558c2ecf20Sopenharmony_cistatic ssize_t prng_reseed_limit_show(struct device *dev, 7568c2ecf20Sopenharmony_ci struct device_attribute *attr, 7578c2ecf20Sopenharmony_ci char *buf) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%u\n", prng_reseed_limit); 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_cistatic ssize_t prng_reseed_limit_store(struct device *dev, 7628c2ecf20Sopenharmony_ci struct device_attribute *attr, 7638c2ecf20Sopenharmony_ci const char *buf, size_t count) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci unsigned limit; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci if (sscanf(buf, "%u\n", &limit) != 1) 7688c2ecf20Sopenharmony_ci return -EINVAL; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci if (prng_mode == PRNG_MODE_SHA512) { 7718c2ecf20Sopenharmony_ci if (limit < PRNG_RESEED_LIMIT_SHA512_LOWER) 7728c2ecf20Sopenharmony_ci return -EINVAL; 7738c2ecf20Sopenharmony_ci } else { 7748c2ecf20Sopenharmony_ci if (limit < PRNG_RESEED_LIMIT_TDES_LOWER) 7758c2ecf20Sopenharmony_ci return -EINVAL; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci prng_reseed_limit = limit; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci return count; 7818c2ecf20Sopenharmony_ci} 7828c2ecf20Sopenharmony_cistatic DEVICE_ATTR(reseed_limit, 0644, 7838c2ecf20Sopenharmony_ci prng_reseed_limit_show, prng_reseed_limit_store); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci/* strength attribute (ro) */ 7868c2ecf20Sopenharmony_cistatic ssize_t prng_strength_show(struct device *dev, 7878c2ecf20Sopenharmony_ci struct device_attribute *attr, 7888c2ecf20Sopenharmony_ci char *buf) 7898c2ecf20Sopenharmony_ci{ 7908c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "256\n"); 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_cistatic DEVICE_ATTR(strength, 0444, prng_strength_show, NULL); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_cistatic struct attribute *prng_sha512_dev_attrs[] = { 7958c2ecf20Sopenharmony_ci &dev_attr_errorflag.attr, 7968c2ecf20Sopenharmony_ci &dev_attr_chunksize.attr, 7978c2ecf20Sopenharmony_ci &dev_attr_byte_counter.attr, 7988c2ecf20Sopenharmony_ci &dev_attr_mode.attr, 7998c2ecf20Sopenharmony_ci &dev_attr_reseed.attr, 8008c2ecf20Sopenharmony_ci &dev_attr_reseed_limit.attr, 8018c2ecf20Sopenharmony_ci &dev_attr_strength.attr, 8028c2ecf20Sopenharmony_ci NULL 8038c2ecf20Sopenharmony_ci}; 8048c2ecf20Sopenharmony_cistatic struct attribute *prng_tdes_dev_attrs[] = { 8058c2ecf20Sopenharmony_ci &dev_attr_chunksize.attr, 8068c2ecf20Sopenharmony_ci &dev_attr_byte_counter.attr, 8078c2ecf20Sopenharmony_ci &dev_attr_mode.attr, 8088c2ecf20Sopenharmony_ci NULL 8098c2ecf20Sopenharmony_ci}; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_cistatic struct attribute_group prng_sha512_dev_attr_group = { 8128c2ecf20Sopenharmony_ci .attrs = prng_sha512_dev_attrs 8138c2ecf20Sopenharmony_ci}; 8148c2ecf20Sopenharmony_cistatic struct attribute_group prng_tdes_dev_attr_group = { 8158c2ecf20Sopenharmony_ci .attrs = prng_tdes_dev_attrs 8168c2ecf20Sopenharmony_ci}; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci/*** module init and exit ***/ 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_cistatic int __init prng_init(void) 8228c2ecf20Sopenharmony_ci{ 8238c2ecf20Sopenharmony_ci int ret; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci /* check if the CPU has a PRNG */ 8268c2ecf20Sopenharmony_ci if (!cpacf_query_func(CPACF_KMC, CPACF_KMC_PRNG)) 8278c2ecf20Sopenharmony_ci return -ENODEV; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci /* check if TRNG subfunction is available */ 8308c2ecf20Sopenharmony_ci if (cpacf_query_func(CPACF_PRNO, CPACF_PRNO_TRNG)) 8318c2ecf20Sopenharmony_ci trng_available = true; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci /* choose prng mode */ 8348c2ecf20Sopenharmony_ci if (prng_mode != PRNG_MODE_TDES) { 8358c2ecf20Sopenharmony_ci /* check for MSA5 support for PRNO operations */ 8368c2ecf20Sopenharmony_ci if (!cpacf_query_func(CPACF_PRNO, CPACF_PRNO_SHA512_DRNG_GEN)) { 8378c2ecf20Sopenharmony_ci if (prng_mode == PRNG_MODE_SHA512) { 8388c2ecf20Sopenharmony_ci pr_err("The prng module cannot " 8398c2ecf20Sopenharmony_ci "start in SHA-512 mode\n"); 8408c2ecf20Sopenharmony_ci return -ENODEV; 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci prng_mode = PRNG_MODE_TDES; 8438c2ecf20Sopenharmony_ci } else 8448c2ecf20Sopenharmony_ci prng_mode = PRNG_MODE_SHA512; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci if (prng_mode == PRNG_MODE_SHA512) { 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci /* SHA512 mode */ 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci if (prng_chunk_size < PRNG_CHUNKSIZE_SHA512_MIN 8528c2ecf20Sopenharmony_ci || prng_chunk_size > PRNG_CHUNKSIZE_SHA512_MAX) 8538c2ecf20Sopenharmony_ci return -EINVAL; 8548c2ecf20Sopenharmony_ci prng_chunk_size = (prng_chunk_size + 0x3f) & ~0x3f; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci if (prng_reseed_limit == 0) 8578c2ecf20Sopenharmony_ci prng_reseed_limit = PRNG_RESEED_LIMIT_SHA512; 8588c2ecf20Sopenharmony_ci else if (prng_reseed_limit < PRNG_RESEED_LIMIT_SHA512_LOWER) 8598c2ecf20Sopenharmony_ci return -EINVAL; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci ret = prng_sha512_instantiate(); 8628c2ecf20Sopenharmony_ci if (ret) 8638c2ecf20Sopenharmony_ci goto out; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci ret = misc_register(&prng_sha512_dev); 8668c2ecf20Sopenharmony_ci if (ret) { 8678c2ecf20Sopenharmony_ci prng_sha512_deinstantiate(); 8688c2ecf20Sopenharmony_ci goto out; 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci ret = sysfs_create_group(&prng_sha512_dev.this_device->kobj, 8718c2ecf20Sopenharmony_ci &prng_sha512_dev_attr_group); 8728c2ecf20Sopenharmony_ci if (ret) { 8738c2ecf20Sopenharmony_ci misc_deregister(&prng_sha512_dev); 8748c2ecf20Sopenharmony_ci prng_sha512_deinstantiate(); 8758c2ecf20Sopenharmony_ci goto out; 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci } else { 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci /* TDES mode */ 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci if (prng_chunk_size < PRNG_CHUNKSIZE_TDES_MIN 8838c2ecf20Sopenharmony_ci || prng_chunk_size > PRNG_CHUNKSIZE_TDES_MAX) 8848c2ecf20Sopenharmony_ci return -EINVAL; 8858c2ecf20Sopenharmony_ci prng_chunk_size = (prng_chunk_size + 0x07) & ~0x07; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci if (prng_reseed_limit == 0) 8888c2ecf20Sopenharmony_ci prng_reseed_limit = PRNG_RESEED_LIMIT_TDES; 8898c2ecf20Sopenharmony_ci else if (prng_reseed_limit < PRNG_RESEED_LIMIT_TDES_LOWER) 8908c2ecf20Sopenharmony_ci return -EINVAL; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci ret = prng_tdes_instantiate(); 8938c2ecf20Sopenharmony_ci if (ret) 8948c2ecf20Sopenharmony_ci goto out; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci ret = misc_register(&prng_tdes_dev); 8978c2ecf20Sopenharmony_ci if (ret) { 8988c2ecf20Sopenharmony_ci prng_tdes_deinstantiate(); 8998c2ecf20Sopenharmony_ci goto out; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci ret = sysfs_create_group(&prng_tdes_dev.this_device->kobj, 9028c2ecf20Sopenharmony_ci &prng_tdes_dev_attr_group); 9038c2ecf20Sopenharmony_ci if (ret) { 9048c2ecf20Sopenharmony_ci misc_deregister(&prng_tdes_dev); 9058c2ecf20Sopenharmony_ci prng_tdes_deinstantiate(); 9068c2ecf20Sopenharmony_ci goto out; 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ciout: 9128c2ecf20Sopenharmony_ci return ret; 9138c2ecf20Sopenharmony_ci} 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_cistatic void __exit prng_exit(void) 9178c2ecf20Sopenharmony_ci{ 9188c2ecf20Sopenharmony_ci if (prng_mode == PRNG_MODE_SHA512) { 9198c2ecf20Sopenharmony_ci sysfs_remove_group(&prng_sha512_dev.this_device->kobj, 9208c2ecf20Sopenharmony_ci &prng_sha512_dev_attr_group); 9218c2ecf20Sopenharmony_ci misc_deregister(&prng_sha512_dev); 9228c2ecf20Sopenharmony_ci prng_sha512_deinstantiate(); 9238c2ecf20Sopenharmony_ci } else { 9248c2ecf20Sopenharmony_ci sysfs_remove_group(&prng_tdes_dev.this_device->kobj, 9258c2ecf20Sopenharmony_ci &prng_tdes_dev_attr_group); 9268c2ecf20Sopenharmony_ci misc_deregister(&prng_tdes_dev); 9278c2ecf20Sopenharmony_ci prng_tdes_deinstantiate(); 9288c2ecf20Sopenharmony_ci } 9298c2ecf20Sopenharmony_ci} 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_cimodule_cpu_feature_match(MSA, prng_init); 9328c2ecf20Sopenharmony_cimodule_exit(prng_exit); 933