@@ -3020,4 +3020,8 @@ to handle it. Note that it may not make sense to enable some and
disable others of a group of related hcalls, but KVM does not prevent
userspace from doing that.
+If the hcall number specified is not one that has an in-kernel
+implementation, the KVM_ENABLE_CAP ioctl will fail with an EINVAL
+error.
+
This capability is a VM-level capability, not a VCPU capability.
@@ -148,6 +148,7 @@ extern void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *
extern int kvmppc_mmu_hpte_sysinit(void);
extern void kvmppc_mmu_hpte_sysexit(void);
extern int kvmppc_mmu_hv_init(void);
+extern int kvmppc_book3s_hcall_implemented(struct kvm *kvm, unsigned long hc);
extern int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, bool data);
extern int kvmppc_st(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, bool data);
@@ -190,6 +191,8 @@ 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 int kvmppc_hcall_impl_pr(unsigned long cmd);
+extern int kvmppc_hcall_impl_hv_realmode(unsigned long cmd);
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,
@@ -228,7 +228,7 @@ struct kvmppc_ops {
void (*fast_vcpu_kick)(struct kvm_vcpu *vcpu);
long (*arch_vm_ioctl)(struct file *filp, unsigned int ioctl,
unsigned long arg);
-
+ int (*hcall_implemented)(unsigned long hcall);
};
extern struct kvmppc_ops *kvmppc_hv_ops;
@@ -913,6 +913,11 @@ int kvmppc_core_check_processor_compat(void)
return 0;
}
+int kvmppc_book3s_hcall_implemented(struct kvm *kvm, unsigned long hcall)
+{
+ return kvm->arch.kvm_ops->hcall_implemented(hcall);
+}
+
static int kvmppc_book3s_init(void)
{
int r;
@@ -645,6 +645,28 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
return RESUME_GUEST;
}
+static int kvmppc_hcall_impl_hv(unsigned long cmd)
+{
+ switch (cmd) {
+ case H_CEDE:
+ case H_PROD:
+ case H_CONFER:
+ case H_REGISTER_VPA:
+#ifdef CONFIG_KVM_XICS
+ case H_XIRR:
+ case H_CPPR:
+ case H_EOI:
+ case H_IPI:
+ case H_IPOLL:
+ case H_XIRR_X:
+#endif
+ return 1;
+ }
+
+ /* See if it's in the real-mode table */
+ return kvmppc_hcall_impl_hv_realmode(cmd);
+}
+
static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu,
struct task_struct *tsk)
{
@@ -2457,9 +2479,13 @@ static unsigned int default_hcall_list[] = {
static void init_default_hcalls(void)
{
int i;
+ unsigned int hcall;
- for (i = 0; default_hcall_list[i]; ++i)
- __set_bit(default_hcall_list[i] / 4, default_enabled_hcalls);
+ for (i = 0; default_hcall_list[i]; ++i) {
+ hcall = default_hcall_list[i];
+ WARN_ON(!kvmppc_hcall_impl_hv(hcall));
+ __set_bit(hcall / 4, default_enabled_hcalls);
+ }
}
static struct kvmppc_ops kvm_ops_hv = {
@@ -2494,6 +2520,7 @@ static struct kvmppc_ops kvm_ops_hv = {
.emulate_mfspr = kvmppc_core_emulate_mfspr_hv,
.fast_vcpu_kick = kvmppc_fast_vcpu_kick_hv,
.arch_vm_ioctl = kvm_arch_vm_ioctl_hv,
+ .hcall_implemented = kvmppc_hcall_impl_hv,
};
static int kvmppc_book3s_init_hv(void)
@@ -181,3 +181,16 @@ void __init kvm_cma_reserve(void)
kvm_cma_declare_contiguous(selected_size, align_size);
}
}
+
+extern int hcall_real_table[], hcall_real_table_end[];
+
+int kvmppc_hcall_impl_hv_realmode(unsigned long cmd)
+{
+ cmd /= 4;
+ if (cmd < hcall_real_table_end - hcall_real_table &&
+ hcall_real_table[cmd])
+ return 1;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kvmppc_hcall_impl_hv_realmode);
@@ -1928,6 +1928,7 @@ hcall_real_table:
.long 0 /* 0x12c */
.long 0 /* 0x130 */
.long .kvmppc_h_set_xdabr - hcall_real_table
+ .globl hcall_real_table_end
hcall_real_table_end:
ignore_hdec:
@@ -1641,6 +1641,9 @@ static struct kvmppc_ops kvm_ops_pr = {
.emulate_mfspr = kvmppc_core_emulate_mfspr_pr,
.fast_vcpu_kick = kvm_vcpu_kick,
.arch_vm_ioctl = kvm_arch_vm_ioctl_pr,
+#ifdef CONFIG_PPC_BOOK3S_64
+ .hcall_implemented = kvmppc_hcall_impl_pr,
+#endif
};
@@ -308,6 +308,27 @@ int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd)
return EMULATE_FAIL;
}
+int kvmppc_hcall_impl_pr(unsigned long cmd)
+{
+ switch (cmd) {
+ case H_ENTER:
+ case H_REMOVE:
+ case H_PROTECT:
+ case H_BULK_REMOVE:
+ case H_PUT_TCE:
+ case H_CEDE:
+#ifdef CONFIG_KVM_XICS
+ case H_XIRR:
+ case H_CPPR:
+ case H_EOI:
+ case H_IPI:
+ case H_IPOLL:
+ case H_XIRR_X:
+#endif
+ return 1;
+ }
+ return 0;
+}
/*
* List of hcall numbers to enable by default.
@@ -336,7 +357,11 @@ static unsigned int default_hcall_list[] = {
void kvmppc_pr_init_default_hcalls(struct kvm *kvm)
{
int i;
+ unsigned int hcall;
- for (i = 0; default_hcall_list[i]; ++i)
- __set_bit(default_hcall_list[i] / 4, kvm->arch.enabled_hcalls);
+ for (i = 0; default_hcall_list[i]; ++i) {
+ hcall = default_hcall_list[i];
+ WARN_ON(!kvmppc_hcall_impl_pr(hcall));
+ __set_bit(hcall / 4, kvm->arch.enabled_hcalls);
+ }
}
@@ -1119,6 +1119,8 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
if (hcall > MAX_HCALL_OPCODE || (hcall & 3) ||
cap->args[1] > 1)
break;
+ if (!kvmppc_book3s_hcall_implemented(kvm, hcall))
+ break;
if (cap->args[1])
set_bit(hcall / 4, kvm->arch.enabled_hcalls);
else
This adds code to check that when the KVM_CAP_PPC_ENABLE_HCALL capability is used to enable or disable in-kernel handling of an hcall, that the hcall is actually implemented by the kernel. If not an EINVAL error is returned. This also checks the default-enabled list of hcalls and prints a warning if any hcall there is not actually implemented. Signed-off-by: Paul Mackerras <paulus@samba.org> --- Documentation/virtual/kvm/api.txt | 4 ++++ arch/powerpc/include/asm/kvm_book3s.h | 3 +++ arch/powerpc/include/asm/kvm_ppc.h | 2 +- arch/powerpc/kvm/book3s.c | 5 +++++ arch/powerpc/kvm/book3s_hv.c | 31 +++++++++++++++++++++++++++++-- arch/powerpc/kvm/book3s_hv_builtin.c | 13 +++++++++++++ arch/powerpc/kvm/book3s_hv_rmhandlers.S | 1 + arch/powerpc/kvm/book3s_pr.c | 3 +++ arch/powerpc/kvm/book3s_pr_papr.c | 29 +++++++++++++++++++++++++++-- arch/powerpc/kvm/powerpc.c | 2 ++ 10 files changed, 88 insertions(+), 5 deletions(-)