xref: /freebsd/sys/dev/random/nehemiah.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
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