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