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:
Carsten Otte 2012-01-04 10:25:20 +01:00 committed by Avi Kivity
parent a138fe7535
commit e08b963716
10 changed files with 65 additions and 18 deletions

View File

@ -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

View File

@ -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;

View File

@ -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);
} }

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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:
*/ */

View File

@ -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);

View File

@ -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);