1e7806b4cSMark Murray /*-
2d1b06863SMark Murray * Copyright (c) 2013-2015 Mark R V Murray
310cb2424SMark Murray * Copyright (c) 2013 David E. O'Brien <obrien@NUXI.org>
4e7806b4cSMark Murray * All rights reserved.
5e7806b4cSMark Murray *
6e7806b4cSMark Murray * Redistribution and use in source and binary forms, with or without
7e7806b4cSMark Murray * modification, are permitted provided that the following conditions
8e7806b4cSMark Murray * are met:
9e7806b4cSMark Murray * 1. Redistributions of source code must retain the above copyright
10e7806b4cSMark Murray * notice, this list of conditions and the following disclaimer
11e7806b4cSMark Murray * in this position and unchanged.
12e7806b4cSMark Murray * 2. Redistributions in binary form must reproduce the above copyright
13e7806b4cSMark Murray * notice, this list of conditions and the following disclaimer in the
14e7806b4cSMark Murray * documentation and/or other materials provided with the distribution.
15e7806b4cSMark Murray *
16e7806b4cSMark Murray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17e7806b4cSMark Murray * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18e7806b4cSMark Murray * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19e7806b4cSMark Murray * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20e7806b4cSMark Murray * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21e7806b4cSMark Murray * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22e7806b4cSMark Murray * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23e7806b4cSMark Murray * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24e7806b4cSMark Murray * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25e7806b4cSMark Murray * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26e7806b4cSMark Murray *
27e7806b4cSMark Murray */
28e7806b4cSMark Murray
295564b4b9SMark Murray #include <sys/param.h>
30f02e47dcSMark Murray #include <sys/kernel.h>
3110cb2424SMark Murray #include <sys/conf.h>
32e7806b4cSMark Murray #include <sys/lock.h>
33095ed2c9SMark Murray #include <sys/malloc.h>
345711939bSDavid E. O'Brien #include <sys/module.h>
35f02e47dcSMark Murray #include <sys/random.h>
365564b4b9SMark Murray #include <sys/systm.h>
37e7806b4cSMark Murray
38cc4d059cSMark Murray #include <machine/segments.h>
3904c49e68SKonstantin Belousov #include <machine/pcb.h>
405711939bSDavid E. O'Brien #include <machine/md_var.h>
415711939bSDavid E. O'Brien #include <machine/specialreg.h>
4204c49e68SKonstantin Belousov
43e7806b4cSMark Murray #include <dev/random/randomdev.h>
445564b4b9SMark Murray
4510cb2424SMark Murray static u_int random_nehemiah_read(void *, u_int);
46e7806b4cSMark Murray
47d1b06863SMark Murray static struct random_source random_nehemiah = {
48d1b06863SMark Murray .rs_ident = "VIA Nehemiah Padlock RNG",
49d1b06863SMark Murray .rs_source = RANDOM_PURE_NEHEMIAH,
50d1b06863SMark Murray .rs_read = random_nehemiah_read
51e7806b4cSMark Murray };
52e7806b4cSMark Murray
53b9887f50SMark Murray /* This H/W source never stores more than 8 bytes in one go */
54e7806b4cSMark Murray /* ARGSUSED */
555564b4b9SMark Murray static __inline size_t
VIA_RNG_store(void * buf)565564b4b9SMark Murray VIA_RNG_store(void *buf)
575564b4b9SMark Murray {
585564b4b9SMark Murray uint32_t retval = 0;
595564b4b9SMark Murray uint32_t rate = 0;
605564b4b9SMark Murray
615564b4b9SMark Murray __asm __volatile(
625564b4b9SMark Murray "movl $0,%%edx\n\t"
63362c6d8dSKonstantin Belousov ".byte 0x0f, 0xa7, 0xc0"
645564b4b9SMark Murray : "=a" (retval), "+d" (rate), "+D" (buf)
655564b4b9SMark Murray :
665564b4b9SMark Murray : "memory"
675564b4b9SMark Murray );
685564b4b9SMark Murray if (rate == 0)
695564b4b9SMark Murray return (retval&0x1f);
705564b4b9SMark Murray return (0);
715564b4b9SMark Murray }
725564b4b9SMark Murray
7310cb2424SMark Murray /* It is specifically allowed that buf is a multiple of sizeof(long) */
7410cb2424SMark Murray static u_int
random_nehemiah_read(void * buf,u_int c)7510cb2424SMark Murray random_nehemiah_read(void *buf, u_int c)
76e7806b4cSMark Murray {
77f02e47dcSMark Murray uint8_t *b;
785564b4b9SMark Murray size_t count, ret;
79f02e47dcSMark Murray uint64_t tmp;
80e7806b4cSMark Murray
81*7aec088cSJohn Baldwin fpu_kern_enter(curthread, NULL, FPU_KERN_NORMAL | FPU_KERN_NOCTX);
82f02e47dcSMark Murray b = buf;
83f02e47dcSMark Murray for (count = c; count > 0; count -= ret) {
84f02e47dcSMark Murray ret = MIN(VIA_RNG_store(&tmp), count);
85f02e47dcSMark Murray memcpy(b, &tmp, ret);
86f02e47dcSMark Murray b += ret;
8704c49e68SKonstantin Belousov }
88*7aec088cSJohn Baldwin fpu_kern_leave(curthread, NULL);
89f02e47dcSMark Murray
90e7806b4cSMark Murray return (c);
91e7806b4cSMark Murray }
92ef9461baSKonstantin Belousov
935711939bSDavid E. O'Brien static int
nehemiah_modevent(module_t mod,int type,void * unused)945711939bSDavid E. O'Brien nehemiah_modevent(module_t mod, int type, void *unused)
955711939bSDavid E. O'Brien {
96f02e47dcSMark Murray int error = 0;
975711939bSDavid E. O'Brien
985711939bSDavid E. O'Brien switch (type) {
995711939bSDavid E. O'Brien case MOD_LOAD:
1005711939bSDavid E. O'Brien if (via_feature_rng & VIA_HAS_RNG) {
101d1b06863SMark Murray random_source_register(&random_nehemiah);
102d1b06863SMark Murray printf("random: fast provider: \"%s\"\n", random_nehemiah.rs_ident);
10310cb2424SMark Murray }
104f02e47dcSMark Murray break;
105f02e47dcSMark Murray
106f02e47dcSMark Murray case MOD_UNLOAD:
1079389e53fSGleb Smirnoff if (via_feature_rng & VIA_HAS_RNG) {
108d1b06863SMark Murray random_source_deregister(&random_nehemiah);
1099389e53fSGleb Smirnoff }
110f02e47dcSMark Murray break;
111f02e47dcSMark Murray
112f02e47dcSMark Murray case MOD_SHUTDOWN:
113f02e47dcSMark Murray break;
114f02e47dcSMark Murray
115f02e47dcSMark Murray default:
116f02e47dcSMark Murray error = EOPNOTSUPP;
117f02e47dcSMark Murray break;
118f02e47dcSMark Murray
1195711939bSDavid E. O'Brien }
1205711939bSDavid E. O'Brien
121f02e47dcSMark Murray return (error);
1225711939bSDavid E. O'Brien }
1235711939bSDavid E. O'Brien
1247384206aSConrad Meyer static moduledata_t nehemiah_mod = {
1257384206aSConrad Meyer "nehemiah",
1267384206aSConrad Meyer nehemiah_modevent,
1277384206aSConrad Meyer 0
1287384206aSConrad Meyer };
1297384206aSConrad Meyer
1307384206aSConrad Meyer DECLARE_MODULE(nehemiah, nehemiah_mod, SI_SUB_RANDOM, SI_ORDER_FOURTH);
13110cb2424SMark Murray MODULE_VERSION(nehemiah, 1);
1327384206aSConrad Meyer MODULE_DEPEND(nehemiah, random_harvestq, 1, 1, 1);
133