From: Andrew Cooper Date: Sat, 2 Mar 2024 21:14:54 +0000 (+0000) Subject: test-swint: Update to use ex_record rather than exlog X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=d00bccb5e5c7c253e3305d55a1a2ab4d3c52b929;p=xtf.git test-swint: Update to use ex_record rather than exlog This is both more precise and consice. As this test pertains to mixing up faults and traps, introduce EXINFO_TRAP and ex_record_trap_eax() to distinguish which EXTABLE entry was used. This in turn means we don't need to export the trap/fault labels to C. Change the nomeclature for instruction prefixes, because "red" is fairly meaningless and confusing in context. No change in test behaviour. Signed-off-by: Andrew Cooper --- diff --git a/tests/swint-emulation/lowlevel.S b/tests/swint-emulation/lowlevel.S index b7bf0fc..53bb72c 100644 --- a/tests/swint-emulation/lowlevel.S +++ b/tests/swint-emulation/lowlevel.S @@ -5,30 +5,24 @@ /* Macro to generate a single test function. */ /* See lowlevel.h for a description of nomenclature. */ -.macro GEN_SINGLE insn, type +.macro GEN_SINGLE name, insn, fep=0, addr=0 - /* Function label. e.g. stub_int3_red(). */ -ENTRY(stub_\insn\()_\type) +ENTRY(stub_\name) + + xor %eax, %eax .ifc \insn, into /* Ensure the overflow flag is set, to trigger 'into'. */ - mov $0x7f, %al - add %al, %al - .else - /* Avoid function label and fault label possibly aliasing. */ - nop + mov $0x7f, %dl + add %dl, %dl .endif /* Possibly insert a Xen Forced Emulation prefix. */ - .ifc \type, force - _ASM_XEN_FEP - .endif - .ifc \type, forcered + .if \fep _ASM_XEN_FEP .endif - /* Label where a fault should occur. e.g. label_int3_red_fault. */ -GLOBAL(label_\insn\()_\type\()_fault) +.L_\name\()_fault: /* * Possibly insert a redundant prefix. @@ -36,10 +30,7 @@ GLOBAL(label_\insn\()_\type\()_fault) * Uses 'address size override' which has no effect on any of the * target instructions, but in a form which GAS won't complain about. */ - .ifc \type, red - .byte 0x67 - .endif - .ifc \type, forcered + .if \addr .byte 0x67 .endif @@ -60,27 +51,22 @@ GLOBAL(label_\insn\()_\type\()_fault) .byte 0xce /* Raw opcode to avoid failure in 64bit build. */ .endif - /* Label where a trap should occur. e.g. label_int3_red_trap. */ -GLOBAL(label_\insn\()_\type\()_trap) +.L_\name\()_trap: - /* Function return. */ ret - /* Fixup from fault label to trap label. */ - _ASM_EXTABLE(label_\insn\()_\type\()_fault, - label_\insn\()_\type\()_trap) - /* Mark traps as ok. */ - _ASM_TRAP_OK(label_\insn\()_\type\()_trap) + _ASM_EXTABLE_HANDLER(.L_\name\()_fault, .L_\name\()_trap, ex_record_fault_eax) + _ASM_EXTABLE_HANDLER(.L_\name\()_trap, .L_\name\()_trap, ex_record_trap_eax) -ENDFUNC(stub_\insn\()_\type) +ENDFUNC(stub_\name\()) .endm /* For a single instruction, generate each test variant. */ .macro GEN_SEQUENCE insn - GEN_SINGLE \insn reg - GEN_SINGLE \insn red - GEN_SINGLE \insn force - GEN_SINGLE \insn forcered + GEN_SINGLE \insn \insn + GEN_SINGLE \insn\()_A \insn addr=1 + GEN_SINGLE \insn\()_F \insn fep=1 + GEN_SINGLE \insn\()_FA \insn fep=1 addr=1 .endm /* Generate test sequences for each instruction. */ diff --git a/tests/swint-emulation/lowlevel.h b/tests/swint-emulation/lowlevel.h index 1cbe8cb..e3ab755 100644 --- a/tests/swint-emulation/lowlevel.h +++ b/tests/swint-emulation/lowlevel.h @@ -6,8 +6,6 @@ * Nomaclature: * - `stub_$X_$Y()` * - Stub function executing instruction `$X` with prefix `$Y`. - * - `label_$X_$Y_{trap, fault}:` - * - Labels for where `$X` is expected to trap or fault. * * Instructions `$X`: * - int3 @@ -22,62 +20,42 @@ * - `into` (`0xce`) * * Prefixes `$Y`: - * - reg + * - (none) * - Regular - no prefix - * - red - * - Redundant - address size override prefix (`0x67`) - * - force + * - A + * - Address size override prefix (`0x67`) + * - F * - Forced Emulation prefix - see @ref _ASM_XEN_FEP - * - forcered - * - Forced Emulation and redundant prefixes + * - FA + * - Forced Emulation and Address override prefixes */ #ifndef __LOWLEVEL_H__ #define __LOWLEVEL_H__ -void stub_int3_reg(void); -void stub_int3_red(void); -void stub_int3_force(void); -void stub_int3_forcered(void); -extern unsigned long label_int3_reg_trap[], label_int3_reg_fault[]; -extern unsigned long label_int3_red_trap[], label_int3_red_fault[]; -extern unsigned long label_int3_force_trap[], label_int3_force_fault[]; -extern unsigned long label_int3_forcered_trap[], label_int3_forcered_fault[]; +unsigned long stub_int3(void); +unsigned long stub_int3_A(void); +unsigned long stub_int3_F(void); +unsigned long stub_int3_FA(void); -void stub_int_0x3_reg(void); -void stub_int_0x3_red(void); -void stub_int_0x3_force(void); -void stub_int_0x3_forcered(void); -extern unsigned long label_int_0x3_reg_trap[], label_int_0x3_reg_fault[]; -extern unsigned long label_int_0x3_red_trap[], label_int_0x3_red_fault[]; -extern unsigned long label_int_0x3_force_trap[], label_int_0x3_force_fault[]; -extern unsigned long label_int_0x3_forcered_trap[], label_int_0x3_forcered_fault[]; +unsigned long stub_int_0x3(void); +unsigned long stub_int_0x3_A(void); +unsigned long stub_int_0x3_F(void); +unsigned long stub_int_0x3_FA(void); -void stub_icebp_reg(void); -void stub_icebp_red(void); -void stub_icebp_force(void); -void stub_icebp_forcered(void); -extern unsigned long label_icebp_reg_trap[], label_icebp_reg_fault[]; -extern unsigned long label_icebp_red_trap[], label_icebp_red_fault[]; -extern unsigned long label_icebp_force_trap[], label_icebp_force_fault[]; -extern unsigned long label_icebp_forcered_trap[], label_icebp_forcered_fault[]; +unsigned long stub_icebp(void); +unsigned long stub_icebp_A(void); +unsigned long stub_icebp_F(void); +unsigned long stub_icebp_FA(void); -void stub_int_0x1_reg(void); -void stub_int_0x1_red(void); -void stub_int_0x1_force(void); -void stub_int_0x1_forcered(void); -extern unsigned long label_int_0x1_reg_trap[], label_int_0x1_reg_fault[]; -extern unsigned long label_int_0x1_red_trap[], label_int_0x1_red_fault[]; -extern unsigned long label_int_0x1_force_trap[], label_int_0x1_force_fault[]; -extern unsigned long label_int_0x1_forcered_trap[], label_int_0x1_forcered_fault[]; +unsigned long stub_int_0x1(void); +unsigned long stub_int_0x1_A(void); +unsigned long stub_int_0x1_F(void); +unsigned long stub_int_0x1_FA(void); -void stub_into_reg(void); -void stub_into_red(void); -void stub_into_force(void); -void stub_into_forcered(void); -extern unsigned long label_into_reg_trap[], label_into_reg_fault[]; -extern unsigned long label_into_red_trap[], label_into_red_fault[]; -extern unsigned long label_into_force_trap[], label_into_force_fault[]; -extern unsigned long label_into_forcered_trap[], label_into_forcered_fault[]; +unsigned long stub_into(void); +unsigned long stub_into_A(void); +unsigned long stub_into_F(void); +unsigned long stub_into_FA(void); #endif /* __LOWLEVEL_H__ */ diff --git a/tests/swint-emulation/main.c b/tests/swint-emulation/main.c index 92ca98b..a4d1452 100644 --- a/tests/swint-emulation/main.c +++ b/tests/swint-emulation/main.c @@ -58,188 +58,92 @@ bool test_wants_user_mappings = true; # define COND(_32, _64) _64 #endif +#define EXINFO_TRAP EXINFO_AVAIL0 + enum mode { KERN, USER }; -/** Single stub's worth of information. */ -struct single +bool ex_record_trap_eax(struct cpu_regs *regs, const struct extable_entry *ex) { - const char *type; - void (*fn)(void); - void *trap, *fault; -}; + regs->ax = EXINFO(regs->entry_vector, regs->error_code) | EXINFO_TRAP; + regs->ip = ex->fixup; + + return true; +} struct insn { const char *name; - struct single tests[4]; + unsigned long (*fn[4])(void); }; const struct insn int3 = { "int3", { - {"regular", stub_int3_reg, - label_int3_reg_trap, label_int3_reg_fault}, - - {"redundant", stub_int3_red, - label_int3_red_trap, label_int3_red_fault}, - - {"forced", stub_int3_force, - label_int3_force_trap, label_int3_force_fault}, - - {"forced redundant", stub_int3_forcered, - label_int3_forcered_trap, label_int3_forcered_fault}, + stub_int3, + stub_int3_A, + stub_int3_F, + stub_int3_FA, }, }; const struct insn int_0x3 = { "int $3", { - {"regular", stub_int_0x3_reg, - label_int_0x3_reg_trap, label_int_0x3_reg_fault}, - - {"redundant", stub_int_0x3_red, - label_int_0x3_red_trap, label_int_0x3_red_fault}, - - {"forced", stub_int_0x3_force, - label_int_0x3_force_trap, label_int_0x3_force_fault}, - - {"forced redundant", stub_int_0x3_forcered, - label_int_0x3_forcered_trap, label_int_0x3_forcered_fault}, + stub_int_0x3, + stub_int_0x3_A, + stub_int_0x3_F, + stub_int_0x3_FA, }, }; const struct insn icebp = { "icebp", { - {"regular", stub_icebp_reg, - label_icebp_reg_trap, label_icebp_reg_fault}, - - {"redundant", stub_icebp_red, - label_icebp_red_trap, label_icebp_red_fault}, - - {"forced", stub_icebp_force, - label_icebp_force_trap, label_icebp_force_fault}, - - {"forced redundant", stub_icebp_forcered, - label_icebp_forcered_trap, label_icebp_forcered_fault}, + stub_icebp, + stub_icebp_A, + stub_icebp_F, + stub_icebp_FA, }, }; const struct insn int_0x1 = { "int $1", { - {"regular", stub_int_0x1_reg, - label_int_0x1_reg_trap, label_int_0x1_reg_fault}, - - {"redundant", stub_int_0x1_red, - label_int_0x1_red_trap, label_int_0x1_red_fault}, - - {"forced", stub_int_0x1_force, - label_int_0x1_force_trap, label_int_0x1_force_fault}, - - {"forced redundant", stub_int_0x1_forcered, - label_int_0x1_forcered_trap, label_int_0x1_forcered_fault}, + stub_int_0x1, + stub_int_0x1_A, + stub_int_0x1_F, + stub_int_0x1_FA, }, }; const struct insn into = { "into", { - {"regular", stub_into_reg, - label_into_reg_trap, label_into_reg_fault}, - - {"redundant", stub_into_red, - label_into_red_trap, label_into_red_fault}, - - {"forced", stub_into_force, - label_into_force_trap, label_into_force_fault}, - - {"forced redundant", stub_into_forcered, - label_into_forcered_trap, label_into_forcered_fault}, + stub_into, + stub_into_A, + stub_into_F, + stub_into_FA, }, }; -struct expectation { - const char *prefix; - const void *ip; - unsigned int ev, ec; -} /** Expected %%eip, vector and error code from the stub under test. */ - expectation; - -/** Latch details of the stub under test. */ -void expect(const void *prefix, const void *ip, - unsigned int ev, unsigned int ec) -{ - expectation = (struct expectation){prefix, ip, ev, ec}; - xtf_exlog_reset(); -} - -/** Check the exception long against the expected details. */ -void check(void) -{ - unsigned int entries = xtf_exlog_entries(); - - if ( entries != 1 ) - { - xtf_failure("Fail %s: Expected 1 exception (vec %u at %p), got %u\n", - expectation.prefix, expectation.ev, - expectation.ip, entries); - xtf_exlog_dump_log(); - return; - } - - exlog_entry_t *entry = xtf_exlog_entry(0); - if ( !entry ) - { - xtf_failure("Fail %s: Unable to retrieve exception log\n", - expectation.prefix); - return; - } - - if ( (_p(entry->ip) != expectation.ip) || - (entry->ev != expectation.ev) || - (entry->ec != expectation.ec) ) - { - xtf_failure("Fail %s:\n" - " Expected vec %2u[%04x] at %p\n" - " got vec %2u[%04x] at %p\n", - expectation.prefix, - expectation.ev, expectation.ec, expectation.ip, - entry->ev, entry->ec, _p(entry->ip)); - return; - } -} - -/** Print expected information in the case of an unexpected exception. */ -bool do_unhandled_exception(struct cpu_regs *regs) -{ - printk("Unhandled Exception at %p\n", _p(regs)); - check(); - - return false; -} - void test_insn(enum mode user, const struct insn *insn, exinfo_t exp) { - unsigned int vector = exinfo_vec(exp); - unsigned int error = exinfo_ec(exp); - bool fault = X86_EXC_FAULTS & (1u << vector); - printk(" Testing %s\n", insn->name); - for ( unsigned int i = 0; i < ARRAY_SIZE(insn->tests); ++i ) + for ( unsigned int i = 0; i < ARRAY_SIZE(insn->fn); ++i ) { - const struct single *s = &insn->tests[i]; - - expect(s->type, - fault ? s->fault : s->trap, - vector, error); + exinfo_t got; - user ? exec_user_void(s->fn) : s->fn(); + got = user ? exec_user(insn->fn[i]) : insn->fn[i](); - check(); + if ( exp != got ) + xtf_failure(" Fail (Force%c, Addr%c): expected %pe %s, got %pe %s\n", + i & 1 ? '+' : '-', + i & 2 ? '+' : '-', + _p(exp), exp & EXINFO_TRAP ? "trap" : "fault", + _p(got), got & EXINFO_TRAP ? "trap" : "fault"); - /* Avoid 'force' and 'forcered' stubs if FEP isn't available. */ + /* Avoid FEP stubs if FEP isn't available. */ if ( i == 1 && !xtf_has_fep ) break; } @@ -261,7 +165,7 @@ static void set_idt_entries_dpl(unsigned int dpl) idt[X86_EXC_OF].dpl = dpl; } -#define TRAP(V) EXINFO_SYM(V, 0) +#define TRAP(V) EXINFO_SYM(V, 0) | EXINFO_TRAP #define FAULT(V) EXINFO_SYM(V, 0) #define FAULT_EC(V, ...) EXINFO_SYM(V, EXC_EC_SYM(__VA_ARGS__)) @@ -342,13 +246,9 @@ void test_main(void) set_idt_entries_present(true); set_idt_entries_dpl(3); - xtf_exlog_start(); - cpl0_tests(); cpl3_tests(); - xtf_exlog_stop(); - xtf_success(NULL); }