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