Message ID | 1441046762-5788-3-git-send-email-thuth@redhat.com |
---|---|
State | New |
Headers | show |
On Mon, Aug 31, 2015 at 08:46:02PM +0200, Thomas Huth wrote: > The PAPR interface provides a hypercall to pass high-quality > hardware generated random numbers to guests. So let's provide > this call in QEMU, too, so that guests that do not support > virtio-rnd yet can get good random numbers, too. > Please note that this hypercall should provide "good" random data > instead of pseudo-random, so the function uses the RngBackend to > retrieve the values instead of using a "simple" library function > like rand() or g_random_int(). Since there are multiple RngBackends > available, the user must select an appropriate backend via the > "h-random" property of the the machine state to enable it, e.g. > > qemu-system-ppc64 -M pseries,h-random=rng-random ... I think it would be a better idea to require that the backend RNG be constructed with -object, then give its id to the pseries code. That matches what's needed for virtio-rng more closely, and also makes it simpler to supply parameters to the RNG backend, if necessary. There's also a wart in that whatever the user specifies by way of backend, it will be silently overridden if KVM does implement the H_RANDOM call. I'm not sure how best to handle that. > to use the /dev/random backend, or "h-random=rng-egd" to use the > Entropy Gathering Daemon instead. > > Signed-off-by: Thomas Huth <thuth@redhat.com> > --- > hw/ppc/spapr.c | 36 +++++++++++++++++++++--- > hw/ppc/spapr_hcall.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++ > include/hw/ppc/spapr.h | 2 ++ > 3 files changed, 109 insertions(+), 4 deletions(-) > > diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c > index bc3a112..3db87b5 100644 > --- a/hw/ppc/spapr.c > +++ b/hw/ppc/spapr.c > @@ -312,7 +312,8 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base, > hwaddr kernel_size, > bool little_endian, > const char *kernel_cmdline, > - uint32_t epow_irq) > + uint32_t epow_irq, > + bool enable_h_random) > { > void *fdt; > uint32_t start_prop = cpu_to_be32(initrd_base); > @@ -466,7 +467,7 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base, > > _FDT((fdt_end_node(fdt))); > > - if (kvmppc_hwrng_present()) { > + if (enable_h_random) { > _FDT(fdt_begin_node(fdt, "ibm,platform-facilities")); > > _FDT(fdt_property_string(fdt, "name", "ibm,platform-facilities")); > @@ -1472,7 +1473,7 @@ static void ppc_spapr_init(MachineState *machine) > uint32_t initrd_base = 0; > long kernel_size = 0, initrd_size = 0; > long load_limit, fw_size; > - bool kernel_le = false; > + bool kernel_le = false, enable_h_random; I'd prefer to have the new variable on a new line - this way makes it very easy to miss the initializer on the old one. > char *filename; > > msi_supported = true; > @@ -1699,6 +1700,10 @@ static void ppc_spapr_init(MachineState *machine) > } > g_free(filename); > > + /* Enable H_RANDOM hypercall if requested by user or supported by kernel */ > + enable_h_random = kvmppc_hwrng_present() || > + !spapr_h_random_init(spapr->h_random_type); > + > /* FIXME: Should register things through the MachineState's qdev > * interface, this is a legacy from the sPAPREnvironment structure > * which predated MachineState but had a similar function */ > @@ -1710,7 +1715,8 @@ static void ppc_spapr_init(MachineState *machine) > spapr->fdt_skel = spapr_create_fdt_skel(initrd_base, initrd_size, > kernel_size, kernel_le, > kernel_cmdline, > - spapr->check_exception_irq); > + spapr->check_exception_irq, > + enable_h_random); > assert(spapr->fdt_skel != NULL); > > /* used by RTAS */ > @@ -1810,6 +1816,21 @@ static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp) > spapr->kvm_type = g_strdup(value); > } > > +static char *spapr_get_h_random_type(Object *obj, Error **errp) > +{ > + sPAPRMachineState *spapr = SPAPR_MACHINE(obj); > + > + return g_strdup(spapr->h_random_type); > +} > + > +static void spapr_set_h_random_type(Object *obj, const char *val, Error **errp) > +{ > + sPAPRMachineState *spapr = SPAPR_MACHINE(obj); > + > + g_free(spapr->h_random_type); > + spapr->h_random_type = g_strdup(val); > +} > + > static void spapr_machine_initfn(Object *obj) > { > object_property_add_str(obj, "kvm-type", > @@ -1817,6 +1838,13 @@ static void spapr_machine_initfn(Object *obj) > object_property_set_description(obj, "kvm-type", > "Specifies the KVM virtualization mode (HV, PR)", > NULL); > + > + object_property_add_str(obj, "h-random", spapr_get_h_random_type, > + spapr_set_h_random_type, NULL); > + object_property_set_description(obj, "h-random", > + "Select RNG backend for H_RANDOM hypercall " > + "(rng-random, rng-egd)", > + NULL); > } > > static void ppc_cpu_do_nmi_on_cpu(void *arg) > diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c > index 652ddf6..ff9d4fd 100644 > --- a/hw/ppc/spapr_hcall.c > +++ b/hw/ppc/spapr_hcall.c > @@ -1,4 +1,8 @@ > #include "sysemu/sysemu.h" > +#include "sysemu/rng.h" > +#include "sysemu/rng-random.h" > +#include "qom/object_interfaces.h" > +#include "qemu/error-report.h" > #include "cpu.h" > #include "helper_regs.h" > #include "hw/ppc/spapr.h" > @@ -929,6 +933,77 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_, > return H_SUCCESS; > } > > +typedef struct HRandomData { > + QemuSemaphore sem; > + union { > + uint64_t v64; > + uint8_t v8[8]; > + } val; > + int received; > +} HRandomData; > + > +static RndRandom *hrandom_rng; Couldn't you avoid the new global by looking this up through the sPAPRMachineState? > + > +static void random_recv(void *dest, const void *src, size_t size) > +{ > + HRandomData *hrcrdp = dest; > + > + if (src && size > 0) { > + memcpy(&hrcrdp->val.v8[hrcrdp->received], src, size); I'd be happier with an assert() ensuring that size doesn't exceed the buffer space we have left. > + hrcrdp->received += size; > + } > + qemu_sem_post(&hrcrdp->sem); Could you avoid a few wakeups by only posting the semaphore once the buffer is filled? > +} > + > +static target_ulong h_random(PowerPCCPU *cpu, sPAPRMachineState *spapr, > + target_ulong opcode, target_ulong *args) > +{ > + HRandomData hrcrd; > + > + if (!hrandom_rng) { > + return H_HARDWARE; > + } > + > + qemu_sem_init(&hrcrd.sem, 0); > + hrcrd.val.v64 = 0; > + hrcrd.received = 0; > + > + qemu_mutex_unlock_iothread(); > + while (hrcrd.received < 8) { > + rng_backend_request_entropy((RngBackend *)hrandom_rng, > + 8 - hrcrd.received, random_recv, &hrcrd); > + qemu_sem_wait(&hrcrd.sem); > + } > + qemu_mutex_lock_iothread(); > + > + qemu_sem_destroy(&hrcrd.sem); > + args[0] = hrcrd.val.v64; > + > + return H_SUCCESS; > +} > + > +int spapr_h_random_init(const char *backend_type) > +{ > + Error *local_err = NULL; > + > + if (!backend_type) { > + return -1; > + } > + > + hrandom_rng = RNG_RANDOM(object_new(backend_type)); > + user_creatable_complete(OBJECT(hrandom_rng), &local_err); > + if (local_err) { > + error_printf("Failed to initialize backend for H_RANDOM:\n %s\n", > + error_get_pretty(local_err)); > + object_unref(OBJECT(hrandom_rng)); > + return -1; > + } > + > + spapr_register_hypercall(H_RANDOM, h_random); > + > + return 0; > +} > + > static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1]; > static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1]; > > diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h > index ab8906f..de17624 100644 > --- a/include/hw/ppc/spapr.h > +++ b/include/hw/ppc/spapr.h > @@ -76,6 +76,7 @@ struct sPAPRMachineState { > > /*< public >*/ > char *kvm_type; > + char *h_random_type; > }; > > #define H_SUCCESS 0 > @@ -592,6 +593,7 @@ int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname, > void spapr_pci_switch_vga(bool big_endian); > void spapr_hotplug_req_add_event(sPAPRDRConnector *drc); > void spapr_hotplug_req_remove_event(sPAPRDRConnector *drc); > +int spapr_h_random_init(const char *backend_type); > > /* rtas-configure-connector state */ > struct sPAPRConfigureConnectorState {
On 01/09/15 02:47, David Gibson wrote: > On Mon, Aug 31, 2015 at 08:46:02PM +0200, Thomas Huth wrote: >> The PAPR interface provides a hypercall to pass high-quality >> hardware generated random numbers to guests. So let's provide >> this call in QEMU, too, so that guests that do not support >> virtio-rnd yet can get good random numbers, too. >> Please note that this hypercall should provide "good" random data >> instead of pseudo-random, so the function uses the RngBackend to >> retrieve the values instead of using a "simple" library function >> like rand() or g_random_int(). Since there are multiple RngBackends >> available, the user must select an appropriate backend via the >> "h-random" property of the the machine state to enable it, e.g. >> >> qemu-system-ppc64 -M pseries,h-random=rng-random ... > > I think it would be a better idea to require that the backend RNG be > constructed with -object, then give its id to the pseries code. That > matches what's needed for virtio-rng more closely, and also makes it > simpler to supply parameters to the RNG backend, if necessary. Ok, sounds like a good idea, will rework my patch accordingly. > There's also a wart in that whatever the user specifies by way of > backend, it will be silently overridden if KVM does implement the > H_RANDOM call. I'm not sure how best to handle that. We could either print a warning message if we detect that the in-kernel implementation is available and the user still tries to use the QEMU implementation - or we simply do not enable the in-kernel hypercall via kvmppc_enable_hcall() if the user tried to use the QEMU implementation. What would you prefer? >> to use the /dev/random backend, or "h-random=rng-egd" to use the >> Entropy Gathering Daemon instead. >> >> Signed-off-by: Thomas Huth <thuth@redhat.com> >> --- >> hw/ppc/spapr.c | 36 +++++++++++++++++++++--- >> hw/ppc/spapr_hcall.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++ >> include/hw/ppc/spapr.h | 2 ++ >> 3 files changed, 109 insertions(+), 4 deletions(-) >> >> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c >> index bc3a112..3db87b5 100644 >> --- a/hw/ppc/spapr.c >> +++ b/hw/ppc/spapr.c ... >> @@ -1472,7 +1473,7 @@ static void ppc_spapr_init(MachineState *machine) >> uint32_t initrd_base = 0; >> long kernel_size = 0, initrd_size = 0; >> long load_limit, fw_size; >> - bool kernel_le = false; >> + bool kernel_le = false, enable_h_random; > > I'd prefer to have the new variable on a new line - this way makes it > very easy to miss the initializer on the old one. Ok. ... >> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c >> index 652ddf6..ff9d4fd 100644 >> --- a/hw/ppc/spapr_hcall.c >> +++ b/hw/ppc/spapr_hcall.c >> @@ -1,4 +1,8 @@ >> #include "sysemu/sysemu.h" >> +#include "sysemu/rng.h" >> +#include "sysemu/rng-random.h" >> +#include "qom/object_interfaces.h" >> +#include "qemu/error-report.h" >> #include "cpu.h" >> #include "helper_regs.h" >> #include "hw/ppc/spapr.h" >> @@ -929,6 +933,77 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_, >> return H_SUCCESS; >> } >> >> +typedef struct HRandomData { >> + QemuSemaphore sem; >> + union { >> + uint64_t v64; >> + uint8_t v8[8]; >> + } val; >> + int received; >> +} HRandomData; >> + >> +static RndRandom *hrandom_rng; > > Couldn't you avoid the new global by looking this up through the > sPAPRMachineState? Sure. >> +static void random_recv(void *dest, const void *src, size_t size) >> +{ >> + HRandomData *hrcrdp = dest; >> + >> + if (src && size > 0) { >> + memcpy(&hrcrdp->val.v8[hrcrdp->received], src, size); > > I'd be happier with an assert() ensuring that size doesn't exceed the > buffer space we have left. That's a different issue - the if-statement above seems to be necassary because the callback sometimes seems to be called with size = 0 or src = NULL, so I had to add this here to avoid crashes. But I can also add an assert(hrcrdp->received + size <= 8) here if you like, just to be sure. >> + hrcrdp->received += size; >> + } >> + qemu_sem_post(&hrcrdp->sem); > > Could you avoid a few wakeups by only posting the semaphore once the > buffer is filled? Then the callback functions has to trigger the next rng_backend_request_entropy() ... not sure yet whether I like that idea... but I can have a try. Thomas
On (Mon) 31 Aug 2015 [20:46:02], Thomas Huth wrote: > The PAPR interface provides a hypercall to pass high-quality > hardware generated random numbers to guests. So let's provide > this call in QEMU, too, so that guests that do not support > virtio-rnd yet can get good random numbers, too. virtio-rng, not rnd. Can you elaborate what you mean by 'guests that do not support virtio-rng yet'? The Linux kernel has had the virtio-rng driver since 2.6.26, so I'm assuming that's not the thing you're alluding to. Not saying this hypercall isn't a good idea, just asking why. I think there's are valid reasons like the driver fails to load, or the driver is compiled out, or simply is loaded too late in the boot cycle. > Please note that this hypercall should provide "good" random data > instead of pseudo-random, so the function uses the RngBackend to > retrieve the values instead of using a "simple" library function > like rand() or g_random_int(). Since there are multiple RngBackends > available, the user must select an appropriate backend via the > "h-random" property of the the machine state to enable it, e.g. > > qemu-system-ppc64 -M pseries,h-random=rng-random ... > > to use the /dev/random backend, or "h-random=rng-egd" to use the > Entropy Gathering Daemon instead. I was going to suggest using -object here, but already I see you and David have reached an agreement for that. Out of curiosity: what does the host kernel use for its source when going the hypercall route? > +static void random_recv(void *dest, const void *src, size_t size) > +{ > + HRandomData *hrcrdp = dest; > + > + if (src && size > 0) { > + memcpy(&hrcrdp->val.v8[hrcrdp->received], src, size); > + hrcrdp->received += size; > + } > + qemu_sem_post(&hrcrdp->sem); > +} > + > +static target_ulong h_random(PowerPCCPU *cpu, sPAPRMachineState *spapr, > + target_ulong opcode, target_ulong *args) > +{ > + HRandomData hrcrd; > + > + if (!hrandom_rng) { > + return H_HARDWARE; > + } > + > + qemu_sem_init(&hrcrd.sem, 0); > + hrcrd.val.v64 = 0; > + hrcrd.received = 0; > + > + qemu_mutex_unlock_iothread(); > + while (hrcrd.received < 8) { > + rng_backend_request_entropy((RngBackend *)hrandom_rng, > + 8 - hrcrd.received, random_recv, &hrcrd); > + qemu_sem_wait(&hrcrd.sem); > + } Is it possible for a second hypercall to arrive while the first is waiting for the backend to provide data? > + qemu_mutex_lock_iothread(); > + > + qemu_sem_destroy(&hrcrd.sem); > + args[0] = hrcrd.val.v64; > + > + return H_SUCCESS; > +} Amit
On Wed, Sep 02, 2015 at 11:04:12AM +0530, Amit Shah wrote: > On (Mon) 31 Aug 2015 [20:46:02], Thomas Huth wrote: > > The PAPR interface provides a hypercall to pass high-quality > > hardware generated random numbers to guests. So let's provide > > this call in QEMU, too, so that guests that do not support > > virtio-rnd yet can get good random numbers, too. > > virtio-rng, not rnd. > > Can you elaborate what you mean by 'guests that do not support > virtio-rng yet'? The Linux kernel has had the virtio-rng driver since > 2.6.26, so I'm assuming that's not the thing you're alluding to. > > Not saying this hypercall isn't a good idea, just asking why. I think > there's are valid reasons like the driver fails to load, or the driver > is compiled out, or simply is loaded too late in the boot cycle. Yeah, I think we'd be talking about guests that just don't have it configured, although I suppose it's possible someone out there is using something earlier than 2.6.26 as well. Note that H_RANDOM has been supported under PowerVM for a long time, and PowerVM doesn't have any virtio support. So it is plausible that there are guests out there with with H_RANDOM support but no virtio-rng support, although I don't know of any examples specifically. RHEL6 had virtio support, including virtio-rng more or less by accident (since it was only supported under PowerVM). SLES may not have made the same fortunate error - I don't have a system handy to check. > > Please note that this hypercall should provide "good" random data > > instead of pseudo-random, so the function uses the RngBackend to > > retrieve the values instead of using a "simple" library function > > like rand() or g_random_int(). Since there are multiple RngBackends > > available, the user must select an appropriate backend via the > > "h-random" property of the the machine state to enable it, e.g. > > > > qemu-system-ppc64 -M pseries,h-random=rng-random ... > > > > to use the /dev/random backend, or "h-random=rng-egd" to use the > > Entropy Gathering Daemon instead. > > I was going to suggest using -object here, but already I see you and > David have reached an agreement for that. > > Out of curiosity: what does the host kernel use for its source when > going the hypercall route? I believe it draws from the same entropy pool as /dev/random. > > +static void random_recv(void *dest, const void *src, size_t size) > > +{ > > + HRandomData *hrcrdp = dest; > > + > > + if (src && size > 0) { > > + memcpy(&hrcrdp->val.v8[hrcrdp->received], src, size); > > + hrcrdp->received += size; > > + } > > + qemu_sem_post(&hrcrdp->sem); > > +} > > + > > +static target_ulong h_random(PowerPCCPU *cpu, sPAPRMachineState *spapr, > > + target_ulong opcode, target_ulong *args) > > +{ > > + HRandomData hrcrd; > > + > > + if (!hrandom_rng) { > > + return H_HARDWARE; > > + } > > + > > + qemu_sem_init(&hrcrd.sem, 0); > > + hrcrd.val.v64 = 0; > > + hrcrd.received = 0; > > + > > + qemu_mutex_unlock_iothread(); > > + while (hrcrd.received < 8) { > > + rng_backend_request_entropy((RngBackend *)hrandom_rng, > > + 8 - hrcrd.received, random_recv, &hrcrd); > > + qemu_sem_wait(&hrcrd.sem); > > + } > > Is it possible for a second hypercall to arrive while the first is > waiting for the backend to provide data? Yes it is. The hypercall itself is synchronous, but you could get concurrent calls from different guest CPUs. Hence the need for iothread unlocking. > > + qemu_mutex_lock_iothread(); > > + > > + qemu_sem_destroy(&hrcrd.sem); > > + args[0] = hrcrd.val.v64; > > + > > + return H_SUCCESS; > > +} > > Amit >
On 02/09/15 09:48, David Gibson wrote: > On Wed, Sep 02, 2015 at 11:04:12AM +0530, Amit Shah wrote: >> On (Mon) 31 Aug 2015 [20:46:02], Thomas Huth wrote: >>> The PAPR interface provides a hypercall to pass high-quality >>> hardware generated random numbers to guests. So let's provide >>> this call in QEMU, too, so that guests that do not support >>> virtio-rnd yet can get good random numbers, too. >> >> virtio-rng, not rnd. Oh, sorry, I'll fix the description. >> Can you elaborate what you mean by 'guests that do not support >> virtio-rng yet'? The Linux kernel has had the virtio-rng driver since >> 2.6.26, so I'm assuming that's not the thing you're alluding to. >> >> Not saying this hypercall isn't a good idea, just asking why. I think >> there's are valid reasons like the driver fails to load, or the driver >> is compiled out, or simply is loaded too late in the boot cycle. > > Yeah, I think we'd be talking about guests that just don't have it > configured, although I suppose it's possible someone out there is > using something earlier than 2.6.26 as well. Note that H_RANDOM has > been supported under PowerVM for a long time, and PowerVM doesn't have > any virtio support. So it is plausible that there are guests out > there with with H_RANDOM support but no virtio-rng support, although I > don't know of any examples specifically. RHEL6 had virtio support, > including virtio-rng more or less by accident (since it was only > supported under PowerVM). SLES may not have made the same fortunate > error - I don't have a system handy to check. Right, thanks David, I couldn't have explained it better. >>> Please note that this hypercall should provide "good" random data >>> instead of pseudo-random, so the function uses the RngBackend to >>> retrieve the values instead of using a "simple" library function >>> like rand() or g_random_int(). Since there are multiple RngBackends >>> available, the user must select an appropriate backend via the >>> "h-random" property of the the machine state to enable it, e.g. >>> >>> qemu-system-ppc64 -M pseries,h-random=rng-random ... >>> >>> to use the /dev/random backend, or "h-random=rng-egd" to use the >>> Entropy Gathering Daemon instead. >> >> I was going to suggest using -object here, but already I see you and >> David have reached an agreement for that. >> >> Out of curiosity: what does the host kernel use for its source when >> going the hypercall route? > > I believe it draws from the same entropy pool as /dev/random. The H_RANDOM handler in the kernel uses powernv_get_random_real_mode() in arch/powerpc/platforms/powernv/rng.c ... that seems to be a powernv-only pool (but it is also used to feed the normal kernel entropy pool, I think), but I am not an expert here so I might be wrong. >>> +static void random_recv(void *dest, const void *src, size_t size) >>> +{ >>> + HRandomData *hrcrdp = dest; >>> + >>> + if (src && size > 0) { >>> + memcpy(&hrcrdp->val.v8[hrcrdp->received], src, size); >>> + hrcrdp->received += size; >>> + } >>> + qemu_sem_post(&hrcrdp->sem); >>> +} >>> + >>> +static target_ulong h_random(PowerPCCPU *cpu, sPAPRMachineState *spapr, >>> + target_ulong opcode, target_ulong *args) >>> +{ >>> + HRandomData hrcrd; >>> + >>> + if (!hrandom_rng) { >>> + return H_HARDWARE; >>> + } >>> + >>> + qemu_sem_init(&hrcrd.sem, 0); >>> + hrcrd.val.v64 = 0; >>> + hrcrd.received = 0; >>> + >>> + qemu_mutex_unlock_iothread(); >>> + while (hrcrd.received < 8) { >>> + rng_backend_request_entropy((RngBackend *)hrandom_rng, >>> + 8 - hrcrd.received, random_recv, &hrcrd); >>> + qemu_sem_wait(&hrcrd.sem); >>> + } >> >> Is it possible for a second hypercall to arrive while the first is >> waiting for the backend to provide data? > > Yes it is. The hypercall itself is synchronous, but you could get > concurrent calls from different guest CPUs. Hence the need for > iothread unlocking. BQL and semaphore handling should be ok, I think, but one remaining question is: Can the RngBackend deal with multiple requests in flight from different vCPUs? Or is it limited to one consumer only? Amit, do you know this? Thomas
On (Wed) 02 Sep 2015 [17:48:01], David Gibson wrote: > On Wed, Sep 02, 2015 at 11:04:12AM +0530, Amit Shah wrote: > > On (Mon) 31 Aug 2015 [20:46:02], Thomas Huth wrote: > > > The PAPR interface provides a hypercall to pass high-quality > > > hardware generated random numbers to guests. So let's provide > > > this call in QEMU, too, so that guests that do not support > > > virtio-rnd yet can get good random numbers, too. > > > > virtio-rng, not rnd. > > > > Can you elaborate what you mean by 'guests that do not support > > virtio-rng yet'? The Linux kernel has had the virtio-rng driver since > > 2.6.26, so I'm assuming that's not the thing you're alluding to. > > > > Not saying this hypercall isn't a good idea, just asking why. I think > > there's are valid reasons like the driver fails to load, or the driver > > is compiled out, or simply is loaded too late in the boot cycle. > > Yeah, I think we'd be talking about guests that just don't have it > configured, although I suppose it's possible someone out there is > using something earlier than 2.6.26 as well. Note that H_RANDOM has > been supported under PowerVM for a long time, and PowerVM doesn't have > any virtio support. So it is plausible that there are guests out > there with with H_RANDOM support but no virtio-rng support, although I > don't know of any examples specifically. RHEL6 had virtio support, > including virtio-rng more or less by accident (since it was only > supported under PowerVM). SLES may not have made the same fortunate > error - I don't have a system handy to check. RHEL6 also used 2.6.32, which means it inherited from upstream. But you're right that x86 didn't have a device for virtio-rng then. > > > Please note that this hypercall should provide "good" random data > > > instead of pseudo-random, so the function uses the RngBackend to > > > retrieve the values instead of using a "simple" library function > > > like rand() or g_random_int(). Since there are multiple RngBackends > > > available, the user must select an appropriate backend via the > > > "h-random" property of the the machine state to enable it, e.g. > > > > > > qemu-system-ppc64 -M pseries,h-random=rng-random ... > > > > > > to use the /dev/random backend, or "h-random=rng-egd" to use the > > > Entropy Gathering Daemon instead. > > > > I was going to suggest using -object here, but already I see you and > > David have reached an agreement for that. > > > > Out of curiosity: what does the host kernel use for its source when > > going the hypercall route? > > I believe it draws from the same entropy pool as /dev/random. OK - I'll take a look there as well. > > > +static void random_recv(void *dest, const void *src, size_t size) > > > +{ > > > + HRandomData *hrcrdp = dest; > > > + > > > + if (src && size > 0) { > > > + memcpy(&hrcrdp->val.v8[hrcrdp->received], src, size); > > > + hrcrdp->received += size; > > > + } > > > + qemu_sem_post(&hrcrdp->sem); > > > +} > > > + > > > +static target_ulong h_random(PowerPCCPU *cpu, sPAPRMachineState *spapr, > > > + target_ulong opcode, target_ulong *args) > > > +{ > > > + HRandomData hrcrd; > > > + > > > + if (!hrandom_rng) { > > > + return H_HARDWARE; > > > + } > > > + > > > + qemu_sem_init(&hrcrd.sem, 0); > > > + hrcrd.val.v64 = 0; > > > + hrcrd.received = 0; > > > + > > > + qemu_mutex_unlock_iothread(); > > > + while (hrcrd.received < 8) { > > > + rng_backend_request_entropy((RngBackend *)hrandom_rng, > > > + 8 - hrcrd.received, random_recv, &hrcrd); > > > + qemu_sem_wait(&hrcrd.sem); > > > + } > > > > Is it possible for a second hypercall to arrive while the first is > > waiting for the backend to provide data? > > Yes it is. The hypercall itself is synchronous, but you could get > concurrent calls from different guest CPUs. Hence the need for > iothread unlocking. OK, thanks! Amit
On (Wed) 02 Sep 2015 [10:58:57], Thomas Huth wrote: > On 02/09/15 09:48, David Gibson wrote: > > On Wed, Sep 02, 2015 at 11:04:12AM +0530, Amit Shah wrote: > >> On (Mon) 31 Aug 2015 [20:46:02], Thomas Huth wrote: > >>> The PAPR interface provides a hypercall to pass high-quality > >>> hardware generated random numbers to guests. So let's provide > >>> this call in QEMU, too, so that guests that do not support > >>> virtio-rnd yet can get good random numbers, too. > >> > >> virtio-rng, not rnd. > > Oh, sorry, I'll fix the description. Thanks. (It's that way in patch 0 too.) > >> Can you elaborate what you mean by 'guests that do not support > >> virtio-rng yet'? The Linux kernel has had the virtio-rng driver since > >> 2.6.26, so I'm assuming that's not the thing you're alluding to. > >> > >> Not saying this hypercall isn't a good idea, just asking why. I think > >> there's are valid reasons like the driver fails to load, or the driver > >> is compiled out, or simply is loaded too late in the boot cycle. > > > > Yeah, I think we'd be talking about guests that just don't have it > > configured, although I suppose it's possible someone out there is > > using something earlier than 2.6.26 as well. Note that H_RANDOM has > > been supported under PowerVM for a long time, and PowerVM doesn't have > > any virtio support. So it is plausible that there are guests out > > there with with H_RANDOM support but no virtio-rng support, although I > > don't know of any examples specifically. RHEL6 had virtio support, > > including virtio-rng more or less by accident (since it was only > > supported under PowerVM). SLES may not have made the same fortunate > > error - I don't have a system handy to check. > > Right, thanks David, I couldn't have explained it better. > > >>> Please note that this hypercall should provide "good" random data > >>> instead of pseudo-random, so the function uses the RngBackend to > >>> retrieve the values instead of using a "simple" library function > >>> like rand() or g_random_int(). Since there are multiple RngBackends > >>> available, the user must select an appropriate backend via the > >>> "h-random" property of the the machine state to enable it, e.g. > >>> > >>> qemu-system-ppc64 -M pseries,h-random=rng-random ... > >>> > >>> to use the /dev/random backend, or "h-random=rng-egd" to use the > >>> Entropy Gathering Daemon instead. > >> > >> I was going to suggest using -object here, but already I see you and > >> David have reached an agreement for that. > >> > >> Out of curiosity: what does the host kernel use for its source when > >> going the hypercall route? > > > > I believe it draws from the same entropy pool as /dev/random. > > The H_RANDOM handler in the kernel uses powernv_get_random_real_mode() > in arch/powerpc/platforms/powernv/rng.c ... that seems to be a > powernv-only pool (but it is also used to feed the normal kernel entropy > pool, I think), but I am not an expert here so I might be wrong. Thanks for the pointer, I'm going to take a look. > >>> +static void random_recv(void *dest, const void *src, size_t size) > >>> +{ > >>> + HRandomData *hrcrdp = dest; > >>> + > >>> + if (src && size > 0) { > >>> + memcpy(&hrcrdp->val.v8[hrcrdp->received], src, size); > >>> + hrcrdp->received += size; > >>> + } > >>> + qemu_sem_post(&hrcrdp->sem); > >>> +} > >>> + > >>> +static target_ulong h_random(PowerPCCPU *cpu, sPAPRMachineState *spapr, > >>> + target_ulong opcode, target_ulong *args) > >>> +{ > >>> + HRandomData hrcrd; > >>> + > >>> + if (!hrandom_rng) { > >>> + return H_HARDWARE; > >>> + } > >>> + > >>> + qemu_sem_init(&hrcrd.sem, 0); > >>> + hrcrd.val.v64 = 0; > >>> + hrcrd.received = 0; > >>> + > >>> + qemu_mutex_unlock_iothread(); > >>> + while (hrcrd.received < 8) { > >>> + rng_backend_request_entropy((RngBackend *)hrandom_rng, > >>> + 8 - hrcrd.received, random_recv, &hrcrd); > >>> + qemu_sem_wait(&hrcrd.sem); > >>> + } > >> > >> Is it possible for a second hypercall to arrive while the first is > >> waiting for the backend to provide data? > > > > Yes it is. The hypercall itself is synchronous, but you could get > > concurrent calls from different guest CPUs. Hence the need for > > iothread unlocking. > > BQL and semaphore handling should be ok, I think, but one remaining > question is: Can the RngBackend deal with multiple requests in flight > from different vCPUs? Or is it limited to one consumer only? Amit, do > you know this? It's not limited by one consumer, it should work fine for the way you're using it. For virtio-rng, though, I've had this feeling for a while that it won't do the right thing (ie it will source more bytes than asked for), which bothers me. One of the things I want to look at later.. Amit
On Wed, 2015-09-02 at 17:48 +1000, David Gibson wrote: > On Wed, Sep 02, 2015 at 11:04:12AM +0530, Amit Shah wrote: > > On (Mon) 31 Aug 2015 [20:46:02], Thomas Huth wrote: > > > The PAPR interface provides a hypercall to pass high-quality > > > hardware generated random numbers to guests. So let's provide > > > this call in QEMU, too, so that guests that do not support > > > virtio-rnd yet can get good random numbers, too. > > > > virtio-rng, not rnd. > > > > Can you elaborate what you mean by 'guests that do not support > > virtio-rng yet'? The Linux kernel has had the virtio-rng driver since > > 2.6.26, so I'm assuming that's not the thing you're alluding to. > > > > Not saying this hypercall isn't a good idea, just asking why. I think > > there's are valid reasons like the driver fails to load, or the driver > > is compiled out, or simply is loaded too late in the boot cycle. > > Yeah, I think we'd be talking about guests that just don't have it > configured, although I suppose it's possible someone out there is > using something earlier than 2.6.26 as well. Note that H_RANDOM has > been supported under PowerVM for a long time, and PowerVM doesn't have > any virtio support. So it is plausible that there are guests out > there with with H_RANDOM support but no virtio-rng support, although I > don't know of any examples specifically. RHEL6 had virtio support, > including virtio-rng more or less by accident (since it was only > supported under PowerVM). SLES may not have made the same fortunate > error - I don't have a system handy to check. There also could be folks who want to run non-Linux operating systems, which don't have a virtio-rng driver, crazy I know :) cheers
On Thu, Sep 03, 2015 at 11:21:24AM +1000, Michael Ellerman wrote: > On Wed, 2015-09-02 at 17:48 +1000, David Gibson wrote: > > On Wed, Sep 02, 2015 at 11:04:12AM +0530, Amit Shah wrote: > > > On (Mon) 31 Aug 2015 [20:46:02], Thomas Huth wrote: > > > > The PAPR interface provides a hypercall to pass high-quality > > > > hardware generated random numbers to guests. So let's provide > > > > this call in QEMU, too, so that guests that do not support > > > > virtio-rnd yet can get good random numbers, too. > > > > > > virtio-rng, not rnd. > > > > > > Can you elaborate what you mean by 'guests that do not support > > > virtio-rng yet'? The Linux kernel has had the virtio-rng driver since > > > 2.6.26, so I'm assuming that's not the thing you're alluding to. > > > > > > Not saying this hypercall isn't a good idea, just asking why. I think > > > there's are valid reasons like the driver fails to load, or the driver > > > is compiled out, or simply is loaded too late in the boot cycle. > > > > Yeah, I think we'd be talking about guests that just don't have it > > configured, although I suppose it's possible someone out there is > > using something earlier than 2.6.26 as well. Note that H_RANDOM has > > been supported under PowerVM for a long time, and PowerVM doesn't have > > any virtio support. So it is plausible that there are guests out > > there with with H_RANDOM support but no virtio-rng support, although I > > don't know of any examples specifically. RHEL6 had virtio support, > > including virtio-rng more or less by accident (since it was only > > supported under PowerVM). SLES may not have made the same fortunate > > error - I don't have a system handy to check. > > There also could be folks who want to run non-Linux operating systems, which > don't have a virtio-rng driver, crazy I know :) Well, yes. Although I don't have any concrete examples of those, either..
On 01/09/15 02:47, David Gibson wrote: > On Mon, Aug 31, 2015 at 08:46:02PM +0200, Thomas Huth wrote: >> The PAPR interface provides a hypercall to pass high-quality >> hardware generated random numbers to guests. So let's provide >> this call in QEMU, too, so that guests that do not support >> virtio-rnd yet can get good random numbers, too. >> Please note that this hypercall should provide "good" random data >> instead of pseudo-random, so the function uses the RngBackend to >> retrieve the values instead of using a "simple" library function >> like rand() or g_random_int(). Since there are multiple RngBackends >> available, the user must select an appropriate backend via the >> "h-random" property of the the machine state to enable it, e.g. >> >> qemu-system-ppc64 -M pseries,h-random=rng-random ... ... >> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c >> index 652ddf6..ff9d4fd 100644 >> --- a/hw/ppc/spapr_hcall.c >> +++ b/hw/ppc/spapr_hcall.c >> @@ -1,4 +1,8 @@ >> #include "sysemu/sysemu.h" >> +#include "sysemu/rng.h" >> +#include "sysemu/rng-random.h" >> +#include "qom/object_interfaces.h" >> +#include "qemu/error-report.h" >> #include "cpu.h" >> #include "helper_regs.h" >> #include "hw/ppc/spapr.h" >> @@ -929,6 +933,77 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_, >> return H_SUCCESS; >> } >> >> +typedef struct HRandomData { >> + QemuSemaphore sem; >> + union { >> + uint64_t v64; >> + uint8_t v8[8]; >> + } val; >> + int received; >> +} HRandomData; >> + >> +static RndRandom *hrandom_rng; > > Couldn't you avoid the new global by looking this up through the > sPAPRMachineState? > >> + >> +static void random_recv(void *dest, const void *src, size_t size) >> +{ >> + HRandomData *hrcrdp = dest; >> + >> + if (src && size > 0) { >> + memcpy(&hrcrdp->val.v8[hrcrdp->received], src, size); > > I'd be happier with an assert() ensuring that size doesn't exceed the > buffer space we have left. > >> + hrcrdp->received += size; >> + } >> + qemu_sem_post(&hrcrdp->sem); > > Could you avoid a few wakeups by only posting the semaphore once the > buffer is filled? I tried that now, but calling rng_backend_request_entropy() from within the callback function does not work (since entropy_available() in rng-random.c clears the callback function variable after having called the callback). And since you normally seem get 8 bytes in the first shot already anyway when using a good random number generator source, I think it's best to simply keep the logic as I've currently got it - at least that's easiest to understand when reading the source code. >> +} >> + >> +static target_ulong h_random(PowerPCCPU *cpu, sPAPRMachineState *spapr, >> + target_ulong opcode, target_ulong *args) >> +{ >> + HRandomData hrcrd; >> + >> + if (!hrandom_rng) { >> + return H_HARDWARE; >> + } >> + >> + qemu_sem_init(&hrcrd.sem, 0); >> + hrcrd.val.v64 = 0; >> + hrcrd.received = 0; >> + >> + qemu_mutex_unlock_iothread(); >> + while (hrcrd.received < 8) { >> + rng_backend_request_entropy((RngBackend *)hrandom_rng, >> + 8 - hrcrd.received, random_recv, &hrcrd); >> + qemu_sem_wait(&hrcrd.sem); >> + } >> + qemu_mutex_lock_iothread(); >> + >> + qemu_sem_destroy(&hrcrd.sem); >> + args[0] = hrcrd.val.v64; >> + >> + return H_SUCCESS; >> +} I'll post a new version with the other changes soon. Thomas
On Mon, Sep 07, 2015 at 05:05:48PM +0200, Thomas Huth wrote: > On 01/09/15 02:47, David Gibson wrote: > > On Mon, Aug 31, 2015 at 08:46:02PM +0200, Thomas Huth wrote: > >> The PAPR interface provides a hypercall to pass high-quality > >> hardware generated random numbers to guests. So let's provide > >> this call in QEMU, too, so that guests that do not support > >> virtio-rnd yet can get good random numbers, too. > >> Please note that this hypercall should provide "good" random data > >> instead of pseudo-random, so the function uses the RngBackend to > >> retrieve the values instead of using a "simple" library function > >> like rand() or g_random_int(). Since there are multiple RngBackends > >> available, the user must select an appropriate backend via the > >> "h-random" property of the the machine state to enable it, e.g. > >> > >> qemu-system-ppc64 -M pseries,h-random=rng-random ... > ... > >> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c > >> index 652ddf6..ff9d4fd 100644 > >> --- a/hw/ppc/spapr_hcall.c > >> +++ b/hw/ppc/spapr_hcall.c > >> @@ -1,4 +1,8 @@ > >> #include "sysemu/sysemu.h" > >> +#include "sysemu/rng.h" > >> +#include "sysemu/rng-random.h" > >> +#include "qom/object_interfaces.h" > >> +#include "qemu/error-report.h" > >> #include "cpu.h" > >> #include "helper_regs.h" > >> #include "hw/ppc/spapr.h" > >> @@ -929,6 +933,77 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_, > >> return H_SUCCESS; > >> } > >> > >> +typedef struct HRandomData { > >> + QemuSemaphore sem; > >> + union { > >> + uint64_t v64; > >> + uint8_t v8[8]; > >> + } val; > >> + int received; > >> +} HRandomData; > >> + > >> +static RndRandom *hrandom_rng; > > > > Couldn't you avoid the new global by looking this up through the > > sPAPRMachineState? > > > >> + > >> +static void random_recv(void *dest, const void *src, size_t size) > >> +{ > >> + HRandomData *hrcrdp = dest; > >> + > >> + if (src && size > 0) { > >> + memcpy(&hrcrdp->val.v8[hrcrdp->received], src, size); > > > > I'd be happier with an assert() ensuring that size doesn't exceed the > > buffer space we have left. > > > >> + hrcrdp->received += size; > >> + } > >> + qemu_sem_post(&hrcrdp->sem); > > > > Could you avoid a few wakeups by only posting the semaphore once the > > buffer is filled? > > I tried that now, but calling rng_backend_request_entropy() from within > the callback function does not work (since entropy_available() in > rng-random.c clears the callback function variable after having called > the callback). Ah, ok. I'd missed the fact that rng_backend_request_entropy() was being called again - I'd assumed that after the first call the backend would just keep notifying until you had as much data as requested. > And since you normally seem get 8 bytes in the first shot already anyway > when using a good random number generator source, I think it's best to > simply keep the logic as I've currently got it - at least that's easiest > to understand when reading the source code. Yes, I concur. > > >> +} > >> + > >> +static target_ulong h_random(PowerPCCPU *cpu, sPAPRMachineState *spapr, > >> + target_ulong opcode, target_ulong *args) > >> +{ > >> + HRandomData hrcrd; > >> + > >> + if (!hrandom_rng) { > >> + return H_HARDWARE; > >> + } > >> + > >> + qemu_sem_init(&hrcrd.sem, 0); > >> + hrcrd.val.v64 = 0; > >> + hrcrd.received = 0; > >> + > >> + qemu_mutex_unlock_iothread(); > >> + while (hrcrd.received < 8) { > >> + rng_backend_request_entropy((RngBackend *)hrandom_rng, > >> + 8 - hrcrd.received, random_recv, &hrcrd); > >> + qemu_sem_wait(&hrcrd.sem); > >> + } > >> + qemu_mutex_lock_iothread(); > >> + > >> + qemu_sem_destroy(&hrcrd.sem); > >> + args[0] = hrcrd.val.v64; > >> + > >> + return H_SUCCESS; > >> +} > > I'll post a new version with the other changes soon. > > Thomas > >
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index bc3a112..3db87b5 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -312,7 +312,8 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base, hwaddr kernel_size, bool little_endian, const char *kernel_cmdline, - uint32_t epow_irq) + uint32_t epow_irq, + bool enable_h_random) { void *fdt; uint32_t start_prop = cpu_to_be32(initrd_base); @@ -466,7 +467,7 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base, _FDT((fdt_end_node(fdt))); - if (kvmppc_hwrng_present()) { + if (enable_h_random) { _FDT(fdt_begin_node(fdt, "ibm,platform-facilities")); _FDT(fdt_property_string(fdt, "name", "ibm,platform-facilities")); @@ -1472,7 +1473,7 @@ static void ppc_spapr_init(MachineState *machine) uint32_t initrd_base = 0; long kernel_size = 0, initrd_size = 0; long load_limit, fw_size; - bool kernel_le = false; + bool kernel_le = false, enable_h_random; char *filename; msi_supported = true; @@ -1699,6 +1700,10 @@ static void ppc_spapr_init(MachineState *machine) } g_free(filename); + /* Enable H_RANDOM hypercall if requested by user or supported by kernel */ + enable_h_random = kvmppc_hwrng_present() || + !spapr_h_random_init(spapr->h_random_type); + /* FIXME: Should register things through the MachineState's qdev * interface, this is a legacy from the sPAPREnvironment structure * which predated MachineState but had a similar function */ @@ -1710,7 +1715,8 @@ static void ppc_spapr_init(MachineState *machine) spapr->fdt_skel = spapr_create_fdt_skel(initrd_base, initrd_size, kernel_size, kernel_le, kernel_cmdline, - spapr->check_exception_irq); + spapr->check_exception_irq, + enable_h_random); assert(spapr->fdt_skel != NULL); /* used by RTAS */ @@ -1810,6 +1816,21 @@ static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp) spapr->kvm_type = g_strdup(value); } +static char *spapr_get_h_random_type(Object *obj, Error **errp) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(obj); + + return g_strdup(spapr->h_random_type); +} + +static void spapr_set_h_random_type(Object *obj, const char *val, Error **errp) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(obj); + + g_free(spapr->h_random_type); + spapr->h_random_type = g_strdup(val); +} + static void spapr_machine_initfn(Object *obj) { object_property_add_str(obj, "kvm-type", @@ -1817,6 +1838,13 @@ static void spapr_machine_initfn(Object *obj) object_property_set_description(obj, "kvm-type", "Specifies the KVM virtualization mode (HV, PR)", NULL); + + object_property_add_str(obj, "h-random", spapr_get_h_random_type, + spapr_set_h_random_type, NULL); + object_property_set_description(obj, "h-random", + "Select RNG backend for H_RANDOM hypercall " + "(rng-random, rng-egd)", + NULL); } static void ppc_cpu_do_nmi_on_cpu(void *arg) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 652ddf6..ff9d4fd 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1,4 +1,8 @@ #include "sysemu/sysemu.h" +#include "sysemu/rng.h" +#include "sysemu/rng-random.h" +#include "qom/object_interfaces.h" +#include "qemu/error-report.h" #include "cpu.h" #include "helper_regs.h" #include "hw/ppc/spapr.h" @@ -929,6 +933,77 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_, return H_SUCCESS; } +typedef struct HRandomData { + QemuSemaphore sem; + union { + uint64_t v64; + uint8_t v8[8]; + } val; + int received; +} HRandomData; + +static RndRandom *hrandom_rng; + +static void random_recv(void *dest, const void *src, size_t size) +{ + HRandomData *hrcrdp = dest; + + if (src && size > 0) { + memcpy(&hrcrdp->val.v8[hrcrdp->received], src, size); + hrcrdp->received += size; + } + qemu_sem_post(&hrcrdp->sem); +} + +static target_ulong h_random(PowerPCCPU *cpu, sPAPRMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + HRandomData hrcrd; + + if (!hrandom_rng) { + return H_HARDWARE; + } + + qemu_sem_init(&hrcrd.sem, 0); + hrcrd.val.v64 = 0; + hrcrd.received = 0; + + qemu_mutex_unlock_iothread(); + while (hrcrd.received < 8) { + rng_backend_request_entropy((RngBackend *)hrandom_rng, + 8 - hrcrd.received, random_recv, &hrcrd); + qemu_sem_wait(&hrcrd.sem); + } + qemu_mutex_lock_iothread(); + + qemu_sem_destroy(&hrcrd.sem); + args[0] = hrcrd.val.v64; + + return H_SUCCESS; +} + +int spapr_h_random_init(const char *backend_type) +{ + Error *local_err = NULL; + + if (!backend_type) { + return -1; + } + + hrandom_rng = RNG_RANDOM(object_new(backend_type)); + user_creatable_complete(OBJECT(hrandom_rng), &local_err); + if (local_err) { + error_printf("Failed to initialize backend for H_RANDOM:\n %s\n", + error_get_pretty(local_err)); + object_unref(OBJECT(hrandom_rng)); + return -1; + } + + spapr_register_hypercall(H_RANDOM, h_random); + + return 0; +} + static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1]; static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1]; diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index ab8906f..de17624 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -76,6 +76,7 @@ struct sPAPRMachineState { /*< public >*/ char *kvm_type; + char *h_random_type; }; #define H_SUCCESS 0 @@ -592,6 +593,7 @@ int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname, void spapr_pci_switch_vga(bool big_endian); void spapr_hotplug_req_add_event(sPAPRDRConnector *drc); void spapr_hotplug_req_remove_event(sPAPRDRConnector *drc); +int spapr_h_random_init(const char *backend_type); /* rtas-configure-connector state */ struct sPAPRConfigureConnectorState {
The PAPR interface provides a hypercall to pass high-quality hardware generated random numbers to guests. So let's provide this call in QEMU, too, so that guests that do not support virtio-rnd yet can get good random numbers, too. Please note that this hypercall should provide "good" random data instead of pseudo-random, so the function uses the RngBackend to retrieve the values instead of using a "simple" library function like rand() or g_random_int(). Since there are multiple RngBackends available, the user must select an appropriate backend via the "h-random" property of the the machine state to enable it, e.g. qemu-system-ppc64 -M pseries,h-random=rng-random ... to use the /dev/random backend, or "h-random=rng-egd" to use the Entropy Gathering Daemon instead. Signed-off-by: Thomas Huth <thuth@redhat.com> --- hw/ppc/spapr.c | 36 +++++++++++++++++++++--- hw/ppc/spapr_hcall.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/hw/ppc/spapr.h | 2 ++ 3 files changed, 109 insertions(+), 4 deletions(-)