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/dee57069232c
branches: trunk
changeset: 1005480:dee57069232c
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 5eef0840079e -r dee57069232c 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 5eef0840079e -r dee57069232c 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