Commit 5b0bf08b authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

x86: taskswitch: use desc library



The APIs in desc.c make it much simpler to understand what the test
is doing.

Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 8f4755fa
......@@ -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"
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment