Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx> --- x86/debug.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/x86/debug.c b/x86/debug.c index b645e7b..f66d1d0 100644 --- a/x86/debug.c +++ b/x86/debug.c @@ -59,6 +59,13 @@ static void handle_db(struct ex_regs *regs) } } +extern unsigned char handle_db_save_rip; +asm("handle_db_save_rip:\n" + "stc\n" + "nop;nop;nop\n" + "rclq $1, n(%rip)\n" + "iretq\n"); + static void handle_bp(struct ex_regs *regs) { bp_addr = regs->rip; @@ -178,5 +185,50 @@ int main(int ac, char **av) db_addr[0] == (unsigned long)&sw_icebp && dr6[0] == 0xffff0ff0); + set_dr7(0x400); + value = KERNEL_DS; + set_dr7(0x00f0040a); // 4-byte read or write + + /* + * Each invocation of the handler should shift n by 1 and set bit 0 to 1. + * We expect a single invocation, so n should become 3. If the entry + * RIP is wrong, or if the handler is executed more than once, the value + * will not match. + */ + set_idt_entry(1, &handle_db_save_rip, 0); + + n = 1; + asm volatile( + "clc\n\t" + "mov %0,%%ss\n\t" + ".byte 0x2e, 0x2e, 0xf1" + : "=m" (value) : : "rax"); + report("MOV SS + watchpoint + ICEBP", n == 3); + + /* + * Here the #DB handler is invoked twice, once as a software exception + * and once as a software interrupt. + */ + n = 1; + asm volatile( + "clc\n\t" + "mov %0,%%ss\n\t" + "int $1" + : "=m" (value) : : "rax"); + report("MOV SS + watchpoint + int $1", n == 7); + + /* + * Here the #DB and #BP handlers are invoked once each. + */ + n = 1; + bp_addr = 0; + asm volatile( + "mov %0,%%ss\n\t" + ".byte 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0xcc\n\t" + "sw_bp2:" + : "=m" (value) : : "rax"); + extern unsigned char sw_bp2; + report("MOV SS + watchpoint + INT3", + n == 3 && bp_addr == (unsigned long)&sw_bp2); return report_summary(); } -- 1.8.3.1