diff options
-rw-r--r-- | Documentation/virtual/kvm/devices/vm.txt | 10 | ||||
-rw-r--r-- | arch/s390/kvm/gaccess.c | 20 | ||||
-rw-r--r-- | arch/s390/kvm/priv.c | 72 |
3 files changed, 53 insertions, 49 deletions
diff --git a/Documentation/virtual/kvm/devices/vm.txt b/Documentation/virtual/kvm/devices/vm.txt index 0d16f96c0eac..d426fc87fe93 100644 --- a/Documentation/virtual/kvm/devices/vm.txt +++ b/Documentation/virtual/kvm/devices/vm.txt | |||
@@ -12,14 +12,14 @@ specific. | |||
12 | 1. GROUP: KVM_S390_VM_MEM_CTRL | 12 | 1. GROUP: KVM_S390_VM_MEM_CTRL |
13 | Architectures: s390 | 13 | Architectures: s390 |
14 | 14 | ||
15 | 1.1. ATTRIBUTE: KVM_S390_VM_MEM_CTRL | 15 | 1.1. ATTRIBUTE: KVM_S390_VM_MEM_ENABLE_CMMA |
16 | Parameters: none | 16 | Parameters: none |
17 | Returns: -EBUSY if already a vcpus is defined, otherwise 0 | 17 | Returns: -EBUSY if a vcpu is already defined, otherwise 0 |
18 | 18 | ||
19 | Enables CMMA for the virtual machine | 19 | Enables Collaborative Memory Management Assist (CMMA) for the virtual machine. |
20 | 20 | ||
21 | 1.2. ATTRIBUTE: KVM_S390_VM_CLR_CMMA | 21 | 1.2. ATTRIBUTE: KVM_S390_VM_MEM_CLR_CMMA |
22 | Parameteres: none | 22 | Parameters: none |
23 | Returns: 0 | 23 | Returns: 0 |
24 | 24 | ||
25 | Clear the CMMA status for all guest pages, so any pages the guest marked | 25 | Clear the CMMA status for all guest pages, so any pages the guest marked |
diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c index c1424e8b7f09..8b9ccf02a2c5 100644 --- a/arch/s390/kvm/gaccess.c +++ b/arch/s390/kvm/gaccess.c | |||
@@ -227,10 +227,12 @@ static void ipte_lock_simple(struct kvm_vcpu *vcpu) | |||
227 | goto out; | 227 | goto out; |
228 | ic = &vcpu->kvm->arch.sca->ipte_control; | 228 | ic = &vcpu->kvm->arch.sca->ipte_control; |
229 | do { | 229 | do { |
230 | old = ACCESS_ONCE(*ic); | 230 | old = *ic; |
231 | barrier(); | ||
231 | while (old.k) { | 232 | while (old.k) { |
232 | cond_resched(); | 233 | cond_resched(); |
233 | old = ACCESS_ONCE(*ic); | 234 | old = *ic; |
235 | barrier(); | ||
234 | } | 236 | } |
235 | new = old; | 237 | new = old; |
236 | new.k = 1; | 238 | new.k = 1; |
@@ -249,7 +251,9 @@ static void ipte_unlock_simple(struct kvm_vcpu *vcpu) | |||
249 | goto out; | 251 | goto out; |
250 | ic = &vcpu->kvm->arch.sca->ipte_control; | 252 | ic = &vcpu->kvm->arch.sca->ipte_control; |
251 | do { | 253 | do { |
252 | new = old = ACCESS_ONCE(*ic); | 254 | old = *ic; |
255 | barrier(); | ||
256 | new = old; | ||
253 | new.k = 0; | 257 | new.k = 0; |
254 | } while (cmpxchg(&ic->val, old.val, new.val) != old.val); | 258 | } while (cmpxchg(&ic->val, old.val, new.val) != old.val); |
255 | wake_up(&vcpu->kvm->arch.ipte_wq); | 259 | wake_up(&vcpu->kvm->arch.ipte_wq); |
@@ -263,10 +267,12 @@ static void ipte_lock_siif(struct kvm_vcpu *vcpu) | |||
263 | 267 | ||
264 | ic = &vcpu->kvm->arch.sca->ipte_control; | 268 | ic = &vcpu->kvm->arch.sca->ipte_control; |
265 | do { | 269 | do { |
266 | old = ACCESS_ONCE(*ic); | 270 | old = *ic; |
271 | barrier(); | ||
267 | while (old.kg) { | 272 | while (old.kg) { |
268 | cond_resched(); | 273 | cond_resched(); |
269 | old = ACCESS_ONCE(*ic); | 274 | old = *ic; |
275 | barrier(); | ||
270 | } | 276 | } |
271 | new = old; | 277 | new = old; |
272 | new.k = 1; | 278 | new.k = 1; |
@@ -280,7 +286,9 @@ static void ipte_unlock_siif(struct kvm_vcpu *vcpu) | |||
280 | 286 | ||
281 | ic = &vcpu->kvm->arch.sca->ipte_control; | 287 | ic = &vcpu->kvm->arch.sca->ipte_control; |
282 | do { | 288 | do { |
283 | new = old = ACCESS_ONCE(*ic); | 289 | old = *ic; |
290 | barrier(); | ||
291 | new = old; | ||
284 | new.kh--; | 292 | new.kh--; |
285 | if (!new.kh) | 293 | if (!new.kh) |
286 | new.k = 0; | 294 | new.k = 0; |
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index 72bb2dd8b9cd..9bde32f66eb5 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c | |||
@@ -762,8 +762,8 @@ int kvm_s390_handle_lctl(struct kvm_vcpu *vcpu) | |||
762 | { | 762 | { |
763 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | 763 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; |
764 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; | 764 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; |
765 | u32 val = 0; | 765 | int reg, rc, nr_regs; |
766 | int reg, rc; | 766 | u32 ctl_array[16]; |
767 | u64 ga; | 767 | u64 ga; |
768 | 768 | ||
769 | vcpu->stat.instruction_lctl++; | 769 | vcpu->stat.instruction_lctl++; |
@@ -779,19 +779,20 @@ int kvm_s390_handle_lctl(struct kvm_vcpu *vcpu) | |||
779 | VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x, addr:%llx", reg1, reg3, ga); | 779 | VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x, addr:%llx", reg1, reg3, ga); |
780 | trace_kvm_s390_handle_lctl(vcpu, 0, reg1, reg3, ga); | 780 | trace_kvm_s390_handle_lctl(vcpu, 0, reg1, reg3, ga); |
781 | 781 | ||
782 | nr_regs = ((reg3 - reg1) & 0xf) + 1; | ||
783 | rc = read_guest(vcpu, ga, ctl_array, nr_regs * sizeof(u32)); | ||
784 | if (rc) | ||
785 | return kvm_s390_inject_prog_cond(vcpu, rc); | ||
782 | reg = reg1; | 786 | reg = reg1; |
787 | nr_regs = 0; | ||
783 | do { | 788 | do { |
784 | rc = read_guest(vcpu, ga, &val, sizeof(val)); | ||
785 | if (rc) | ||
786 | return kvm_s390_inject_prog_cond(vcpu, rc); | ||
787 | vcpu->arch.sie_block->gcr[reg] &= 0xffffffff00000000ul; | 789 | vcpu->arch.sie_block->gcr[reg] &= 0xffffffff00000000ul; |
788 | vcpu->arch.sie_block->gcr[reg] |= val; | 790 | vcpu->arch.sie_block->gcr[reg] |= ctl_array[nr_regs++]; |
789 | ga += 4; | ||
790 | if (reg == reg3) | 791 | if (reg == reg3) |
791 | break; | 792 | break; |
792 | reg = (reg + 1) % 16; | 793 | reg = (reg + 1) % 16; |
793 | } while (1); | 794 | } while (1); |
794 | 795 | kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu); | |
795 | return 0; | 796 | return 0; |
796 | } | 797 | } |
797 | 798 | ||
@@ -799,9 +800,9 @@ int kvm_s390_handle_stctl(struct kvm_vcpu *vcpu) | |||
799 | { | 800 | { |
800 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | 801 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; |
801 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; | 802 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; |
803 | int reg, rc, nr_regs; | ||
804 | u32 ctl_array[16]; | ||
802 | u64 ga; | 805 | u64 ga; |
803 | u32 val; | ||
804 | int reg, rc; | ||
805 | 806 | ||
806 | vcpu->stat.instruction_stctl++; | 807 | vcpu->stat.instruction_stctl++; |
807 | 808 | ||
@@ -817,26 +818,24 @@ int kvm_s390_handle_stctl(struct kvm_vcpu *vcpu) | |||
817 | trace_kvm_s390_handle_stctl(vcpu, 0, reg1, reg3, ga); | 818 | trace_kvm_s390_handle_stctl(vcpu, 0, reg1, reg3, ga); |
818 | 819 | ||
819 | reg = reg1; | 820 | reg = reg1; |
821 | nr_regs = 0; | ||
820 | do { | 822 | do { |
821 | val = vcpu->arch.sie_block->gcr[reg] & 0x00000000fffffffful; | 823 | ctl_array[nr_regs++] = vcpu->arch.sie_block->gcr[reg]; |
822 | rc = write_guest(vcpu, ga, &val, sizeof(val)); | ||
823 | if (rc) | ||
824 | return kvm_s390_inject_prog_cond(vcpu, rc); | ||
825 | ga += 4; | ||
826 | if (reg == reg3) | 824 | if (reg == reg3) |
827 | break; | 825 | break; |
828 | reg = (reg + 1) % 16; | 826 | reg = (reg + 1) % 16; |
829 | } while (1); | 827 | } while (1); |
830 | 828 | rc = write_guest(vcpu, ga, ctl_array, nr_regs * sizeof(u32)); | |
831 | return 0; | 829 | return rc ? kvm_s390_inject_prog_cond(vcpu, rc) : 0; |
832 | } | 830 | } |
833 | 831 | ||
834 | static int handle_lctlg(struct kvm_vcpu *vcpu) | 832 | static int handle_lctlg(struct kvm_vcpu *vcpu) |
835 | { | 833 | { |
836 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | 834 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; |
837 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; | 835 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; |
838 | u64 ga, val; | 836 | int reg, rc, nr_regs; |
839 | int reg, rc; | 837 | u64 ctl_array[16]; |
838 | u64 ga; | ||
840 | 839 | ||
841 | vcpu->stat.instruction_lctlg++; | 840 | vcpu->stat.instruction_lctlg++; |
842 | 841 | ||
@@ -848,22 +847,22 @@ static int handle_lctlg(struct kvm_vcpu *vcpu) | |||
848 | if (ga & 7) | 847 | if (ga & 7) |
849 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | 848 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); |
850 | 849 | ||
851 | reg = reg1; | ||
852 | |||
853 | VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x, addr:%llx", reg1, reg3, ga); | 850 | VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x, addr:%llx", reg1, reg3, ga); |
854 | trace_kvm_s390_handle_lctl(vcpu, 1, reg1, reg3, ga); | 851 | trace_kvm_s390_handle_lctl(vcpu, 1, reg1, reg3, ga); |
855 | 852 | ||
853 | nr_regs = ((reg3 - reg1) & 0xf) + 1; | ||
854 | rc = read_guest(vcpu, ga, ctl_array, nr_regs * sizeof(u64)); | ||
855 | if (rc) | ||
856 | return kvm_s390_inject_prog_cond(vcpu, rc); | ||
857 | reg = reg1; | ||
858 | nr_regs = 0; | ||
856 | do { | 859 | do { |
857 | rc = read_guest(vcpu, ga, &val, sizeof(val)); | 860 | vcpu->arch.sie_block->gcr[reg] = ctl_array[nr_regs++]; |
858 | if (rc) | ||
859 | return kvm_s390_inject_prog_cond(vcpu, rc); | ||
860 | vcpu->arch.sie_block->gcr[reg] = val; | ||
861 | ga += 8; | ||
862 | if (reg == reg3) | 861 | if (reg == reg3) |
863 | break; | 862 | break; |
864 | reg = (reg + 1) % 16; | 863 | reg = (reg + 1) % 16; |
865 | } while (1); | 864 | } while (1); |
866 | 865 | kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu); | |
867 | return 0; | 866 | return 0; |
868 | } | 867 | } |
869 | 868 | ||
@@ -871,8 +870,9 @@ static int handle_stctg(struct kvm_vcpu *vcpu) | |||
871 | { | 870 | { |
872 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | 871 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; |
873 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; | 872 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; |
874 | u64 ga, val; | 873 | int reg, rc, nr_regs; |
875 | int reg, rc; | 874 | u64 ctl_array[16]; |
875 | u64 ga; | ||
876 | 876 | ||
877 | vcpu->stat.instruction_stctg++; | 877 | vcpu->stat.instruction_stctg++; |
878 | 878 | ||
@@ -884,23 +884,19 @@ static int handle_stctg(struct kvm_vcpu *vcpu) | |||
884 | if (ga & 7) | 884 | if (ga & 7) |
885 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | 885 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); |
886 | 886 | ||
887 | reg = reg1; | ||
888 | |||
889 | VCPU_EVENT(vcpu, 5, "stctg r1:%x, r3:%x, addr:%llx", reg1, reg3, ga); | 887 | VCPU_EVENT(vcpu, 5, "stctg r1:%x, r3:%x, addr:%llx", reg1, reg3, ga); |
890 | trace_kvm_s390_handle_stctl(vcpu, 1, reg1, reg3, ga); | 888 | trace_kvm_s390_handle_stctl(vcpu, 1, reg1, reg3, ga); |
891 | 889 | ||
890 | reg = reg1; | ||
891 | nr_regs = 0; | ||
892 | do { | 892 | do { |
893 | val = vcpu->arch.sie_block->gcr[reg]; | 893 | ctl_array[nr_regs++] = vcpu->arch.sie_block->gcr[reg]; |
894 | rc = write_guest(vcpu, ga, &val, sizeof(val)); | ||
895 | if (rc) | ||
896 | return kvm_s390_inject_prog_cond(vcpu, rc); | ||
897 | ga += 8; | ||
898 | if (reg == reg3) | 894 | if (reg == reg3) |
899 | break; | 895 | break; |
900 | reg = (reg + 1) % 16; | 896 | reg = (reg + 1) % 16; |
901 | } while (1); | 897 | } while (1); |
902 | 898 | rc = write_guest(vcpu, ga, ctl_array, nr_regs * sizeof(u64)); | |
903 | return 0; | 899 | return rc ? kvm_s390_inject_prog_cond(vcpu, rc) : 0; |
904 | } | 900 | } |
905 | 901 | ||
906 | static const intercept_handler_t eb_handlers[256] = { | 902 | static const intercept_handler_t eb_handlers[256] = { |