diff options
author | Carsten Otte <cotte@de.ibm.com> | 2007-10-29 11:08:35 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-01-30 10:52:57 -0500 |
commit | 1fe779f8eccd16e527315e1bafd2b3a876ff2489 (patch) | |
tree | 1af54558db85a9dcb8c9a78861849c2798d86cf5 /drivers/kvm/x86.c | |
parent | b733bfb524af69612f85c36a511f0109c5e3fe8d (diff) |
KVM: Portability: Split kvm_vm_ioctl v3
This patch splits kvm_vm_ioctl into archtecture independent parts, and
x86 specific parts which go to kvm_arch_vcpu_ioctl in x86.c.
The patch is unchanged since last submission.
Common ioctls for all architectures are:
KVM_CREATE_VCPU, KVM_GET_DIRTY_LOG, KVM_SET_USER_MEMORY_REGION
x86 specific ioctls are:
KVM_SET_MEMORY_REGION,
KVM_GET/SET_NR_MMU_PAGES, KVM_SET_MEMORY_ALIAS, KVM_CREATE_IRQCHIP,
KVM_CREATE_IRQ_LINE, KVM_GET/SET_IRQCHIP
KVM_SET_TSS_ADDR
Signed-off-by: Carsten Otte <cotte@de.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>
Acked-by: Hollis Blanchard <hollisb@us.ibm.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/x86.c')
-rw-r--r-- | drivers/kvm/x86.c | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/drivers/kvm/x86.c b/drivers/kvm/x86.c index 1fe209dd4caf..b84cb6707f78 100644 --- a/drivers/kvm/x86.c +++ b/drivers/kvm/x86.c | |||
@@ -300,6 +300,264 @@ out: | |||
300 | return r; | 300 | return r; |
301 | } | 301 | } |
302 | 302 | ||
303 | static int kvm_vm_ioctl_set_tss_addr(struct kvm *kvm, unsigned long addr) | ||
304 | { | ||
305 | int ret; | ||
306 | |||
307 | if (addr > (unsigned int)(-3 * PAGE_SIZE)) | ||
308 | return -1; | ||
309 | ret = kvm_x86_ops->set_tss_addr(kvm, addr); | ||
310 | return ret; | ||
311 | } | ||
312 | |||
313 | static int kvm_vm_ioctl_set_nr_mmu_pages(struct kvm *kvm, | ||
314 | u32 kvm_nr_mmu_pages) | ||
315 | { | ||
316 | if (kvm_nr_mmu_pages < KVM_MIN_ALLOC_MMU_PAGES) | ||
317 | return -EINVAL; | ||
318 | |||
319 | mutex_lock(&kvm->lock); | ||
320 | |||
321 | kvm_mmu_change_mmu_pages(kvm, kvm_nr_mmu_pages); | ||
322 | kvm->n_requested_mmu_pages = kvm_nr_mmu_pages; | ||
323 | |||
324 | mutex_unlock(&kvm->lock); | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static int kvm_vm_ioctl_get_nr_mmu_pages(struct kvm *kvm) | ||
329 | { | ||
330 | return kvm->n_alloc_mmu_pages; | ||
331 | } | ||
332 | |||
333 | /* | ||
334 | * Set a new alias region. Aliases map a portion of physical memory into | ||
335 | * another portion. This is useful for memory windows, for example the PC | ||
336 | * VGA region. | ||
337 | */ | ||
338 | static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm, | ||
339 | struct kvm_memory_alias *alias) | ||
340 | { | ||
341 | int r, n; | ||
342 | struct kvm_mem_alias *p; | ||
343 | |||
344 | r = -EINVAL; | ||
345 | /* General sanity checks */ | ||
346 | if (alias->memory_size & (PAGE_SIZE - 1)) | ||
347 | goto out; | ||
348 | if (alias->guest_phys_addr & (PAGE_SIZE - 1)) | ||
349 | goto out; | ||
350 | if (alias->slot >= KVM_ALIAS_SLOTS) | ||
351 | goto out; | ||
352 | if (alias->guest_phys_addr + alias->memory_size | ||
353 | < alias->guest_phys_addr) | ||
354 | goto out; | ||
355 | if (alias->target_phys_addr + alias->memory_size | ||
356 | < alias->target_phys_addr) | ||
357 | goto out; | ||
358 | |||
359 | mutex_lock(&kvm->lock); | ||
360 | |||
361 | p = &kvm->aliases[alias->slot]; | ||
362 | p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT; | ||
363 | p->npages = alias->memory_size >> PAGE_SHIFT; | ||
364 | p->target_gfn = alias->target_phys_addr >> PAGE_SHIFT; | ||
365 | |||
366 | for (n = KVM_ALIAS_SLOTS; n > 0; --n) | ||
367 | if (kvm->aliases[n - 1].npages) | ||
368 | break; | ||
369 | kvm->naliases = n; | ||
370 | |||
371 | kvm_mmu_zap_all(kvm); | ||
372 | |||
373 | mutex_unlock(&kvm->lock); | ||
374 | |||
375 | return 0; | ||
376 | |||
377 | out: | ||
378 | return r; | ||
379 | } | ||
380 | |||
381 | static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip) | ||
382 | { | ||
383 | int r; | ||
384 | |||
385 | r = 0; | ||
386 | switch (chip->chip_id) { | ||
387 | case KVM_IRQCHIP_PIC_MASTER: | ||
388 | memcpy(&chip->chip.pic, | ||
389 | &pic_irqchip(kvm)->pics[0], | ||
390 | sizeof(struct kvm_pic_state)); | ||
391 | break; | ||
392 | case KVM_IRQCHIP_PIC_SLAVE: | ||
393 | memcpy(&chip->chip.pic, | ||
394 | &pic_irqchip(kvm)->pics[1], | ||
395 | sizeof(struct kvm_pic_state)); | ||
396 | break; | ||
397 | case KVM_IRQCHIP_IOAPIC: | ||
398 | memcpy(&chip->chip.ioapic, | ||
399 | ioapic_irqchip(kvm), | ||
400 | sizeof(struct kvm_ioapic_state)); | ||
401 | break; | ||
402 | default: | ||
403 | r = -EINVAL; | ||
404 | break; | ||
405 | } | ||
406 | return r; | ||
407 | } | ||
408 | |||
409 | static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip) | ||
410 | { | ||
411 | int r; | ||
412 | |||
413 | r = 0; | ||
414 | switch (chip->chip_id) { | ||
415 | case KVM_IRQCHIP_PIC_MASTER: | ||
416 | memcpy(&pic_irqchip(kvm)->pics[0], | ||
417 | &chip->chip.pic, | ||
418 | sizeof(struct kvm_pic_state)); | ||
419 | break; | ||
420 | case KVM_IRQCHIP_PIC_SLAVE: | ||
421 | memcpy(&pic_irqchip(kvm)->pics[1], | ||
422 | &chip->chip.pic, | ||
423 | sizeof(struct kvm_pic_state)); | ||
424 | break; | ||
425 | case KVM_IRQCHIP_IOAPIC: | ||
426 | memcpy(ioapic_irqchip(kvm), | ||
427 | &chip->chip.ioapic, | ||
428 | sizeof(struct kvm_ioapic_state)); | ||
429 | break; | ||
430 | default: | ||
431 | r = -EINVAL; | ||
432 | break; | ||
433 | } | ||
434 | kvm_pic_update_irq(pic_irqchip(kvm)); | ||
435 | return r; | ||
436 | } | ||
437 | |||
438 | long kvm_arch_vm_ioctl(struct file *filp, | ||
439 | unsigned int ioctl, unsigned long arg) | ||
440 | { | ||
441 | struct kvm *kvm = filp->private_data; | ||
442 | void __user *argp = (void __user *)arg; | ||
443 | int r = -EINVAL; | ||
444 | |||
445 | switch (ioctl) { | ||
446 | case KVM_SET_TSS_ADDR: | ||
447 | r = kvm_vm_ioctl_set_tss_addr(kvm, arg); | ||
448 | if (r < 0) | ||
449 | goto out; | ||
450 | break; | ||
451 | case KVM_SET_MEMORY_REGION: { | ||
452 | struct kvm_memory_region kvm_mem; | ||
453 | struct kvm_userspace_memory_region kvm_userspace_mem; | ||
454 | |||
455 | r = -EFAULT; | ||
456 | if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem)) | ||
457 | goto out; | ||
458 | kvm_userspace_mem.slot = kvm_mem.slot; | ||
459 | kvm_userspace_mem.flags = kvm_mem.flags; | ||
460 | kvm_userspace_mem.guest_phys_addr = kvm_mem.guest_phys_addr; | ||
461 | kvm_userspace_mem.memory_size = kvm_mem.memory_size; | ||
462 | r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem, 0); | ||
463 | if (r) | ||
464 | goto out; | ||
465 | break; | ||
466 | } | ||
467 | case KVM_SET_NR_MMU_PAGES: | ||
468 | r = kvm_vm_ioctl_set_nr_mmu_pages(kvm, arg); | ||
469 | if (r) | ||
470 | goto out; | ||
471 | break; | ||
472 | case KVM_GET_NR_MMU_PAGES: | ||
473 | r = kvm_vm_ioctl_get_nr_mmu_pages(kvm); | ||
474 | break; | ||
475 | case KVM_SET_MEMORY_ALIAS: { | ||
476 | struct kvm_memory_alias alias; | ||
477 | |||
478 | r = -EFAULT; | ||
479 | if (copy_from_user(&alias, argp, sizeof alias)) | ||
480 | goto out; | ||
481 | r = kvm_vm_ioctl_set_memory_alias(kvm, &alias); | ||
482 | if (r) | ||
483 | goto out; | ||
484 | break; | ||
485 | } | ||
486 | case KVM_CREATE_IRQCHIP: | ||
487 | r = -ENOMEM; | ||
488 | kvm->vpic = kvm_create_pic(kvm); | ||
489 | if (kvm->vpic) { | ||
490 | r = kvm_ioapic_init(kvm); | ||
491 | if (r) { | ||
492 | kfree(kvm->vpic); | ||
493 | kvm->vpic = NULL; | ||
494 | goto out; | ||
495 | } | ||
496 | } else | ||
497 | goto out; | ||
498 | break; | ||
499 | case KVM_IRQ_LINE: { | ||
500 | struct kvm_irq_level irq_event; | ||
501 | |||
502 | r = -EFAULT; | ||
503 | if (copy_from_user(&irq_event, argp, sizeof irq_event)) | ||
504 | goto out; | ||
505 | if (irqchip_in_kernel(kvm)) { | ||
506 | mutex_lock(&kvm->lock); | ||
507 | if (irq_event.irq < 16) | ||
508 | kvm_pic_set_irq(pic_irqchip(kvm), | ||
509 | irq_event.irq, | ||
510 | irq_event.level); | ||
511 | kvm_ioapic_set_irq(kvm->vioapic, | ||
512 | irq_event.irq, | ||
513 | irq_event.level); | ||
514 | mutex_unlock(&kvm->lock); | ||
515 | r = 0; | ||
516 | } | ||
517 | break; | ||
518 | } | ||
519 | case KVM_GET_IRQCHIP: { | ||
520 | /* 0: PIC master, 1: PIC slave, 2: IOAPIC */ | ||
521 | struct kvm_irqchip chip; | ||
522 | |||
523 | r = -EFAULT; | ||
524 | if (copy_from_user(&chip, argp, sizeof chip)) | ||
525 | goto out; | ||
526 | r = -ENXIO; | ||
527 | if (!irqchip_in_kernel(kvm)) | ||
528 | goto out; | ||
529 | r = kvm_vm_ioctl_get_irqchip(kvm, &chip); | ||
530 | if (r) | ||
531 | goto out; | ||
532 | r = -EFAULT; | ||
533 | if (copy_to_user(argp, &chip, sizeof chip)) | ||
534 | goto out; | ||
535 | r = 0; | ||
536 | break; | ||
537 | } | ||
538 | case KVM_SET_IRQCHIP: { | ||
539 | /* 0: PIC master, 1: PIC slave, 2: IOAPIC */ | ||
540 | struct kvm_irqchip chip; | ||
541 | |||
542 | r = -EFAULT; | ||
543 | if (copy_from_user(&chip, argp, sizeof chip)) | ||
544 | goto out; | ||
545 | r = -ENXIO; | ||
546 | if (!irqchip_in_kernel(kvm)) | ||
547 | goto out; | ||
548 | r = kvm_vm_ioctl_set_irqchip(kvm, &chip); | ||
549 | if (r) | ||
550 | goto out; | ||
551 | r = 0; | ||
552 | break; | ||
553 | } | ||
554 | default: | ||
555 | ; | ||
556 | } | ||
557 | out: | ||
558 | return r; | ||
559 | } | ||
560 | |||
303 | static __init void kvm_init_msr_list(void) | 561 | static __init void kvm_init_msr_list(void) |
304 | { | 562 | { |
305 | u32 dummy[2]; | 563 | u32 dummy[2]; |