All of lore.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.