From: Gleb Natapov <gleb@redhat.com>
To: Kevin Wolf <kwolf@redhat.com>
Cc: kvm@vger.kernel.org, mtosatti@redhat.com
Subject: Re: [PATCH kvm-unittests v2] x86/taskswitch2: Task switches into/out of VM86
Date: Sun, 14 Apr 2013 15:42:24 +0300 [thread overview]
Message-ID: <20130414124224.GO17919@redhat.com> (raw)
In-Reply-To: <1365765287-5759-1-git-send-email-kwolf@redhat.com>
On Fri, Apr 12, 2013 at 01:14:47PM +0200, Kevin Wolf wrote:
> This adds a test case that jumps into VM86 by iret-ing to a TSS and back
> to Protected Mode using a task gate in the IDT.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Applied, thanks. Found a bug with it and emulate_invalid_guest_state=1
which is default. Are you running with emulate_invalid_guest_state=0?
> ---
> 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
--
Gleb.
next prev parent reply other threads:[~2013-04-14 12:42 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-04-12 11:14 [PATCH kvm-unittests v2] x86/taskswitch2: Task switches into/out of VM86 Kevin Wolf
2013-04-14 12:42 ` Gleb Natapov [this message]
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=20130414124224.GO17919@redhat.com \
--to=gleb@redhat.com \
--cc=kvm@vger.kernel.org \
--cc=kwolf@redhat.com \
--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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.