Re: [PATCH kvm-unittests v2] x86/taskswitch2: Task switches into/out of VM86

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Apr 12, 2013 at 01:14:47PM +0200, Kevin Wolf wrote:
> This adds a test case that jumps into VM86 by iret-ing to a TSS and back
> to Protected Mode using a task gate in the IDT.
> 
> Signed-off-by: Kevin Wolf <kwolf@xxxxxxxxxx>
Applied, thanks. Found a bug with it and emulate_invalid_guest_state=1
which is default. Are you running with emulate_invalid_guest_state=0?

> ---
>  lib/x86/desc.c    | 41 ++++------------------------------
>  lib/x86/desc.h    | 36 ++++++++++++++++++++++++++++++
>  lib/x86/vm.c      |  4 ++--
>  lib/x86/vm.h      |  1 +
>  x86/taskswitch2.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
>  5 files changed, 104 insertions(+), 45 deletions(-)
> 
> diff --git a/lib/x86/desc.c b/lib/x86/desc.c
> index 770c250..7c5c721 100644
> --- a/lib/x86/desc.c
> +++ b/lib/x86/desc.c
> @@ -27,41 +27,6 @@ typedef struct {
>  	u8 base_high;
>  } gdt_entry_t;
>  
> -typedef struct {
> -	u16 prev;
> -	u16 res1;
> -	u32 esp0;
> -	u16 ss0;
> -	u16 res2;
> -	u32 esp1;
> -	u16 ss1;
> -	u16 res3;
> -	u32 esp2;
> -	u16 ss2;
> -	u16 res4;
> -	u32 cr3;
> -	u32 eip;
> -	u32 eflags;
> -	u32 eax, ecx, edx, ebx, esp, ebp, esi, edi;
> -	u16 es;
> -	u16 res5;
> -	u16 cs;
> -	u16 res6;
> -	u16 ss;
> -	u16 res7;
> -	u16 ds;
> -	u16 res8;
> -	u16 fs;
> -	u16 res9;
> -	u16 gs;
> -	u16 res10;
> -	u16 ldt;
> -	u16 res11;
> -	u16 t:1;
> -	u16 res12:15;
> -	u16 iomap_base;
> -} tss32_t;
> -
>  extern idt_entry_t boot_idt[256];
>  
>  void set_idt_entry(int vec, void *addr, int dpl)
> @@ -268,9 +233,11 @@ unsigned exception_error_code(void)
>   * 0x18 - Not presend code segment
>   * 0x20 - Primery task
>   * 0x28 - Interrupt task
> + *
> + * 0x30 to 0x48 - Free to use for test cases
>   */
>  
> -static gdt_entry_t gdt[6];
> +static gdt_entry_t gdt[10];
>  #define TSS_GDT_OFFSET 4
>  
>  void set_gdt_entry(int num, u32 base,  u32 limit, u8 access, u8 gran)
> @@ -327,7 +294,7 @@ void setup_gdt(void)
>  		      ".Lflush2: "::"r"(0x10));
>  }
>  
> -static void set_idt_task_gate(int vec, u16 sel)
> +void set_idt_task_gate(int vec, u16 sel)
>  {
>      idt_entry_t *e = &boot_idt[vec];
>  
> diff --git a/lib/x86/desc.h b/lib/x86/desc.h
> index 0b4897c..f819452 100644
> --- a/lib/x86/desc.h
> +++ b/lib/x86/desc.h
> @@ -24,6 +24,41 @@ struct ex_regs {
>      unsigned long rflags;
>  };
>  
> +typedef struct {
> +	u16 prev;
> +	u16 res1;
> +	u32 esp0;
> +	u16 ss0;
> +	u16 res2;
> +	u32 esp1;
> +	u16 ss1;
> +	u16 res3;
> +	u32 esp2;
> +	u16 ss2;
> +	u16 res4;
> +	u32 cr3;
> +	u32 eip;
> +	u32 eflags;
> +	u32 eax, ecx, edx, ebx, esp, ebp, esi, edi;
> +	u16 es;
> +	u16 res5;
> +	u16 cs;
> +	u16 res6;
> +	u16 ss;
> +	u16 res7;
> +	u16 ds;
> +	u16 res8;
> +	u16 fs;
> +	u16 res9;
> +	u16 gs;
> +	u16 res10;
> +	u16 ldt;
> +	u16 res11;
> +	u16 t:1;
> +	u16 res12:15;
> +	u16 iomap_base;
> +} tss32_t;
> +
>  #define ASM_TRY(catch)                                  \
>      "movl $0, %%gs:4 \n\t"                              \
>      ".pushsection .data.ex \n\t"                        \
> @@ -44,6 +79,7 @@ unsigned exception_error_code(void);
>  void set_idt_entry(int vec, void *addr, int dpl);
>  void set_idt_sel(int vec, u16 sel);
>  void set_gdt_entry(int num, u32 base,  u32 limit, u8 access, u8 gran);
> +void set_idt_task_gate(int vec, u16 sel);
>  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));
> diff --git a/lib/x86/vm.c b/lib/x86/vm.c
> index 2852c6c..260ec45 100644
> --- a/lib/x86/vm.c
> +++ b/lib/x86/vm.c
> @@ -109,14 +109,14 @@ void install_large_page(unsigned long *cr3,
>                                unsigned long phys,
>                                void *virt)
>  {
> -    install_pte(cr3, 2, virt, phys | PTE_PRESENT | PTE_WRITE | PTE_PSE, 0);
> +    install_pte(cr3, 2, virt, phys | PTE_PRESENT | PTE_WRITE | PTE_USER | PTE_PSE, 0);
>  }
>  
>  void install_page(unsigned long *cr3,
>                    unsigned long phys,
>                    void *virt)
>  {
> -    install_pte(cr3, 1, virt, phys | PTE_PRESENT | PTE_WRITE, 0);
> +    install_pte(cr3, 1, virt, phys | PTE_PRESENT | PTE_WRITE | PTE_USER, 0);
>  }
>  
>  
> diff --git a/lib/x86/vm.h b/lib/x86/vm.h
> index 3473f8d..0b5b5c7 100644
> --- a/lib/x86/vm.h
> +++ b/lib/x86/vm.h
> @@ -13,6 +13,7 @@
>  #define PTE_PRESENT (1ull << 0)
>  #define PTE_PSE     (1ull << 7)
>  #define PTE_WRITE   (1ull << 1)
> +#define PTE_USER    (1ull << 2)
>  #define PTE_ADDR    (0xffffffffff000ull)
>  
>  void setup_vm();
> diff --git a/x86/taskswitch2.c b/x86/taskswitch2.c
> index 683834e..6573696 100644
> --- a/x86/taskswitch2.c
> +++ b/x86/taskswitch2.c
> @@ -5,6 +5,10 @@
>  #include "processor.h"
>  #include "vm.h"
>  
> +#define FREE_GDT_INDEX 6
> +#define MAIN_TSS_INDEX (FREE_GDT_INDEX + 0)
> +#define VM86_TSS_INDEX (FREE_GDT_INDEX + 1)
> +
>  #define xstr(s) str(s)
>  #define str(s) #s
>  
> @@ -113,15 +117,10 @@ start:
>  	goto start;
>  }
>  
> -int main()
> +void test_kernel_mode_int()
>  {
>  	unsigned int res;
>  
> -	setup_vm();
> -	setup_idt();
> -	setup_gdt();
> -	setup_tss32();
> -
>  	/* test that int $2 triggers task gate */
>  	test_count = 0;
>  	set_intr_task_gate(2, nmi_tss);
> @@ -217,6 +216,62 @@ int main()
>  	asm volatile ("ljmp $" xstr(TSS_INTR) ", $0xf4f4f4f4");
>  	printf("Jump back succeeded\n");
>  	report("ljmp", test_count == 1);
> +}
> +
> +void test_vm86_switch(void)
> +{
> +    static tss32_t main_tss;
> +    static tss32_t vm86_tss;
> +
> +    u8 *vm86_start;
> +
> +    /* Write a 'ud2' instruction somewhere below 1 MB */
> +    vm86_start = (void*) 0x42000;
> +    vm86_start[0] = 0x0f;
> +    vm86_start[1] = 0x0b;
> +
> +    /* Main TSS */
> +    set_gdt_entry(MAIN_TSS_INDEX, (u32)&main_tss, sizeof(tss32_t) - 1, 0x89, 0);
> +    ltr(MAIN_TSS_INDEX << 3);
> +    main_tss = (tss32_t) {
> +        .prev   = VM86_TSS_INDEX << 3,
> +        .cr3    = read_cr3(),
> +    };
> +
> +    /* VM86 TSS (marked as busy, so we can iret to it) */
> +    set_gdt_entry(VM86_TSS_INDEX, (u32)&vm86_tss, sizeof(tss32_t) - 1, 0x8b, 0);
> +    vm86_tss = (tss32_t) {
> +        .eflags = 0x20002,
> +        .cr3    = read_cr3(),
> +        .eip    = (u32) vm86_start & 0x0f,
> +        .cs     = (u32) vm86_start >> 4,
> +        .ds     = 0x1234,
> +        .es     = 0x2345,
> +    };
> +
> +    /* Setup task gate to main TSS for #UD */
> +    set_idt_task_gate(6, MAIN_TSS_INDEX << 3);
> +
> +    /* Jump into VM86 task with iret, #UD lets it come back immediately */
> +    printf("Switch to VM86 task and back\n");
> +    asm volatile(
> +        "pushf\n"
> +        "orw $0x4000, (%esp)\n"
> +        "popf\n"
> +        "iret\n"
> +    );
> +    report("VM86", 1);
> +}
> +
> +int main()
> +{
> +	setup_vm();
> +	setup_idt();
> +	setup_gdt();
> +	setup_tss32();
> +
> +	test_kernel_mode_int();
> +	test_vm86_switch();
>  
>  	printf("\nsummary: %d tests, %d failures\n", g_tests, g_fail);
>  
> -- 
> 1.8.1.4

--
			Gleb.
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux