summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Borntraeger <borntraeger@de.ibm.com>2017-06-07 06:45:22 -0400
committerChristian Borntraeger <borntraeger@de.ibm.com>2017-06-22 06:41:06 -0400
commit6ae1574c2a24eec5efa8bac305a8f87c839acc64 (patch)
tree186dbaa684e7575b718783b1c1486f92653d365a
parent4036e3874a1ce41a4f7267289f9a0d8e5cd49408 (diff)
KVM: s390: implement instruction execution protection for emulated
ifetch While currently only used to fetch the original instruction on failure for getting the instruction length code, we should make the page table walking code future proof. Suggested-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
-rw-r--r--arch/s390/include/asm/ctl_reg.h4
-rw-r--r--arch/s390/kvm/gaccess.c39
2 files changed, 32 insertions, 11 deletions
diff --git a/arch/s390/include/asm/ctl_reg.h b/arch/s390/include/asm/ctl_reg.h
index d0441ad2a990..e508dff92535 100644
--- a/arch/s390/include/asm/ctl_reg.h
+++ b/arch/s390/include/asm/ctl_reg.h
@@ -59,7 +59,9 @@ union ctlreg0 {
59 unsigned long lap : 1; /* Low-address-protection control */ 59 unsigned long lap : 1; /* Low-address-protection control */
60 unsigned long : 4; 60 unsigned long : 4;
61 unsigned long edat : 1; /* Enhanced-DAT-enablement control */ 61 unsigned long edat : 1; /* Enhanced-DAT-enablement control */
62 unsigned long : 4; 62 unsigned long : 2;
63 unsigned long iep : 1; /* Instruction-Execution-Protection */
64 unsigned long : 1;
63 unsigned long afp : 1; /* AFP-register control */ 65 unsigned long afp : 1; /* AFP-register control */
64 unsigned long vx : 1; /* Vector enablement control */ 66 unsigned long vx : 1; /* Vector enablement control */
65 unsigned long : 7; 67 unsigned long : 7;
diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c
index 9da243d94cc3..6fda095f1a99 100644
--- a/arch/s390/kvm/gaccess.c
+++ b/arch/s390/kvm/gaccess.c
@@ -89,7 +89,7 @@ struct region3_table_entry_fc1 {
89 unsigned long f : 1; /* Fetch-Protection Bit */ 89 unsigned long f : 1; /* Fetch-Protection Bit */
90 unsigned long fc : 1; /* Format-Control */ 90 unsigned long fc : 1; /* Format-Control */
91 unsigned long p : 1; /* DAT-Protection Bit */ 91 unsigned long p : 1; /* DAT-Protection Bit */
92 unsigned long co : 1; /* Change-Recording Override */ 92 unsigned long iep: 1; /* Instruction-Execution-Protection */
93 unsigned long : 2; 93 unsigned long : 2;
94 unsigned long i : 1; /* Region-Invalid Bit */ 94 unsigned long i : 1; /* Region-Invalid Bit */
95 unsigned long cr : 1; /* Common-Region Bit */ 95 unsigned long cr : 1; /* Common-Region Bit */
@@ -131,7 +131,7 @@ struct segment_entry_fc1 {
131 unsigned long f : 1; /* Fetch-Protection Bit */ 131 unsigned long f : 1; /* Fetch-Protection Bit */
132 unsigned long fc : 1; /* Format-Control */ 132 unsigned long fc : 1; /* Format-Control */
133 unsigned long p : 1; /* DAT-Protection Bit */ 133 unsigned long p : 1; /* DAT-Protection Bit */
134 unsigned long co : 1; /* Change-Recording Override */ 134 unsigned long iep: 1; /* Instruction-Execution-Protection */
135 unsigned long : 2; 135 unsigned long : 2;
136 unsigned long i : 1; /* Segment-Invalid Bit */ 136 unsigned long i : 1; /* Segment-Invalid Bit */
137 unsigned long cs : 1; /* Common-Segment Bit */ 137 unsigned long cs : 1; /* Common-Segment Bit */
@@ -168,7 +168,8 @@ union page_table_entry {
168 unsigned long z : 1; /* Zero Bit */ 168 unsigned long z : 1; /* Zero Bit */
169 unsigned long i : 1; /* Page-Invalid Bit */ 169 unsigned long i : 1; /* Page-Invalid Bit */
170 unsigned long p : 1; /* DAT-Protection Bit */ 170 unsigned long p : 1; /* DAT-Protection Bit */
171 unsigned long : 9; 171 unsigned long iep: 1; /* Instruction-Execution-Protection */
172 unsigned long : 8;
172 }; 173 };
173}; 174};
174 175
@@ -485,6 +486,7 @@ enum prot_type {
485 PROT_TYPE_KEYC = 1, 486 PROT_TYPE_KEYC = 1,
486 PROT_TYPE_ALC = 2, 487 PROT_TYPE_ALC = 2,
487 PROT_TYPE_DAT = 3, 488 PROT_TYPE_DAT = 3,
489 PROT_TYPE_IEP = 4,
488}; 490};
489 491
490static int trans_exc(struct kvm_vcpu *vcpu, int code, unsigned long gva, 492static int trans_exc(struct kvm_vcpu *vcpu, int code, unsigned long gva,
@@ -500,6 +502,9 @@ static int trans_exc(struct kvm_vcpu *vcpu, int code, unsigned long gva,
500 switch (code) { 502 switch (code) {
501 case PGM_PROTECTION: 503 case PGM_PROTECTION:
502 switch (prot) { 504 switch (prot) {
505 case PROT_TYPE_IEP:
506 tec->b61 = 1;
507 /* FALL THROUGH */
503 case PROT_TYPE_LA: 508 case PROT_TYPE_LA:
504 tec->b56 = 1; 509 tec->b56 = 1;
505 break; 510 break;
@@ -591,6 +596,7 @@ static int deref_table(struct kvm *kvm, unsigned long gpa, unsigned long *val)
591 * @gpa: points to where guest physical (absolute) address should be stored 596 * @gpa: points to where guest physical (absolute) address should be stored
592 * @asce: effective asce 597 * @asce: effective asce
593 * @mode: indicates the access mode to be used 598 * @mode: indicates the access mode to be used
599 * @prot: returns the type for protection exceptions
594 * 600 *
595 * Translate a guest virtual address into a guest absolute address by means 601 * Translate a guest virtual address into a guest absolute address by means
596 * of dynamic address translation as specified by the architecture. 602 * of dynamic address translation as specified by the architecture.
@@ -606,19 +612,21 @@ static int deref_table(struct kvm *kvm, unsigned long gpa, unsigned long *val)
606 */ 612 */
607static unsigned long guest_translate(struct kvm_vcpu *vcpu, unsigned long gva, 613static unsigned long guest_translate(struct kvm_vcpu *vcpu, unsigned long gva,
608 unsigned long *gpa, const union asce asce, 614 unsigned long *gpa, const union asce asce,
609 enum gacc_mode mode) 615 enum gacc_mode mode, enum prot_type *prot)
610{ 616{
611 union vaddress vaddr = {.addr = gva}; 617 union vaddress vaddr = {.addr = gva};
612 union raddress raddr = {.addr = gva}; 618 union raddress raddr = {.addr = gva};
613 union page_table_entry pte; 619 union page_table_entry pte;
614 int dat_protection = 0; 620 int dat_protection = 0;
621 int iep_protection = 0;
615 union ctlreg0 ctlreg0; 622 union ctlreg0 ctlreg0;
616 unsigned long ptr; 623 unsigned long ptr;
617 int edat1, edat2; 624 int edat1, edat2, iep;
618 625
619 ctlreg0.val = vcpu->arch.sie_block->gcr[0]; 626 ctlreg0.val = vcpu->arch.sie_block->gcr[0];
620 edat1 = ctlreg0.edat && test_kvm_facility(vcpu->kvm, 8); 627 edat1 = ctlreg0.edat && test_kvm_facility(vcpu->kvm, 8);
621 edat2 = edat1 && test_kvm_facility(vcpu->kvm, 78); 628 edat2 = edat1 && test_kvm_facility(vcpu->kvm, 78);
629 iep = ctlreg0.iep && test_kvm_facility(vcpu->kvm, 130);
622 if (asce.r) 630 if (asce.r)
623 goto real_address; 631 goto real_address;
624 ptr = asce.origin * 4096; 632 ptr = asce.origin * 4096;
@@ -702,6 +710,7 @@ static unsigned long guest_translate(struct kvm_vcpu *vcpu, unsigned long gva,
702 return PGM_TRANSLATION_SPEC; 710 return PGM_TRANSLATION_SPEC;
703 if (rtte.fc && edat2) { 711 if (rtte.fc && edat2) {
704 dat_protection |= rtte.fc1.p; 712 dat_protection |= rtte.fc1.p;
713 iep_protection = rtte.fc1.iep;
705 raddr.rfaa = rtte.fc1.rfaa; 714 raddr.rfaa = rtte.fc1.rfaa;
706 goto absolute_address; 715 goto absolute_address;
707 } 716 }
@@ -729,6 +738,7 @@ static unsigned long guest_translate(struct kvm_vcpu *vcpu, unsigned long gva,
729 return PGM_TRANSLATION_SPEC; 738 return PGM_TRANSLATION_SPEC;
730 if (ste.fc && edat1) { 739 if (ste.fc && edat1) {
731 dat_protection |= ste.fc1.p; 740 dat_protection |= ste.fc1.p;
741 iep_protection = ste.fc1.iep;
732 raddr.sfaa = ste.fc1.sfaa; 742 raddr.sfaa = ste.fc1.sfaa;
733 goto absolute_address; 743 goto absolute_address;
734 } 744 }
@@ -745,12 +755,19 @@ static unsigned long guest_translate(struct kvm_vcpu *vcpu, unsigned long gva,
745 if (pte.z) 755 if (pte.z)
746 return PGM_TRANSLATION_SPEC; 756 return PGM_TRANSLATION_SPEC;
747 dat_protection |= pte.p; 757 dat_protection |= pte.p;
758 iep_protection = pte.iep;
748 raddr.pfra = pte.pfra; 759 raddr.pfra = pte.pfra;
749real_address: 760real_address:
750 raddr.addr = kvm_s390_real_to_abs(vcpu, raddr.addr); 761 raddr.addr = kvm_s390_real_to_abs(vcpu, raddr.addr);
751absolute_address: 762absolute_address:
752 if (mode == GACC_STORE && dat_protection) 763 if (mode == GACC_STORE && dat_protection) {
764 *prot = PROT_TYPE_DAT;
753 return PGM_PROTECTION; 765 return PGM_PROTECTION;
766 }
767 if (mode == GACC_IFETCH && iep_protection && iep) {
768 *prot = PROT_TYPE_IEP;
769 return PGM_PROTECTION;
770 }
754 if (kvm_is_error_gpa(vcpu->kvm, raddr.addr)) 771 if (kvm_is_error_gpa(vcpu->kvm, raddr.addr))
755 return PGM_ADDRESSING; 772 return PGM_ADDRESSING;
756 *gpa = raddr.addr; 773 *gpa = raddr.addr;
@@ -782,6 +799,7 @@ static int guest_page_range(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar,
782{ 799{
783 psw_t *psw = &vcpu->arch.sie_block->gpsw; 800 psw_t *psw = &vcpu->arch.sie_block->gpsw;
784 int lap_enabled, rc = 0; 801 int lap_enabled, rc = 0;
802 enum prot_type prot;
785 803
786 lap_enabled = low_address_protection_enabled(vcpu, asce); 804 lap_enabled = low_address_protection_enabled(vcpu, asce);
787 while (nr_pages) { 805 while (nr_pages) {
@@ -791,7 +809,7 @@ static int guest_page_range(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar,
791 PROT_TYPE_LA); 809 PROT_TYPE_LA);
792 ga &= PAGE_MASK; 810 ga &= PAGE_MASK;
793 if (psw_bits(*psw).t) { 811 if (psw_bits(*psw).t) {
794 rc = guest_translate(vcpu, ga, pages, asce, mode); 812 rc = guest_translate(vcpu, ga, pages, asce, mode, &prot);
795 if (rc < 0) 813 if (rc < 0)
796 return rc; 814 return rc;
797 } else { 815 } else {
@@ -800,7 +818,7 @@ static int guest_page_range(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar,
800 rc = PGM_ADDRESSING; 818 rc = PGM_ADDRESSING;
801 } 819 }
802 if (rc) 820 if (rc)
803 return trans_exc(vcpu, rc, ga, ar, mode, PROT_TYPE_DAT); 821 return trans_exc(vcpu, rc, ga, ar, mode, prot);
804 ga += PAGE_SIZE; 822 ga += PAGE_SIZE;
805 pages++; 823 pages++;
806 nr_pages--; 824 nr_pages--;
@@ -886,6 +904,7 @@ int guest_translate_address(struct kvm_vcpu *vcpu, unsigned long gva, u8 ar,
886 unsigned long *gpa, enum gacc_mode mode) 904 unsigned long *gpa, enum gacc_mode mode)
887{ 905{
888 psw_t *psw = &vcpu->arch.sie_block->gpsw; 906 psw_t *psw = &vcpu->arch.sie_block->gpsw;
907 enum prot_type prot;
889 union asce asce; 908 union asce asce;
890 int rc; 909 int rc;
891 910
@@ -900,9 +919,9 @@ int guest_translate_address(struct kvm_vcpu *vcpu, unsigned long gva, u8 ar,
900 } 919 }
901 920
902 if (psw_bits(*psw).t && !asce.r) { /* Use DAT? */ 921 if (psw_bits(*psw).t && !asce.r) { /* Use DAT? */
903 rc = guest_translate(vcpu, gva, gpa, asce, mode); 922 rc = guest_translate(vcpu, gva, gpa, asce, mode, &prot);
904 if (rc > 0) 923 if (rc > 0)
905 return trans_exc(vcpu, rc, gva, 0, mode, PROT_TYPE_DAT); 924 return trans_exc(vcpu, rc, gva, 0, mode, prot);
906 } else { 925 } else {
907 *gpa = kvm_s390_real_to_abs(vcpu, gva); 926 *gpa = kvm_s390_real_to_abs(vcpu, gva);
908 if (kvm_is_error_gpa(vcpu->kvm, *gpa)) 927 if (kvm_is_error_gpa(vcpu->kvm, *gpa))