1 // SPDX-License-Identifier: GPL-2.0 2 #include <test_util.h> 3 #include <kvm_util.h> 4 #include <processor.h> 5 #include <linux/bitfield.h> 6 7 #define MDSCR_KDE (1 << 13) 8 #define MDSCR_MDE (1 << 15) 9 #define MDSCR_SS (1 << 0) 10 11 #define DBGBCR_LEN8 (0xff << 5) 12 #define DBGBCR_EXEC (0x0 << 3) 13 #define DBGBCR_EL1 (0x1 << 1) 14 #define DBGBCR_E (0x1 << 0) 15 16 #define DBGWCR_LEN8 (0xff << 5) 17 #define DBGWCR_RD (0x1 << 3) 18 #define DBGWCR_WR (0x2 << 3) 19 #define DBGWCR_EL1 (0x1 << 1) 20 #define DBGWCR_E (0x1 << 0) 21 22 #define SPSR_D (1 << 9) 23 #define SPSR_SS (1 << 21) 24 25 extern unsigned char sw_bp, sw_bp2, hw_bp, hw_bp2, bp_svc, bp_brk, hw_wp, ss_start; 26 extern unsigned char iter_ss_begin, iter_ss_end; 27 static volatile uint64_t sw_bp_addr, hw_bp_addr; 28 static volatile uint64_t wp_addr, wp_data_addr; 29 static volatile uint64_t svc_addr; 30 static volatile uint64_t ss_addr[4], ss_idx; 31 #define PC(v) ((uint64_t)&(v)) 32 33 #define GEN_DEBUG_WRITE_REG(reg_name) \ 34 static void write_##reg_name(int num, uint64_t val) \ 35 { \ 36 switch (num) { \ 37 case 0: \ 38 write_sysreg(val, reg_name##0_el1); \ 39 break; \ 40 case 1: \ 41 write_sysreg(val, reg_name##1_el1); \ 42 break; \ 43 case 2: \ 44 write_sysreg(val, reg_name##2_el1); \ 45 break; \ 46 case 3: \ 47 write_sysreg(val, reg_name##3_el1); \ 48 break; \ 49 case 4: \ 50 write_sysreg(val, reg_name##4_el1); \ 51 break; \ 52 case 5: \ 53 write_sysreg(val, reg_name##5_el1); \ 54 break; \ 55 case 6: \ 56 write_sysreg(val, reg_name##6_el1); \ 57 break; \ 58 case 7: \ 59 write_sysreg(val, reg_name##7_el1); \ 60 break; \ 61 case 8: \ 62 write_sysreg(val, reg_name##8_el1); \ 63 break; \ 64 case 9: \ 65 write_sysreg(val, reg_name##9_el1); \ 66 break; \ 67 case 10: \ 68 write_sysreg(val, reg_name##10_el1); \ 69 break; \ 70 case 11: \ 71 write_sysreg(val, reg_name##11_el1); \ 72 break; \ 73 case 12: \ 74 write_sysreg(val, reg_name##12_el1); \ 75 break; \ 76 case 13: \ 77 write_sysreg(val, reg_name##13_el1); \ 78 break; \ 79 case 14: \ 80 write_sysreg(val, reg_name##14_el1); \ 81 break; \ 82 case 15: \ 83 write_sysreg(val, reg_name##15_el1); \ 84 break; \ 85 default: \ 86 GUEST_ASSERT(0); \ 87 } \ 88 } 89 90 /* Define write_dbgbcr()/write_dbgbvr()/write_dbgwcr()/write_dbgwvr() */ 91 GEN_DEBUG_WRITE_REG(dbgbcr) 92 GEN_DEBUG_WRITE_REG(dbgbvr) 93 GEN_DEBUG_WRITE_REG(dbgwcr) 94 GEN_DEBUG_WRITE_REG(dbgwvr) 95 96 static void reset_debug_state(void) 97 { 98 asm volatile("msr daifset, #8"); 99 100 write_sysreg(0, osdlr_el1); 101 write_sysreg(0, oslar_el1); 102 isb(); 103 104 write_sysreg(0, mdscr_el1); 105 /* This test only uses the first bp and wp slot. */ 106 write_sysreg(0, dbgbvr0_el1); 107 write_sysreg(0, dbgbcr0_el1); 108 write_sysreg(0, dbgwcr0_el1); 109 write_sysreg(0, dbgwvr0_el1); 110 isb(); 111 } 112 113 static void enable_os_lock(void) 114 { 115 write_sysreg(1, oslar_el1); 116 isb(); 117 118 GUEST_ASSERT(read_sysreg(oslsr_el1) & 2); 119 } 120 121 static void install_wp(uint64_t addr) 122 { 123 uint32_t wcr; 124 uint32_t mdscr; 125 126 wcr = DBGWCR_LEN8 | DBGWCR_RD | DBGWCR_WR | DBGWCR_EL1 | DBGWCR_E; 127 write_dbgwcr(0, wcr); 128 write_dbgwvr(0, addr); 129 130 isb(); 131 132 asm volatile("msr daifclr, #8"); 133 134 mdscr = read_sysreg(mdscr_el1) | MDSCR_KDE | MDSCR_MDE; 135 write_sysreg(mdscr, mdscr_el1); 136 isb(); 137 } 138 139 static void install_hw_bp(uint64_t addr) 140 { 141 uint32_t bcr; 142 uint32_t mdscr; 143 144 bcr = DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1 | DBGBCR_E; 145 write_dbgbcr(0, bcr); 146 write_dbgbvr(0, addr); 147 isb(); 148 149 asm volatile("msr daifclr, #8"); 150 151 mdscr = read_sysreg(mdscr_el1) | MDSCR_KDE | MDSCR_MDE; 152 write_sysreg(mdscr, mdscr_el1); 153 isb(); 154 } 155 156 static void install_ss(void) 157 { 158 uint32_t mdscr; 159 160 asm volatile("msr daifclr, #8"); 161 162 mdscr = read_sysreg(mdscr_el1) | MDSCR_KDE | MDSCR_SS; 163 write_sysreg(mdscr, mdscr_el1); 164 isb(); 165 } 166 167 static volatile char write_data; 168 169 static void guest_code(void) 170 { 171 GUEST_SYNC(0); 172 173 /* Software-breakpoint */ 174 reset_debug_state(); 175 asm volatile("sw_bp: brk #0"); 176 GUEST_ASSERT_EQ(sw_bp_addr, PC(sw_bp)); 177 178 GUEST_SYNC(1); 179 180 /* Hardware-breakpoint */ 181 reset_debug_state(); 182 install_hw_bp(PC(hw_bp)); 183 asm volatile("hw_bp: nop"); 184 GUEST_ASSERT_EQ(hw_bp_addr, PC(hw_bp)); 185 186 GUEST_SYNC(2); 187 188 /* Hardware-breakpoint + svc */ 189 reset_debug_state(); 190 install_hw_bp(PC(bp_svc)); 191 asm volatile("bp_svc: svc #0"); 192 GUEST_ASSERT_EQ(hw_bp_addr, PC(bp_svc)); 193 GUEST_ASSERT_EQ(svc_addr, PC(bp_svc) + 4); 194 195 GUEST_SYNC(3); 196 197 /* Hardware-breakpoint + software-breakpoint */ 198 reset_debug_state(); 199 install_hw_bp(PC(bp_brk)); 200 asm volatile("bp_brk: brk #0"); 201 GUEST_ASSERT_EQ(sw_bp_addr, PC(bp_brk)); 202 GUEST_ASSERT_EQ(hw_bp_addr, PC(bp_brk)); 203 204 GUEST_SYNC(4); 205 206 /* Watchpoint */ 207 reset_debug_state(); 208 install_wp(PC(write_data)); 209 write_data = 'x'; 210 GUEST_ASSERT_EQ(write_data, 'x'); 211 GUEST_ASSERT_EQ(wp_data_addr, PC(write_data)); 212 213 GUEST_SYNC(5); 214 215 /* Single-step */ 216 reset_debug_state(); 217 install_ss(); 218 ss_idx = 0; 219 asm volatile("ss_start:\n" 220 "mrs x0, esr_el1\n" 221 "add x0, x0, #1\n" 222 "msr daifset, #8\n" 223 : : : "x0"); 224 GUEST_ASSERT_EQ(ss_addr[0], PC(ss_start)); 225 GUEST_ASSERT_EQ(ss_addr[1], PC(ss_start) + 4); 226 GUEST_ASSERT_EQ(ss_addr[2], PC(ss_start) + 8); 227 228 GUEST_SYNC(6); 229 230 /* OS Lock does not block software-breakpoint */ 231 reset_debug_state(); 232 enable_os_lock(); 233 sw_bp_addr = 0; 234 asm volatile("sw_bp2: brk #0"); 235 GUEST_ASSERT_EQ(sw_bp_addr, PC(sw_bp2)); 236 237 GUEST_SYNC(7); 238 239 /* OS Lock blocking hardware-breakpoint */ 240 reset_debug_state(); 241 enable_os_lock(); 242 install_hw_bp(PC(hw_bp2)); 243 hw_bp_addr = 0; 244 asm volatile("hw_bp2: nop"); 245 GUEST_ASSERT_EQ(hw_bp_addr, 0); 246 247 GUEST_SYNC(8); 248 249 /* OS Lock blocking watchpoint */ 250 reset_debug_state(); 251 enable_os_lock(); 252 write_data = '\0'; 253 wp_data_addr = 0; 254 install_wp(PC(write_data)); 255 write_data = 'x'; 256 GUEST_ASSERT_EQ(write_data, 'x'); 257 GUEST_ASSERT_EQ(wp_data_addr, 0); 258 259 GUEST_SYNC(9); 260 261 /* OS Lock blocking single-step */ 262 reset_debug_state(); 263 enable_os_lock(); 264 ss_addr[0] = 0; 265 install_ss(); 266 ss_idx = 0; 267 asm volatile("mrs x0, esr_el1\n\t" 268 "add x0, x0, #1\n\t" 269 "msr daifset, #8\n\t" 270 : : : "x0"); 271 GUEST_ASSERT_EQ(ss_addr[0], 0); 272 273 GUEST_DONE(); 274 } 275 276 static void guest_sw_bp_handler(struct ex_regs *regs) 277 { 278 sw_bp_addr = regs->pc; 279 regs->pc += 4; 280 } 281 282 static void guest_hw_bp_handler(struct ex_regs *regs) 283 { 284 hw_bp_addr = regs->pc; 285 regs->pstate |= SPSR_D; 286 } 287 288 static void guest_wp_handler(struct ex_regs *regs) 289 { 290 wp_data_addr = read_sysreg(far_el1); 291 wp_addr = regs->pc; 292 regs->pstate |= SPSR_D; 293 } 294 295 static void guest_ss_handler(struct ex_regs *regs) 296 { 297 GUEST_ASSERT_1(ss_idx < 4, ss_idx); 298 ss_addr[ss_idx++] = regs->pc; 299 regs->pstate |= SPSR_SS; 300 } 301 302 static void guest_svc_handler(struct ex_regs *regs) 303 { 304 svc_addr = regs->pc; 305 } 306 307 enum single_step_op { 308 SINGLE_STEP_ENABLE = 0, 309 SINGLE_STEP_DISABLE = 1, 310 }; 311 312 static void guest_code_ss(int test_cnt) 313 { 314 uint64_t i; 315 uint64_t bvr, wvr, w_bvr, w_wvr; 316 317 for (i = 0; i < test_cnt; i++) { 318 /* Bits [1:0] of dbg{b,w}vr are RES0 */ 319 w_bvr = i << 2; 320 w_wvr = i << 2; 321 322 /* Enable Single Step execution */ 323 GUEST_SYNC(SINGLE_STEP_ENABLE); 324 325 /* 326 * The userspace will veriry that the pc is as expected during 327 * single step execution between iter_ss_begin and iter_ss_end. 328 */ 329 asm volatile("iter_ss_begin:nop\n"); 330 331 write_sysreg(w_bvr, dbgbvr0_el1); 332 write_sysreg(w_wvr, dbgwvr0_el1); 333 bvr = read_sysreg(dbgbvr0_el1); 334 wvr = read_sysreg(dbgwvr0_el1); 335 336 asm volatile("iter_ss_end:\n"); 337 338 /* Disable Single Step execution */ 339 GUEST_SYNC(SINGLE_STEP_DISABLE); 340 341 GUEST_ASSERT(bvr == w_bvr); 342 GUEST_ASSERT(wvr == w_wvr); 343 } 344 GUEST_DONE(); 345 } 346 347 static int debug_version(struct kvm_vcpu *vcpu) 348 { 349 uint64_t id_aa64dfr0; 350 351 vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1), &id_aa64dfr0); 352 return FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_DEBUGVER), id_aa64dfr0); 353 } 354 355 static void test_guest_debug_exceptions(void) 356 { 357 struct kvm_vcpu *vcpu; 358 struct kvm_vm *vm; 359 struct ucall uc; 360 int stage; 361 362 vm = vm_create_with_one_vcpu(&vcpu, guest_code); 363 ucall_init(vm, NULL); 364 365 vm_init_descriptor_tables(vm); 366 vcpu_init_descriptor_tables(vcpu); 367 368 vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT, 369 ESR_EC_BRK_INS, guest_sw_bp_handler); 370 vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT, 371 ESR_EC_HW_BP_CURRENT, guest_hw_bp_handler); 372 vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT, 373 ESR_EC_WP_CURRENT, guest_wp_handler); 374 vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT, 375 ESR_EC_SSTEP_CURRENT, guest_ss_handler); 376 vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT, 377 ESR_EC_SVC64, guest_svc_handler); 378 379 for (stage = 0; stage < 11; stage++) { 380 vcpu_run(vcpu); 381 382 switch (get_ucall(vcpu, &uc)) { 383 case UCALL_SYNC: 384 TEST_ASSERT(uc.args[1] == stage, 385 "Stage %d: Unexpected sync ucall, got %lx", 386 stage, (ulong)uc.args[1]); 387 break; 388 case UCALL_ABORT: 389 REPORT_GUEST_ASSERT_2(uc, "values: %#lx, %#lx"); 390 break; 391 case UCALL_DONE: 392 goto done; 393 default: 394 TEST_FAIL("Unknown ucall %lu", uc.cmd); 395 } 396 } 397 398 done: 399 kvm_vm_free(vm); 400 } 401 402 void test_single_step_from_userspace(int test_cnt) 403 { 404 struct kvm_vcpu *vcpu; 405 struct kvm_vm *vm; 406 struct ucall uc; 407 struct kvm_run *run; 408 uint64_t pc, cmd; 409 uint64_t test_pc = 0; 410 bool ss_enable = false; 411 struct kvm_guest_debug debug = {}; 412 413 vm = vm_create_with_one_vcpu(&vcpu, guest_code_ss); 414 ucall_init(vm, NULL); 415 run = vcpu->run; 416 vcpu_args_set(vcpu, 1, test_cnt); 417 418 while (1) { 419 vcpu_run(vcpu); 420 if (run->exit_reason != KVM_EXIT_DEBUG) { 421 cmd = get_ucall(vcpu, &uc); 422 if (cmd == UCALL_ABORT) { 423 REPORT_GUEST_ASSERT(uc); 424 /* NOT REACHED */ 425 } else if (cmd == UCALL_DONE) { 426 break; 427 } 428 429 TEST_ASSERT(cmd == UCALL_SYNC, 430 "Unexpected ucall cmd 0x%lx", cmd); 431 432 if (uc.args[1] == SINGLE_STEP_ENABLE) { 433 debug.control = KVM_GUESTDBG_ENABLE | 434 KVM_GUESTDBG_SINGLESTEP; 435 ss_enable = true; 436 } else { 437 debug.control = SINGLE_STEP_DISABLE; 438 ss_enable = false; 439 } 440 441 vcpu_guest_debug_set(vcpu, &debug); 442 continue; 443 } 444 445 TEST_ASSERT(ss_enable, "Unexpected KVM_EXIT_DEBUG"); 446 447 /* Check if the current pc is expected. */ 448 vcpu_get_reg(vcpu, ARM64_CORE_REG(regs.pc), &pc); 449 TEST_ASSERT(!test_pc || pc == test_pc, 450 "Unexpected pc 0x%lx (expected 0x%lx)", 451 pc, test_pc); 452 453 /* 454 * If the current pc is between iter_ss_bgin and 455 * iter_ss_end, the pc for the next KVM_EXIT_DEBUG should 456 * be the current pc + 4. 457 */ 458 if ((pc >= (uint64_t)&iter_ss_begin) && 459 (pc < (uint64_t)&iter_ss_end)) 460 test_pc = pc + 4; 461 else 462 test_pc = 0; 463 } 464 465 kvm_vm_free(vm); 466 } 467 468 static void help(char *name) 469 { 470 puts(""); 471 printf("Usage: %s [-h] [-i iterations of the single step test]\n", name); 472 puts(""); 473 exit(0); 474 } 475 476 int main(int argc, char *argv[]) 477 { 478 struct kvm_vcpu *vcpu; 479 struct kvm_vm *vm; 480 int opt; 481 int ss_iteration = 10000; 482 483 vm = vm_create_with_one_vcpu(&vcpu, guest_code); 484 __TEST_REQUIRE(debug_version(vcpu) >= 6, 485 "Armv8 debug architecture not supported."); 486 kvm_vm_free(vm); 487 488 while ((opt = getopt(argc, argv, "i:")) != -1) { 489 switch (opt) { 490 case 'i': 491 ss_iteration = atoi(optarg); 492 break; 493 case 'h': 494 default: 495 help(argv[0]); 496 break; 497 } 498 } 499 500 test_guest_debug_exceptions(); 501 test_single_step_from_userspace(ss_iteration); 502 503 return 0; 504 } 505