public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH unit-tests 00/16] task switch and event injection tests
@ 2010-12-22 15:06 Gleb Natapov
  2010-12-22 15:06 ` [PATCH unit-tests 01/16] Move idt.c into lib code Gleb Natapov
                   ` (15 more replies)
  0 siblings, 16 replies; 22+ messages in thread
From: Gleb Natapov @ 2010-12-22 15:06 UTC (permalink / raw)
  To: avi, mtosatti; +Cc: kvm

Long time ago I wrote a mini guest to test various interesting task
switch and even injection scenarios. This is the port of the test cases
to unit test framework.

Gleb Natapov (16):
  Move idt.c into lib code.
  Make access.c use library functions.
  Remove duplicated idt code from apic test.
  Remove unused function from apic test.
  Rename idt.[ch] into desc.[ch]
  Specify correct operand length for ltr and str.
  Move irq_(enable|disable) into library code.
  Add another task switch test.
  Move vm.[ch] info library code.
  Fix mmu on 32 bit.
  Set WP bit in CR0 to make write protection work.
  Fix exception handling on i386 arch.
  Move handle_irq() from apic test into library code.
  Add handle_exception() interface.
  Move invlpg() into library code.
  Add even injection test.

 config-i386.mak       |    3 +-
 config-x86-common.mak |   24 ++--
 lib/x86/desc.c        |  393 +++++++++++++++++++++++++++++++++++++++++++++++++
 lib/x86/desc.h        |   51 +++++++
 lib/x86/idt.h         |   19 ---
 lib/x86/isr.c         |   99 +++++++++++++
 lib/x86/isr.h         |   14 ++
 lib/x86/processor.h   |   18 ++-
 lib/x86/vm.c          |  256 ++++++++++++++++++++++++++++++++
 lib/x86/vm.h          |   47 ++++++
 x86/access.c          |   97 +------------
 x86/apic.c            |  156 +-------------------
 x86/emulator.c        |    2 +-
 x86/eventinj.c        |  372 ++++++++++++++++++++++++++++++++++++++++++++++
 x86/idt.c             |  148 -------------------
 x86/idt_test.c        |    2 +-
 x86/taskswitch2.c     |  185 +++++++++++++++++++++++
 x86/vm.c              |  229 ----------------------------
 x86/vm.h              |   46 ------
 x86/xsave.c           |    2 +-
 20 files changed, 1464 insertions(+), 699 deletions(-)
 create mode 100644 lib/x86/desc.c
 create mode 100644 lib/x86/desc.h
 delete mode 100644 lib/x86/idt.h
 create mode 100644 lib/x86/isr.c
 create mode 100644 lib/x86/isr.h
 create mode 100644 lib/x86/vm.c
 create mode 100644 lib/x86/vm.h
 create mode 100644 x86/eventinj.c
 delete mode 100644 x86/idt.c
 create mode 100644 x86/taskswitch2.c
 delete mode 100644 x86/vm.c
 delete mode 100644 x86/vm.h

-- 
1.7.2.3


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH unit-tests 01/16] Move idt.c into lib code.
  2010-12-22 15:06 [PATCH unit-tests 00/16] task switch and event injection tests Gleb Natapov
@ 2010-12-22 15:06 ` Gleb Natapov
  2010-12-22 15:06 ` [PATCH unit-tests 02/16] Make access.c use library functions Gleb Natapov
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Gleb Natapov @ 2010-12-22 15:06 UTC (permalink / raw)
  To: avi, mtosatti; +Cc: kvm

Make it compilable in 32 and 64 bit mode.

Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
 config-x86-common.mak |    7 +-
 lib/x86/idt.c         |  159 +++++++++++++++++++++++++++++++++++++++++++++++++
 lib/x86/idt.h         |    1 +
 x86/idt.c             |  148 ---------------------------------------------
 4 files changed, 164 insertions(+), 151 deletions(-)
 create mode 100644 lib/x86/idt.c
 delete mode 100644 x86/idt.c

diff --git a/config-x86-common.mak b/config-x86-common.mak
index c5508b3..2269c4a 100644
--- a/config-x86-common.mak
+++ b/config-x86-common.mak
@@ -11,6 +11,7 @@ cflatobjs += \
 cflatobjs += lib/x86/fwcfg.o
 cflatobjs += lib/x86/apic.o
 cflatobjs += lib/x86/atomic.o
+cflatobjs += lib/x86/idt.o
 
 $(libcflat): LDFLAGS += -nostdlib
 $(libcflat): CFLAGS += -ffreestanding -I lib
@@ -50,7 +51,7 @@ $(TEST_DIR)/vmexit.elf: $(cstart.o) $(TEST_DIR)/vmexit.o
 $(TEST_DIR)/smptest.elf: $(cstart.o) $(TEST_DIR)/smptest.o
 
 $(TEST_DIR)/emulator.elf: $(cstart.o) $(TEST_DIR)/emulator.o \
-			   $(TEST_DIR)/vm.o $(TEST_DIR)/idt.o
+			   $(TEST_DIR)/vm.o
 
 $(TEST_DIR)/port80.elf: $(cstart.o) $(TEST_DIR)/port80.o
 
@@ -65,9 +66,9 @@ $(TEST_DIR)/realmode.o: bits = 32
 
 $(TEST_DIR)/msr.elf: $(cstart.o) $(TEST_DIR)/msr.o
 
-$(TEST_DIR)/idt_test.elf: $(cstart.o) $(TEST_DIR)/idt.o $(TEST_DIR)/idt_test.o
+$(TEST_DIR)/idt_test.elf: $(cstart.o) $(TEST_DIR)/idt_test.o
 
-$(TEST_DIR)/xsave.elf: $(cstart.o) $(TEST_DIR)/idt.o $(TEST_DIR)/xsave.o
+$(TEST_DIR)/xsave.elf: $(cstart.o) $(TEST_DIR)/xsave.o
 
 $(TEST_DIR)/rmap_chain.elf: $(cstart.o) $(TEST_DIR)/rmap_chain.o \
 			     $(TEST_DIR)/vm.o
diff --git a/lib/x86/idt.c b/lib/x86/idt.c
new file mode 100644
index 0000000..b3e47d4
--- /dev/null
+++ b/lib/x86/idt.c
@@ -0,0 +1,159 @@
+#include "idt.h"
+#include "libcflat.h"
+#include "processor.h"
+
+typedef struct {
+    unsigned short offset0;
+    unsigned short selector;
+    unsigned short ist : 3;
+    unsigned short : 5;
+    unsigned short type : 4;
+    unsigned short : 1;
+    unsigned short dpl : 2;
+    unsigned short p : 1;
+    unsigned short offset1;
+#ifdef __x86_64__
+    unsigned offset2;
+    unsigned reserved;
+#endif
+} idt_entry_t;
+
+static idt_entry_t idt[256];
+
+void load_lidt(idt_entry_t *idt, int nentries)
+{
+    struct descriptor_table_ptr dt;
+
+    dt.limit = nentries * sizeof(*idt) - 1;
+    dt.base = (unsigned long)idt;
+    lidt(&dt);
+    asm volatile ("lidt %0" : : "m"(dt));
+}
+
+void set_idt_entry(int vec, void *addr, int dpl)
+{
+    idt_entry_t *e = &idt[vec];
+    memset(e, 0, sizeof *e);
+    e->offset0 = (unsigned long)addr;
+    e->selector = read_cs();
+    e->ist = 0;
+    e->type = 14;
+    e->dpl = dpl;
+    e->p = 1;
+    e->offset1 = (unsigned long)addr >> 16;
+#ifdef __x86_64__
+    e->offset2 = (unsigned long)addr >> 32;
+#endif
+}
+
+struct ex_regs {
+    unsigned long rax, rcx, rdx, rbx;
+    unsigned long dummy, rbp, rsi, rdi;
+#ifdef __x86_64__
+    unsigned long r8, r9, r10, r11;
+    unsigned long r12, r13, r14, r15;
+#endif
+    unsigned long vector;
+    unsigned long error_code;
+    unsigned long rip;
+    unsigned long cs;
+    unsigned long rflags;
+};
+
+struct ex_record {
+    unsigned long rip;
+    unsigned long handler;
+};
+
+extern struct ex_record exception_table_start, exception_table_end;
+
+void do_handle_exception(struct ex_regs *regs)
+{
+    struct ex_record *ex;
+    unsigned ex_val;
+
+    ex_val = regs->vector | (regs->error_code << 16);
+
+    asm("mov %0, %%gs:4" : : "r"(ex_val));
+
+    for (ex = &exception_table_start; ex != &exception_table_end; ++ex) {
+        if (ex->rip == regs->rip) {
+            regs->rip = ex->handler;
+            return;
+        }
+    }
+    printf("unhandled excecption\n");
+    exit(7);
+}
+
+#ifdef __x86_64__
+#  define R "r"
+#  define W "q"
+#  define S "8"
+#else
+#  define R "e"
+#  define W "l"
+#  define S "4"
+#endif
+
+asm (".pushsection .text \n\t"
+     "ud_fault: \n\t"
+     "push"W" $0 \n\t"
+     "push"W" $6 \n\t"
+     "jmp handle_exception \n\t"
+
+     "gp_fault: \n\t"
+     "push"W" $13 \n\t"
+     "jmp handle_exception \n\t"
+
+     "de_fault: \n\t"
+     "push"W" $0 \n\t"
+     "push"W" $0 \n\t"
+     "jmp handle_exception \n\t"
+
+     "handle_exception: \n\t"
+#ifdef __x86_64__
+     "push %r15; push %r14; push %r13; push %r12 \n\t"
+     "push %r11; push %r10; push %r9; push %r8 \n\t"
+#endif
+     "push %"R"di; push %"R"si; push %"R"bp; sub $"S", %"R"sp \n\t"
+     "push %"R"bx; push %"R"dx; push %"R"cx; push %"R"ax \n\t"
+     "mov %"R"sp, %"R"di \n\t"
+     "call do_handle_exception \n\t"
+     "pop %"R"ax; pop %"R"cx; pop %"R"dx; pop %"R"bx \n\t"
+     "add $"S", %"R"sp; pop %"R"bp; pop %"R"si; pop %"R"di \n\t"
+#ifdef __x86_64__
+     "pop %r8; pop %r9; pop %r10; pop %r11 \n\t"
+     "pop %r12; pop %r13; pop %r14; pop %r15 \n\t"
+#endif
+     "add $"S", %"R"sp \n\t"
+     "add $"S", %"R"sp \n\t"
+     "iret"W" \n\t"
+     ".popsection");
+
+
+void setup_idt(void)
+{
+    extern char ud_fault, gp_fault, de_fault;
+
+    load_lidt(idt, 256);
+    set_idt_entry(0, &de_fault, 0);
+    set_idt_entry(6, &ud_fault, 0);
+    set_idt_entry(13, &gp_fault, 0);
+}
+
+unsigned exception_vector(void)
+{
+    unsigned short vector;
+
+    asm("mov %%gs:4, %0" : "=rm"(vector));
+    return vector;
+}
+
+unsigned exception_error_code(void)
+{
+    unsigned short error_code;
+
+    asm("mov %%gs:6, %0" : "=rm"(error_code));
+    return error_code;
+}
diff --git a/lib/x86/idt.h b/lib/x86/idt.h
index 6babcb4..81b8944 100644
--- a/lib/x86/idt.h
+++ b/lib/x86/idt.h
@@ -15,5 +15,6 @@ void setup_idt(void);
 
 unsigned exception_vector(void);
 unsigned exception_error_code(void);
+void set_idt_entry(int vec, void *addr, int dpl);
 
 #endif
diff --git a/x86/idt.c b/x86/idt.c
deleted file mode 100644
index 4480833..0000000
--- a/x86/idt.c
+++ /dev/null
@@ -1,148 +0,0 @@
-#include "idt.h"
-#include "libcflat.h"
-
-typedef struct {
-    unsigned short offset0;
-    unsigned short selector;
-    unsigned short ist : 3;
-    unsigned short : 5;
-    unsigned short type : 4;
-    unsigned short : 1;
-    unsigned short dpl : 2;
-    unsigned short p : 1;
-    unsigned short offset1;
-    unsigned offset2;
-    unsigned reserved;
-} idt_entry_t;
-
-static idt_entry_t idt[256];
-
-typedef struct {
-    unsigned short limit;
-    unsigned long linear_addr;
-} __attribute__((packed)) descriptor_table_t;
-
-void lidt(idt_entry_t *idt, int nentries)
-{
-    descriptor_table_t dt;
-
-    dt.limit = nentries * sizeof(*idt) - 1;
-    dt.linear_addr = (unsigned long)idt;
-    asm volatile ("lidt %0" : : "m"(dt));
-}
-
-unsigned short read_cs()
-{
-    unsigned short r;
-
-    asm volatile ("mov %%cs, %0" : "=r"(r));
-    return r;
-}
-
-void set_idt_entry(idt_entry_t *e, void *addr, int dpl)
-{
-    memset(e, 0, sizeof *e);
-    e->offset0 = (unsigned long)addr;
-    e->selector = read_cs();
-    e->ist = 0;
-    e->type = 14;
-    e->dpl = dpl;
-    e->p = 1;
-    e->offset1 = (unsigned long)addr >> 16;
-    e->offset2 = (unsigned long)addr >> 32;
-}
-
-struct ex_regs {
-    unsigned long rax, rcx, rdx, rbx;
-    unsigned long dummy, rbp, rsi, rdi;
-    unsigned long r8, r9, r10, r11;
-    unsigned long r12, r13, r14, r15;
-    unsigned long vector;
-    unsigned long error_code;
-    unsigned long rip;
-    unsigned long cs;
-    unsigned long rflags;
-};
-
-struct ex_record {
-    unsigned long rip;
-    unsigned long handler;
-};
-
-extern struct ex_record exception_table_start, exception_table_end;
-
-void do_handle_exception(struct ex_regs *regs)
-{
-    struct ex_record *ex;
-    unsigned ex_val;
-
-    ex_val = regs->vector | (regs->error_code << 16);
-
-    asm("mov %0, %%gs:4" : : "r"(ex_val));
-
-    for (ex = &exception_table_start; ex != &exception_table_end; ++ex) {
-        if (ex->rip == regs->rip) {
-            regs->rip = ex->handler;
-            return;
-        }
-    }
-    printf("unhandled excecption\n");
-    exit(7);
-}
-
-asm (".pushsection .text \n\t"
-     "ud_fault: \n\t"
-     "pushq $0 \n\t"
-     "pushq $6 \n\t"
-     "jmp handle_exception \n\t"
-
-     "gp_fault: \n\t"
-     "pushq $13 \n\t"
-     "jmp handle_exception \n\t"
-
-     "de_fault: \n\t"
-     "pushq $0 \n\t"
-     "pushq $0 \n\t"
-     "jmp handle_exception \n\t"
-
-     "handle_exception: \n\t"
-     "push %r15; push %r14; push %r13; push %r12 \n\t"
-     "push %r11; push %r10; push %r9; push %r8 \n\t"
-     "push %rdi; push %rsi; push %rbp; sub $8, %rsp \n\t"
-     "push %rbx; push %rdx; push %rcx; push %rax \n\t"
-     "mov %rsp, %rdi \n\t"
-     "call do_handle_exception \n\t"
-     "pop %rax; pop %rcx; pop %rdx; pop %rbx \n\t"
-     "add $8, %rsp; pop %rbp; pop %rsi; pop %rdi \n\t"
-     "pop %r8; pop %r9; pop %r10; pop %r11 \n\t"
-     "pop %r12; pop %r13; pop %r14; pop %r15 \n\t"
-     "add $16, %rsp \n\t"
-     "iretq \n\t"
-     ".popsection");
-
-
-void setup_idt(void)
-{
-    extern char ud_fault, gp_fault, de_fault;
-
-    lidt(idt, 256);
-    set_idt_entry(&idt[0], &de_fault, 0);
-    set_idt_entry(&idt[6], &ud_fault, 0);
-    set_idt_entry(&idt[13], &gp_fault, 0);
-}
-
-unsigned exception_vector(void)
-{
-    unsigned short vector;
-
-    asm("mov %%gs:4, %0" : "=rm"(vector));
-    return vector;
-}
-
-unsigned exception_error_code(void)
-{
-    unsigned short error_code;
-
-    asm("mov %%gs:6, %0" : "=rm"(error_code));
-    return error_code;
-}
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH unit-tests 02/16] Make access.c use library functions.
  2010-12-22 15:06 [PATCH unit-tests 00/16] task switch and event injection tests Gleb Natapov
  2010-12-22 15:06 ` [PATCH unit-tests 01/16] Move idt.c into lib code Gleb Natapov
@ 2010-12-22 15:06 ` Gleb Natapov
  2010-12-22 15:06 ` [PATCH unit-tests 03/16] Remove duplicated idt code from apic test Gleb Natapov
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Gleb Natapov @ 2010-12-22 15:06 UTC (permalink / raw)
  To: avi, mtosatti; +Cc: kvm

access.c has functions that are provided by library code. Remove them
and use library functions instead.

Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
 x86/access.c |   92 +++------------------------------------------------------
 1 files changed, 5 insertions(+), 87 deletions(-)

diff --git a/x86/access.c b/x86/access.c
index 067565b..df943d9 100644
--- a/x86/access.c
+++ b/x86/access.c
@@ -1,5 +1,7 @@
 
 #include "libcflat.h"
+#include "idt.h"
+#include "processor.h"
 
 #define smp_id() 0
 
@@ -98,34 +100,6 @@ static inline void *va(pt_element_t phys)
     return (void *)phys;
 }
 
-static unsigned long read_cr0()
-{
-    unsigned long cr0;
-
-    asm volatile ("mov %%cr0, %0" : "=r"(cr0));
-
-    return cr0;
-}
-
-static void write_cr0(unsigned long cr0)
-{
-    asm volatile ("mov %0, %%cr0" : : "r"(cr0));
-}
-
-typedef struct {
-    unsigned short offset0;
-    unsigned short selector;
-    unsigned short ist : 3;
-    unsigned short : 5;
-    unsigned short type : 4;
-    unsigned short : 1;
-    unsigned short dpl : 2;
-    unsigned short p : 1;
-    unsigned short offset1;
-    unsigned offset2;
-    unsigned reserved;
-} idt_entry_t;
-
 typedef struct {
     pt_element_t pt_pool;
     unsigned pt_pool_size;
@@ -143,7 +117,6 @@ typedef struct {
     pt_element_t ignore_pde;
     int expected_fault;
     unsigned expected_error;
-    idt_entry_t idt[256];
 } ac_test_t;
 
 typedef struct {
@@ -154,51 +127,6 @@ typedef struct {
 
 static void ac_test_show(ac_test_t *at);
 
-void lidt(idt_entry_t *idt, int nentries)
-{
-    descriptor_table_t dt;
-
-    dt.limit = nentries * sizeof(*idt) - 1;
-    dt.linear_addr = (unsigned long)idt;
-    asm volatile ("lidt %0" : : "m"(dt));
-}
-
-unsigned short read_cs()
-{
-    unsigned short r;
-
-    asm volatile ("mov %%cs, %0" : "=r"(r));
-    return r;
-}
-
-unsigned long long rdmsr(unsigned index)
-{
-    unsigned a, d;
-
-    asm volatile("rdmsr" : "=a"(a), "=d"(d) : "c"(index));
-    return ((unsigned long long)d << 32) | a;
-}
-
-void wrmsr(unsigned index, unsigned long long val)
-{
-    unsigned a = val, d = val >> 32;
-
-    asm volatile("wrmsr" : : "a"(a), "d"(d), "c"(index));
-}
-
-void set_idt_entry(idt_entry_t *e, void *addr, int dpl)
-{
-    memset(e, 0, sizeof *e);
-    e->offset0 = (unsigned long)addr;
-    e->selector = read_cs();
-    e->ist = 0;
-    e->type = 14;
-    e->dpl = dpl;
-    e->p = 1;
-    e->offset1 = (unsigned long)addr >> 16;
-    e->offset2 = (unsigned long)addr >> 32;
-}
-
 void set_cr0_wp(int wp)
 {
     unsigned long cr0 = read_cr0();
@@ -222,13 +150,11 @@ void set_efer_nx(int nx)
 
 static void ac_env_int(ac_pool_t *pool)
 {
-    static idt_entry_t idt[256];
+    setup_idt();
 
-    memset(idt, 0, sizeof(idt));
-    lidt(idt, 256);
     extern char page_fault, kernel_entry;
-    set_idt_entry(&idt[14], &page_fault, 0);
-    set_idt_entry(&idt[0x20], &kernel_entry, 3);
+    set_idt_entry(14, &page_fault, 0);
+    set_idt_entry(0x20, &kernel_entry, 3);
 
     pool->pt_pool = 33 * 1024 * 1024;
     pool->pt_pool_size = 120 * 1024 * 1024 - pool->pt_pool;
@@ -273,14 +199,6 @@ int ac_test_bump(ac_test_t *at)
     return ret;
 }
 
-unsigned long read_cr3()
-{
-    unsigned long cr3;
-
-    asm volatile ("mov %%cr3, %0" : "=r"(cr3));
-    return cr3;
-}
-
 void invlpg(void *addr)
 {
     asm volatile ("invlpg (%0)" : : "r"(addr));
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH unit-tests 03/16] Remove duplicated idt code from apic test.
  2010-12-22 15:06 [PATCH unit-tests 00/16] task switch and event injection tests Gleb Natapov
  2010-12-22 15:06 ` [PATCH unit-tests 01/16] Move idt.c into lib code Gleb Natapov
  2010-12-22 15:06 ` [PATCH unit-tests 02/16] Make access.c use library functions Gleb Natapov
@ 2010-12-22 15:06 ` Gleb Natapov
  2010-12-22 15:06 ` [PATCH unit-tests 04/16] Remove unused function " Gleb Natapov
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Gleb Natapov @ 2010-12-22 15:06 UTC (permalink / raw)
  To: avi, mtosatti; +Cc: kvm

Use library idt code instead.

Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
 x86/apic.c |   49 +++++++++++--------------------------------------
 1 files changed, 11 insertions(+), 38 deletions(-)

diff --git a/x86/apic.c b/x86/apic.c
index 2207040..6d06f9f 100644
--- a/x86/apic.c
+++ b/x86/apic.c
@@ -2,22 +2,7 @@
 #include "apic.h"
 #include "vm.h"
 #include "smp.h"
-
-typedef struct {
-    unsigned short offset0;
-    unsigned short selector;
-    unsigned short ist : 3;
-    unsigned short : 5;
-    unsigned short type : 4;
-    unsigned short : 1;
-    unsigned short dpl : 2;
-    unsigned short p : 1;
-    unsigned short offset1;
-#ifdef __x86_64__
-    unsigned offset2;
-    unsigned reserved;
-#endif
-} idt_entry_t;
+#include "idt.h"
 
 typedef struct {
     ulong regs[sizeof(ulong)*2];
@@ -90,8 +75,6 @@ asm (
 #endif
     );
 
-static idt_entry_t *idt = 0;
-
 static int g_fail;
 static int g_tests;
 
@@ -128,22 +111,12 @@ void test_enable_x2apic(void)
     }
 }
 
-static void set_idt_entry(unsigned vec, void (*func)(isr_regs_t *regs))
+static void handle_irq(unsigned vec, void (*func)(isr_regs_t *regs))
 {
     u8 *thunk = vmalloc(50);
-    ulong ptr = (ulong)thunk;
-    idt_entry_t ent = {
-        .offset0 = ptr,
-        .selector = read_cs(),
-        .ist = 0,
-        .type = 14,
-        .dpl = 0,
-        .p = 1,
-        .offset1 = ptr >> 16,
-#ifdef __x86_64__
-        .offset2 = ptr >> 32,
-#endif
-    };
+
+    set_idt_entry(vec, thunk, 0);
+
 #ifdef __x86_64__
     /* sub $8, %rsp */
     *thunk++ = 0x48; *thunk++ = 0x83; *thunk++ = 0xec; *thunk++ = 0x08;
@@ -164,7 +137,6 @@ static void set_idt_entry(unsigned vec, void (*func)(isr_regs_t *regs))
     *thunk ++ = 0xe9;
     *(u32 *)thunk = (ulong)isr_entry_point - (ulong)(thunk + 4);
 #endif
-    idt[vec] = ent;
 }
 
 static void irq_disable(void)
@@ -194,7 +166,7 @@ static void test_self_ipi(void)
 {
     int vec = 0xf1;
 
-    set_idt_entry(vec, self_ipi_isr);
+    handle_irq(vec, self_ipi_isr);
     irq_enable();
     apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_FIXED | vec,
                    0);
@@ -234,7 +206,7 @@ static void ioapic_isr_77(isr_regs_t *regs)
 
 static void test_ioapic_intr(void)
 {
-    set_idt_entry(0x77, ioapic_isr_77);
+    handle_irq(0x77, ioapic_isr_77);
     set_ioapic_redir(0x10, 0x77);
     toggle_irq_line(0x10);
     asm volatile ("nop");
@@ -262,8 +234,8 @@ static void ioapic_isr_66(isr_regs_t *regs)
 
 static void test_ioapic_simultaneous(void)
 {
-    set_idt_entry(0x78, ioapic_isr_78);
-    set_idt_entry(0x66, ioapic_isr_66);
+    handle_irq(0x78, ioapic_isr_78);
+    handle_irq(0x66, ioapic_isr_66);
     set_ioapic_redir(0x10, 0x78);
     set_ioapic_redir(0x11, 0x66);
     irq_disable();
@@ -323,7 +295,7 @@ static void test_sti_nmi(void)
 	return;
     }
 
-    set_idt_entry(2, nmi_handler);
+    handle_irq(2, nmi_handler);
     on_cpu(1, update_cr3, (void *)read_cr3());
 
     sti_loop_active = 1;
@@ -343,6 +315,7 @@ int main()
 {
     setup_vm();
     smp_init();
+    setup_idt();
 
     test_lapic_existence();
 
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH unit-tests 04/16] Remove unused function from apic test.
  2010-12-22 15:06 [PATCH unit-tests 00/16] task switch and event injection tests Gleb Natapov
                   ` (2 preceding siblings ...)
  2010-12-22 15:06 ` [PATCH unit-tests 03/16] Remove duplicated idt code from apic test Gleb Natapov
@ 2010-12-22 15:06 ` Gleb Natapov
  2010-12-22 15:06 ` [PATCH unit-tests 05/16] Rename idt.[ch] into desc.[ch] Gleb Natapov
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Gleb Natapov @ 2010-12-22 15:06 UTC (permalink / raw)
  To: avi, mtosatti; +Cc: kvm


Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
 x86/apic.c |    5 -----
 1 files changed, 0 insertions(+), 5 deletions(-)

diff --git a/x86/apic.c b/x86/apic.c
index 6d06f9f..bcb9fc1 100644
--- a/x86/apic.c
+++ b/x86/apic.c
@@ -78,11 +78,6 @@ asm (
 static int g_fail;
 static int g_tests;
 
-static void outb(unsigned char data, unsigned short port)
-{
-    asm volatile ("out %0, %1" : : "a"(data), "d"(port));
-}
-
 static void report(const char *msg, int pass)
 {
     ++g_tests;
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH unit-tests 05/16] Rename idt.[ch] into desc.[ch]
  2010-12-22 15:06 [PATCH unit-tests 00/16] task switch and event injection tests Gleb Natapov
                   ` (3 preceding siblings ...)
  2010-12-22 15:06 ` [PATCH unit-tests 04/16] Remove unused function " Gleb Natapov
@ 2010-12-22 15:06 ` Gleb Natapov
  2010-12-29  9:38   ` Avi Kivity
  2010-12-22 15:06 ` [PATCH unit-tests 06/16] Specify correct operand length for ltr and str Gleb Natapov
                   ` (10 subsequent siblings)
  15 siblings, 1 reply; 22+ messages in thread
From: Gleb Natapov @ 2010-12-22 15:06 UTC (permalink / raw)
  To: avi, mtosatti; +Cc: kvm

All descriptor related code will go there.

Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
 config-x86-common.mak |    2 +-
 lib/x86/desc.c        |  159 +++++++++++++++++++++++++++++++++++++++++++++++++
 lib/x86/desc.h        |   20 ++++++
 lib/x86/idt.c         |  159 -------------------------------------------------
 lib/x86/idt.h         |   20 ------
 x86/access.c          |    2 +-
 x86/apic.c            |    2 +-
 x86/emulator.c        |    2 +-
 x86/idt_test.c        |    2 +-
 x86/xsave.c           |    2 +-
 10 files changed, 185 insertions(+), 185 deletions(-)
 create mode 100644 lib/x86/desc.c
 create mode 100644 lib/x86/desc.h
 delete mode 100644 lib/x86/idt.c
 delete mode 100644 lib/x86/idt.h

diff --git a/config-x86-common.mak b/config-x86-common.mak
index 2269c4a..367c0be 100644
--- a/config-x86-common.mak
+++ b/config-x86-common.mak
@@ -11,7 +11,7 @@ cflatobjs += \
 cflatobjs += lib/x86/fwcfg.o
 cflatobjs += lib/x86/apic.o
 cflatobjs += lib/x86/atomic.o
-cflatobjs += lib/x86/idt.o
+cflatobjs += lib/x86/desc.o
 
 $(libcflat): LDFLAGS += -nostdlib
 $(libcflat): CFLAGS += -ffreestanding -I lib
diff --git a/lib/x86/desc.c b/lib/x86/desc.c
new file mode 100644
index 0000000..25a25bc
--- /dev/null
+++ b/lib/x86/desc.c
@@ -0,0 +1,159 @@
+#include "libcflat.h"
+#include "desc.h"
+#include "processor.h"
+
+typedef struct {
+    unsigned short offset0;
+    unsigned short selector;
+    unsigned short ist : 3;
+    unsigned short : 5;
+    unsigned short type : 4;
+    unsigned short : 1;
+    unsigned short dpl : 2;
+    unsigned short p : 1;
+    unsigned short offset1;
+#ifdef __x86_64__
+    unsigned offset2;
+    unsigned reserved;
+#endif
+} idt_entry_t;
+
+static idt_entry_t idt[256];
+
+void load_lidt(idt_entry_t *idt, int nentries)
+{
+    struct descriptor_table_ptr dt;
+
+    dt.limit = nentries * sizeof(*idt) - 1;
+    dt.base = (unsigned long)idt;
+    lidt(&dt);
+    asm volatile ("lidt %0" : : "m"(dt));
+}
+
+void set_idt_entry(int vec, void *addr, int dpl)
+{
+    idt_entry_t *e = &idt[vec];
+    memset(e, 0, sizeof *e);
+    e->offset0 = (unsigned long)addr;
+    e->selector = read_cs();
+    e->ist = 0;
+    e->type = 14;
+    e->dpl = dpl;
+    e->p = 1;
+    e->offset1 = (unsigned long)addr >> 16;
+#ifdef __x86_64__
+    e->offset2 = (unsigned long)addr >> 32;
+#endif
+}
+
+struct ex_regs {
+    unsigned long rax, rcx, rdx, rbx;
+    unsigned long dummy, rbp, rsi, rdi;
+#ifdef __x86_64__
+    unsigned long r8, r9, r10, r11;
+    unsigned long r12, r13, r14, r15;
+#endif
+    unsigned long vector;
+    unsigned long error_code;
+    unsigned long rip;
+    unsigned long cs;
+    unsigned long rflags;
+};
+
+struct ex_record {
+    unsigned long rip;
+    unsigned long handler;
+};
+
+extern struct ex_record exception_table_start, exception_table_end;
+
+void do_handle_exception(struct ex_regs *regs)
+{
+    struct ex_record *ex;
+    unsigned ex_val;
+
+    ex_val = regs->vector | (regs->error_code << 16);
+
+    asm("mov %0, %%gs:4" : : "r"(ex_val));
+
+    for (ex = &exception_table_start; ex != &exception_table_end; ++ex) {
+        if (ex->rip == regs->rip) {
+            regs->rip = ex->handler;
+            return;
+        }
+    }
+    printf("unhandled excecption\n");
+    exit(7);
+}
+
+#ifdef __x86_64__
+#  define R "r"
+#  define W "q"
+#  define S "8"
+#else
+#  define R "e"
+#  define W "l"
+#  define S "4"
+#endif
+
+asm (".pushsection .text \n\t"
+     "ud_fault: \n\t"
+     "push"W" $0 \n\t"
+     "push"W" $6 \n\t"
+     "jmp handle_exception \n\t"
+
+     "gp_fault: \n\t"
+     "push"W" $13 \n\t"
+     "jmp handle_exception \n\t"
+
+     "de_fault: \n\t"
+     "push"W" $0 \n\t"
+     "push"W" $0 \n\t"
+     "jmp handle_exception \n\t"
+
+     "handle_exception: \n\t"
+#ifdef __x86_64__
+     "push %r15; push %r14; push %r13; push %r12 \n\t"
+     "push %r11; push %r10; push %r9; push %r8 \n\t"
+#endif
+     "push %"R"di; push %"R"si; push %"R"bp; sub $"S", %"R"sp \n\t"
+     "push %"R"bx; push %"R"dx; push %"R"cx; push %"R"ax \n\t"
+     "mov %"R"sp, %"R"di \n\t"
+     "call do_handle_exception \n\t"
+     "pop %"R"ax; pop %"R"cx; pop %"R"dx; pop %"R"bx \n\t"
+     "add $"S", %"R"sp; pop %"R"bp; pop %"R"si; pop %"R"di \n\t"
+#ifdef __x86_64__
+     "pop %r8; pop %r9; pop %r10; pop %r11 \n\t"
+     "pop %r12; pop %r13; pop %r14; pop %r15 \n\t"
+#endif
+     "add $"S", %"R"sp \n\t"
+     "add $"S", %"R"sp \n\t"
+     "iret"W" \n\t"
+     ".popsection");
+
+
+void setup_idt(void)
+{
+    extern char ud_fault, gp_fault, de_fault;
+
+    load_lidt(idt, 256);
+    set_idt_entry(0, &de_fault, 0);
+    set_idt_entry(6, &ud_fault, 0);
+    set_idt_entry(13, &gp_fault, 0);
+}
+
+unsigned exception_vector(void)
+{
+    unsigned short vector;
+
+    asm("mov %%gs:4, %0" : "=rm"(vector));
+    return vector;
+}
+
+unsigned exception_error_code(void)
+{
+    unsigned short error_code;
+
+    asm("mov %%gs:6, %0" : "=rm"(error_code));
+    return error_code;
+}
diff --git a/lib/x86/desc.h b/lib/x86/desc.h
new file mode 100644
index 0000000..81b8944
--- /dev/null
+++ b/lib/x86/desc.h
@@ -0,0 +1,20 @@
+#ifndef __IDT_TEST__
+#define __IDT_TEST__
+
+void setup_idt(void);
+
+#define ASM_TRY(catch)                                  \
+    "movl $0, %%gs:4 \n\t"                              \
+    ".pushsection .data.ex \n\t"                        \
+    ".quad 1111f, " catch "\n\t"                        \
+    ".popsection \n\t"                                  \
+    "1111:"
+
+#define UD_VECTOR   6
+#define GP_VECTOR   13
+
+unsigned exception_vector(void);
+unsigned exception_error_code(void);
+void set_idt_entry(int vec, void *addr, int dpl);
+
+#endif
diff --git a/lib/x86/idt.c b/lib/x86/idt.c
deleted file mode 100644
index b3e47d4..0000000
--- a/lib/x86/idt.c
+++ /dev/null
@@ -1,159 +0,0 @@
-#include "idt.h"
-#include "libcflat.h"
-#include "processor.h"
-
-typedef struct {
-    unsigned short offset0;
-    unsigned short selector;
-    unsigned short ist : 3;
-    unsigned short : 5;
-    unsigned short type : 4;
-    unsigned short : 1;
-    unsigned short dpl : 2;
-    unsigned short p : 1;
-    unsigned short offset1;
-#ifdef __x86_64__
-    unsigned offset2;
-    unsigned reserved;
-#endif
-} idt_entry_t;
-
-static idt_entry_t idt[256];
-
-void load_lidt(idt_entry_t *idt, int nentries)
-{
-    struct descriptor_table_ptr dt;
-
-    dt.limit = nentries * sizeof(*idt) - 1;
-    dt.base = (unsigned long)idt;
-    lidt(&dt);
-    asm volatile ("lidt %0" : : "m"(dt));
-}
-
-void set_idt_entry(int vec, void *addr, int dpl)
-{
-    idt_entry_t *e = &idt[vec];
-    memset(e, 0, sizeof *e);
-    e->offset0 = (unsigned long)addr;
-    e->selector = read_cs();
-    e->ist = 0;
-    e->type = 14;
-    e->dpl = dpl;
-    e->p = 1;
-    e->offset1 = (unsigned long)addr >> 16;
-#ifdef __x86_64__
-    e->offset2 = (unsigned long)addr >> 32;
-#endif
-}
-
-struct ex_regs {
-    unsigned long rax, rcx, rdx, rbx;
-    unsigned long dummy, rbp, rsi, rdi;
-#ifdef __x86_64__
-    unsigned long r8, r9, r10, r11;
-    unsigned long r12, r13, r14, r15;
-#endif
-    unsigned long vector;
-    unsigned long error_code;
-    unsigned long rip;
-    unsigned long cs;
-    unsigned long rflags;
-};
-
-struct ex_record {
-    unsigned long rip;
-    unsigned long handler;
-};
-
-extern struct ex_record exception_table_start, exception_table_end;
-
-void do_handle_exception(struct ex_regs *regs)
-{
-    struct ex_record *ex;
-    unsigned ex_val;
-
-    ex_val = regs->vector | (regs->error_code << 16);
-
-    asm("mov %0, %%gs:4" : : "r"(ex_val));
-
-    for (ex = &exception_table_start; ex != &exception_table_end; ++ex) {
-        if (ex->rip == regs->rip) {
-            regs->rip = ex->handler;
-            return;
-        }
-    }
-    printf("unhandled excecption\n");
-    exit(7);
-}
-
-#ifdef __x86_64__
-#  define R "r"
-#  define W "q"
-#  define S "8"
-#else
-#  define R "e"
-#  define W "l"
-#  define S "4"
-#endif
-
-asm (".pushsection .text \n\t"
-     "ud_fault: \n\t"
-     "push"W" $0 \n\t"
-     "push"W" $6 \n\t"
-     "jmp handle_exception \n\t"
-
-     "gp_fault: \n\t"
-     "push"W" $13 \n\t"
-     "jmp handle_exception \n\t"
-
-     "de_fault: \n\t"
-     "push"W" $0 \n\t"
-     "push"W" $0 \n\t"
-     "jmp handle_exception \n\t"
-
-     "handle_exception: \n\t"
-#ifdef __x86_64__
-     "push %r15; push %r14; push %r13; push %r12 \n\t"
-     "push %r11; push %r10; push %r9; push %r8 \n\t"
-#endif
-     "push %"R"di; push %"R"si; push %"R"bp; sub $"S", %"R"sp \n\t"
-     "push %"R"bx; push %"R"dx; push %"R"cx; push %"R"ax \n\t"
-     "mov %"R"sp, %"R"di \n\t"
-     "call do_handle_exception \n\t"
-     "pop %"R"ax; pop %"R"cx; pop %"R"dx; pop %"R"bx \n\t"
-     "add $"S", %"R"sp; pop %"R"bp; pop %"R"si; pop %"R"di \n\t"
-#ifdef __x86_64__
-     "pop %r8; pop %r9; pop %r10; pop %r11 \n\t"
-     "pop %r12; pop %r13; pop %r14; pop %r15 \n\t"
-#endif
-     "add $"S", %"R"sp \n\t"
-     "add $"S", %"R"sp \n\t"
-     "iret"W" \n\t"
-     ".popsection");
-
-
-void setup_idt(void)
-{
-    extern char ud_fault, gp_fault, de_fault;
-
-    load_lidt(idt, 256);
-    set_idt_entry(0, &de_fault, 0);
-    set_idt_entry(6, &ud_fault, 0);
-    set_idt_entry(13, &gp_fault, 0);
-}
-
-unsigned exception_vector(void)
-{
-    unsigned short vector;
-
-    asm("mov %%gs:4, %0" : "=rm"(vector));
-    return vector;
-}
-
-unsigned exception_error_code(void)
-{
-    unsigned short error_code;
-
-    asm("mov %%gs:6, %0" : "=rm"(error_code));
-    return error_code;
-}
diff --git a/lib/x86/idt.h b/lib/x86/idt.h
deleted file mode 100644
index 81b8944..0000000
--- a/lib/x86/idt.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __IDT_TEST__
-#define __IDT_TEST__
-
-void setup_idt(void);
-
-#define ASM_TRY(catch)                                  \
-    "movl $0, %%gs:4 \n\t"                              \
-    ".pushsection .data.ex \n\t"                        \
-    ".quad 1111f, " catch "\n\t"                        \
-    ".popsection \n\t"                                  \
-    "1111:"
-
-#define UD_VECTOR   6
-#define GP_VECTOR   13
-
-unsigned exception_vector(void);
-unsigned exception_error_code(void);
-void set_idt_entry(int vec, void *addr, int dpl);
-
-#endif
diff --git a/x86/access.c b/x86/access.c
index df943d9..120682d 100644
--- a/x86/access.c
+++ b/x86/access.c
@@ -1,6 +1,6 @@
 
 #include "libcflat.h"
-#include "idt.h"
+#include "desc.h"
 #include "processor.h"
 
 #define smp_id() 0
diff --git a/x86/apic.c b/x86/apic.c
index bcb9fc1..4f05b02 100644
--- a/x86/apic.c
+++ b/x86/apic.c
@@ -2,7 +2,7 @@
 #include "apic.h"
 #include "vm.h"
 #include "smp.h"
-#include "idt.h"
+#include "desc.h"
 
 typedef struct {
     ulong regs[sizeof(ulong)*2];
diff --git a/x86/emulator.c b/x86/emulator.c
index 845e7a0..0486d38 100644
--- a/x86/emulator.c
+++ b/x86/emulator.c
@@ -1,7 +1,7 @@
 #include "ioram.h"
 #include "vm.h"
 #include "libcflat.h"
-#include "idt.h"
+#include "desc.h"
 
 #define memset __builtin_memset
 #define TESTDEV_IO_PORT 0xe0
diff --git a/x86/idt_test.c b/x86/idt_test.c
index 59256d4..2d2e0c2 100644
--- a/x86/idt_test.c
+++ b/x86/idt_test.c
@@ -1,5 +1,5 @@
 #include "libcflat.h"
-#include "idt.h"
+#include "desc.h"
 
 int test_ud2(void)
 {
diff --git a/x86/xsave.c b/x86/xsave.c
index a22b44c..057b0ff 100644
--- a/x86/xsave.c
+++ b/x86/xsave.c
@@ -1,5 +1,5 @@
 #include "libcflat.h"
-#include "idt.h"
+#include "desc.h"
 
 #ifdef __x86_64__
 #define uint64_t unsigned long
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH unit-tests 06/16] Specify correct operand length for ltr and str.
  2010-12-22 15:06 [PATCH unit-tests 00/16] task switch and event injection tests Gleb Natapov
                   ` (4 preceding siblings ...)
  2010-12-22 15:06 ` [PATCH unit-tests 05/16] Rename idt.[ch] into desc.[ch] Gleb Natapov
@ 2010-12-22 15:06 ` Gleb Natapov
  2010-12-29  9:37   ` Avi Kivity
  2010-12-22 15:06 ` [PATCH unit-tests 07/16] Move irq_(enable|disable) into library code Gleb Natapov
                   ` (9 subsequent siblings)
  15 siblings, 1 reply; 22+ messages in thread
From: Gleb Natapov @ 2010-12-22 15:06 UTC (permalink / raw)
  To: avi, mtosatti; +Cc: kvm


Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
 lib/x86/processor.h |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/x86/processor.h b/lib/x86/processor.h
index c348808..c3ab109 100644
--- a/lib/x86/processor.h
+++ b/lib/x86/processor.h
@@ -193,13 +193,13 @@ static inline u16 sldt(void)
 
 static inline void ltr(unsigned val)
 {
-    asm volatile ("ltr %0" : : "rm"(val));
+    asm volatile ("ltr %w0" : : "rm"(val));
 }
 
 static inline u16 str(void)
 {
     u16 val;
-    asm volatile ("str %0" : "=rm"(val));
+    asm volatile ("str %w0" : "=rm"(val));
     return val;
 }
 
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH unit-tests 07/16] Move irq_(enable|disable) into library code.
  2010-12-22 15:06 [PATCH unit-tests 00/16] task switch and event injection tests Gleb Natapov
                   ` (5 preceding siblings ...)
  2010-12-22 15:06 ` [PATCH unit-tests 06/16] Specify correct operand length for ltr and str Gleb Natapov
@ 2010-12-22 15:06 ` Gleb Natapov
  2010-12-22 15:06 ` [PATCH unit-tests 08/16] Add another task switch test Gleb Natapov
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Gleb Natapov @ 2010-12-22 15:06 UTC (permalink / raw)
  To: avi, mtosatti; +Cc: kvm


Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
 lib/x86/processor.h |   10 ++++++++++
 x86/apic.c          |   10 ----------
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/lib/x86/processor.h b/lib/x86/processor.h
index c3ab109..52881a3 100644
--- a/lib/x86/processor.h
+++ b/lib/x86/processor.h
@@ -280,4 +280,14 @@ static inline void wrtsc(u64 tsc)
 	asm volatile("wrmsr" : : "a"(a), "d"(d), "c"(0x10));
 }
 
+static inline void irq_disable(void)
+{
+    asm volatile("cli");
+}
+
+static inline void irq_enable(void)
+{
+    asm volatile("sti");
+}
+
 #endif
diff --git a/x86/apic.c b/x86/apic.c
index 4f05b02..3dd2485 100644
--- a/x86/apic.c
+++ b/x86/apic.c
@@ -134,16 +134,6 @@ static void handle_irq(unsigned vec, void (*func)(isr_regs_t *regs))
 #endif
 }
 
-static void irq_disable(void)
-{
-    asm volatile("cli");
-}
-
-static void irq_enable(void)
-{
-    asm volatile("sti");
-}
-
 static void eoi(void)
 {
     apic_write(APIC_EOI, 0);
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH unit-tests 08/16] Add another task switch test.
  2010-12-22 15:06 [PATCH unit-tests 00/16] task switch and event injection tests Gleb Natapov
                   ` (6 preceding siblings ...)
  2010-12-22 15:06 ` [PATCH unit-tests 07/16] Move irq_(enable|disable) into library code Gleb Natapov
@ 2010-12-22 15:06 ` Gleb Natapov
  2010-12-22 15:06 ` [PATCH unit-tests 09/16] Move vm.[ch] info library code Gleb Natapov
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Gleb Natapov @ 2010-12-22 15:06 UTC (permalink / raw)
  To: avi, mtosatti; +Cc: kvm

It has more test cases then existing one.  These test cases were written
when I worked on fixing task switch emulation code. Most of them check
for previously existing issue.

Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
 config-i386.mak   |    3 +-
 lib/x86/desc.c    |  172 +++++++++++++++++++++++++++++++++++++++++++++++++
 lib/x86/desc.h    |   13 ++++
 x86/taskswitch2.c |  185 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 372 insertions(+), 1 deletions(-)
 create mode 100644 x86/taskswitch2.c

diff --git a/config-i386.mak b/config-i386.mak
index c1b6e08..de52f3d 100644
--- a/config-i386.mak
+++ b/config-i386.mak
@@ -5,8 +5,9 @@ ldarch = elf32-i386
 CFLAGS += -D__i386__
 CFLAGS += -I $(KERNELDIR)/include
 
-tests = $(TEST_DIR)/taskswitch.flat
+tests = $(TEST_DIR)/taskswitch.flat $(TEST_DIR)/taskswitch2.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
diff --git a/lib/x86/desc.c b/lib/x86/desc.c
index 25a25bc..2f73a5a 100644
--- a/lib/x86/desc.c
+++ b/lib/x86/desc.c
@@ -18,6 +18,50 @@ typedef struct {
 #endif
 } idt_entry_t;
 
+typedef struct {
+	u16 limit_low;
+	u16 base_low;
+	u8 base_middle;
+	u8 access;
+	u8 granularity;
+	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;
+
 static idt_entry_t idt[256];
 
 void load_lidt(idt_entry_t *idt, int nentries)
@@ -157,3 +201,131 @@ unsigned exception_error_code(void)
     asm("mov %%gs:6, %0" : "=rm"(error_code));
     return error_code;
 }
+
+#ifndef __x86_64__
+/*
+ * GDT, with 6 entries:
+ * 0x00 - NULL descriptor
+ * 0x08 - Code segment
+ * 0x10 - Data segment
+ * 0x18 - Not presend code segment
+ * 0x20 - Primery task
+ * 0x28 - Interrupt task
+ */
+
+static gdt_entry_t gdt[6];
+#define TSS_GDT_OFFSET 4
+
+void set_gdt_entry(int num, u32 base,  u32 limit, u8 access, u8 gran)
+{
+	/* Setup the descriptor base address */
+	gdt[num].base_low = (base & 0xFFFF);
+	gdt[num].base_middle = (base >> 16) & 0xFF;
+	gdt[num].base_high = (base >> 24) & 0xFF;
+
+	/* Setup the descriptor limits */
+	gdt[num].limit_low = (limit & 0xFFFF);
+	gdt[num].granularity = ((limit >> 16) & 0x0F);
+
+	/* Finally, set up the granularity and access flags */
+	gdt[num].granularity |= (gran & 0xF0);
+	gdt[num].access = access;
+}
+
+void setup_gdt(void)
+{
+	struct descriptor_table_ptr gp;
+	/* Setup the GDT pointer and limit */
+	gp.limit = sizeof(gdt) - 1;
+	gp.base = (ulong)&gdt;
+
+	memset(gdt, 0, sizeof(gdt));
+
+	/* Our NULL descriptor */
+	set_gdt_entry(0, 0, 0, 0, 0);
+
+	/* The second entry is our Code Segment. The base address
+	 *  is 0, the limit is 4GBytes, it uses 4KByte granularity,
+	 *  uses 32-bit opcodes, and is a Code Segment descriptor. */
+	set_gdt_entry(1, 0, 0xFFFFFFFF, 0x9A, 0xcf);
+
+	/* The third entry is our Data Segment. It's EXACTLY the
+	 *  same as our code segment, but the descriptor type in
+	 *  this entry's access byte says it's a Data Segment */
+	set_gdt_entry(2, 0, 0xFFFFFFFF, 0x92, 0xcf);
+
+	/* Same as code register above but not present */
+	set_gdt_entry(3, 0, 0xFFFFFFFF, 0x1A, 0xcf);
+
+
+	/* Flush out the old GDT and install the new changes! */
+	lgdt(&gp);
+
+	asm volatile ("mov %0, %%ds\n\t"
+		      "mov %0, %%es\n\t"
+		      "mov %0, %%fs\n\t"
+		      "mov %0, %%gs\n\t"
+		      "mov %0, %%ss\n\t"
+		      "jmp $0x08, $.Lflush2\n\t"
+		      ".Lflush2: "::"r"(0x10));
+}
+
+static void set_idt_task_gate(int vec, u16 sel)
+{
+    idt_entry_t *e = &idt[vec];
+
+    memset(e, 0, sizeof *e);
+
+    e->selector = sel;
+    e->ist = 0;
+    e->type = 5;
+    e->dpl = 0;
+    e->p = 1;
+}
+
+/*
+ * 0 - main task
+ * 1 - interrupt task
+ */
+
+static tss32_t tss[2];
+static char tss_stack[2][4096];
+
+void setup_tss32(void)
+{
+	u16 desc_size = sizeof(tss32_t);
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		tss[i].cr3 = read_cr3();
+		tss[i].ss0 = tss[i].ss1 = tss[i].ss2 = 0x10;
+		tss[i].esp = tss[i].esp0 = tss[i].esp1 = tss[i].esp2 =
+			(u32)tss_stack[i];
+		tss[i].cs = 0x08;
+		tss[i].ds = tss[i].es = tss[i].fs = tss[i].gs = tss[i].ss = 0x10;
+		tss[i].iomap_base = (u16)desc_size;
+		set_gdt_entry(TSS_GDT_OFFSET + i, (u32)&tss[i],
+			     desc_size - 1, 0x89, 0x0f);
+	}
+
+	ltr(TSS_MAIN);
+}
+
+void set_intr_task_gate(int e, void *fn)
+{
+	tss[1].eip = (u32)fn;
+	set_idt_task_gate(e, TSS_INTR);
+}
+
+void print_current_tss_info(void)
+{
+	u16 tr = str();
+	int i = (tr == TSS_MAIN) ? 0 : 1;
+
+	if (tr != TSS_MAIN && tr != TSS_INTR)
+		printf("Unknown TSS %x\n", tr);
+	else
+		printf("TR=%x Main TSS back link %x. Current TSS back link %x\n",
+               tr, tss[0].prev, tss[i].prev);
+}
+#endif
diff --git a/lib/x86/desc.h b/lib/x86/desc.h
index 81b8944..2c9db5b 100644
--- a/lib/x86/desc.h
+++ b/lib/x86/desc.h
@@ -2,6 +2,13 @@
 #define __IDT_TEST__
 
 void setup_idt(void);
+#ifndef __x86_64__
+void setup_gdt(void);
+void setup_tss32(void);
+#else
+static inline void setup_gdt(void){}
+static inline void setup_tss32(void){}
+#endif
 
 #define ASM_TRY(catch)                                  \
     "movl $0, %%gs:4 \n\t"                              \
@@ -13,8 +20,14 @@ void setup_idt(void);
 #define UD_VECTOR   6
 #define GP_VECTOR   13
 
+#define TSS_MAIN 0x20
+#define TSS_INTR 0x28
+
 unsigned exception_vector(void);
 unsigned exception_error_code(void);
 void set_idt_entry(int vec, void *addr, int dpl);
+void set_gdt_entry(int num, u32 base,  u32 limit, u8 access, u8 gran);
+void set_intr_task_gate(int e, void *fn);
+void print_current_tss_info(void);
 
 #endif
diff --git a/x86/taskswitch2.c b/x86/taskswitch2.c
new file mode 100644
index 0000000..f51cb91
--- /dev/null
+++ b/x86/taskswitch2.c
@@ -0,0 +1,185 @@
+#include "libcflat.h"
+#include "desc.h"
+#include "apic-defs.h"
+#include "apic.h"
+#include "processor.h"
+
+#define xstr(s) str(s)
+#define str(s) #s
+
+static volatile int test_count;
+static volatile unsigned int test_divider;
+
+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:
+	printf("NMI task is running\n");
+	print_current_tss_info();
+	test_count++;
+	asm volatile ("iret");
+	goto start;
+}
+
+static void de_tss(void)
+{
+start:
+	printf("DE task is running\n");
+	print_current_tss_info();
+	test_divider = 10;
+	test_count++;
+	asm volatile ("iret");
+	goto start;
+}
+
+static void of_tss(void)
+{
+start:
+	printf("OF task is running\n");
+	print_current_tss_info();
+	test_count++;
+	asm volatile ("iret");
+	goto start;
+}
+
+static void bp_tss(void)
+{
+start:
+	printf("BP task is running\n");
+	print_current_tss_info();
+	test_count++;
+	asm volatile ("iret");
+	goto start;
+}
+
+static void jmp_tss(void)
+{
+start:
+	printf("JMP to task succeeded\n");
+	print_current_tss_info();
+	test_count++;
+	asm volatile ("ljmp $" xstr(TSS_MAIN) ", $0");
+	goto start;
+}
+
+static void irq_tss(void)
+{
+start:
+	printf("IRQ task is running\n");
+	print_current_tss_info();
+	test_count++;
+	asm volatile ("iret");
+	test_count++;
+	printf("IRQ task restarts after iret.\n");
+	goto start;
+}
+
+int main()
+{
+	unsigned int res;
+
+	setup_idt();
+	setup_gdt();
+	setup_tss32();
+
+	/* test that int $2 triggers task gate */
+	test_count = 0;
+	set_intr_task_gate(2, nmi_tss);
+	printf("Triggering nmi 2\n");
+	asm volatile ("int $2");
+	printf("Return from nmi %d\n", test_count);
+	report("NMI int $2", test_count == 1);
+
+	/* test that external NMI triggers task gate */
+	test_count = 0;
+	set_intr_task_gate(2, nmi_tss);
+	printf("Triggering nmi through APIC\n");
+	apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0);
+	io_delay();
+	printf("Return from APIC nmi\n");
+	report("NMI external", test_count == 1);
+
+	/* test that external interrupt triggesr task gate */
+	test_count = 0;
+	printf("Trigger IRQ from APIC\n");
+	set_intr_task_gate(0xf0, irq_tss);
+	irq_enable();
+	apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT | 0xf0, 0);
+	io_delay();
+	irq_disable();
+	printf("Return from APIC IRQ\n");
+	report("IRQ external", test_count == 1);
+
+	/* test that HW exception triggesr task gate */
+	set_intr_task_gate(0, de_tss);
+	printf("Try to devide by 0\n");
+	asm volatile ("divl %3": "=a"(res)
+		      : "d"(0), "a"(1500), "m"(test_divider));
+	printf("Result is %d\n", res);
+	report("DE exeption", res == 150);
+
+	/* test if call HW exeption DE by int $0 triggers task gate */
+	test_count = 0;
+	set_intr_task_gate(0, de_tss);
+	printf("Call int 0\n");
+	asm volatile ("int $0");
+	printf("Return from int 0\n");
+	report("int $0", test_count == 1);
+
+	/* test if HW exception OF triggers task gate */
+	test_count = 0;
+	set_intr_task_gate(4, of_tss);
+	printf("Call into\n");
+	asm volatile ("addb $127, %b0\ninto"::"a"(127));
+	printf("Return from into\n");
+	report("OF exeption", test_count);
+
+	/* test if HW exception BP triggers task gate */
+	test_count = 0;
+	set_intr_task_gate(3, bp_tss);
+	printf("Call int 3\n");
+	asm volatile ("int $3");
+	printf("Return from int 3\n");
+	report("BP exeption", test_count == 1);
+
+	/* test that calling a task by lcall works */
+	test_count = 0;
+	set_intr_task_gate(0, irq_tss);
+	printf("Calling task by lcall\n");
+	/* hlt opcode is 0xf4 I use destination IP 0xf4f4f4f4 to catch
+	   incorrect instruction length calculation */
+	asm volatile("lcall $" xstr(TSS_INTR) ", $0xf4f4f4f4");
+	printf("Return from call\n");
+	report("lcall", test_count == 1);
+
+	/* call the same task again and check that it restarted after iret */
+	test_count = 0;
+	asm volatile("lcall $" xstr(TSS_INTR) ", $0xf4f4f4f4");
+	report("lcall2", test_count == 2);
+
+	/* test that calling a task by ljmp works */
+	test_count = 0;
+	set_intr_task_gate(0, jmp_tss);
+	printf("Jumping to a task by ljmp\n");
+	asm volatile ("ljmp $" xstr(TSS_INTR) ", $0xf4f4f4f4");
+	printf("Jump back succeeded\n");
+	report("ljmp", test_count == 1);
+
+	printf("\nsummary: %d tests, %d failures\n", g_tests, g_fail);
+
+	return g_fail != 0;
+}
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH unit-tests 09/16] Move vm.[ch] info library code.
  2010-12-22 15:06 [PATCH unit-tests 00/16] task switch and event injection tests Gleb Natapov
                   ` (7 preceding siblings ...)
  2010-12-22 15:06 ` [PATCH unit-tests 08/16] Add another task switch test Gleb Natapov
@ 2010-12-22 15:06 ` Gleb Natapov
  2010-12-22 15:06 ` [PATCH unit-tests 10/16] Fix mmu on 32 bit Gleb Natapov
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Gleb Natapov @ 2010-12-22 15:06 UTC (permalink / raw)
  To: avi, mtosatti; +Cc: kvm


Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
 config-x86-common.mak |   14 ++--
 lib/x86/vm.c          |  229 +++++++++++++++++++++++++++++++++++++++++++++++++
 lib/x86/vm.h          |   46 ++++++++++
 x86/vm.c              |  229 -------------------------------------------------
 x86/vm.h              |   46 ----------
 5 files changed, 281 insertions(+), 283 deletions(-)
 create mode 100644 lib/x86/vm.c
 create mode 100644 lib/x86/vm.h
 delete mode 100644 x86/vm.c
 delete mode 100644 x86/vm.h

diff --git a/config-x86-common.mak b/config-x86-common.mak
index 367c0be..c546ee3 100644
--- a/config-x86-common.mak
+++ b/config-x86-common.mak
@@ -8,6 +8,7 @@ cflatobjs += \
 	lib/x86/io.o \
 	lib/x86/smp.o
 
+cflatobjs += lib/x86/vm.o
 cflatobjs += lib/x86/fwcfg.o
 cflatobjs += lib/x86/apic.o
 cflatobjs += lib/x86/atomic.o
@@ -43,21 +44,19 @@ $(TEST_DIR)/access.elf: $(cstart.o) $(TEST_DIR)/access.o
 
 $(TEST_DIR)/hypercall.elf: $(cstart.o) $(TEST_DIR)/hypercall.o
 
-$(TEST_DIR)/sieve.elf: $(cstart.o) $(TEST_DIR)/sieve.o \
-		$(TEST_DIR)/vm.o
+$(TEST_DIR)/sieve.elf: $(cstart.o) $(TEST_DIR)/sieve.o
 
 $(TEST_DIR)/vmexit.elf: $(cstart.o) $(TEST_DIR)/vmexit.o
 
 $(TEST_DIR)/smptest.elf: $(cstart.o) $(TEST_DIR)/smptest.o
 
-$(TEST_DIR)/emulator.elf: $(cstart.o) $(TEST_DIR)/emulator.o \
-			   $(TEST_DIR)/vm.o
+$(TEST_DIR)/emulator.elf: $(cstart.o) $(TEST_DIR)/emulator.o
 
 $(TEST_DIR)/port80.elf: $(cstart.o) $(TEST_DIR)/port80.o
 
 $(TEST_DIR)/tsc.elf: $(cstart.o) $(TEST_DIR)/tsc.o
 
-$(TEST_DIR)/apic.elf: $(cstart.o) $(TEST_DIR)/apic.o $(TEST_DIR)/vm.o
+$(TEST_DIR)/apic.elf: $(cstart.o) $(TEST_DIR)/apic.o
 
 $(TEST_DIR)/realmode.elf: $(TEST_DIR)/realmode.o
 	$(CC) -m32 -nostdlib -o $@ -Wl,-T,$(TEST_DIR)/realmode.lds $^
@@ -70,10 +69,9 @@ $(TEST_DIR)/idt_test.elf: $(cstart.o) $(TEST_DIR)/idt_test.o
 
 $(TEST_DIR)/xsave.elf: $(cstart.o) $(TEST_DIR)/xsave.o
 
-$(TEST_DIR)/rmap_chain.elf: $(cstart.o) $(TEST_DIR)/rmap_chain.o \
-			     $(TEST_DIR)/vm.o
+$(TEST_DIR)/rmap_chain.elf: $(cstart.o) $(TEST_DIR)/rmap_chain.o
 
-$(TEST_DIR)/svm.elf: $(cstart.o) $(TEST_DIR)/vm.o
+$(TEST_DIR)/svm.elf: $(cstart.o)
 
 $(TEST_DIR)/kvmclock_test.elf: $(cstart.o) $(TEST_DIR)/kvmclock.o \
                                 $(TEST_DIR)/kvmclock_test.o
diff --git a/lib/x86/vm.c b/lib/x86/vm.c
new file mode 100644
index 0000000..b34449f
--- /dev/null
+++ b/lib/x86/vm.c
@@ -0,0 +1,229 @@
+#include "vm.h"
+#include "libcflat.h"
+
+#define PAGE_SIZE 4096ul
+#ifdef __x86_64__
+#define LARGE_PAGE_SIZE (512 * PAGE_SIZE)
+#else
+#define LARGE_PAGE_SIZE (1024 * PAGE_SIZE)
+#endif
+
+#define X86_CR0_PE      0x00000001
+#define X86_CR0_PG      0x80000000
+#define X86_CR4_PSE     0x00000010
+static void *free = 0;
+static void *vfree_top = 0;
+
+static void free_memory(void *mem, unsigned long size)
+{
+    while (size >= PAGE_SIZE) {
+	*(void **)mem = free;
+	free = mem;
+	mem += PAGE_SIZE;
+	size -= PAGE_SIZE;
+    }
+}
+
+void *alloc_page()
+{
+    void *p;
+
+    if (!free)
+	return 0;
+
+    p = free;
+    free = *(void **)free;
+
+    return p;
+}
+
+void free_page(void *page)
+{
+    *(void **)page = free;
+    free = page;
+}
+
+extern char edata;
+static unsigned long end_of_memory;
+
+#ifdef __x86_64__
+#define	PAGE_LEVEL	4
+#define	PGDIR_WIDTH	9
+#define	PGDIR_MASK	511
+#else
+#define	PAGE_LEVEL	2
+#define	PGDIR_WIDTH	10
+#define	PGDIR_MASK	1023
+#endif
+
+void install_pte(unsigned long *cr3,
+		 int pte_level,
+		 void *virt,
+		 unsigned long pte,
+		 unsigned long *pt_page)
+{
+    int level;
+    unsigned long *pt = cr3;
+    unsigned offset;
+
+    for (level = PAGE_LEVEL; level > pte_level; --level) {
+	offset = ((unsigned long)virt >> ((level-1) * PGDIR_WIDTH + 12)) & PGDIR_MASK;
+	if (!(pt[offset] & PTE_PRESENT)) {
+	    unsigned long *new_pt = pt_page;
+            if (!new_pt)
+                new_pt = alloc_page();
+            else
+                pt_page = 0;
+	    memset(new_pt, 0, PAGE_SIZE);
+	    pt[offset] = virt_to_phys(new_pt) | PTE_PRESENT | PTE_WRITE;
+	}
+	pt = phys_to_virt(pt[offset] & 0xffffffffff000ull);
+    }
+    offset = ((unsigned long)virt >> ((level-1) * PGDIR_WIDTH + 12)) & PGDIR_MASK;
+    pt[offset] = pte;
+}
+
+static unsigned long get_pte(unsigned long *cr3, void *virt)
+{
+    int level;
+    unsigned long *pt = cr3, pte;
+    unsigned offset;
+
+    for (level = PAGE_LEVEL; level > 1; --level) {
+	offset = ((unsigned long)virt >> (((level-1) * PGDIR_WIDTH) + 12)) & PGDIR_MASK;
+	pte = pt[offset];
+	if (!(pte & PTE_PRESENT))
+	    return 0;
+	if (level == 2 && (pte & PTE_PSE))
+	    return pte;
+	pt = phys_to_virt(pte & 0xffffffffff000ull);
+    }
+    offset = ((unsigned long)virt >> (((level-1) * PGDIR_WIDTH) + 12)) & PGDIR_MASK;
+    pte = pt[offset];
+    return pte;
+}
+
+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);
+}
+
+void install_page(unsigned long *cr3,
+                  unsigned long phys,
+                  void *virt)
+{
+    install_pte(cr3, 1, virt, phys | PTE_PRESENT | PTE_WRITE, 0);
+}
+
+
+static inline void load_gdt(unsigned long *table, int nent)
+{
+    struct descriptor_table_ptr descr;
+
+    descr.limit = nent * 8 - 1;
+    descr.base = (ulong)table;
+    lgdt(&descr);
+}
+
+#define SEG_CS_32 8
+#define SEG_CS_64 16
+
+struct ljmp {
+    void *ofs;
+    unsigned short seg;
+};
+
+static void setup_mmu(unsigned long len)
+{
+    unsigned long *cr3 = alloc_page();
+    unsigned long phys = 0;
+
+    if (len < (1ul << 32))
+        len = 1ul << 32;  /* map mmio 1:1 */
+
+    memset(cr3, 0, PAGE_SIZE);
+    while (phys + LARGE_PAGE_SIZE <= len) {
+	install_large_page(cr3, phys, (void *)phys);
+	phys += LARGE_PAGE_SIZE;
+    }
+    while (phys + PAGE_SIZE <= len) {
+	install_page(cr3, phys, (void *)phys);
+	phys += PAGE_SIZE;
+    }
+    write_cr3(virt_to_phys(cr3));
+#ifndef __x86_64__
+    write_cr4(X86_CR4_PSE);
+#endif
+    write_cr0(X86_CR0_PG |X86_CR0_PE);
+
+    printf("paging enabled\n");
+    printf("cr0 = %x\n", read_cr0());
+    printf("cr3 = %x\n", read_cr3());
+    printf("cr4 = %x\n", read_cr4());
+}
+
+static unsigned int inl(unsigned short port)
+{
+    unsigned int val;
+    asm volatile("inl %w1, %0" : "=a"(val) : "Nd"(port));
+    return val;
+}
+
+void setup_vm()
+{
+    end_of_memory = inl(0xd1);
+    free_memory(&edata, end_of_memory - (unsigned long)&edata);
+    setup_mmu(end_of_memory);
+}
+
+void *vmalloc(unsigned long size)
+{
+    void *mem, *p;
+    unsigned pages;
+
+    size += sizeof(unsigned long);
+
+    size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+    vfree_top -= size;
+    mem = p = vfree_top;
+    pages = size / PAGE_SIZE;
+    while (pages--) {
+	install_page(phys_to_virt(read_cr3()), virt_to_phys(alloc_page()), p);
+	p += PAGE_SIZE;
+    }
+    *(unsigned long *)mem = size;
+    mem += sizeof(unsigned long);
+    return mem;
+}
+
+void vfree(void *mem)
+{
+    unsigned long size = ((unsigned long *)mem)[-1];
+
+    while (size) {
+	free_page(phys_to_virt(get_pte(phys_to_virt(read_cr3()), mem) & PTE_ADDR));
+	mem += PAGE_SIZE;
+	size -= PAGE_SIZE;
+    }
+}
+
+void *vmap(unsigned long long phys, unsigned long size)
+{
+    void *mem, *p;
+    unsigned pages;
+
+    size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+    vfree_top -= size;
+    phys &= ~(unsigned long long)(PAGE_SIZE - 1);
+
+    mem = p = vfree_top;
+    pages = size / PAGE_SIZE;
+    while (pages--) {
+	install_page(phys_to_virt(read_cr3()), phys, p);
+	phys += PAGE_SIZE;
+	p += PAGE_SIZE;
+    }
+    return mem;
+}
diff --git a/lib/x86/vm.h b/lib/x86/vm.h
new file mode 100644
index 0000000..a3d2676
--- /dev/null
+++ b/lib/x86/vm.h
@@ -0,0 +1,46 @@
+#ifndef VM_H
+#define VM_H
+
+#include "processor.h"
+
+#define PAGE_SIZE 4096ul
+#ifdef __x86_64__
+#define LARGE_PAGE_SIZE (512 * PAGE_SIZE)
+#else
+#define LARGE_PAGE_SIZE (1024 * PAGE_SIZE)
+#endif
+
+#define PTE_PRESENT (1ull << 0)
+#define PTE_PSE     (1ull << 7)
+#define PTE_WRITE   (1ull << 1)
+#define PTE_ADDR    (0xffffffffff000ull)
+
+void setup_vm();
+
+void *vmalloc(unsigned long size);
+void vfree(void *mem);
+void *vmap(unsigned long long phys, unsigned long size);
+
+void install_pte(unsigned long *cr3,
+                        int pte_level,
+                        void *virt,
+                        unsigned long pte,
+                        unsigned long *pt_page);
+
+void *alloc_page();
+
+void install_large_page(unsigned long *cr3,unsigned long phys,
+                               void *virt);
+void install_page(unsigned long *cr3, unsigned long phys, void *virt);
+
+static inline unsigned long virt_to_phys(const void *virt)
+{
+    return (unsigned long)virt;
+}
+
+static inline void *phys_to_virt(unsigned long phys)
+{
+    return (void *)phys;
+}
+
+#endif
diff --git a/x86/vm.c b/x86/vm.c
deleted file mode 100644
index b34449f..0000000
--- a/x86/vm.c
+++ /dev/null
@@ -1,229 +0,0 @@
-#include "vm.h"
-#include "libcflat.h"
-
-#define PAGE_SIZE 4096ul
-#ifdef __x86_64__
-#define LARGE_PAGE_SIZE (512 * PAGE_SIZE)
-#else
-#define LARGE_PAGE_SIZE (1024 * PAGE_SIZE)
-#endif
-
-#define X86_CR0_PE      0x00000001
-#define X86_CR0_PG      0x80000000
-#define X86_CR4_PSE     0x00000010
-static void *free = 0;
-static void *vfree_top = 0;
-
-static void free_memory(void *mem, unsigned long size)
-{
-    while (size >= PAGE_SIZE) {
-	*(void **)mem = free;
-	free = mem;
-	mem += PAGE_SIZE;
-	size -= PAGE_SIZE;
-    }
-}
-
-void *alloc_page()
-{
-    void *p;
-
-    if (!free)
-	return 0;
-
-    p = free;
-    free = *(void **)free;
-
-    return p;
-}
-
-void free_page(void *page)
-{
-    *(void **)page = free;
-    free = page;
-}
-
-extern char edata;
-static unsigned long end_of_memory;
-
-#ifdef __x86_64__
-#define	PAGE_LEVEL	4
-#define	PGDIR_WIDTH	9
-#define	PGDIR_MASK	511
-#else
-#define	PAGE_LEVEL	2
-#define	PGDIR_WIDTH	10
-#define	PGDIR_MASK	1023
-#endif
-
-void install_pte(unsigned long *cr3,
-		 int pte_level,
-		 void *virt,
-		 unsigned long pte,
-		 unsigned long *pt_page)
-{
-    int level;
-    unsigned long *pt = cr3;
-    unsigned offset;
-
-    for (level = PAGE_LEVEL; level > pte_level; --level) {
-	offset = ((unsigned long)virt >> ((level-1) * PGDIR_WIDTH + 12)) & PGDIR_MASK;
-	if (!(pt[offset] & PTE_PRESENT)) {
-	    unsigned long *new_pt = pt_page;
-            if (!new_pt)
-                new_pt = alloc_page();
-            else
-                pt_page = 0;
-	    memset(new_pt, 0, PAGE_SIZE);
-	    pt[offset] = virt_to_phys(new_pt) | PTE_PRESENT | PTE_WRITE;
-	}
-	pt = phys_to_virt(pt[offset] & 0xffffffffff000ull);
-    }
-    offset = ((unsigned long)virt >> ((level-1) * PGDIR_WIDTH + 12)) & PGDIR_MASK;
-    pt[offset] = pte;
-}
-
-static unsigned long get_pte(unsigned long *cr3, void *virt)
-{
-    int level;
-    unsigned long *pt = cr3, pte;
-    unsigned offset;
-
-    for (level = PAGE_LEVEL; level > 1; --level) {
-	offset = ((unsigned long)virt >> (((level-1) * PGDIR_WIDTH) + 12)) & PGDIR_MASK;
-	pte = pt[offset];
-	if (!(pte & PTE_PRESENT))
-	    return 0;
-	if (level == 2 && (pte & PTE_PSE))
-	    return pte;
-	pt = phys_to_virt(pte & 0xffffffffff000ull);
-    }
-    offset = ((unsigned long)virt >> (((level-1) * PGDIR_WIDTH) + 12)) & PGDIR_MASK;
-    pte = pt[offset];
-    return pte;
-}
-
-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);
-}
-
-void install_page(unsigned long *cr3,
-                  unsigned long phys,
-                  void *virt)
-{
-    install_pte(cr3, 1, virt, phys | PTE_PRESENT | PTE_WRITE, 0);
-}
-
-
-static inline void load_gdt(unsigned long *table, int nent)
-{
-    struct descriptor_table_ptr descr;
-
-    descr.limit = nent * 8 - 1;
-    descr.base = (ulong)table;
-    lgdt(&descr);
-}
-
-#define SEG_CS_32 8
-#define SEG_CS_64 16
-
-struct ljmp {
-    void *ofs;
-    unsigned short seg;
-};
-
-static void setup_mmu(unsigned long len)
-{
-    unsigned long *cr3 = alloc_page();
-    unsigned long phys = 0;
-
-    if (len < (1ul << 32))
-        len = 1ul << 32;  /* map mmio 1:1 */
-
-    memset(cr3, 0, PAGE_SIZE);
-    while (phys + LARGE_PAGE_SIZE <= len) {
-	install_large_page(cr3, phys, (void *)phys);
-	phys += LARGE_PAGE_SIZE;
-    }
-    while (phys + PAGE_SIZE <= len) {
-	install_page(cr3, phys, (void *)phys);
-	phys += PAGE_SIZE;
-    }
-    write_cr3(virt_to_phys(cr3));
-#ifndef __x86_64__
-    write_cr4(X86_CR4_PSE);
-#endif
-    write_cr0(X86_CR0_PG |X86_CR0_PE);
-
-    printf("paging enabled\n");
-    printf("cr0 = %x\n", read_cr0());
-    printf("cr3 = %x\n", read_cr3());
-    printf("cr4 = %x\n", read_cr4());
-}
-
-static unsigned int inl(unsigned short port)
-{
-    unsigned int val;
-    asm volatile("inl %w1, %0" : "=a"(val) : "Nd"(port));
-    return val;
-}
-
-void setup_vm()
-{
-    end_of_memory = inl(0xd1);
-    free_memory(&edata, end_of_memory - (unsigned long)&edata);
-    setup_mmu(end_of_memory);
-}
-
-void *vmalloc(unsigned long size)
-{
-    void *mem, *p;
-    unsigned pages;
-
-    size += sizeof(unsigned long);
-
-    size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
-    vfree_top -= size;
-    mem = p = vfree_top;
-    pages = size / PAGE_SIZE;
-    while (pages--) {
-	install_page(phys_to_virt(read_cr3()), virt_to_phys(alloc_page()), p);
-	p += PAGE_SIZE;
-    }
-    *(unsigned long *)mem = size;
-    mem += sizeof(unsigned long);
-    return mem;
-}
-
-void vfree(void *mem)
-{
-    unsigned long size = ((unsigned long *)mem)[-1];
-
-    while (size) {
-	free_page(phys_to_virt(get_pte(phys_to_virt(read_cr3()), mem) & PTE_ADDR));
-	mem += PAGE_SIZE;
-	size -= PAGE_SIZE;
-    }
-}
-
-void *vmap(unsigned long long phys, unsigned long size)
-{
-    void *mem, *p;
-    unsigned pages;
-
-    size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
-    vfree_top -= size;
-    phys &= ~(unsigned long long)(PAGE_SIZE - 1);
-
-    mem = p = vfree_top;
-    pages = size / PAGE_SIZE;
-    while (pages--) {
-	install_page(phys_to_virt(read_cr3()), phys, p);
-	phys += PAGE_SIZE;
-	p += PAGE_SIZE;
-    }
-    return mem;
-}
diff --git a/x86/vm.h b/x86/vm.h
deleted file mode 100644
index a3d2676..0000000
--- a/x86/vm.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef VM_H
-#define VM_H
-
-#include "processor.h"
-
-#define PAGE_SIZE 4096ul
-#ifdef __x86_64__
-#define LARGE_PAGE_SIZE (512 * PAGE_SIZE)
-#else
-#define LARGE_PAGE_SIZE (1024 * PAGE_SIZE)
-#endif
-
-#define PTE_PRESENT (1ull << 0)
-#define PTE_PSE     (1ull << 7)
-#define PTE_WRITE   (1ull << 1)
-#define PTE_ADDR    (0xffffffffff000ull)
-
-void setup_vm();
-
-void *vmalloc(unsigned long size);
-void vfree(void *mem);
-void *vmap(unsigned long long phys, unsigned long size);
-
-void install_pte(unsigned long *cr3,
-                        int pte_level,
-                        void *virt,
-                        unsigned long pte,
-                        unsigned long *pt_page);
-
-void *alloc_page();
-
-void install_large_page(unsigned long *cr3,unsigned long phys,
-                               void *virt);
-void install_page(unsigned long *cr3, unsigned long phys, void *virt);
-
-static inline unsigned long virt_to_phys(const void *virt)
-{
-    return (unsigned long)virt;
-}
-
-static inline void *phys_to_virt(unsigned long phys)
-{
-    return (void *)phys;
-}
-
-#endif
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH unit-tests 10/16] Fix mmu on 32 bit.
  2010-12-22 15:06 [PATCH unit-tests 00/16] task switch and event injection tests Gleb Natapov
                   ` (8 preceding siblings ...)
  2010-12-22 15:06 ` [PATCH unit-tests 09/16] Move vm.[ch] info library code Gleb Natapov
@ 2010-12-22 15:06 ` Gleb Natapov
  2010-12-22 15:06 ` [PATCH unit-tests 11/16] Set WP bit in CR0 to make write protection work Gleb Natapov
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Gleb Natapov @ 2010-12-22 15:06 UTC (permalink / raw)
  To: avi, mtosatti; +Cc: kvm

The way virtual memory is setup now does not leave space for vmalloc on
32bit system. Make a hole in address space from 2G to 3G for vmalloc on
32 bit.

Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
 lib/x86/vm.c |   42 +++++++++++++++++++++++++++++++-----------
 1 files changed, 31 insertions(+), 11 deletions(-)

diff --git a/lib/x86/vm.c b/lib/x86/vm.c
index b34449f..4d0a955 100644
--- a/lib/x86/vm.c
+++ b/lib/x86/vm.c
@@ -135,23 +135,43 @@ struct ljmp {
     unsigned short seg;
 };
 
+static void setup_mmu_range(unsigned long *cr3, unsigned long start,
+			    unsigned long len)
+{
+	u64 max = (u64)len + (u64)start;
+	u64 phys = start;
+
+	while (phys + LARGE_PAGE_SIZE <= max) {
+		install_large_page(cr3, phys, (void *)(ulong)phys);
+		phys += LARGE_PAGE_SIZE;
+	}
+	while (phys + PAGE_SIZE <= max) {
+		install_page(cr3, phys, (void *)(ulong)phys);
+		phys += PAGE_SIZE;
+	}
+}
+
 static void setup_mmu(unsigned long len)
 {
     unsigned long *cr3 = alloc_page();
-    unsigned long phys = 0;
 
+    memset(cr3, 0, PAGE_SIZE);
+
+#ifdef __x86_64__
     if (len < (1ul << 32))
-        len = 1ul << 32;  /* map mmio 1:1 */
+        len = (1ul << 32);  /* map mmio 1:1 */
+
+    setup_mmu_range(cr3, 0, len);
+#else
+    if (len > (1ul << 31))
+	    len = (1ul << 31);
+
+    /* 0 - 2G memory, 2G-3G valloc area, 3G-4G mmio */
+    setup_mmu_range(cr3, 0, len);
+    setup_mmu_range(cr3, 3ul << 30, (1ul << 30));
+    vfree_top = (void*)(3ul << 30);
+#endif
 
-    memset(cr3, 0, PAGE_SIZE);
-    while (phys + LARGE_PAGE_SIZE <= len) {
-	install_large_page(cr3, phys, (void *)phys);
-	phys += LARGE_PAGE_SIZE;
-    }
-    while (phys + PAGE_SIZE <= len) {
-	install_page(cr3, phys, (void *)phys);
-	phys += PAGE_SIZE;
-    }
     write_cr3(virt_to_phys(cr3));
 #ifndef __x86_64__
     write_cr4(X86_CR4_PSE);
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH unit-tests 11/16] Set WP bit in CR0 to make write protection work.
  2010-12-22 15:06 [PATCH unit-tests 00/16] task switch and event injection tests Gleb Natapov
                   ` (9 preceding siblings ...)
  2010-12-22 15:06 ` [PATCH unit-tests 10/16] Fix mmu on 32 bit Gleb Natapov
@ 2010-12-22 15:06 ` Gleb Natapov
  2010-12-22 15:06 ` [PATCH unit-tests 12/16] Fix exception handling on i386 arch Gleb Natapov
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Gleb Natapov @ 2010-12-22 15:06 UTC (permalink / raw)
  To: avi, mtosatti; +Cc: kvm


Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
 lib/x86/vm.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/lib/x86/vm.c b/lib/x86/vm.c
index 4d0a955..1ca8a05 100644
--- a/lib/x86/vm.c
+++ b/lib/x86/vm.c
@@ -9,6 +9,7 @@
 #endif
 
 #define X86_CR0_PE      0x00000001
+#define X86_CR0_WP      0x00010000
 #define X86_CR0_PG      0x80000000
 #define X86_CR4_PSE     0x00000010
 static void *free = 0;
@@ -176,7 +177,7 @@ static void setup_mmu(unsigned long len)
 #ifndef __x86_64__
     write_cr4(X86_CR4_PSE);
 #endif
-    write_cr0(X86_CR0_PG |X86_CR0_PE);
+    write_cr0(X86_CR0_PG |X86_CR0_PE | X86_CR0_WP);
 
     printf("paging enabled\n");
     printf("cr0 = %x\n", read_cr0());
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH unit-tests 12/16] Fix exception handling on i386 arch.
  2010-12-22 15:06 [PATCH unit-tests 00/16] task switch and event injection tests Gleb Natapov
                   ` (10 preceding siblings ...)
  2010-12-22 15:06 ` [PATCH unit-tests 11/16] Set WP bit in CR0 to make write protection work Gleb Natapov
@ 2010-12-22 15:06 ` Gleb Natapov
  2010-12-22 15:06 ` [PATCH unit-tests 13/16] Move handle_irq() from apic test into library code Gleb Natapov
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Gleb Natapov @ 2010-12-22 15:06 UTC (permalink / raw)
  To: avi, mtosatti; +Cc: kvm

Pass parameter to exception handler in correct register.

Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
 lib/x86/desc.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/lib/x86/desc.c b/lib/x86/desc.c
index 2f73a5a..aa0b4f4 100644
--- a/lib/x86/desc.c
+++ b/lib/x86/desc.c
@@ -111,6 +111,9 @@ struct ex_record {
 
 extern struct ex_record exception_table_start, exception_table_end;
 
+#ifndef __x86_64__
+__attribute__((regparm(1)))
+#endif
 void do_handle_exception(struct ex_regs *regs)
 {
     struct ex_record *ex;
@@ -162,7 +165,11 @@ asm (".pushsection .text \n\t"
 #endif
      "push %"R"di; push %"R"si; push %"R"bp; sub $"S", %"R"sp \n\t"
      "push %"R"bx; push %"R"dx; push %"R"cx; push %"R"ax \n\t"
+#ifdef __x86_64__
      "mov %"R"sp, %"R"di \n\t"
+#else
+     "mov %"R"sp, %"R"ax \n\t"
+#endif
      "call do_handle_exception \n\t"
      "pop %"R"ax; pop %"R"cx; pop %"R"dx; pop %"R"bx \n\t"
      "add $"S", %"R"sp; pop %"R"bp; pop %"R"si; pop %"R"di \n\t"
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH unit-tests 13/16] Move handle_irq() from apic test into library code.
  2010-12-22 15:06 [PATCH unit-tests 00/16] task switch and event injection tests Gleb Natapov
                   ` (11 preceding siblings ...)
  2010-12-22 15:06 ` [PATCH unit-tests 12/16] Fix exception handling on i386 arch Gleb Natapov
@ 2010-12-22 15:06 ` Gleb Natapov
  2010-12-22 15:06 ` [PATCH unit-tests 14/16] Add handle_exception() interface Gleb Natapov
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Gleb Natapov @ 2010-12-22 15:06 UTC (permalink / raw)
  To: avi, mtosatti; +Cc: kvm


Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
 config-x86-common.mak |    1 +
 lib/x86/isr.c         |   99 ++++++++++++++++++++++++++++++++++++++++++++++++
 lib/x86/isr.h         |   14 +++++++
 x86/apic.c            |  100 +------------------------------------------------
 4 files changed, 115 insertions(+), 99 deletions(-)
 create mode 100644 lib/x86/isr.c
 create mode 100644 lib/x86/isr.h

diff --git a/config-x86-common.mak b/config-x86-common.mak
index c546ee3..3a77a93 100644
--- a/config-x86-common.mak
+++ b/config-x86-common.mak
@@ -13,6 +13,7 @@ cflatobjs += lib/x86/fwcfg.o
 cflatobjs += lib/x86/apic.o
 cflatobjs += lib/x86/atomic.o
 cflatobjs += lib/x86/desc.o
+cflatobjs += lib/x86/isr.o
 
 $(libcflat): LDFLAGS += -nostdlib
 $(libcflat): CFLAGS += -ffreestanding -I lib
diff --git a/lib/x86/isr.c b/lib/x86/isr.c
new file mode 100644
index 0000000..0bacff9
--- /dev/null
+++ b/lib/x86/isr.c
@@ -0,0 +1,99 @@
+#include "libcflat.h"
+#include "isr.h"
+#include "vm.h"
+#include "desc.h"
+
+#ifdef __x86_64__
+#  define R "r"
+#else
+#  define R "e"
+#endif
+
+extern char isr_entry_point[];
+
+asm (
+    "isr_entry_point: \n"
+#ifdef __x86_64__
+    "push %r15 \n\t"
+    "push %r14 \n\t"
+    "push %r13 \n\t"
+    "push %r12 \n\t"
+    "push %r11 \n\t"
+    "push %r10 \n\t"
+    "push %r9  \n\t"
+    "push %r8  \n\t"
+#endif
+    "push %"R "di \n\t"
+    "push %"R "si \n\t"
+    "push %"R "bp \n\t"
+    "push %"R "sp \n\t"
+    "push %"R "bx \n\t"
+    "push %"R "dx \n\t"
+    "push %"R "cx \n\t"
+    "push %"R "ax \n\t"
+#ifdef __x86_64__
+    "mov %rsp, %rdi \n\t"
+    "callq *8*16(%rsp) \n\t"
+#else
+    "push %esp \n\t"
+    "calll *4+4*8(%esp) \n\t"
+    "add $4, %esp \n\t"
+#endif
+    "pop %"R "ax \n\t"
+    "pop %"R "cx \n\t"
+    "pop %"R "dx \n\t"
+    "pop %"R "bx \n\t"
+    "pop %"R "bp \n\t"
+    "pop %"R "bp \n\t"
+    "pop %"R "si \n\t"
+    "pop %"R "di \n\t"
+#ifdef __x86_64__
+    "pop %r8  \n\t"
+    "pop %r9  \n\t"
+    "pop %r10 \n\t"
+    "pop %r11 \n\t"
+    "pop %r12 \n\t"
+    "pop %r13 \n\t"
+    "pop %r14 \n\t"
+    "pop %r15 \n\t"
+#endif
+    ".globl isr_iret_ip\n\t"
+#ifdef __x86_64__
+    "add $8, %rsp \n\t"
+    "isr_iret_ip: \n\t"
+    "iretq \n\t"
+#else
+    "add $4, %esp \n\t"
+    "isr_iret_ip: \n\t"
+    "iretl \n\t"
+#endif
+    );
+
+void handle_irq(unsigned vec, void (*func)(isr_regs_t *regs))
+{
+    u8 *thunk = vmalloc(50);
+
+    set_idt_entry(vec, thunk, 0);
+
+#ifdef __x86_64__
+    /* sub $8, %rsp */
+    *thunk++ = 0x48; *thunk++ = 0x83; *thunk++ = 0xec; *thunk++ = 0x08;
+    /* mov $func_low, %(rsp) */
+    *thunk++ = 0xc7; *thunk++ = 0x04; *thunk++ = 0x24;
+    *(u32 *)thunk = (ulong)func; thunk += 4;
+    /* mov $func_high, %(rsp+4) */
+    *thunk++ = 0xc7; *thunk++ = 0x44; *thunk++ = 0x24; *thunk++ = 0x04;
+    *(u32 *)thunk = (ulong)func >> 32; thunk += 4;
+    /* jmp isr_entry_point */
+    *thunk ++ = 0xe9;
+    *(u32 *)thunk = (ulong)isr_entry_point - (ulong)(thunk + 4);
+#else
+    /* push $func */
+    *thunk++ = 0x68;
+    *(u32 *)thunk = (ulong)func; thunk += 4;
+    /* jmp isr_entry_point */
+    *thunk++ = 0xe9;
+    *(u32 *)thunk = (ulong)isr_entry_point - (ulong)(thunk + 4);
+#endif
+}
+
diff --git a/lib/x86/isr.h b/lib/x86/isr.h
new file mode 100644
index 0000000..b07a32a
--- /dev/null
+++ b/lib/x86/isr.h
@@ -0,0 +1,14 @@
+#ifndef __ISR_TEST__
+#define __ISR_TEST__
+
+typedef struct {
+    ulong regs[sizeof(ulong)*2];
+    ulong func;
+    ulong rip;
+    ulong cs;
+    ulong rflags;
+} isr_regs_t;
+
+void handle_irq(unsigned vec, void (*func)(isr_regs_t *regs));
+
+#endif
diff --git a/x86/apic.c b/x86/apic.c
index 3dd2485..1366185 100644
--- a/x86/apic.c
+++ b/x86/apic.c
@@ -3,77 +3,7 @@
 #include "vm.h"
 #include "smp.h"
 #include "desc.h"
-
-typedef struct {
-    ulong regs[sizeof(ulong)*2];
-    ulong func;
-    ulong rip;
-    ulong cs;
-    ulong rflags;
-} isr_regs_t;
-
-#ifdef __x86_64__
-#  define R "r"
-#else
-#  define R "e"
-#endif
-
-extern char isr_entry_point[];
-
-asm (
-    "isr_entry_point: \n"
-#ifdef __x86_64__
-    "push %r15 \n\t"
-    "push %r14 \n\t"
-    "push %r13 \n\t"
-    "push %r12 \n\t"
-    "push %r11 \n\t"
-    "push %r10 \n\t"
-    "push %r9  \n\t"
-    "push %r8  \n\t"
-#endif
-    "push %"R "di \n\t"
-    "push %"R "si \n\t"
-    "push %"R "bp \n\t"
-    "push %"R "sp \n\t"
-    "push %"R "bx \n\t"
-    "push %"R "dx \n\t"
-    "push %"R "cx \n\t"
-    "push %"R "ax \n\t"
-#ifdef __x86_64__
-    "mov %rsp, %rdi \n\t"
-    "callq *8*16(%rsp) \n\t"
-#else
-    "push %esp \n\t"
-    "calll *4+4*8(%esp) \n\t"
-    "add $4, %esp \n\t"
-#endif
-    "pop %"R "ax \n\t"
-    "pop %"R "cx \n\t"
-    "pop %"R "dx \n\t"
-    "pop %"R "bx \n\t"
-    "pop %"R "bp \n\t"
-    "pop %"R "bp \n\t"
-    "pop %"R "si \n\t"
-    "pop %"R "di \n\t"
-#ifdef __x86_64__
-    "pop %r8  \n\t"
-    "pop %r9  \n\t"
-    "pop %r10 \n\t"
-    "pop %r11 \n\t"
-    "pop %r12 \n\t"
-    "pop %r13 \n\t"
-    "pop %r14 \n\t"
-    "pop %r15 \n\t"
-#endif
-#ifdef __x86_64__
-    "add $8, %rsp \n\t"
-    "iretq \n\t"
-#else
-    "add $4, %esp \n\t"
-    "iretl \n\t"
-#endif
-    );
+#include "isr.h"
 
 static int g_fail;
 static int g_tests;
@@ -106,34 +36,6 @@ void test_enable_x2apic(void)
     }
 }
 
-static void handle_irq(unsigned vec, void (*func)(isr_regs_t *regs))
-{
-    u8 *thunk = vmalloc(50);
-
-    set_idt_entry(vec, thunk, 0);
-
-#ifdef __x86_64__
-    /* sub $8, %rsp */
-    *thunk++ = 0x48; *thunk++ = 0x83; *thunk++ = 0xec; *thunk++ = 0x08;
-    /* mov $func_low, %(rsp) */
-    *thunk++ = 0xc7; *thunk++ = 0x04; *thunk++ = 0x24;
-    *(u32 *)thunk = (ulong)func; thunk += 4;
-    /* mov $func_high, %(rsp+4) */
-    *thunk++ = 0xc7; *thunk++ = 0x44; *thunk++ = 0x24; *thunk++ = 0x04;
-    *(u32 *)thunk = (ulong)func >> 32; thunk += 4;
-    /* jmp isr_entry_point */
-    *thunk ++ = 0xe9;
-    *(u32 *)thunk = (ulong)isr_entry_point - (ulong)(thunk + 4);
-#else
-    /* push $func */
-    *thunk++ = 0x68;
-    *(u32 *)thunk = (ulong)func;
-    /* jmp isr_entry_point */
-    *thunk ++ = 0xe9;
-    *(u32 *)thunk = (ulong)isr_entry_point - (ulong)(thunk + 4);
-#endif
-}
-
 static void eoi(void)
 {
     apic_write(APIC_EOI, 0);
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH unit-tests 14/16] Add handle_exception() interface.
  2010-12-22 15:06 [PATCH unit-tests 00/16] task switch and event injection tests Gleb Natapov
                   ` (12 preceding siblings ...)
  2010-12-22 15:06 ` [PATCH unit-tests 13/16] Move handle_irq() from apic test into library code Gleb Natapov
@ 2010-12-22 15:06 ` Gleb Natapov
  2010-12-22 15:06 ` [PATCH unit-tests 15/16] Move invlpg() into library code Gleb Natapov
  2010-12-22 15:06 ` [PATCH unit-tests 16/16] Add even injection test Gleb Natapov
  15 siblings, 0 replies; 22+ messages in thread
From: Gleb Natapov @ 2010-12-22 15:06 UTC (permalink / raw)
  To: avi, mtosatti; +Cc: kvm

Provide easy way for test to hook its own exception handler.

Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
 lib/x86/desc.c |  122 +++++++++++++++++++++++++++++++++++++++----------------
 lib/x86/desc.h |   15 +++++++
 2 files changed, 101 insertions(+), 36 deletions(-)

diff --git a/lib/x86/desc.c b/lib/x86/desc.c
index aa0b4f4..0da8989 100644
--- a/lib/x86/desc.c
+++ b/lib/x86/desc.c
@@ -90,19 +90,6 @@ void set_idt_entry(int vec, void *addr, int dpl)
 #endif
 }
 
-struct ex_regs {
-    unsigned long rax, rcx, rdx, rbx;
-    unsigned long dummy, rbp, rsi, rdi;
-#ifdef __x86_64__
-    unsigned long r8, r9, r10, r11;
-    unsigned long r12, r13, r14, r15;
-#endif
-    unsigned long vector;
-    unsigned long error_code;
-    unsigned long rip;
-    unsigned long cs;
-    unsigned long rflags;
-};
 
 struct ex_record {
     unsigned long rip;
@@ -111,10 +98,7 @@ struct ex_record {
 
 extern struct ex_record exception_table_start, exception_table_end;
 
-#ifndef __x86_64__
-__attribute__((regparm(1)))
-#endif
-void do_handle_exception(struct ex_regs *regs)
+static void check_exception_table(struct ex_regs *regs)
 {
     struct ex_record *ex;
     unsigned ex_val;
@@ -129,10 +113,34 @@ void do_handle_exception(struct ex_regs *regs)
             return;
         }
     }
-    printf("unhandled excecption\n");
+    printf("unhandled excecption %d\n", regs->vector);
     exit(7);
 }
 
+static void (*exception_handlers[32])(struct ex_regs *regs);
+
+
+void handle_exception(u8 v, void (*func)(struct ex_regs *regs))
+{
+	if (v < 32)
+		exception_handlers[v] = func;
+}
+
+#ifndef __x86_64__
+__attribute__((regparm(1)))
+#endif
+void do_handle_exception(struct ex_regs *regs)
+{
+	if (regs->vector < 32 && exception_handlers[regs->vector]) {
+		exception_handlers[regs->vector](regs);
+		return;
+	}
+	printf("unhandled cpu excecption %d\n", regs->vector);
+	if (regs->vector == 14)
+		printf("PF at %p addr %p\n", regs->rip, read_cr2());
+	exit(7);
+}
+
 #ifdef __x86_64__
 #  define R "r"
 #  define W "q"
@@ -143,22 +151,42 @@ void do_handle_exception(struct ex_regs *regs)
 #  define S "4"
 #endif
 
-asm (".pushsection .text \n\t"
-     "ud_fault: \n\t"
-     "push"W" $0 \n\t"
-     "push"W" $6 \n\t"
-     "jmp handle_exception \n\t"
-
-     "gp_fault: \n\t"
-     "push"W" $13 \n\t"
-     "jmp handle_exception \n\t"
-
-     "de_fault: \n\t"
-     "push"W" $0 \n\t"
-     "push"W" $0 \n\t"
-     "jmp handle_exception \n\t"
+#define EX(NAME, N) extern char NAME##_fault;	\
+	asm (".pushsection .text \n\t"		\
+	     #NAME"_fault: \n\t"		\
+	     "push"W" $0 \n\t"			\
+	     "push"W" $"#N" \n\t"		\
+	     "jmp __handle_exception \n\t"	\
+	     ".popsection")
+
+#define EX_E(NAME, N) extern char NAME##_fault;	\
+	asm (".pushsection .text \n\t"		\
+	     #NAME"_fault: \n\t"		\
+	     "push"W" $"#N" \n\t"		\
+	     "jmp __handle_exception \n\t"	\
+	     ".popsection")
+
+EX(de, 0);
+EX(db, 1);
+EX(nmi, 2);
+EX(bp, 3);
+EX(of, 4);
+EX(br, 5);
+EX(ud, 6);
+EX(nm, 7);
+EX_E(df, 8);
+EX_E(ts, 10);
+EX_E(np, 11);
+EX_E(ss, 12);
+EX_E(gp, 13);
+EX_E(pf, 14);
+EX(mf, 16);
+EX_E(ac, 17);
+EX(mc, 18);
+EX(xm, 19);
 
-     "handle_exception: \n\t"
+asm (".pushsection .text \n\t"
+     "__handle_exception: \n\t"
 #ifdef __x86_64__
      "push %r15; push %r14; push %r13; push %r12 \n\t"
      "push %r11; push %r10; push %r9; push %r8 \n\t"
@@ -182,15 +210,37 @@ asm (".pushsection .text \n\t"
      "iret"W" \n\t"
      ".popsection");
 
+static void *idt_handlers[32] = {
+	[0] = &de_fault,
+	[1] = &db_fault,
+	[2] = &nmi_fault,
+	[3] = &bp_fault,
+	[4] = &of_fault,
+	[5] = &br_fault,
+	[6] = &ud_fault,
+	[7] = &nm_fault,
+	[8] = &df_fault,
+	[10] = &ts_fault,
+	[11] = &np_fault,
+	[12] = &ss_fault,
+	[13] = &gp_fault,
+	[14] = &pf_fault,
+	[16] = &mf_fault,
+	[17] = &ac_fault,
+	[18] = &mc_fault,
+	[19] = &xm_fault,
+};
 
 void setup_idt(void)
 {
-    extern char ud_fault, gp_fault, de_fault;
-
+    int i;
     load_lidt(idt, 256);
-    set_idt_entry(0, &de_fault, 0);
-    set_idt_entry(6, &ud_fault, 0);
-    set_idt_entry(13, &gp_fault, 0);
+    for (i = 0; i < 32; i++)
+	    if (idt_handlers[i])
+		    set_idt_entry(i, idt_handlers[i], 0);
+    handle_exception(0, check_exception_table);
+    handle_exception(6, check_exception_table);
+    handle_exception(13, check_exception_table);
 }
 
 unsigned exception_vector(void)
diff --git a/lib/x86/desc.h b/lib/x86/desc.h
index 2c9db5b..073878d 100644
--- a/lib/x86/desc.h
+++ b/lib/x86/desc.h
@@ -10,6 +10,20 @@ static inline void setup_gdt(void){}
 static inline void setup_tss32(void){}
 #endif
 
+struct ex_regs {
+    unsigned long rax, rcx, rdx, rbx;
+    unsigned long dummy, rbp, rsi, rdi;
+#ifdef __x86_64__
+    unsigned long r8, r9, r10, r11;
+    unsigned long r12, r13, r14, r15;
+#endif
+    unsigned long vector;
+    unsigned long error_code;
+    unsigned long rip;
+    unsigned long cs;
+    unsigned long rflags;
+};
+
 #define ASM_TRY(catch)                                  \
     "movl $0, %%gs:4 \n\t"                              \
     ".pushsection .data.ex \n\t"                        \
@@ -29,5 +43,6 @@ void set_idt_entry(int vec, void *addr, int dpl);
 void set_gdt_entry(int num, u32 base,  u32 limit, u8 access, u8 gran);
 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));
 
 #endif
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH unit-tests 15/16] Move invlpg() into library code.
  2010-12-22 15:06 [PATCH unit-tests 00/16] task switch and event injection tests Gleb Natapov
                   ` (13 preceding siblings ...)
  2010-12-22 15:06 ` [PATCH unit-tests 14/16] Add handle_exception() interface Gleb Natapov
@ 2010-12-22 15:06 ` Gleb Natapov
  2010-12-22 15:06 ` [PATCH unit-tests 16/16] Add even injection test Gleb Natapov
  15 siblings, 0 replies; 22+ messages in thread
From: Gleb Natapov @ 2010-12-22 15:06 UTC (permalink / raw)
  To: avi, mtosatti; +Cc: kvm


Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
 lib/x86/processor.h |    4 ++++
 x86/access.c        |    5 -----
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/lib/x86/processor.h b/lib/x86/processor.h
index 52881a3..61f3fc9 100644
--- a/lib/x86/processor.h
+++ b/lib/x86/processor.h
@@ -290,4 +290,8 @@ static inline void irq_enable(void)
     asm volatile("sti");
 }
 
+static inline void invlpg(void *va)
+{
+	asm volatile("invlpg (%0)" ::"r" (va) : "memory");
+}
 #endif
diff --git a/x86/access.c b/x86/access.c
index 120682d..c0554d7 100644
--- a/x86/access.c
+++ b/x86/access.c
@@ -199,11 +199,6 @@ int ac_test_bump(ac_test_t *at)
     return ret;
 }
 
-void invlpg(void *addr)
-{
-    asm volatile ("invlpg (%0)" : : "r"(addr));
-}
-
 pt_element_t ac_test_alloc_pt(ac_pool_t *pool)
 {
     pt_element_t ret = pool->pt_pool + pool->pt_pool_current;
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH unit-tests 16/16] Add even injection test.
  2010-12-22 15:06 [PATCH unit-tests 00/16] task switch and event injection tests Gleb Natapov
                   ` (14 preceding siblings ...)
  2010-12-22 15:06 ` [PATCH unit-tests 15/16] Move invlpg() into library code Gleb Natapov
@ 2010-12-22 15:06 ` Gleb Natapov
  15 siblings, 0 replies; 22+ messages in thread
From: Gleb Natapov @ 2010-12-22 15:06 UTC (permalink / raw)
  To: avi, mtosatti; +Cc: kvm

Add various event injection test. Those tests use testdev to unmap
pages from shadow pages/ept tables which make it possible to test
rare scenarios.

Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
 config-x86-common.mak |    4 +-
 lib/x86/desc.c        |    7 +-
 lib/x86/desc.h        |    3 +
 lib/x86/vm.c          |    6 +
 lib/x86/vm.h          |    1 +
 x86/eventinj.c        |  372 +++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 391 insertions(+), 2 deletions(-)
 create mode 100644 x86/eventinj.c

diff --git a/config-x86-common.mak b/config-x86-common.mak
index 3a77a93..732c4b7 100644
--- a/config-x86-common.mak
+++ b/config-x86-common.mak
@@ -33,7 +33,7 @@ tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \
                $(TEST_DIR)/smptest.flat  $(TEST_DIR)/port80.flat \
                $(TEST_DIR)/realmode.flat $(TEST_DIR)/msr.flat \
                $(TEST_DIR)/hypercall.flat $(TEST_DIR)/sieve.flat \
-               $(TEST_DIR)/kvmclock_test.flat
+               $(TEST_DIR)/kvmclock_test.flat  $(TEST_DIR)/eventinj.flat
 
 tests_and_config = $(TEST_DIR)/*.flat $(TEST_DIR)/unittests.cfg
 
@@ -77,6 +77,8 @@ $(TEST_DIR)/svm.elf: $(cstart.o)
 $(TEST_DIR)/kvmclock_test.elf: $(cstart.o) $(TEST_DIR)/kvmclock.o \
                                 $(TEST_DIR)/kvmclock_test.o
 
+$(TEST_DIR)/eventinj.elf: $(cstart.o) $(TEST_DIR)/eventinj.o
+
 arch_clean:
 	$(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat $(TEST_DIR)/*.elf \
 	$(TEST_DIR)/.*.d $(TEST_DIR)/lib/.*.d $(TEST_DIR)/lib/*.o
diff --git a/lib/x86/desc.c b/lib/x86/desc.c
index 0da8989..1bd4421 100644
--- a/lib/x86/desc.c
+++ b/lib/x86/desc.c
@@ -62,7 +62,7 @@ typedef struct {
 	u16 iomap_base;
 } tss32_t;
 
-static idt_entry_t idt[256];
+static idt_entry_t idt[256] __attribute__((aligned(4096)));
 
 void load_lidt(idt_entry_t *idt, int nentries)
 {
@@ -90,6 +90,11 @@ void set_idt_entry(int vec, void *addr, int dpl)
 #endif
 }
 
+void set_idt_sel(int vec, u16 sel)
+{
+    idt_entry_t *e = &idt[vec];
+    e->selector = sel;
+}
 
 struct ex_record {
     unsigned long rip;
diff --git a/lib/x86/desc.h b/lib/x86/desc.h
index 073878d..0b4897c 100644
--- a/lib/x86/desc.h
+++ b/lib/x86/desc.h
@@ -37,9 +37,12 @@ struct ex_regs {
 #define TSS_MAIN 0x20
 #define TSS_INTR 0x28
 
+#define NP_SEL 0x18
+
 unsigned exception_vector(void);
 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_intr_task_gate(int e, void *fn);
 void print_current_tss_info(void);
diff --git a/lib/x86/vm.c b/lib/x86/vm.c
index 1ca8a05..abbb0c9 100644
--- a/lib/x86/vm.c
+++ b/lib/x86/vm.c
@@ -248,3 +248,9 @@ void *vmap(unsigned long long phys, unsigned long size)
     }
     return mem;
 }
+
+void *alloc_vpage(void)
+{
+	vfree_top -= PAGE_SIZE;
+	return vfree_top;
+}
diff --git a/lib/x86/vm.h b/lib/x86/vm.h
index a3d2676..bf8fd52 100644
--- a/lib/x86/vm.h
+++ b/lib/x86/vm.h
@@ -20,6 +20,7 @@ void setup_vm();
 void *vmalloc(unsigned long size);
 void vfree(void *mem);
 void *vmap(unsigned long long phys, unsigned long size);
+void *alloc_vpage(void);
 
 void install_pte(unsigned long *cr3,
                         int pte_level,
diff --git a/x86/eventinj.c b/x86/eventinj.c
new file mode 100644
index 0000000..bcdc481
--- /dev/null
+++ b/x86/eventinj.c
@@ -0,0 +1,372 @@
+#include "libcflat.h"
+#include "processor.h"
+#include "vm.h"
+#include "desc.h"
+#include "isr.h"
+#include "apic.h"
+#include "apic-defs.h"
+
+#ifdef __x86_64__
+#  define R "r"
+#else
+#  define R "e"
+#endif
+
+static int g_fail;
+static int g_tests;
+
+static inline void io_delay(void)
+{
+}
+
+static inline void outl(int addr, int val)
+{
+        asm volatile ("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 |
+		       APIC_INT_ASSERT | v, 0);
+}
+
+void apic_self_nmi(void)
+{
+	apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0);
+}
+
+static void eoi(void)
+{
+    apic_write(APIC_EOI, 0);
+}
+
+#define flush_phys_addr(__s) outl(0xe4, __s)
+#define flush_stack() do {						\
+		int __l;						\
+		flush_phys_addr(virt_to_phys(&__l));			\
+	} while (0)
+
+extern char isr_iret_ip[];
+
+static void flush_idt_page()
+{
+	struct descriptor_table_ptr ptr;
+	sidt(&ptr);
+	flush_phys_addr(virt_to_phys((void*)ptr.base));
+}
+
+static volatile unsigned int test_divider;
+static volatile int test_count;
+
+#ifndef __x86_64__
+ulong stack_phys;
+void *stack_va;
+
+static void pf_tss(void)
+{
+start:
+	printf("PF running\n");
+	install_pte(phys_to_virt(read_cr3()), 1, stack_va,
+		    stack_phys | PTE_PRESENT | PTE_WRITE, 0);
+	invlpg(stack_va);
+	asm volatile ("iret");
+	goto start;
+}
+
+static void of_isr(struct ex_regs *r)
+{
+	printf("OF isr running\n");
+	test_count++;
+}
+
+static void np_isr(struct ex_regs *r)
+{
+	printf("NP isr running %x err=%x\n", r->rip, r->error_code);
+	set_idt_sel(33, read_cs());
+	test_count++;
+}
+#endif
+
+static void de_isr(struct ex_regs *r)
+{
+	printf("DE isr running divider is %d\n", test_divider);
+	test_divider = 10;
+}
+
+static void bp_isr(struct ex_regs *r)
+{
+	printf("BP isr running\n");
+	test_count++;
+}
+
+static void nested_nmi_isr(struct ex_regs *r)
+{
+	printf("Nested NMI isr running rip=%x\n", r->rip);
+
+	if (r->rip != (ulong)&isr_iret_ip)
+		test_count++;
+}
+static void nmi_isr(struct ex_regs *r)
+{
+	printf("NMI isr running %x\n", &isr_iret_ip);
+	test_count++;
+	handle_exception(2, nested_nmi_isr);
+	printf("Try send nested NMI to itself\n");
+	apic_self_nmi();
+	io_delay();
+	printf("After nested NMI to itself\n");
+}
+
+static void tirq0(isr_regs_t *r)
+{
+	printf("irq0 running\n");
+	if (test_count != 0)
+		test_count++;
+	eoi();
+}
+
+static void tirq1(isr_regs_t *r)
+{
+	printf("irq1 running\n");
+	test_count++;
+	eoi();
+}
+
+ulong saved_stack;
+
+#define switch_stack(S) do {						\
+		asm volatile ("mov %%"R"sp, %0":"=r"(saved_stack));	\
+		asm volatile ("mov %0, %%"R"sp"::"r"(S));		\
+	} while(0)
+
+#define restore_stack() do {						\
+		asm volatile ("mov %0, %%"R"sp"::"r"(saved_stack));	\
+	} while(0)
+
+int main()
+{
+	unsigned int res;
+	ulong *pt, *cr3, i;
+
+	setup_vm();
+	setup_idt();
+	setup_gdt();
+	setup_tss32();
+
+	handle_irq(32, tirq0);
+	handle_irq(33, tirq1);
+
+	/* generate HW exception that will fault on IDT and stack */
+	handle_exception(0, de_isr);
+	printf("Try to divide by 0\n");
+	flush_idt_page();
+	flush_stack();
+	asm volatile ("divl %3": "=a"(res)
+		      : "d"(0), "a"(1500), "m"(test_divider));
+	printf("Result is %d\n", res);
+	report("DE exception", res == 150);
+
+	/* generate soft exception (BP) that will fault on IDT and stack */
+	test_count = 0;
+	handle_exception(3, bp_isr);
+	printf("Try int 3\n");
+	flush_idt_page();
+	flush_stack();
+	asm volatile ("int $3");
+	printf("After int 3\n");
+	report("BP exception", test_count == 1);
+
+#ifndef __x86_64__
+	/* generate soft exception (OF) that will fault on IDT */
+	test_count = 0;
+	handle_exception(4, of_isr);
+	flush_idt_page();
+	printf("Try into\n");
+	asm volatile ("addb $127, %b0\ninto"::"a"(127));
+	printf("After into\n");
+	report("OF exception", test_count == 1);
+
+	/* generate soft exception (OF) using two bit instruction that will
+	   fault on IDT */
+	test_count = 0;
+	handle_exception(4, of_isr);
+	flush_idt_page();
+	printf("Try into\n");
+	asm volatile ("addb $127, %b0\naddr16 into"::"a"(127));
+	printf("After into\n");
+	report("2 byte OF exception", test_count == 1);
+#endif
+
+	/* generate HW interrupt that will fault on IDT */
+	test_count = 0;
+	flush_idt_page();
+	printf("Try send vec 33 to itself\n");
+	irq_enable();
+	apic_self_ipi(33);
+	io_delay();
+	irq_disable();
+	printf("After vec 33 to itself\n");
+	report("vec 33", test_count == 1);
+
+	/* generate soft interrupt that will fault on IDT and stack */
+	test_count = 0;
+	flush_idt_page();
+	printf("Try int $33\n");
+	flush_stack();
+	asm volatile ("int $33");
+	printf("After int $33\n");
+	report("int $33", test_count == 1);
+
+	/* Inject two HW interrupt than open iterrupt windows. Both interrupt
+	   will fault on IDT access */
+	test_count = 0;
+	flush_idt_page();
+	printf("Try send vec 32 and 33 to itself\n");
+	apic_self_ipi(32);
+	apic_self_ipi(33);
+	io_delay();
+	irq_enable();
+	asm volatile("nop");
+	irq_disable();
+	printf("After vec 32 and 33 to itself\n");
+	report("vec 32/33", test_count == 2);
+
+
+	/* Inject HW interrupt, do sti and than (while in irq shadow) inject
+	   soft interrupt. Fault during soft interrupt. Soft interrup shoud be
+	   handled before HW interrupt */
+	test_count = 0;
+	flush_idt_page();
+	printf("Try send vec 32 and int $33\n");
+	apic_self_ipi(32);
+	flush_stack();
+	io_delay();
+	irq_enable();
+	asm volatile ("int $33");
+	irq_disable();
+	printf("After vec 32 and int $33\n");
+	report("vec 32/int $33", test_count == 2);
+
+	/* test that TPR is honored */
+	test_count = 0;
+	handle_irq(62, tirq1);
+	flush_idt_page();
+	printf("Try send vec 33 and 62 and mask one with TPR\n");
+	apic_write(APIC_TASKPRI, 0xf << 4);
+	irq_enable();
+	apic_self_ipi(32);
+	apic_self_ipi(62);
+	io_delay();
+	apic_write(APIC_TASKPRI, 0x2 << 4);
+	printf("After 33/62 TPR test\n");
+	report("TPR", test_count == 1);
+	apic_write(APIC_TASKPRI, 0x0);
+	while(test_count != 2); /* wait for second irq */
+	irq_disable();
+
+#ifndef __x86_64__
+	/* test fault durint NP delivery */
+	printf("Before NP test\n");
+	test_count = 0;
+	handle_exception(11, np_isr);
+	set_idt_sel(33, NP_SEL);
+	flush_idt_page();
+	flush_stack();
+	asm volatile ("int $33");
+	printf("After int33\n");
+	report("NP exception", test_count == 2);
+#endif
+
+	/* generate NMI that will fault on IDT */
+	test_count = 0;
+	handle_exception(2, nmi_isr);
+	flush_idt_page();
+	printf("Try send NMI to itself\n");
+	apic_self_nmi();
+	printf("After NMI to itself\n");
+	/* this is needed on VMX without NMI window notificatoin.
+	   Interrupt windows is used instead, so let pending NMI
+	   to be injected */
+	irq_enable();
+	asm volatile ("nop");
+	irq_disable();
+	report("NMI", test_count == 2);
+
+#ifndef __x86_64__
+	stack_phys = (ulong)virt_to_phys(alloc_page());
+	stack_va = alloc_vpage();
+
+	/* Generate DE and PF exceptions serially */
+	test_divider = 0;
+	set_intr_task_gate(14, pf_tss);
+	handle_exception(0, de_isr);
+	printf("Try to divide by 0\n");
+	/* install read only pte */
+	install_pte(phys_to_virt(read_cr3()), 1, stack_va,
+		    stack_phys | PTE_PRESENT, 0);
+	invlpg(stack_va);
+	flush_phys_addr(stack_phys);
+	switch_stack(stack_va + 4095);
+	flush_idt_page();
+	asm volatile ("divl %3": "=a"(res)
+		      : "d"(0), "a"(1500), "m"(test_divider));
+	restore_stack();
+	printf("Result is %d\n", res);
+	report("DE PF exceptions", res == 150);
+
+	/* Generate NP and PF exceptions serially */
+	printf("Before NP test\n");
+	test_count = 0;
+	set_intr_task_gate(14, pf_tss);
+	handle_exception(11, np_isr);
+	set_idt_sel(33, NP_SEL);
+	/* install read only pte */
+	install_pte(phys_to_virt(read_cr3()), 1, stack_va,
+		    stack_phys | PTE_PRESENT, 0);
+	invlpg(stack_va);
+	flush_idt_page();
+	flush_phys_addr(stack_phys);
+	switch_stack(stack_va + 4095);
+	asm volatile ("int $33");
+	restore_stack();
+	printf("After int33\n");
+	report("NP PF exceptions", test_count == 2);
+#endif
+
+	pt = alloc_page();
+	cr3 = (void*)read_cr3();
+	memset(pt, 0, 4096);
+	/* use shadowed stack during interrupt delivery */
+	for (i = 0; i < 4096/sizeof(ulong); i++) {
+		if (!cr3[i]) {
+			cr3[i] = virt_to_phys(pt) | PTE_PRESENT | PTE_WRITE;
+			pt[0] = virt_to_phys(pt) | PTE_PRESENT | PTE_WRITE;
+#ifndef __x86_64__
+			((ulong*)(i<<22))[1] = 0;
+#else
+			((ulong*)(i<<39))[1] = 0;
+#endif
+			write_cr3(virt_to_phys(cr3));
+			break;
+		}
+	}
+	test_count = 0;
+	printf("Try int 33 with shadowed stack\n");
+	switch_stack(((char*)pt) + 4095);
+	asm volatile("int $33");
+	restore_stack();
+	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;
+}
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH unit-tests 06/16] Specify correct operand length for ltr and str.
  2010-12-22 15:06 ` [PATCH unit-tests 06/16] Specify correct operand length for ltr and str Gleb Natapov
@ 2010-12-29  9:37   ` Avi Kivity
  2010-12-29  9:40     ` Gleb Natapov
  0 siblings, 1 reply; 22+ messages in thread
From: Avi Kivity @ 2010-12-29  9:37 UTC (permalink / raw)
  To: Gleb Natapov; +Cc: mtosatti, kvm

On 12/22/2010 05:06 PM, Gleb Natapov wrote:
> Signed-off-by: Gleb Natapov<gleb@redhat.com>
> ---
>   lib/x86/processor.h |    4 ++--
>   1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/lib/x86/processor.h b/lib/x86/processor.h
> index c348808..c3ab109 100644
> --- a/lib/x86/processor.h
> +++ b/lib/x86/processor.h
> @@ -193,13 +193,13 @@ static inline u16 sldt(void)
>
>   static inline void ltr(unsigned val)
>   {
> -    asm volatile ("ltr %0" : : "rm"(val));
> +    asm volatile ("ltr %w0" : : "rm"(val));
>   }

Is this really needed?  And isn't this done better by declaring 'u16 val'?

>
>   static inline u16 str(void)
>   {
>       u16 val;
> -    asm volatile ("str %0" : "=rm"(val));
> +    asm volatile ("str %w0" : "=rm"(val));
>       return val;
>   }
>

This looks completely unneeded, since val is already a u16.

-- 
error compiling committee.c: too many arguments to function


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH unit-tests 05/16] Rename idt.[ch] into desc.[ch]
  2010-12-22 15:06 ` [PATCH unit-tests 05/16] Rename idt.[ch] into desc.[ch] Gleb Natapov
@ 2010-12-29  9:38   ` Avi Kivity
  0 siblings, 0 replies; 22+ messages in thread
From: Avi Kivity @ 2010-12-29  9:38 UTC (permalink / raw)
  To: Gleb Natapov; +Cc: mtosatti, kvm

On 12/22/2010 05:06 PM, Gleb Natapov wrote:
> All descriptor related code will go there.
>

In the future, please set diff.rename = true in your global git 
configuration so renames look nicer.

-- 
error compiling committee.c: too many arguments to function


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH unit-tests 06/16] Specify correct operand length for ltr and str.
  2010-12-29  9:37   ` Avi Kivity
@ 2010-12-29  9:40     ` Gleb Natapov
  2010-12-29  9:43       ` Gleb Natapov
  0 siblings, 1 reply; 22+ messages in thread
From: Gleb Natapov @ 2010-12-29  9:40 UTC (permalink / raw)
  To: Avi Kivity; +Cc: mtosatti, kvm

On Wed, Dec 29, 2010 at 11:37:58AM +0200, Avi Kivity wrote:
> On 12/22/2010 05:06 PM, Gleb Natapov wrote:
> >Signed-off-by: Gleb Natapov<gleb@redhat.com>
> >---
> >  lib/x86/processor.h |    4 ++--
> >  1 files changed, 2 insertions(+), 2 deletions(-)
> >
> >diff --git a/lib/x86/processor.h b/lib/x86/processor.h
> >index c348808..c3ab109 100644
> >--- a/lib/x86/processor.h
> >+++ b/lib/x86/processor.h
> >@@ -193,13 +193,13 @@ static inline u16 sldt(void)
> >
> >  static inline void ltr(unsigned val)
> >  {
> >-    asm volatile ("ltr %0" : : "rm"(val));
> >+    asm volatile ("ltr %w0" : : "rm"(val));
> >  }
> 
> Is this really needed?  And isn't this done better by declaring 'u16 val'?
> 
> >
> >  static inline u16 str(void)
> >  {
> >      u16 val;
> >-    asm volatile ("str %0" : "=rm"(val));
> >+    asm volatile ("str %w0" : "=rm"(val));
> >      return val;
> >  }
> >
> 
> This looks completely unneeded, since val is already a u16.
> 
IIRC I got errors from assembler. Will recheck.

--
			Gleb.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH unit-tests 06/16] Specify correct operand length for ltr and str.
  2010-12-29  9:40     ` Gleb Natapov
@ 2010-12-29  9:43       ` Gleb Natapov
  2010-12-29  9:47         ` Avi Kivity
  0 siblings, 1 reply; 22+ messages in thread
From: Gleb Natapov @ 2010-12-29  9:43 UTC (permalink / raw)
  To: Avi Kivity; +Cc: mtosatti, kvm

On Wed, Dec 29, 2010 at 11:40:15AM +0200, Gleb Natapov wrote:
> On Wed, Dec 29, 2010 at 11:37:58AM +0200, Avi Kivity wrote:
> > On 12/22/2010 05:06 PM, Gleb Natapov wrote:
> > >Signed-off-by: Gleb Natapov<gleb@redhat.com>
> > >---
> > >  lib/x86/processor.h |    4 ++--
> > >  1 files changed, 2 insertions(+), 2 deletions(-)
> > >
> > >diff --git a/lib/x86/processor.h b/lib/x86/processor.h
> > >index c348808..c3ab109 100644
> > >--- a/lib/x86/processor.h
> > >+++ b/lib/x86/processor.h
> > >@@ -193,13 +193,13 @@ static inline u16 sldt(void)
> > >
> > >  static inline void ltr(unsigned val)
> > >  {
> > >-    asm volatile ("ltr %0" : : "rm"(val));
> > >+    asm volatile ("ltr %w0" : : "rm"(val));
> > >  }
> > 
> > Is this really needed?  And isn't this done better by declaring 'u16 val'?
> > 
> > >
> > >  static inline u16 str(void)
> > >  {
> > >      u16 val;
> > >-    asm volatile ("str %0" : "=rm"(val));
> > >+    asm volatile ("str %w0" : "=rm"(val));
> > >      return val;
> > >  }
> > >
> > 
> > This looks completely unneeded, since val is already a u16.
> > 
> IIRC I got errors from assembler. Will recheck.
> 
You are correct. The error was only about ltr. Changing unsigned to u16
fixes it.

--
			Gleb.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH unit-tests 06/16] Specify correct operand length for ltr and str.
  2010-12-29  9:43       ` Gleb Natapov
@ 2010-12-29  9:47         ` Avi Kivity
  0 siblings, 0 replies; 22+ messages in thread
From: Avi Kivity @ 2010-12-29  9:47 UTC (permalink / raw)
  To: Gleb Natapov; +Cc: mtosatti, kvm

On 12/29/2010 11:43 AM, Gleb Natapov wrote:
> >  >
> >  >  This looks completely unneeded, since val is already a u16.
> >  >
> >  IIRC I got errors from assembler. Will recheck.
> >
> You are correct. The error was only about ltr. Changing unsigned to u16
> fixes it.
>

Ok, I'll fix it.  Applied all the other patches.

-- 
error compiling committee.c: too many arguments to function


^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2010-12-29  9:47 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-12-22 15:06 [PATCH unit-tests 00/16] task switch and event injection tests Gleb Natapov
2010-12-22 15:06 ` [PATCH unit-tests 01/16] Move idt.c into lib code Gleb Natapov
2010-12-22 15:06 ` [PATCH unit-tests 02/16] Make access.c use library functions Gleb Natapov
2010-12-22 15:06 ` [PATCH unit-tests 03/16] Remove duplicated idt code from apic test Gleb Natapov
2010-12-22 15:06 ` [PATCH unit-tests 04/16] Remove unused function " Gleb Natapov
2010-12-22 15:06 ` [PATCH unit-tests 05/16] Rename idt.[ch] into desc.[ch] Gleb Natapov
2010-12-29  9:38   ` Avi Kivity
2010-12-22 15:06 ` [PATCH unit-tests 06/16] Specify correct operand length for ltr and str Gleb Natapov
2010-12-29  9:37   ` Avi Kivity
2010-12-29  9:40     ` Gleb Natapov
2010-12-29  9:43       ` Gleb Natapov
2010-12-29  9:47         ` Avi Kivity
2010-12-22 15:06 ` [PATCH unit-tests 07/16] Move irq_(enable|disable) into library code Gleb Natapov
2010-12-22 15:06 ` [PATCH unit-tests 08/16] Add another task switch test Gleb Natapov
2010-12-22 15:06 ` [PATCH unit-tests 09/16] Move vm.[ch] info library code Gleb Natapov
2010-12-22 15:06 ` [PATCH unit-tests 10/16] Fix mmu on 32 bit Gleb Natapov
2010-12-22 15:06 ` [PATCH unit-tests 11/16] Set WP bit in CR0 to make write protection work Gleb Natapov
2010-12-22 15:06 ` [PATCH unit-tests 12/16] Fix exception handling on i386 arch Gleb Natapov
2010-12-22 15:06 ` [PATCH unit-tests 13/16] Move handle_irq() from apic test into library code Gleb Natapov
2010-12-22 15:06 ` [PATCH unit-tests 14/16] Add handle_exception() interface Gleb Natapov
2010-12-22 15:06 ` [PATCH unit-tests 15/16] Move invlpg() into library code Gleb Natapov
2010-12-22 15:06 ` [PATCH unit-tests 16/16] Add even injection test Gleb Natapov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox