diff options
| author | Paolo Bonzini <pbonzini@redhat.com> | 2014-11-07 09:39:44 -0500 |
|---|---|---|
| committer | Paolo Bonzini <pbonzini@redhat.com> | 2014-11-07 09:39:44 -0500 |
| commit | 173ede4ddd054e072f9178d655a660c8aaa80cea (patch) | |
| tree | cb2b2ed48c2e91a03bcc67e2ce0018a0afc27dc0 | |
| parent | c6338ce494456ed9c92ef10f63c0a8408bfeac6d (diff) | |
| parent | 365dc1633521a32d55d839f56b41bb9a531d957a (diff) | |
Merge tag 'kvm-s390-next-20141107' of git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux into HEAD
KVM: s390: Fixes for kvm/next (3.19) and stable
1. We should flush TLBs for load control instruction emulation (stable)
2. A workaround for a compiler bug that renders ACCESS_ONCE broken (stable)
3. Fix program check handling for load control
4. Documentation Fix
| -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] = { |
