KVM: s390: add parameter for KVM_CREATE_VM
This patch introduces a new config option for user controlled kernel virtual machines. It introduces a parameter to KVM_CREATE_VM that allows to set bits that alter the capabilities of the newly created virtual machine. The parameter is passed to kvm_arch_init_vm for all architectures. The only valid modifier bit for now is KVM_VM_S390_UCONTROL. This requires CAP_SYS_ADMIN privileges and creates a user controlled virtual machine on s390 architectures. Signed-off-by: Carsten Otte <cotte@de.ibm.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com>
This commit is contained in:
parent
a138fe7535
commit
e08b963716
|
@ -95,7 +95,7 @@ described as 'basic' will be available.
|
||||||
Capability: basic
|
Capability: basic
|
||||||
Architectures: all
|
Architectures: all
|
||||||
Type: system ioctl
|
Type: system ioctl
|
||||||
Parameters: none
|
Parameters: machine type identifier (KVM_VM_*)
|
||||||
Returns: a VM fd that can be used to control the new virtual machine.
|
Returns: a VM fd that can be used to control the new virtual machine.
|
||||||
|
|
||||||
The new VM has no virtual cpus and no memory. An mmap() of a VM fd
|
The new VM has no virtual cpus and no memory. An mmap() of a VM fd
|
||||||
|
@ -103,6 +103,11 @@ will access the virtual machine's physical address space; offset zero
|
||||||
corresponds to guest physical address zero. Use of mmap() on a VM fd
|
corresponds to guest physical address zero. Use of mmap() on a VM fd
|
||||||
is discouraged if userspace memory allocation (KVM_CAP_USER_MEMORY) is
|
is discouraged if userspace memory allocation (KVM_CAP_USER_MEMORY) is
|
||||||
available.
|
available.
|
||||||
|
You most certainly want to use 0 as machine type.
|
||||||
|
|
||||||
|
In order to create user controlled virtual machines on S390, check
|
||||||
|
KVM_CAP_S390_UCONTROL and use the flag KVM_VM_S390_UCONTROL as
|
||||||
|
privileged user (CAP_SYS_ADMIN).
|
||||||
|
|
||||||
4.3 KVM_GET_MSR_INDEX_LIST
|
4.3 KVM_GET_MSR_INDEX_LIST
|
||||||
|
|
||||||
|
|
|
@ -809,10 +809,13 @@ static void kvm_build_io_pmt(struct kvm *kvm)
|
||||||
#define GUEST_PHYSICAL_RR4 0x2739
|
#define GUEST_PHYSICAL_RR4 0x2739
|
||||||
#define VMM_INIT_RR 0x1660
|
#define VMM_INIT_RR 0x1660
|
||||||
|
|
||||||
int kvm_arch_init_vm(struct kvm *kvm)
|
int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
|
||||||
{
|
{
|
||||||
BUG_ON(!kvm);
|
BUG_ON(!kvm);
|
||||||
|
|
||||||
|
if (type)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
kvm->arch.is_sn2 = ia64_platform_is("sn2");
|
kvm->arch.is_sn2 = ia64_platform_is("sn2");
|
||||||
|
|
||||||
kvm->arch.metaphysical_rr0 = GUEST_PHYSICAL_RR0;
|
kvm->arch.metaphysical_rr0 = GUEST_PHYSICAL_RR0;
|
||||||
|
|
|
@ -171,8 +171,11 @@ void kvm_arch_check_processor_compat(void *rtn)
|
||||||
*(int *)rtn = kvmppc_core_check_processor_compat();
|
*(int *)rtn = kvmppc_core_check_processor_compat();
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvm_arch_init_vm(struct kvm *kvm)
|
int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
|
||||||
{
|
{
|
||||||
|
if (type)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
return kvmppc_core_init_vm(kvm);
|
return kvmppc_core_init_vm(kvm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,15 @@ config KVM
|
||||||
|
|
||||||
If unsure, say N.
|
If unsure, say N.
|
||||||
|
|
||||||
|
config KVM_S390_UCONTROL
|
||||||
|
bool "Userspace controlled virtual machines"
|
||||||
|
depends on KVM
|
||||||
|
---help---
|
||||||
|
Allow CAP_SYS_ADMIN users to create KVM virtual machines that are
|
||||||
|
controlled by userspace.
|
||||||
|
|
||||||
|
If unsure, say N.
|
||||||
|
|
||||||
# OK, it's a little counter-intuitive to do this, but it puts it neatly under
|
# OK, it's a little counter-intuitive to do this, but it puts it neatly under
|
||||||
# the virtualization menu.
|
# the virtualization menu.
|
||||||
source drivers/vhost/Kconfig
|
source drivers/vhost/Kconfig
|
||||||
|
|
|
@ -171,11 +171,22 @@ long kvm_arch_vm_ioctl(struct file *filp,
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvm_arch_init_vm(struct kvm *kvm)
|
int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
char debug_name[16];
|
char debug_name[16];
|
||||||
|
|
||||||
|
rc = -EINVAL;
|
||||||
|
#ifdef CONFIG_KVM_S390_UCONTROL
|
||||||
|
if (type & ~KVM_VM_S390_UCONTROL)
|
||||||
|
goto out_err;
|
||||||
|
if ((type & KVM_VM_S390_UCONTROL) && (!capable(CAP_SYS_ADMIN)))
|
||||||
|
goto out_err;
|
||||||
|
#else
|
||||||
|
if (type)
|
||||||
|
goto out_err;
|
||||||
|
#endif
|
||||||
|
|
||||||
rc = s390_enable_sie();
|
rc = s390_enable_sie();
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out_err;
|
goto out_err;
|
||||||
|
@ -198,10 +209,13 @@ int kvm_arch_init_vm(struct kvm *kvm)
|
||||||
debug_register_view(kvm->arch.dbf, &debug_sprintf_view);
|
debug_register_view(kvm->arch.dbf, &debug_sprintf_view);
|
||||||
VM_EVENT(kvm, 3, "%s", "vm created");
|
VM_EVENT(kvm, 3, "%s", "vm created");
|
||||||
|
|
||||||
kvm->arch.gmap = gmap_alloc(current->mm);
|
if (type & KVM_VM_S390_UCONTROL) {
|
||||||
if (!kvm->arch.gmap)
|
kvm->arch.gmap = NULL;
|
||||||
goto out_nogmap;
|
} else {
|
||||||
|
kvm->arch.gmap = gmap_alloc(current->mm);
|
||||||
|
if (!kvm->arch.gmap)
|
||||||
|
goto out_nogmap;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
out_nogmap:
|
out_nogmap:
|
||||||
debug_unregister(kvm->arch.dbf);
|
debug_unregister(kvm->arch.dbf);
|
||||||
|
|
|
@ -47,6 +47,16 @@ static inline int __cpu_is_stopped(struct kvm_vcpu *vcpu)
|
||||||
return atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_STOP_INT;
|
return atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_STOP_INT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int kvm_is_ucontrol(struct kvm *kvm)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_KVM_S390_UCONTROL
|
||||||
|
if (kvm->arch.gmap)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
int kvm_s390_handle_wait(struct kvm_vcpu *vcpu);
|
int kvm_s390_handle_wait(struct kvm_vcpu *vcpu);
|
||||||
enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer);
|
enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer);
|
||||||
void kvm_s390_tasklet(unsigned long parm);
|
void kvm_s390_tasklet(unsigned long parm);
|
||||||
|
|
|
@ -6031,8 +6031,11 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
|
||||||
free_page((unsigned long)vcpu->arch.pio_data);
|
free_page((unsigned long)vcpu->arch.pio_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvm_arch_init_vm(struct kvm *kvm)
|
int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
|
||||||
{
|
{
|
||||||
|
if (type)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&kvm->arch.active_mmu_pages);
|
INIT_LIST_HEAD(&kvm->arch.active_mmu_pages);
|
||||||
INIT_LIST_HEAD(&kvm->arch.assigned_dev_head);
|
INIT_LIST_HEAD(&kvm->arch.assigned_dev_head);
|
||||||
|
|
||||||
|
|
|
@ -431,6 +431,9 @@ struct kvm_ppc_pvinfo {
|
||||||
|
|
||||||
#define KVMIO 0xAE
|
#define KVMIO 0xAE
|
||||||
|
|
||||||
|
/* machine type bits, to be used as argument to KVM_CREATE_VM */
|
||||||
|
#define KVM_VM_S390_UCONTROL 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ioctls for /dev/kvm fds:
|
* ioctls for /dev/kvm fds:
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -520,7 +520,7 @@ static inline void kvm_arch_free_vm(struct kvm *kvm)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int kvm_arch_init_vm(struct kvm *kvm);
|
int kvm_arch_init_vm(struct kvm *kvm, unsigned long type);
|
||||||
void kvm_arch_destroy_vm(struct kvm *kvm);
|
void kvm_arch_destroy_vm(struct kvm *kvm);
|
||||||
void kvm_free_all_assigned_devices(struct kvm *kvm);
|
void kvm_free_all_assigned_devices(struct kvm *kvm);
|
||||||
void kvm_arch_sync_events(struct kvm *kvm);
|
void kvm_arch_sync_events(struct kvm *kvm);
|
||||||
|
|
|
@ -449,7 +449,7 @@ static void kvm_init_memslots_id(struct kvm *kvm)
|
||||||
slots->id_to_index[i] = slots->memslots[i].id = i;
|
slots->id_to_index[i] = slots->memslots[i].id = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct kvm *kvm_create_vm(void)
|
static struct kvm *kvm_create_vm(unsigned long type)
|
||||||
{
|
{
|
||||||
int r, i;
|
int r, i;
|
||||||
struct kvm *kvm = kvm_arch_alloc_vm();
|
struct kvm *kvm = kvm_arch_alloc_vm();
|
||||||
|
@ -457,7 +457,7 @@ static struct kvm *kvm_create_vm(void)
|
||||||
if (!kvm)
|
if (!kvm)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
r = kvm_arch_init_vm(kvm);
|
r = kvm_arch_init_vm(kvm, type);
|
||||||
if (r)
|
if (r)
|
||||||
goto out_err_nodisable;
|
goto out_err_nodisable;
|
||||||
|
|
||||||
|
@ -2198,12 +2198,12 @@ static struct file_operations kvm_vm_fops = {
|
||||||
.llseek = noop_llseek,
|
.llseek = noop_llseek,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int kvm_dev_ioctl_create_vm(void)
|
static int kvm_dev_ioctl_create_vm(unsigned long type)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
struct kvm *kvm;
|
struct kvm *kvm;
|
||||||
|
|
||||||
kvm = kvm_create_vm();
|
kvm = kvm_create_vm(type);
|
||||||
if (IS_ERR(kvm))
|
if (IS_ERR(kvm))
|
||||||
return PTR_ERR(kvm);
|
return PTR_ERR(kvm);
|
||||||
#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
|
#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
|
||||||
|
@ -2254,10 +2254,7 @@ static long kvm_dev_ioctl(struct file *filp,
|
||||||
r = KVM_API_VERSION;
|
r = KVM_API_VERSION;
|
||||||
break;
|
break;
|
||||||
case KVM_CREATE_VM:
|
case KVM_CREATE_VM:
|
||||||
r = -EINVAL;
|
r = kvm_dev_ioctl_create_vm(arg);
|
||||||
if (arg)
|
|
||||||
goto out;
|
|
||||||
r = kvm_dev_ioctl_create_vm();
|
|
||||||
break;
|
break;
|
||||||
case KVM_CHECK_EXTENSION:
|
case KVM_CHECK_EXTENSION:
|
||||||
r = kvm_dev_ioctl_check_extension_generic(arg);
|
r = kvm_dev_ioctl_check_extension_generic(arg);
|
||||||
|
|
Loading…
Reference in New Issue