aboutsummaryrefslogtreecommitdiffstats
path: root/virt
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2013-04-12 10:08:42 -0400
committerAlexander Graf <agraf@suse.de>2013-04-26 14:27:20 -0400
commit852b6d57dc7fa378019786fa84727036e56839ea (patch)
tree4d617ba91f6fc5de3fddac349e695d914e626a49 /virt
parent7df35f549606e8a9004a77ef31dc80dfa893a590 (diff)
kvm: add device control API
Currently, devices that are emulated inside KVM are configured in a hardcoded manner based on an assumption that any given architecture only has one way to do it. If there's any need to access device state, it is done through inflexible one-purpose-only IOCTLs (e.g. KVM_GET/SET_LAPIC). Defining new IOCTLs for every little thing is cumbersome and depletes a limited numberspace. This API provides a mechanism to instantiate a device of a certain type, returning an ID that can be used to set/get attributes of the device. Attributes may include configuration parameters (e.g. register base address), device state, operational commands, etc. It is similar to the ONE_REG API, except that it acts on devices rather than vcpus. Both device types and individual attributes can be tested without having to create the device or get/set the attribute, without the need for separately managing enumerated capabilities. Signed-off-by: Scott Wood <scottwood@freescale.com> Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'virt')
-rw-r--r--virt/kvm/kvm_main.c129
1 files changed, 129 insertions, 0 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index f9492f3847d6..5f0d78c2537b 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -2159,6 +2159,117 @@ out:
2159} 2159}
2160#endif 2160#endif
2161 2161
2162static int kvm_device_ioctl_attr(struct kvm_device *dev,
2163 int (*accessor)(struct kvm_device *dev,
2164 struct kvm_device_attr *attr),
2165 unsigned long arg)
2166{
2167 struct kvm_device_attr attr;
2168
2169 if (!accessor)
2170 return -EPERM;
2171
2172 if (copy_from_user(&attr, (void __user *)arg, sizeof(attr)))
2173 return -EFAULT;
2174
2175 return accessor(dev, &attr);
2176}
2177
2178static long kvm_device_ioctl(struct file *filp, unsigned int ioctl,
2179 unsigned long arg)
2180{
2181 struct kvm_device *dev = filp->private_data;
2182
2183 switch (ioctl) {
2184 case KVM_SET_DEVICE_ATTR:
2185 return kvm_device_ioctl_attr(dev, dev->ops->set_attr, arg);
2186 case KVM_GET_DEVICE_ATTR:
2187 return kvm_device_ioctl_attr(dev, dev->ops->get_attr, arg);
2188 case KVM_HAS_DEVICE_ATTR:
2189 return kvm_device_ioctl_attr(dev, dev->ops->has_attr, arg);
2190 default:
2191 if (dev->ops->ioctl)
2192 return dev->ops->ioctl(dev, ioctl, arg);
2193
2194 return -ENOTTY;
2195 }
2196}
2197
2198void kvm_device_get(struct kvm_device *dev)
2199{
2200 atomic_inc(&dev->users);
2201}
2202
2203void kvm_device_put(struct kvm_device *dev)
2204{
2205 if (atomic_dec_and_test(&dev->users))
2206 dev->ops->destroy(dev);
2207}
2208
2209static int kvm_device_release(struct inode *inode, struct file *filp)
2210{
2211 struct kvm_device *dev = filp->private_data;
2212 struct kvm *kvm = dev->kvm;
2213
2214 kvm_device_put(dev);
2215 kvm_put_kvm(kvm);
2216 return 0;
2217}
2218
2219static const struct file_operations kvm_device_fops = {
2220 .unlocked_ioctl = kvm_device_ioctl,
2221 .release = kvm_device_release,
2222};
2223
2224struct kvm_device *kvm_device_from_filp(struct file *filp)
2225{
2226 if (filp->f_op != &kvm_device_fops)
2227 return NULL;
2228
2229 return filp->private_data;
2230}
2231
2232static int kvm_ioctl_create_device(struct kvm *kvm,
2233 struct kvm_create_device *cd)
2234{
2235 struct kvm_device_ops *ops = NULL;
2236 struct kvm_device *dev;
2237 bool test = cd->flags & KVM_CREATE_DEVICE_TEST;
2238 int ret;
2239
2240 switch (cd->type) {
2241 default:
2242 return -ENODEV;
2243 }
2244
2245 if (test)
2246 return 0;
2247
2248 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
2249 if (!dev)
2250 return -ENOMEM;
2251
2252 dev->ops = ops;
2253 dev->kvm = kvm;
2254 atomic_set(&dev->users, 1);
2255
2256 ret = ops->create(dev, cd->type);
2257 if (ret < 0) {
2258 kfree(dev);
2259 return ret;
2260 }
2261
2262 ret = anon_inode_getfd(ops->name, &kvm_device_fops, dev, O_RDWR);
2263 if (ret < 0) {
2264 ops->destroy(dev);
2265 return ret;
2266 }
2267
2268 kvm_get_kvm(kvm);
2269 cd->fd = ret;
2270 return 0;
2271}
2272
2162static long kvm_vm_ioctl(struct file *filp, 2273static long kvm_vm_ioctl(struct file *filp,
2163 unsigned int ioctl, unsigned long arg) 2274 unsigned int ioctl, unsigned long arg)
2164{ 2275{
@@ -2304,6 +2415,24 @@ static long kvm_vm_ioctl(struct file *filp,
2304 break; 2415 break;
2305 } 2416 }
2306#endif /* CONFIG_HAVE_KVM_IRQ_ROUTING */ 2417#endif /* CONFIG_HAVE_KVM_IRQ_ROUTING */
2418 case KVM_CREATE_DEVICE: {
2419 struct kvm_create_device cd;
2420
2421 r = -EFAULT;
2422 if (copy_from_user(&cd, argp, sizeof(cd)))
2423 goto out;
2424
2425 r = kvm_ioctl_create_device(kvm, &cd);
2426 if (r)
2427 goto out;
2428
2429 r = -EFAULT;
2430 if (copy_to_user(argp, &cd, sizeof(cd)))
2431 goto out;
2432
2433 r = 0;
2434 break;
2435 }
2307 default: 2436 default:
2308 r = kvm_arch_vm_ioctl(filp, ioctl, arg); 2437 r = kvm_arch_vm_ioctl(filp, ioctl, arg);
2309 if (r == -ENOTTY) 2438 if (r == -ENOTTY)