The APIs in desc.c make it much simpler to understand what the test is doing. Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx> --- lib/x86/desc.c | 7 ++- lib/x86/desc.h | 2 + x86/taskswitch.c | 134 +++++-------------------------------------------------- 3 files changed, 18 insertions(+), 125 deletions(-) diff --git a/lib/x86/desc.c b/lib/x86/desc.c index 812295c..442c9a1 100644 --- a/lib/x86/desc.c +++ b/lib/x86/desc.c @@ -217,6 +217,11 @@ void set_gdt_entry(int sel, u32 base, u32 limit, u8 access, u8 gran) gdt32[num].access = access; } +void set_gdt_task_gate(u16 sel, u16 tss_sel) +{ + set_gdt_entry(sel, tss_sel, 0, 0x85, 0); // task, present +} + void set_idt_task_gate(int vec, u16 sel) { idt_entry_t *e = &boot_idt[vec]; @@ -235,7 +240,7 @@ void set_idt_task_gate(int vec, u16 sel) * 1 - interrupt task */ -static tss32_t tss_intr; +tss32_t tss_intr; static char tss_stack[4096]; void setup_tss32(void) diff --git a/lib/x86/desc.h b/lib/x86/desc.h index e0af335..4689474 100644 --- a/lib/x86/desc.h +++ b/lib/x86/desc.h @@ -106,6 +106,7 @@ extern idt_entry_t boot_idt[256]; #ifndef __x86_64__ extern gdt_entry_t gdt32[]; extern tss32_t tss; +extern tss32_t tss_intr; #endif unsigned exception_vector(void); @@ -113,6 +114,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 sel, u32 base, u32 limit, u8 access, u8 gran); +void set_gdt_task_gate(u16 tss_sel, u16 sel); void set_idt_task_gate(int vec, u16 sel); void set_intr_task_gate(int e, void *fn); void print_current_tss_info(void); diff --git a/x86/taskswitch.c b/x86/taskswitch.c index 8ed8a93..423f51e 100644 --- a/x86/taskswitch.c +++ b/x86/taskswitch.c @@ -6,152 +6,38 @@ */ #include "libcflat.h" +#include "lib/x86/desc.h" -#define FIRST_SPARE_SEL 0x18 - -struct exception_frame { - unsigned long error_code; - unsigned long ip; - unsigned long cs; - unsigned long flags; -}; - -struct tss32 { - unsigned short prev; - unsigned short res1; - unsigned long esp0; - unsigned short ss0; - unsigned short res2; - unsigned long esp1; - unsigned short ss1; - unsigned short res3; - unsigned long esp2; - unsigned short ss2; - unsigned short res4; - unsigned long cr3; - unsigned long eip; - unsigned long eflags; - unsigned long eax, ecx, edx, ebx, esp, ebp, esi, edi; - unsigned short es; - unsigned short res5; - unsigned short cs; - unsigned short res6; - unsigned short ss; - unsigned short res7; - unsigned short ds; - unsigned short res8; - unsigned short fs; - unsigned short res9; - unsigned short gs; - unsigned short res10; - unsigned short ldt; - unsigned short res11; - unsigned short t:1; - unsigned short res12:15; - unsigned short iomap_base; -}; - -static char main_stack[4096]; -static char fault_stack[4096]; -static struct tss32 main_tss; -static struct tss32 fault_tss; - -static unsigned long long gdt[] __attribute__((aligned(16))) = { - 0, - 0x00cf9b000000ffffull, - 0x00cf93000000ffffull, - 0, 0, /* TSS segments */ - 0, /* task return gate */ -}; - -static unsigned long long gdtr; +#define TSS_RETURN (FIRST_SPARE_SEL) void fault_entry(void); static __attribute__((used, regparm(1))) void fault_handler(unsigned long error_code) { - unsigned short *desc; - - printf("fault at %x:%x, prev task %x, error code %x\n", - main_tss.cs, main_tss.eip, fault_tss.prev, error_code); + print_current_tss_info(); + printf("error code %x\n", error_code); - main_tss.eip += 2; + tss.eip += 2; - desc = (unsigned short *)&gdt[3]; - desc[2] &= ~0x0200; + gdt32[TSS_MAIN / 8].access &= ~2; - desc = (unsigned short *)&gdt[5]; - desc[0] = 0; - desc[1] = fault_tss.prev; - desc[2] = 0x8500; - desc[3] = 0; + set_gdt_task_gate(TSS_RETURN, tss_intr.prev); } asm ( "fault_entry:\n" " mov (%esp),%eax\n" " call fault_handler\n" - " jmp $0x28, $0\n" + " jmp $" xstr(TSS_RETURN) ", $0\n" ); -static void setup_tss(struct tss32 *tss, void *entry, - void *stack_base, unsigned long stack_size) -{ - unsigned long cr3; - unsigned short cs, ds; - - asm ("mov %%cr3,%0" : "=r" (cr3)); - asm ("mov %%cs,%0" : "=r" (cs)); - asm ("mov %%ds,%0" : "=r" (ds)); - - tss->ss0 = tss->ss1 = tss->ss2 = tss->ss = ds; - tss->esp0 = tss->esp1 = tss->esp2 = tss->esp = - (unsigned long)stack_base + stack_size; - tss->ds = tss->es = tss->fs = tss->gs = ds; - tss->cs = cs; - tss->eip = (unsigned long)entry; - tss->cr3 = cr3; -} - -static void setup_tss_desc(unsigned short tss_sel, struct tss32 *tss) -{ - unsigned long addr = (unsigned long)tss; - unsigned short *desc; - - desc = (unsigned short *)&gdt[tss_sel/8]; - desc[0] = sizeof(*tss) - 1; - desc[1] = addr; - desc[2] = 0x8900 | ((addr & 0x00ff0000) >> 16); - desc[3] = (addr & 0xff000000) >> 16; -} - -static void set_intr_task(unsigned short tss_sel, int intr, struct tss32 *tss) -{ - unsigned short *desc = (void *)(intr* sizeof(long) * 2); - - setup_tss_desc(tss_sel, tss); - - desc[0] = 0; - desc[1] = tss_sel; - desc[2] = 0x8500; - desc[3] = 0; -} - int main(int ac, char **av) { const long invalid_segment = 0x1234; - gdtr = ((unsigned long long)(unsigned long)&gdt << 16) | - (sizeof(gdt) - 1); - asm ("lgdt %0" : : "m" (gdtr)); - - setup_tss(&main_tss, 0, main_stack, sizeof(main_stack)); - setup_tss_desc(FIRST_SPARE_SEL, &main_tss); - asm ("ltr %0" : : "r" ((unsigned short)FIRST_SPARE_SEL)); - - setup_tss(&fault_tss, fault_entry, fault_stack, sizeof(fault_stack)); - set_intr_task(FIRST_SPARE_SEL+8, 13, &fault_tss); + setup_tss32(); + set_intr_task_gate(13, fault_entry); asm ( "mov %0,%%es\n" -- 1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html