xref: /openbsd-src/sys/arch/sparc64/dev/vrng.c (revision eb7eaf8de3ff431d305450f61b441e5460c82246)
1*eb7eaf8dSmpi /*	$OpenBSD: vrng.c,v 1.7 2021/10/24 17:05:04 mpi Exp $	*/
2b14b4dc9Skettenis /*
3b14b4dc9Skettenis  * Copyright (c) 2008 Mark Kettenis
4b14b4dc9Skettenis  *
5b14b4dc9Skettenis  * Permission to use, copy, modify, and distribute this software for any
6b14b4dc9Skettenis  * purpose with or without fee is hereby granted, provided that the above
7b14b4dc9Skettenis  * copyright notice and this permission notice appear in all copies.
8b14b4dc9Skettenis  *
9b14b4dc9Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10b14b4dc9Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11b14b4dc9Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12b14b4dc9Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13b14b4dc9Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14b14b4dc9Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15b14b4dc9Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16b14b4dc9Skettenis  */
17b14b4dc9Skettenis 
18b14b4dc9Skettenis #include <sys/param.h>
19b14b4dc9Skettenis #include <sys/device.h>
20b14b4dc9Skettenis #include <sys/malloc.h>
21b14b4dc9Skettenis #include <sys/systm.h>
22b14b4dc9Skettenis #include <sys/timeout.h>
23b14b4dc9Skettenis 
24b14b4dc9Skettenis #include <uvm/uvm_extern.h>
25b14b4dc9Skettenis 
26b14b4dc9Skettenis #include <machine/autoconf.h>
27b14b4dc9Skettenis #include <machine/hypervisor.h>
28b14b4dc9Skettenis #include <machine/openfirm.h>
29b14b4dc9Skettenis #include <machine/sparc64.h>
30b14b4dc9Skettenis 
31b14b4dc9Skettenis #define HSVC_GROUP_RNG	0x104
32b14b4dc9Skettenis 
33b14b4dc9Skettenis #include <sparc64/dev/vbusvar.h>
34b14b4dc9Skettenis 
35b14b4dc9Skettenis struct rng_ctl {
36b14b4dc9Skettenis 	uint64_t rng_res : 39;
37b14b4dc9Skettenis 	uint64_t rng_wait_cnt : 16;
38b14b4dc9Skettenis 	uint64_t rng_bypass : 1;
39b14b4dc9Skettenis 	uint64_t rng_vcoctl_sel : 2;
40b14b4dc9Skettenis 	uint64_t rng_anlg_sel : 2;
41b14b4dc9Skettenis 	uint64_t rng_ctl4 : 1;
42b14b4dc9Skettenis 	uint64_t rng_ctl3 : 1;
43b14b4dc9Skettenis 	uint64_t rng_ctl2 : 1;
44b14b4dc9Skettenis 	uint64_t rng_ctl1 : 1;
45b14b4dc9Skettenis };
46b14b4dc9Skettenis 
47b14b4dc9Skettenis struct vrng_softc {
48b14b4dc9Skettenis 	struct device sc_dv;
49b14b4dc9Skettenis 	struct timeout sc_to;
50b14b4dc9Skettenis 	int sc_count;
51b14b4dc9Skettenis };
52b14b4dc9Skettenis 
53b14b4dc9Skettenis int	vrng_match(struct device *, void *, void *);
54b14b4dc9Skettenis void	vrng_attach(struct device *, struct device *, void *);
55b14b4dc9Skettenis 
56*eb7eaf8dSmpi const struct cfattach vrng_ca = {
57b14b4dc9Skettenis 	sizeof(struct vrng_softc), vrng_match, vrng_attach
58b14b4dc9Skettenis };
59b14b4dc9Skettenis 
60b14b4dc9Skettenis struct cfdriver vrng_cd = {
61b14b4dc9Skettenis 	NULL, "vrng", DV_DULL
62b14b4dc9Skettenis };
63b14b4dc9Skettenis 
64b14b4dc9Skettenis void	vrng_rnd(void *);
65b14b4dc9Skettenis 
66b14b4dc9Skettenis int
vrng_match(struct device * parent,void * match,void * aux)67b14b4dc9Skettenis vrng_match(struct device *parent, void *match, void *aux)
68b14b4dc9Skettenis {
69b14b4dc9Skettenis 	struct vbus_attach_args *va = aux;
70b14b4dc9Skettenis 
71b14b4dc9Skettenis 	if (strcmp(va->va_name, "random-number-generator") == 0)
72b14b4dc9Skettenis 		return (1);
73b14b4dc9Skettenis 
74b14b4dc9Skettenis 	return (0);
75b14b4dc9Skettenis }
76b14b4dc9Skettenis 
77b14b4dc9Skettenis void
vrng_attach(struct device * parent,struct device * self,void * aux)78b14b4dc9Skettenis vrng_attach(struct device *parent, struct device *self, void *aux)
79b14b4dc9Skettenis {
80b14b4dc9Skettenis 	struct vrng_softc *sc = (void *)self;
81b14b4dc9Skettenis 	uint64_t supported_minor;
82b14b4dc9Skettenis 	struct rng_ctl ctl[4];
83b14b4dc9Skettenis 	uint64_t delta;
84b14b4dc9Skettenis 	paddr_t addr;
85b14b4dc9Skettenis 	int err;
86b14b4dc9Skettenis 
87b14b4dc9Skettenis 	if (prom_set_sun4v_api_version(HSVC_GROUP_RNG, 1, 0, &supported_minor))
88b14b4dc9Skettenis 		printf(": unsupported hypervisor\n");
89b14b4dc9Skettenis 
90b14b4dc9Skettenis 	err = hv_rng_get_diag_control();
91f87ed4e0Skettenis 	if (err != H_EOK && err != H_ENOACCESS)
92b14b4dc9Skettenis 		printf(": hv_rng_get_diag_control %d\n", err);
93b14b4dc9Skettenis 
94f87ed4e0Skettenis 	/*
95f87ed4e0Skettenis 	 * If we're not the Trusted Domain, the hypervisor call above
96f87ed4e0Skettenis 	 * will fails with H_ENOACCESS.  In that case we hope that the
97f87ed4e0Skettenis 	 * RNG has been properly initialized.
98f87ed4e0Skettenis 	 */
99f87ed4e0Skettenis 	if (err == H_EOK) {
100b14b4dc9Skettenis 		bzero(ctl, sizeof(ctl));
101b14b4dc9Skettenis 
102b14b4dc9Skettenis 		ctl[0].rng_ctl1 = 1;
103b14b4dc9Skettenis 		ctl[0].rng_vcoctl_sel = 0;
104b14b4dc9Skettenis 		ctl[0].rng_wait_cnt = 0x3e;
105b14b4dc9Skettenis 
106b14b4dc9Skettenis 		ctl[1].rng_ctl2 = 1;
107b14b4dc9Skettenis 		ctl[1].rng_vcoctl_sel = 1;
108b14b4dc9Skettenis 		ctl[1].rng_wait_cnt = 0x3e;
109b14b4dc9Skettenis 
110b14b4dc9Skettenis 		ctl[2].rng_ctl3 = 1;
111b14b4dc9Skettenis 		ctl[2].rng_vcoctl_sel = 2;
112b14b4dc9Skettenis 		ctl[2].rng_wait_cnt = 0x3e;
113b14b4dc9Skettenis 
114b14b4dc9Skettenis 		ctl[3].rng_ctl1 = 1;
115b14b4dc9Skettenis 		ctl[3].rng_ctl2 = 1;
116b14b4dc9Skettenis 		ctl[3].rng_ctl3 = 1;
117b14b4dc9Skettenis 		ctl[3].rng_ctl4 = 1;
118b14b4dc9Skettenis 		ctl[3].rng_wait_cnt = 0x3e;
119b14b4dc9Skettenis 
120b14b4dc9Skettenis 		if (!pmap_extract(pmap_kernel(), (vaddr_t)&ctl, &addr))
121859d5ed4Skrw 			panic("vrng_attach: pmap_extract failed");
122b14b4dc9Skettenis 
123b14b4dc9Skettenis 		err = hv_rng_ctl_write(addr, RNG_STATE_CONFIGURED, 0, &delta);
124b14b4dc9Skettenis 		if (err != H_EOK)
125b14b4dc9Skettenis 			printf(": hv_rng_ctl_write %d\n", err);
126f87ed4e0Skettenis 	}
127b14b4dc9Skettenis 
128b14b4dc9Skettenis 	printf("\n");
129b14b4dc9Skettenis 
130b14b4dc9Skettenis 	timeout_set(&sc->sc_to, vrng_rnd, sc);
131b14b4dc9Skettenis 	vrng_rnd(sc);
132b14b4dc9Skettenis }
133b14b4dc9Skettenis 
134b14b4dc9Skettenis void
vrng_rnd(void * v)135b14b4dc9Skettenis vrng_rnd(void *v)
136b14b4dc9Skettenis {
137b14b4dc9Skettenis 	struct vrng_softc *sc = v;
138b14b4dc9Skettenis 	uint64_t rnd;
139b14b4dc9Skettenis 	uint64_t delta;
140b14b4dc9Skettenis 	paddr_t addr;
141b14b4dc9Skettenis 	int err;
142b14b4dc9Skettenis 
143b14b4dc9Skettenis 	if (!pmap_extract(pmap_kernel(), (vaddr_t)&rnd, &addr))
144859d5ed4Skrw 		panic("vrng_rnd: pmap_extract failed");
145b14b4dc9Skettenis 	err = hv_rng_data_read(addr, &delta);
146b14b4dc9Skettenis 	if (err == H_EOK) {
147b14b4dc9Skettenis #if 0
148b14b4dc9Skettenis 		if ((sc->sc_count++ % 100) == 0)
149b14b4dc9Skettenis 			printf("vrng: %lx\n", rnd);
150b14b4dc9Skettenis #endif
1519e9abf5bSjasper 		enqueue_randomness(rnd);
1529e9abf5bSjasper 		enqueue_randomness(rnd >> 32);
153b14b4dc9Skettenis 	}
154e51682d5Skettenis 	if (err != H_EOK && err != H_EWOULDBLOCK)
155b14b4dc9Skettenis 		printf("vrng_rnd: err = %d\n", err);
156b14b4dc9Skettenis 	else
157b14b4dc9Skettenis 		timeout_add(&sc->sc_to, 1);
158b14b4dc9Skettenis }
159