Changeset View
Standalone View
sys/dev/random/armv8rng.c
- This file was added.
/*- | |||||
* Copyright (c) 2022 The FreeBSD Foundation | |||||
* | |||||
* This software was developed by Andrew Turner under sponsorship from | |||||
* the FreeBSD Foundation. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in the | |||||
* documentation and/or other materials provided with the distribution. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
* SUCH DAMAGE. | |||||
*/ | |||||
#include <sys/cdefs.h> | |||||
#include <sys/param.h> | |||||
#include <sys/systm.h> | |||||
#include <sys/conf.h> | |||||
#include <sys/kernel.h> | |||||
#include <sys/lock.h> | |||||
#include <sys/malloc.h> | |||||
#include <sys/module.h> | |||||
#include <sys/random.h> | |||||
#include <machine/armreg.h> | |||||
#include <dev/random/randomdev.h> | |||||
static u_int random_rndr_read(void *, u_int); | |||||
static bool has_rndr; | |||||
static struct random_source random_armv8_rndr = { | |||||
.rs_ident = "Armv8 rndr RNG", | |||||
.rs_source = RANDOM_PURE_ARMV8, | |||||
.rs_read = random_rndr_read, | |||||
}; | |||||
static inline int | |||||
random_rndr_read_one(u_long *buf) | |||||
{ | |||||
u_long val; | |||||
int loop, ret; | |||||
loop = 10; | |||||
do { | |||||
__asm __volatile( | |||||
".arch_extension rng\n" | |||||
"mrs %0, rndr\n" /* Read the random number */ | |||||
"cset %w1, ne\n" /* 1 on success, 0 on faulure */ | |||||
cem: I think `RNDRRS` would make more sense, if available. (On x86, we prefer `RDSEED` to `RDRAND`.) | |||||
Done Inline ActionsMy understanding is RNDR is equivilant to RDSEED [1]. RNDRRS just adds a reseed of the hardware CSPRNG used to generate random numbers. [1] https://lore.kernel.org/linux-arm-kernel/6e75d7b9-1c30-adab-bb74-1aaaa4e98ad4@linaro.org/ andrew: My understanding is `RNDR` is equivilant to `RDSEED` [1]. `RNDRRS` just adds a reseed of the… | |||||
Not Done Inline ActionsHuh. I’m not sure how to reconcile that with the language in the ISA doc, which reads more or less like RDRAND. What’s the downside of using RNDRRS? cem: Huh. I’m not sure how to reconcile that with the language in the ISA doc, which reads more or… | |||||
Done Inline ActionsK11.1 Properties of the generated random number talks about the random number generator as a whole. In userspace I tested a loop reading from each register. For RNDR I can read just under 15 million random numbers per second, for RNDRRS it's about 20500, so the former is ~730 times as fast as the latter (on an AWS Graviton3 instance). andrew: `K11.1 Properties of the generated random number` talks about the random number generator as a… | |||||
Not Done Inline ActionsI'd be tempted to make a comment here. We don't need to reseed the pool often, so we use the stronger random source. Explain why we chose this one and possibly some of the numbers behind that choice. Future explorers will be happy you did. imp: I'd be tempted to make a comment here.
We don't need to reseed the pool often, so we use the… | |||||
".arch_extension norng\n" | |||||
: "=&r" (val), "=&r"(ret) :: "cc"); | |||||
} while (ret != 0 && --loop > 0); | |||||
if (ret != 0) | |||||
*buf = val; | |||||
return (ret); | |||||
} | |||||
static u_int | |||||
random_rndr_read(void *buf, u_int c) | |||||
Not Done Inline ActionsNeed a blank line. imp: Need a blank line. | |||||
{ | |||||
u_long *b; | |||||
u_int count; | |||||
b = buf; | |||||
for (count = 0; count < c; count += sizeof(*b)) { | |||||
if (!random_rndr_read_one(b)) | |||||
break; | |||||
b++; | |||||
} | |||||
return (count); | |||||
} | |||||
static int | |||||
rndr_modevent(module_t mod, int type, void *unused) | |||||
{ | |||||
uint64_t reg; | |||||
int error = 0; | |||||
switch (type) { | |||||
case MOD_LOAD: | |||||
has_rndr = false; | |||||
if (get_kernel_reg(ID_AA64ISAR0_EL1, ®) && | |||||
ID_AA64ISAR0_RNDR_VAL(reg) != ID_AA64ISAR0_RNDR_NONE) { | |||||
has_rndr = true; | |||||
random_source_register(&random_armv8_rndr); | |||||
printf("random: fast provider: \"%s\"\n", | |||||
random_armv8_rndr.rs_ident); | |||||
} | |||||
break; | |||||
case MOD_UNLOAD: | |||||
if (has_rndr) | |||||
random_source_deregister(&random_armv8_rndr); | |||||
break; | |||||
case MOD_SHUTDOWN: | |||||
break; | |||||
default: | |||||
error = EOPNOTSUPP; | |||||
break; | |||||
} | |||||
return (error); | |||||
} | |||||
static moduledata_t rndr_mod = { | |||||
"rndr", | |||||
rndr_modevent, | |||||
0 | |||||
}; | |||||
DECLARE_MODULE(rndr, rndr_mod, SI_SUB_RANDOM, SI_ORDER_FOURTH); | |||||
MODULE_VERSION(rndr, 1); | |||||
MODULE_DEPEND(rndr, random_harvestq, 1, 1, 1); |
I think RNDRRS would make more sense, if available. (On x86, we prefer RDSEED to RDRAND.)