There is no particular reason to use a specific TSS in tests that use task-switching. In fact, in many cases the tests just want a separate interrupt stack and could run on 64-bit just as well if the task-switching is abstracted. As a first step, remove duplicate protected mode setup from desc.c's users. Just leave some spare selectors in cstart.S's GDT before the CPUs' main TSS. Then reuse CPU 0's TSS as TSS_MAIN. Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx> --- lib/x86/desc.c | 98 ++++++++++++++----------------------------------------- lib/x86/desc.h | 13 +++++--- x86/asyncpf.c | 1 - x86/cstart.S | 16 +++++++++ x86/eventinj.c | 1 - x86/taskswitch2.c | 1 - 6 files changed, 49 insertions(+), 81 deletions(-) diff --git a/lib/x86/desc.c b/lib/x86/desc.c index 32034cf..812295c 100644 --- a/lib/x86/desc.c +++ b/lib/x86/desc.c @@ -193,69 +193,28 @@ unsigned exception_error_code(void) * 0x00 - NULL descriptor * 0x08 - Code segment * 0x10 - Data segment - * 0x18 - Not presend code segment - * 0x20 - Primery task - * 0x28 - Interrupt task - * - * 0x30 to 0x48 - Free to use for test cases + * 0x18 - Not present code segment + * 0x20 - Interrupt task + * 0x28 to 0x78 - Free to use for test cases + * 0x80 - Primary task (CPU 0) */ -static gdt_entry_t gdt[10]; - void set_gdt_entry(int sel, u32 base, u32 limit, u8 access, u8 gran) { int num = sel >> 3; /* Setup the descriptor base address */ - gdt[num].base_low = (base & 0xFFFF); - gdt[num].base_middle = (base >> 16) & 0xFF; - gdt[num].base_high = (base >> 24) & 0xFF; + gdt32[num].base_low = (base & 0xFFFF); + gdt32[num].base_middle = (base >> 16) & 0xFF; + gdt32[num].base_high = (base >> 24) & 0xFF; /* Setup the descriptor limits */ - gdt[num].limit_low = (limit & 0xFFFF); - gdt[num].granularity = ((limit >> 16) & 0x0F); + gdt32[num].limit_low = (limit & 0xFFFF); + gdt32[num].granularity = ((limit >> 16) & 0x0F); /* Finally, set up the granularity and access flags */ - gdt[num].granularity |= (gran & 0xF0); - gdt[num].access = access; -} - -void setup_gdt(void) -{ - struct descriptor_table_ptr gp; - /* Setup the GDT pointer and limit */ - gp.limit = sizeof(gdt) - 1; - gp.base = (ulong)&gdt; - - memset(gdt, 0, sizeof(gdt)); - - /* Our NULL descriptor */ - set_gdt_entry(0, 0, 0, 0, 0); - - /* The second entry is our Code Segment. The base address - * is 0, the limit is 4GBytes, it uses 4KByte granularity, - * uses 32-bit opcodes, and is a Code Segment descriptor. */ - set_gdt_entry(KERNEL_CS, 0, 0xFFFFFFFF, 0x9A, 0xcf); - - /* The third entry is our Data Segment. It's EXACTLY the - * same as our code segment, but the descriptor type in - * this entry's access byte says it's a Data Segment */ - set_gdt_entry(KERNEL_DS, 0, 0xFFFFFFFF, 0x92, 0xcf); - - /* Same as code register above but not present */ - set_gdt_entry(NP_SEL, 0, 0xFFFFFFFF, 0x1A, 0xcf); - - - /* Flush out the old GDT and install the new changes! */ - lgdt(&gp); - - asm volatile ("mov %0, %%ds\n\t" - "mov %0, %%es\n\t" - "mov %0, %%fs\n\t" - "mov %0, %%gs\n\t" - "mov %0, %%ss\n\t" - "jmp $" xstr(KERNEL_CS), $.Lflush2\n\t" - ".Lflush2: "::"r"(0x10)); + gdt32[num].granularity |= (gran & 0xF0); + gdt32[num].access = access; } void set_idt_task_gate(int vec, u16 sel) @@ -276,46 +235,39 @@ void set_idt_task_gate(int vec, u16 sel) * 1 - interrupt task */ -static tss32_t tss[2]; -static char tss_stack[2][4096]; +static tss32_t tss_intr; +static char tss_stack[4096]; void setup_tss32(void) { u16 desc_size = sizeof(tss32_t); - int i; - - for (i = 0; i < 2; i++) { - tss[i].cr3 = read_cr3(); - tss[i].ss0 = tss[i].ss1 = tss[i].ss2 = 0x10; - tss[i].esp = tss[i].esp0 = tss[i].esp1 = tss[i].esp2 = - (u32)tss_stack[i] + 4096; - tss[i].cs = KERNEL_CS; - tss[i].ds = tss[i].es = tss[i].fs = tss[i].gs = - tss[i].ss = KERNEL_DS; - tss[i].iomap_base = (u16)desc_size; - set_gdt_entry(TSS_MAIN + (i << 3), (u32)&tss[i], - desc_size - 1, 0x89, 0x0f); - } - ltr(TSS_MAIN); + tss.cr3 = read_cr3(); + tss_intr.cr3 = read_cr3(); + tss_intr.ss0 = tss_intr.ss1 = tss_intr.ss2 = 0x10; + tss_intr.esp = tss_intr.esp0 = tss_intr.esp1 = tss_intr.esp2 = + (u32)tss_stack + 4096; + tss_intr.cs = 0x08; + tss_intr.ds = tss_intr.es = tss_intr.fs = tss_intr.gs = tss_intr.ss = 0x10; + tss_intr.iomap_base = (u16)desc_size; + set_gdt_entry(TSS_INTR, (u32)&tss_intr, desc_size - 1, 0x89, 0x0f); } void set_intr_task_gate(int e, void *fn) { - tss[1].eip = (u32)fn; + tss_intr.eip = (u32)fn; set_idt_task_gate(e, TSS_INTR); } void print_current_tss_info(void) { u16 tr = str(); - int i = (tr == TSS_MAIN) ? 0 : 1; if (tr != TSS_MAIN && tr != TSS_INTR) printf("Unknown TSS %x\n", tr); else - printf("TR=%x Main TSS back link %x. Current TSS back link %x\n", - tr, tss[0].prev, tss[i].prev); + printf("TR=%x (%s) Main TSS back link %x. Intr TSS back link %x\n", + tr, tr ? "interrupt" : "main", tss.prev, tss_intr.prev); } #endif diff --git a/lib/x86/desc.h b/lib/x86/desc.h index 0614273..e0af335 100644 --- a/lib/x86/desc.h +++ b/lib/x86/desc.h @@ -3,10 +3,8 @@ void setup_idt(void); #ifndef __x86_64__ -void setup_gdt(void); void setup_tss32(void); #else -static inline void setup_gdt(void){} static inline void setup_tss32(void){} #endif @@ -74,9 +72,9 @@ typedef struct { #define KERNEL_CS 0x08 #define KERNEL_DS 0x10 #define NP_SEL 0x18 -#define TSS_MAIN 0x20 -#define TSS_INTR 0x28 -#define FIRST_SPARE_SEL 0x30 +#define TSS_INTR 0x20 +#define FIRST_SPARE_SEL 0x28 +#define TSS_MAIN 0x80 typedef struct { unsigned short offset0; @@ -105,6 +103,11 @@ typedef struct { extern idt_entry_t boot_idt[256]; +#ifndef __x86_64__ +extern gdt_entry_t gdt32[]; +extern tss32_t tss; +#endif + unsigned exception_vector(void); unsigned exception_error_code(void); void set_idt_entry(int vec, void *addr, int dpl); diff --git a/x86/asyncpf.c b/x86/asyncpf.c index 95e7741..5d269f7 100644 --- a/x86/asyncpf.c +++ b/x86/asyncpf.c @@ -89,7 +89,6 @@ int main(int ac, char **av) setup_vm(); setup_idt(); - setup_gdt(); printf("install handler\n"); handle_exception(14, pf_isr); apf_reason = 0; diff --git a/x86/cstart.S b/x86/cstart.S index bc8d563..ffa0768 100644 --- a/x86/cstart.S +++ b/x86/cstart.S @@ -28,10 +28,25 @@ i = 0 i = i + 1 .endr +.globl gdt32 gdt32: .quad 0 .quad 0x00cf9b000000ffff // flat 32-bit code segment .quad 0x00cf93000000ffff // flat 32-bit data segment + .quad 0x00cf1b000000ffff // flat 32-bit code segment, not present + + .quad 0 // 12 spare selectors + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 tss_descr: .rept max_cpus @@ -40,6 +55,7 @@ tss_descr: gdt32_end: i = 0 +.globl tss tss: .rept max_cpus .long 0 diff --git a/x86/eventinj.c b/x86/eventinj.c index a218aaf..900cfda 100644 --- a/x86/eventinj.c +++ b/x86/eventinj.c @@ -183,7 +183,6 @@ int main() setup_vm(); setup_idt(); - setup_gdt(); setup_tss32(); handle_irq(32, tirq0); diff --git a/x86/taskswitch2.c b/x86/taskswitch2.c index de7e969..92fc941 100644 --- a/x86/taskswitch2.c +++ b/x86/taskswitch2.c @@ -252,7 +252,6 @@ int main() { setup_vm(); setup_idt(); - setup_gdt(); setup_tss32(); test_kernel_mode_int(); -- 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