aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kvm/kvm-s390.c
diff options
context:
space:
mode:
authorDavid Hildenbrand <dahi@linux.vnet.ibm.com>2014-01-23 06:26:52 -0500
committerChristian Borntraeger <borntraeger@de.ibm.com>2014-04-22 07:24:51 -0400
commit27291e2165b6de70c476b7b675308113edd69a60 (patch)
tree1508e3bb47e7171c176d82ab4fa231947a267140 /arch/s390/kvm/kvm-s390.c
parentaf1827e773c983f1d601d674447aea89efdb1acb (diff)
KVM: s390: hardware support for guest debugging
This patch adds support to debug the guest using the PER facility on s390. Single-stepping, hardware breakpoints and hardware watchpoints are supported. In order to use the PER facility of the guest without it noticing it, the control registers of the guest have to be patched and access to them has to be intercepted(stctl, stctg, lctl, lctlg). All PER program interrupts have to be intercepted and only the relevant PER interrupts for the guest have to be given back. Special care has to be taken about repeated exits on the same hardware breakpoint. The intervention of the host in the guests PER configuration is not fully transparent. PER instruction nullification can not be used by the guest and too many storage alteration events may be reported to the guest (if it is activated for special address ranges only) when the host concurrently debugging it. Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Diffstat (limited to 'arch/s390/kvm/kvm-s390.c')
-rw-r--r--arch/s390/kvm/kvm-s390.c53
1 files changed, 51 insertions, 2 deletions
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 7ae8c26065fb..e6bbfe1a9474 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -934,10 +934,40 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
934 return -EINVAL; /* not implemented yet */ 934 return -EINVAL; /* not implemented yet */
935} 935}
936 936
937#define VALID_GUESTDBG_FLAGS (KVM_GUESTDBG_SINGLESTEP | \
938 KVM_GUESTDBG_USE_HW_BP | \
939 KVM_GUESTDBG_ENABLE)
940
937int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, 941int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
938 struct kvm_guest_debug *dbg) 942 struct kvm_guest_debug *dbg)
939{ 943{
940 return -EINVAL; /* not implemented yet */ 944 int rc = 0;
945
946 vcpu->guest_debug = 0;
947 kvm_s390_clear_bp_data(vcpu);
948
949 if (vcpu->guest_debug & ~VALID_GUESTDBG_FLAGS)
950 return -EINVAL;
951
952 if (dbg->control & KVM_GUESTDBG_ENABLE) {
953 vcpu->guest_debug = dbg->control;
954 /* enforce guest PER */
955 atomic_set_mask(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags);
956
957 if (dbg->control & KVM_GUESTDBG_USE_HW_BP)
958 rc = kvm_s390_import_bp_data(vcpu, dbg);
959 } else {
960 atomic_clear_mask(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags);
961 vcpu->arch.guestdbg.last_bp = 0;
962 }
963
964 if (rc) {
965 vcpu->guest_debug = 0;
966 kvm_s390_clear_bp_data(vcpu);
967 atomic_clear_mask(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags);
968 }
969
970 return rc;
941} 971}
942 972
943int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, 973int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
@@ -1095,6 +1125,11 @@ static int vcpu_pre_run(struct kvm_vcpu *vcpu)
1095 if (rc) 1125 if (rc)
1096 return rc; 1126 return rc;
1097 1127
1128 if (guestdbg_enabled(vcpu)) {
1129 kvm_s390_backup_guest_per_regs(vcpu);
1130 kvm_s390_patch_guest_per_regs(vcpu);
1131 }
1132
1098 vcpu->arch.sie_block->icptcode = 0; 1133 vcpu->arch.sie_block->icptcode = 0;
1099 cpuflags = atomic_read(&vcpu->arch.sie_block->cpuflags); 1134 cpuflags = atomic_read(&vcpu->arch.sie_block->cpuflags);
1100 VCPU_EVENT(vcpu, 6, "entering sie flags %x", cpuflags); 1135 VCPU_EVENT(vcpu, 6, "entering sie flags %x", cpuflags);
@@ -1111,6 +1146,9 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
1111 vcpu->arch.sie_block->icptcode); 1146 vcpu->arch.sie_block->icptcode);
1112 trace_kvm_s390_sie_exit(vcpu, vcpu->arch.sie_block->icptcode); 1147 trace_kvm_s390_sie_exit(vcpu, vcpu->arch.sie_block->icptcode);
1113 1148
1149 if (guestdbg_enabled(vcpu))
1150 kvm_s390_restore_guest_per_regs(vcpu);
1151
1114 if (exit_reason >= 0) { 1152 if (exit_reason >= 0) {
1115 rc = 0; 1153 rc = 0;
1116 } else if (kvm_is_ucontrol(vcpu->kvm)) { 1154 } else if (kvm_is_ucontrol(vcpu->kvm)) {
@@ -1176,7 +1214,7 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
1176 vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); 1214 vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
1177 1215
1178 rc = vcpu_post_run(vcpu, exit_reason); 1216 rc = vcpu_post_run(vcpu, exit_reason);
1179 } while (!signal_pending(current) && !rc); 1217 } while (!signal_pending(current) && !guestdbg_exit_pending(vcpu) && !rc);
1180 1218
1181 srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); 1219 srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
1182 return rc; 1220 return rc;
@@ -1187,6 +1225,11 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1187 int rc; 1225 int rc;
1188 sigset_t sigsaved; 1226 sigset_t sigsaved;
1189 1227
1228 if (guestdbg_exit_pending(vcpu)) {
1229 kvm_s390_prepare_debug_exit(vcpu);
1230 return 0;
1231 }
1232
1190 if (vcpu->sigset_active) 1233 if (vcpu->sigset_active)
1191 sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); 1234 sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
1192 1235
@@ -1199,6 +1242,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1199 case KVM_EXIT_S390_RESET: 1242 case KVM_EXIT_S390_RESET:
1200 case KVM_EXIT_S390_UCONTROL: 1243 case KVM_EXIT_S390_UCONTROL:
1201 case KVM_EXIT_S390_TSCH: 1244 case KVM_EXIT_S390_TSCH:
1245 case KVM_EXIT_DEBUG:
1202 break; 1246 break;
1203 default: 1247 default:
1204 BUG(); 1248 BUG();
@@ -1224,6 +1268,11 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1224 rc = -EINTR; 1268 rc = -EINTR;
1225 } 1269 }
1226 1270
1271 if (guestdbg_exit_pending(vcpu) && !rc) {
1272 kvm_s390_prepare_debug_exit(vcpu);
1273 rc = 0;
1274 }
1275
1227 if (rc == -EOPNOTSUPP) { 1276 if (rc == -EOPNOTSUPP) {
1228 /* intercept cannot be handled in-kernel, prepare kvm-run */ 1277 /* intercept cannot be handled in-kernel, prepare kvm-run */
1229 kvm_run->exit_reason = KVM_EXIT_S390_SIEIC; 1278 kvm_run->exit_reason = KVM_EXIT_S390_SIEIC;