|
13 | 13 | #include <linux/device.h> |
14 | 14 | #include <linux/list.h> |
15 | 15 | #include <linux/ctype.h> |
| 16 | +#include <linux/bitops.h> |
| 17 | +#include <linux/kvm_host.h> |
| 18 | +#include <linux/module.h> |
| 19 | +#include <asm/kvm.h> |
16 | 20 | #include <asm/zcrypt.h> |
17 | 21 |
|
18 | 22 | #include "vfio_ap_private.h" |
@@ -54,6 +58,9 @@ static int vfio_ap_mdev_remove(struct mdev_device *mdev) |
54 | 58 | { |
55 | 59 | struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); |
56 | 60 |
|
| 61 | + if (matrix_mdev->kvm) |
| 62 | + return -EBUSY; |
| 63 | + |
57 | 64 | mutex_lock(&matrix_dev->lock); |
58 | 65 | list_del(&matrix_mdev->node); |
59 | 66 | mutex_unlock(&matrix_dev->lock); |
@@ -305,6 +312,10 @@ static ssize_t assign_adapter_store(struct device *dev, |
305 | 312 | struct mdev_device *mdev = mdev_from_dev(dev); |
306 | 313 | struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); |
307 | 314 |
|
| 315 | + /* If the guest is running, disallow assignment of adapter */ |
| 316 | + if (matrix_mdev->kvm) |
| 317 | + return -EBUSY; |
| 318 | + |
308 | 319 | ret = kstrtoul(buf, 0, &apid); |
309 | 320 | if (ret) |
310 | 321 | return ret; |
@@ -367,6 +378,10 @@ static ssize_t unassign_adapter_store(struct device *dev, |
367 | 378 | struct mdev_device *mdev = mdev_from_dev(dev); |
368 | 379 | struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); |
369 | 380 |
|
| 381 | + /* If the guest is running, disallow un-assignment of adapter */ |
| 382 | + if (matrix_mdev->kvm) |
| 383 | + return -EBUSY; |
| 384 | + |
370 | 385 | ret = kstrtoul(buf, 0, &apid); |
371 | 386 | if (ret) |
372 | 387 | return ret; |
@@ -444,6 +459,10 @@ static ssize_t assign_domain_store(struct device *dev, |
444 | 459 | struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); |
445 | 460 | unsigned long max_apqi = matrix_mdev->matrix.aqm_max; |
446 | 461 |
|
| 462 | + /* If the guest is running, disallow assignment of domain */ |
| 463 | + if (matrix_mdev->kvm) |
| 464 | + return -EBUSY; |
| 465 | + |
447 | 466 | ret = kstrtoul(buf, 0, &apqi); |
448 | 467 | if (ret) |
449 | 468 | return ret; |
@@ -501,6 +520,10 @@ static ssize_t unassign_domain_store(struct device *dev, |
501 | 520 | struct mdev_device *mdev = mdev_from_dev(dev); |
502 | 521 | struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); |
503 | 522 |
|
| 523 | + /* If the guest is running, disallow un-assignment of domain */ |
| 524 | + if (matrix_mdev->kvm) |
| 525 | + return -EBUSY; |
| 526 | + |
504 | 527 | ret = kstrtoul(buf, 0, &apqi); |
505 | 528 | if (ret) |
506 | 529 | return ret; |
@@ -541,6 +564,10 @@ static ssize_t assign_control_domain_store(struct device *dev, |
541 | 564 | struct mdev_device *mdev = mdev_from_dev(dev); |
542 | 565 | struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); |
543 | 566 |
|
| 567 | + /* If the guest is running, disallow assignment of control domain */ |
| 568 | + if (matrix_mdev->kvm) |
| 569 | + return -EBUSY; |
| 570 | + |
544 | 571 | ret = kstrtoul(buf, 0, &id); |
545 | 572 | if (ret) |
546 | 573 | return ret; |
@@ -587,6 +614,10 @@ static ssize_t unassign_control_domain_store(struct device *dev, |
587 | 614 | struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); |
588 | 615 | unsigned long max_domid = matrix_mdev->matrix.adm_max; |
589 | 616 |
|
| 617 | + /* If the guest is running, disallow un-assignment of control domain */ |
| 618 | + if (matrix_mdev->kvm) |
| 619 | + return -EBUSY; |
| 620 | + |
590 | 621 | ret = kstrtoul(buf, 0, &domid); |
591 | 622 | if (ret) |
592 | 623 | return ret; |
@@ -696,12 +727,142 @@ static const struct attribute_group *vfio_ap_mdev_attr_groups[] = { |
696 | 727 | NULL |
697 | 728 | }; |
698 | 729 |
|
| 730 | +static void vfio_ap_mdev_copy_masks(struct ap_matrix_mdev *matrix_mdev) |
| 731 | +{ |
| 732 | + int nbytes; |
| 733 | + unsigned long *apm, *aqm, *adm; |
| 734 | + struct kvm_s390_crypto_cb *crycb = matrix_mdev->kvm->arch.crypto.crycb; |
| 735 | + |
| 736 | + switch (matrix_mdev->kvm->arch.crypto.crycbd & CRYCB_FORMAT_MASK) { |
| 737 | + case CRYCB_FORMAT2: |
| 738 | + apm = (unsigned long *)crycb->apcb1.apm; |
| 739 | + aqm = (unsigned long *)crycb->apcb1.aqm; |
| 740 | + adm = (unsigned long *)crycb->apcb1.adm; |
| 741 | + break; |
| 742 | + case CRYCB_FORMAT1: |
| 743 | + case CRYCB_FORMAT0: |
| 744 | + apm = (unsigned long *)crycb->apcb0.apm; |
| 745 | + aqm = (unsigned long *)crycb->apcb0.aqm; |
| 746 | + adm = (unsigned long *)crycb->apcb0.adm; |
| 747 | + break; |
| 748 | + default: |
| 749 | + /* cannot happen */ |
| 750 | + return; |
| 751 | + } |
| 752 | + |
| 753 | + nbytes = DIV_ROUND_UP(matrix_mdev->matrix.apm_max + 1, BITS_PER_BYTE); |
| 754 | + memcpy(apm, matrix_mdev->matrix.apm, nbytes); |
| 755 | + nbytes = DIV_ROUND_UP(matrix_mdev->matrix.aqm_max + 1, BITS_PER_BYTE); |
| 756 | + memcpy(aqm, matrix_mdev->matrix.aqm, nbytes); |
| 757 | + nbytes = DIV_ROUND_UP(matrix_mdev->matrix.adm_max + 1, BITS_PER_BYTE); |
| 758 | + memcpy(adm, matrix_mdev->matrix.adm, nbytes); |
| 759 | +} |
| 760 | + |
| 761 | +/** |
| 762 | + * vfio_ap_mdev_set_kvm |
| 763 | + * |
| 764 | + * @matrix_mdev: a mediated matrix device |
| 765 | + * @kvm: reference to KVM instance |
| 766 | + * |
| 767 | + * Verifies no other mediated matrix device has @kvm and sets a reference to |
| 768 | + * it in @matrix_mdev->kvm. |
| 769 | + * |
| 770 | + * Return 0 if no other mediated matrix device has a reference to @kvm; |
| 771 | + * otherwise, returns an -EPERM. |
| 772 | + */ |
| 773 | +static int vfio_ap_mdev_set_kvm(struct ap_matrix_mdev *matrix_mdev, |
| 774 | + struct kvm *kvm) |
| 775 | +{ |
| 776 | + struct ap_matrix_mdev *m; |
| 777 | + |
| 778 | + mutex_lock(&matrix_dev->lock); |
| 779 | + |
| 780 | + list_for_each_entry(m, &matrix_dev->mdev_list, node) { |
| 781 | + if ((m != matrix_mdev) && (m->kvm == kvm)) { |
| 782 | + mutex_unlock(&matrix_dev->lock); |
| 783 | + return -EPERM; |
| 784 | + } |
| 785 | + } |
| 786 | + |
| 787 | + matrix_mdev->kvm = kvm; |
| 788 | + mutex_unlock(&matrix_dev->lock); |
| 789 | + |
| 790 | + return 0; |
| 791 | +} |
| 792 | + |
| 793 | +static int vfio_ap_mdev_group_notifier(struct notifier_block *nb, |
| 794 | + unsigned long action, void *data) |
| 795 | +{ |
| 796 | + int ret; |
| 797 | + struct ap_matrix_mdev *matrix_mdev; |
| 798 | + |
| 799 | + if (action != VFIO_GROUP_NOTIFY_SET_KVM) |
| 800 | + return NOTIFY_OK; |
| 801 | + |
| 802 | + matrix_mdev = container_of(nb, struct ap_matrix_mdev, group_notifier); |
| 803 | + |
| 804 | + if (!data) { |
| 805 | + matrix_mdev->kvm = NULL; |
| 806 | + return NOTIFY_OK; |
| 807 | + } |
| 808 | + |
| 809 | + ret = vfio_ap_mdev_set_kvm(matrix_mdev, data); |
| 810 | + if (ret) |
| 811 | + return NOTIFY_DONE; |
| 812 | + |
| 813 | + /* If there is no CRYCB pointer, then we can't copy the masks */ |
| 814 | + if (!matrix_mdev->kvm->arch.crypto.crycbd) |
| 815 | + return NOTIFY_DONE; |
| 816 | + |
| 817 | + vfio_ap_mdev_copy_masks(matrix_mdev); |
| 818 | + |
| 819 | + return NOTIFY_OK; |
| 820 | +} |
| 821 | + |
| 822 | +static int vfio_ap_mdev_open(struct mdev_device *mdev) |
| 823 | +{ |
| 824 | + struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); |
| 825 | + unsigned long events; |
| 826 | + int ret; |
| 827 | + |
| 828 | + |
| 829 | + if (!try_module_get(THIS_MODULE)) |
| 830 | + return -ENODEV; |
| 831 | + |
| 832 | + matrix_mdev->group_notifier.notifier_call = vfio_ap_mdev_group_notifier; |
| 833 | + events = VFIO_GROUP_NOTIFY_SET_KVM; |
| 834 | + |
| 835 | + ret = vfio_register_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY, |
| 836 | + &events, &matrix_mdev->group_notifier); |
| 837 | + if (ret) { |
| 838 | + module_put(THIS_MODULE); |
| 839 | + return ret; |
| 840 | + } |
| 841 | + |
| 842 | + return 0; |
| 843 | +} |
| 844 | + |
| 845 | +static void vfio_ap_mdev_release(struct mdev_device *mdev) |
| 846 | +{ |
| 847 | + struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); |
| 848 | + |
| 849 | + if (matrix_mdev->kvm) |
| 850 | + kvm_arch_crypto_clear_masks(matrix_mdev->kvm); |
| 851 | + |
| 852 | + vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY, |
| 853 | + &matrix_mdev->group_notifier); |
| 854 | + matrix_mdev->kvm = NULL; |
| 855 | + module_put(THIS_MODULE); |
| 856 | +} |
| 857 | + |
699 | 858 | static const struct mdev_parent_ops vfio_ap_matrix_ops = { |
700 | 859 | .owner = THIS_MODULE, |
701 | 860 | .supported_type_groups = vfio_ap_mdev_type_groups, |
702 | 861 | .mdev_attr_groups = vfio_ap_mdev_attr_groups, |
703 | 862 | .create = vfio_ap_mdev_create, |
704 | 863 | .remove = vfio_ap_mdev_remove, |
| 864 | + .open = vfio_ap_mdev_open, |
| 865 | + .release = vfio_ap_mdev_release, |
705 | 866 | }; |
706 | 867 |
|
707 | 868 | int vfio_ap_mdev_register(void) |
|
0 commit comments