1 /*- 2 * Copyright (c) 2022 The FreeBSD Foundation 3 * 4 * This software was developed by Andrew Turner under sponsorship from 5 * the FreeBSD Foundation. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/conf.h> 34 #include <sys/kernel.h> 35 #include <sys/lock.h> 36 #include <sys/malloc.h> 37 #include <sys/module.h> 38 #include <sys/random.h> 39 40 #include <machine/armreg.h> 41 42 #include <dev/random/randomdev.h> 43 44 static u_int random_rndr_read(void *, u_int); 45 46 static bool has_rndr; 47 static struct random_source random_armv8_rndr = { 48 .rs_ident = "Armv8 rndr RNG", 49 .rs_source = RANDOM_PURE_ARMV8, 50 .rs_read = random_rndr_read, 51 }; 52 53 static inline int 54 random_rndr_read_one(u_long *buf) 55 { 56 u_long val; 57 int loop, ret; 58 59 loop = 10; 60 do { 61 __asm __volatile( 62 ".arch_extension rng \n" 63 "mrs %0, rndrrs \n" /* Read the random number */ 64 "cset %w1, ne \n" /* 1 on success, 0 on failure */ 65 ".arch_extension norng \n" 66 : "=&r" (val), "=&r"(ret) :: "cc"); 67 } while (ret != 0 && --loop > 0); 68 69 if (ret != 0) 70 *buf = val; 71 72 return (ret); 73 } 74 75 static u_int 76 random_rndr_read(void *buf, u_int c) 77 { 78 u_long *b; 79 u_int count; 80 81 b = buf; 82 for (count = 0; count < c; count += sizeof(*b)) { 83 if (!random_rndr_read_one(b)) 84 break; 85 86 b++; 87 } 88 89 return (count); 90 } 91 92 static int 93 rndr_modevent(module_t mod, int type, void *unused) 94 { 95 uint64_t reg; 96 int error = 0; 97 98 switch (type) { 99 case MOD_LOAD: 100 has_rndr = false; 101 if (get_kernel_reg(ID_AA64ISAR0_EL1, ®) && 102 ID_AA64ISAR0_RNDR_VAL(reg) != ID_AA64ISAR0_RNDR_NONE) { 103 has_rndr = true; 104 random_source_register(&random_armv8_rndr); 105 printf("random: fast provider: \"%s\"\n", 106 random_armv8_rndr.rs_ident); 107 } 108 break; 109 110 case MOD_UNLOAD: 111 if (has_rndr) 112 random_source_deregister(&random_armv8_rndr); 113 break; 114 115 case MOD_SHUTDOWN: 116 break; 117 118 default: 119 error = EOPNOTSUPP; 120 break; 121 122 } 123 124 return (error); 125 } 126 127 static moduledata_t rndr_mod = { 128 "rndr", 129 rndr_modevent, 130 0 131 }; 132 133 DECLARE_MODULE(rndr, rndr_mod, SI_SUB_RANDOM, SI_ORDER_FOURTH); 134 MODULE_VERSION(rndr, 1); 135 MODULE_DEPEND(rndr, random_harvestq, 1, 1, 1); 136