2 * QEMU sPAPR random number generator "device" for H_RANDOM hypercall
4 * Copyright 2015 Thomas Huth, Red Hat Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License,
9 * or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "qemu/osdep.h"
21 #include "qapi/error.h"
22 #include "qemu-common.h"
24 #include "qemu/error-report.h"
25 #include "sysemu/sysemu.h"
26 #include "sysemu/device_tree.h"
27 #include "sysemu/rng.h"
28 #include "hw/ppc/spapr.h"
31 #define SPAPR_RNG(obj) \
32 OBJECT_CHECK(sPAPRRngState, (obj), TYPE_SPAPR_RNG)
34 struct sPAPRRngState
{
40 typedef struct sPAPRRngState sPAPRRngState
;
50 typedef struct HRandomData HRandomData
;
52 /* Callback function for the RngBackend */
53 static void random_recv(void *dest
, const void *src
, size_t size
)
55 HRandomData
*hrdp
= dest
;
57 if (src
&& size
> 0) {
58 assert(size
+ hrdp
->received
<= sizeof(hrdp
->val
.v8
));
59 memcpy(&hrdp
->val
.v8
[hrdp
->received
], src
, size
);
60 hrdp
->received
+= size
;
63 qemu_sem_post(&hrdp
->sem
);
66 /* Handler for the H_RANDOM hypercall */
67 static target_ulong
h_random(PowerPCCPU
*cpu
, sPAPRMachineState
*spapr
,
68 target_ulong opcode
, target_ulong
*args
)
70 sPAPRRngState
*rngstate
;
73 rngstate
= SPAPR_RNG(object_resolve_path_type("", TYPE_SPAPR_RNG
, NULL
));
75 if (!rngstate
|| !rngstate
->backend
) {
79 qemu_sem_init(&hrdata
.sem
, 0);
83 while (hrdata
.received
< 8) {
84 rng_backend_request_entropy(rngstate
->backend
, 8 - hrdata
.received
,
85 random_recv
, &hrdata
);
86 qemu_mutex_unlock_iothread();
87 qemu_sem_wait(&hrdata
.sem
);
88 qemu_mutex_lock_iothread();
91 qemu_sem_destroy(&hrdata
.sem
);
92 args
[0] = hrdata
.val
.v64
;
97 static void spapr_rng_instance_init(Object
*obj
)
99 sPAPRRngState
*rngstate
= SPAPR_RNG(obj
);
101 if (object_resolve_path_type("", TYPE_SPAPR_RNG
, NULL
) != NULL
) {
102 error_report("spapr-rng can not be instantiated twice!");
106 object_property_add_link(obj
, "rng", TYPE_RNG_BACKEND
,
107 (Object
**)&rngstate
->backend
,
108 object_property_allow_set_link
,
109 OBJ_PROP_LINK_UNREF_ON_RELEASE
, NULL
);
110 object_property_set_description(obj
, "rng",
111 "ID of the random number generator backend",
115 static void spapr_rng_realize(DeviceState
*dev
, Error
**errp
)
118 sPAPRRngState
*rngstate
= SPAPR_RNG(dev
);
120 if (rngstate
->use_kvm
) {
121 if (kvmppc_enable_hwrng() == 0) {
125 * If user specified both, use-kvm and a backend, we fall back to
126 * the backend now. If not, provide an appropriate error message.
128 if (!rngstate
->backend
) {
129 error_setg(errp
, "Could not initialize in-kernel H_RANDOM call!");
134 if (rngstate
->backend
) {
135 spapr_register_hypercall(H_RANDOM
, h_random
);
137 error_setg(errp
, "spapr-rng needs an RNG backend!");
141 int spapr_rng_populate_dt(void *fdt
)
146 node
= qemu_fdt_add_subnode(fdt
, "/ibm,platform-facilities");
150 ret
= fdt_setprop_string(fdt
, node
, "device_type",
151 "ibm,platform-facilities");
152 ret
|= fdt_setprop_cell(fdt
, node
, "#address-cells", 0x1);
153 ret
|= fdt_setprop_cell(fdt
, node
, "#size-cells", 0x0);
155 node
= fdt_add_subnode(fdt
, node
, "ibm,random-v1");
159 ret
|= fdt_setprop_string(fdt
, node
, "compatible", "ibm,random");
164 static Property spapr_rng_properties
[] = {
165 DEFINE_PROP_BOOL("use-kvm", sPAPRRngState
, use_kvm
, false),
166 DEFINE_PROP_END_OF_LIST(),
169 static void spapr_rng_class_init(ObjectClass
*oc
, void *data
)
171 DeviceClass
*dc
= DEVICE_CLASS(oc
);
173 dc
->realize
= spapr_rng_realize
;
174 set_bit(DEVICE_CATEGORY_MISC
, dc
->categories
);
175 dc
->props
= spapr_rng_properties
;
176 dc
->hotpluggable
= false;
179 static const TypeInfo spapr_rng_info
= {
180 .name
= TYPE_SPAPR_RNG
,
181 .parent
= TYPE_DEVICE
,
182 .instance_size
= sizeof(sPAPRRngState
),
183 .instance_init
= spapr_rng_instance_init
,
184 .class_init
= spapr_rng_class_init
,
187 static void spapr_rng_register_type(void)
189 type_register_static(&spapr_rng_info
);
191 type_init(spapr_rng_register_type
)