debug-exceptions.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  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. #define MDSCR_KDE (1 << 13)
  7. #define MDSCR_MDE (1 << 15)
  8. #define MDSCR_SS (1 << 0)
  9. #define DBGBCR_LEN8 (0xff << 5)
  10. #define DBGBCR_EXEC (0x0 << 3)
  11. #define DBGBCR_EL1 (0x1 << 1)
  12. #define DBGBCR_E (0x1 << 0)
  13. #define DBGBCR_LBN_SHIFT 16
  14. #define DBGBCR_BT_SHIFT 20
  15. #define DBGBCR_BT_ADDR_LINK_CTX (0x1 << DBGBCR_BT_SHIFT)
  16. #define DBGBCR_BT_CTX_LINK (0x3 << DBGBCR_BT_SHIFT)
  17. #define DBGWCR_LEN8 (0xff << 5)
  18. #define DBGWCR_RD (0x1 << 3)
  19. #define DBGWCR_WR (0x2 << 3)
  20. #define DBGWCR_EL1 (0x1 << 1)
  21. #define DBGWCR_E (0x1 << 0)
  22. #define DBGWCR_LBN_SHIFT 16
  23. #define DBGWCR_WT_SHIFT 20
  24. #define DBGWCR_WT_LINK (0x1 << DBGWCR_WT_SHIFT)
  25. #define SPSR_D (1 << 9)
  26. #define SPSR_SS (1 << 21)
  27. extern unsigned char sw_bp, sw_bp2, hw_bp, hw_bp2, bp_svc, bp_brk, hw_wp, ss_start, hw_bp_ctx;
  28. extern unsigned char iter_ss_begin, iter_ss_end;
  29. static volatile uint64_t sw_bp_addr, hw_bp_addr;
  30. static volatile uint64_t wp_addr, wp_data_addr;
  31. static volatile uint64_t svc_addr;
  32. static volatile uint64_t ss_addr[4], ss_idx;
  33. #define PC(v) ((uint64_t)&(v))
  34. #define GEN_DEBUG_WRITE_REG(reg_name) \
  35. static void write_##reg_name(int num, uint64_t val) \
  36. { \
  37. switch (num) { \
  38. case 0: \
  39. write_sysreg(val, reg_name##0_el1); \
  40. break; \
  41. case 1: \
  42. write_sysreg(val, reg_name##1_el1); \
  43. break; \
  44. case 2: \
  45. write_sysreg(val, reg_name##2_el1); \
  46. break; \
  47. case 3: \
  48. write_sysreg(val, reg_name##3_el1); \
  49. break; \
  50. case 4: \
  51. write_sysreg(val, reg_name##4_el1); \
  52. break; \
  53. case 5: \
  54. write_sysreg(val, reg_name##5_el1); \
  55. break; \
  56. case 6: \
  57. write_sysreg(val, reg_name##6_el1); \
  58. break; \
  59. case 7: \
  60. write_sysreg(val, reg_name##7_el1); \
  61. break; \
  62. case 8: \
  63. write_sysreg(val, reg_name##8_el1); \
  64. break; \
  65. case 9: \
  66. write_sysreg(val, reg_name##9_el1); \
  67. break; \
  68. case 10: \
  69. write_sysreg(val, reg_name##10_el1); \
  70. break; \
  71. case 11: \
  72. write_sysreg(val, reg_name##11_el1); \
  73. break; \
  74. case 12: \
  75. write_sysreg(val, reg_name##12_el1); \
  76. break; \
  77. case 13: \
  78. write_sysreg(val, reg_name##13_el1); \
  79. break; \
  80. case 14: \
  81. write_sysreg(val, reg_name##14_el1); \
  82. break; \
  83. case 15: \
  84. write_sysreg(val, reg_name##15_el1); \
  85. break; \
  86. default: \
  87. GUEST_ASSERT(0); \
  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. static void reset_debug_state(void)
  96. {
  97. uint8_t brps, wrps, i;
  98. uint64_t dfr0;
  99. asm volatile("msr daifset, #8");
  100. write_sysreg(0, osdlr_el1);
  101. write_sysreg(0, oslar_el1);
  102. isb();
  103. write_sysreg(0, mdscr_el1);
  104. write_sysreg(0, contextidr_el1);
  105. /* Reset all bcr/bvr/wcr/wvr registers */
  106. dfr0 = read_sysreg(id_aa64dfr0_el1);
  107. brps = FIELD_GET(ID_AA64DFR0_EL1_BRPs, dfr0);
  108. for (i = 0; i <= brps; i++) {
  109. write_dbgbcr(i, 0);
  110. write_dbgbvr(i, 0);
  111. }
  112. wrps = FIELD_GET(ID_AA64DFR0_EL1_WRPs, dfr0);
  113. for (i = 0; i <= wrps; i++) {
  114. write_dbgwcr(i, 0);
  115. write_dbgwvr(i, 0);
  116. }
  117. isb();
  118. }
  119. static void enable_os_lock(void)
  120. {
  121. write_sysreg(1, oslar_el1);
  122. isb();
  123. GUEST_ASSERT(read_sysreg(oslsr_el1) & 2);
  124. }
  125. static void enable_monitor_debug_exceptions(void)
  126. {
  127. uint64_t mdscr;
  128. asm volatile("msr daifclr, #8");
  129. mdscr = read_sysreg(mdscr_el1) | MDSCR_KDE | MDSCR_MDE;
  130. write_sysreg(mdscr, mdscr_el1);
  131. isb();
  132. }
  133. static void install_wp(uint8_t wpn, uint64_t addr)
  134. {
  135. uint32_t wcr;
  136. wcr = DBGWCR_LEN8 | DBGWCR_RD | DBGWCR_WR | DBGWCR_EL1 | DBGWCR_E;
  137. write_dbgwcr(wpn, wcr);
  138. write_dbgwvr(wpn, addr);
  139. isb();
  140. enable_monitor_debug_exceptions();
  141. }
  142. static void install_hw_bp(uint8_t bpn, uint64_t addr)
  143. {
  144. uint32_t bcr;
  145. bcr = DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1 | DBGBCR_E;
  146. write_dbgbcr(bpn, bcr);
  147. write_dbgbvr(bpn, addr);
  148. isb();
  149. enable_monitor_debug_exceptions();
  150. }
  151. static void install_wp_ctx(uint8_t addr_wp, uint8_t ctx_bp, uint64_t addr,
  152. uint64_t ctx)
  153. {
  154. uint32_t wcr;
  155. uint64_t ctx_bcr;
  156. /* Setup a context-aware breakpoint for Linked Context ID Match */
  157. ctx_bcr = DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1 | DBGBCR_E |
  158. DBGBCR_BT_CTX_LINK;
  159. write_dbgbcr(ctx_bp, ctx_bcr);
  160. write_dbgbvr(ctx_bp, ctx);
  161. /* Setup a linked watchpoint (linked to the context-aware breakpoint) */
  162. wcr = DBGWCR_LEN8 | DBGWCR_RD | DBGWCR_WR | DBGWCR_EL1 | DBGWCR_E |
  163. DBGWCR_WT_LINK | ((uint32_t)ctx_bp << DBGWCR_LBN_SHIFT);
  164. write_dbgwcr(addr_wp, wcr);
  165. write_dbgwvr(addr_wp, addr);
  166. isb();
  167. enable_monitor_debug_exceptions();
  168. }
  169. void install_hw_bp_ctx(uint8_t addr_bp, uint8_t ctx_bp, uint64_t addr,
  170. uint64_t ctx)
  171. {
  172. uint32_t addr_bcr, ctx_bcr;
  173. /* Setup a context-aware breakpoint for Linked Context ID Match */
  174. ctx_bcr = DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1 | DBGBCR_E |
  175. DBGBCR_BT_CTX_LINK;
  176. write_dbgbcr(ctx_bp, ctx_bcr);
  177. write_dbgbvr(ctx_bp, ctx);
  178. /*
  179. * Setup a normal breakpoint for Linked Address Match, and link it
  180. * to the context-aware breakpoint.
  181. */
  182. addr_bcr = DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1 | DBGBCR_E |
  183. DBGBCR_BT_ADDR_LINK_CTX |
  184. ((uint32_t)ctx_bp << DBGBCR_LBN_SHIFT);
  185. write_dbgbcr(addr_bp, addr_bcr);
  186. write_dbgbvr(addr_bp, addr);
  187. isb();
  188. enable_monitor_debug_exceptions();
  189. }
  190. static void install_ss(void)
  191. {
  192. uint64_t mdscr;
  193. asm volatile("msr daifclr, #8");
  194. mdscr = read_sysreg(mdscr_el1) | MDSCR_KDE | MDSCR_SS;
  195. write_sysreg(mdscr, mdscr_el1);
  196. isb();
  197. }
  198. static volatile char write_data;
  199. static void guest_code(uint8_t bpn, uint8_t wpn, uint8_t ctx_bpn)
  200. {
  201. uint64_t ctx = 0xabcdef; /* a random context number */
  202. /* Software-breakpoint */
  203. reset_debug_state();
  204. asm volatile("sw_bp: brk #0");
  205. GUEST_ASSERT_EQ(sw_bp_addr, PC(sw_bp));
  206. /* Hardware-breakpoint */
  207. reset_debug_state();
  208. install_hw_bp(bpn, PC(hw_bp));
  209. asm volatile("hw_bp: nop");
  210. GUEST_ASSERT_EQ(hw_bp_addr, PC(hw_bp));
  211. /* Hardware-breakpoint + svc */
  212. reset_debug_state();
  213. install_hw_bp(bpn, PC(bp_svc));
  214. asm volatile("bp_svc: svc #0");
  215. GUEST_ASSERT_EQ(hw_bp_addr, PC(bp_svc));
  216. GUEST_ASSERT_EQ(svc_addr, PC(bp_svc) + 4);
  217. /* Hardware-breakpoint + software-breakpoint */
  218. reset_debug_state();
  219. install_hw_bp(bpn, PC(bp_brk));
  220. asm volatile("bp_brk: brk #0");
  221. GUEST_ASSERT_EQ(sw_bp_addr, PC(bp_brk));
  222. GUEST_ASSERT_EQ(hw_bp_addr, PC(bp_brk));
  223. /* Watchpoint */
  224. reset_debug_state();
  225. install_wp(wpn, PC(write_data));
  226. write_data = 'x';
  227. GUEST_ASSERT_EQ(write_data, 'x');
  228. GUEST_ASSERT_EQ(wp_data_addr, PC(write_data));
  229. /* Single-step */
  230. reset_debug_state();
  231. install_ss();
  232. ss_idx = 0;
  233. asm volatile("ss_start:\n"
  234. "mrs x0, esr_el1\n"
  235. "add x0, x0, #1\n"
  236. "msr daifset, #8\n"
  237. : : : "x0");
  238. GUEST_ASSERT_EQ(ss_addr[0], PC(ss_start));
  239. GUEST_ASSERT_EQ(ss_addr[1], PC(ss_start) + 4);
  240. GUEST_ASSERT_EQ(ss_addr[2], PC(ss_start) + 8);
  241. /* OS Lock does not block software-breakpoint */
  242. reset_debug_state();
  243. enable_os_lock();
  244. sw_bp_addr = 0;
  245. asm volatile("sw_bp2: brk #0");
  246. GUEST_ASSERT_EQ(sw_bp_addr, PC(sw_bp2));
  247. /* OS Lock blocking hardware-breakpoint */
  248. reset_debug_state();
  249. enable_os_lock();
  250. install_hw_bp(bpn, PC(hw_bp2));
  251. hw_bp_addr = 0;
  252. asm volatile("hw_bp2: nop");
  253. GUEST_ASSERT_EQ(hw_bp_addr, 0);
  254. /* OS Lock blocking watchpoint */
  255. reset_debug_state();
  256. enable_os_lock();
  257. write_data = '\0';
  258. wp_data_addr = 0;
  259. install_wp(wpn, PC(write_data));
  260. write_data = 'x';
  261. GUEST_ASSERT_EQ(write_data, 'x');
  262. GUEST_ASSERT_EQ(wp_data_addr, 0);
  263. /* OS Lock blocking single-step */
  264. reset_debug_state();
  265. enable_os_lock();
  266. ss_addr[0] = 0;
  267. install_ss();
  268. ss_idx = 0;
  269. asm volatile("mrs x0, esr_el1\n\t"
  270. "add x0, x0, #1\n\t"
  271. "msr daifset, #8\n\t"
  272. : : : "x0");
  273. GUEST_ASSERT_EQ(ss_addr[0], 0);
  274. /* Linked hardware-breakpoint */
  275. hw_bp_addr = 0;
  276. reset_debug_state();
  277. install_hw_bp_ctx(bpn, ctx_bpn, PC(hw_bp_ctx), ctx);
  278. /* Set context id */
  279. write_sysreg(ctx, contextidr_el1);
  280. isb();
  281. asm volatile("hw_bp_ctx: nop");
  282. write_sysreg(0, contextidr_el1);
  283. GUEST_ASSERT_EQ(hw_bp_addr, PC(hw_bp_ctx));
  284. /* Linked watchpoint */
  285. reset_debug_state();
  286. install_wp_ctx(wpn, ctx_bpn, PC(write_data), ctx);
  287. /* Set context id */
  288. write_sysreg(ctx, contextidr_el1);
  289. isb();
  290. write_data = 'x';
  291. GUEST_ASSERT_EQ(write_data, 'x');
  292. GUEST_ASSERT_EQ(wp_data_addr, PC(write_data));
  293. GUEST_DONE();
  294. }
  295. static void guest_sw_bp_handler(struct ex_regs *regs)
  296. {
  297. sw_bp_addr = regs->pc;
  298. regs->pc += 4;
  299. }
  300. static void guest_hw_bp_handler(struct ex_regs *regs)
  301. {
  302. hw_bp_addr = regs->pc;
  303. regs->pstate |= SPSR_D;
  304. }
  305. static void guest_wp_handler(struct ex_regs *regs)
  306. {
  307. wp_data_addr = read_sysreg(far_el1);
  308. wp_addr = regs->pc;
  309. regs->pstate |= SPSR_D;
  310. }
  311. static void guest_ss_handler(struct ex_regs *regs)
  312. {
  313. __GUEST_ASSERT(ss_idx < 4, "Expected index < 4, got '%lu'", ss_idx);
  314. ss_addr[ss_idx++] = regs->pc;
  315. regs->pstate |= SPSR_SS;
  316. }
  317. static void guest_svc_handler(struct ex_regs *regs)
  318. {
  319. svc_addr = regs->pc;
  320. }
  321. static void guest_code_ss(int test_cnt)
  322. {
  323. uint64_t i;
  324. uint64_t bvr, wvr, w_bvr, w_wvr;
  325. for (i = 0; i < test_cnt; i++) {
  326. /* Bits [1:0] of dbg{b,w}vr are RES0 */
  327. w_bvr = i << 2;
  328. w_wvr = i << 2;
  329. /*
  330. * Enable Single Step execution. Note! This _must_ be a bare
  331. * ucall as the ucall() path uses atomic operations to manage
  332. * the ucall structures, and the built-in "atomics" are usually
  333. * implemented via exclusive access instructions. The exlusive
  334. * monitor is cleared on ERET, and so taking debug exceptions
  335. * during a LDREX=>STREX sequence will prevent forward progress
  336. * and hang the guest/test.
  337. */
  338. GUEST_UCALL_NONE();
  339. /*
  340. * The userspace will verify that the pc is as expected during
  341. * single step execution between iter_ss_begin and iter_ss_end.
  342. */
  343. asm volatile("iter_ss_begin:nop\n");
  344. write_sysreg(w_bvr, dbgbvr0_el1);
  345. write_sysreg(w_wvr, dbgwvr0_el1);
  346. bvr = read_sysreg(dbgbvr0_el1);
  347. wvr = read_sysreg(dbgwvr0_el1);
  348. /* Userspace disables Single Step when the end is nigh. */
  349. asm volatile("iter_ss_end:\n");
  350. GUEST_ASSERT_EQ(bvr, w_bvr);
  351. GUEST_ASSERT_EQ(wvr, w_wvr);
  352. }
  353. GUEST_DONE();
  354. }
  355. static int debug_version(uint64_t id_aa64dfr0)
  356. {
  357. return FIELD_GET(ID_AA64DFR0_EL1_DebugVer, id_aa64dfr0);
  358. }
  359. static void test_guest_debug_exceptions(uint8_t bpn, uint8_t wpn, uint8_t ctx_bpn)
  360. {
  361. struct kvm_vcpu *vcpu;
  362. struct kvm_vm *vm;
  363. struct ucall uc;
  364. vm = vm_create_with_one_vcpu(&vcpu, guest_code);
  365. vm_init_descriptor_tables(vm);
  366. vcpu_init_descriptor_tables(vcpu);
  367. vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
  368. ESR_ELx_EC_BRK64, guest_sw_bp_handler);
  369. vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
  370. ESR_ELx_EC_BREAKPT_CUR, guest_hw_bp_handler);
  371. vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
  372. ESR_ELx_EC_WATCHPT_CUR, guest_wp_handler);
  373. vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
  374. ESR_ELx_EC_SOFTSTP_CUR, guest_ss_handler);
  375. vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
  376. ESR_ELx_EC_SVC64, guest_svc_handler);
  377. /* Specify bpn/wpn/ctx_bpn to be tested */
  378. vcpu_args_set(vcpu, 3, bpn, wpn, ctx_bpn);
  379. pr_debug("Use bpn#%d, wpn#%d and ctx_bpn#%d\n", bpn, wpn, ctx_bpn);
  380. vcpu_run(vcpu);
  381. switch (get_ucall(vcpu, &uc)) {
  382. case UCALL_ABORT:
  383. REPORT_GUEST_ASSERT(uc);
  384. break;
  385. case UCALL_DONE:
  386. goto done;
  387. default:
  388. TEST_FAIL("Unknown ucall %lu", uc.cmd);
  389. }
  390. done:
  391. kvm_vm_free(vm);
  392. }
  393. void test_single_step_from_userspace(int test_cnt)
  394. {
  395. struct kvm_vcpu *vcpu;
  396. struct kvm_vm *vm;
  397. struct ucall uc;
  398. struct kvm_run *run;
  399. uint64_t pc, cmd;
  400. uint64_t test_pc = 0;
  401. bool ss_enable = false;
  402. struct kvm_guest_debug debug = {};
  403. vm = vm_create_with_one_vcpu(&vcpu, guest_code_ss);
  404. run = vcpu->run;
  405. vcpu_args_set(vcpu, 1, test_cnt);
  406. while (1) {
  407. vcpu_run(vcpu);
  408. if (run->exit_reason != KVM_EXIT_DEBUG) {
  409. cmd = get_ucall(vcpu, &uc);
  410. if (cmd == UCALL_ABORT) {
  411. REPORT_GUEST_ASSERT(uc);
  412. /* NOT REACHED */
  413. } else if (cmd == UCALL_DONE) {
  414. break;
  415. }
  416. TEST_ASSERT(cmd == UCALL_NONE,
  417. "Unexpected ucall cmd 0x%lx", cmd);
  418. debug.control = KVM_GUESTDBG_ENABLE |
  419. KVM_GUESTDBG_SINGLESTEP;
  420. ss_enable = true;
  421. vcpu_guest_debug_set(vcpu, &debug);
  422. continue;
  423. }
  424. TEST_ASSERT(ss_enable, "Unexpected KVM_EXIT_DEBUG");
  425. /* Check if the current pc is expected. */
  426. pc = vcpu_get_reg(vcpu, ARM64_CORE_REG(regs.pc));
  427. TEST_ASSERT(!test_pc || pc == test_pc,
  428. "Unexpected pc 0x%lx (expected 0x%lx)",
  429. pc, test_pc);
  430. if ((pc + 4) == (uint64_t)&iter_ss_end) {
  431. test_pc = 0;
  432. debug.control = KVM_GUESTDBG_ENABLE;
  433. ss_enable = false;
  434. vcpu_guest_debug_set(vcpu, &debug);
  435. continue;
  436. }
  437. /*
  438. * If the current pc is between iter_ss_bgin and
  439. * iter_ss_end, the pc for the next KVM_EXIT_DEBUG should
  440. * be the current pc + 4.
  441. */
  442. if ((pc >= (uint64_t)&iter_ss_begin) &&
  443. (pc < (uint64_t)&iter_ss_end))
  444. test_pc = pc + 4;
  445. else
  446. test_pc = 0;
  447. }
  448. kvm_vm_free(vm);
  449. }
  450. /*
  451. * Run debug testing using the various breakpoint#, watchpoint# and
  452. * context-aware breakpoint# with the given ID_AA64DFR0_EL1 configuration.
  453. */
  454. void test_guest_debug_exceptions_all(uint64_t aa64dfr0)
  455. {
  456. uint8_t brp_num, wrp_num, ctx_brp_num, normal_brp_num, ctx_brp_base;
  457. int b, w, c;
  458. /* Number of breakpoints */
  459. brp_num = FIELD_GET(ID_AA64DFR0_EL1_BRPs, aa64dfr0) + 1;
  460. __TEST_REQUIRE(brp_num >= 2, "At least two breakpoints are required");
  461. /* Number of watchpoints */
  462. wrp_num = FIELD_GET(ID_AA64DFR0_EL1_WRPs, aa64dfr0) + 1;
  463. /* Number of context aware breakpoints */
  464. ctx_brp_num = FIELD_GET(ID_AA64DFR0_EL1_CTX_CMPs, aa64dfr0) + 1;
  465. pr_debug("%s brp_num:%d, wrp_num:%d, ctx_brp_num:%d\n", __func__,
  466. brp_num, wrp_num, ctx_brp_num);
  467. /* Number of normal (non-context aware) breakpoints */
  468. normal_brp_num = brp_num - ctx_brp_num;
  469. /* Lowest context aware breakpoint number */
  470. ctx_brp_base = normal_brp_num;
  471. /* Run tests with all supported breakpoints/watchpoints */
  472. for (c = ctx_brp_base; c < ctx_brp_base + ctx_brp_num; c++) {
  473. for (b = 0; b < normal_brp_num; b++) {
  474. for (w = 0; w < wrp_num; w++)
  475. test_guest_debug_exceptions(b, w, c);
  476. }
  477. }
  478. }
  479. static void help(char *name)
  480. {
  481. puts("");
  482. printf("Usage: %s [-h] [-i iterations of the single step test]\n", name);
  483. puts("");
  484. exit(0);
  485. }
  486. int main(int argc, char *argv[])
  487. {
  488. struct kvm_vcpu *vcpu;
  489. struct kvm_vm *vm;
  490. int opt;
  491. int ss_iteration = 10000;
  492. uint64_t aa64dfr0;
  493. vm = vm_create_with_one_vcpu(&vcpu, guest_code);
  494. aa64dfr0 = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1));
  495. __TEST_REQUIRE(debug_version(aa64dfr0) >= 6,
  496. "Armv8 debug architecture not supported.");
  497. kvm_vm_free(vm);
  498. while ((opt = getopt(argc, argv, "i:")) != -1) {
  499. switch (opt) {
  500. case 'i':
  501. ss_iteration = atoi_positive("Number of iterations", optarg);
  502. break;
  503. case 'h':
  504. default:
  505. help(argv[0]);
  506. break;
  507. }
  508. }
  509. test_guest_debug_exceptions_all(aa64dfr0);
  510. test_single_step_from_userspace(ss_iteration);
  511. return 0;
  512. }