diff mbox series

[kvm-unit-tests,2/3] arm64: debug: add a migration test for watchpoint state

Message ID 20211210165804.1623253-3-ricarkol@google.com (mailing list archive)
State New, archived
Headers show
Series arm64: debug: add migration tests for debug state | expand

Commit Message

Ricardo Koller Dec. 10, 2021, 4:58 p.m. UTC
Test the migration of watchpoint state. Program as many watchpoints as
possible, migrate, and check that we get the corresponding exceptions.

Signed-off-by: Ricardo Koller <ricarkol@google.com>
---
 arm/debug.c       | 164 ++++++++++++++++++++++++++++++++++++++++++++++
 arm/unittests.cfg |  12 ++++
 2 files changed, 176 insertions(+)
diff mbox series

Patch

diff --git a/arm/debug.c b/arm/debug.c
index fedf4ab..b2240d7 100644
--- a/arm/debug.c
+++ b/arm/debug.c
@@ -9,20 +9,31 @@ 
 
 #define MDSCR_KDE		(1 << 13)
 #define MDSCR_MDE		(1 << 15)
+#define MDSCR_SS		(1 << 0)
 
 #define DBGBCR_LEN8		(0xff << 5)
 #define DBGBCR_EXEC		(0x0 << 3)
 #define DBGBCR_EL1		(0x1 << 1)
 #define DBGBCR_E		(0x1 << 0)
 
+#define DBGWCR_LEN8		(0xff << 5)
+#define DBGWCR_RD		(0x1 << 3)
+#define DBGWCR_WR		(0x2 << 3)
+#define DBGWCR_EL1		(0x1 << 1)
+#define DBGWCR_E		(0x1 << 0)
+
 #define SPSR_D			(1 << 9)
 
 #define ESR_EC_HW_BP_CURRENT    0x31
+#define ESR_EC_WP_CURRENT       0x35
 
 #define ID_AA64DFR0_BRPS_SHIFT	12
 #define ID_AA64DFR0_BRPS_MASK	0xf
+#define ID_AA64DFR0_WRPS_SHIFT	20
+#define ID_AA64DFR0_WRPS_MASK	0xf
 
 static volatile uint64_t hw_bp_idx, hw_bp_addr[16];
+static volatile uint64_t wp_idx, wp_data_addr[16];
 
 static void hw_bp_handler(struct pt_regs *regs, unsigned int esr)
 {
@@ -30,6 +41,12 @@  static void hw_bp_handler(struct pt_regs *regs, unsigned int esr)
 	regs->pstate |= SPSR_D;
 }
 
+static void wp_handler(struct pt_regs *regs, unsigned int esr)
+{
+	wp_data_addr[wp_idx++] = read_sysreg(far_el1);
+	regs->pstate |= SPSR_D;
+}
+
 static int get_num_hw_bp(void)
 {
 	uint64_t reg = read_sysreg(id_aa64dfr0_el1);
@@ -39,6 +56,15 @@  static int get_num_hw_bp(void)
 	return brps + 1;
 }
 
+static int get_num_wp(void)
+{
+	uint64_t reg = read_sysreg(id_aa64dfr0_el1);
+	/* Number of watchpoints, minus 1 */
+	uint8_t wrps = (reg >> ID_AA64DFR0_WRPS_SHIFT) & ID_AA64DFR0_WRPS_MASK;
+
+	return wrps + 1;
+}
+
 static void write_dbgbcr(int n, uint32_t bcr)
 {
 	switch (n) {
@@ -119,9 +145,90 @@  static void write_dbgbvr(int n, uint64_t bvr)
 	}
 }
 
+static void write_dbgwcr(int n, uint32_t wcr)
+{
+	switch (n) {
+	case 0:
+		write_sysreg(wcr, dbgwcr0_el1); break;
+	case 1:
+		write_sysreg(wcr, dbgwcr1_el1); break;
+	case 2:
+		write_sysreg(wcr, dbgwcr2_el1); break;
+	case 3:
+		write_sysreg(wcr, dbgwcr3_el1); break;
+	case 4:
+		write_sysreg(wcr, dbgwcr4_el1); break;
+	case 5:
+		write_sysreg(wcr, dbgwcr5_el1); break;
+	case 6:
+		write_sysreg(wcr, dbgwcr6_el1); break;
+	case 7:
+		write_sysreg(wcr, dbgwcr7_el1); break;
+	case 8:
+		write_sysreg(wcr, dbgwcr8_el1); break;
+	case 9:
+		write_sysreg(wcr, dbgwcr9_el1); break;
+	case 10:
+		write_sysreg(wcr, dbgwcr10_el1); break;
+	case 11:
+		write_sysreg(wcr, dbgwcr11_el1); break;
+	case 12:
+		write_sysreg(wcr, dbgwcr12_el1); break;
+	case 13:
+		write_sysreg(wcr, dbgwcr13_el1); break;
+	case 14:
+		write_sysreg(wcr, dbgwcr14_el1); break;
+	case 15:
+		write_sysreg(wcr, dbgwcr15_el1); break;
+	default:
+		report_abort("Invalid wcr");
+	}
+}
+
+static void write_dbgwvr(int n, uint64_t wvr)
+{
+	switch (n) {
+	case 0:
+		write_sysreg(wvr, dbgwvr0_el1); break;
+	case 1:
+		write_sysreg(wvr, dbgwvr1_el1); break;
+	case 2:
+		write_sysreg(wvr, dbgwvr2_el1); break;
+	case 3:
+		write_sysreg(wvr, dbgwvr3_el1); break;
+	case 4:
+		write_sysreg(wvr, dbgwvr4_el1); break;
+	case 5:
+		write_sysreg(wvr, dbgwvr5_el1); break;
+	case 6:
+		write_sysreg(wvr, dbgwvr6_el1); break;
+	case 7:
+		write_sysreg(wvr, dbgwvr7_el1); break;
+	case 8:
+		write_sysreg(wvr, dbgwvr8_el1); break;
+	case 9:
+		write_sysreg(wvr, dbgwvr9_el1); break;
+	case 10:
+		write_sysreg(wvr, dbgwvr10_el1); break;
+	case 11:
+		write_sysreg(wvr, dbgwvr11_el1); break;
+	case 12:
+		write_sysreg(wvr, dbgwvr12_el1); break;
+	case 13:
+		write_sysreg(wvr, dbgwvr13_el1); break;
+	case 14:
+		write_sysreg(wvr, dbgwvr14_el1); break;
+	case 15:
+		write_sysreg(wvr, dbgwvr15_el1); break;
+	default:
+		report_abort("invalid wvr");
+	}
+}
+
 static void reset_debug_state(void)
 {
 	int i, num_bp = get_num_hw_bp();
+	int num_wp = get_num_wp();
 
 	asm volatile("msr daifset, #8");
 
@@ -134,6 +241,10 @@  static void reset_debug_state(void)
 		write_dbgbvr(i, 0);
 		write_dbgbcr(i, 0);
 	}
+	for (i = 0; i < num_wp; i++) {
+		write_dbgwvr(i, 0);
+		write_dbgwcr(i, 0);
+	}
 	isb();
 }
 
@@ -188,6 +299,51 @@  static void test_hw_bp(bool migrate)
 		report(hw_bp_addr[i] == addr, "hw breakpoint: %d", i);
 }
 
+static volatile char write_data[16];
+
+static void test_wp(bool migrate)
+{
+	uint32_t wcr;
+	uint32_t mdscr;
+	int num_wp = get_num_wp();
+	int i;
+
+	install_exception_handler(EL1H_SYNC, ESR_EC_WP_CURRENT, wp_handler);
+
+	reset_debug_state();
+
+	wcr = DBGWCR_LEN8 | DBGWCR_RD | DBGWCR_WR | DBGWCR_EL1 | DBGWCR_E;
+	for (i = 0; i < num_wp; i++) {
+		write_dbgwcr(i, wcr);
+		write_dbgwvr(i, (uint64_t)&write_data[i]);
+	}
+	isb();
+
+	asm volatile("msr daifclr, #8");
+
+	mdscr = read_sysreg(mdscr_el1) | MDSCR_KDE | MDSCR_MDE;
+	write_sysreg(mdscr, mdscr_el1);
+	isb();
+
+	if (migrate) {
+		do_migrate();
+		report(num_wp == get_num_wp(), "wrps match after migrate");
+	}
+
+	wp_idx = 0;
+
+	for (i = 0; i < num_wp; i++) {
+		write_data[i] = i;
+		asm volatile("msr daifclr, #8");
+	}
+
+	for (i = 0; i < num_wp; i++) {
+		report(wp_data_addr[i] == (uint64_t)&write_data[i],
+			"watchpoint received: %d", i);
+		report(write_data[i] == i, "watchpoint data: %d", i);
+	}
+}
+
 int main(int argc, char **argv)
 {
 	if (argc < 2)
@@ -201,6 +357,14 @@  int main(int argc, char **argv)
 		report_prefix_push(argv[1]);
 		test_hw_bp(true);
 		report_prefix_pop();
+	} else if (strcmp(argv[1], "wp") == 0) {
+		report_prefix_push(argv[1]);
+		test_wp(false);
+		report_prefix_pop();
+	} else if (strcmp(argv[1], "wp-migration") == 0) {
+		report_prefix_push(argv[1]);
+		test_wp(true);
+		report_prefix_pop();
 	} else {
 		report_abort("Unknown subtest '%s'", argv[1]);
 	}
diff --git a/arm/unittests.cfg b/arm/unittests.cfg
index 896ff87..bca2fad 100644
--- a/arm/unittests.cfg
+++ b/arm/unittests.cfg
@@ -254,3 +254,15 @@  file = debug.flat
 arch = arm64
 extra_params = -append 'bp-migration'
 groups = debug migration
+
+[debug-wp]
+file = debug.flat
+arch = arm64
+extra_params = -append 'wp'
+groups = debug
+
+[debug-wp-migration]
+file = debug.flat
+arch = arm64
+extra_params = -append 'wp-migration'
+groups = debug migration