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: Paul Mackerras <paulus@samba.org> Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
Родитель
699a0ea082
Коммит
ae2113a4f1
|
@ -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
|
||||
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.
|
||||
|
|
|
@ -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 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);
|
||||
|
@ -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 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;
|
||||
|
|
|
@ -925,6 +925,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)
|
||||
{
|
||||
|
@ -2451,9 +2473,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 = {
|
||||
|
@ -2488,6 +2514,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)
|
||||
|
|
|
@ -212,3 +212,16 @@ bool kvm_hv_mode_active(void)
|
|||
{
|
||||
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:
|
|||
.long 0 /* 0x12c */
|
||||
.long 0 /* 0x130 */
|
||||
.long DOTSYM(kvmppc_h_set_xdabr) - hcall_real_table
|
||||
.globl hcall_real_table_end
|
||||
hcall_real_table_end:
|
||||
|
||||
ignore_hdec:
|
||||
|
|
|
@ -1670,6 +1670,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
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -309,6 +309,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.
|
||||
|
@ -337,7 +358,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
|
||||
|
|
Загрузка…
Ссылка в новой задаче