Source-Changes-HG archive

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

[src/trunk]: src/sys/arch Draft driver for Allwinner Crypto Engine.



details:   https://anonhg.NetBSD.org/src/rev/534c6ce201b1
branches:  trunk
changeset: 847079:534c6ce201b1
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Mon Dec 09 04:51:03 2019 +0000

description:
Draft driver for Allwinner Crypto Engine.

Found on, e.g., the Pinebook.

Only used for TRNG at the moment, but hooking it up to opencrypto(9)
shouldn't be too hard if anyone still cares about that these days.

The distribution of the alleged TRNG is very nonuniform distributed
seems to alternate between toward runs with exceptionally high
fractions of 0 bits and runs with exceptionally high fractions of 1
bits -- initially all my samples were mostly 0's, and then all my
samples were mostly 1's, and now I'm seeing more oscillation between
these runs.

So I've wired it up as RND_TYPE_UNKNOWN, not RND_TYPE_RNG (it will
immediately flunk our rngtest and be disabled), and I estimated it to
provide at most one bit of entropy per byte of data -- which may
still be optimistic.  I also added a sysctl node hw.sun8icryptoN.rng
to read out 1024-byte samples for analysis, and I left the driver
commented out in GENERIC64 for now.

(If anyone has contacts at Allwinner who can tell us about how the
alleged TRNG is supposed to work, please let me know!)

diffstat:

 sys/arch/arm/sunxi/files.sunxi    |     7 +-
 sys/arch/arm/sunxi/sun8i_crypto.c |  1349 +++++++++++++++++++++++++++++++++++++
 sys/arch/arm/sunxi/sun8i_crypto.h |   152 ++++
 sys/arch/evbarm/conf/GENERIC64    |     3 +-
 4 files changed, 1509 insertions(+), 2 deletions(-)

diffs (truncated from 1548 to 300 lines):

diff -r e547b4dccab6 -r 534c6ce201b1 sys/arch/arm/sunxi/files.sunxi
--- a/sys/arch/arm/sunxi/files.sunxi    Mon Dec 09 04:40:50 2019 +0000
+++ b/sys/arch/arm/sunxi/files.sunxi    Mon Dec 09 04:51:03 2019 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files.sunxi,v 1.66 2019/08/03 13:28:42 tnn Exp $
+#      $NetBSD: files.sunxi,v 1.67 2019/12/09 04:51:03 riastradh Exp $
 #
 # Configuration info for Allwinner sunxi family SoCs
 #
@@ -364,6 +364,11 @@
 attach sunxihdmiphy at fdt with sunxi_hdmiphy
 file   arch/arm/sunxi/sunxi_hdmiphy.c          sunxi_hdmiphy | sunxi_dwhdmi
 
+# Allwinner Crypto Engine
+device sun8icrypto
+attach sun8icrypto at fdt with sun8i_crypto
+file   arch/arm/sunxi/sun8i_crypto.c           sun8i_crypto
+
 # SOC parameters
 defflag        opt_soc.h                       SOC_SUNXI
 defflag        opt_soc.h                       SOC_SUNXI_MC
diff -r e547b4dccab6 -r 534c6ce201b1 sys/arch/arm/sunxi/sun8i_crypto.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/sunxi/sun8i_crypto.c Mon Dec 09 04:51:03 2019 +0000
@@ -0,0 +1,1349 @@
+/*     $NetBSD: sun8i_crypto.c,v 1.1 2019/12/09 04:51:03 riastradh Exp $       */
+
+/*-
+ * Copyright (c) 2019 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Taylor R. Campbell.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * sun8i_crypto -- Allwinner Crypto Engine driver
+ *
+ * The Crypto Engine is documented in Sec. 3.15 of the Allwinner A64
+ * User Manual v1.1, on pp. 230--241.  We only use it for the TRNG at
+ * the moment, but in principle it could be wired up with opencrypto(9)
+ * to compute AES, DES, 3DES, MD5, SHA-1, SHA-224, SHA-256, HMAC-SHA1,
+ * HMAC-HA256, RSA, and an undocumented PRNG.  It also seems to support
+ * AES keys in SRAM (for some kind of HDMI HDCP stuff?).
+ *
+ * https://linux-sunxi.org/images/b/b4/Allwinner_A64_User_Manual_V1.1.pdf
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(1, "$NetBSD: sun8i_crypto.c,v 1.1 2019/12/09 04:51:03 riastradh Exp $");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/atomic.h>
+#include <sys/bus.h>
+#include <sys/callout.h>
+#include <sys/conf.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/kmem.h>
+#include <sys/mutex.h>
+#include <sys/rndpool.h>
+#include <sys/rndsource.h>
+#include <sys/sysctl.h>
+#include <sys/workqueue.h>
+
+#include <dev/fdt/fdtvar.h>
+
+#include <arm/sunxi/sun8i_crypto.h>
+
+#define        SUN8I_CRYPTO_TIMEOUT    hz
+#define        SUN8I_CRYPTO_RNGENTROPY 8 /* estimated bits per bit of entropy */
+#define        SUN8I_CRYPTO_RNGBYTES                                                 \
+       (SUN8I_CRYPTO_RNGENTROPY*howmany(RND_POOLBITS, NBBY))
+
+struct sun8i_crypto_task;
+
+struct sun8i_crypto_buf {
+       bus_dma_segment_t       cb_seg[1];
+       int                     cb_nsegs;
+       bus_dmamap_t            cb_map;
+       void                    *cb_kva;
+};
+
+struct sun8i_crypto_softc {
+       device_t                        sc_dev;
+       bus_space_tag_t                 sc_bst;
+       bus_space_handle_t              sc_bsh;
+       bus_dma_tag_t                   sc_dmat;
+       kmutex_t                        sc_lock;
+       struct sun8i_crypto_chan {
+               struct sun8i_crypto_task        *cc_task;
+               unsigned                        cc_starttime;
+       }                               sc_chan[SUN8I_CRYPTO_NCHAN];
+       struct callout                  sc_timeout;
+       struct workqueue                *sc_wq;
+       struct work                     sc_work;
+       void                            *sc_ih;
+       uint32_t                        sc_done;
+       uint32_t                        sc_esr;
+       bool                            sc_work_pending;
+       struct sun8i_crypto_rng {
+               struct sun8i_crypto_buf         cr_buf;
+               struct sun8i_crypto_task        *cr_task;
+               struct krndsource               cr_rndsource;
+               bool                            cr_pending;
+       }                               sc_rng;
+       struct sun8i_crypto_selftest {
+               struct sun8i_crypto_buf         cs_in;
+               struct sun8i_crypto_buf         cs_key;
+               struct sun8i_crypto_buf         cs_out;
+               struct sun8i_crypto_task        *cs_task;
+       }                               sc_selftest;
+       struct sun8i_crypto_sysctl {
+               struct sysctllog                *cy_log;
+               const struct sysctlnode         *cy_root_node;
+               const struct sysctlnode         *cy_trng_node;
+       }                               sc_sysctl;
+};
+
+struct sun8i_crypto_task {
+       bus_dma_segment_t       ct_desc_seg[1];
+       int                     ct_desc_nseg;
+       bus_dmamap_t            ct_desc_map;
+       void                    *ct_desc_kva;
+       struct sun8i_crypto_taskdesc *ct_desc;
+       void                    (*ct_callback)(struct sun8i_crypto_softc *,
+                                   struct sun8i_crypto_task *, void *, int);
+       void                    *ct_cookie;
+};
+
+/*
+ * Forward declarations
+ */
+
+static int     sun8i_crypto_match(device_t, cfdata_t, void *);
+static void    sun8i_crypto_attach(device_t, device_t, void *);
+
+static struct sun8i_crypto_task *
+               sun8i_crypto_task_get(struct sun8i_crypto_softc *,
+                   void (*)(struct sun8i_crypto_softc *,
+                       struct sun8i_crypto_task *, void *, int),
+                   void *);
+static void    sun8i_crypto_task_put(struct sun8i_crypto_softc *,
+                   struct sun8i_crypto_task *);
+static void    sun8i_crypto_task_reset(struct sun8i_crypto_task *);
+
+static void    sun8i_crypto_task_set_key(struct sun8i_crypto_task *,
+                   bus_dmamap_t);
+static void    sun8i_crypto_task_set_iv(struct sun8i_crypto_task *,
+                   bus_dmamap_t);
+static void    sun8i_crypto_task_set_ctr(struct sun8i_crypto_task *,
+                   bus_dmamap_t);
+static void    sun8i_crypto_task_set_input(struct sun8i_crypto_task *,
+                   bus_dmamap_t);
+static void    sun8i_crypto_task_set_output(struct sun8i_crypto_task *,
+                   bus_dmamap_t);
+
+static void    sun8i_crypto_task_scatter(struct sun8i_crypto_adrlen *,
+                   bus_dmamap_t);
+
+static int     sun8i_crypto_submit_trng(struct sun8i_crypto_softc *,
+                   struct sun8i_crypto_task *, uint32_t);
+static int     sun8i_crypto_submit_aesecb(struct sun8i_crypto_softc *,
+                   struct sun8i_crypto_task *, uint32_t, uint32_t, uint32_t);
+static int     sun8i_crypto_submit(struct sun8i_crypto_softc *,
+                   struct sun8i_crypto_task *);
+
+static void    sun8i_crypto_timeout(void *);
+static int     sun8i_crypto_intr(void *);
+static void    sun8i_crypto_schedule_worker(struct sun8i_crypto_softc *);
+static void    sun8i_crypto_worker(struct work *, void *);
+static void    sun8i_crypto_chan_done(struct sun8i_crypto_softc *, unsigned,
+                   int);
+
+static int     sun8i_crypto_allocbuf(struct sun8i_crypto_softc *, size_t,
+                   struct sun8i_crypto_buf *);
+static void    sun8i_crypto_freebuf(struct sun8i_crypto_softc *, size_t,
+                   struct sun8i_crypto_buf *);
+
+static void    sun8i_crypto_rng_attach(struct sun8i_crypto_softc *);
+static void    sun8i_crypto_rng_get(size_t, void *);
+static void    sun8i_crypto_rng_done(struct sun8i_crypto_softc *,
+                   struct sun8i_crypto_task *, void *, int);
+
+static void    sun8i_crypto_selftest(device_t);
+static void    sun8i_crypto_selftest_done(struct sun8i_crypto_softc *,
+                   struct sun8i_crypto_task *, void *, int);
+
+static void    sun8i_crypto_sysctl_attach(struct sun8i_crypto_softc *);
+static int     sun8i_crypto_sysctl_rng(SYSCTLFN_ARGS);
+static void    sun8i_crypto_sysctl_rng_done(struct sun8i_crypto_softc *,
+                   struct sun8i_crypto_task *, void *, int);
+
+/*
+ * Register access
+ */
+
+static uint32_t
+sun8i_crypto_read(struct sun8i_crypto_softc *sc, bus_addr_t reg)
+{
+       return bus_space_read_4(sc->sc_bst, sc->sc_bsh, reg);
+}
+
+static void
+sun8i_crypto_write(struct sun8i_crypto_softc *sc, bus_addr_t reg, uint32_t v)
+{
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, reg, v);
+}
+
+/*
+ * Autoconf goo
+ */
+
+CFATTACH_DECL_NEW(sun8i_crypto, sizeof(struct sun8i_crypto_softc),
+    sun8i_crypto_match, sun8i_crypto_attach, NULL, NULL);
+
+static const struct of_compat_data compat_data[] = {
+       {"allwinner,sun50i-a64-crypto", 0},
+       {NULL}
+};
+
+static int
+sun8i_crypto_match(device_t parent, cfdata_t cf, void *aux)
+{
+       const struct fdt_attach_args *const faa = aux;
+
+       return of_match_compat_data(faa->faa_phandle, compat_data);
+}
+
+static void
+sun8i_crypto_attach(device_t parent, device_t self, void *aux)
+{
+       struct sun8i_crypto_softc *const sc = device_private(self);
+       const struct fdt_attach_args *const faa = aux;
+       bus_addr_t addr;
+       bus_size_t size;
+       const int phandle = faa->faa_phandle;
+       char intrstr[128];
+       struct clk *clk;
+       struct fdtbus_reset *rst;
+
+       sc->sc_dev = self;
+       sc->sc_dmat = faa->faa_dmat;
+       sc->sc_bst = faa->faa_bst;
+       mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
+       callout_init(&sc->sc_timeout, CALLOUT_MPSAFE);
+       callout_setfunc(&sc->sc_timeout, &sun8i_crypto_timeout, sc);
+       if (workqueue_create(&sc->sc_wq, device_xname(self),
+               &sun8i_crypto_worker, sc, PRI_NONE, IPL_VM, WQ_MPSAFE) != 0) {
+               aprint_error(": couldn't create workqueue\n");
+               return;
+       }
+
+       /* Get and map device registers.  */
+       if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
+               aprint_error(": couldn't get registers\n");
+               return;
+       }
+       if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
+               aprint_error(": couldn't map registers\n");
+               return;
+       }
+
+       /* Get an interrupt handle.  */
+       if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
+               aprint_error(": failed to decode interrupt\n");
+               return;
+       }
+
+       /* Enable the bus clock.  */
+       if (fdtbus_clock_enable(phandle, "bus", true) != 0) {
+               aprint_error(": couldn't enable bus clock\n");
+               return;
+       }
+
+       /* Get the module clock and set it to 300 MHz.  */
+       if ((clk = fdtbus_clock_get(phandle, "mod")) != NULL) {
+               if (clk_enable(clk) != 0) {



Home | Main Index | Thread Index | Old Index