Skip to contentSkip to conversation

Minor cleanup and fix for 32bit test

PATCH Superseded Jason Wang 2 participants 13 messages Aug 24, 2010

Subsystems (2)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore

Jason Wang

author
#0 lore raw

cover Minor cleanup and fix for 32bit test

The following series do some minor cleanup and fix for the 32bit test.

---

Jason Wang (10):
Do not track config.mak and kvmtrace
Remove trailing whitespaces
Makefile cleanup
Correct the path in README
Drop print.S
Remove the duplicated rdmsr/wrmsr
Correct the tss size
Check whether in long mode before testing vmexit caused by cr8 access Do not test IA32_EFER in 32bit mode.
Add the 32bit smp initialization code

 Makefile              |    9 --
 README                |   10 +--
 config-x86-common.mak |   21 +++---
 config.mak            |    8 --
 kvmtrace              |  Bin
 x86/access.c          |    2 -
 x86/cstart.S          |  179 +++++++++++++++++++++++++++++++++++++++++++++++--
 x86/cstart64.S        |    6 +-
 x86/msr.c             |   18 +----
 x86/print.S           |   31 --------
 x86/sieve.c           |    2 -
 x86/vm.c              |    6 +-
 x86/vmexit.c          |   34 ++++-----
 13 files changed, 215 insertions(+), 111 deletions(-)
 delete mode 100644 config.mak
 delete mode 100755 kvmtrace
 delete mode 100644 x86/print.S
Signature · 1 line
Jason Wang
author
#1 lore raw

PATCH 1/10 Do not track config.mak and kvmtrace

config.mak was generated by configure and kvmtrace were compiled throuh makefile.

---
 config.mak |    8 --------
 kvmtrace   |  Bin
 2 files changed, 0 insertions(+), 8 deletions(-)
 delete mode 100644 config.mak
 delete mode 100755 kvmtrace
config.mak deleted +0 -8
deleted file mode 100644
index 333ec7c..0000000
@@ -1,8 +0,0 @@
-PREFIX=/usr/local
-KERNELDIR=/home/avi/kvm/linux-2.6
-ARCH=x86_64
-PROCESSOR=x86_64
-CC=gcc
-LD=ld
-OBJCOPY=objcopy
-AR=ar
kvmtrace deleted binary +0 -0
deleted file mode 100755
index d4610290bd47922b276f6cd3604972b07bb2e07d..0000000000000000000000000000000000000000
GIT binary patch
author
#2 lore raw

PATCH 2/10 Remove trailing whitespaces

In reply to Jason Wang
---
 config-x86-common.mak |   14 +++++++-------
 x86/access.c          |    2 +-
 x86/cstart64.S        |    4 ++--
 x86/print.S           |    6 +++---
 x86/sieve.c           |    2 +-
 x86/vm.c              |    6 +++---
 6 files changed, 17 insertions(+), 17 deletions(-)
config-x86-common.mak +7 -7
index 19bffd4..2d2965f 100644
@@ -32,18 +32,18 @@ tests_and_config = $(TEST_DIR)/*.flat $(TEST_DIR)/unittests.cfg
 test_cases: $(tests-common) $(tests)
 
 $(TEST_DIR)/%.o: CFLAGS += -std=gnu99 -ffreestanding -I lib -I lib/x86
- 
+
 $(TEST_DIR)/access.flat: $(cstart.o) $(TEST_DIR)/access.o $(TEST_DIR)/print.o
- 
+
 $(TEST_DIR)/hypercall.flat: $(cstart.o) $(TEST_DIR)/hypercall.o
- 
+
 $(TEST_DIR)/sieve.flat: $(cstart.o) $(TEST_DIR)/sieve.o \
 		$(TEST_DIR)/vm.o
- 
+
 $(TEST_DIR)/vmexit.flat: $(cstart.o) $(TEST_DIR)/vmexit.o
- 
+
 $(TEST_DIR)/smptest.flat: $(cstart.o) $(TEST_DIR)/smptest.o
- 
+
 $(TEST_DIR)/emulator.flat: $(cstart.o) $(TEST_DIR)/emulator.o \
 			   $(TEST_DIR)/vm.o $(TEST_DIR)/print.o
 
@@ -52,7 +52,7 @@ $(TEST_DIR)/port80.flat: $(cstart.o) $(TEST_DIR)/port80.o
 $(TEST_DIR)/tsc.flat: $(cstart.o) $(TEST_DIR)/tsc.o
 
 $(TEST_DIR)/apic.flat: $(cstart.o) $(TEST_DIR)/apic.o $(TEST_DIR)/vm.o \
-		       $(TEST_DIR)/print.o 
+		       $(TEST_DIR)/print.o
 
 $(TEST_DIR)/realmode.flat: $(TEST_DIR)/realmode.o
 	$(CC) -m32 -nostdlib -o $@ -Wl,-T,$(TEST_DIR)/realmode.lds $^
x86/access.c +1 -1
index a0d88e1..067565b 100644
@@ -157,7 +157,7 @@ static void ac_test_show(ac_test_t *at);
 void lidt(idt_entry_t *idt, int nentries)
 {
     descriptor_table_t dt;
-    
+
     dt.limit = nentries * sizeof(*idt) - 1;
     dt.linear_addr = (unsigned long)idt;
     asm volatile ("lidt %0" : : "m"(dt));
x86/cstart64.S +2 -2
index cc4c80f..5d358ad 100644
@@ -19,7 +19,7 @@ stacktop:
 ring0stacktop:
 
 .data
-		
+
 .align 4096
 ptl2:
 i = 0
@@ -38,7 +38,7 @@ ptl3:
 .align 4096
 ptl4:
 	.quad ptl3 + 7
-	
+
 .align 4096
 
 gdt64_desc:
x86/print.S +3 -3
index c1b1c0d..b445381 100644
@@ -3,12 +3,12 @@
 
 #define PSEUDO_SERIAL_PORT 0xf1
 
-	
+
 .text
 	PRINT "boo"
 	hlt
 1:	jmp 1b
-	
+
 .globl print
 print:
 	push %rax
@@ -24,7 +24,7 @@ putchar:
 	outsb
 	jmp putchar
 done:
-	
+
 	pop %rdx
 	pop %rsi
 	pop %rax
x86/sieve.c +1 -1
index ef4a5a0..6cbcd6d 100644
@@ -46,6 +46,6 @@ int main()
 	test_sieve("virtual", v, VSIZE);
 	vfree(v);
     }
-    
+
     return 0;
 }
x86/vm.c +3 -3
index 62b3ba8..b34449f 100644
@@ -30,7 +30,7 @@ void *alloc_page()
 
     if (!free)
 	return 0;
-    
+
     p = free;
     free = *(void **)free;
 
@@ -184,7 +184,7 @@ void *vmalloc(unsigned long size)
     unsigned pages;
 
     size += sizeof(unsigned long);
-    
+
     size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
     vfree_top -= size;
     mem = p = vfree_top;
@@ -201,7 +201,7 @@ void *vmalloc(unsigned long size)
 void vfree(void *mem)
 {
     unsigned long size = ((unsigned long *)mem)[-1];
-    
+
     while (size) {
 	free_page(phys_to_virt(get_pte(phys_to_virt(read_cr3()), mem) & PTE_ADDR));
 	mem += PAGE_SIZE;
author
#3 lore raw

PATCH 3/10 Makefile cleanup

In reply to Jason Wang

Remove the obsoleted target and directories.

---
 Makefile |    9 +--------
 1 files changed, 1 insertions(+), 8 deletions(-)
Makefile +1 -8
index 5347ce8..d25e6f2 100644
@@ -30,10 +30,6 @@ CFLAGS += -O1
 CFLAGS += $(autodepend-flags) -g -fomit-frame-pointer -Wall
 CFLAGS += $(call cc-option, -fno-stack-protector, "")
 CFLAGS += $(call cc-option, -fno-stack-protector-all, "")
-CFLAGS += -I../include
-CFLAGS += -I ../libkvm
-
-LDFLAGS += $(CFLAGS) -L ../libkvm
 
 CXXFLAGS = $(autodepend-flags)
 
@@ -43,9 +39,6 @@ LDFLAGS += -pthread -lrt
 
 kvmtrace_objs= kvmtrace.o
 
-kvmctl: $(kvmctl_objs)
-	$(CC) $(LDFLAGS) $^ -o $@
-
 kvmtrace: $(kvmtrace_objs)
 	$(CC) $(LDFLAGS) $^ -o $@
 
@@ -62,4 +55,4 @@ install:
 	install $(tests_and_config) $(DESTDIR)
 
 clean: arch_clean
-	$(RM) kvmctl kvmtrace *.o *.a .*.d $(libcflat) $(cflatobjs)
+	$(RM) kvmtrace *.o *.a .*.d $(libcflat) $(cflatobjs)
author
#4 lore raw

PATCH 4/10 Correct the path in README

In reply to Jason Wang
---
 README |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)
README +5 -5
index 6a83831..9c0c518 100644
@@ -7,17 +7,17 @@ Tests uses a qemu's virtual test device, named testdev, for services like printi
 See file testdev.txt for more details.
 
 To create the tests' images just type 'make' in this directory.
-Tests' images created in ./test/<ARCH>/*.flat
+Tests' images created in ./<ARCH>/*.flat
 
 An example of a test invocation:
-qemu-system-x86_64 -device testdev,chardev=testlog -chardev file,id=testlog,path=msr.out -kernel ./test/x86/msr.flat
+qemu-system-x86_64 -device testdev,chardev=testlog -chardev file,id=testlog,path=msr.out -kernel ./x86/msr.flat
 This invocation runs the msr test case. The test output is in file msr.out.
 
 
 
 Directory structure:
 .:  Makefile and config files for the tests
-./test/lib: general services for the tests
-./test/lib/<ARCH>: architecture dependent services for the tests
-./test/<ARCH>: the sources of the tests and the created objects/images
+./lib: general services for the tests
+./lib/<ARCH>: architecture dependent services for the tests
+./<ARCH>: the sources of the tests and the created objects/images
 
author
#5 lore raw

PATCH 5/10 Drop print.S

In reply to Jason Wang

We've already had lib/printf.c.

---
 config-x86-common.mak |    9 ++++-----
 x86/print.S           |   31 -------------------------------
 2 files changed, 4 insertions(+), 36 deletions(-)
 delete mode 100644 x86/print.S
config-x86-common.mak +4 -5
index 2d2965f..a623983 100644
@@ -33,7 +33,7 @@ test_cases: $(tests-common) $(tests)
 
 $(TEST_DIR)/%.o: CFLAGS += -std=gnu99 -ffreestanding -I lib -I lib/x86
 
-$(TEST_DIR)/access.flat: $(cstart.o) $(TEST_DIR)/access.o $(TEST_DIR)/print.o
+$(TEST_DIR)/access.flat: $(cstart.o) $(TEST_DIR)/access.o
 
 $(TEST_DIR)/hypercall.flat: $(cstart.o) $(TEST_DIR)/hypercall.o
 
@@ -45,14 +45,13 @@ $(TEST_DIR)/vmexit.flat: $(cstart.o) $(TEST_DIR)/vmexit.o
 $(TEST_DIR)/smptest.flat: $(cstart.o) $(TEST_DIR)/smptest.o
 
 $(TEST_DIR)/emulator.flat: $(cstart.o) $(TEST_DIR)/emulator.o \
-			   $(TEST_DIR)/vm.o $(TEST_DIR)/print.o
+			   $(TEST_DIR)/vm.o
 
 $(TEST_DIR)/port80.flat: $(cstart.o) $(TEST_DIR)/port80.o
 
 $(TEST_DIR)/tsc.flat: $(cstart.o) $(TEST_DIR)/tsc.o
 
-$(TEST_DIR)/apic.flat: $(cstart.o) $(TEST_DIR)/apic.o $(TEST_DIR)/vm.o \
-		       $(TEST_DIR)/print.o
+$(TEST_DIR)/apic.flat: $(cstart.o) $(TEST_DIR)/apic.o $(TEST_DIR)/vm.o
 
 $(TEST_DIR)/realmode.flat: $(TEST_DIR)/realmode.o
 	$(CC) -m32 -nostdlib -o $@ -Wl,-T,$(TEST_DIR)/realmode.lds $^
@@ -66,7 +65,7 @@ $(TEST_DIR)/idt_test.flat: $(cstart.o) $(TEST_DIR)/idt.o $(TEST_DIR)/idt_test.o
 $(TEST_DIR)/xsave.flat: $(cstart.o) $(TEST_DIR)/idt.o $(TEST_DIR)/xsave.o
 
 $(TEST_DIR)/rmap_chain.flat: $(cstart.o) $(TEST_DIR)/rmap_chain.o \
-			     $(TEST_DIR)/print.o $(TEST_DIR)/vm.o
+			     $(TEST_DIR)/vm.o
 
 $(TEST_DIR)/svm.flat: $(cstart.o) $(TEST_DIR)/vm.o
 
x86/print.S deleted +0 -31
deleted file mode 100644
index b445381..0000000
@@ -1,31 +0,0 @@
-
-#include "print.h"
-
-#define PSEUDO_SERIAL_PORT 0xf1
-
-
-.text
-	PRINT "boo"
-	hlt
-1:	jmp 1b
-
-.globl print
-print:
-	push %rax
-	push %rsi
-	push %rdx
-
-	mov %rdi, %rsi
-	mov $(PSEUDO_SERIAL_PORT), %edx
-
-putchar:
-	cmpb $0, (%rsi)
-	jz done
-	outsb
-	jmp putchar
-done:
-
-	pop %rdx
-	pop %rsi
-	pop %rax
-	ret
author
#6 lore raw

PATCH 6/10 Remove the duplicated rdmsr/wrmsr

In reply to Jason Wang

They have been implemented in lib/x86/processor.h. Also rename the cpuid to cpuid_test because cpuid have been defined.

---
 x86/msr.c    |   16 +---------------
 x86/vmexit.c |   20 +++-----------------
 2 files changed, 4 insertions(+), 32 deletions(-)
x86/msr.c +1 -15
index 1e7987d..9c85369 100644
@@ -1,6 +1,7 @@
 /* msr tests */
 
 #include "libcflat.h"
+#include "processor.h"
 
 struct msr_info {
     int index;
@@ -87,21 +88,6 @@ static void report(const char *name, int passed)
 	printf("%s: %s\n", name, passed ? "PASS" : "FAIL");
 }
 
-static void wrmsr(unsigned index, unsigned long long value)
-{
-	unsigned a = value, d = value >> 32;
-
-	asm volatile("wrmsr" : : "a"(a), "d"(d), "c"(index));
-}
-
-static unsigned long long rdmsr(unsigned index)
-{
-	unsigned a, d;
-
-	asm volatile("rdmsr" : "=a"(a), "=d"(d) : "c"(index));
-	return ((unsigned long long)d << 32) | a;
-}
-
 static void test_msr_rw(int msr_index, unsigned long long input, unsigned long long expected)
 {
     unsigned long long r = 0;
x86/vmexit.c +3 -17
index 707d5c6..819c24b 100644
@@ -1,6 +1,7 @@
 
 #include "libcflat.h"
 #include "smp.h"
+#include "processor.h"
 
 static inline unsigned long long rdtsc()
 {
@@ -32,7 +33,7 @@ static unsigned int inl(unsigned short port)
 #  define R "e"
 #endif
 
-static void cpuid(void)
+static void cpuid_test(void)
 {
 	asm volatile ("push %%"R "bx; cpuid; pop %%"R "bx"
 		      : : : "eax", "ecx", "edx");
@@ -48,21 +49,6 @@ static void vmcall(void)
 #define MSR_EFER 0xc0000080
 #define EFER_NX_MASK            (1ull << 11)
 
-unsigned long long rdmsr(unsigned index)
-{
-	unsigned a, d;
-
-	asm volatile("rdmsr" : "=a"(a), "=d"(d) : "c"(index));
-	return ((unsigned long long)d << 32) | a;
-}
-
-void wrmsr(unsigned index, unsigned long long val)
-{
-	unsigned a = val, d = val >> 32;
-
-	asm volatile("wrmsr" : : "a"(a), "d"(d), "c"(index));
-}
-
 static void mov_from_cr8(void)
 {
 	unsigned long cr8;
@@ -112,7 +98,7 @@ static struct test {
 	int (*valid)(void);
 	int parallel;
 } tests[] = {
-	{ cpuid, "cpuid", .parallel = 1,  },
+	{ cpuid_test, "cpuid", .parallel = 1,  },
 	{ vmcall, "vmcall", .parallel = 1, },
 	{ mov_from_cr8, "mov_from_cr8", .parallel = 1, },
 	{ mov_to_cr8, "mov_to_cr8" , .parallel = 1, },
author
#7 lore raw

PATCH 7/10 Correct the tss size

In reply to Jason Wang

TSS size should be 104 byte.

---
 x86/cstart64.S |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
x86/cstart64.S +1 -1
index 5d358ad..b871153 100644
@@ -69,7 +69,7 @@ tss:
 	.long 0
 	.quad ring0stacktop - i * 4096
 	.quad 0, 0, 0
-	.quad 0, 0, 0, 0, 0, 0, 0, 0
+	.quad 0, 0, 0, 0, 0, 0, 0
 	.long 0, 0, 0
 i = i + 1
 	.endr
#8 lore raw

Re: [PATCH kvm-unit-tests 07/10] Correct the tss size

Quoted 12 lines · Jason Wang

TSS size should be 104 byte.

---
  x86/cstart64.S |    2 +-
  1 files changed, 1 insertions(+), 1 deletions(-)
x86/cstart64.S +0 -0
index 5d358ad..b871153 100644

x86/cstart64.S tss: · line 70

Quoted 2 lines
x86/cstart64.S +0 -0
@@ -69,7 +69,7 @@ tss:
  	.long 0
  	.quad ring0stacktop - i * 4096

ring 0 stack

x86/cstart64.S tss: · line 71

Quoted 1 line
x86/cstart64.S +0 -0
  	.quad 0, 0, 0

rings 1, 2, 3 stack

x86/cstart64.S tss: · line 72

Quoted 1 line
x86/cstart64.S +0 -1
-	.quad 0, 0, 0, 0, 0, 0, 0, 0

1 qword reserved, 7 qwords IST

x86/cstart64.S tss: · line 73

Quoted 2 lines
x86/cstart64.S +1 -0
+	.quad 0, 0, 0, 0, 0, 0, 0
  	.long 0, 0, 0

3 dwords reserved + I/O map base address - so this looks correct?

Quoted 3 lines
x86/cstart64.S +0 -0
  i = i + 1
  	.endr
Signature · 1 line
error compiling committee.c: too many arguments to function
author
#9 lore raw

PATCH 8/10 Check whether in long mode before testing vmexit caused by cr8 access

In reply to Jason Wang

CR8 is only availabe when in long mode.

---
 x86/vmexit.c |   14 ++++++++++++--
 1 files changed, 12 insertions(+), 2 deletions(-)
x86/vmexit.c +12 -2
index 819c24b..34b0af4 100644
@@ -48,6 +48,7 @@ static void vmcall(void)
 
 #define MSR_EFER 0xc0000080
 #define EFER_NX_MASK            (1ull << 11)
+#define EFER_LMA_MASK           (1ull << 10)
 
 static void mov_from_cr8(void)
 {
@@ -68,6 +69,15 @@ static int is_smp(void)
 	return cpu_count() > 1;
 }
 
+static int is_long_mode(void)
+{
+#ifdef __i386__
+        return 0;
+#else
+        return rdmsr(MSR_EFER) | EFER_LMA_MASK;
+#endif
+}
+
 static void nop(void *junk)
 {
 }
@@ -100,8 +110,8 @@ static struct test {
 } tests[] = {
 	{ cpuid_test, "cpuid", .parallel = 1,  },
 	{ vmcall, "vmcall", .parallel = 1, },
-	{ mov_from_cr8, "mov_from_cr8", .parallel = 1, },
-	{ mov_to_cr8, "mov_to_cr8" , .parallel = 1, },
+	{ mov_from_cr8, "mov_from_cr8", is_long_mode, .parallel = 1, },
+	{ mov_to_cr8, "mov_to_cr8" , is_long_mode, .parallel = 1, },
 	{ inl_pmtimer, "inl_from_pmtimer", .parallel = 1, },
 	{ ipi, "ipi", is_smp, .parallel = 0, },
 	{ ipi_halt, "ipi+halt", is_smp, .parallel = 0, },
#10 lore raw

Re: [PATCH kvm-unit-tests 08/10] Check whether in long mode before testing vmexit caused by cr8 access

Quoted 36 lines · Jason Wang

CR8 is only availabe when in long mode.

---
  x86/vmexit.c |   14 ++++++++++++--
  1 files changed, 12 insertions(+), 2 deletions(-)
x86/vmexit.c +10 -0
index 819c24b..34b0af4 100644
@@ -48,6 +48,7 @@ static void vmcall(void)
 
  #define MSR_EFER 0xc0000080
  #define EFER_NX_MASK            (1ull<<  11)
+#define EFER_LMA_MASK           (1ull<<  10)
 
  static void mov_from_cr8(void)
  {
@@ -68,6 +69,15 @@ static int is_smp(void)
  	return cpu_count()>  1;
  }
 
+static int is_long_mode(void)
+{
+#ifdef __i386__
+        return 0;
+#else
+        return rdmsr(MSR_EFER) | EFER_LMA_MASK;
+#endif
+}
+
  static void nop(void *junk)
  {
  }

x86/vmexit.c static struct test { · line 117

Quoted 10 lines
x86/vmexit.c +2 -2
@@ -100,8 +110,8 @@ static struct test {
  } tests[] = {
  	{ cpuid_test, "cpuid", .parallel = 1,  },
  	{ vmcall, "vmcall", .parallel = 1, },
-	{ mov_from_cr8, "mov_from_cr8", .parallel = 1, },
-	{ mov_to_cr8, "mov_to_cr8" , .parallel = 1, },
+	{ mov_from_cr8, "mov_from_cr8", is_long_mode, .parallel = 1, },
+	{ mov_to_cr8, "mov_to_cr8" , is_long_mode, .parallel = 1, },
  	{ inl_pmtimer, "inl_from_pmtimer", .parallel = 1, },
  	{ ipi, "ipi", is_smp, .parallel = 0, },
  	{ ipi_halt, "ipi+halt", is_smp, .parallel = 0, },

Enough to #ifdef __x86_64__. If it's defined we're in long mode.

Signature · 1 line
error compiling committee.c: too many arguments to function
author
#11 lore raw

PATCH 9/10 Do not test IA32_EFER in 32bit mode.

In reply to Jason Wang
---
 x86/msr.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
x86/msr.c +2 -0
index 9c85369..c3e0014 100644
@@ -49,9 +49,11 @@ struct msr_info msr_info[] =
     { .index = 0xc0000102, .name = "MSR_KERNEL_GS_BASE",
       .val_pairs = {{ .valid = 1, .value = addr_64, .expected = addr_64}}
     },
+#ifdef __x86_64__
     { .index = 0xc0000080, .name = "MSR_EFER",
       .val_pairs = {{ .valid = 1, .value = 0xD00, .expected = 0xD00}}
     },
+#endif
     { .index = 0xc0000082, .name = "MSR_LSTAR",
       .val_pairs = {{ .valid = 1, .value = addr_64, .expected = addr_64}}
     },
author
#12 lore raw

PATCH 10/10 Add the 32bit smp initialization code

In reply to Jason Wang

Add the smp initlaization codes for 32bit. This would make the 32bit smp tests available.

---
 x86/cstart.S |  179 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 173 insertions(+), 6 deletions(-)
x86/cstart.S +173 -6
index 1bdf789..6ce200d 100644
@@ -1,9 +1,65 @@
 
+#include "apic-defs.h"
+
+.globl boot_idt
+boot_idt = 0
+
+ipi_vector = 0x20
+
+max_cpus = 4
 
 .bss
 
+	. = . + 4096 * max_cpus
+	.align 16
+stacktop:
+
+	. = . + 4096
+	.align 16
+ring0stacktop:
+
+.data
+
+.align 4096
+pt:
+i = 0
+        .rept 1024
+        .long 0x1e7 | (i << 22)
+        i = i + 1
+        .endr
+
+gdt32:
+	.quad 0
+	.quad 0x00cf9b000000ffff // flat 32-bit code segment
+	.quad 0x00cf93000000ffff // flat 32-bit data segment
+
+tss_descr:
+        .rept max_cpus
+        .quad 0x000089000000ffff // 32-bit avail tss
+        .endr
+gdt32_end:
+
+i = 0
+tss:
+        .rept max_cpus
+        .long 0
+        .long ring0stacktop - i * 4096
+        .long 0
+        .quad 0, 0, 0
+        .quad 0, 0, 0, 0, 0, 0, 0
+        .long 0, 0, 0
+        i = i + 1
+        .endr
+tss_end:
+
+idt_descr:
+	.word 16 * 256 - 1
+	.long boot_idt
+
 .section .init
 
+.code32
+
 mb_magic = 0x1BADB002
 mb_flags = 0x0
 
@@ -11,15 +67,126 @@ mb_flags = 0x0
 	.long mb_magic, mb_flags, 0 - (mb_magic + mb_flags)
 mb_cmdline = 16
 
+MSR_GS_BASE = 0xc0000101
+
+.macro setup_percpu_area
+	lea -4096(%esp), %eax
+	mov $0, %edx
+	mov $MSR_GS_BASE, %ecx
+	wrmsr
+.endm
+
 .globl start
 start:
-	mov mb_cmdline(%ebx), %eax
-	mov %eax, __args
-	call __setup_args
-	pushl $__argv
-	pushl __argc
-	call main
+        mov mb_cmdline(%ebx), %eax
+        mov %eax, __args
+        call __setup_args
+        mov $stacktop, %esp
+        setup_percpu_area
+        call prepare_32
+        jmpl $8, $start32
+
+prepare_32:
+        lgdtl gdt32_descr
+
+	mov %cr4, %eax
+	bts $4, %eax  // pse
+	mov %eax, %cr4
+
+	mov $pt, %eax
+	mov %eax, %cr3
+
+	mov %cr0, %eax
+	bts $0, %eax
+	bts $31, %eax
+	mov %eax, %cr0
+	ret
+
+smp_stacktop:	.long 0xa0000
+
+ap_start32:
+	mov $0x10, %ax
+	mov %ax, %ds
+	mov %ax, %es
+	mov %ax, %fs
+	mov %ax, %gs
+	mov %ax, %ss
+	mov $-4096, %esp
+	lock/xaddl %esp, smp_stacktop
+	setup_percpu_area
+	call prepare_32
+	call load_tss
+	call enable_apic
+	call enable_x2apic
+	sti
+	nop
+	lock incw cpu_online_count
+
+1:	hlt
+	jmp 1b
+
+start32:
+	call load_tss
+	call mask_pic_interrupts
+	call enable_apic
+	call smp_init
+	call enable_x2apic
+        push $__argv
+        push __argc
+        call main
 	push %eax
 	call exit
 
+load_tss:
+	lidt idt_descr
+	mov $16, %eax
+	mov %ax, %ss
+	mov $(APIC_DEFAULT_PHYS_BASE + APIC_ID), %eax
+	mov (%eax), %eax
+	shr $24, %eax
+	mov %eax, %ebx
+	shl $3, %ebx
+	mov $((tss_end - tss) / max_cpus), %edx
+	imul %edx
+	add $tss, %eax
+	mov %ax, tss_descr+2(%ebx)
+	shr $16, %eax
+	mov %al, tss_descr+4(%ebx)
+	shr $8, %eax
+	mov %al, tss_descr+7(%ebx)
+	lea tss_descr-gdt32(%ebx), %eax
+	ltr %ax
+	ret
+
+smp_init:
+	cld
+	lea sipi_entry, %esi
+	xor %edi, %edi
+	mov $(sipi_end - sipi_entry), %ecx
+	rep/movsb
+	mov $APIC_DEFAULT_PHYS_BASE, %eax
+	movl $(APIC_DEST_ALLBUT | APIC_DEST_PHYSICAL | APIC_DM_INIT | APIC_INT_ASSERT), APIC_ICR(%eax)
+	movl $(APIC_DEST_ALLBUT | APIC_DEST_PHYSICAL | APIC_DM_INIT), APIC_ICR(%eax)
+	movl $(APIC_DEST_ALLBUT | APIC_DEST_PHYSICAL | APIC_DM_STARTUP), APIC_ICR(%eax)
+	call fwcfg_get_nb_cpus
+1:	pause
+	cmpw %ax, cpu_online_count
+	jne 1b
+smp_init_done:
+	ret
+
+cpu_online_count:	.word 1
+
+.code16
+sipi_entry:
+	mov %cr0, %eax
+	or $1, %eax
+	mov %eax, %cr0
+	lgdtl gdt32_descr - sipi_entry
+	ljmpl $8, $ap_start32
+
+gdt32_descr:
+	.word gdt32_end - gdt32 - 1
+	.long gdt32
 
+sipi_end: