1 /* 2 * kvm guest debug support 3 * 4 * Copyright IBM Corp. 2014 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License (version 2 only) 8 * as published by the Free Software Foundation. 9 * 10 * Author(s): David Hildenbrand <dahi@linux.vnet.ibm.com> 11 */ 12 #include <linux/kvm_host.h> 13 #include <linux/errno.h> 14 #include "kvm-s390.h" 15 #include "gaccess.h" 16 17 /* 18 * Extends the address range given by *start and *stop to include the address 19 * range starting with estart and the length len. Takes care of overflowing 20 * intervals and tries to minimize the overall intervall size. 21 */ 22 static void extend_address_range(u64 *start, u64 *stop, u64 estart, int len) 23 { 24 u64 estop; 25 26 if (len > 0) 27 len--; 28 else 29 len = 0; 30 31 estop = estart + len; 32 33 /* 0-0 range represents "not set" */ 34 if ((*start == 0) && (*stop == 0)) { 35 *start = estart; 36 *stop = estop; 37 } else if (*start <= *stop) { 38 /* increase the existing range */ 39 if (estart < *start) 40 *start = estart; 41 if (estop > *stop) 42 *stop = estop; 43 } else { 44 /* "overflowing" interval, whereby *stop > *start */ 45 if (estart <= *stop) { 46 if (estop > *stop) 47 *stop = estop; 48 } else if (estop > *start) { 49 if (estart < *start) 50 *start = estart; 51 } 52 /* minimize the range */ 53 else if ((estop - *stop) < (*start - estart)) 54 *stop = estop; 55 else 56 *start = estart; 57 } 58 } 59 60 #define MAX_INST_SIZE 6 61 62 static void enable_all_hw_bp(struct kvm_vcpu *vcpu) 63 { 64 unsigned long start, len; 65 u64 *cr9 = &vcpu->arch.sie_block->gcr[9]; 66 u64 *cr10 = &vcpu->arch.sie_block->gcr[10]; 67 u64 *cr11 = &vcpu->arch.sie_block->gcr[11]; 68 int i; 69 70 if (vcpu->arch.guestdbg.nr_hw_bp <= 0 || 71 vcpu->arch.guestdbg.hw_bp_info == NULL) 72 return; 73 74 /* 75 * If the guest is not interrested in branching events, we can savely 76 * limit them to the PER address range. 77 */ 78 if (!(*cr9 & PER_EVENT_BRANCH)) 79 *cr9 |= PER_CONTROL_BRANCH_ADDRESS; 80 *cr9 |= PER_EVENT_IFETCH | PER_EVENT_BRANCH; 81 82 for (i = 0; i < vcpu->arch.guestdbg.nr_hw_bp; i++) { 83 start = vcpu->arch.guestdbg.hw_bp_info[i].addr; 84 len = vcpu->arch.guestdbg.hw_bp_info[i].len; 85 86 /* 87 * The instruction in front of the desired bp has to 88 * report instruction-fetching events 89 */ 90 if (start < MAX_INST_SIZE) { 91 len += start; 92 start = 0; 93 } else { 94 start -= MAX_INST_SIZE; 95 len += MAX_INST_SIZE; 96 } 97 98 extend_address_range(cr10, cr11, start, len); 99 } 100 } 101 102 static void enable_all_hw_wp(struct kvm_vcpu *vcpu) 103 { 104 unsigned long start, len; 105 u64 *cr9 = &vcpu->arch.sie_block->gcr[9]; 106 u64 *cr10 = &vcpu->arch.sie_block->gcr[10]; 107 u64 *cr11 = &vcpu->arch.sie_block->gcr[11]; 108 int i; 109 110 if (vcpu->arch.guestdbg.nr_hw_wp <= 0 || 111 vcpu->arch.guestdbg.hw_wp_info == NULL) 112 return; 113 114 /* if host uses storage alternation for special address 115 * spaces, enable all events and give all to the guest */ 116 if (*cr9 & PER_EVENT_STORE && *cr9 & PER_CONTROL_ALTERATION) { 117 *cr9 &= ~PER_CONTROL_ALTERATION; 118 *cr10 = 0; 119 *cr11 = PSW_ADDR_INSN; 120 } else { 121 *cr9 &= ~PER_CONTROL_ALTERATION; 122 *cr9 |= PER_EVENT_STORE; 123 124 for (i = 0; i < vcpu->arch.guestdbg.nr_hw_wp; i++) { 125 start = vcpu->arch.guestdbg.hw_wp_info[i].addr; 126 len = vcpu->arch.guestdbg.hw_wp_info[i].len; 127 128 extend_address_range(cr10, cr11, start, len); 129 } 130 } 131 } 132 133 void kvm_s390_backup_guest_per_regs(struct kvm_vcpu *vcpu) 134 { 135 vcpu->arch.guestdbg.cr0 = vcpu->arch.sie_block->gcr[0]; 136 vcpu->arch.guestdbg.cr9 = vcpu->arch.sie_block->gcr[9]; 137 vcpu->arch.guestdbg.cr10 = vcpu->arch.sie_block->gcr[10]; 138 vcpu->arch.guestdbg.cr11 = vcpu->arch.sie_block->gcr[11]; 139 } 140 141 void kvm_s390_restore_guest_per_regs(struct kvm_vcpu *vcpu) 142 { 143 vcpu->arch.sie_block->gcr[0] = vcpu->arch.guestdbg.cr0; 144 vcpu->arch.sie_block->gcr[9] = vcpu->arch.guestdbg.cr9; 145 vcpu->arch.sie_block->gcr[10] = vcpu->arch.guestdbg.cr10; 146 vcpu->arch.sie_block->gcr[11] = vcpu->arch.guestdbg.cr11; 147 } 148 149 void kvm_s390_patch_guest_per_regs(struct kvm_vcpu *vcpu) 150 { 151 /* 152 * TODO: if guest psw has per enabled, otherwise 0s! 153 * This reduces the amount of reported events. 154 * Need to intercept all psw changes! 155 */ 156 157 if (guestdbg_sstep_enabled(vcpu)) { 158 /* disable timer (clock-comparator) interrupts */ 159 vcpu->arch.sie_block->gcr[0] &= ~0x800ul; 160 vcpu->arch.sie_block->gcr[9] |= PER_EVENT_IFETCH; 161 vcpu->arch.sie_block->gcr[10] = 0; 162 vcpu->arch.sie_block->gcr[11] = PSW_ADDR_INSN; 163 } 164 165 if (guestdbg_hw_bp_enabled(vcpu)) { 166 enable_all_hw_bp(vcpu); 167 enable_all_hw_wp(vcpu); 168 } 169 170 /* TODO: Instruction-fetching-nullification not allowed for now */ 171 if (vcpu->arch.sie_block->gcr[9] & PER_EVENT_NULLIFICATION) 172 vcpu->arch.sie_block->gcr[9] &= ~PER_EVENT_NULLIFICATION; 173 } 174 175 #define MAX_WP_SIZE 100 176 177 static int __import_wp_info(struct kvm_vcpu *vcpu, 178 struct kvm_hw_breakpoint *bp_data, 179 struct kvm_hw_wp_info_arch *wp_info) 180 { 181 int ret = 0; 182 wp_info->len = bp_data->len; 183 wp_info->addr = bp_data->addr; 184 wp_info->phys_addr = bp_data->phys_addr; 185 wp_info->old_data = NULL; 186 187 if (wp_info->len < 0 || wp_info->len > MAX_WP_SIZE) 188 return -EINVAL; 189 190 wp_info->old_data = kmalloc(bp_data->len, GFP_KERNEL); 191 if (!wp_info->old_data) 192 return -ENOMEM; 193 /* try to backup the original value */ 194 ret = read_guest_abs(vcpu, wp_info->phys_addr, wp_info->old_data, 195 wp_info->len); 196 if (ret) { 197 kfree(wp_info->old_data); 198 wp_info->old_data = NULL; 199 } 200 201 return ret; 202 } 203 204 #define MAX_BP_COUNT 50 205 206 int kvm_s390_import_bp_data(struct kvm_vcpu *vcpu, 207 struct kvm_guest_debug *dbg) 208 { 209 int ret = 0, nr_wp = 0, nr_bp = 0, i, size; 210 struct kvm_hw_breakpoint *bp_data = NULL; 211 struct kvm_hw_wp_info_arch *wp_info = NULL; 212 struct kvm_hw_bp_info_arch *bp_info = NULL; 213 214 if (dbg->arch.nr_hw_bp <= 0 || !dbg->arch.hw_bp) 215 return 0; 216 else if (dbg->arch.nr_hw_bp > MAX_BP_COUNT) 217 return -EINVAL; 218 219 size = dbg->arch.nr_hw_bp * sizeof(struct kvm_hw_breakpoint); 220 bp_data = kmalloc(size, GFP_KERNEL); 221 if (!bp_data) { 222 ret = -ENOMEM; 223 goto error; 224 } 225 226 if (copy_from_user(bp_data, dbg->arch.hw_bp, size)) { 227 ret = -EFAULT; 228 goto error; 229 } 230 231 for (i = 0; i < dbg->arch.nr_hw_bp; i++) { 232 switch (bp_data[i].type) { 233 case KVM_HW_WP_WRITE: 234 nr_wp++; 235 break; 236 case KVM_HW_BP: 237 nr_bp++; 238 break; 239 default: 240 break; 241 } 242 } 243 244 size = nr_wp * sizeof(struct kvm_hw_wp_info_arch); 245 if (size > 0) { 246 wp_info = kmalloc(size, GFP_KERNEL); 247 if (!wp_info) { 248 ret = -ENOMEM; 249 goto error; 250 } 251 } 252 size = nr_bp * sizeof(struct kvm_hw_bp_info_arch); 253 if (size > 0) { 254 bp_info = kmalloc(size, GFP_KERNEL); 255 if (!bp_info) { 256 ret = -ENOMEM; 257 goto error; 258 } 259 } 260 261 for (nr_wp = 0, nr_bp = 0, i = 0; i < dbg->arch.nr_hw_bp; i++) { 262 switch (bp_data[i].type) { 263 case KVM_HW_WP_WRITE: 264 ret = __import_wp_info(vcpu, &bp_data[i], 265 &wp_info[nr_wp]); 266 if (ret) 267 goto error; 268 nr_wp++; 269 break; 270 case KVM_HW_BP: 271 bp_info[nr_bp].len = bp_data[i].len; 272 bp_info[nr_bp].addr = bp_data[i].addr; 273 nr_bp++; 274 break; 275 } 276 } 277 278 vcpu->arch.guestdbg.nr_hw_bp = nr_bp; 279 vcpu->arch.guestdbg.hw_bp_info = bp_info; 280 vcpu->arch.guestdbg.nr_hw_wp = nr_wp; 281 vcpu->arch.guestdbg.hw_wp_info = wp_info; 282 return 0; 283 error: 284 kfree(bp_data); 285 kfree(wp_info); 286 kfree(bp_info); 287 return ret; 288 } 289 290 void kvm_s390_clear_bp_data(struct kvm_vcpu *vcpu) 291 { 292 int i; 293 struct kvm_hw_wp_info_arch *hw_wp_info = NULL; 294 295 for (i = 0; i < vcpu->arch.guestdbg.nr_hw_wp; i++) { 296 hw_wp_info = &vcpu->arch.guestdbg.hw_wp_info[i]; 297 kfree(hw_wp_info->old_data); 298 hw_wp_info->old_data = NULL; 299 } 300 kfree(vcpu->arch.guestdbg.hw_wp_info); 301 vcpu->arch.guestdbg.hw_wp_info = NULL; 302 303 kfree(vcpu->arch.guestdbg.hw_bp_info); 304 vcpu->arch.guestdbg.hw_bp_info = NULL; 305 306 vcpu->arch.guestdbg.nr_hw_wp = 0; 307 vcpu->arch.guestdbg.nr_hw_bp = 0; 308 } 309 310 static inline int in_addr_range(u64 addr, u64 a, u64 b) 311 { 312 if (a <= b) 313 return (addr >= a) && (addr <= b); 314 else 315 /* "overflowing" interval */ 316 return (addr <= a) && (addr >= b); 317 } 318 319 #define end_of_range(bp_info) (bp_info->addr + bp_info->len - 1) 320 321 static struct kvm_hw_bp_info_arch *find_hw_bp(struct kvm_vcpu *vcpu, 322 unsigned long addr) 323 { 324 struct kvm_hw_bp_info_arch *bp_info = vcpu->arch.guestdbg.hw_bp_info; 325 int i; 326 327 if (vcpu->arch.guestdbg.nr_hw_bp == 0) 328 return NULL; 329 330 for (i = 0; i < vcpu->arch.guestdbg.nr_hw_bp; i++) { 331 /* addr is directly the start or in the range of a bp */ 332 if (addr == bp_info->addr) 333 goto found; 334 if (bp_info->len > 0 && 335 in_addr_range(addr, bp_info->addr, end_of_range(bp_info))) 336 goto found; 337 338 bp_info++; 339 } 340 341 return NULL; 342 found: 343 return bp_info; 344 } 345 346 static struct kvm_hw_wp_info_arch *any_wp_changed(struct kvm_vcpu *vcpu) 347 { 348 int i; 349 struct kvm_hw_wp_info_arch *wp_info = NULL; 350 void *temp = NULL; 351 352 if (vcpu->arch.guestdbg.nr_hw_wp == 0) 353 return NULL; 354 355 for (i = 0; i < vcpu->arch.guestdbg.nr_hw_wp; i++) { 356 wp_info = &vcpu->arch.guestdbg.hw_wp_info[i]; 357 if (!wp_info || !wp_info->old_data || wp_info->len <= 0) 358 continue; 359 360 temp = kmalloc(wp_info->len, GFP_KERNEL); 361 if (!temp) 362 continue; 363 364 /* refetch the wp data and compare it to the old value */ 365 if (!read_guest_abs(vcpu, wp_info->phys_addr, temp, 366 wp_info->len)) { 367 if (memcmp(temp, wp_info->old_data, wp_info->len)) { 368 kfree(temp); 369 return wp_info; 370 } 371 } 372 kfree(temp); 373 temp = NULL; 374 } 375 376 return NULL; 377 } 378 379 void kvm_s390_prepare_debug_exit(struct kvm_vcpu *vcpu) 380 { 381 vcpu->run->exit_reason = KVM_EXIT_DEBUG; 382 vcpu->guest_debug &= ~KVM_GUESTDBG_EXIT_PENDING; 383 } 384 385 #define per_bp_event(code) \ 386 (code & (PER_EVENT_IFETCH | PER_EVENT_BRANCH)) 387 #define per_write_wp_event(code) \ 388 (code & (PER_EVENT_STORE | PER_EVENT_STORE_REAL)) 389 390 static int debug_exit_required(struct kvm_vcpu *vcpu) 391 { 392 u32 perc = (vcpu->arch.sie_block->perc << 24); 393 struct kvm_debug_exit_arch *debug_exit = &vcpu->run->debug.arch; 394 struct kvm_hw_wp_info_arch *wp_info = NULL; 395 struct kvm_hw_bp_info_arch *bp_info = NULL; 396 unsigned long addr = vcpu->arch.sie_block->gpsw.addr; 397 unsigned long peraddr = vcpu->arch.sie_block->peraddr; 398 399 if (guestdbg_hw_bp_enabled(vcpu)) { 400 if (per_write_wp_event(perc) && 401 vcpu->arch.guestdbg.nr_hw_wp > 0) { 402 wp_info = any_wp_changed(vcpu); 403 if (wp_info) { 404 debug_exit->addr = wp_info->addr; 405 debug_exit->type = KVM_HW_WP_WRITE; 406 goto exit_required; 407 } 408 } 409 if (per_bp_event(perc) && 410 vcpu->arch.guestdbg.nr_hw_bp > 0) { 411 bp_info = find_hw_bp(vcpu, addr); 412 /* remove duplicate events if PC==PER address */ 413 if (bp_info && (addr != peraddr)) { 414 debug_exit->addr = addr; 415 debug_exit->type = KVM_HW_BP; 416 vcpu->arch.guestdbg.last_bp = addr; 417 goto exit_required; 418 } 419 /* breakpoint missed */ 420 bp_info = find_hw_bp(vcpu, peraddr); 421 if (bp_info && vcpu->arch.guestdbg.last_bp != peraddr) { 422 debug_exit->addr = peraddr; 423 debug_exit->type = KVM_HW_BP; 424 goto exit_required; 425 } 426 } 427 } 428 if (guestdbg_sstep_enabled(vcpu) && per_bp_event(perc)) { 429 debug_exit->addr = addr; 430 debug_exit->type = KVM_SINGLESTEP; 431 goto exit_required; 432 } 433 434 return 0; 435 exit_required: 436 return 1; 437 } 438 439 #define guest_per_enabled(vcpu) \ 440 (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PER) 441 442 static void filter_guest_per_event(struct kvm_vcpu *vcpu) 443 { 444 u32 perc = vcpu->arch.sie_block->perc << 24; 445 u64 peraddr = vcpu->arch.sie_block->peraddr; 446 u64 addr = vcpu->arch.sie_block->gpsw.addr; 447 u64 cr9 = vcpu->arch.sie_block->gcr[9]; 448 u64 cr10 = vcpu->arch.sie_block->gcr[10]; 449 u64 cr11 = vcpu->arch.sie_block->gcr[11]; 450 /* filter all events, demanded by the guest */ 451 u32 guest_perc = perc & cr9 & PER_EVENT_MASK; 452 453 if (!guest_per_enabled(vcpu)) 454 guest_perc = 0; 455 456 /* filter "successful-branching" events */ 457 if (guest_perc & PER_EVENT_BRANCH && 458 cr9 & PER_CONTROL_BRANCH_ADDRESS && 459 !in_addr_range(addr, cr10, cr11)) 460 guest_perc &= ~PER_EVENT_BRANCH; 461 462 /* filter "instruction-fetching" events */ 463 if (guest_perc & PER_EVENT_IFETCH && 464 !in_addr_range(peraddr, cr10, cr11)) 465 guest_perc &= ~PER_EVENT_IFETCH; 466 467 /* All other PER events will be given to the guest */ 468 /* TODO: Check alterated address/address space */ 469 470 vcpu->arch.sie_block->perc = guest_perc >> 24; 471 472 if (!guest_perc) 473 vcpu->arch.sie_block->iprcc &= ~PGM_PER; 474 } 475 476 void kvm_s390_handle_per_event(struct kvm_vcpu *vcpu) 477 { 478 if (debug_exit_required(vcpu)) 479 vcpu->guest_debug |= KVM_GUESTDBG_EXIT_PENDING; 480 481 filter_guest_per_event(vcpu); 482 } 483