@@ -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)
@@ -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);
@@ -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"
The APIs in desc.c make it much simpler to understand what the test is doing. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> --- lib/x86/desc.c | 7 ++- lib/x86/desc.h | 2 + x86/taskswitch.c | 134 +++++-------------------------------------------------- 3 files changed, 18 insertions(+), 125 deletions(-)