From nobody Thu Nov 04 16:02:51 2021 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 76EF0183DA27; Thu, 4 Nov 2021 16:02:52 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4HlT1l3tswz3HDG; Thu, 4 Nov 2021 16:02:51 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4D21D2F0F9; Thu, 4 Nov 2021 16:02:51 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 1A4G2pxk003654; Thu, 4 Nov 2021 16:02:51 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 1A4G2p7J003653; Thu, 4 Nov 2021 16:02:51 GMT (envelope-from git) Date: Thu, 4 Nov 2021 16:02:51 GMT Message-Id: <202111041602.1A4G2p7J003653@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Adrian Chadd Subject: git: 1492c8c0d825 - main - qcom_rnd: add initial qualcomm prng driver. List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-main@freebsd.org X-BeenThere: dev-commits-src-main@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: adrian X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 1492c8c0d825d1dcd8a2b2975fe35e4269b0b7de Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by adrian: URL: https://cgit.FreeBSD.org/src/commit/?id=1492c8c0d825d1dcd8a2b2975fe35e4269b0b7de commit 1492c8c0d825d1dcd8a2b2975fe35e4269b0b7de Author: Adrian Chadd AuthorDate: 2021-10-21 03:05:10 +0000 Commit: Adrian Chadd CommitDate: 2021-11-04 16:02:27 +0000 qcom_rnd: add initial qualcomm prng driver. This is the MVP required to initialise and consume random data from the QCA PRNG hardware found on the IPQ401x. Reviewed by: andrew, manu, imp Differential Revision: https://reviews.freebsd.org/D32723 --- sys/dev/qcom_rnd/qcom_rnd.c | 257 ++++++++++++++++++++++++++++++++++++++++ sys/dev/qcom_rnd/qcom_rnd_reg.h | 43 +++++++ sys/sys/random.h | 1 + 3 files changed, 301 insertions(+) diff --git a/sys/dev/qcom_rnd/qcom_rnd.c b/sys/dev/qcom_rnd/qcom_rnd.c new file mode 100644 index 000000000000..c78438a29ba0 --- /dev/null +++ b/sys/dev/qcom_rnd/qcom_rnd.c @@ -0,0 +1,257 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2021, Adrian Chadd + * + * 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 unmodified, 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 ``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 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. + */ + +/* Driver for Qualcomm MSM entropy device. */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +struct qcom_rnd_softc { + device_t dev; + int reg_rid; + struct resource *reg; +}; + +static int qcom_rnd_modevent(module_t, int, void *); + +static int qcom_rnd_probe(device_t); +static int qcom_rnd_attach(device_t); +static int qcom_rnd_detach(device_t); + +static int qcom_rnd_harvest(struct qcom_rnd_softc *, void *, size_t *); +static unsigned qcom_rnd_read(void *, unsigned); + +static struct random_source random_qcom_rnd = { + .rs_ident = "Qualcomm Entropy Adapter", + .rs_source = RANDOM_PURE_QUALCOMM, + .rs_read = qcom_rnd_read, +}; + +/* Kludge for API limitations of random(4). */ +static _Atomic(struct qcom_rnd_softc *) g_qcom_rnd_softc; + +static int +qcom_rnd_modevent(module_t mod, int type, void *unused) +{ + int error; + + switch (type) { + case MOD_LOAD: + case MOD_QUIESCE: + case MOD_UNLOAD: + case MOD_SHUTDOWN: + error = 0; + break; + default: + error = EOPNOTSUPP; + break; + } + + return (error); +} + +static int +qcom_rnd_probe(device_t dev) +{ + if (! ofw_bus_status_okay(dev)) { + return (ENXIO); + } + + if (ofw_bus_is_compatible(dev, "qcom,prng") == 0) { + return (ENXIO); + } + + return (0); +} + +static int +qcom_rnd_attach(device_t dev) +{ + struct qcom_rnd_softc *sc, *exp; + uint32_t reg; + + sc = device_get_softc(dev); + + + /* Found a compatible device! */ + + sc->dev = dev; + + exp = NULL; + if (!atomic_compare_exchange_strong_explicit(&g_qcom_rnd_softc, &exp, + sc, memory_order_release, memory_order_acquire)) { + return (ENXIO); + } + + sc->reg_rid = 0; + sc->reg = bus_alloc_resource_anywhere(dev, SYS_RES_MEMORY, + &sc->reg_rid, 0x140, RF_ACTIVE); + if (sc->reg == NULL) { + device_printf(dev, "Couldn't allocate memory resource!\n"); + return (ENXIO); + } + + device_set_desc(dev, "Qualcomm PRNG"); + + /* + * Check to see whether the PRNG has already been setup or not. + */ + bus_barrier(sc->reg, 0, 0x120, BUS_SPACE_BARRIER_READ); + reg = bus_read_4(sc->reg, QCOM_RND_PRNG_CONFIG); + if (reg & QCOM_RND_PRNG_CONFIG_HW_ENABLE) { + device_printf(dev, "PRNG HW already enabled\n"); + } else { + /* + * Do PRNG setup and then enable it. + */ + reg = bus_read_4(sc->reg, QCOM_RND_PRNG_LFSR_CFG); + reg &= QCOM_RND_PRNG_LFSR_CFG_MASK; + reg |= QCOM_RND_PRNG_LFSR_CFG_CLOCKS; + bus_write_4(sc->reg, QCOM_RND_PRNG_LFSR_CFG, reg); + bus_barrier(sc->reg, 0, 0x120, BUS_SPACE_BARRIER_WRITE); + + reg = bus_read_4(sc->reg, QCOM_RND_PRNG_CONFIG); + reg |= QCOM_RND_PRNG_CONFIG_HW_ENABLE; + bus_write_4(sc->reg, QCOM_RND_PRNG_CONFIG, reg); + bus_barrier(sc->reg, 0, 0x120, BUS_SPACE_BARRIER_WRITE); + } + + random_source_register(&random_qcom_rnd); + return (0); + +} + +static int +qcom_rnd_detach(device_t dev) +{ + struct qcom_rnd_softc *sc; + + sc = device_get_softc(dev); + KASSERT( + atomic_load_explicit(&g_qcom_rnd_softc, memory_order_acquire) == sc, + ("only one global instance at a time")); + + random_source_deregister(&random_qcom_rnd); + if (sc->reg != NULL) { + bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->reg_rid, sc->reg); + } + atomic_store_explicit(&g_qcom_rnd_softc, NULL, memory_order_release); + return (0); +} + +static int +qcom_rnd_harvest(struct qcom_rnd_softc *sc, void *buf, size_t *sz) +{ + /* + * Add data to buf until we either run out of entropy or we + * fill the buffer. + * + * Note - be mindful of the provided buffer size; we're reading + * 4 bytes at a time but we only want to supply up to the max + * buffer size, so don't write past it! + */ + size_t rz = 0; + uint32_t reg; + + while (rz < *sz) { + bus_barrier(sc->reg, 0, 0x120, BUS_SPACE_BARRIER_READ); + reg = bus_read_4(sc->reg, QCOM_RND_PRNG_STATUS); + if ((reg & QCOM_RND_PRNG_STATUS_DATA_AVAIL) == 0) + break; + reg = bus_read_4(sc->reg, QCOM_RND_PRNG_DATA_OUT); + memcpy(((char *) buf) + rz, ®, sizeof(uint32_t)); + rz += sizeof(uint32_t); + } + + if (rz == 0) + return (EAGAIN); + *sz = rz; + return (0); +} + +static unsigned +qcom_rnd_read(void *buf, unsigned usz) +{ + struct qcom_rnd_softc *sc; + size_t sz; + int error; + + sc = g_qcom_rnd_softc; + if (sc == NULL) + return (0); + + sz = usz; + error = qcom_rnd_harvest(sc, buf, &sz); + if (error != 0) + return (0); + + return (sz); +} + +static device_method_t qcom_rnd_methods[] = { + /* Device methods. */ + DEVMETHOD(device_probe, qcom_rnd_probe), + DEVMETHOD(device_attach, qcom_rnd_attach), + DEVMETHOD(device_detach, qcom_rnd_detach), + + DEVMETHOD_END +}; + +static driver_t qcom_rnd_driver = { + "qcom_rnd", + qcom_rnd_methods, + sizeof(struct qcom_rnd_softc) +}; +static devclass_t qcom_rnd_devclass; + +DRIVER_MODULE(qcom_rnd_random, simplebus, qcom_rnd_driver, qcom_rnd_devclass, + qcom_rnd_modevent, 0); +DRIVER_MODULE(qcom_rnd_random, ofwbus, qcom_rnd_driver, qcom_rnd_devclass, + qcom_rnd_modevent, 0); +MODULE_DEPEND(qcom_rnd_random, random_device, 1, 1, 1); +MODULE_VERSION(qcom_rnd_random, 1); diff --git a/sys/dev/qcom_rnd/qcom_rnd_reg.h b/sys/dev/qcom_rnd/qcom_rnd_reg.h new file mode 100644 index 000000000000..64cb0d678b6b --- /dev/null +++ b/sys/dev/qcom_rnd/qcom_rnd_reg.h @@ -0,0 +1,43 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2021, Adrian Chadd + * + * 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 unmodified, 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 ``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 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. + */ + +#ifndef __QCOM_RND_REG_H__ +#define __QCOM_RND_REG_H__ + +#define QCOM_RND_PRNG_DATA_OUT 0x0000 + +#define QCOM_RND_PRNG_STATUS 0x0004 +#define QCOM_RND_PRNG_STATUS_DATA_AVAIL (1 << 0) + +#define QCOM_RND_PRNG_LFSR_CFG 0x0100 +#define QCOM_RND_PRNG_LFSR_CFG_MASK 0x0000ffff +#define QCOM_RND_PRNG_LFSR_CFG_CLOCKS 0x0000dddd + +#define QCOM_RND_PRNG_CONFIG 0x0104 +#define QCOM_RND_PRNG_CONFIG_HW_ENABLE (1 << 1) + +#endif /* __QCOM_RND_REG_H__ */ diff --git a/sys/sys/random.h b/sys/sys/random.h index e2c4ab144d2a..cfcf4b30e698 100644 --- a/sys/sys/random.h +++ b/sys/sys/random.h @@ -102,6 +102,7 @@ enum random_entropy_source { RANDOM_PURE_DARN, RANDOM_PURE_TPM, RANDOM_PURE_VMGENID, + RANDOM_PURE_QUALCOMM, ENTROPYSOURCE }; _Static_assert(ENTROPYSOURCE <= 32,