From: Kevin Wolf <kwolf@redhat.com>
To: kvm@vger.kernel.org
Cc: kwolf@redhat.com, gleb@redhat.com, mtosatti@redhat.com
Subject: [PATCH kvm-unittests v2] x86/taskswitch2: Task switches into/out of VM86
Date: Fri, 12 Apr 2013 13:14:47 +0200 [thread overview]
Message-ID: <1365765287-5759-1-git-send-email-kwolf@redhat.com> (raw)
This adds a test case that jumps into VM86 by iret-ing to a TSS and back
to Protected Mode using a task gate in the IDT.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
lib/x86/desc.c | 41 ++++------------------------------
lib/x86/desc.h | 36 ++++++++++++++++++++++++++++++
lib/x86/vm.c | 4 ++--
lib/x86/vm.h | 1 +
x86/taskswitch2.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
5 files changed, 104 insertions(+), 45 deletions(-)
diff --git a/lib/x86/desc.c b/lib/x86/desc.c
index 770c250..7c5c721 100644
--- a/lib/x86/desc.c
+++ b/lib/x86/desc.c
@@ -27,41 +27,6 @@ typedef struct {
u8 base_high;
} gdt_entry_t;
-typedef struct {
- u16 prev;
- u16 res1;
- u32 esp0;
- u16 ss0;
- u16 res2;
- u32 esp1;
- u16 ss1;
- u16 res3;
- u32 esp2;
- u16 ss2;
- u16 res4;
- u32 cr3;
- u32 eip;
- u32 eflags;
- u32 eax, ecx, edx, ebx, esp, ebp, esi, edi;
- u16 es;
- u16 res5;
- u16 cs;
- u16 res6;
- u16 ss;
- u16 res7;
- u16 ds;
- u16 res8;
- u16 fs;
- u16 res9;
- u16 gs;
- u16 res10;
- u16 ldt;
- u16 res11;
- u16 t:1;
- u16 res12:15;
- u16 iomap_base;
-} tss32_t;
-
extern idt_entry_t boot_idt[256];
void set_idt_entry(int vec, void *addr, int dpl)
@@ -268,9 +233,11 @@ unsigned exception_error_code(void)
* 0x18 - Not presend code segment
* 0x20 - Primery task
* 0x28 - Interrupt task
+ *
+ * 0x30 to 0x48 - Free to use for test cases
*/
-static gdt_entry_t gdt[6];
+static gdt_entry_t gdt[10];
#define TSS_GDT_OFFSET 4
void set_gdt_entry(int num, u32 base, u32 limit, u8 access, u8 gran)
@@ -327,7 +294,7 @@ void setup_gdt(void)
".Lflush2: "::"r"(0x10));
}
-static void set_idt_task_gate(int vec, u16 sel)
+void set_idt_task_gate(int vec, u16 sel)
{
idt_entry_t *e = &boot_idt[vec];
diff --git a/lib/x86/desc.h b/lib/x86/desc.h
index 0b4897c..f819452 100644
--- a/lib/x86/desc.h
+++ b/lib/x86/desc.h
@@ -24,6 +24,41 @@ struct ex_regs {
unsigned long rflags;
};
+typedef struct {
+ u16 prev;
+ u16 res1;
+ u32 esp0;
+ u16 ss0;
+ u16 res2;
+ u32 esp1;
+ u16 ss1;
+ u16 res3;
+ u32 esp2;
+ u16 ss2;
+ u16 res4;
+ u32 cr3;
+ u32 eip;
+ u32 eflags;
+ u32 eax, ecx, edx, ebx, esp, ebp, esi, edi;
+ u16 es;
+ u16 res5;
+ u16 cs;
+ u16 res6;
+ u16 ss;
+ u16 res7;
+ u16 ds;
+ u16 res8;
+ u16 fs;
+ u16 res9;
+ u16 gs;
+ u16 res10;
+ u16 ldt;
+ u16 res11;
+ u16 t:1;
+ u16 res12:15;
+ u16 iomap_base;
+} tss32_t;
+
#define ASM_TRY(catch) \
"movl $0, %%gs:4 \n\t" \
".pushsection .data.ex \n\t" \
@@ -44,6 +79,7 @@ unsigned exception_error_code(void);
void set_idt_entry(int vec, void *addr, int dpl);
void set_idt_sel(int vec, u16 sel);
void set_gdt_entry(int num, u32 base, u32 limit, u8 access, u8 gran);
+void set_idt_task_gate(int vec, u16 sel);
void set_intr_task_gate(int e, void *fn);
void print_current_tss_info(void);
void handle_exception(u8 v, void (*func)(struct ex_regs *regs));
diff --git a/lib/x86/vm.c b/lib/x86/vm.c
index 2852c6c..260ec45 100644
--- a/lib/x86/vm.c
+++ b/lib/x86/vm.c
@@ -109,14 +109,14 @@ void install_large_page(unsigned long *cr3,
unsigned long phys,
void *virt)
{
- install_pte(cr3, 2, virt, phys | PTE_PRESENT | PTE_WRITE | PTE_PSE, 0);
+ install_pte(cr3, 2, virt, phys | PTE_PRESENT | PTE_WRITE | PTE_USER | PTE_PSE, 0);
}
void install_page(unsigned long *cr3,
unsigned long phys,
void *virt)
{
- install_pte(cr3, 1, virt, phys | PTE_PRESENT | PTE_WRITE, 0);
+ install_pte(cr3, 1, virt, phys | PTE_PRESENT | PTE_WRITE | PTE_USER, 0);
}
diff --git a/lib/x86/vm.h b/lib/x86/vm.h
index 3473f8d..0b5b5c7 100644
--- a/lib/x86/vm.h
+++ b/lib/x86/vm.h
@@ -13,6 +13,7 @@
#define PTE_PRESENT (1ull << 0)
#define PTE_PSE (1ull << 7)
#define PTE_WRITE (1ull << 1)
+#define PTE_USER (1ull << 2)
#define PTE_ADDR (0xffffffffff000ull)
void setup_vm();
diff --git a/x86/taskswitch2.c b/x86/taskswitch2.c
index 683834e..6573696 100644
--- a/x86/taskswitch2.c
+++ b/x86/taskswitch2.c
@@ -5,6 +5,10 @@
#include "processor.h"
#include "vm.h"
+#define FREE_GDT_INDEX 6
+#define MAIN_TSS_INDEX (FREE_GDT_INDEX + 0)
+#define VM86_TSS_INDEX (FREE_GDT_INDEX + 1)
+
#define xstr(s) str(s)
#define str(s) #s
@@ -113,15 +117,10 @@ start:
goto start;
}
-int main()
+void test_kernel_mode_int()
{
unsigned int res;
- setup_vm();
- setup_idt();
- setup_gdt();
- setup_tss32();
-
/* test that int $2 triggers task gate */
test_count = 0;
set_intr_task_gate(2, nmi_tss);
@@ -217,6 +216,62 @@ int main()
asm volatile ("ljmp $" xstr(TSS_INTR) ", $0xf4f4f4f4");
printf("Jump back succeeded\n");
report("ljmp", test_count == 1);
+}
+
+void test_vm86_switch(void)
+{
+ static tss32_t main_tss;
+ static tss32_t vm86_tss;
+
+ u8 *vm86_start;
+
+ /* Write a 'ud2' instruction somewhere below 1 MB */
+ vm86_start = (void*) 0x42000;
+ vm86_start[0] = 0x0f;
+ vm86_start[1] = 0x0b;
+
+ /* Main TSS */
+ set_gdt_entry(MAIN_TSS_INDEX, (u32)&main_tss, sizeof(tss32_t) - 1, 0x89, 0);
+ ltr(MAIN_TSS_INDEX << 3);
+ main_tss = (tss32_t) {
+ .prev = VM86_TSS_INDEX << 3,
+ .cr3 = read_cr3(),
+ };
+
+ /* VM86 TSS (marked as busy, so we can iret to it) */
+ set_gdt_entry(VM86_TSS_INDEX, (u32)&vm86_tss, sizeof(tss32_t) - 1, 0x8b, 0);
+ vm86_tss = (tss32_t) {
+ .eflags = 0x20002,
+ .cr3 = read_cr3(),
+ .eip = (u32) vm86_start & 0x0f,
+ .cs = (u32) vm86_start >> 4,
+ .ds = 0x1234,
+ .es = 0x2345,
+ };
+
+ /* Setup task gate to main TSS for #UD */
+ set_idt_task_gate(6, MAIN_TSS_INDEX << 3);
+
+ /* Jump into VM86 task with iret, #UD lets it come back immediately */
+ printf("Switch to VM86 task and back\n");
+ asm volatile(
+ "pushf\n"
+ "orw $0x4000, (%esp)\n"
+ "popf\n"
+ "iret\n"
+ );
+ report("VM86", 1);
+}
+
+int main()
+{
+ setup_vm();
+ setup_idt();
+ setup_gdt();
+ setup_tss32();
+
+ test_kernel_mode_int();
+ test_vm86_switch();
printf("\nsummary: %d tests, %d failures\n", g_tests, g_fail);
--
1.8.1.4
next reply other threads:[~2013-04-12 11:14 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-04-12 11:14 Kevin Wolf [this message]
2013-04-14 12:42 ` [PATCH kvm-unittests v2] x86/taskswitch2: Task switches into/out of VM86 Gleb Natapov
2013-04-15 8:56 ` Kevin Wolf
2013-04-15 15:38 ` Gleb Natapov
2013-04-15 15:42 ` Kevin Wolf
2013-04-15 15:49 ` Gleb Natapov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1365765287-5759-1-git-send-email-kwolf@redhat.com \
--to=kwolf@redhat.com \
--cc=gleb@redhat.com \
--cc=kvm@vger.kernel.org \
--cc=mtosatti@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox