kvm-unit-tests: Various improvements for x86 tests
Subsystems (3)
cover kvm-unit-tests: Various improvements for x86 tests
Highlights:
- improved preemption timer and interrupt injection tests (obsoletes my two patches in vmx queue)
- tests for IA32_APIC_BASE writes
- test for unconditional IO exiting (VMX)
- basic test of debug facilities (hw breakpoints etc.)
Jan Kiszka (13):
VMX: Add test cases around interrupt injection and halting
VMX: Extend preemption timer tests
apic: Remove redundant enable_apic
VMX: Fix return label in fault-triggering handlers lib/x86: Move exception test code into library
x2apic: Test for invalid state transitions lib/x86/apic: Consolidate over MSR_IA32_APICBASE
apic: Add test case for relocation and writing reserved bits
VMX: Check unconditional I/O exiting
Provide common report and report_summary services Ignore *.elf build outputs
svm: Add missing build dependency
x86: Add debug facility test case
.gitignore | 1 + Makefile | 3 +- config-x86-common.mak | 4 +- config-x86_64.mak | 2 +- lib/libcflat.h | 4 + lib/report.c | 36 +++++++ lib/x86/apic-defs.h | 3 + lib/x86/apic.c | 7 +- lib/x86/desc.c | 24 +++++ lib/x86/desc.h | 6 ++ x86/apic.c | 84 +++++++++++++--- x86/debug.c | 113 +++++++++++++++++++++ x86/emulator.c | 16 +-- x86/eventinj.c | 15 +-- x86/idt_test.c | 21 +--- x86/msr.c | 15 +-- x86/pcid.c | 14 +-- x86/pmu.c | 37 +++---- x86/taskswitch2.c | 15 +-- x86/unittests.cfg | 3 + x86/vmx.c | 57 +++-------- x86/vmx.h | 4 +- x86/vmx_tests.c | 264 ++++++++++++++++++++++++++++++++++++++++++++++---- 23 files changed, 548 insertions(+), 200 deletions(-) create mode 100644 lib/report.c create mode 100644 x86/debug.c
Signature · 1 line
1.8.1.1.298.ge7eed54
PATCH 1/13 VMX: Add test cases around interrupt injection and halting
From: Jan Kiszka <[email protected]>
This checks for interrupt delivery to L2, unintercepted hlt in L2 and explicit L2 suspension via the activity state HLT. All tests are performed both with direct interrupt injection and external interrupt interception.
--- x86/vmx.c | 3 +- x86/vmx.h | 3 ++ x86/vmx_tests.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 2 deletions(-)
x86/vmx.c +1 -2
@@ -457,7 +457,7 @@ static void init_vmcs_guest(void)vmcs_write (GUEST_RFLAGS ,0x2 );/* 26.3.1.5 */ -vmcs_write (GUEST_ACTV_STATE ,0 ); +vmcs_write (GUEST_ACTV_STATE ,ACTV_ACTIVE );vmcs_write (GUEST_INTR_STATE ,0 ); }
@@ -482,7 +482,6 @@ static int init_vmcs(struct vmcs **vmcs) ctrl_pin |=PIN_EXTINT |PIN_NMI |PIN_VIRT_NMI ; ctrl_exit =EXI_LOAD_EFER |EXI_HOST_64 ; ctrl_enter = (ENT_LOAD_EFER |ENT_GUEST_64 ); - ctrl_cpu[0 ] |=CPU_HLT ;/* DIsable IO instruction VMEXIT now */ ctrl_cpu[0 ] &= (~(CPU_IO |CPU_IO_BITMAP )); ctrl_cpu[1 ] =0 ;
x86/vmx.h +3 -0
@@ -500,6 +500,9 @@ enum Ctrl1 {#define INVEPT_SINGLE 1#define INVEPT_GLOBAL 2 +#define ACTV_ACTIVE 0 +#define ACTV_HLT 1 +extern struct regs regs;extern union vmx_basic basic;
x86/vmx_tests.c +144 -0
161 lines not on this page · raw message
Signature · 1 line
1.8.1.1.298.ge7eed54
PATCH 2/13 VMX: Extend preemption timer tests
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
This checks that we properly expire the preemption timer while the guest is in HLT state and that we do not progress guest execution of the preemption timer is activated with a timer value of 0.
--- x86/vmx_tests.c | 84 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 20 deletions(-)
x86/vmx_tests.c +64 -20
@@ -99,6 +99,7 @@ int vmenter_exit_handler()u32 preempt_scale;volatile unsigned long long tsc_val;volatile u32 preempt_val; +u64 saved_rip;int preemption_timer_init () {
@@ -126,17 +127,24 @@ void preemption_timer_main()if (get_stage () ==1 )vmcall (); } -while (1 ) { +set_stage (1 ); +while (get_stage () ==1 ) {if (((rdtsc () - tsc_val) >> preempt_scale) >10 * preempt_val) {set_stage (2 );vmcall (); } } + tsc_val =rdtsc (); + asmvolatile ("hlt" ); +vmcall (); +set_stage (5 ); +vmcall (); }int preemption_timer_exit_handler () { +bool guest_halted;u64 guest_rip;ulong reason;u32 insn_len;
@@ -147,33 +155,69 @@ int preemption_timer_exit_handler() insn_len =vmcs_read (EXI_INST_LEN );switch (reason) {case VMX_PREEMPT : -if (((rdtsc () - tsc_val) >> preempt_scale) < preempt_val) -report ("Preemption timer" ,0 ); -else -report ("Preemption timer" ,1 ); +switch (get_stage ()) { +case 1 : +case 2 : +report ("busy-wait for preemption timer" , + ((rdtsc () - tsc_val) >> preempt_scale) >= + preempt_val); +set_stage (3 ); +vmcs_write (PREEMPT_TIMER_VALUE , preempt_val); +return VMX_TEST_RESUME ; +case 3 : + guest_halted = + (vmcs_read (GUEST_ACTV_STATE ) ==ACTV_HLT ); +report ("preemption timer during hlt" , + ((rdtsc () - tsc_val) >> preempt_scale) >= + preempt_val && guest_halted); +set_stage (4 ); +vmcs_write (PIN_CONTROLS , +vmcs_read (PIN_CONTROLS ) & ~PIN_PREEMPT ); +vmcs_write (GUEST_ACTV_STATE ,ACTV_ACTIVE ); +return VMX_TEST_RESUME ; +case 4 : +report ("preemption timer with 0 value" , + saved_rip == guest_rip); +break ; +default : +printf ("Invalid stage.\n" ); +print_vmexit_info (); +break ; + }break ;case VMX_VMCALL : +vmcs_write (GUEST_RIP , guest_rip + insn_len);switch (get_stage ()) {case 0 : -if (vmcs_read (PREEMPT_TIMER_VALUE ) != preempt_val) -report ("Save preemption value" ,0 ); -else { -set_stage (get_stage () +1 ); - ctrl_exit = (vmcs_read (EXI_CONTROLS ) | -EXI_SAVE_PREEMPT ) & ctrl_exit_rev.clr; -vmcs_write (EXI_CONTROLS , ctrl_exit); - } -vmcs_write (GUEST_RIP , guest_rip + insn_len); +report ("Keep preemption value" , +vmcs_read (PREEMPT_TIMER_VALUE ) == preempt_val); +set_stage (1 ); +vmcs_write (PREEMPT_TIMER_VALUE , preempt_val); + ctrl_exit = (vmcs_read (EXI_CONTROLS ) | +EXI_SAVE_PREEMPT ) & ctrl_exit_rev.clr; +vmcs_write (EXI_CONTROLS , ctrl_exit);return VMX_TEST_RESUME ;case 1 : -if (vmcs_read (PREEMPT_TIMER_VALUE ) >= preempt_val) -report ("Save preemption value" ,0 ); -else -report ("Save preemption value" ,1 ); -vmcs_write (GUEST_RIP , guest_rip + insn_len); +report ("Save preemption value" , +vmcs_read (PREEMPT_TIMER_VALUE ) < preempt_val);return VMX_TEST_RESUME ;case 2 : -report ("Preemption timer" ,0 ); +report ("busy-wait for preemption timer" ,0 ); +set_stage (3 ); +vmcs_write (PREEMPT_TIMER_VALUE , preempt_val); +return VMX_TEST_RESUME ; +case 3 : +report ("preemption timer during hlt" ,0 ); +set_stage (4 ); +/* fall through */ +case 4 : +vmcs_write (PIN_CONTROLS , +vmcs_read (PIN_CONTROLS ) |PIN_PREEMPT ); +vmcs_write (PREEMPT_TIMER_VALUE ,0 ); + saved_rip = guest_rip + insn_len; +return VMX_TEST_RESUME ; +case 5 : +report ("preemption timer with 0 value (vmcall stage 5)" ,0 );break ;default :// Should not reach here
Signature · 1 line
1.8.1.1.298.ge7eed54
PATCH 3/13 apic: Remove redundant enable_apic
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
Already called by the bootstrap code.
--- x86/apic.c | 1 - 1 file changed, 1 deletion(-)
x86/apic.c +0 -1
@@ -326,7 +326,6 @@ int main()test_lapic_existence ();mask_pic_interrupts (); -enable_apic ();test_enable_x2apic ();test_self_ipi ();
Signature · 1 line
1.8.1.1.298.ge7eed54
PATCH 4/13 VMX: Fix return label in fault-triggering handlers
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
Some compiler versions (seen with gcc 4.8.1) move the resume label after the return statement which, of course, causes sever problems.
--- x86/vmx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
x86/vmx.c +2 -2
@@ -563,7 +563,7 @@ static void do_vmxon_off(void)vmx_on ();vmx_off (); resume: -return ; +barrier (); }static void do_write_feature_control (void )
@@ -572,7 +572,7 @@ static void do_write_feature_control(void)barrier ();wrmsr (MSR_IA32_FEATURE_CONTROL ,0 ); resume: -return ; +barrier (); }static int test_vmx_feature_control (void )
Signature · 1 line
1.8.1.1.298.ge7eed54
Paolo Bonzini
maintainerRe: [PATCH 04/13] VMX: Fix return label in fault-triggering handlers
Il 04/01/2014 18:59, Jan Kiszka ha scritto:
Quoted 4 lines
From: Jan Kiszka <[email protected]>
Some compiler versions (seen with gcc 4.8.1) move the resume label after the return statement which, of course, causes sever problems.
Can you include the assembly output? Do you mean after the "ret" instruction?
The return should not be needed except for the rule that a label must be followed by a statement. But I would not except any difference between a ";" and a barrier in this case.
Paolo
Quoted 28 lines
Signed-off-by Jan Kiszka <[email protected]>--- x86/vmx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)x86/vmx.c +2
-2@@ -563,7 +563,7 @@ static void do_vmxon_off(void)vmx_on ();vmx_off (); resume: -return ; +barrier (); }static void do_write_feature_control (void )@@ -572,7 +572,7 @@ static void do_write_feature_control(void)barrier ();wrmsr (MSR_IA32_FEATURE_CONTROL ,0 ); resume: -return ; +barrier (); }static int test_vmx_feature_control (void )
Paolo Bonzini
maintainerRe: [PATCH 04/13] VMX: Fix return label in fault-triggering handlers
Il 22/01/2014 16:00, Paolo Bonzini ha scritto:
Quoted 8 lines
Il 04/01/2014 18:59, Jan Kiszka ha scritto:
Quoted 4 lines
From: Jan Kiszka <[email protected]>
Some compiler versions (seen with gcc 4.8.1) move the resume label after the return statement which, of course, causes sever problems.
Can you include the assembly output? Do you mean after the "ret" instruction?
Reproduced now, I think it's a compiler bug... with -O2 it's even weird, &&resume points to the *first* instruction in the function.
I'll report it to GCC.
Paolo
PATCH 5/13 lib/x86: Move exception test code into library
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
Will also be used by the APIC test. Moving exception_return assignment out of line, we can drop the explicit compiler barrier.
--- lib/x86/desc.c | 24 ++++++++++++++++++++++++ lib/x86/desc.h | 4 ++++ x86/vmx.c | 34 +++++++--------------------------- 3 files changed, 35 insertions(+), 27 deletions(-)
lib/x86/desc.c +24 -0
@@ -353,3 +353,27 @@ void print_current_tss_info(void) tr, tss[0].prev, tss[i].prev); }#endif + +static bool exception; +static void *exception_return; + +static void exception_handler (struct ex_regs *regs) +{ + exception = true; + regs->rip = (unsigned long )exception_return; +} + +bool test_for_exception (unsigned int ex,void (*trigger_func)(void *data), +void *data) +{ +handle_exception (ex, exception_handler); + exception = false; +trigger_func (data); +handle_exception (ex,NULL ); +return exception; +} + +void set_exception_return (void *addr) +{ + exception_return = addr; +}
lib/x86/desc.h +4 -0
@@ -84,4 +84,8 @@ void set_intr_task_gate(int e, void *fn);void print_current_tss_info (void );void handle_exception (u8 v,void (*func)(struct ex_regs *regs)); +bool test_for_exception (unsigned int ex,void (*trigger_func)(void *data), +void *data); +void set_exception_return (void *addr); +#endif
x86/vmx.c +7 -27
@@ -538,38 +538,18 @@ static void init_vmx(void)memset (guest_syscall_stack,0 ,PAGE_SIZE ); } -static bool exception; -static void *exception_return; - -static void exception_handler (struct ex_regs *regs) +static void do_vmxon_off (void *data) { - exception = true; - regs->rip = (u64 )exception_return; -} - -static int test_for_exception (unsigned int ex,void (*func)(void )) -{ -handle_exception (ex, exception_handler); - exception = false; -func (); -handle_exception (ex,NULL ); -return exception; -} - -static void do_vmxon_off (void ) -{ - exception_return = &&resume; -barrier (); +set_exception_return (&&resume);vmx_on ();vmx_off (); resume:barrier (); } -static void do_write_feature_control (void ) +static void do_write_feature_control (void *data) { - exception_return = &&resume; -barrier (); +set_exception_return (&&resume);wrmsr (MSR_IA32_FEATURE_CONTROL ,0 ); resume:barrier ();
@@ -592,18 +572,18 @@ static int test_vmx_feature_control(void)wrmsr (MSR_IA32_FEATURE_CONTROL ,0 );report ("test vmxon with FEATURE_CONTROL cleared" , -test_for_exception (GP_VECTOR , &do_vmxon_off)); +test_for_exception (GP_VECTOR , &do_vmxon_off,NULL ));wrmsr (MSR_IA32_FEATURE_CONTROL ,0x4 );report ("test vmxon without FEATURE_CONTROL lock" , -test_for_exception (GP_VECTOR , &do_vmxon_off)); +test_for_exception (GP_VECTOR , &do_vmxon_off,NULL ));wrmsr (MSR_IA32_FEATURE_CONTROL ,0x5 ); vmx_enabled = ((rdmsr (MSR_IA32_FEATURE_CONTROL ) &0x5 ) ==0x5 );report ("test enable VMX in FEATURE_CONTROL" , vmx_enabled);report ("test FEATURE_CONTROL lock bit" , -test_for_exception (GP_VECTOR , &do_write_feature_control)); +test_for_exception (GP_VECTOR , &do_write_feature_control,NULL ));return !vmx_enabled; }
Signature · 1 line
1.8.1.1.298.ge7eed54
PATCH 6/13 x2apic: Test for invalid state transitions
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
This checks if KVM properly acknowledges invalid state transitions on MSR_APIC_BASE writes with a #GP.
--- lib/x86/apic-defs.h | 3 +++ x86/apic.c | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-)
lib/x86/apic-defs.h +3 -0
@@ -9,6 +9,9 @@*/ #define APIC_DEFAULT_PHYS_BASE 0xfee00000 +#define APIC_BSP (1UL << 8) +#define APIC_EXTD (1UL << 10) +#define APIC_EN (1UL << 11)#define APIC_ID 0x20
x86/apic.c +40 -1
60 lines not on this page · raw message
Signature · 1 line
1.8.1.1.298.ge7eed54
PATCH 7/13 lib/x86/apic: Consolidate over MSR_IA32_APICBASE
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
--- lib/x86/apic.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
lib/x86/apic.c +3 -4
@@ -1,5 +1,6 @@#include "libcflat.h" #include "apic.h" +#include "msr.h" static void *g_apic = (void *)0xfee00000 ;static void *g_ioapic = (void *)0xfec00000 ;
@@ -99,8 +100,6 @@ uint32_t apic_id(void)return apic_ops->id (); } -#define MSR_APIC_BASE 0x0000001b -int enable_x2apic (void ) {unsigned a, b, c, d;
@@ -108,9 +107,9 @@ int enable_x2apic(void) asm ("cpuid" :"=a" (a),"=b" (b),"=c" (c),"=d" (d) :"0" (1 ));if (c & (1 <<21 )) { - asm ("rdmsr" :"=a" (a),"=d" (d) :"c" (MSR_APIC_BASE )); + asm ("rdmsr" :"=a" (a),"=d" (d) :"c" (MSR_IA32_APICBASE )); a |=1 <<10 ; - asm ("wrmsr" : :"a" (a),"d" (d),"c" (MSR_APIC_BASE )); + asm ("wrmsr" : :"a" (a),"d" (d),"c" (MSR_IA32_APICBASE )); apic_ops = &x2apic_ops;return 1 ; }else {
Signature · 1 line
1.8.1.1.298.ge7eed54
PATCH 8/13 apic: Add test case for relocation and writing reserved bits
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
Check that the xAPIC is relocatable and that writing a reserved bit to MSR_IA32_APICBASE triggers a #GP.
--- x86/apic.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
x86/apic.c +27 -0
@@ -120,6 +120,32 @@ void test_enable_x2apic(void) } } +#define ALTERNATE_APIC_BASE 0x42000000 + +static void test_apicbase (void ) +{ +u64 orig_apicbase =rdmsr (MSR_IA32_APICBASE ); +u32 lvr =apic_read (APIC_LVR ); +u64 value; + +wrmsr (MSR_IA32_APICBASE , orig_apicbase & ~(APIC_EN |APIC_EXTD )); +wrmsr (MSR_IA32_APICBASE ,ALTERNATE_APIC_BASE |APIC_BSP |APIC_EN ); + +report ("relocate apic" , + *(volatile u32 *)(ALTERNATE_APIC_BASE +APIC_LVR ) == lvr); + + value = orig_apicbase | (1UL << (cpuid (0x80000008 ).a &0xff )); +report ("apicbase: reserved physaddr bits" , +test_for_exception (GP_VECTOR , do_write_apicbase, &value)); + + value = orig_apicbase |1 ; +report ("apicbase: reserved low bits" , +test_for_exception (GP_VECTOR , do_write_apicbase, &value)); + +wrmsr (MSR_IA32_APICBASE , orig_apicbase); +apic_write (APIC_SPIV ,0x1ff ); +} +static void eoi (void ) {apic_write (APIC_EOI ,0 );
@@ -366,6 +392,7 @@ int main()mask_pic_interrupts ();test_enable_x2apic (); +test_apicbase ();test_self_ipi ();
Signature · 1 line
1.8.1.1.298.ge7eed54
PATCH 9/13 VMX: Check unconditional I/O exiting
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
Test if we ignore "unconditional I/O exiting" as long as "use I/O bitmap" is enabled. Also test if unconditional exiting itself works.
--- x86/vmx_tests.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-)
x86/vmx_tests.c +35 -1
@@ -701,13 +701,21 @@ static void iobmp_main()report ("I/O bitmap - overrun" ,1 ); else report("I/O bitmap - overrun", 0); +set_stage (9 ); +vmcall (); +outb (0x0 ,0x0 ); +report ("I/O bitmap - ignore unconditional exiting" , stage ==9 ); +set_stage (10 ); +vmcall (); +outb (0x0 ,0x0 ); +report ("I/O bitmap - unconditional exiting" , stage ==11 ); }static int iobmp_exit_handler () {u64 guest_rip;ulong reason, exit_qual; -u32 insn_len; +u32 insn_len, ctrl_cpu0; guest_rip =vmcs_read (GUEST_RIP ); reason =vmcs_read (EXI_REASON ) &0xff ;
@@ -765,6 +773,32 @@ static int iobmp_exit_handler()if (((exit_qual &VMX_IO_PORT_MASK ) >>VMX_IO_PORT_SHIFT ) ==0xFFFF )set_stage (stage +1 );break ; +case 9 : +case 10 : + ctrl_cpu0 =vmcs_read (CPU_EXEC_CTRL0 ); +vmcs_write (CPU_EXEC_CTRL0 , ctrl_cpu0 & ~CPU_IO ); +set_stage (stage +1 ); +break ; +default : +// Should not reach here +printf ("ERROR : unexpected stage, %d\n" ,get_stage ()); +print_vmexit_info (); +return VMX_TEST_VMEXIT ; + } +vmcs_write (GUEST_RIP , guest_rip + insn_len); +return VMX_TEST_RESUME ; +case VMX_VMCALL : +switch (get_stage ()) { +case 9 : + ctrl_cpu0 =vmcs_read (CPU_EXEC_CTRL0 ); + ctrl_cpu0 |=CPU_IO |CPU_IO_BITMAP ; +vmcs_write (CPU_EXEC_CTRL0 , ctrl_cpu0); +break ; +case 10 : + ctrl_cpu0 =vmcs_read (CPU_EXEC_CTRL0 ); + ctrl_cpu0 = (ctrl_cpu0 & ~CPU_IO_BITMAP ) |CPU_IO ; +vmcs_write (CPU_EXEC_CTRL0 , ctrl_cpu0); +break ;default :// Should not reach here printf ("ERROR : unexpected stage, %d\n" ,get_stage ());
Signature · 1 line
1.8.1.1.298.ge7eed54
PATCH 10/13 Provide common report and report_summary services
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
This both reduces code duplication and standardizes the output format a bit more.
--- Makefile | 3 ++- lib/libcflat.h | 4 ++++ lib/report.c | 36 ++++++++++++++++++++++++++++++++++++ x86/apic.c | 15 +-------------- x86/emulator.c | 16 +--------------- x86/eventinj.c | 15 +-------------- x86/idt_test.c | 21 ++++----------------- x86/msr.c | 15 +-------------- x86/pcid.c | 14 +------------- x86/pmu.c | 37 +++++++++++++++---------------------- x86/taskswitch2.c | 15 +-------------- x86/vmx.c | 16 +--------------- x86/vmx.h | 1 - 13 files changed, 68 insertions(+), 140 deletions(-) create mode 100644 lib/report.c
Makefile +2 -1
@@ -14,7 +14,8 @@ libcflat := lib/libcflat.a cflatobjs := \ lib/panic.o \ lib/printf.o \ - lib/string.o + lib/string.o \ + lib/report.o cflatobjs += lib/argv.o #include architecure specific make rules
lib/libcflat.h +4 -0
@@ -45,6 +45,7 @@ extern char *strcat(char *dest, const char *src);extern int strcmp (const char *a,const char *b);extern int printf (const char *fmt, ...); +extern int snprintf (char *buf,int size,const char *fmt, ...);extern int vsnprintf (char *buf,int size,const char *fmt,va_list va);extern void puts (const char *s);
@@ -58,4 +59,7 @@ extern long atol(const char *ptr);#define offsetof (TYPE ,MEMBER ) __builtin_offsetof (TYPE, MEMBER)#define NULL ((void *)0UL) + +void report (const char *msg_fmt,bool pass, ...); +int report_summary (void );#endif
lib/report.c new file +36 -0
@@ -0,0 +1,36 @@ +/* +* Test result reporting +* +* Copyright (c) Siemens AG, 2014 +* +* Authors: +* Jan Kiszka <[email protected]> +* +* This work is licensed under the terms of the GNU LGPL, version 2. +*/ + +#include "libcflat.h" + +static unsigned int tests, failures; + +void report (const char *msg_fmt,bool pass, ...) +{ +char buf[2000 ]; +va_list va; + + tests++; +printf ("%s: " , pass ?"PASS" :"FAIL" ); +va_start (va, pass); +vsnprintf (buf,sizeof (buf), msg_fmt, va); +va_end (va); +puts (buf); +puts ("\n" ); +if (!pass) + failures++; +} + +int report_summary (void ) +{ +printf ("\nSUMMARY: %d tests, %d failures\n" , tests, failures); +return failures >0 ?1 :0 ; +}
x86/apic.c +1 -14
@@ -6,17 +6,6 @@#include "isr.h" #include "msr.h" -static int g_fail; -static int g_tests; - -static void report (const char *msg,int pass) -{ - ++g_tests; -printf ("%s: %s\n" , msg, (pass ?"PASS" :"FAIL" )); -if (!pass) - ++g_fail; -} -static void test_lapic_existence (void ) {u32 lvr;
@@ -403,7 +392,5 @@ int main()test_tsc_deadline_timer (); -printf ("\nsummary: %d tests, %d failures\n" , g_tests, g_fail); - -return g_fail !=0 ; +return report_summary (); }
x86/emulator.c +1 -15
@@ -7,8 +7,6 @@#define memset __builtin_memset#define TESTDEV_IO_PORT 0xe0 -int fails, tests; -static int exceptions;struct regs {
@@ -25,17 +23,6 @@ struct insn_desc {size_t len; }; -void report (const char *name,int result) -{ - ++tests; -if (result) -printf ("PASS: %s\n" , name); -else { -printf ("FAIL: %s\n" , name); - ++fails; - } -} -static char st1[] ="abcdefghijklmnop" ;void test_stringio ()
@@ -1022,6 +1009,5 @@ int main()test_string_io_mmio (mem); -printf ("\nSUMMARY: %d tests, %d failures\n" , tests, fails); -return fails ?1 :0 ; +return report_summary (); }
x86/eventinj.c +1 -14
@@ -12,9 +12,6 @@# define R "e"#endif -static int g_fail; -static int g_tests; -static inline void io_delay (void ) { }
@@ -24,14 +21,6 @@ static inline void outl(int addr, int val) asmvolatile ("outl %1, %w0" : :"d" (addr),"a" (val)); } -static void report (const char *msg,int pass) -{ - ++g_tests; -printf ("%s: %s\n" , msg, (pass ?"PASS" :"FAIL" )); -if (!pass) - ++g_fail; -} -void apic_self_ipi (u8 v) { apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_FIXED |
@@ -416,7 +405,5 @@ int main()printf ("After int 33 with shadowed stack\n" );report ("int 33 with shadowed stack" , test_count ==1 ); -printf ("\nsummary: %d tests, %d failures\n" , g_tests, g_fail); - -return g_fail !=0 ; +return report_summary (); }
x86/idt_test.c +4 -17
@@ -21,19 +21,6 @@ int test_gp(void)return exception_vector (); } -static int nr_fail, nr_test; - -static void report (int cond,const char *name) -{ - ++nr_test; -if (!cond) { - ++nr_fail; -printf ("%s: FAIL\n" , name); - }else { -printf ("%s: PASS\n" , name); - } -} -int main (void ) {int r;
@@ -41,9 +28,9 @@ int main(void)printf ("Starting IDT test\n" );setup_idt (); r =test_gp (); -report (r ==GP_VECTOR ,"Testing #GP" ); +report ("Testing #GP" , r ==GP_VECTOR ); r =test_ud2 (); -report (r ==UD_VECTOR ,"Testing #UD" ); -printf ("%d failures of %d tests\n" , nr_fail, nr_test); -return !nr_fail ?0 :1 ; +report ("Testing #UD" , r ==UD_VECTOR ); + +return report_summary (); }
x86/msr.c +1 -14
@@ -80,17 +80,6 @@ static int find_msr_info(int msr_index)return -1 ; } - -int nr_passed, nr_tests; - -static void report (const char *name,int passed) -{ - ++nr_tests; -if (passed) - ++nr_passed; -printf ("%s: %s\n" , name, passed ?"PASS" :"FAIL" ); -} -static void test_msr_rw (int msr_index,unsigned long long input,unsigned long long expected) {unsigned long long r =0 ;
@@ -142,8 +131,6 @@ int main(int ac, char **av)test_syscall_lazy_load (); -printf ("%d tests, %d failures\n" , nr_tests, nr_tests - nr_passed); - -return nr_passed == nr_tests ?0 :1 ; +return report_summary (); }
x86/pcid.c +1 -13
@@ -4,8 +4,6 @@#include "processor.h" #include "desc.h" -int nr_passed, nr_tests; -#define X86_FEATURE_PCID (1 << 17)#define X86_FEATURE_INVPCID (1 << 10)
@@ -22,14 +20,6 @@ struct invpcid_desc { unsigned long addr : 64; }; -static void report (const char *name,int passed) -{ - ++nr_tests; -if (passed) - ++nr_passed; -printf ("%s: %s\n" , name, passed ?"PASS" :"FAIL" ); -} -int write_cr0_checking (unsigned long val) { asm volatile(ASM_TRY("1f")
@@ -180,7 +170,5 @@ int main(int ac, char **av)else test_invpcid_disabled (); -printf ("%d tests, %d failures\n" , nr_tests, nr_tests - nr_passed); - -return nr_passed == nr_tests ?0 :1 ; +return report_summary (); }
x86/pmu.c +15 -22
@@ -92,7 +92,6 @@ struct pmu_event { };static int num_counters; -static int tests, failures;char *buf;
@@ -211,13 +210,6 @@ static void measure(pmu_counter_t *evt, int count)stop_event (&evt[i]); } -static void report (const char *name,int n,bool pass) -{ -printf ("%s: pmu %s-%d\n" , pass ?"PASS" :"FAIL" , name, n); - tests +=1 ; - failures += !pass; -} -static bool verify_event (uint64_t count,struct pmu_event *e) {// printf("%lld >= %lld <= %lld\n", e->min, count, e->max);
@@ -236,12 +228,14 @@ static void check_gp_counter(struct pmu_event *evt) .ctr = MSR_IA32_PERFCTR0, .config = EVNTSEL_OS | EVNTSEL_USR | evt->unit_sel, }; +char fmt[100 ];int i;for (i =0 ; i < num_counters; i++, cnt.ctr++) { cnt.count =0 ;measure (&cnt,1 ); -report (evt->name, i,verify_event (cnt.count, evt)); +snprintf (fmt,sizeof (fmt),"%s-%%d" , evt->name); +report (fmt,verify_event (cnt.count, evt), i); } }
@@ -268,7 +262,7 @@ static void check_fixed_counters(void) cnt.count =0 ; cnt.ctr = fixed_events[i].unit_sel;measure (&cnt,1 ); -report ("fixed" , i,verify_event (cnt.count, &fixed_events[i])); +report ("fixed-%d" ,verify_event (cnt.count, &fixed_events[i]), i); } }
@@ -299,7 +293,7 @@ static void check_counters_many(void)if (!verify_counter (&cnt[i]))break ; -report ("all counters" ,0 , i == n); +report ("all counters" , i == n); }static void check_counter_overflow (void )
@@ -329,13 +323,13 @@ static void check_counter_overflow(void) idx =event_to_global_idx (&cnt); cnt.count =1 - count;measure (&cnt,1 ); -report ("overflow" , i, cnt.count ==1 ); +report ("overflow-%d" , cnt.count ==1 , i); status =rdmsr (MSR_CORE_PERF_GLOBAL_STATUS ); -report ("overflow status" , i, status & (1ull << idx)); +report ("overflow status-%d" , status & (1ull << idx), i);wrmsr (MSR_CORE_PERF_GLOBAL_OVF_CTRL , status); status =rdmsr (MSR_CORE_PERF_GLOBAL_STATUS ); -report ("overflow status clear" , i, !(status & (1ull << idx))); -report ("overflow irq" , i,check_irq () == (i %2 )); +report ("overflow status clear-%d" , !(status & (1ull << idx)), i); +report ("overflow irq-%d" ,check_irq () == (i %2 ), i); } }
@@ -348,7 +342,7 @@ static void check_gp_counter_cmask(void) }; cnt.config |= (0x2 <<EVNTSEL_CMASK_SHIFT );measure (&cnt,1 ); -report ("cmask" ,0 , cnt.count < gp_events[1 ].min); +report ("cmask" , cnt.count < gp_events[1 ].min); }static void check_rdpmc (void )
@@ -360,15 +354,15 @@ static void check_rdpmc(void)uint64_t x = (val &0xffffffff ) | ((1ull << (eax.split.bit_width -32 )) -1 ) <<32 ;wrmsr (MSR_IA32_PERFCTR0 + i, val); -report ("rdpmc" , i,rdpmc (i) == x); -report ("rdpmc fast" , i,rdpmc (i | (1 <<31 )) == (u32 )val); +report ("rdpmc-%d" ,rdpmc (i) == x, i); +report ("rdpmc fast-%d" ,rdpmc (i | (1 <<31 )) == (u32 )val, i); }for (i =0 ; i < edx.split.num_counters_fixed; i++) {uint64_t x = (val &0xffffffff ) | ((1ull << (edx.split.bit_width_fixed -32 )) -1 ) <<32 ;wrmsr (MSR_CORE_PERF_FIXED_CTR0 + i, val); -report ("rdpmc fixed" , i,rdpmc (i | (1 <<30 )) == x); -report ("rdpmc fixed fast" , i,rdpmc (i | (3 <<30 )) == (u32 )val); +report ("rdpmc fixed-%d" ,rdpmc (i | (1 <<30 )) == x, i); +report ("rdpmc fixed fast-%d" ,rdpmc (i | (3 <<30 )) == (u32 )val, i); } }
@@ -409,6 +403,5 @@ int main(int ac, char **av)check_counter_overflow ();check_gp_counter_cmask (); -printf ("\n%d tests, %d failures\n" , tests, failures); -return !failures ?0 :1 ; +return report_summary (); }
x86/taskswitch2.c +1 -14
@@ -18,21 +18,10 @@ static volatile unsigned int test_divider;static char *fault_addr;static ulong fault_phys; -static int g_fail; -static int g_tests; -static inline void io_delay (void ) { } -static void report (const char *msg,int pass) -{ - ++g_tests; -printf ("%s: %s\n" , msg, (pass ?"PASS" :"FAIL" )); -if (!pass) - ++g_fail; -} -static void nmi_tss (void ) { start:
@@ -273,7 +262,5 @@ int main()test_kernel_mode_int ();test_vm86_switch (); -printf ("\nsummary: %d tests, %d failures\n" , g_tests, g_fail); - -return g_fail !=0 ; +return report_summary (); }
x86/vmx.c +1 -15
@@ -37,7 +37,6 @@#include "smp.h" #include "io.h" -int fails, tests;u32 *vmxon_region;struct vmcs *vmcs_root;u32 vpid_cnt;
@@ -63,17 +62,6 @@ extern void *vmx_return;extern void *entry_sysenter;extern void *guest_entry; -void report (const char *name,int result) -{ - ++tests; -if (result) -printf ("PASS: %s\n" , name); -else { -printf ("FAIL: %s\n" , name); - ++fails; - } -} -static int make_vmcs_current (struct vmcs *vmcs) {bool ret;
@@ -786,7 +774,6 @@ int main(void)setup_vm ();setup_idt (); - fails = tests =0 ; hypercall_field =0 ;if (!(cpuid (1 ).c & (1 <<5 ))) {
@@ -815,6 +802,5 @@ int main(void) goto exit; exit: -printf ("\nSUMMARY: %d tests, %d failures\n" , tests, fails); -return fails ?1 :0 ; +return report_summary (); }
x86/vmx.h +0 -1
@@ -550,7 +550,6 @@ static inline void invept(unsigned long type, u64 eptp) asmvolatile ("invept %0, %1\n" ::"m" (operand),"r" (type)); } -void report (const char *name,int result);void print_vmexit_info (); void install_ept_entry(unsigned long *pml4, int pte_level, unsigned long guest_addr, unsigned long pte,
Signature · 1 line
1.8.1.1.298.ge7eed54
PATCH 11/13 Ignore *.elf build outputs
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
--- .gitignore | 1 + 1 file changed, 1 insertion(+)
.gitignore +1 -0
@@ -3,6 +3,7 @@ *.d *.o *.flat +*.elf .pc patches .stgit-*
Signature · 1 line
1.8.1.1.298.ge7eed54
PATCH 12/13 svm: Add missing build dependency
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
--- config-x86-common.mak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
config-x86-common.mak +1 -1
@@ -86,7 +86,7 @@ $(TEST_DIR)/xsave.elf: $(cstart.o) $(TEST_DIR)/xsave.o $(TEST_DIR)/rmap_chain.elf: $(cstart.o) $(TEST_DIR)/rmap_chain.o -$(TEST_DIR)/svm.elf: $(cstart.o) +$(TEST_DIR)/svm.elf: $(cstart.o) $(TEST_DIR)/svm.o $(TEST_DIR)/kvmclock_test.elf: $(cstart.o) $(TEST_DIR)/kvmclock.o \ $(TEST_DIR)/kvmclock_test.o
Signature · 1 line
1.8.1.1.298.ge7eed54
PATCH 13/13 x86: Add debug facility test case
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
This adds a basic test for INT3/#BP, hardware breakpoints, hardware watchpoints and single-stepping.
--- config-x86-common.mak | 2 + config-x86_64.mak | 2 +- lib/x86/desc.h | 2 + x86/debug.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++ x86/unittests.cfg | 3 ++ 5 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 x86/debug.c
config-x86-common.mak +2 -0
@@ -103,6 +103,8 @@ $(TEST_DIR)/pcid.elf: $(cstart.o) $(TEST_DIR)/pcid.o $(TEST_DIR)/vmx.elf: $(cstart.o) $(TEST_DIR)/vmx.o $(TEST_DIR)/vmx_tests.o +$(TEST_DIR)/debug.elf: $(cstart.o) $(TEST_DIR)/debug.o + arch_clean: $(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat $(TEST_DIR)/*.elf \ $(TEST_DIR)/.*.d $(TEST_DIR)/lib/.*.d $(TEST_DIR)/lib/*.o
config-x86_64.mak +1 -1
@@ -7,7 +7,7 @@ CFLAGS += -D__x86_64__ tests = $(TEST_DIR)/access.flat $(TEST_DIR)/apic.flat \ $(TEST_DIR)/emulator.flat $(TEST_DIR)/idt_test.flat \ $(TEST_DIR)/xsave.flat $(TEST_DIR)/rmap_chain.flat \ - $(TEST_DIR)/pcid.flat + $(TEST_DIR)/pcid.flat $(TEST_DIR)/debug.flat tests += $(TEST_DIR)/svm.flat tests += $(TEST_DIR)/vmx.flat
lib/x86/desc.h +2 -0
@@ -66,6 +66,8 @@ typedef struct {".popsection \n\t" \ "1111:" +#define DB_VECTOR 1 +#define BP_VECTOR 3#define UD_VECTOR 6#define GP_VECTOR 13
x86/debug.c new file +113 -0
113 lines not on this page · raw message
x86/unittests.cfg +3 -0
@@ -155,3 +155,6 @@ file = vmx.flat extra_params = -cpu host,+vmx arch = x86_64 +[debug] +file = debug.flag +arch = x86_64
Signature · 1 line
1.8.1.1.298.ge7eed54
Paolo Bonzini
maintainerIl 04/01/2014 18:59, Jan Kiszka ha scritto:
Quoted 40 lines
Highlights:
- improved preemption timer and interrupt injection tests (obsoletes my two patches in vmx queue)
- tests forIA32_APIC_BASEwrites
- test for unconditional IO exiting (VMX)
- basic test of debug facilities (hw breakpoints etc.)Jan Kiszka (13):
VMX: Add test cases around interrupt injection and halting
VMX: Extend preemption timer tests
apic: Remove redundantenable_apic
VMX: Fix return label in fault-triggering handlers lib/x86: Move exception test code into library
x2apic: Test for invalid state transitionslib/x86/apic: Consolidate overMSR_IA32_APICBASE
apic: Add test case for relocation and writing reserved bits
VMX: Check unconditional I/O exiting
Provide common report andreport_summaryservices Ignore *.elf build outputs
svm: Add missing build dependency
x86: Add debug facility test case.gitignore | 1 + Makefile | 3 +- config-x86-common.mak | 4 +- config-x86_64.mak | 2 +- lib/libcflat.h | 4 + lib/report.c | 36 +++++++ lib/x86/apic-defs.h | 3 + lib/x86/apic.c | 7 +- lib/x86/desc.c | 24 +++++ lib/x86/desc.h | 6 ++ x86/apic.c | 84 +++++++++++++--- x86/debug.c | 113 +++++++++++++++++++++ x86/emulator.c | 16 +-- x86/eventinj.c | 15 +-- x86/idt_test.c | 21 +--- x86/msr.c | 15 +-- x86/pcid.c | 14 +-- x86/pmu.c | 37 +++----
Quoted 9 lines
x86/taskswitch2.c | 15 +-- x86/unittests.cfg | 3 + x86/vmx.c | 57 +++-------- x86/vmx.h | 4 +- x86/vmx_tests.c | 264 ++++++++++++++++++++++++++++++++++++++++++++++---- 23 files changed, 548 insertions(+), 200 deletions(-) create mode 100644 lib/report.c create mode 100644 x86/debug.c
I'm applying patches 3-13 to the master branch, and patches 1-2 to the vmx branch.
Thanks!
Paolo
Il 04/01/2014 18:59, Jan Kiszka ha scritto:
Quoted 7 lines
Highlights:
- improved preemption timer and interrupt injection tests (obsoletes my two patches in vmx queue)
- tests forIA32_APIC_BASEwrites
- test for unconditional IO exiting (VMX)
- basic test of debug facilities (hw breakpoints etc.)
Quoted 14 lines
Jan Kiszka (13):
VMX: Add test cases around interrupt injection and halting
VMX: Extend preemption timer tests
apic: Remove redundantenable_apic
VMX: Fix return label in fault-triggering handlers lib/x86: Move exception test code into library
x2apic: Test for invalid state transitionslib/x86/apic: Consolidate overMSR_IA32_APICBASE
apic: Add test case for relocation and writing reserved bits
VMX: Check unconditional I/O exiting
Provide common report andreport_summaryservices Ignore *.elf build outputs
svm: Add missing build dependency
x86: Add debug facility test case
Applied patches 3-13 for now. Will go back to 1 and 2 when I look at your pending KVM patches.
Thanks, and sorry for the delay. I was sure I had already pushed this (and I had been testing with them for one month).
Paolo