|
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