diff options
Diffstat (limited to 'arch/x86/kvm/i8259.c')
-rw-r--r-- | arch/x86/kvm/i8259.c | 123 |
1 files changed, 97 insertions, 26 deletions
diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c index 19fe855e7953..cac4746d7ffb 100644 --- a/arch/x86/kvm/i8259.c +++ b/arch/x86/kvm/i8259.c | |||
@@ -34,6 +34,9 @@ | |||
34 | #include <linux/kvm_host.h> | 34 | #include <linux/kvm_host.h> |
35 | #include "trace.h" | 35 | #include "trace.h" |
36 | 36 | ||
37 | #define pr_pic_unimpl(fmt, ...) \ | ||
38 | pr_err_ratelimited("kvm: pic: " fmt, ## __VA_ARGS__) | ||
39 | |||
37 | static void pic_irq_request(struct kvm *kvm, int level); | 40 | static void pic_irq_request(struct kvm *kvm, int level); |
38 | 41 | ||
39 | static void pic_lock(struct kvm_pic *s) | 42 | static void pic_lock(struct kvm_pic *s) |
@@ -306,10 +309,10 @@ static void pic_ioport_write(void *opaque, u32 addr, u32 val) | |||
306 | } | 309 | } |
307 | s->init_state = 1; | 310 | s->init_state = 1; |
308 | if (val & 0x02) | 311 | if (val & 0x02) |
309 | printk(KERN_ERR "single mode not supported"); | 312 | pr_pic_unimpl("single mode not supported"); |
310 | if (val & 0x08) | 313 | if (val & 0x08) |
311 | printk(KERN_ERR | 314 | pr_pic_unimpl( |
312 | "level sensitive irq not supported"); | 315 | "level sensitive irq not supported"); |
313 | } else if (val & 0x08) { | 316 | } else if (val & 0x08) { |
314 | if (val & 0x04) | 317 | if (val & 0x04) |
315 | s->poll = 1; | 318 | s->poll = 1; |
@@ -459,22 +462,15 @@ static int picdev_in_range(gpa_t addr) | |||
459 | } | 462 | } |
460 | } | 463 | } |
461 | 464 | ||
462 | static inline struct kvm_pic *to_pic(struct kvm_io_device *dev) | 465 | static int picdev_write(struct kvm_pic *s, |
463 | { | ||
464 | return container_of(dev, struct kvm_pic, dev); | ||
465 | } | ||
466 | |||
467 | static int picdev_write(struct kvm_io_device *this, | ||
468 | gpa_t addr, int len, const void *val) | 466 | gpa_t addr, int len, const void *val) |
469 | { | 467 | { |
470 | struct kvm_pic *s = to_pic(this); | ||
471 | unsigned char data = *(unsigned char *)val; | 468 | unsigned char data = *(unsigned char *)val; |
472 | if (!picdev_in_range(addr)) | 469 | if (!picdev_in_range(addr)) |
473 | return -EOPNOTSUPP; | 470 | return -EOPNOTSUPP; |
474 | 471 | ||
475 | if (len != 1) { | 472 | if (len != 1) { |
476 | if (printk_ratelimit()) | 473 | pr_pic_unimpl("non byte write\n"); |
477 | printk(KERN_ERR "PIC: non byte write\n"); | ||
478 | return 0; | 474 | return 0; |
479 | } | 475 | } |
480 | pic_lock(s); | 476 | pic_lock(s); |
@@ -494,17 +490,15 @@ static int picdev_write(struct kvm_io_device *this, | |||
494 | return 0; | 490 | return 0; |
495 | } | 491 | } |
496 | 492 | ||
497 | static int picdev_read(struct kvm_io_device *this, | 493 | static int picdev_read(struct kvm_pic *s, |
498 | gpa_t addr, int len, void *val) | 494 | gpa_t addr, int len, void *val) |
499 | { | 495 | { |
500 | struct kvm_pic *s = to_pic(this); | ||
501 | unsigned char data = 0; | 496 | unsigned char data = 0; |
502 | if (!picdev_in_range(addr)) | 497 | if (!picdev_in_range(addr)) |
503 | return -EOPNOTSUPP; | 498 | return -EOPNOTSUPP; |
504 | 499 | ||
505 | if (len != 1) { | 500 | if (len != 1) { |
506 | if (printk_ratelimit()) | 501 | pr_pic_unimpl("non byte read\n"); |
507 | printk(KERN_ERR "PIC: non byte read\n"); | ||
508 | return 0; | 502 | return 0; |
509 | } | 503 | } |
510 | pic_lock(s); | 504 | pic_lock(s); |
@@ -525,6 +519,48 @@ static int picdev_read(struct kvm_io_device *this, | |||
525 | return 0; | 519 | return 0; |
526 | } | 520 | } |
527 | 521 | ||
522 | static int picdev_master_write(struct kvm_io_device *dev, | ||
523 | gpa_t addr, int len, const void *val) | ||
524 | { | ||
525 | return picdev_write(container_of(dev, struct kvm_pic, dev_master), | ||
526 | addr, len, val); | ||
527 | } | ||
528 | |||
529 | static int picdev_master_read(struct kvm_io_device *dev, | ||
530 | gpa_t addr, int len, void *val) | ||
531 | { | ||
532 | return picdev_read(container_of(dev, struct kvm_pic, dev_master), | ||
533 | addr, len, val); | ||
534 | } | ||
535 | |||
536 | static int picdev_slave_write(struct kvm_io_device *dev, | ||
537 | gpa_t addr, int len, const void *val) | ||
538 | { | ||
539 | return picdev_write(container_of(dev, struct kvm_pic, dev_slave), | ||
540 | addr, len, val); | ||
541 | } | ||
542 | |||
543 | static int picdev_slave_read(struct kvm_io_device *dev, | ||
544 | gpa_t addr, int len, void *val) | ||
545 | { | ||
546 | return picdev_read(container_of(dev, struct kvm_pic, dev_slave), | ||
547 | addr, len, val); | ||
548 | } | ||
549 | |||
550 | static int picdev_eclr_write(struct kvm_io_device *dev, | ||
551 | gpa_t addr, int len, const void *val) | ||
552 | { | ||
553 | return picdev_write(container_of(dev, struct kvm_pic, dev_eclr), | ||
554 | addr, len, val); | ||
555 | } | ||
556 | |||
557 | static int picdev_eclr_read(struct kvm_io_device *dev, | ||
558 | gpa_t addr, int len, void *val) | ||
559 | { | ||
560 | return picdev_read(container_of(dev, struct kvm_pic, dev_eclr), | ||
561 | addr, len, val); | ||
562 | } | ||
563 | |||
528 | /* | 564 | /* |
529 | * callback when PIC0 irq status changed | 565 | * callback when PIC0 irq status changed |
530 | */ | 566 | */ |
@@ -537,9 +573,19 @@ static void pic_irq_request(struct kvm *kvm, int level) | |||
537 | s->output = level; | 573 | s->output = level; |
538 | } | 574 | } |
539 | 575 | ||
540 | static const struct kvm_io_device_ops picdev_ops = { | 576 | static const struct kvm_io_device_ops picdev_master_ops = { |
541 | .read = picdev_read, | 577 | .read = picdev_master_read, |
542 | .write = picdev_write, | 578 | .write = picdev_master_write, |
579 | }; | ||
580 | |||
581 | static const struct kvm_io_device_ops picdev_slave_ops = { | ||
582 | .read = picdev_slave_read, | ||
583 | .write = picdev_slave_write, | ||
584 | }; | ||
585 | |||
586 | static const struct kvm_io_device_ops picdev_eclr_ops = { | ||
587 | .read = picdev_eclr_read, | ||
588 | .write = picdev_eclr_write, | ||
543 | }; | 589 | }; |
544 | 590 | ||
545 | struct kvm_pic *kvm_create_pic(struct kvm *kvm) | 591 | struct kvm_pic *kvm_create_pic(struct kvm *kvm) |
@@ -560,16 +606,39 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm) | |||
560 | /* | 606 | /* |
561 | * Initialize PIO device | 607 | * Initialize PIO device |
562 | */ | 608 | */ |
563 | kvm_iodevice_init(&s->dev, &picdev_ops); | 609 | kvm_iodevice_init(&s->dev_master, &picdev_master_ops); |
610 | kvm_iodevice_init(&s->dev_slave, &picdev_slave_ops); | ||
611 | kvm_iodevice_init(&s->dev_eclr, &picdev_eclr_ops); | ||
564 | mutex_lock(&kvm->slots_lock); | 612 | mutex_lock(&kvm->slots_lock); |
565 | ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, &s->dev); | 613 | ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, 0x20, 2, |
614 | &s->dev_master); | ||
615 | if (ret < 0) | ||
616 | goto fail_unlock; | ||
617 | |||
618 | ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, 0xa0, 2, &s->dev_slave); | ||
619 | if (ret < 0) | ||
620 | goto fail_unreg_2; | ||
621 | |||
622 | ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, 0x4d0, 2, &s->dev_eclr); | ||
623 | if (ret < 0) | ||
624 | goto fail_unreg_1; | ||
625 | |||
566 | mutex_unlock(&kvm->slots_lock); | 626 | mutex_unlock(&kvm->slots_lock); |
567 | if (ret < 0) { | ||
568 | kfree(s); | ||
569 | return NULL; | ||
570 | } | ||
571 | 627 | ||
572 | return s; | 628 | return s; |
629 | |||
630 | fail_unreg_1: | ||
631 | kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &s->dev_slave); | ||
632 | |||
633 | fail_unreg_2: | ||
634 | kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &s->dev_master); | ||
635 | |||
636 | fail_unlock: | ||
637 | mutex_unlock(&kvm->slots_lock); | ||
638 | |||
639 | kfree(s); | ||
640 | |||
641 | return NULL; | ||
573 | } | 642 | } |
574 | 643 | ||
575 | void kvm_destroy_pic(struct kvm *kvm) | 644 | void kvm_destroy_pic(struct kvm *kvm) |
@@ -577,7 +646,9 @@ void kvm_destroy_pic(struct kvm *kvm) | |||
577 | struct kvm_pic *vpic = kvm->arch.vpic; | 646 | struct kvm_pic *vpic = kvm->arch.vpic; |
578 | 647 | ||
579 | if (vpic) { | 648 | if (vpic) { |
580 | kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &vpic->dev); | 649 | kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &vpic->dev_master); |
650 | kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &vpic->dev_slave); | ||
651 | kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &vpic->dev_eclr); | ||
581 | kvm->arch.vpic = NULL; | 652 | kvm->arch.vpic = NULL; |
582 | kfree(vpic); | 653 | kfree(vpic); |
583 | } | 654 | } |