padlock - initial rng support
authorAlex Hornung <ahornung@gmail.com>
Sat, 18 Jun 2011 00:23:28 +0000 (01:23 +0100)
committerAlex Hornung <ahornung@gmail.com>
Sat, 18 Jun 2011 00:24:52 +0000 (01:24 +0100)
 * Please note that the rng support is completely experimental as I
   don't have a VIA CPU available for testing.

 * NOTE: this might cause a kernel panic until it's tested properly.

sys/dev/crypto/padlock/Makefile
sys/dev/crypto/padlock/padlock.c
sys/dev/crypto/padlock/padlock.h
sys/dev/crypto/padlock/padlock_rng.c [new file with mode: 0644]

index 8d3862e..9d695a1 100644 (file)
@@ -1,7 +1,7 @@
 # $FreeBSD: src/sys/modules/padlock/Makefile,v 1.3 2007/03/21 17:37:13 sam Exp $
 
 KMOD=  padlock
-SRCS=  padlock.c padlock_cipher.c padlock_hash.c
+SRCS=  padlock.c padlock_cipher.c padlock_hash.c padlock_rng.c
 SRCS   += device_if.h bus_if.h opt_bus.h cryptodev_if.h
 
 .include <bsd.kmod.mk>
index 107eeec..dedb7b5 100644 (file)
  * http://www.via.com.tw/en/downloads/whitepapers/initiatives/padlock/programming_guide.pdf
  */
 
-struct padlock_softc {
-       int32_t         sc_cid;
-       uint32_t        sc_sid;
-       TAILQ_HEAD(padlock_sessions_head, padlock_session) sc_sessions;
-       struct spinlock sc_sessions_lock;
-};
-
 static int padlock_newsession(device_t, uint32_t *sidp, struct cryptoini *cri);
 static int padlock_freesession(device_t, uint64_t tid);
 static void padlock_freesession_one(struct padlock_softc *sc,
@@ -108,6 +101,10 @@ padlock_probe(device_t dev)
        if (via_feature_xcrypt & VIA_HAS_MM)
                strlcat(capp, ",RSA", sizeof(capp));
 #endif
+
+       if (via_feature_rng & VIA_HAS_RNG)
+               strlcat(capp, ",RNG", sizeof(capp));
+
        device_set_desc_copy(dev, capp);
        return (0);
 #else
@@ -137,6 +134,10 @@ padlock_attach(device_t dev)
        crypto_register(sc->sc_cid, CRYPTO_SHA2_256_HMAC, 0, 0);
        crypto_register(sc->sc_cid, CRYPTO_SHA2_384_HMAC, 0, 0);
        crypto_register(sc->sc_cid, CRYPTO_SHA2_512_HMAC, 0, 0);
+
+       if (via_feature_rng & VIA_HAS_RNG)
+               padlock_rng_init(sc);
+
        return (0);
 }
 
@@ -162,6 +163,10 @@ padlock_detach(device_t dev)
        spin_unlock(&sc->sc_sessions_lock);
        spin_uninit(&sc->sc_sessions_lock);
        crypto_unregister_all(sc->sc_cid);
+
+       if (via_feature_rng & VIA_HAS_RNG)
+               padlock_rng_uninit(sc);
+
        return (0);
 }
 
index ca82e6a..f8cd27a 100644 (file)
 #ifndef _PADLOCK_H_
 #define _PADLOCK_H_
 
+#include <sys/spinlock.h>
 #include <opencrypto/cryptodev.h>
 #include <crypto/rijndael/rijndael.h>
 
+
 union padlock_cw {
        uint64_t raw;
        struct {
@@ -73,6 +75,15 @@ struct padlock_session {
        void            *ses_freeaddr;
 } __aligned(16);
 
+struct padlock_softc {
+       int32_t         sc_cid;
+       uint32_t        sc_sid;
+       int32_t         sc_rng_ticks;
+       struct callout  sc_rng_co;
+       TAILQ_HEAD(padlock_sessions_head, padlock_session) sc_sessions;
+       struct spinlock sc_sessions_lock;
+};
+
 #define        PADLOCK_ALIGN(p)        (void *)(roundup2((uintptr_t)(p), 16))
 
 int    padlock_cipher_setup(struct padlock_session *ses,
@@ -84,5 +95,7 @@ int   padlock_hash_setup(struct padlock_session *ses,
 int    padlock_hash_process(struct padlock_session *ses,
            struct cryptodesc *maccrd, struct cryptop *crp);
 void   padlock_hash_free(struct padlock_session *ses);
+void   padlock_rng_init(struct padlock_softc *sc);
+void   padlock_rng_uninit(struct padlock_softc *sc);
 
 #endif /* !_PADLOCK_H_ */
diff --git a/sys/dev/crypto/padlock/padlock_rng.c b/sys/dev/crypto/padlock/padlock_rng.c
new file mode 100644 (file)
index 0000000..9deca0e
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
+ * All rights reserved.
+ *
+ * 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/libkern.h>
+#include <sys/random.h>
+
+#include <dev/crypto/padlock/padlock.h>
+
+static int random_count = 16;
+
+static __inline void
+padlock_rng(int *out, size_t count)
+{
+       unsigned int status;
+
+       /*
+        * xstore-rng:
+        * eax: (output) RNG status word
+        * ecx: (input)  rep. count
+        * edx: (input)  quality factor (0-3)
+        * edi: (input)  buffer for random data
+        */
+       __asm __volatile(
+               "pushf                  \n\t"
+               "popf                   \n\t"
+               "rep                    \n\t"
+               ".byte  0x0f, 0xa7, 0xc0"
+                       : "=a" (status)
+                       : "d" (2), "D" (out), "c" (count*sizeof(*out))
+                       : "cc", "memory"
+       );
+}
+
+static void
+padlock_rng_harvest(void *arg)
+{
+       struct padlock_softc *sc = arg;
+       int randomness[128];
+       int *arandomness; /* randomness aligned */
+       int i;
+
+       arandomness = PADLOCK_ALIGN(randomness);
+       padlock_rng(arandomness, random_count);
+
+       for (i = 0; i < random_count; i++)
+               add_true_randomness(arandomness[i]);
+
+       callout_reset(&sc->sc_rng_co, sc->sc_rng_ticks,
+           padlock_rng_harvest, sc);
+}
+
+void
+padlock_rng_init(struct padlock_softc *sc)
+{
+       if (hz > 100)
+               sc->sc_rng_ticks = hz/100;
+       else
+               sc->sc_rng_ticks = 1;
+
+       callout_init_mp(&sc->sc_rng_co);
+       callout_reset(&sc->sc_rng_co, sc->sc_rng_ticks,
+           padlock_rng_harvest, sc);
+}
+
+void
+padlock_rng_uninit(struct padlock_softc *sc)
+{
+       callout_stop(&sc->sc_rng_co);
+}
+