[PATCH kvm-unit-tests 05/18] x86: desc: reuse cstart.S GDT and TSS

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux