From patchwork Fri Sep 18 09:05:52 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Greg Kurz X-Patchwork-Id: 519186 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id E9D7E140281 for ; Fri, 18 Sep 2015 19:06:14 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752188AbbIRJGN (ORCPT ); Fri, 18 Sep 2015 05:06:13 -0400 Received: from e06smtp07.uk.ibm.com ([195.75.94.103]:41000 "EHLO e06smtp07.uk.ibm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751702AbbIRJGK (ORCPT ); Fri, 18 Sep 2015 05:06:10 -0400 Received: from /spool/local by e06smtp07.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Fri, 18 Sep 2015 10:06:04 +0100 Received: from d06dlp03.portsmouth.uk.ibm.com (9.149.20.15) by e06smtp07.uk.ibm.com (192.168.101.137) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Fri, 18 Sep 2015 10:06:01 +0100 X-Helo: d06dlp03.portsmouth.uk.ibm.com X-MailFrom: gkurz@linux.vnet.ibm.com X-RcptTo: kvm-ppc@vger.kernel.org Received: from b06cxnps3075.portsmouth.uk.ibm.com (d06relay10.portsmouth.uk.ibm.com [9.149.109.195]) by d06dlp03.portsmouth.uk.ibm.com (Postfix) with ESMTP id 9DFB01B0806E for ; Fri, 18 Sep 2015 10:07:42 +0100 (BST) Received: from d06av05.portsmouth.uk.ibm.com (d06av05.portsmouth.uk.ibm.com [9.149.37.229]) by b06cxnps3075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id t8I960Qp36438146 for ; Fri, 18 Sep 2015 09:06:00 GMT Received: from d06av05.portsmouth.uk.ibm.com (localhost [127.0.0.1]) by d06av05.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id t8I95uR5006611 for ; Fri, 18 Sep 2015 03:05:57 -0600 Received: from smtp.lab.toulouse-stg.fr.ibm.com (srv01.lab.toulouse-stg.fr.ibm.com [9.101.4.1]) by d06av05.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id t8I95u6Z006607; Fri, 18 Sep 2015 03:05:56 -0600 Received: from bahia.local (icon-9-164-149-40.megacenter.de.ibm.com [9.164.149.40]) by smtp.lab.toulouse-stg.fr.ibm.com (Postfix) with ESMTP id 2D57C220020; Fri, 18 Sep 2015 11:05:55 +0200 (CEST) Date: Fri, 18 Sep 2015 11:05:52 +0200 From: Greg Kurz To: Thomas Huth Cc: qemu-ppc@nongnu.org, agraf@suse.de, david@gibson.dropbear.id.au, qemu-devel@nongnu.org, michael@ellerman.id.au, amit.shah@redhat.com, kvm-ppc@vger.kernel.org, sam.bobroff@au1.ibm.com Subject: Re: [PATCH v4] ppc/spapr: Implement H_RANDOM hypercall in QEMU Message-ID: <20150918110552.6487a506@bahia.local> In-Reply-To: <1442479781-20164-1-git-send-email-thuth@redhat.com> References: <1442479781-20164-1-git-send-email-thuth@redhat.com> Organization: IBM X-Mailer: Claws Mail 3.11.1 (GTK+ 2.24.28; x86_64-redhat-linux-gnu) MIME-Version: 1.0 X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 15091809-0029-0000-0000-0000042BE88A Sender: kvm-ppc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm-ppc@vger.kernel.org On Thu, 17 Sep 2015 10:49:41 +0200 Thomas Huth wrote: > The PAPR interface defines a hypercall to pass high-quality > hardware generated random numbers to guests. Recent kernels can > already provide this hypercall to the guest if the right hardware > random number generator is available. But in case the user wants > to use another source like EGD, or QEMU is running with an older > kernel, we should also have this call in QEMU, so that guests that > do not support virtio-rng yet can get good random numbers, too. > > This patch now adds a new pseudo-device to QEMU that either > directly provides this hypercall to the guest or is able to > enable the in-kernel hypercall if available. The in-kernel > hypercall can be enabled with the use-kvm property, e.g.: > > qemu-system-ppc64 -device spapr-rng,use-kvm=true > > For handling the hypercall in QEMU instead, a "RngBackend" is > required since the hypercall should provide "good" random data > instead of pseudo-random (like from a "simple" library function > like rand() or g_random_int()). Since there are multiple RngBackends > available, the user must select an appropriate back-end via the > "rng" property of the device, e.g.: > > qemu-system-ppc64 -object rng-random,filename=/dev/hwrng,id=gid0 \ > -device spapr-rng,rng=gid0 ... > > See http://wiki.qemu-project.org/Features-Done/VirtIORNG for > other example of specifying RngBackends. > > Signed-off-by: Thomas Huth > --- It is a good thing that the user can choose between in-kernel and backend, and this patch does the work. This being said, I am not sure about the use case where a user has a hwrng capable platform and wants to run guests without any hwrng support at all is an appropriate default behavior... I guess we will find more users that want in-kernel being the default if it is available. The patch below modifies yours to do just this: the pseudo-device is only created if hwrng is present and not already created. > hw/ppc/Makefile.objs | 2 +- > hw/ppc/spapr.c | 8 +++ > hw/ppc/spapr_rng.c | 186 +++++++++++++++++++++++++++++++++++++++++++++++++ > include/hw/ppc/spapr.h | 4 ++ > target-ppc/kvm.c | 9 +++ > target-ppc/kvm_ppc.h | 5 ++ > 6 files changed, 213 insertions(+), 1 deletion(-) > create mode 100644 hw/ppc/spapr_rng.c > > diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs > index c8ab06e..c1ffc77 100644 > --- a/hw/ppc/Makefile.objs > +++ b/hw/ppc/Makefile.objs > @@ -3,7 +3,7 @@ obj-y += ppc.o ppc_booke.o > # IBM pSeries (sPAPR) > obj-$(CONFIG_PSERIES) += spapr.o spapr_vio.o spapr_events.o > obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o > -obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o > +obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng.o > ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy) > obj-y += spapr_pci_vfio.o > endif > diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c > index bf0c64f..34e7d24 100644 > --- a/hw/ppc/spapr.c > +++ b/hw/ppc/spapr.c > @@ -768,6 +768,14 @@ static void spapr_finalize_fdt(sPAPRMachineState *spapr, > exit(1); > } > > + if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL)) { > + ret = spapr_rng_populate_dt(fdt); > + if (ret < 0) { > + fprintf(stderr, "could not set up rng device in the fdt\n"); > + exit(1); > + } > + } > + > QLIST_FOREACH(phb, &spapr->phbs, list) { > ret = spapr_populate_pci_dt(phb, PHANDLE_XICP, fdt); > } > diff --git a/hw/ppc/spapr_rng.c b/hw/ppc/spapr_rng.c > new file mode 100644 > index 0000000..ed43d5e > --- /dev/null > +++ b/hw/ppc/spapr_rng.c > @@ -0,0 +1,186 @@ > +/* > + * QEMU sPAPR random number generator "device" for H_RANDOM hypercall > + * > + * Copyright 2015 Thomas Huth, Red Hat Inc. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, > + * or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, see . > + */ > + > +#include "qemu/error-report.h" > +#include "sysemu/sysemu.h" > +#include "sysemu/device_tree.h" > +#include "sysemu/rng.h" > +#include "hw/ppc/spapr.h" > +#include "kvm_ppc.h" > + > +#define SPAPR_RNG(obj) \ > + OBJECT_CHECK(sPAPRRngState, (obj), TYPE_SPAPR_RNG) > + > +struct sPAPRRngState { > + /*< private >*/ > + DeviceState ds; > + RngBackend *backend; > + bool use_kvm; > +}; > +typedef struct sPAPRRngState sPAPRRngState; > + > +struct HRandomData { > + QemuSemaphore sem; > + union { > + uint64_t v64; > + uint8_t v8[8]; > + } val; > + int received; > +}; > +typedef struct HRandomData HRandomData; > + > +/* Callback function for the RngBackend */ > +static void random_recv(void *dest, const void *src, size_t size) > +{ > + HRandomData *hrdp = dest; > + > + if (src && size > 0) { > + assert(size + hrdp->received <= sizeof(hrdp->val.v8)); > + memcpy(&hrdp->val.v8[hrdp->received], src, size); > + hrdp->received += size; > + } > + > + qemu_sem_post(&hrdp->sem); > +} > + > +/* Handler for the H_RANDOM hypercall */ > +static target_ulong h_random(PowerPCCPU *cpu, sPAPRMachineState *spapr, > + target_ulong opcode, target_ulong *args) > +{ > + sPAPRRngState *rngstate; > + HRandomData hrdata; > + > + rngstate = SPAPR_RNG(object_resolve_path_type("", TYPE_SPAPR_RNG, NULL)); > + > + if (!rngstate || !rngstate->backend) { > + return H_HARDWARE; > + } > + > + qemu_sem_init(&hrdata.sem, 0); > + hrdata.val.v64 = 0; > + hrdata.received = 0; > + > + qemu_mutex_unlock_iothread(); > + while (hrdata.received < 8) { > + rng_backend_request_entropy(rngstate->backend, 8 - hrdata.received, > + random_recv, &hrdata); > + qemu_sem_wait(&hrdata.sem); > + } > + qemu_mutex_lock_iothread(); > + > + qemu_sem_destroy(&hrdata.sem); > + args[0] = hrdata.val.v64; > + > + return H_SUCCESS; > +} > + > +static void spapr_rng_instance_init(Object *obj) > +{ > + sPAPRRngState *rngstate = SPAPR_RNG(obj); > + > + if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL) != NULL) { > + error_report("spapr-rng can not be instantiated twice!"); > + return; > + } > + > + object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, > + (Object **)&rngstate->backend, > + object_property_allow_set_link, > + OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL); > + object_property_set_description(obj, "rng", > + "ID of the random number generator backend", > + NULL); > +} > + > +static void spapr_rng_realize(DeviceState *dev, Error **errp) > +{ > + > + sPAPRRngState *rngstate = SPAPR_RNG(dev); > + > + if (rngstate->use_kvm) { > + if (kvmppc_enable_hwrng() == 0) { > + return; > + } > + /* > + * If user specified both, use-kvm and a backend, we fall back to > + * the backend now. If not, provide an appropriate error message. > + */ > + if (!rngstate->backend) { > + error_setg(errp, "Could not initialize in-kernel H_RANDOM call!"); > + return; > + } > + } > + > + if (rngstate->backend) { > + spapr_register_hypercall(H_RANDOM, h_random); > + } else { > + error_setg(errp, "spapr-rng needs an RNG backend!"); > + } > +} > + > +int spapr_rng_populate_dt(void *fdt) > +{ > + int node; > + int ret; > + > + node = qemu_fdt_add_subnode(fdt, "/ibm,platform-facilities"); > + if (node <= 0) { > + return -1; > + } > + ret = fdt_setprop_string(fdt, node, "device_type", > + "ibm,platform-facilities"); > + ret |= fdt_setprop_cell(fdt, node, "#address-cells", 0x1); > + ret |= fdt_setprop_cell(fdt, node, "#size-cells", 0x0); > + > + node = fdt_add_subnode(fdt, node, "ibm,random-v1"); > + if (node <= 0) { > + return -1; > + } > + ret |= fdt_setprop_string(fdt, node, "compatible", "ibm,random"); > + > + return ret ? -1 : 0; > +} > + > +static Property spapr_rng_properties[] = { > + DEFINE_PROP_BOOL("use-kvm", sPAPRRngState, use_kvm, false), > + DEFINE_PROP_END_OF_LIST(), > +}; > + > +static void spapr_rng_class_init(ObjectClass *oc, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(oc); > + > + dc->realize = spapr_rng_realize; > + set_bit(DEVICE_CATEGORY_MISC, dc->categories); > + dc->props = spapr_rng_properties; > +} > + > +static const TypeInfo spapr_rng_info = { > + .name = TYPE_SPAPR_RNG, > + .parent = TYPE_DEVICE, > + .instance_size = sizeof(sPAPRRngState), > + .instance_init = spapr_rng_instance_init, > + .class_init = spapr_rng_class_init, > +}; > + > +static void spapr_rng_register_type(void) > +{ > + type_register_static(&spapr_rng_info); > +} > +type_init(spapr_rng_register_type) > diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h > index 91a61ab..4e8aa2d 100644 > --- a/include/hw/ppc/spapr.h > +++ b/include/hw/ppc/spapr.h > @@ -331,6 +331,7 @@ struct sPAPRMachineState { > #define H_SET_MPP 0x2D0 > #define H_GET_MPP 0x2D4 > #define H_XIRR_X 0x2FC > +#define H_RANDOM 0x300 > #define H_SET_MODE 0x31C > #define MAX_HCALL_OPCODE H_SET_MODE > > @@ -603,10 +604,13 @@ struct sPAPRConfigureConnectorState { > void spapr_ccs_reset_hook(void *opaque); > > #define TYPE_SPAPR_RTC "spapr-rtc" > +#define TYPE_SPAPR_RNG "spapr-rng" > > void spapr_rtc_read(DeviceState *dev, struct tm *tm, uint32_t *ns); > int spapr_rtc_import_offset(DeviceState *dev, int64_t legacy_offset); > > +int spapr_rng_populate_dt(void *fdt); > + > #define SPAPR_MEMORY_BLOCK_SIZE (1 << 28) /* 256MB */ > > #endif /* !defined (__HW_SPAPR_H__) */ > diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c > index 110436d..42f66fe 100644 > --- a/target-ppc/kvm.c > +++ b/target-ppc/kvm.c > @@ -2484,3 +2484,12 @@ int kvm_arch_msi_data_to_gsi(uint32_t data) > { > return data & 0xffff; > } > + > +int kvmppc_enable_hwrng(void) > +{ > + if (!kvm_enabled() || !kvm_check_extension(kvm_state, KVM_CAP_PPC_HWRNG)) { > + return -1; > + } > + > + return kvmppc_enable_hcall(kvm_state, H_RANDOM); > +} > diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h > index 4d30e27..68836b4 100644 > --- a/target-ppc/kvm_ppc.h > +++ b/target-ppc/kvm_ppc.h > @@ -55,6 +55,7 @@ void kvmppc_hash64_free_pteg(uint64_t token); > void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index, > target_ulong pte0, target_ulong pte1); > bool kvmppc_has_cap_fixup_hcalls(void); > +int kvmppc_enable_hwrng(void); > > #else > > @@ -248,6 +249,10 @@ static inline bool kvmppc_has_cap_fixup_hcalls(void) > abort(); > } > > +static inline int kvmppc_enable_hwrng(void) > +{ > + return -1; > +} > #endif > > #ifndef CONFIG_KVM Acked-by: Greg Kurz Tested-by: Greg Kurz --- To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 240fab72e7af..4b92efed2ef3 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -939,6 +939,14 @@ static int spapr_check_htab_fd(sPAPRMachineState *spapr) return rc; } +static void spapr_rng_create(void) +{ + Object *rng = object_new(TYPE_SPAPR_RNG); + + object_property_set_bool(rng, true, "use-kvm", &error_abort); + object_property_set_bool(rng, true, "realized", &error_abort); +} + static void ppc_spapr_reset(void) { sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); @@ -962,6 +970,14 @@ static void ppc_spapr_reset(void) spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE; spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE; + /* Create a rng device if the user did not provide it already and + * KVM has hwrng support. + */ + if (kvmppc_hwrng_present() && + !object_resolve_path_type("", TYPE_SPAPR_RNG, NULL)) { + spapr_rng_create(); + } + /* Load the fdt */ spapr_finalize_fdt(spapr, spapr->fdt_addr, spapr->rtas_addr, spapr->rtas_size); diff --git a/hw/ppc/spapr_rng.c b/hw/ppc/spapr_rng.c index ed43d5e04221..ee5af302bd4d 100644 --- a/hw/ppc/spapr_rng.c +++ b/hw/ppc/spapr_rng.c @@ -114,7 +114,7 @@ static void spapr_rng_realize(DeviceState *dev, Error **errp) sPAPRRngState *rngstate = SPAPR_RNG(dev); if (rngstate->use_kvm) { - if (kvmppc_enable_hwrng() == 0) { + if (kvmppc_hwrng_present() && kvmppc_enable_hwrng() == 0) { return; } /* diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 42f66fea23e9..008f8a26ab17 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -2485,11 +2485,12 @@ int kvm_arch_msi_data_to_gsi(uint32_t data) return data & 0xffff; } -int kvmppc_enable_hwrng(void) +bool kvmppc_hwrng_present(void) { - if (!kvm_enabled() || !kvm_check_extension(kvm_state, KVM_CAP_PPC_HWRNG)) { - return -1; - } + return kvm_enabled() && kvm_check_extension(kvm_state, KVM_CAP_PPC_HWRNG); +} +int kvmppc_enable_hwrng(void) +{ return kvmppc_enable_hcall(kvm_state, H_RANDOM); } diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 68836b401105..4b78bfe5224a 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -55,6 +55,7 @@ void kvmppc_hash64_free_pteg(uint64_t token); void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index, target_ulong pte0, target_ulong pte1); bool kvmppc_has_cap_fixup_hcalls(void); +bool kvmppc_hwrng_present(void); int kvmppc_enable_hwrng(void); #else @@ -249,6 +250,11 @@ static inline bool kvmppc_has_cap_fixup_hcalls(void) abort(); } +static inline bool kvmppc_hwrng_present(void) +{ + return false; +} + static inline int kvmppc_enable_hwrng(void) { return -1;