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