Message ID | 1401106626-13130-2-git-send-email-paulus@samba.org |
---|---|
State | New, archived |
Headers | show |
On 26.05.14 14:17, Paul Mackerras wrote: > This provides a way for userspace controls which PAPR hcalls get > handled in the kernel. Each hcall can be individually enabled or > disabled for in-kernel handling, except for H_RTAS. The exception > for H_RTAS is because userspace can already control whether > individual RTAS functions are handled in-kernel or not via the > KVM_PPC_RTAS_DEFINE_TOKEN ioctl, and because the numeric value for > H_RTAS is out of the normal sequence of hcall numbers. > > Hcalls are enabled or disabled using the KVM_ENABLE_CAP ioctl for > the KVM_CAP_PPC_ENABLE_HCALL capability. The args field of the > struct kvm_enable_cap specifies the hcall number in args[0] and > the enable/disable flag in args[1]; 0 means disable in-kernel > handling (so that the hcall will always cause an exit to userspace) > and 1 means enable. > > Enabling or disabling in-kernel handling of an hcall is effective > across the whole VM, even though the KVM_ENABLE_CAP ioctl is > applied to a vcpu. > > When a VM is created, an initial set of hcalls are enabled for > in-kernel handling. The set that is enabled is the set that have > an in-kernel implementation at this point. Any new hcall > implementations from this point onwards should not be added to the > default set. > > No distinction is made between real-mode and virtual-mode hcall > implementations; the one setting controls them both. > > Signed-off-by: Paul Mackerras <paulus@samba.org> > --- > Documentation/virtual/kvm/api.txt | 17 +++++++++++ > arch/powerpc/include/asm/kvm_book3s.h | 1 + > arch/powerpc/include/asm/kvm_host.h | 2 ++ > arch/powerpc/kernel/asm-offsets.c | 1 + > arch/powerpc/kvm/book3s_hv.c | 51 +++++++++++++++++++++++++++++++++ > arch/powerpc/kvm/book3s_hv_rmhandlers.S | 11 +++++++ > arch/powerpc/kvm/book3s_pr.c | 5 ++++ > arch/powerpc/kvm/book3s_pr_papr.c | 37 ++++++++++++++++++++++++ > arch/powerpc/kvm/powerpc.c | 19 ++++++++++++ > include/uapi/linux/kvm.h | 1 + > 10 files changed, 145 insertions(+) > > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt > index 6b0225d..dfd6e0c 100644 > --- a/Documentation/virtual/kvm/api.txt > +++ b/Documentation/virtual/kvm/api.txt > @@ -2983,3 +2983,20 @@ Parameters: args[0] is the XICS device fd > args[1] is the XICS CPU number (server ID) for this vcpu > > This capability connects the vcpu to an in-kernel XICS device. > + > +6.8 KVM_CAP_PPC_ENABLE_HCALL > + > +Architectures: ppc > +Parameters: args[0] is the PAPR hcall number > + args[1] is 0 to disable, 1 to enable in-kernel handling > + > +This capability controls whether individual PAPR hypercalls (hcalls) > +get handled by the kernel or not. Enabling or disabling in-kernel > +handling of an hcall is effective across the VM. On creation, an Hrm. Could we move the CAP to vm level then? > +initial set of hcalls are enabled for in-kernel handling, which > +consists of those hcalls for which in-kernel handlers were implemented > +before this capability was implemented. If disabled, the kernel will > +not to attempt to handle the hcall, but will always exit to userspace > +to handle it. Note that it may not make sense to enable some and > +disable others of a group of related hcalls, but KVM will not prevent > +userspace from doing that. > diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h > index f52f656..772044b 100644 > --- a/arch/powerpc/include/asm/kvm_book3s.h > +++ b/arch/powerpc/include/asm/kvm_book3s.h > @@ -189,6 +189,7 @@ extern void kvmppc_hv_entry_trampoline(void); > extern u32 kvmppc_alignment_dsisr(struct kvm_vcpu *vcpu, unsigned int inst); > extern ulong kvmppc_alignment_dar(struct kvm_vcpu *vcpu, unsigned int inst); > extern int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd); > +extern void kvmppc_pr_init_default_hcalls(struct kvm *kvm); > extern void kvmppc_copy_to_svcpu(struct kvmppc_book3s_shadow_vcpu *svcpu, > struct kvm_vcpu *vcpu); > extern void kvmppc_copy_from_svcpu(struct kvm_vcpu *vcpu, > diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h > index bb66d8b..2889587 100644 > --- a/arch/powerpc/include/asm/kvm_host.h > +++ b/arch/powerpc/include/asm/kvm_host.h > @@ -34,6 +34,7 @@ > #include <asm/processor.h> > #include <asm/page.h> > #include <asm/cacheflush.h> > +#include <asm/hvcall.h> > > #define KVM_MAX_VCPUS NR_CPUS > #define KVM_MAX_VCORES NR_CPUS > @@ -263,6 +264,7 @@ struct kvm_arch { > #ifdef CONFIG_PPC_BOOK3S_64 > struct list_head spapr_tce_tables; > struct list_head rtas_tokens; > + DECLARE_BITMAP(enabled_hcalls, MAX_HCALL_OPCODE/4 + 1); > #endif > #ifdef CONFIG_KVM_MPIC > struct openpic *mpic; > diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c > index 93e1465..c427b51 100644 > --- a/arch/powerpc/kernel/asm-offsets.c > +++ b/arch/powerpc/kernel/asm-offsets.c > @@ -492,6 +492,7 @@ int main(void) > DEFINE(KVM_HOST_SDR1, offsetof(struct kvm, arch.host_sdr1)); > DEFINE(KVM_TLBIE_LOCK, offsetof(struct kvm, arch.tlbie_lock)); > DEFINE(KVM_NEED_FLUSH, offsetof(struct kvm, arch.need_tlb_flush.bits)); > + DEFINE(KVM_ENABLED_HCALLS, offsetof(struct kvm, arch.enabled_hcalls)); > DEFINE(KVM_LPCR, offsetof(struct kvm, arch.lpcr)); > DEFINE(KVM_RMOR, offsetof(struct kvm, arch.rmor)); > DEFINE(KVM_VRMA_SLB_V, offsetof(struct kvm, arch.vrma_slb_v)); > diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c > index aba05bb..84e695d 100644 > --- a/arch/powerpc/kvm/book3s_hv.c > +++ b/arch/powerpc/kvm/book3s_hv.c > @@ -67,6 +67,8 @@ > /* Used as a "null" value for timebase values */ > #define TB_NIL (~(u64)0) > > +static DECLARE_BITMAP(default_enabled_hcalls, MAX_HCALL_OPCODE/4 + 1); > + > static void kvmppc_end_cede(struct kvm_vcpu *vcpu); > static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu); > > @@ -562,6 +564,10 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) > struct kvm_vcpu *tvcpu; > int idx, rc; > > + if (req <= MAX_HCALL_OPCODE && > + !test_bit(req/4, vcpu->kvm->arch.enabled_hcalls)) > + return RESUME_HOST; > + > switch (req) { > case H_ENTER: > idx = srcu_read_lock(&vcpu->kvm->srcu); > @@ -2275,6 +2281,10 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm) > */ > cpumask_setall(&kvm->arch.need_tlb_flush); > > + /* Start out with the default set of hcalls enabled */ > + memcpy(kvm->arch.enabled_hcalls, default_enabled_hcalls, > + sizeof(kvm->arch.enabled_hcalls)); > + > kvm->arch.rma = NULL; > > kvm->arch.host_sdr1 = mfspr(SPRN_SDR1); > @@ -2413,6 +2423,45 @@ static long kvm_arch_vm_ioctl_hv(struct file *filp, > return r; > } > > +/* > + * List of hcall numbers to enable by default. > + * For compatibility with old userspace, we enable by default > + * all hcalls that were implemented before the hcall-enabling > + * facility was added. Note this list should not include H_RTAS. > + */ > +static unsigned int default_hcall_list[] = { > + H_REMOVE, > + H_ENTER, > + H_READ, > + H_PROTECT, > + H_BULK_REMOVE, > + H_GET_TCE, > + H_PUT_TCE, > + H_SET_DABR, > + H_SET_XDABR, > + H_CEDE, > + H_PROD, > + H_CONFER, > + H_REGISTER_VPA, > +#ifdef CONFIG_KVM_XICS > + H_EOI, > + H_CPPR, > + H_IPI, > + H_IPOLL, > + H_XIRR, > + H_XIRR_X, > +#endif > + 0 > +}; > + > +static void init_default_hcalls(void) > +{ > + int i; > + > + for (i = 0; default_hcall_list[i]; ++i) BUG_ON(default_hcall_list[i] > MAX_HCALL_OPCODE); Alex > + __set_bit(default_hcall_list[i] / 4, default_enabled_hcalls); > +} > + > static struct kvmppc_ops kvm_ops_hv = { > .get_sregs = kvm_arch_vcpu_ioctl_get_sregs_hv, > .set_sregs = kvm_arch_vcpu_ioctl_set_sregs_hv, > @@ -2460,6 +2509,8 @@ static int kvmppc_book3s_init_hv(void) > kvm_ops_hv.owner = THIS_MODULE; > kvmppc_hv_ops = &kvm_ops_hv; > > + init_default_hcalls(); > + > r = kvmppc_mmu_hv_init(); > return r; > } > diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S > index 220aefb..c26b0e2 100644 > --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S > +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S > @@ -1795,6 +1795,17 @@ hcall_try_real_mode: > clrrdi r3,r3,2 > cmpldi r3,hcall_real_table_end - hcall_real_table > bge guest_exit_cont > + /* See if this hcall is enabled for in-kernel handling */ > + ld r4, VCPU_KVM(r9) > + srdi r0, r3, 8 /* r0 = (r3 / 4) >> 6 */ > + sldi r0, r0, 3 /* index into kvm->arch.enabled_hcalls[] */ > + add r4, r4, r0 > + ld r0, KVM_ENABLED_HCALLS(r4) > + rlwinm r4, r3, 32-2, 0x3f /* r4 = (r3 / 4) & 0x3f */ > + srd r0, r0, r4 > + andi. r0, r0, 1 > + beq guest_exit_cont > + /* Get pointer to handler, if any, and call it */ > LOAD_REG_ADDR(r4, hcall_real_table) > lwax r3,r3,r4 > cmpwi r3,0 > diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c > index 23367a7..59dc94e 100644 > --- a/arch/powerpc/kvm/book3s_pr.c > +++ b/arch/powerpc/kvm/book3s_pr.c > @@ -1568,6 +1568,11 @@ static int kvmppc_core_init_vm_pr(struct kvm *kvm) > { > mutex_init(&kvm->arch.hpt_mutex); > > +#ifdef CONFIG_PPC_BOOK3S_64 > + /* Start out with the default set of hcalls enabled */ > + kvmppc_pr_init_default_hcalls(kvm); > +#endif > + > if (firmware_has_feature(FW_FEATURE_SET_MODE)) { > spin_lock(&kvm_global_user_count_lock); > if (++kvm_global_user_count == 1) > diff --git a/arch/powerpc/kvm/book3s_pr_papr.c b/arch/powerpc/kvm/book3s_pr_papr.c > index 52a63bf..c5afde2 100644 > --- a/arch/powerpc/kvm/book3s_pr_papr.c > +++ b/arch/powerpc/kvm/book3s_pr_papr.c > @@ -266,6 +266,10 @@ static int kvmppc_h_pr_xics_hcall(struct kvm_vcpu *vcpu, u32 cmd) > > int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd) > { > + if (cmd <= MAX_HCALL_OPCODE && > + !test_bit(cmd/4, vcpu->kvm->arch.enabled_hcalls)) > + return EMULATE_FAIL; > + > switch (cmd) { > case H_ENTER: > return kvmppc_h_pr_enter(vcpu); > @@ -303,3 +307,36 @@ int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd) > > return EMULATE_FAIL; > } > + > + > +/* > + * List of hcall numbers to enable by default. > + * For compatibility with old userspace, we enable by default > + * all hcalls that were implemented before the hcall-enabling > + * facility was added. Note this list should not include H_RTAS. > + */ > +static unsigned int default_hcall_list[] = { > + H_ENTER, > + H_REMOVE, > + H_PROTECT, > + H_BULK_REMOVE, > + H_PUT_TCE, > + H_CEDE, > +#ifdef CONFIG_KVM_XICS > + H_XIRR, > + H_CPPR, > + H_EOI, > + H_IPI, > + H_IPOLL, > + H_XIRR_X, > +#endif > + 0 > +}; > + > +void kvmppc_pr_init_default_hcalls(struct kvm *kvm) > +{ > + int i; > + > + for (i = 0; default_hcall_list[i]; ++i) > + __set_bit(default_hcall_list[i] / 4, kvm->arch.enabled_hcalls); > +} > diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c > index 154f352..5690c74 100644 > --- a/arch/powerpc/kvm/powerpc.c > +++ b/arch/powerpc/kvm/powerpc.c > @@ -416,6 +416,7 @@ int kvm_dev_ioctl_check_extension(long ext) > case KVM_CAP_SPAPR_TCE: > case KVM_CAP_PPC_ALLOC_HTAB: > case KVM_CAP_PPC_RTAS: > + case KVM_CAP_PPC_ENABLE_HCALL: > #ifdef CONFIG_KVM_XICS > case KVM_CAP_IRQ_XICS: > #endif > @@ -964,6 +965,24 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, > break; > } > #endif /* CONFIG_KVM_XICS */ > +#ifdef CONFIG_KVM_BOOK3S_64_HANDLER > + case KVM_CAP_PPC_ENABLE_HCALL: { > + unsigned long hcall = cap->args[0]; > + > + r = -EINVAL; > + if (!vcpu->arch.papr_enabled) > + break; > + if (hcall > MAX_HCALL_OPCODE || (hcall & 3) || > + cap->args[1] > 1) > + break; > + if (cap->args[1]) > + set_bit(hcall / 4, vcpu->kvm->arch.enabled_hcalls); > + else > + clear_bit(hcall / 4, vcpu->kvm->arch.enabled_hcalls); > + r = 0; > + break; > + } > +#endif > default: > r = -EINVAL; > break; > diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h > index 836e15b..79e4532 100644 > --- a/include/uapi/linux/kvm.h > +++ b/include/uapi/linux/kvm.h > @@ -746,6 +746,7 @@ struct kvm_ppc_smmu_info { > #define KVM_CAP_S390_IRQCHIP 99 > #define KVM_CAP_IOEVENTFD_NO_LENGTH 100 > #define KVM_CAP_VM_ATTRIBUTES 101 > +#define KVM_CAP_PPC_ENABLE_HCALL 102 > > #ifdef KVM_CAP_IRQ_ROUTING > -- 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
On Wed, May 28, 2014 at 03:27:32PM +0200, Alexander Graf wrote: > > On 26.05.14 14:17, Paul Mackerras wrote: > >+6.8 KVM_CAP_PPC_ENABLE_HCALL > >+ > >+Architectures: ppc > >+Parameters: args[0] is the PAPR hcall number > >+ args[1] is 0 to disable, 1 to enable in-kernel handling > >+ > >+This capability controls whether individual PAPR hypercalls (hcalls) > >+get handled by the kernel or not. Enabling or disabling in-kernel > >+handling of an hcall is effective across the VM. On creation, an > > Hrm. Could we move the CAP to vm level then? You mean, define a VM ioctl instead of using a capability? Or are you suggesting something else? Paul. -- 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
> Am 29.05.2014 um 07:27 schrieb Paul Mackerras <paulus@samba.org>: > >> On Wed, May 28, 2014 at 03:27:32PM +0200, Alexander Graf wrote: >> >>> On 26.05.14 14:17, Paul Mackerras wrote: >>> +6.8 KVM_CAP_PPC_ENABLE_HCALL >>> + >>> +Architectures: ppc >>> +Parameters: args[0] is the PAPR hcall number >>> + args[1] is 0 to disable, 1 to enable in-kernel handling >>> + >>> +This capability controls whether individual PAPR hypercalls (hcalls) >>> +get handled by the kernel or not. Enabling or disabling in-kernel >>> +handling of an hcall is effective across the VM. On creation, an >> >> Hrm. Could we move the CAP to vm level then? > > You mean, define a VM ioctl instead of using a capability? Or are you > suggesting something else? I'm suggesting ENABLE_CAP on the vm fd :) Alex > > Paul. -- 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/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 6b0225d..dfd6e0c 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2983,3 +2983,20 @@ Parameters: args[0] is the XICS device fd args[1] is the XICS CPU number (server ID) for this vcpu This capability connects the vcpu to an in-kernel XICS device. + +6.8 KVM_CAP_PPC_ENABLE_HCALL + +Architectures: ppc +Parameters: args[0] is the PAPR hcall number + args[1] is 0 to disable, 1 to enable in-kernel handling + +This capability controls whether individual PAPR hypercalls (hcalls) +get handled by the kernel or not. Enabling or disabling in-kernel +handling of an hcall is effective across the VM. On creation, an +initial set of hcalls are enabled for in-kernel handling, which +consists of those hcalls for which in-kernel handlers were implemented +before this capability was implemented. If disabled, the kernel will +not to attempt to handle the hcall, but will always exit to userspace +to handle it. Note that it may not make sense to enable some and +disable others of a group of related hcalls, but KVM will not prevent +userspace from doing that. diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h index f52f656..772044b 100644 --- a/arch/powerpc/include/asm/kvm_book3s.h +++ b/arch/powerpc/include/asm/kvm_book3s.h @@ -189,6 +189,7 @@ extern void kvmppc_hv_entry_trampoline(void); extern u32 kvmppc_alignment_dsisr(struct kvm_vcpu *vcpu, unsigned int inst); extern ulong kvmppc_alignment_dar(struct kvm_vcpu *vcpu, unsigned int inst); extern int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd); +extern void kvmppc_pr_init_default_hcalls(struct kvm *kvm); extern void kvmppc_copy_to_svcpu(struct kvmppc_book3s_shadow_vcpu *svcpu, struct kvm_vcpu *vcpu); extern void kvmppc_copy_from_svcpu(struct kvm_vcpu *vcpu, diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index bb66d8b..2889587 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -34,6 +34,7 @@ #include <asm/processor.h> #include <asm/page.h> #include <asm/cacheflush.h> +#include <asm/hvcall.h> #define KVM_MAX_VCPUS NR_CPUS #define KVM_MAX_VCORES NR_CPUS @@ -263,6 +264,7 @@ struct kvm_arch { #ifdef CONFIG_PPC_BOOK3S_64 struct list_head spapr_tce_tables; struct list_head rtas_tokens; + DECLARE_BITMAP(enabled_hcalls, MAX_HCALL_OPCODE/4 + 1); #endif #ifdef CONFIG_KVM_MPIC struct openpic *mpic; diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 93e1465..c427b51 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -492,6 +492,7 @@ int main(void) DEFINE(KVM_HOST_SDR1, offsetof(struct kvm, arch.host_sdr1)); DEFINE(KVM_TLBIE_LOCK, offsetof(struct kvm, arch.tlbie_lock)); DEFINE(KVM_NEED_FLUSH, offsetof(struct kvm, arch.need_tlb_flush.bits)); + DEFINE(KVM_ENABLED_HCALLS, offsetof(struct kvm, arch.enabled_hcalls)); DEFINE(KVM_LPCR, offsetof(struct kvm, arch.lpcr)); DEFINE(KVM_RMOR, offsetof(struct kvm, arch.rmor)); DEFINE(KVM_VRMA_SLB_V, offsetof(struct kvm, arch.vrma_slb_v)); diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index aba05bb..84e695d 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -67,6 +67,8 @@ /* Used as a "null" value for timebase values */ #define TB_NIL (~(u64)0) +static DECLARE_BITMAP(default_enabled_hcalls, MAX_HCALL_OPCODE/4 + 1); + static void kvmppc_end_cede(struct kvm_vcpu *vcpu); static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu); @@ -562,6 +564,10 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) struct kvm_vcpu *tvcpu; int idx, rc; + if (req <= MAX_HCALL_OPCODE && + !test_bit(req/4, vcpu->kvm->arch.enabled_hcalls)) + return RESUME_HOST; + switch (req) { case H_ENTER: idx = srcu_read_lock(&vcpu->kvm->srcu); @@ -2275,6 +2281,10 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm) */ cpumask_setall(&kvm->arch.need_tlb_flush); + /* Start out with the default set of hcalls enabled */ + memcpy(kvm->arch.enabled_hcalls, default_enabled_hcalls, + sizeof(kvm->arch.enabled_hcalls)); + kvm->arch.rma = NULL; kvm->arch.host_sdr1 = mfspr(SPRN_SDR1); @@ -2413,6 +2423,45 @@ static long kvm_arch_vm_ioctl_hv(struct file *filp, return r; } +/* + * List of hcall numbers to enable by default. + * For compatibility with old userspace, we enable by default + * all hcalls that were implemented before the hcall-enabling + * facility was added. Note this list should not include H_RTAS. + */ +static unsigned int default_hcall_list[] = { + H_REMOVE, + H_ENTER, + H_READ, + H_PROTECT, + H_BULK_REMOVE, + H_GET_TCE, + H_PUT_TCE, + H_SET_DABR, + H_SET_XDABR, + H_CEDE, + H_PROD, + H_CONFER, + H_REGISTER_VPA, +#ifdef CONFIG_KVM_XICS + H_EOI, + H_CPPR, + H_IPI, + H_IPOLL, + H_XIRR, + H_XIRR_X, +#endif + 0 +}; + +static void init_default_hcalls(void) +{ + int i; + + for (i = 0; default_hcall_list[i]; ++i) + __set_bit(default_hcall_list[i] / 4, default_enabled_hcalls); +} + static struct kvmppc_ops kvm_ops_hv = { .get_sregs = kvm_arch_vcpu_ioctl_get_sregs_hv, .set_sregs = kvm_arch_vcpu_ioctl_set_sregs_hv, @@ -2460,6 +2509,8 @@ static int kvmppc_book3s_init_hv(void) kvm_ops_hv.owner = THIS_MODULE; kvmppc_hv_ops = &kvm_ops_hv; + init_default_hcalls(); + r = kvmppc_mmu_hv_init(); return r; } diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 220aefb..c26b0e2 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -1795,6 +1795,17 @@ hcall_try_real_mode: clrrdi r3,r3,2 cmpldi r3,hcall_real_table_end - hcall_real_table bge guest_exit_cont + /* See if this hcall is enabled for in-kernel handling */ + ld r4, VCPU_KVM(r9) + srdi r0, r3, 8 /* r0 = (r3 / 4) >> 6 */ + sldi r0, r0, 3 /* index into kvm->arch.enabled_hcalls[] */ + add r4, r4, r0 + ld r0, KVM_ENABLED_HCALLS(r4) + rlwinm r4, r3, 32-2, 0x3f /* r4 = (r3 / 4) & 0x3f */ + srd r0, r0, r4 + andi. r0, r0, 1 + beq guest_exit_cont + /* Get pointer to handler, if any, and call it */ LOAD_REG_ADDR(r4, hcall_real_table) lwax r3,r3,r4 cmpwi r3,0 diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index 23367a7..59dc94e 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -1568,6 +1568,11 @@ static int kvmppc_core_init_vm_pr(struct kvm *kvm) { mutex_init(&kvm->arch.hpt_mutex); +#ifdef CONFIG_PPC_BOOK3S_64 + /* Start out with the default set of hcalls enabled */ + kvmppc_pr_init_default_hcalls(kvm); +#endif + if (firmware_has_feature(FW_FEATURE_SET_MODE)) { spin_lock(&kvm_global_user_count_lock); if (++kvm_global_user_count == 1) diff --git a/arch/powerpc/kvm/book3s_pr_papr.c b/arch/powerpc/kvm/book3s_pr_papr.c index 52a63bf..c5afde2 100644 --- a/arch/powerpc/kvm/book3s_pr_papr.c +++ b/arch/powerpc/kvm/book3s_pr_papr.c @@ -266,6 +266,10 @@ static int kvmppc_h_pr_xics_hcall(struct kvm_vcpu *vcpu, u32 cmd) int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd) { + if (cmd <= MAX_HCALL_OPCODE && + !test_bit(cmd/4, vcpu->kvm->arch.enabled_hcalls)) + return EMULATE_FAIL; + switch (cmd) { case H_ENTER: return kvmppc_h_pr_enter(vcpu); @@ -303,3 +307,36 @@ int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd) return EMULATE_FAIL; } + + +/* + * List of hcall numbers to enable by default. + * For compatibility with old userspace, we enable by default + * all hcalls that were implemented before the hcall-enabling + * facility was added. Note this list should not include H_RTAS. + */ +static unsigned int default_hcall_list[] = { + H_ENTER, + H_REMOVE, + H_PROTECT, + H_BULK_REMOVE, + H_PUT_TCE, + H_CEDE, +#ifdef CONFIG_KVM_XICS + H_XIRR, + H_CPPR, + H_EOI, + H_IPI, + H_IPOLL, + H_XIRR_X, +#endif + 0 +}; + +void kvmppc_pr_init_default_hcalls(struct kvm *kvm) +{ + int i; + + for (i = 0; default_hcall_list[i]; ++i) + __set_bit(default_hcall_list[i] / 4, kvm->arch.enabled_hcalls); +} diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 154f352..5690c74 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -416,6 +416,7 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_SPAPR_TCE: case KVM_CAP_PPC_ALLOC_HTAB: case KVM_CAP_PPC_RTAS: + case KVM_CAP_PPC_ENABLE_HCALL: #ifdef CONFIG_KVM_XICS case KVM_CAP_IRQ_XICS: #endif @@ -964,6 +965,24 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, break; } #endif /* CONFIG_KVM_XICS */ +#ifdef CONFIG_KVM_BOOK3S_64_HANDLER + case KVM_CAP_PPC_ENABLE_HCALL: { + unsigned long hcall = cap->args[0]; + + r = -EINVAL; + if (!vcpu->arch.papr_enabled) + break; + if (hcall > MAX_HCALL_OPCODE || (hcall & 3) || + cap->args[1] > 1) + break; + if (cap->args[1]) + set_bit(hcall / 4, vcpu->kvm->arch.enabled_hcalls); + else + clear_bit(hcall / 4, vcpu->kvm->arch.enabled_hcalls); + r = 0; + break; + } +#endif default: r = -EINVAL; break; diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 836e15b..79e4532 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -746,6 +746,7 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_S390_IRQCHIP 99 #define KVM_CAP_IOEVENTFD_NO_LENGTH 100 #define KVM_CAP_VM_ATTRIBUTES 101 +#define KVM_CAP_PPC_ENABLE_HCALL 102 #ifdef KVM_CAP_IRQ_ROUTING
This provides a way for userspace controls which PAPR hcalls get handled in the kernel. Each hcall can be individually enabled or disabled for in-kernel handling, except for H_RTAS. The exception for H_RTAS is because userspace can already control whether individual RTAS functions are handled in-kernel or not via the KVM_PPC_RTAS_DEFINE_TOKEN ioctl, and because the numeric value for H_RTAS is out of the normal sequence of hcall numbers. Hcalls are enabled or disabled using the KVM_ENABLE_CAP ioctl for the KVM_CAP_PPC_ENABLE_HCALL capability. The args field of the struct kvm_enable_cap specifies the hcall number in args[0] and the enable/disable flag in args[1]; 0 means disable in-kernel handling (so that the hcall will always cause an exit to userspace) and 1 means enable. Enabling or disabling in-kernel handling of an hcall is effective across the whole VM, even though the KVM_ENABLE_CAP ioctl is applied to a vcpu. When a VM is created, an initial set of hcalls are enabled for in-kernel handling. The set that is enabled is the set that have an in-kernel implementation at this point. Any new hcall implementations from this point onwards should not be added to the default set. No distinction is made between real-mode and virtual-mode hcall implementations; the one setting controls them both. Signed-off-by: Paul Mackerras <paulus@samba.org> --- Documentation/virtual/kvm/api.txt | 17 +++++++++++ arch/powerpc/include/asm/kvm_book3s.h | 1 + arch/powerpc/include/asm/kvm_host.h | 2 ++ arch/powerpc/kernel/asm-offsets.c | 1 + arch/powerpc/kvm/book3s_hv.c | 51 +++++++++++++++++++++++++++++++++ arch/powerpc/kvm/book3s_hv_rmhandlers.S | 11 +++++++ arch/powerpc/kvm/book3s_pr.c | 5 ++++ arch/powerpc/kvm/book3s_pr_papr.c | 37 ++++++++++++++++++++++++ arch/powerpc/kvm/powerpc.c | 19 ++++++++++++ include/uapi/linux/kvm.h | 1 + 10 files changed, 145 insertions(+)