On Mon, Jan 23, 2012 at 05:20:22PM +0100, Kevin Wolf wrote:
> Am 23.01.2012 17:10, schrieb Gleb Natapov:
> > On Mon, Jan 23, 2012 at 05:07:13PM +0100, 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.
> >>
> > Can you add the test case to taskswitch2.c?
> 
Running one test to check all aspects of taskswitch emulation.

> That's actually what I intended to do at first, but there's nothing to
> share and having a clean environment that can't interfere with other
> tests feels nicer.
> 
> What would we gain from merging the files?
> 
> Kevin
> 
> 
> > 
> >> Signed-off-by: Kevin Wolf <kw...@redhat.com>
> >> ---
> >>  config-i386.mak       |    3 +-
> >>  lib/x86/desc.c        |   37 +-----------------------------
> >>  lib/x86/desc.h        |   36 +++++++++++++++++++++++++++++
> >>  lib/x86/vm.c          |    4 +-
> >>  lib/x86/vm.h          |    1 +
> >>  x86/taskswitch_vm86.c |   59 
> >> +++++++++++++++++++++++++++++++++++++++++++++++++
> >>  x86/unittests.cfg     |    6 +++++
> >>  7 files changed, 107 insertions(+), 39 deletions(-)
> >>  create mode 100644 x86/taskswitch_vm86.c
> >>
> >> diff --git a/config-i386.mak b/config-i386.mak
> >> index de52f3d..b5c3b9c 100644
> >> --- a/config-i386.mak
> >> +++ b/config-i386.mak
> >> @@ -5,9 +5,10 @@ ldarch = elf32-i386
> >>  CFLAGS += -D__i386__
> >>  CFLAGS += -I $(KERNELDIR)/include
> >>  
> >> -tests = $(TEST_DIR)/taskswitch.flat $(TEST_DIR)/taskswitch2.flat
> >> +tests = $(TEST_DIR)/taskswitch.flat $(TEST_DIR)/taskswitch2.flat 
> >> $(TEST_DIR)/taskswitch_vm86.flat
> >>  
> >>  include config-x86-common.mak
> >>  
> >>  $(TEST_DIR)/taskswitch.elf: $(cstart.o) $(TEST_DIR)/taskswitch.o
> >>  $(TEST_DIR)/taskswitch2.elf: $(cstart.o) $(TEST_DIR)/taskswitch2.o
> >> +$(TEST_DIR)/taskswitch_vm86.elf: $(cstart.o) $(TEST_DIR)/taskswitch_vm86.o
> >> diff --git a/lib/x86/desc.c b/lib/x86/desc.c
> >> index 770c250..c4a3607 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)
> >> @@ -327,7 +292,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 abbb0c9..aae044a 100644
> >> --- a/lib/x86/vm.c
> >> +++ b/lib/x86/vm.c
> >> @@ -108,14 +108,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 bf8fd52..aebc5c3 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/taskswitch_vm86.c b/x86/taskswitch_vm86.c
> >> new file mode 100644
> >> index 0000000..363cb00
> >> --- /dev/null
> >> +++ b/x86/taskswitch_vm86.c
> >> @@ -0,0 +1,59 @@
> >> +#include "libcflat.h"
> >> +#include "desc.h"
> >> +#include "processor.h"
> >> +#include "vm.h"
> >> +
> >> +static tss32_t main_tss;
> >> +static tss32_t vm86_tss;
> >> +
> >> +#define FREE_GDT_INDEX 4
> >> +#define MAIN_TSS_INDEX (FREE_GDT_INDEX + 0)
> >> +#define VM86_TSS_INDEX (FREE_GDT_INDEX + 1)
> >> +
> >> +extern void vm86_start(void);
> >> +
> >> +int main(void)
> >> +{
> >> +    u8 *vm86_start;
> >> +
> >> +    setup_vm();
> >> +    setup_idt();
> >> +    setup_gdt();
> >> +
> >> +    /* 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 */
> >> +    asm volatile(
> >> +        "pushf\n"
> >> +        "orw $0x4000, (%esp)\n"
> >> +        "popf\n"
> >> +        "iret\n"
> >> +    );
> >> +
> >> +    return 0;
> >> +}
> >> diff --git a/x86/unittests.cfg b/x86/unittests.cfg
> >> index dac7d44..194850b 100644
> >> --- a/x86/unittests.cfg
> >> +++ b/x86/unittests.cfg
> >> @@ -76,6 +76,12 @@ smp = 2
> >>  extra_params = -cpu qemu64,-svm
> >>  groups = task
> >>  
> >> +[taskswitch_vm86]
> >> +file = taskswitch_vm86.flat
> >> +smp = 2
> >> +extra_params = -cpu qemu64,-svm
> >> +groups = task
> >> +
> >>  [kvmclock_test]
> >>  file = kvmclock_test.flat
> >>  smp = 2
> >> -- 
> >> 1.7.6.5
> >>
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe kvm" in
> >> the body of a message to majord...@vger.kernel.org
> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > 
> > --
> >                     Gleb.

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

Reply via email to