2222#define SPSR_SS (1 << 21)
2323
2424extern 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 ;
2526static volatile uint64_t sw_bp_addr , hw_bp_addr ;
2627static volatile uint64_t wp_addr , wp_data_addr ;
2728static volatile uint64_t svc_addr ;
@@ -238,6 +239,46 @@ static void guest_svc_handler(struct ex_regs *regs)
238239 svc_addr = regs -> pc ;
239240}
240241
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+
241282static int debug_version (struct kvm_vcpu * vcpu )
242283{
243284 uint64_t id_aa64dfr0 ;
@@ -246,7 +287,7 @@ static int debug_version(struct kvm_vcpu *vcpu)
246287 return id_aa64dfr0 & 0xf ;
247288}
248289
249- int main ( int argc , char * argv [] )
290+ static void test_guest_debug_exceptions ( void )
250291{
251292 struct kvm_vcpu * vcpu ;
252293 struct kvm_vm * vm ;
@@ -259,9 +300,6 @@ int main(int argc, char *argv[])
259300 vm_init_descriptor_tables (vm );
260301 vcpu_init_descriptor_tables (vcpu );
261302
262- __TEST_REQUIRE (debug_version (vcpu ) >= 6 ,
263- "Armv8 debug architecture not supported." );
264-
265303 vm_install_sync_handler (vm , VECTOR_SYNC_CURRENT ,
266304 ESR_EC_BRK_INS , guest_sw_bp_handler );
267305 vm_install_sync_handler (vm , VECTOR_SYNC_CURRENT ,
@@ -294,5 +332,108 @@ int main(int argc, char *argv[])
294332
295333done :
296334 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+
297438 return 0 ;
298439}
0 commit comments