Commit ae2113a4 authored by Paul Mackerras's avatar Paul Mackerras Committed by Alexander Graf

KVM: PPC: Book3S: Allow only implemented hcalls to be enabled or disabled

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: default avatarPaul Mackerras <paulus@samba.org>
Signed-off-by: default avatarAlexander Graf <agraf@suse.de>
parent 699a0ea0
...@@ -3039,3 +3039,7 @@ not to attempt to handle the hcall, but will always exit to userspace ...@@ -3039,3 +3039,7 @@ 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 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 disable others of a group of related hcalls, but KVM does not prevent
userspace from doing that. 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.
...@@ -146,6 +146,7 @@ extern void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache * ...@@ -146,6 +146,7 @@ extern void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *
extern int kvmppc_mmu_hpte_sysinit(void); extern int kvmppc_mmu_hpte_sysinit(void);
extern void kvmppc_mmu_hpte_sysexit(void); extern void kvmppc_mmu_hpte_sysexit(void);
extern int kvmppc_mmu_hv_init(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_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); extern int kvmppc_st(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, bool data);
...@@ -188,6 +189,8 @@ extern u32 kvmppc_alignment_dsisr(struct kvm_vcpu *vcpu, unsigned int inst); ...@@ -188,6 +189,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 ulong kvmppc_alignment_dar(struct kvm_vcpu *vcpu, unsigned int inst);
extern int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd); 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_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, extern void kvmppc_copy_to_svcpu(struct kvmppc_book3s_shadow_vcpu *svcpu,
struct kvm_vcpu *vcpu); struct kvm_vcpu *vcpu);
extern void kvmppc_copy_from_svcpu(struct kvm_vcpu *vcpu, extern void kvmppc_copy_from_svcpu(struct kvm_vcpu *vcpu,
......
...@@ -228,7 +228,7 @@ struct kvmppc_ops { ...@@ -228,7 +228,7 @@ struct kvmppc_ops {
void (*fast_vcpu_kick)(struct kvm_vcpu *vcpu); void (*fast_vcpu_kick)(struct kvm_vcpu *vcpu);
long (*arch_vm_ioctl)(struct file *filp, unsigned int ioctl, long (*arch_vm_ioctl)(struct file *filp, unsigned int ioctl,
unsigned long arg); unsigned long arg);
int (*hcall_implemented)(unsigned long hcall);
}; };
extern struct kvmppc_ops *kvmppc_hv_ops; extern struct kvmppc_ops *kvmppc_hv_ops;
......
...@@ -925,6 +925,11 @@ int kvmppc_core_check_processor_compat(void) ...@@ -925,6 +925,11 @@ int kvmppc_core_check_processor_compat(void)
return 0; 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) static int kvmppc_book3s_init(void)
{ {
int r; int r;
......
...@@ -645,6 +645,28 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) ...@@ -645,6 +645,28 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
return RESUME_GUEST; 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, static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu,
struct task_struct *tsk) struct task_struct *tsk)
{ {
...@@ -2451,9 +2473,13 @@ static unsigned int default_hcall_list[] = { ...@@ -2451,9 +2473,13 @@ static unsigned int default_hcall_list[] = {
static void init_default_hcalls(void) static void init_default_hcalls(void)
{ {
int i; int i;
unsigned int hcall;
for (i = 0; default_hcall_list[i]; ++i) for (i = 0; default_hcall_list[i]; ++i) {
__set_bit(default_hcall_list[i] / 4, default_enabled_hcalls); 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 = { static struct kvmppc_ops kvm_ops_hv = {
...@@ -2488,6 +2514,7 @@ static struct kvmppc_ops kvm_ops_hv = { ...@@ -2488,6 +2514,7 @@ static struct kvmppc_ops kvm_ops_hv = {
.emulate_mfspr = kvmppc_core_emulate_mfspr_hv, .emulate_mfspr = kvmppc_core_emulate_mfspr_hv,
.fast_vcpu_kick = kvmppc_fast_vcpu_kick_hv, .fast_vcpu_kick = kvmppc_fast_vcpu_kick_hv,
.arch_vm_ioctl = kvm_arch_vm_ioctl_hv, .arch_vm_ioctl = kvm_arch_vm_ioctl_hv,
.hcall_implemented = kvmppc_hcall_impl_hv,
}; };
static int kvmppc_book3s_init_hv(void) static int kvmppc_book3s_init_hv(void)
......
...@@ -212,3 +212,16 @@ bool kvm_hv_mode_active(void) ...@@ -212,3 +212,16 @@ bool kvm_hv_mode_active(void)
{ {
return atomic_read(&hv_vm_count) != 0; return atomic_read(&hv_vm_count) != 0;
} }
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);
...@@ -2042,6 +2042,7 @@ hcall_real_table: ...@@ -2042,6 +2042,7 @@ hcall_real_table:
.long 0 /* 0x12c */ .long 0 /* 0x12c */
.long 0 /* 0x130 */ .long 0 /* 0x130 */
.long DOTSYM(kvmppc_h_set_xdabr) - hcall_real_table .long DOTSYM(kvmppc_h_set_xdabr) - hcall_real_table
.globl hcall_real_table_end
hcall_real_table_end: hcall_real_table_end:
ignore_hdec: ignore_hdec:
......
...@@ -1670,6 +1670,9 @@ static struct kvmppc_ops kvm_ops_pr = { ...@@ -1670,6 +1670,9 @@ static struct kvmppc_ops kvm_ops_pr = {
.emulate_mfspr = kvmppc_core_emulate_mfspr_pr, .emulate_mfspr = kvmppc_core_emulate_mfspr_pr,
.fast_vcpu_kick = kvm_vcpu_kick, .fast_vcpu_kick = kvm_vcpu_kick,
.arch_vm_ioctl = kvm_arch_vm_ioctl_pr, .arch_vm_ioctl = kvm_arch_vm_ioctl_pr,
#ifdef CONFIG_PPC_BOOK3S_64
.hcall_implemented = kvmppc_hcall_impl_pr,
#endif
}; };
......
...@@ -309,6 +309,27 @@ int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd) ...@@ -309,6 +309,27 @@ int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd)
return EMULATE_FAIL; 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. * List of hcall numbers to enable by default.
...@@ -337,7 +358,11 @@ static unsigned int default_hcall_list[] = { ...@@ -337,7 +358,11 @@ static unsigned int default_hcall_list[] = {
void kvmppc_pr_init_default_hcalls(struct kvm *kvm) void kvmppc_pr_init_default_hcalls(struct kvm *kvm)
{ {
int i; int i;
unsigned int hcall;
for (i = 0; default_hcall_list[i]; ++i) for (i = 0; default_hcall_list[i]; ++i) {
__set_bit(default_hcall_list[i] / 4, kvm->arch.enabled_hcalls); 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, ...@@ -1119,6 +1119,8 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
if (hcall > MAX_HCALL_OPCODE || (hcall & 3) || if (hcall > MAX_HCALL_OPCODE || (hcall & 3) ||
cap->args[1] > 1) cap->args[1] > 1)
break; break;
if (!kvmppc_book3s_hcall_implemented(kvm, hcall))
break;
if (cap->args[1]) if (cap->args[1])
set_bit(hcall / 4, kvm->arch.enabled_hcalls); set_bit(hcall / 4, kvm->arch.enabled_hcalls);
else else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment