* [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* 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 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
* [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