public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
From: Anthony Liguori <anthony-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
To: Dor Laor <dor.laor-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
Cc: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
Subject: Re: [PATCH 4/4] [Hypercall] Allow modules	registeration for hypercalls.
Date: Mon, 27 Aug 2007 17:22:44 -0500	[thread overview]
Message-ID: <1188253364.22727.13.camel@squirrel> (raw)
In-Reply-To: <64F9B87B6B770947A9F8391472E032160D59004F-yEcIvxbTEBqsx+V+t5oei8rau4O3wl8o3fe8/T/H7NteoWH0uzbU5w@public.gmane.org>

I don't really like the idea of having other modules register
hypercalls.  The hypercall address space is fixed and should be
maintained by KVM.

I think things like virtio are rare and important enough, that it
warrants having kvm.ko know enough about them to provide a higher level
registration mechanism.  The virtio network driver should register the
fact that it's a virtio device, not which hypercalls it cares about.

I'm not sure you gain anything by doing the virtio infrastructure in a
module either.  If anything, a config option in kvm.ko would suffice.

Regards,

Anthony Liguori


On Fri, 2007-08-24 at 16:59 -0700, Dor Laor wrote:
> New kernel modules for KVM are upcoming soon, these module
> will need to use hypercalls. Before calling the hypercall function,
> the kvm_main core module has to make sure it won't get unloaded.
> So hypercall register/unregister are added.
> 
> Except that the kernel hypercalls handlers are numberes
> 0-KVM_NR_HYPERCALLS.
> All the userspace handlers are above KVM_NR_HYPERCALLS.
> 
> Signed-off-by: Dor Laor <dor.laor-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
> ---
>  drivers/kvm/kvm.h        |    9 ++
>  drivers/kvm/kvm_main.c   |  223
> ++++++++++++++++++++++++++++++++++++++--------
>  include/linux/kvm_para.h |    4 +-
>  3 files changed, 197 insertions(+), 39 deletions(-)
>  mode change 100644 => 100755 drivers/kvm/kvm_main.c
> 
> diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
> index a42a6f3..37240cf 100644
> --- a/drivers/kvm/kvm.h
> +++ b/drivers/kvm/kvm.h
> @@ -472,6 +472,12 @@ struct kvm_arch_ops {
>  				unsigned char *hypercall_addr);
>  };
>  
> +struct kvm_hypercall {
> +	unsigned long (*hypercall)(struct kvm_vcpu*, unsigned long
> args[]);
> +	struct module *module;
> +	int idx;
> +};
> +
>  extern struct kvm_arch_ops *kvm_arch_ops;
>  
>  /* The guest did something we don't support. */
> @@ -588,6 +594,9 @@ int kvm_mmu_load(struct kvm_vcpu *vcpu);
>  void kvm_mmu_unload(struct kvm_vcpu *vcpu);
>  
>  int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run);
> +int kvm_register_hypercall(struct module *module, struct kvm_hypercall
> *hypercall);
> +int kvm_unregister_hypercall(struct kvm_hypercall *hypercall);
> +
>  
>  static inline int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
>  				     u32 error_code)
> diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
> old mode 100644
> new mode 100755
> index abd7498..051b47a
> --- a/drivers/kvm/kvm_main.c
> +++ b/drivers/kvm/kvm_main.c
> @@ -20,6 +20,7 @@
>  #include "segment_descriptor.h"
>  
>  #include <linux/kvm.h>
> +#include <linux/kvm_para.h>
>  #include <linux/module.h>
>  #include <linux/errno.h>
>  #include <linux/percpu.h>
> @@ -84,6 +85,23 @@ static struct kvm_stats_debugfs_item {
>  
>  static struct dentry *debugfs_dir;
>  
> +static struct kvm_hypercall hypercalls[KVM_KERNEL_NR_HYPERCALLS];
> +
> +static int test_hypercall(struct kvm_vcpu *vcpu, unsigned long args[])
> +{
> +	printk(KERN_DEBUG "%s: hypercall invoked\n", __FUNCTION__);
> +
> +	return 0;
> +}
> +
> +static struct kvm_hypercall __hypercall_test = {
> +	(unsigned long (*)(struct kvm_vcpu*, unsigned long
> args[]))test_hypercall,
> +	THIS_MODULE,
> +	__NR_hypercall_test,
> +};
> +
> +static atomic_t dev_kvm_open_count = ATOMIC_INIT(0);
> +
>  #define MAX_IO_MSRS 256
>  
>  #define CR0_RESERVED_BITS
> \
> @@ -302,6 +320,24 @@ static struct kvm *kvm_create_vm(void)
>  	return kvm;
>  }
>  
> +static int kvm_dev_open(struct inode *inode, struct file *filp)
> +{
> +	int ret = 0;
> +
> +	if (atomic_inc_return(&dev_kvm_open_count) == 1) {
> +		ret = kvm_register_hypercall(THIS_MODULE,
> &__hypercall_test);
> +		if (ret < 0) {
> +			printk(KERN_DEBUG "%s: kvm_register_hypercall
> error, "
> +			       "hypercall: %s\n",
> +			       __FUNCTION__, "test");
> +			goto out_test;
> +		}
> +	}
> +
> +out_test:
> +	return ret;
> +}
> +
>  /*
>   * Free any memory in @free but not in @dont.
>   */
> @@ -371,6 +407,20 @@ static void kvm_free_vcpus(struct kvm *kvm)
>  
>  }
>  
> +static int kvm_dev_release(struct inode *inode, struct file *filp)
> +{
> +	int ret = 0;
> +
> +	atomic_dec(&dev_kvm_open_count);
> +	ret = kvm_unregister_hypercall(&__hypercall_test);
> +	if (ret < 0) {
> +		printk(KERN_DEBUG "%s:kvm_unregister_hypercall error "
> +		       "hypercall: %s\n", __FUNCTION__,
> "hypercall_test");
> +	}
> +
> +	return ret;
> +}
> +
>  static void kvm_destroy_vm(struct kvm *kvm)
>  {
>  	spin_lock(&kvm_lock);
> @@ -1267,50 +1317,145 @@ int kvm_emulate_halt(struct kvm_vcpu *vcpu)
>  }
>  EXPORT_SYMBOL_GPL(kvm_emulate_halt);
>  
> -int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
> +int kvm_register_hypercall(struct module* module, struct kvm_hypercall
> *hypercall)
>  {
> -	unsigned long nr, a0, a1, a2, a3, a4, a5, ret;
> +	int r = 0;
>  
> -	kvm_arch_ops->cache_regs(vcpu);
> -	ret = -KVM_EINVAL;
> -#ifdef CONFIG_X86_64
> -	if (is_long_mode(vcpu)) {
> -		nr = vcpu->regs[VCPU_REGS_RAX];
> -		a0 = vcpu->regs[VCPU_REGS_RDI];
> -		a1 = vcpu->regs[VCPU_REGS_RSI];
> -		a2 = vcpu->regs[VCPU_REGS_RDX];
> -		a3 = vcpu->regs[VCPU_REGS_RCX];
> -		a4 = vcpu->regs[VCPU_REGS_R8];
> -		a5 = vcpu->regs[VCPU_REGS_R9];
> -	} else
> -#endif
> -	{
> +	if (hypercall->idx >= KVM_KERNEL_NR_HYPERCALLS ||
> +	    hypercall->idx < 0) {
> +		printk(KERN_DEBUG "%s:hypercall registration idx(%d)\n",
> +			 __FUNCTION__, hypercall->idx);
> +		return -EINVAL;
> +	}
> +
> +	spin_lock(&kvm_lock);
> +
> +	if (hypercalls[hypercall->idx].hypercall) {
> +		printk(KERN_DEBUG "%s:hypercall idx(%d) already
> taken\n",
> +			__FUNCTION__, hypercall->idx);
> +		r = -EEXIST;
> +		goto out;
> +	}
> +
> +	if (try_module_get(module) < 0) {
> +		printk(KERN_DEBUG "%s: module reference count++
> failed\n",
> +			__FUNCTION__);
> +		r = -EINVAL;
> +		goto out;
> +	}
> +
> +	hypercalls[hypercall->idx].hypercall = hypercall->hypercall;
> +	hypercalls[hypercall->idx].module = module;
> +
> +out:
> +	spin_unlock(&kvm_lock);
> +
> +	return r;
> +}
> +EXPORT_SYMBOL_GPL(kvm_register_hypercall);
> +
> +int kvm_unregister_hypercall(struct kvm_hypercall *hypercall)
> +{
> +	if (hypercall->idx >= KVM_KERNEL_NR_HYPERCALLS ||
> +	    hypercall->idx < 0) {
> +		printk(KERN_DEBUG "%s:hypercall unregistration
> idx(%d)\n",
> +			 __FUNCTION__, hypercall->idx);
> +		return -EINVAL;
> +	}
> +
> +	spin_lock(&kvm_lock);
> +	if (!hypercalls[hypercall->idx].hypercall) {
> +		printk(KERN_DEBUG "%s:hypercall idx(%d) was not
> registered\n",
> +			__FUNCTION__, hypercall->idx);
> +		spin_unlock(&kvm_lock);
> +		return -EEXIST;
> +	}
> +
> +	hypercalls[hypercall->idx].hypercall = 0;
> +	module_put(hypercalls[hypercall->idx].module);
> +	spin_unlock(&kvm_lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(kvm_unregister_hypercall);
> +
> +/*
> + * Generic hypercall dispatcher routine.
> + * Returns 0 for user space handling, 1 on success handling
> + */
> + int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
> + {
> +	unsigned long nr, ret;
> +	unsigned long args[6];
> + 
> + 	kvm_arch_ops->cache_regs(vcpu);
> + 	ret = -KVM_EINVAL;
> + #ifdef CONFIG_X86_64
> + 	if (is_long_mode(vcpu)) {
> + 		nr = vcpu->regs[VCPU_REGS_RAX];
> +		args[0] = vcpu->regs[VCPU_REGS_RDI];
> +		args[1] = vcpu->regs[VCPU_REGS_RSI];
> +		args[2] = vcpu->regs[VCPU_REGS_RDX];
> +		args[3] = vcpu->regs[VCPU_REGS_RCX];
> +		args[4] = vcpu->regs[VCPU_REGS_R8];
> +		args[5] = vcpu->regs[VCPU_REGS_R9];
> + 	} else
> + #endif
> + 	{
>  		nr = vcpu->regs[VCPU_REGS_RBX] & -1u;
> -		a0 = vcpu->regs[VCPU_REGS_RAX] & -1u;
> -		a1 = vcpu->regs[VCPU_REGS_RCX] & -1u;
> -		a2 = vcpu->regs[VCPU_REGS_RDX] & -1u;
> -		a3 = vcpu->regs[VCPU_REGS_RSI] & -1u;
> -		a4 = vcpu->regs[VCPU_REGS_RDI] & -1u;
> -		a5 = vcpu->regs[VCPU_REGS_RBP] & -1u;
> -	}
> -	switch (nr) {
> -	default:
> -		run->hypercall.nr = nr;
> -		run->hypercall.args[0] = a0;
> -		run->hypercall.args[1] = a1;
> -		run->hypercall.args[2] = a2;
> -		run->hypercall.args[3] = a3;
> -		run->hypercall.args[4] = a4;
> -		run->hypercall.args[5] = a5;
> -		run->hypercall.ret = ret;
> -		run->hypercall.longmode = is_long_mode(vcpu);
> -		kvm_arch_ops->decache_regs(vcpu);
> +		args[0] = vcpu->regs[VCPU_REGS_RAX] & -1u;
> +		args[1] = vcpu->regs[VCPU_REGS_RCX] & -1u;
> +		args[2] = vcpu->regs[VCPU_REGS_RDX] & -1u;
> +		args[3] = vcpu->regs[VCPU_REGS_RSI] & -1u;
> +		args[4] = vcpu->regs[VCPU_REGS_RDI] & -1u;
> +		args[5] = vcpu->regs[VCPU_REGS_RBP] & -1u;
> +	}
> +
> +	if (nr >= KVM_KERNEL_NR_HYPERCALLS || nr < 0) {
> + 		run->hypercall.nr = nr;
> +		memcpy(run->hypercall.args, args, sizeof(args));
> +		run->hypercall.ret = 0;
> + 		run->hypercall.longmode = is_long_mode(vcpu);
> + 		kvm_arch_ops->decache_regs(vcpu);
>  		run->exit_reason = KVM_EXIT_HYPERCALL;
>  
> -		return 0;
> + 		return 0;
> + 	}
> +
> +	/* The hypercall might block or do intensive work */
> +	vcpu_put(vcpu);
> +
> +	/*
> +	 * Increase the hypercall's module ref count assures
> +	 * that no one will remove the module while a hypercall
> +	 * is executing.
> +	 * Theoretically we need to lock to get coherent
> module-hypercall
> +	 * view but practically there's almost no users this mechanism
> now.
> +	 */
> +	if (try_module_get(hypercalls[nr].module) < 0) {
> +		printk(KERN_DEBUG "%s: module reference count++
> failed\n",
> +			__FUNCTION__);
> +		ret = -EINVAL;
> +		goto out;
>  	}
> -	vcpu->regs[VCPU_REGS_RAX] = ret;
> -	kvm_arch_ops->decache_regs(vcpu);
> +
> +	if (!hypercalls[nr].hypercall) {
> +		printk(KERN_ERR "%s: hypercall nr(%lx) was not yet
> registered\n",
> +		       __FUNCTION__, nr);
> +		ret = -EINVAL;
> +		goto out_put;
> +	}
> +
> +	ret = hypercalls[nr].hypercall(vcpu, args);
> +
> +out_put:
> +	module_put(hypercalls[nr].module);
> +out:
> +	vcpu_load(vcpu);
> +
> + 	vcpu->regs[VCPU_REGS_RAX] = ret;
> + 	kvm_arch_ops->decache_regs(vcpu);
> +
>  	return 1;
>  }
>  EXPORT_SYMBOL_GPL(kvm_hypercall);
> @@ -2847,6 +2992,8 @@ out:
>  }
>  
>  static struct file_operations kvm_chardev_ops = {
> +	.open           = kvm_dev_open,
> +	.release        = kvm_dev_release,
>  	.unlocked_ioctl = kvm_dev_ioctl,
>  	.compat_ioctl   = kvm_dev_ioctl,
>  };
> diff --git a/include/linux/kvm_para.h b/include/linux/kvm_para.h
> index 754e29d..0cf516a 100644
> --- a/include/linux/kvm_para.h
> +++ b/include/linux/kvm_para.h
> @@ -71,6 +71,8 @@ struct kvm_vcpu_para_state {
>   * No registers are clobbered by the hypercall, except that the
>   * return value is in RAX.
>   */
> -#define __NR_hypercalls			0
> +
> +#define KVM_KERNEL_NR_HYPERCALLS		1
> +#define __NR_hypercall_test			0
>  
>  #endif
> 
> 
> -----
> In simplicity there is elegance.
> Dor Laor ;)
> 
> 
> -------------------------------------------------------------------------
> This SF.net email is sponsored by: Splunk Inc.
> Still grepping through log files to find problems?  Stop.
> Now Search log events and configuration files using AJAX and a browser.
> Download your FREE copy of Splunk now >>  http://get.splunk.com/
> _______________________________________________
> kvm-devel mailing list
> kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
> https://lists.sourceforge.net/lists/listinfo/kvm-devel


-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

      parent reply	other threads:[~2007-08-27 22:22 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-08-24 23:59 [PATCH 4/4] [Hypercall] Allow modules registeration for hypercalls Dor Laor
     [not found] ` <64F9B87B6B770947A9F8391472E032160D59004F-yEcIvxbTEBqsx+V+t5oei8rau4O3wl8o3fe8/T/H7NteoWH0uzbU5w@public.gmane.org>
2007-08-25  8:29   ` Avi Kivity
     [not found]     ` <46CFE857.8050207-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2007-08-25  9:53       ` Dor Laor
2007-08-27 22:22   ` Anthony Liguori [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1188253364.22727.13.camel@squirrel \
    --to=anthony-rdkfgonbjusknkdkm+me6a@public.gmane.org \
    --cc=dor.laor-atKUWr5tajBWk0Htik3J/w@public.gmane.org \
    --cc=kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox