Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src-draft/trunk]: src/sys/arch/aarch64/aarch64 Add support for the ARMv8.5-R...



details:   https://anonhg.NetBSD.org/src-all/rev/cf93ae42b143
branches:  trunk
changeset: 932549:cf93ae42b143
user:      Taylor R Campbell <riastradh%NetBSD.org@localhost>
date:      Sun May 10 20:21:53 2020 +0000

description:
Add support for the ARMv8.5-RNG CPU random number generator.

We use the RNDRRS system register.  I made the following two
wild-arse guesses about the architecture of real implementations,
which might not exist yet:

1. There's only one physical source per CPU package, so not worth
   attaching one per core.

2. Like other CPU RNGs -- RDSEED, VIA C3 -- this probably gives about
   half a bit of entropy per bit of data.

Tested in qemu as well as I can, using `-cpu max' (which doesn't get
to userland for unrelated reasons).

This uses the numeric notation `mrs %0, s3_3_c2_c4_1' for the rndrrs
system register instead of the more legible `mrs %0, rndrrs' as
suggested in the ARMv8.5 ARM.  Why?

- clang doesn't like `mrs %0, rndrrs' for reasons unclear to me.

- gas only likes it with `.arch armv8.5-a+rng', but there's no clear
  way to keep that scoped; the `.set push/pop' stack that would be an
  obvious choice for this works only on mips.

- gcc supports __attribute__((target("arch=..."))) on functions, but
  the version we use doesn't yet know about armv8.5-a+rng.

Later on, we should replace this by a target attribute and the more
obvious `mrs %0, rndrrs' notation.

diffstat:

 sys/arch/aarch64/aarch64/cpu.c |  69 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 69 insertions(+), 0 deletions(-)

diffs (100 lines):

diff -r c95a1338cc93 -r cf93ae42b143 sys/arch/aarch64/aarch64/cpu.c
--- a/sys/arch/aarch64/aarch64/cpu.c    Sun May 10 22:38:51 2020 +0000
+++ b/sys/arch/aarch64/aarch64/cpu.c    Sun May 10 20:21:53 2020 +0000
@@ -40,6 +40,7 @@
 #include <sys/device.h>
 #include <sys/kmem.h>
 #include <sys/reboot.h>
+#include <sys/rndsource.h>
 #include <sys/sysctl.h>
 #include <sys/systm.h>
 
@@ -68,6 +69,7 @@
 static void cpu_init_counter(struct cpu_info *);
 static void cpu_setup_id(struct cpu_info *);
 static void cpu_setup_sysctl(device_t, struct cpu_info *);
+static void cpu_setup_rng(device_t, struct cpu_info *);
 
 #ifdef MULTIPROCESSOR
 #define NCPUINFO       MAXCPUS
@@ -153,6 +155,7 @@
        cpu_init_counter(ci);
 
        cpu_setup_sysctl(dv, ci);
+       cpu_setup_rng(dv, ci);
 }
 
 struct cpuidtab {
@@ -502,6 +505,72 @@
                       CTL_CREATE, CTL_EOL);
 }
 
+static struct krndsource rndrrs_source;
+
+static void
+rndrrs_get(size_t nbytes, void *cookie)
+{
+       /* Entropy bits per data byte, wild-arse guess.  */
+       const unsigned bpb = 4;
+       size_t nbits = nbytes*NBBY;
+       uint64_t x;
+       int error;
+
+       while (nbits) {
+               /*
+                * x := random 64-bit sample
+                * ok := true if Z bit is clear, meaning sample is good
+                *
+                * XXX This should be done by marking the function
+                * __attribute__((target("arch=armv8.5-a+rng"))) and
+                * using `mrs %0, rndrrs', but:
+                *
+                * (a) the version of gcc we use doesn't support that,
+                * and
+                * (b) clang doesn't seem to like `rndrrs' itself.
+                *
+                * So we use the numeric encoding for now.
+                */
+               __asm __volatile(""
+                   "mrs        %0, s3_3_c2_c4_1\n"
+                   "cset       %w1, eq"
+                   : "=r"(x), "=r"(error));
+               if (error)
+                       break;
+               rnd_add_data_sync(&rndrrs_source, &x, sizeof(x),
+                   bpb*sizeof(x));
+               nbits -= MIN(nbits, bpb*sizeof(x));
+       }
+
+       explicit_memset(&x, 0, sizeof x);
+}
+
+/*
+ * setup the RNDRRS entropy source
+ */
+static void
+cpu_setup_rng(device_t dv, struct cpu_info *ci)
+{
+       struct aarch64_sysctl_cpu_id *id = &ci->ci_id;
+
+       /* Probably shared between cores.  */
+       if (!CPU_IS_PRIMARY(ci))
+               return;
+
+       /* Verify that it is supported.  */
+       switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_RNDR)) {
+       case ID_AA64ISAR0_EL1_RNDR_RNDRRS:
+               break;
+       default:
+               return;
+       }
+
+       /* Attach it.  */
+       rndsource_setcb(&rndrrs_source, rndrrs_get, NULL);
+       rnd_attach_source(&rndrrs_source, "rndrrs", RND_TYPE_RNG,
+           RND_FLAG_DEFAULT|RND_FLAG_HASCB);
+}
+
 #ifdef MULTIPROCESSOR
 void
 cpu_hatch(struct cpu_info *ci)



Home | Main Index | Thread Index | Old Index