public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
From: jyoung5-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org
To: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
Cc: kvm-ppc-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
Subject: [PATCH 2 of 2] Move all x86 specific tests to there own directory
Date: Tue, 23 Oct 2007 22:26:40 -0500	[thread overview]
Message-ID: <1335122fbf8be195a699.1193196400@thinkpad> (raw)
In-Reply-To: <patchbomb.1193196398@thinkpad>

# HG changeset patch
# User Jerone Young <jyoung5-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
# Date 1193196215 18000
# Node ID 1335122fbf8be195a699377c4f86c9ef143bce77
# Parent  d6b11d52fe56b21349f5e38c9105026dcf5926b2
Move all x86 specific tests to there own directory.

Signed-off-by: Jerone Young <jyoung5-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>

diff --git a/user/Makefile b/user/Makefile
--- a/user/Makefile
+++ b/user/Makefile
@@ -2,6 +2,8 @@ include config.mak
 include config.mak
 
 DESTDIR :=
+
+.PHONY: arch_clean clean
 
 #make sure env CFLAGS variable is not used
 CFLAGS =
@@ -15,15 +17,22 @@ cc-option = $(shell if $(CC) $(1) -S -o 
 cc-option = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \
               > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
 
-CFLAGS += $(autodepend-flags) -g -fomit-frame-pointer -Wall 
+CFLAGS += $(autodepend-flags) -g -fomit-frame-pointer -Wall
 CFLAGS += $(call cc-option, -fno-stack-protector, "")
 CFLAGS += $(call cc-option, -fno-stack-protector-all, "")
 
 LDFLAGS += $(CFLAGS)
 
-CXXFLAGS = $(autodepend-flags) 
+CXXFLAGS = $(autodepend-flags)
 
 autodepend-flags = -MMD -MF $(dir $*).$(notdir $*).d
+
+kvmctl: LDFLAGS += -pthread -lrt
+
+kvmctl: $(kvmctl_objs)
+
+libkvm.a: $(libkvm_objs)
+	$(AR) rcs $@ $^
 
 install:
 	install -D kvmctl.h $(DESTDIR)/$(PREFIX)/include/kvmctl.h
@@ -36,29 +45,10 @@ install:
 %.flat: %.o
 	$(CC) $(CFLAGS) -nostdlib -o $@ -Wl,-T,flat.lds $^
 
-test/bootstrap: test/bootstrap.o
-	$(CC) -nostdlib -o $@ -Wl,-T,bootstrap.lds $^
-
 %.o: %.S
 	$(CC) $(CFLAGS) -c -nostdlib -o $@ $^
 
-test/irq.flat: test/print.o
-
-test/access.flat: $(cstart.o) test/access.o test/printf.o test/print.o \
-	test/smp.o
-
-test/sieve.flat: $(cstart.o) test/sieve.o test/print.o test/vm.o
-
-test/vmexit.flat: $(cstart.o) test/vmexit.o test/printf.o test/smp.o
-
-test/test32.flat: test/test32.o
-
-test/smp.flat: $(cstart.o) test/smp.o test/printf.o test/smptest.o
-
-test/%.o: CFLAGS += -std=gnu99 -ffreestanding
-
 -include .*.d
 
-clean:
+clean: arch_clean
 	$(RM) kvmctl *.o *.a .*.d
-	$(RM) test/bootstrap test/*.o test/*.flat test/.*.d
diff --git a/user/config-i386.mak b/user/config-i386.mak
--- a/user/config-i386.mak
+++ b/user/config-i386.mak
@@ -1,11 +1,12 @@ LIBDIR = /lib
 LIBDIR = /lib
-cstart.o = test/cstart.o
+TEST_DIR=test/x86
+cstart.o = $(TEST_DIR)/cstart.o
 bits = 32
 ldarch = elf32-i386
 CFLAGS += -m32
 CFLAGS += -D__i386__
 CFLAGS += -I $(KERNELDIR)/include
 
-flatfile_tests=
+tests=
 
 include config-x86-common.mak
diff --git a/user/config-x86-common.mak b/user/config-x86-common.mak
--- a/user/config-x86-common.mak
+++ b/user/config-x86-common.mak
@@ -1,16 +1,40 @@
 #This is a make file with common rules for both x86 & x86-64
 
-all: kvmctl libkvm.a flatfiles
+all: kvmctl libkvm.a test_cases
 
-kvmctl: LDFLAGS += -pthread -lrt
+kvmctl_objs=kvmctl.o main.o
 
-kvmctl: kvmctl.o main.o
-
-libkvm.a: kvmctl.o
-	$(AR) rcs $@ $^
+libkvm_objs=kvmctl.o
 
 balloon_ctl: balloon_ctl.o
 
-flatfiles_tests-common = test/bootstrap test/vmexit.flat test/smp.flat
+tests-common = $(TEST_DIR)/bootstrap \
+			$(TEST_DIR)/vmexit.flat \
+			$(TEST_DIR)/smp.flat
 
-flatfiles: $(flatfiles_tests-common) $(flatfile_tests))
+test_cases: $(tests-common) $(tests)
+
+$(TEST_DIR)/%.o: CFLAGS += -std=gnu99 -ffreestanding
+ 
+$(TEST_DIR)/bootstrap: $(TEST_DIR)/bootstrap.o
+	$(CC) -nostdlib -o $@ -Wl,-T,bootstrap.lds $^
+ 
+$(TEST_DIR)/irq.flat: $(TEST_DIR)/test/print.o
+ 
+$(TEST_DIR)/access.flat: $(cstart.o) $(TEST_DIR)/access.o \
+	$(TEST_DIR)/printf.o $(TEST_DIR)/print.o $(TEST_DIR)/smp.o
+ 
+$(TEST_DIR)/sieve.flat: $(cstart.o) $(TEST_DIR)/sieve.o \
+		$(TEST_DIR)/print.o $(TEST_DIR)/vm.o
+ 
+$(TEST_DIR)/vmexit.flat: $(cstart.o) $(TEST_DIR)/vmexit.o \
+	$(TEST_DIR)/printf.o $(TEST_DIR)/smp.o
+ 
+$(TEST_DIR)/test32.flat: $(TEST_DIR)/test32.o
+
+$(TEST_DIR)/smp.flat: $(cstart.o) $(TEST_DIR)/smp.o $(TEST_DIR)/printf.o \
+			$(TEST_DIR)/smptest.o
+ 
+arch_clean:
+	$(RM) $(TEST_DIR)/bootstrap $(TEST_DIR)/*.o $(TEST_DIR)/*.flat \
+	$(TEST_DIR)/.*.d
diff --git a/user/config-x86_64.mak b/user/config-x86_64.mak
--- a/user/config-x86_64.mak
+++ b/user/config-x86_64.mak
@@ -1,11 +1,12 @@ LIBDIR = /lib64
 LIBDIR = /lib64
-cstart.o = test/cstart64.o
+TEST_DIR=test/x86
+cstart.o = $(TEST_DIR)/cstart64.o
 bits = 64
 ldarch = elf64-x86-64
 CFLAGS += -m64
 CFLAGS += -D__x86_64__
 CFLAGS += -I $(KERNELDIR)/include
 
-flatfile_tests = test/access.flat test/irq.flat test/sieve.flat test/simple.flat test/stringio.flat test/memtest1.flat
+tests = test/access.flat test/irq.flat test/sieve.flat test/simple.flat test/stringio.flat test/memtest1.flat
 
 include config-x86-common.mak
diff --git a/user/main.c b/user/main.c
--- a/user/main.c
+++ b/user/main.c
@@ -17,7 +17,7 @@
 #define _GNU_SOURCE
 
 #include "kvmctl.h"
-#include "test/apic.h"
+#include "test/x86/apic.h"
 
 #include <stdio.h>
 #include <unistd.h>
diff --git a/user/test/access.c b/user/test/access.c
deleted file mode 100644
--- a/user/test/access.c
+++ /dev/null
@@ -1,367 +0,0 @@
-
-#include "smp.h"
-#include "printf.h"
-
-typedef unsigned long pt_element_t;
-
-#define PAGE_SIZE ((pt_element_t)4096)
-#define PAGE_MASK (~(PAGE_SIZE-1))
-
-#define PT_BASE_ADDR_MASK ((pt_element_t)((((pt_element_t)1 << 40) - 1) & PAGE_MASK))
-
-#define PT_PRESENT_MASK    ((pt_element_t)1 << 0)
-#define PT_WRITABLE_MASK   ((pt_element_t)1 << 1)
-#define PT_USER_MASK       ((pt_element_t)1 << 2)
-#define PT_ACCESSED_MASK   ((pt_element_t)1 << 5)
-#define PT_DIRTY_MASK      ((pt_element_t)1 << 6)
-
-#define CR0_WP_MASK (1UL << 16)
-
-#define PFERR_PRESENT_MASK (1U << 0)
-#define PFERR_WRITE_MASK (1U << 1)
-#define PFERR_USER_MASK (1U << 2)
-
-/*
- * page table access check tests
- */
-
-enum {
-    AC_PTE_PRESENT,
-    AC_PTE_WRITABLE,
-    AC_PTE_USER,
-    AC_PTE_ACCESSED,
-    AC_PTE_DIRTY,
-    // AC_PTE_NX,
-
-    AC_ACCESS_USER,
-    AC_ACCESS_WRITE,
-    // AC_ACCESS_FETCH,
-    // AC_ACCESS_PTE,
-
-    // AC_CPU_EFER_NX,
-    AC_CPU_CR0_WP,
-
-    NR_AC_FLAGS
-};
-
-const char *ac_names[] = {
-    [AC_PTE_PRESENT] = "pte.p",
-    [AC_PTE_ACCESSED] = "pte.a",
-    [AC_PTE_WRITABLE] = "pte.rw",
-    [AC_PTE_USER] = "pte.user",
-    [AC_PTE_DIRTY] = "pte.d",
-    [AC_ACCESS_WRITE] = "write",
-    [AC_ACCESS_USER] = "user",
-    [AC_CPU_CR0_WP] = "cr0.wp",
-};
-
-static inline void *va(pt_element_t phys)
-{
-    return (void *)phys;
-}
-
-static unsigned long read_cr0()
-{
-    unsigned long cr0;
-
-    asm volatile ("mov %%cr0, %0" : "=r"(cr0));
-
-    return cr0;
-}
-
-static void write_cr0(unsigned long cr0)
-{
-    asm volatile ("mov %0, %%cr0" : : "r"(cr0));
-}
-
-typedef struct {
-    unsigned short offset0;
-    unsigned short selector;
-    unsigned short ist : 3;
-    unsigned short : 5;
-    unsigned short type : 4;
-    unsigned short : 1;
-    unsigned short dpl : 2;
-    unsigned short p : 1;
-    unsigned short offset1;
-    unsigned offset2;
-    unsigned reserved;
-} idt_entry_t;
-
-typedef struct {
-    unsigned flags[NR_AC_FLAGS];
-    void *virt;
-    pt_element_t phys;
-    pt_element_t pt_pool;
-    pt_element_t *ptep;
-    pt_element_t expected_pte;
-    int expected_fault;
-    unsigned expected_error;
-    idt_entry_t idt[256];
-} ac_test_t;
-
-typedef struct {
-    unsigned short limit;
-    unsigned long linear_addr;
-} __attribute__((packed)) descriptor_table_t;
-
-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));
-}
-
-void memset(void *a, unsigned char v, int n)
-{
-    unsigned char *x = a;
-
-    while (n--)
-	*x++ = v;
-}
-
-unsigned short read_cs()
-{
-    unsigned short r;
-
-    asm volatile ("mov %%cs, %0" : "=r"(r));
-}
-
-void set_idt_entry(idt_entry_t *e, void *addr, int dpl)
-{
-    memset(e, 0, sizeof *e);
-    e->offset0 = (unsigned long)addr;
-    e->selector = read_cs();
-    e->ist = 0;
-    e->type = 14;
-    e->dpl = dpl;
-    e->p = 1;
-    e->offset1 = (unsigned long)addr >> 16;
-    e->offset2 = (unsigned long)addr >> 32;
-}
-
-void set_cr0_wp(int wp)
-{
-    unsigned long cr0 = read_cr0();
-
-    cr0 &= ~CR0_WP_MASK;
-    if (wp)
-	cr0 |= CR0_WP_MASK;
-    write_cr0(cr0);
-}
-
-void ac_test_init(ac_test_t *at)
-{
-    set_cr0_wp(1);
-    for (int i = 0; i < NR_AC_FLAGS; ++i)
-	at->flags[i] = 0;
-    at->virt = (void *)(0x123400000000 + 16 * smp_id());
-    at->phys = 32 * 1024 * 1024;
-    at->pt_pool = 33 * 1024 * 1024;
-    memset(at->idt, 0, sizeof at->idt);
-    lidt(at->idt, 256);
-    extern char page_fault, kernel_entry;
-    set_idt_entry(&at->idt[14], &page_fault, 0);
-    set_idt_entry(&at->idt[0x20], &kernel_entry, 3);
-}
-
-int ac_test_bump(ac_test_t *at)
-{
-    for (int i = 0; i < NR_AC_FLAGS; ++i)
-	if (!at->flags[i]) {
-	    at->flags[i] = 1;
-	    return 1;
-	} else
-	    at->flags[i] = 0;
-    return 0;
-}
-
-unsigned long read_cr3()
-{
-    unsigned long cr3;
-
-    asm volatile ("mov %%cr3, %0" : "=r"(cr3));
-    return cr3;
-}
-
-void invlpg(void *addr)
-{
-    asm volatile ("invlpg (%0)" : : "r"(addr));
-}
-
-pt_element_t ac_test_alloc_pt(ac_test_t *at)
-{
-    pt_element_t ret = at->pt_pool;
-    at->pt_pool += PAGE_SIZE;
-    return ret;
-}
-
-void ac_test_setup_pte(ac_test_t *at)
-{
-    unsigned long root = read_cr3();
-
-    for (int i = 4; i >= 1; --i) {
-	pt_element_t *vroot = va(root & PT_BASE_ADDR_MASK);
-	unsigned index = ((unsigned long)at->virt >> (12 + (i-1) * 9)) & 511;
-	pt_element_t pte;
-	if (i != 1) {
-	    pte = vroot[index];
-	    if (!(pte & PT_PRESENT_MASK))
-		pte = ac_test_alloc_pt(at) | PT_PRESENT_MASK;
-	    pte |= PT_WRITABLE_MASK | PT_USER_MASK;
-	} else {
-	    pte = at->phys & PT_BASE_ADDR_MASK;
-	    if (at->flags[AC_PTE_PRESENT])
-		pte |= PT_PRESENT_MASK;
-	    if (at->flags[AC_PTE_WRITABLE])
-		pte |= PT_WRITABLE_MASK;
-	    if (at->flags[AC_PTE_USER])
-		pte |= PT_USER_MASK;
-	    if (at->flags[AC_PTE_ACCESSED])
-		pte |= PT_ACCESSED_MASK;
-	    if (at->flags[AC_PTE_DIRTY])
-		pte |= PT_DIRTY_MASK;
-	    at->ptep = &vroot[index];
-	}
-	vroot[index] = pte;
-	root = vroot[index];
-    }
-    invlpg(at->virt);
-    at->expected_pte = *at->ptep;
-    at->expected_fault = 0;
-    at->expected_error = 0;
-    if (!at->flags[AC_PTE_PRESENT])
-	at->expected_fault = 1;
-    else
-	at->expected_error |= PFERR_PRESENT_MASK;
-
-    if (at->flags[AC_ACCESS_USER]) {
-	at->expected_error |= PFERR_USER_MASK;
-	if (!at->flags[AC_PTE_USER])
-	    at->expected_fault = 1;
-    }
-
-    if (at->flags[AC_ACCESS_WRITE]) {
-	at->expected_error |= PFERR_WRITE_MASK;
-	if (!at->flags[AC_PTE_WRITABLE]
-	    && (at->flags[AC_CPU_CR0_WP] || at->flags[AC_ACCESS_USER])) {
-	    at->expected_fault = 1;
-	} else if (!at->expected_fault) {
-	    at->expected_pte |= PT_DIRTY_MASK;
-	}
-    }
-
-    if (!at->expected_fault) {
-	at->expected_pte |= PT_ACCESSED_MASK;
-    }
-}
-
-int ac_test_do_access(ac_test_t *at)
-{
-    static unsigned unique = 42;
-    int fault = 0;
-    unsigned e;
-    static unsigned char user_stack[4096];
-    unsigned long rsp;
-
-    ++unique;
-
-    unsigned r = unique;
-    set_cr0_wp(at->flags[AC_CPU_CR0_WP]);
-    asm volatile ("mov %%rsp, %%rdx \n\t"
-		  "cmp $0, %[user] \n\t"
-		  "jz do_access \n\t"
-		  "push %%rax; mov %[user_ds], %%ax; mov %%ax, %%ds; pop %%rax  \n\t"
-		  "pushq %[user_ds] \n\t"
-		  "pushq %[user_stack_top] \n\t"
-		  "pushfq \n\t"
-		  "pushq %[user_cs] \n\t"
-		  "pushq $do_access \n\t"
-		  "iretq \n"
-		  "do_access: \n\t"
-		  "cmp $0, %[write] \n\t"
-		  "jnz 1f \n\t"
-		  "mov (%[addr]), %[reg] \n\t"
-		  "jmp done \n\t"
-		  "1: mov %[reg], (%[addr]) \n\t"
-		  "done: \n"
-		  "fixed1: \n"
-		  "int %[kernel_entry_vector] \n\t"
-		  "back_to_kernel:"
-		  : [reg]"+r"(r), "+a"(fault), "=b"(e), "=&d"(rsp)
-		  : [addr]"r"(at->virt),
-		    [write]"r"(at->flags[AC_ACCESS_WRITE]),
-		    [user]"r"(at->flags[AC_ACCESS_USER]),
-		    [user_ds]"i"(32+3),
-		    [user_cs]"i"(24+3),
-		    [user_stack_top]"r"(user_stack + sizeof user_stack),
-		    [kernel_entry_vector]"i"(0x20));
-
-    asm volatile (".section .text.pf \n\t"
-		  "page_fault: \n\t"
-		  "pop %rbx \n\t"
-		  "movq $fixed1, (%rsp) \n\t"
-		  "movl $1, %eax \n\t"
-		  "iretq \n\t"
-		  ".section .text");
-
-    asm volatile (".section .text.entry \n\t"
-		  "kernel_entry: \n\t"
-		  "mov %rdx, %rsp \n\t"
-		  "jmp back_to_kernel \n\t"
-		  ".section .text");
-
-    if (fault && !at->expected_fault) {
-	printf("unexpected fault\n");
-	return 0;
-    }
-    if (!fault && at->expected_fault) {
-	printf("unexpected access\n");
-	return 0;
-    }
-    if (fault && e != at->expected_error) {
-	printf("error code %x expected %x\n", e, at->expected_fault);
-	return 0;
-    }
-    if (*at->ptep != at->expected_pte) {
-	printf("pte %x expected %x\n", *at->ptep, at->expected_pte);
-	return 0;
-    }
-
-    printf("OK\n");
-    return 1;
-}
-
-void ac_test_exec(ac_test_t *at)
-{
-    int r;
-
-    printf("test");
-    for (int i = 0; i < NR_AC_FLAGS; ++i)
-	if (at->flags[i])
-	    printf(" %s", ac_names[i]);
-    printf(": ");
-    ac_test_setup_pte(at);
-    r = ac_test_do_access(at);
-}
-
-void ac_test_run()
-{
-    static ac_test_t at;
-
-    printf("run\n");
-    ac_test_init(&at);
-    do {
-	ac_test_exec(&at);
-    } while (ac_test_bump(&at));
-}
-
-int main()
-{
-    printf("starting test\n\n");
-    smp_init(ac_test_run);
-    ac_test_run();
-    return 0;
-}
diff --git a/user/test/apic.h b/user/test/apic.h
deleted file mode 100644
--- a/user/test/apic.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef SILLY_APIC_H
-#define SILLY_APIC_H
-
-#define APIC_BASE 0x1000
-#define APIC_SIZE 0x100
-
-#define APIC_REG_NCPU        0x00
-#define APIC_REG_ID          0x04
-#define APIC_REG_SIPI_ADDR   0x08
-#define APIC_REG_SEND_SIPI   0x0c
-#define APIC_REG_IPI_VECTOR  0x10
-#define APIC_REG_SEND_IPI    0x14
-
-#endif
diff --git a/user/test/bootstrap.S b/user/test/bootstrap.S
deleted file mode 100644
--- a/user/test/bootstrap.S
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * minimal bootstrap to set up flat 32-bit protected mode
- */
-
-#include "apic.h"
-	
-bstart = 0xf0000
-	
-.code16
-
-stack_top = 0x1000
-cpu_up = 0x1000
-cpu_up_pmode = 0x1004
-
-pmode_stack_start = 0x10000
-pmode_stack_shift = 16
-pmode_stack_size = (1 << pmode_stack_shift)
-
-ipi_vec = 0xf0
-	
-start:
-	mov $stack_top, %sp
-	call smp_init
-
-	cs lidtl idt_desc
-	cs lgdtl gdt_desc
-	mov %cr0, %eax
-	or $1, %eax
-	mov %eax, %cr0
-	ljmpl $8, $pmode + bstart
-
-smp_init:
-	mov $ipi_vec, %eax
-	mov $(APIC_BASE + APIC_REG_IPI_VECTOR), %dx
-	out %eax, %dx
-	movw $ap_switch_to_pmode, ipi_vec*4
-	movw %cs, %ax
-	mov %ax, ipi_vec*4+2
-	mov $sipi, %eax
-	mov $(APIC_BASE + APIC_REG_SIPI_ADDR), %dx
-	outl %eax, %dx
-	mov $(APIC_BASE + APIC_REG_NCPU), %dx
-	inl %dx, %eax
-	mov %eax, %ecx
-	mov $1, %esi
-smp_loop:
-	cmp %esi, %ecx
-	jbe smp_done
-	mov %esi, %eax
-	mov $(APIC_BASE + APIC_REG_SEND_SIPI), %dx
-	outl %eax, %dx
-wait_for_cpu:
-	cmp cpu_up, %esi
-	jne wait_for_cpu
-	mov %esi, %eax
-	mov $(APIC_BASE + APIC_REG_SEND_IPI), %dx
-	out %eax, %dx
-wait_for_cpu_pmode:
-	cmp cpu_up_pmode, %esi
-	jne wait_for_cpu_pmode
-	
-	inc %esi
-	jmp smp_loop
-smp_done:
-	ret
-
-sipi:
-	mov $(APIC_BASE + APIC_REG_ID), %dx
-	inl %dx, %eax
-	mov %eax, cpu_up
-	shl $12, %eax
-	addl $stack_top, %eax
-	movl %eax, %esp
-	sti
-	nop
-1:	hlt
-	jmp 1b
-
-ap_switch_to_pmode:
-	cs lidtl idt_desc
-	cs lgdtl gdt_desc
-	mov %cr0, %eax
-	or $1, %eax
-	mov %eax, %cr0
-	ljmpl $8, $ap_pmode + bstart
-
-.code32	
-ap_pmode:
-	mov $0x10, %ax
-	mov %ax, %ds
-	mov %ax, %es
-	mov %ax, %fs
-	mov %ax, %gs
-	mov %ax, %ss
-	mov $(APIC_BASE + APIC_REG_ID), %dx
-	in %dx, %eax
-	mov %eax, cpu_up_pmode
-	shl $pmode_stack_shift, %eax
-	lea pmode_stack_start + pmode_stack_size(%eax), %esp
-	sti
-	nop
-ap_pmode_wait:
-	hlt
-	jmp ap_pmode_wait
-
-pmode:
-	mov $0x10, %ax
-	mov %ax, %ds
-	mov %ax, %es
-	mov %ax, %fs
-	mov %ax, %gs
-	mov %ax, %ss
-	mov $pmode_stack_start + pmode_stack_size, %esp
-	ljmp $8, $0x100000
-
-.align 16
-	
-idt_desc:
-	.word 8*256-1
-	.long 0
-
-gdt_desc:
-	.word gdt_end - gdt - 1
-	.long gdt + bstart
-
-.align 16
-
-gdt:
-	.quad 0
-	.quad 0x00cf9b000000ffff // flat 32-bit code segment
-	.quad 0x00cf93000000ffff // flat 32-bit data segment
-gdt_end:
-	
-. = 0xfff0
-	.code16
-	ljmp $0xf000, $start
-.align 65536
diff --git a/user/test/cstart.S b/user/test/cstart.S
deleted file mode 100644
--- a/user/test/cstart.S
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-.bss
-
-.section .init
-	call main
-1:	hlt
-	jmp 1b
-
-
diff --git a/user/test/cstart64.S b/user/test/cstart64.S
deleted file mode 100644
--- a/user/test/cstart64.S
+++ /dev/null
@@ -1,169 +0,0 @@
-
-#include "apic.h"
-
-boot_idt = 0
-
-ipi_vector = 0x20
-
-max_cpus = 4
-
-.bss
-
-	. = . + 4096 * max_cpus
-	.align 16
-stacktop:
-
-	. = . + 4096
-	.align 16
-ring0stacktop:
-
-.data
-		
-.align 4096
-ptl2:
-i = 0
-	.rept 512
-	.quad 0x1e7 | (i << 21)
-	i = i + 1
-	.endr
-
-.align 4096
-ptl3:
-	.quad ptl2 + 7
-
-.align 4096
-ptl4:
-	.quad ptl3 + 7
-	
-.align 4096
-
-gdt64_desc:
-	.word gdt64_end - gdt64 - 1
-	.quad gdt64
-
-gdt64:
-	.quad 0
-	.quad 0x00af9b000000ffff // 64-bit code segment
-	.quad 0x00cf93000000ffff // 64-bit data segment
-	.quad 0x00affb000000ffff // 64-bit code segment (user)
-	.quad 0x00cff3000000ffff // 64-bit data segment (user)
-tss_descr:
-	.rept max_cpus
-	.quad 0x000089000000ffff // 64-bit avail tss
-	.quad 0                  // tss high addr
-	.endr
-gdt64_end:
-
-i = 0
-tss:
-	.rept max_cpus
-	.long 0
-	.quad ring0stacktop - i * 4096
-	.quad 0, 0, 0
-	.quad 0, 0, 0, 0, 0, 0, 0, 0
-	.long 0, 0, 0
-i = i + 1
-	.endr
-tss_end:
-
-.section .init
-
-.code32
-	call prepare_64
-	jmpl $8, $start64
-
-prepare_64:
-	lgdt gdt64_desc
-
-	mov %cr4, %eax
-	bts $5, %eax  // pae
-	mov %eax, %cr4
-
-	mov $ptl4, %eax
-	mov %eax, %cr3
-
-efer = 0xc0000080
-	mov $efer, %ecx
-	rdmsr
-	bts $8, %eax
-	wrmsr
-
-	mov %cr0, %eax
-	bts $0, %eax
-	bts $31, %eax
-	mov %eax, %cr0
-	ret
-
-
-smp_init_ipi:
-	call prepare_64
-	jmpl $8, $ap_start64
-
-.code64
-ap_start64:
-	call load_tss
-	sti
-	nop
-
-1:	hlt
-	jmp 1b
-
-start64:
-	call load_tss
-	call smp_init
-	call main
-
-1:	hlt
-	jmp 1b
-
-load_tss:
-	mov $0, %eax
-	mov %ax, %ss
-	mov $(APIC_BASE + APIC_REG_ID), %dx
-	in %dx, %eax
-	mov %eax, %ebx
-	shl $4, %ebx
-	mov $((tss_end - tss) / max_cpus), %edx
-	imul %edx
-	add $tss, %rax
-	mov %ax, tss_descr+2(%rbx)
-	shr $16, %rax
-	mov %al, tss_descr+4(%rbx)
-	shr $8, %rax
-	mov %al, tss_descr+7(%rbx)
-	shr $8, %rax
-	mov %eax, tss_descr+8(%rbx)
-	lea tss_descr-gdt64(%rbx), %rax
-	ltr %ax
-	ret
-
-smp_init:
-	lea boot_idt + ipi_vector * 8, %rdi
-	mov $smp_init_ipi, %eax
-	mov %ax, (%rdi)
-	mov %cs, %ax
-	mov %ax, 2(%rdi)
-	movw $0x8e00, 4(%rdi)
-	shr $16, %eax
-	mov %ax, 6(%rdi)
-
-	mov $(APIC_BASE + APIC_REG_IPI_VECTOR), %dx
-	mov $ipi_vector, %eax
-	out %eax, %dx
-
-	mov $(APIC_BASE + APIC_REG_NCPU), %dx
-	in %dx, %eax
-	mov %eax, %ecx
-	mov $1, %esi
-smp_loop:
-	cmp %esi, %ecx
-	je smp_init_done
-
-	mov $(APIC_BASE + APIC_REG_SEND_IPI), %dx
-	mov %esi, %eax
-	out %eax, %dx
-
-	inc %esi
-	jmp smp_loop
-smp_init_done:
-	ret
diff --git a/user/test/irq.S b/user/test/irq.S
deleted file mode 100644
--- a/user/test/irq.S
+++ /dev/null
@@ -1,118 +0,0 @@
-// irq test program.  assumes outb $irq, $0xff generates an interrupt $irq.
-
-#include "print.h"
-	
-.text
-	PRINT "irq test"
-	mov $stack_top, %rsp
-
-	call setup_gdt
-	
-	mov %ds, %ax
-	mov %ax, %ds  // check ds descriptor is okay
-
-	mov $irq_handler, %rdx
-	mov $0x20, %eax
-	call setup_idt_entry
-
-	lidt idt_descriptor
-
-	PRINT "software interrupt"
-	int $0x20
-
-	sti
-	nop
-
-	PRINT "injecting interrupt with interrupts enabled"
-	
-	mov $0x20, %al
-	outb %al, $0xff // inject interrupt
-
-	nop
-	nop
-	nop
-	PRINT "after injection"
-
-	cli
-
-	PRINT "injecting interrupt with interrupts disabled"
-	
-	mov $0x20, %al
-	outb %al, $0xff // inject interrupt
-
-	// no interrupt here (disabled)
-	nop
-	nop
-	PRINT "enabling interrupts"
-	nop
-	nop
-	sti
-	out %al, $0x80 // blocked by sti
-	// interrupt here
-	out %al, $0x80 
-
-	PRINT "after injection"
-	nop
-	nop
-	
-	hlt
-	
-irq_handler:
-	PRINT "interrupt handler"
-	iretq
-	
-setup_idt_entry:	// %rax: irq %rdx: handler
-	shl $4, %rax
-	mov %dx, idt(%rax)
-	shr $16, %rdx
-	mov %cs, 2+idt(%rax)
-	mov %dx, 6+idt(%rax)
-	shr $16, %rdx
-	mov %edx, 8+idt(%rax)
-	movw $0x8e00, 4+idt(%rax)
-	ret
-
-setup_gdt:
-	mov $0, %eax
-	mov %cs, %ax
-	andl $~7, %eax
-	movl $0xffff, gdt(%rax)
-	movl $0xaf9b00, 4+gdt(%rax)
-
-	mov $0, %eax
-	mov %ds, %ax
-	andl $~7, %eax
-	movl $0xffff, gdt(%rax)
-	movl $0x8f9300, 4+gdt(%rax)
-
-	lgdt gdt_descriptor
-	ret
-	
-.data
-	
-.align 16
-
-idt:	
-	. = . + 256 * 16
-
-idt_descriptor:
-	.word . - idt - 1
-	.quad idt
-
-.align 8
-	
-gdt:
-	. = . + 256 * 8
-
-gdt_descriptor:
-	.word . - gdt - 1
-	.quad gdt 
-
-	
-.align 4096
-stack_base:
-	. = . + 4096
-stack_top:
-	
-
-
diff --git a/user/test/memtest1.S b/user/test/memtest1.S
deleted file mode 100644
--- a/user/test/memtest1.S
+++ /dev/null
@@ -1,44 +0,0 @@
-.text
-	
-start:
-	mov    $0x1000,%r8
-	mov    $0x0a,%ecx
-
-init_page:
-	dec    %ecx
-	jne    no_io
-	mov    $0x0,%al
-	out    %al,$0x80
-	mov    $0x0a,%ecx
-
-no_io:
-	mov    %r8,(%r8)
-	add    $0x1000,%r8
-	cmp    $0x8000000,%r8
-	jne    init_page
-	mov    $0x1000,%r8
-	mov    $0x0a,%ecx
-
-test_loop:
-	dec    %ecx
-	jne    no_io2
-	mov    $0x0,%al
-	out    %al,$0x80
-	mov    $0x0a,%ecx
-
-no_io2:
-	mov    (%r8),%r9
-	cmp    %r8,%r9
-	jne    err
-	add    $0x1000,%r8
-	cmp    $0x8000000,%r8
-	jne    test_loop
-	mov    $0x1000,%r8
-	jmp    test_loop
-
-err:
-	mov    $0xffffffffffffffff,%r12
-	mov    $0xffffffffffffffff,%r13
-	mov    $0x0,%al
-	out    %al,$0x80
-	jmp    err
diff --git a/user/test/print.S b/user/test/print.S
deleted file mode 100644
--- a/user/test/print.S
+++ /dev/null
@@ -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
diff --git a/user/test/print.h b/user/test/print.h
deleted file mode 100644
--- a/user/test/print.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef PRINT_H
-#define PRINT_H
-
-.macro PRINT text
-
-.data
-
-333: .asciz "\text\n"
-
-.previous
-
-	push %rdi
-	lea 333b, %rdi
-	call print
-	pop %rdi
-
-.endm
-
-#endif
diff --git a/user/test/printf.c b/user/test/printf.c
deleted file mode 100644
--- a/user/test/printf.c
+++ /dev/null
@@ -1,169 +0,0 @@
-#include "printf.h"
-#include "smp.h"
-#include <stdarg.h>
-
-static struct spinlock lock;
-
-void print(const char *s);
-
-typedef struct pstream {
-    char *buffer;
-    int remain;
-    int added;
-} pstream_t;
-
-static void addchar(pstream_t *p, char c)
-{
-    if (p->remain) {
-	*p->buffer++ = c;
-	--p->remain;
-    }
-    ++p->added;
-}
-
-void print_str(pstream_t *p, const char *s)
-{
-    while (*s)
-	addchar(p, *s++);
-}
-
-static char digits[16] = "0123456789abcdef";
-
-void print_int(pstream_t *ps, long n, int base)
-{
-    char buf[sizeof(long) * 3 + 2], *p = buf;
-    int s = 0, i;
-    
-    if (n < 0) {
-	n = -n;
-	s = 1;
-    }
-
-    while (n) {
-	*p++ = digits[n % base];
-	n /= base;
-    }
-    
-    if (s)
-	*p++ = '-';
-
-    if (p == buf)
-	*p++ = '0';
-    
-    for (i = 0; i < (p - buf) / 2; ++i) {
-	char tmp;
-
-	tmp = buf[i];
-	buf[i] = p[-1-i];
-	p[-1-i] = tmp;
-    }
-
-    *p = 0;
-
-    print_str(ps, buf);
-}
-
-void print_unsigned(pstream_t *ps, unsigned long n, int base)
-{
-    char buf[sizeof(long) * 3 + 1], *p = buf;
-    int i;
-    
-    while (n) {
-	*p++ = digits[n % base];
-	n /= base;
-    }
-    
-    if (p == buf)
-	*p++ = '0';
-    
-    for (i = 0; i < (p - buf) / 2; ++i) {
-	char tmp;
-
-	tmp = buf[i];
-	buf[i] = p[-1-i];
-	p[-1-i] = tmp;
-    }
-
-    *p = 0;
-
-    print_str(ps, buf);
-}
-
-int vsnprintf(char *buf, int size, const char *fmt, va_list va)
-{
-    int n;
-    pstream_t s;
-
-    s.buffer = buf;
-    s.remain = size - 1;
-    s.added = 0;
-    while (*fmt) {
-	char f = *fmt++;
-
-	if (f != '%') {
-	    addchar(&s, f);
-	    continue;
-	}
-	f = *fmt++;
-	switch (f) {
-	case '%':
-	    addchar(&s, '%');
-	    break;
-	case '\0':
-	    --fmt;
-	    break;
-	case 'd':
-	    print_int(&s, va_arg(va, int), 10);
-	    break;
-	case 'x':
-	    print_unsigned(&s, va_arg(va, int), 16);
-	    break;
-	case 'p':
-	    print_str(&s, "0x");
-	    print_unsigned(&s, (unsigned long)va_arg(va, void *), 16);
-	    break;
-	case 's':
-	    print_str(&s, va_arg(va, const char *));
-	    break;
-	default:
-	    addchar(&s, f);
-	    break;
-	}
-    }
-    *s.buffer = 0;
-    ++s.added;
-    return s.added;
-}
-
-
-int snprintf(char *buf, int size, const char *fmt, ...)
-{
-    va_list va;
-    int r;
-
-    va_start(va, fmt);
-    r = vsnprintf(buf, size, fmt, va);
-    va_end(va);
-    return r;
-}
-
-void print_serial(const char *buf)
-{
-    while (*buf)
-	asm volatile ("out %%al, $0xf1" : : "a"(*buf++));
-}
-
-int printf(const char *fmt, ...)
-{
-    va_list va;
-    char buf[2000];
-    int r;
-
-    va_start(va, fmt);
-    r = vsnprintf(buf, sizeof buf, fmt, va);
-    va_end(va);
-    spin_lock(&lock);
-    print_serial(buf);
-    spin_unlock(&lock);
-    return r;
-}
diff --git a/user/test/printf.h b/user/test/printf.h
deleted file mode 100644
--- a/user/test/printf.h
+++ /dev/null
@@ -1,2 +0,0 @@
-
-int printf(const char *fmt, ...);
diff --git a/user/test/sieve.c b/user/test/sieve.c
deleted file mode 100644
--- a/user/test/sieve.c
+++ /dev/null
@@ -1,89 +0,0 @@
-#include "vm.h"
-
-void print(const char *text);
-
-void printi(int n)
-{
-    char buf[10], *p = buf;
-    int s = 0, i;
-    
-    if (n < 0) {
-	n = -n;
-	s = 1;
-    }
-
-    while (n) {
-	*p++ = '0' + n % 10;
-	n /= 10;
-    }
-    
-    if (s)
-	*p++ = '-';
-
-    if (p == buf)
-	*p++ = '0';
-    
-    for (i = 0; i < (p - buf) / 2; ++i) {
-	char tmp;
-
-	tmp = buf[i];
-	buf[i] = p[-1-i];
-	p[-1-i] = tmp;
-    }
-
-    *p = 0;
-
-    print(buf);
-}
-
-int sieve(char* data, int size)
-{
-    int i, j, r = 0;
-
-    for (i = 0; i < size; ++i)
-	data[i] = 1;
-
-    data[0] = data[1] = 0;
-
-    for (i = 2; i < size; ++i)
-	if (data[i]) {
-	    ++r;
-	    for (j = i*2; j < size; j += i)
-		data[j] = 0;
-	}
-    return r;
-}
-
-void test_sieve(const char *msg, char *data, int size)
-{
-    int r;
-
-    print(msg);
-    print(": ");
-    r = sieve(data, size);
-    printi(r);
-    print("\n");
-}
-
-#define STATIC_SIZE 1000000
-#define VSIZE 100000000
-char static_data[STATIC_SIZE];
-
-int main()
-{
-    void *v;
-    int i;
-
-    print("starting sieve\n");
-    test_sieve("static", static_data, STATIC_SIZE);
-    setup_vm();
-    print("mapped: ");
-    test_sieve("mapped", static_data, STATIC_SIZE);
-    for (i = 0; i < 30; ++i) {
-	v = vmalloc(VSIZE);
-	test_sieve("virtual", v, VSIZE);
-	vfree(v);
-    }
-    
-    return 0;
-}
diff --git a/user/test/simple.S b/user/test/simple.S
deleted file mode 100644
--- a/user/test/simple.S
+++ /dev/null
@@ -1,13 +0,0 @@
-
-	.text
-
-	mov $0, %al
-	mov $10000, %ebx
-1:
-	mov %rbx, %rcx
-2:	
-	loop 2b
-	out %al, $0x80
-	inc %al
-	add $10000, %rbx
-	jmp 1b
diff --git a/user/test/smp.c b/user/test/smp.c
deleted file mode 100644
--- a/user/test/smp.c
+++ /dev/null
@@ -1,151 +0,0 @@
-
-
-#include "smp.h"
-#include "apic.h"
-#include "printf.h"
-
-#define IPI_VECTOR 0x20
-
-static int apic_read(int reg)
-{
-    unsigned short port = APIC_BASE + reg;
-    unsigned v;
-
-    asm volatile ("in %1, %0" : "=a"(v) : "d"(port));
-    return v;
-}
-
-static void apic_write(int reg, unsigned v)
-{
-    unsigned short port = APIC_BASE + reg;
-
-    asm volatile ("out %0, %1" : : "a"(v), "d"(port));
-}
-
-static int apic_get_cpu_count()
-{
-    return apic_read(APIC_REG_NCPU);
-}
-
-static int apic_get_id()
-{
-    return apic_read(APIC_REG_ID);
-}
-
-static void apic_set_ipi_vector(int vector)
-{
-    apic_write(APIC_REG_IPI_VECTOR, vector);
-}
-
-static void apic_send_ipi(int cpu)
-{
-    apic_write(APIC_REG_SEND_IPI, cpu);
-}
-
-static struct spinlock ipi_lock;
-static void (*ipi_function)(void *data);
-static void *ipi_data;
-static volatile int ipi_done;
-
-static __attribute__((used)) void ipi()
-{
-    ipi_function(ipi_data);
-    ipi_done = 1;
-}
-
-asm (
-     "ipi_entry: \n"
-     "   call ipi \n"
-#ifndef __x86_64__
-     "   iret"
-#else
-     "   iretq"
-#endif
-     );
-
-
-static void set_ipi_descriptor(void (*ipi_entry)(void))
-{
-    unsigned short *desc = (void *)(IPI_VECTOR * sizeof(long) * 2);
-    unsigned short cs;
-    unsigned long ipi = (unsigned long)ipi_entry;
-
-    asm ("mov %%cs, %0" : "=r"(cs));
-    desc[0] = ipi;
-    desc[1] = cs;
-    desc[2] = 0x8e00;
-    desc[3] = ipi >> 16;
-#ifdef __x86_64__
-    desc[4] = ipi >> 32;
-    desc[5] = ipi >> 48;
-    desc[6] = 0;
-    desc[7] = 0;
-#endif
-}
-
-void spin_lock(struct spinlock *lock)
-{
-    int v = 1;
-
-    do {
-	asm volatile ("xchg %1, %0" : "+m"(lock->v), "+r"(v));
-    } while (v);
-    asm volatile ("" : : : "memory");
-}
-
-void spin_unlock(struct spinlock *lock)
-{
-    asm volatile ("" : : : "memory");
-    lock->v = 0;
-}
-
-int cpu_count(void)
-{
-    return apic_get_cpu_count();
-}
-
-int smp_id(void)
-{
-    return apic_get_id();
-}
-
-void on_cpu(int cpu, void (*function)(void *data), void *data)
-{
-    spin_lock(&ipi_lock);
-    if (cpu == apic_get_id())
-	function(data);
-    else {
-	ipi_function = function;
-	ipi_data = data;
-	apic_send_ipi(cpu);
-	while (!ipi_done)
-	    ;
-	ipi_done = 0;
-    }
-    spin_unlock(&ipi_lock);
-}
-
-static void (*smp_main_func)(void);
-static volatile int smp_main_running;
-
-asm ("smp_init_entry: \n"
-     "incl smp_main_running \n"
-     "sti \n"
-     "call *smp_main_func");
-
-void smp_init(void (*smp_main)(void))
-{
-    int i;
-    void smp_init_entry(void);
-    void ipi_entry(void);
-
-    apic_set_ipi_vector(IPI_VECTOR);
-    set_ipi_descriptor(smp_init_entry);
-    smp_main_func = smp_main;
-    for (i = 1; i < cpu_count(); ++i) {
-	apic_send_ipi(i);
-	while (smp_main_running < i)
-	    ;
-    }
-    set_ipi_descriptor(ipi_entry);
-}
diff --git a/user/test/smp.h b/user/test/smp.h
deleted file mode 100644
--- a/user/test/smp.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef __SMP_H
-#define __SMP_H
-
-struct spinlock {
-    int v;
-};
-
-void smp_init(void (*smp_main)(void));
-
-int cpu_count(void);
-int smp_id(void);
-void on_cpu(int cpu, void (*function)(void *data), void *data);
-void spin_lock(struct spinlock *lock);
-void spin_unlock(struct spinlock *lock);
-
-#endif
diff --git a/user/test/smptest.c b/user/test/smptest.c
deleted file mode 100644
--- a/user/test/smptest.c
+++ /dev/null
@@ -1,32 +0,0 @@
-
-#include "smp.h"
-#include "printf.h"
-
-static void ipi_test(void *data)
-{
-    int n = (long)data;
-
-    printf("ipi called, cpu %d\n", n);
-    if (n != smp_id())
-	printf("but wrong cpu %d\n", smp_id());
-}
-
-static void smp_main(void)
-{
-    printf("smp main %d\n", smp_id());
-    while (1)
-	asm volatile ("hlt" : : : "memory");
-}
-
-int main()
-{
-    int ncpus;
-    int i;
-
-    smp_init(smp_main);
-    ncpus = cpu_count();
-    printf("found %d cpus\n", ncpus);
-    for (i = 0; i < ncpus; ++i)
-	on_cpu(i, ipi_test, (void *)(long)i);
-    return 0;
-}
diff --git a/user/test/stringio.S b/user/test/stringio.S
deleted file mode 100644
--- a/user/test/stringio.S
+++ /dev/null
@@ -1,31 +0,0 @@
-
-.data
-
-.macro str name, value
-
-\name :	.long 1f-2f
-2:	.ascii "\value"
-1:	
-.endm	
-
-	str "forward", "forward"
-	str "backward", "backward"
-		
-.text
-
-
-	cld
-	movl forward, %ecx
-	lea  4+forward, %rsi
-	movw $1, %dx
-	rep outsb
-
-	std
-	movl backward, %ecx
-	lea 4+backward-1(%rcx), %rsi
-	movw $2, %dx
-	rep outsb
-	
-	hlt
-
-
diff --git a/user/test/test32.S b/user/test/test32.S
deleted file mode 100644
--- a/user/test/test32.S
+++ /dev/null
@@ -1,8 +0,0 @@
-.code32
-
-.text
-
-1:
-	mov $0x12, %al
-	out %al, $0x80
-	jmp 1b
diff --git a/user/test/vm.c b/user/test/vm.c
deleted file mode 100644
--- a/user/test/vm.c
+++ /dev/null
@@ -1,249 +0,0 @@
-
-#include "vm.h"
-
-void print(const char *s);
-
-#define PAGE_SIZE 4096ul
-#define LARGE_PAGE_SIZE (512 * PAGE_SIZE)
-
-static void *free = 0;
-static void *vfree_top = 0;
-
-static unsigned long virt_to_phys(const void *virt) 
-{ 
-    return (unsigned long)virt;
-}
-
-static void *phys_to_virt(unsigned long phys)
-{
-    return (void *)phys;
-}
-
-void *memset(void *data, int c, unsigned long len)
-{
-    char *s = data;
-
-    while (len--)
-	*s++ = c;
-
-    return data;
-}
-
-static void free_memory(void *mem, unsigned long size)
-{
-    while (size >= PAGE_SIZE) {
-	*(void **)mem = free;
-	free = mem;
-	mem += PAGE_SIZE;
-	size -= PAGE_SIZE;
-    }
-}
-
-void *alloc_page()
-{
-    void *p;
-
-    if (!free)
-	return 0;
-    
-    p = free;
-    free = *(void **)free;
-
-    return p;
-}
-
-void free_page(void *page)
-{
-    *(void **)page = free;
-    free = page;
-}
-
-extern char edata;
-static unsigned long end_of_memory;
-
-#define PTE_PRESENT (1ull << 0)
-#define PTE_PSE     (1ull << 7)
-#define PTE_WRITE   (1ull << 1)
-#define PTE_ADDR    (0xffffffffff000ull)
-
-static void install_pte(unsigned long *cr3, 
-			int pte_level, 
-			void *virt,
-			unsigned long pte)
-{
-    int level;
-    unsigned long *pt = cr3;
-    unsigned offset;
-
-    for (level = 4; level > pte_level; --level) {
-	offset = ((unsigned long)virt >> ((level-1) * 9 + 12)) & 511;
-	if (!(pt[offset] & PTE_PRESENT)) {
-	    unsigned long *new_pt = alloc_page();
-	    memset(new_pt, 0, PAGE_SIZE);
-	    pt[offset] = virt_to_phys(new_pt) | PTE_PRESENT | PTE_WRITE;
-	}
-	pt = phys_to_virt(pt[offset] & 0xffffffffff000ull);
-    }
-    offset = ((unsigned long)virt >> (((level-1) * 9) + 12)) & 511;
-    pt[offset] = pte;
-}
-
-static unsigned long get_pte(unsigned long *cr3, void *virt)
-{
-    int level;
-    unsigned long *pt = cr3, pte;
-    unsigned offset;
-
-    for (level = 4; level > 1; --level) {
-	offset = ((unsigned long)virt >> (((level-1) * 9) + 12)) & 511;
-	pte = pt[offset];
-	if (!(pte & PTE_PRESENT))
-	    return 0;
-	if (level == 2 && (pte & PTE_PSE))
-	    return pte;
-	pt = phys_to_virt(pte & 0xffffffffff000ull);
-    }
-    offset = ((unsigned long)virt >> (((level-1) * 9) + 12)) & 511;
-    pte = pt[offset];
-    return pte;
-}
-
-static void install_large_page(unsigned long *cr3, 
-			       unsigned long phys,
-			       void *virt)
-{
-    install_pte(cr3, 2, virt, phys | PTE_PRESENT | PTE_WRITE | PTE_PSE);
-}
-
-static void install_page(unsigned long *cr3, 
-			 unsigned long phys,
-			 void *virt)
-{
-    install_pte(cr3, 1, virt, phys | PTE_PRESENT | PTE_WRITE);
-}
-
-static inline void load_cr3(unsigned long cr3)
-{
-    asm ( "mov %0, %%cr3" : : "r"(cr3) );
-}
-
-static inline unsigned long read_cr3()
-{
-    unsigned long cr3;
-
-    asm volatile ( "mov %%cr3, %0" : "=r"(cr3) );
-    return cr3;
-}
-
-static inline void load_cr0(unsigned long cr0)
-{
-    asm volatile ( "mov %0, %%cr0" : : "r"(cr0) );
-}
-
-static inline unsigned long read_cr0()
-{
-    unsigned long cr0;
-
-    asm volatile ( "mov %%cr0, %0" : "=r"(cr0) );
-    return cr0;
-}
-
-static inline void load_cr4(unsigned long cr4)
-{
-    asm volatile ( "mov %0, %%cr4" : : "r"(cr4) );
-}
-
-static inline unsigned long read_cr4()
-{
-    unsigned long cr4;
-
-    asm volatile ( "mov %%cr4, %0" : "=r"(cr4) );
-    return cr4;
-}
-
-struct gdt_table_descr
-{
-    unsigned short len;
-    unsigned long *table;
-} __attribute__((packed));
-
-static inline void load_gdt(unsigned long *table, int nent)
-{
-    struct gdt_table_descr descr;
-
-    descr.len = nent * 8 - 1;
-    descr.table = table;
-    asm volatile ( "lgdt %0" : : "m"(descr) );
-}
-
-#define SEG_CS_32 8
-#define SEG_CS_64 16
-
-struct ljmp {
-    void *ofs;
-    unsigned short seg;
-};
-
-static void setup_mmu(unsigned long len)
-{
-    unsigned long *cr3 = alloc_page();
-    unsigned long phys = 0;
-
-    memset(cr3, 0, PAGE_SIZE);
-    while (phys + LARGE_PAGE_SIZE <= len) {
-	install_large_page(cr3, phys, (void *)phys);
-	phys += LARGE_PAGE_SIZE;
-    }
-    while (phys + PAGE_SIZE <= len) {
-	install_page(cr3, phys, (void *)phys);
-	phys += PAGE_SIZE;
-    }
-    
-    load_cr3(virt_to_phys(cr3));
-    print("paging enabled\n");
-}
-
-static unsigned int inl(unsigned short port)
-{
-    unsigned int val;
-    asm volatile("inl %w1, %0" : "=a"(val) : "Nd"(port));
-    return val;
-}
-
-void setup_vm()
-{
-    end_of_memory = inl(0xd1);
-    free_memory(&edata, end_of_memory - (unsigned long)&edata);
-    setup_mmu(end_of_memory);
-}
-
-void *vmalloc(unsigned long size)
-{
-    void *mem, *p;
-    unsigned pages;
-
-    size += sizeof(unsigned long);
-    
-    size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
-    vfree_top -= size;
-    mem = p = vfree_top;
-    pages = size / PAGE_SIZE;
-    while (pages--) {
-	install_page(phys_to_virt(read_cr3()), virt_to_phys(alloc_page()), p);
-	p += PAGE_SIZE;
-    }
-    *(unsigned long *)mem = size;
-    mem += sizeof(unsigned long);
-    return mem;
-}
-
-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;
-	size -= PAGE_SIZE;
-    }
-}
diff --git a/user/test/vm.h b/user/test/vm.h
deleted file mode 100644
--- a/user/test/vm.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef VM_H
-#define VM_H
-
-void setup_vm();
-
-void *vmalloc(unsigned long size);
-void vfree(void *mem);
-
-#endif
diff --git a/user/test/vmexit.c b/user/test/vmexit.c
deleted file mode 100644
--- a/user/test/vmexit.c
+++ /dev/null
@@ -1,32 +0,0 @@
-
-#include "printf.h"
-
-static inline unsigned long long rdtsc()
-{
-	long long r;
-
-#ifdef __x86_64__
-	unsigned a, d;
-
-	asm volatile ("rdtsc" : "=a"(a), "=d"(d));
-	r = a | ((long long)d << 32);
-#else
-	asm volatile ("rdtsc" : "=A"(r));
-#endif
-	return r;
-}
-
-#define N (1 << 22)
-
-int main()
-{
-	int i;
-	unsigned long long t1, t2;
-
-	t1 = rdtsc();
-	for (i = 0; i < N; ++i)
-		asm volatile ("cpuid" : : : "eax", "ebx", "ecx", "edx");
-	t2 = rdtsc();
-	printf("vmexit latency: %d\n", (int)((t2 - t1) / N));
-	return 0;
-}
diff --git a/user/test/x86/access.c b/user/test/x86/access.c
new file mode 100644
--- /dev/null
+++ b/user/test/x86/access.c
@@ -0,0 +1,367 @@
+
+#include "smp.h"
+#include "printf.h"
+
+typedef unsigned long pt_element_t;
+
+#define PAGE_SIZE ((pt_element_t)4096)
+#define PAGE_MASK (~(PAGE_SIZE-1))
+
+#define PT_BASE_ADDR_MASK ((pt_element_t)((((pt_element_t)1 << 40) - 1) & PAGE_MASK))
+
+#define PT_PRESENT_MASK    ((pt_element_t)1 << 0)
+#define PT_WRITABLE_MASK   ((pt_element_t)1 << 1)
+#define PT_USER_MASK       ((pt_element_t)1 << 2)
+#define PT_ACCESSED_MASK   ((pt_element_t)1 << 5)
+#define PT_DIRTY_MASK      ((pt_element_t)1 << 6)
+
+#define CR0_WP_MASK (1UL << 16)
+
+#define PFERR_PRESENT_MASK (1U << 0)
+#define PFERR_WRITE_MASK (1U << 1)
+#define PFERR_USER_MASK (1U << 2)
+
+/*
+ * page table access check tests
+ */
+
+enum {
+    AC_PTE_PRESENT,
+    AC_PTE_WRITABLE,
+    AC_PTE_USER,
+    AC_PTE_ACCESSED,
+    AC_PTE_DIRTY,
+    // AC_PTE_NX,
+
+    AC_ACCESS_USER,
+    AC_ACCESS_WRITE,
+    // AC_ACCESS_FETCH,
+    // AC_ACCESS_PTE,
+
+    // AC_CPU_EFER_NX,
+    AC_CPU_CR0_WP,
+
+    NR_AC_FLAGS
+};
+
+const char *ac_names[] = {
+    [AC_PTE_PRESENT] = "pte.p",
+    [AC_PTE_ACCESSED] = "pte.a",
+    [AC_PTE_WRITABLE] = "pte.rw",
+    [AC_PTE_USER] = "pte.user",
+    [AC_PTE_DIRTY] = "pte.d",
+    [AC_ACCESS_WRITE] = "write",
+    [AC_ACCESS_USER] = "user",
+    [AC_CPU_CR0_WP] = "cr0.wp",
+};
+
+static inline void *va(pt_element_t phys)
+{
+    return (void *)phys;
+}
+
+static unsigned long read_cr0()
+{
+    unsigned long cr0;
+
+    asm volatile ("mov %%cr0, %0" : "=r"(cr0));
+
+    return cr0;
+}
+
+static void write_cr0(unsigned long cr0)
+{
+    asm volatile ("mov %0, %%cr0" : : "r"(cr0));
+}
+
+typedef struct {
+    unsigned short offset0;
+    unsigned short selector;
+    unsigned short ist : 3;
+    unsigned short : 5;
+    unsigned short type : 4;
+    unsigned short : 1;
+    unsigned short dpl : 2;
+    unsigned short p : 1;
+    unsigned short offset1;
+    unsigned offset2;
+    unsigned reserved;
+} idt_entry_t;
+
+typedef struct {
+    unsigned flags[NR_AC_FLAGS];
+    void *virt;
+    pt_element_t phys;
+    pt_element_t pt_pool;
+    pt_element_t *ptep;
+    pt_element_t expected_pte;
+    int expected_fault;
+    unsigned expected_error;
+    idt_entry_t idt[256];
+} ac_test_t;
+
+typedef struct {
+    unsigned short limit;
+    unsigned long linear_addr;
+} __attribute__((packed)) descriptor_table_t;
+
+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));
+}
+
+void memset(void *a, unsigned char v, int n)
+{
+    unsigned char *x = a;
+
+    while (n--)
+	*x++ = v;
+}
+
+unsigned short read_cs()
+{
+    unsigned short r;
+
+    asm volatile ("mov %%cs, %0" : "=r"(r));
+}
+
+void set_idt_entry(idt_entry_t *e, void *addr, int dpl)
+{
+    memset(e, 0, sizeof *e);
+    e->offset0 = (unsigned long)addr;
+    e->selector = read_cs();
+    e->ist = 0;
+    e->type = 14;
+    e->dpl = dpl;
+    e->p = 1;
+    e->offset1 = (unsigned long)addr >> 16;
+    e->offset2 = (unsigned long)addr >> 32;
+}
+
+void set_cr0_wp(int wp)
+{
+    unsigned long cr0 = read_cr0();
+
+    cr0 &= ~CR0_WP_MASK;
+    if (wp)
+	cr0 |= CR0_WP_MASK;
+    write_cr0(cr0);
+}
+
+void ac_test_init(ac_test_t *at)
+{
+    set_cr0_wp(1);
+    for (int i = 0; i < NR_AC_FLAGS; ++i)
+	at->flags[i] = 0;
+    at->virt = (void *)(0x123400000000 + 16 * smp_id());
+    at->phys = 32 * 1024 * 1024;
+    at->pt_pool = 33 * 1024 * 1024;
+    memset(at->idt, 0, sizeof at->idt);
+    lidt(at->idt, 256);
+    extern char page_fault, kernel_entry;
+    set_idt_entry(&at->idt[14], &page_fault, 0);
+    set_idt_entry(&at->idt[0x20], &kernel_entry, 3);
+}
+
+int ac_test_bump(ac_test_t *at)
+{
+    for (int i = 0; i < NR_AC_FLAGS; ++i)
+	if (!at->flags[i]) {
+	    at->flags[i] = 1;
+	    return 1;
+	} else
+	    at->flags[i] = 0;
+    return 0;
+}
+
+unsigned long read_cr3()
+{
+    unsigned long cr3;
+
+    asm volatile ("mov %%cr3, %0" : "=r"(cr3));
+    return cr3;
+}
+
+void invlpg(void *addr)
+{
+    asm volatile ("invlpg (%0)" : : "r"(addr));
+}
+
+pt_element_t ac_test_alloc_pt(ac_test_t *at)
+{
+    pt_element_t ret = at->pt_pool;
+    at->pt_pool += PAGE_SIZE;
+    return ret;
+}
+
+void ac_test_setup_pte(ac_test_t *at)
+{
+    unsigned long root = read_cr3();
+
+    for (int i = 4; i >= 1; --i) {
+	pt_element_t *vroot = va(root & PT_BASE_ADDR_MASK);
+	unsigned index = ((unsigned long)at->virt >> (12 + (i-1) * 9)) & 511;
+	pt_element_t pte;
+	if (i != 1) {
+	    pte = vroot[index];
+	    if (!(pte & PT_PRESENT_MASK))
+		pte = ac_test_alloc_pt(at) | PT_PRESENT_MASK;
+	    pte |= PT_WRITABLE_MASK | PT_USER_MASK;
+	} else {
+	    pte = at->phys & PT_BASE_ADDR_MASK;
+	    if (at->flags[AC_PTE_PRESENT])
+		pte |= PT_PRESENT_MASK;
+	    if (at->flags[AC_PTE_WRITABLE])
+		pte |= PT_WRITABLE_MASK;
+	    if (at->flags[AC_PTE_USER])
+		pte |= PT_USER_MASK;
+	    if (at->flags[AC_PTE_ACCESSED])
+		pte |= PT_ACCESSED_MASK;
+	    if (at->flags[AC_PTE_DIRTY])
+		pte |= PT_DIRTY_MASK;
+	    at->ptep = &vroot[index];
+	}
+	vroot[index] = pte;
+	root = vroot[index];
+    }
+    invlpg(at->virt);
+    at->expected_pte = *at->ptep;
+    at->expected_fault = 0;
+    at->expected_error = 0;
+    if (!at->flags[AC_PTE_PRESENT])
+	at->expected_fault = 1;
+    else
+	at->expected_error |= PFERR_PRESENT_MASK;
+
+    if (at->flags[AC_ACCESS_USER]) {
+	at->expected_error |= PFERR_USER_MASK;
+	if (!at->flags[AC_PTE_USER])
+	    at->expected_fault = 1;
+    }
+
+    if (at->flags[AC_ACCESS_WRITE]) {
+	at->expected_error |= PFERR_WRITE_MASK;
+	if (!at->flags[AC_PTE_WRITABLE]
+	    && (at->flags[AC_CPU_CR0_WP] || at->flags[AC_ACCESS_USER])) {
+	    at->expected_fault = 1;
+	} else if (!at->expected_fault) {
+	    at->expected_pte |= PT_DIRTY_MASK;
+	}
+    }
+
+    if (!at->expected_fault) {
+	at->expected_pte |= PT_ACCESSED_MASK;
+    }
+}
+
+int ac_test_do_access(ac_test_t *at)
+{
+    static unsigned unique = 42;
+    int fault = 0;
+    unsigned e;
+    static unsigned char user_stack[4096];
+    unsigned long rsp;
+
+    ++unique;
+
+    unsigned r = unique;
+    set_cr0_wp(at->flags[AC_CPU_CR0_WP]);
+    asm volatile ("mov %%rsp, %%rdx \n\t"
+		  "cmp $0, %[user] \n\t"
+		  "jz do_access \n\t"
+		  "push %%rax; mov %[user_ds], %%ax; mov %%ax, %%ds; pop %%rax  \n\t"
+		  "pushq %[user_ds] \n\t"
+		  "pushq %[user_stack_top] \n\t"
+		  "pushfq \n\t"
+		  "pushq %[user_cs] \n\t"
+		  "pushq $do_access \n\t"
+		  "iretq \n"
+		  "do_access: \n\t"
+		  "cmp $0, %[write] \n\t"
+		  "jnz 1f \n\t"
+		  "mov (%[addr]), %[reg] \n\t"
+		  "jmp done \n\t"
+		  "1: mov %[reg], (%[addr]) \n\t"
+		  "done: \n"
+		  "fixed1: \n"
+		  "int %[kernel_entry_vector] \n\t"
+		  "back_to_kernel:"
+		  : [reg]"+r"(r), "+a"(fault), "=b"(e), "=&d"(rsp)
+		  : [addr]"r"(at->virt),
+		    [write]"r"(at->flags[AC_ACCESS_WRITE]),
+		    [user]"r"(at->flags[AC_ACCESS_USER]),
+		    [user_ds]"i"(32+3),
+		    [user_cs]"i"(24+3),
+		    [user_stack_top]"r"(user_stack + sizeof user_stack),
+		    [kernel_entry_vector]"i"(0x20));
+
+    asm volatile (".section .text.pf \n\t"
+		  "page_fault: \n\t"
+		  "pop %rbx \n\t"
+		  "movq $fixed1, (%rsp) \n\t"
+		  "movl $1, %eax \n\t"
+		  "iretq \n\t"
+		  ".section .text");
+
+    asm volatile (".section .text.entry \n\t"
+		  "kernel_entry: \n\t"
+		  "mov %rdx, %rsp \n\t"
+		  "jmp back_to_kernel \n\t"
+		  ".section .text");
+
+    if (fault && !at->expected_fault) {
+	printf("unexpected fault\n");
+	return 0;
+    }
+    if (!fault && at->expected_fault) {
+	printf("unexpected access\n");
+	return 0;
+    }
+    if (fault && e != at->expected_error) {
+	printf("error code %x expected %x\n", e, at->expected_fault);
+	return 0;
+    }
+    if (*at->ptep != at->expected_pte) {
+	printf("pte %x expected %x\n", *at->ptep, at->expected_pte);
+	return 0;
+    }
+
+    printf("OK\n");
+    return 1;
+}
+
+void ac_test_exec(ac_test_t *at)
+{
+    int r;
+
+    printf("test");
+    for (int i = 0; i < NR_AC_FLAGS; ++i)
+	if (at->flags[i])
+	    printf(" %s", ac_names[i]);
+    printf(": ");
+    ac_test_setup_pte(at);
+    r = ac_test_do_access(at);
+}
+
+void ac_test_run()
+{
+    static ac_test_t at;
+
+    printf("run\n");
+    ac_test_init(&at);
+    do {
+	ac_test_exec(&at);
+    } while (ac_test_bump(&at));
+}
+
+int main()
+{
+    printf("starting test\n\n");
+    smp_init(ac_test_run);
+    ac_test_run();
+    return 0;
+}
diff --git a/user/test/x86/apic.h b/user/test/x86/apic.h
new file mode 100644
--- /dev/null
+++ b/user/test/x86/apic.h
@@ -0,0 +1,14 @@
+#ifndef SILLY_APIC_H
+#define SILLY_APIC_H
+
+#define APIC_BASE 0x1000
+#define APIC_SIZE 0x100
+
+#define APIC_REG_NCPU        0x00
+#define APIC_REG_ID          0x04
+#define APIC_REG_SIPI_ADDR   0x08
+#define APIC_REG_SEND_SIPI   0x0c
+#define APIC_REG_IPI_VECTOR  0x10
+#define APIC_REG_SEND_IPI    0x14
+
+#endif
diff --git a/user/test/x86/bootstrap.S b/user/test/x86/bootstrap.S
new file mode 100644
--- /dev/null
+++ b/user/test/x86/bootstrap.S
@@ -0,0 +1,137 @@
+/*
+ * minimal bootstrap to set up flat 32-bit protected mode
+ */
+
+#include "apic.h"
+	
+bstart = 0xf0000
+	
+.code16
+
+stack_top = 0x1000
+cpu_up = 0x1000
+cpu_up_pmode = 0x1004
+
+pmode_stack_start = 0x10000
+pmode_stack_shift = 16
+pmode_stack_size = (1 << pmode_stack_shift)
+
+ipi_vec = 0xf0
+	
+start:
+	mov $stack_top, %sp
+	call smp_init
+
+	cs lidtl idt_desc
+	cs lgdtl gdt_desc
+	mov %cr0, %eax
+	or $1, %eax
+	mov %eax, %cr0
+	ljmpl $8, $pmode + bstart
+
+smp_init:
+	mov $ipi_vec, %eax
+	mov $(APIC_BASE + APIC_REG_IPI_VECTOR), %dx
+	out %eax, %dx
+	movw $ap_switch_to_pmode, ipi_vec*4
+	movw %cs, %ax
+	mov %ax, ipi_vec*4+2
+	mov $sipi, %eax
+	mov $(APIC_BASE + APIC_REG_SIPI_ADDR), %dx
+	outl %eax, %dx
+	mov $(APIC_BASE + APIC_REG_NCPU), %dx
+	inl %dx, %eax
+	mov %eax, %ecx
+	mov $1, %esi
+smp_loop:
+	cmp %esi, %ecx
+	jbe smp_done
+	mov %esi, %eax
+	mov $(APIC_BASE + APIC_REG_SEND_SIPI), %dx
+	outl %eax, %dx
+wait_for_cpu:
+	cmp cpu_up, %esi
+	jne wait_for_cpu
+	mov %esi, %eax
+	mov $(APIC_BASE + APIC_REG_SEND_IPI), %dx
+	out %eax, %dx
+wait_for_cpu_pmode:
+	cmp cpu_up_pmode, %esi
+	jne wait_for_cpu_pmode
+	
+	inc %esi
+	jmp smp_loop
+smp_done:
+	ret
+
+sipi:
+	mov $(APIC_BASE + APIC_REG_ID), %dx
+	inl %dx, %eax
+	mov %eax, cpu_up
+	shl $12, %eax
+	addl $stack_top, %eax
+	movl %eax, %esp
+	sti
+	nop
+1:	hlt
+	jmp 1b
+
+ap_switch_to_pmode:
+	cs lidtl idt_desc
+	cs lgdtl gdt_desc
+	mov %cr0, %eax
+	or $1, %eax
+	mov %eax, %cr0
+	ljmpl $8, $ap_pmode + bstart
+
+.code32	
+ap_pmode:
+	mov $0x10, %ax
+	mov %ax, %ds
+	mov %ax, %es
+	mov %ax, %fs
+	mov %ax, %gs
+	mov %ax, %ss
+	mov $(APIC_BASE + APIC_REG_ID), %dx
+	in %dx, %eax
+	mov %eax, cpu_up_pmode
+	shl $pmode_stack_shift, %eax
+	lea pmode_stack_start + pmode_stack_size(%eax), %esp
+	sti
+	nop
+ap_pmode_wait:
+	hlt
+	jmp ap_pmode_wait
+
+pmode:
+	mov $0x10, %ax
+	mov %ax, %ds
+	mov %ax, %es
+	mov %ax, %fs
+	mov %ax, %gs
+	mov %ax, %ss
+	mov $pmode_stack_start + pmode_stack_size, %esp
+	ljmp $8, $0x100000
+
+.align 16
+	
+idt_desc:
+	.word 8*256-1
+	.long 0
+
+gdt_desc:
+	.word gdt_end - gdt - 1
+	.long gdt + bstart
+
+.align 16
+
+gdt:
+	.quad 0
+	.quad 0x00cf9b000000ffff // flat 32-bit code segment
+	.quad 0x00cf93000000ffff // flat 32-bit data segment
+gdt_end:
+	
+. = 0xfff0
+	.code16
+	ljmp $0xf000, $start
+.align 65536
diff --git a/user/test/x86/cstart.S b/user/test/x86/cstart.S
new file mode 100644
--- /dev/null
+++ b/user/test/x86/cstart.S
@@ -0,0 +1,10 @@
+
+
+.bss
+
+.section .init
+	call main
+1:	hlt
+	jmp 1b
+
+
diff --git a/user/test/x86/cstart64.S b/user/test/x86/cstart64.S
new file mode 100644
--- /dev/null
+++ b/user/test/x86/cstart64.S
@@ -0,0 +1,169 @@
+
+#include "apic.h"
+
+boot_idt = 0
+
+ipi_vector = 0x20
+
+max_cpus = 4
+
+.bss
+
+	. = . + 4096 * max_cpus
+	.align 16
+stacktop:
+
+	. = . + 4096
+	.align 16
+ring0stacktop:
+
+.data
+		
+.align 4096
+ptl2:
+i = 0
+	.rept 512
+	.quad 0x1e7 | (i << 21)
+	i = i + 1
+	.endr
+
+.align 4096
+ptl3:
+	.quad ptl2 + 7
+
+.align 4096
+ptl4:
+	.quad ptl3 + 7
+	
+.align 4096
+
+gdt64_desc:
+	.word gdt64_end - gdt64 - 1
+	.quad gdt64
+
+gdt64:
+	.quad 0
+	.quad 0x00af9b000000ffff // 64-bit code segment
+	.quad 0x00cf93000000ffff // 64-bit data segment
+	.quad 0x00affb000000ffff // 64-bit code segment (user)
+	.quad 0x00cff3000000ffff // 64-bit data segment (user)
+tss_descr:
+	.rept max_cpus
+	.quad 0x000089000000ffff // 64-bit avail tss
+	.quad 0                  // tss high addr
+	.endr
+gdt64_end:
+
+i = 0
+tss:
+	.rept max_cpus
+	.long 0
+	.quad ring0stacktop - i * 4096
+	.quad 0, 0, 0
+	.quad 0, 0, 0, 0, 0, 0, 0, 0
+	.long 0, 0, 0
+i = i + 1
+	.endr
+tss_end:
+
+.section .init
+
+.code32
+	call prepare_64
+	jmpl $8, $start64
+
+prepare_64:
+	lgdt gdt64_desc
+
+	mov %cr4, %eax
+	bts $5, %eax  // pae
+	mov %eax, %cr4
+
+	mov $ptl4, %eax
+	mov %eax, %cr3
+
+efer = 0xc0000080
+	mov $efer, %ecx
+	rdmsr
+	bts $8, %eax
+	wrmsr
+
+	mov %cr0, %eax
+	bts $0, %eax
+	bts $31, %eax
+	mov %eax, %cr0
+	ret
+
+
+smp_init_ipi:
+	call prepare_64
+	jmpl $8, $ap_start64
+
+.code64
+ap_start64:
+	call load_tss
+	sti
+	nop
+
+1:	hlt
+	jmp 1b
+
+start64:
+	call load_tss
+	call smp_init
+	call main
+
+1:	hlt
+	jmp 1b
+
+load_tss:
+	mov $0, %eax
+	mov %ax, %ss
+	mov $(APIC_BASE + APIC_REG_ID), %dx
+	in %dx, %eax
+	mov %eax, %ebx
+	shl $4, %ebx
+	mov $((tss_end - tss) / max_cpus), %edx
+	imul %edx
+	add $tss, %rax
+	mov %ax, tss_descr+2(%rbx)
+	shr $16, %rax
+	mov %al, tss_descr+4(%rbx)
+	shr $8, %rax
+	mov %al, tss_descr+7(%rbx)
+	shr $8, %rax
+	mov %eax, tss_descr+8(%rbx)
+	lea tss_descr-gdt64(%rbx), %rax
+	ltr %ax
+	ret
+
+smp_init:
+	lea boot_idt + ipi_vector * 8, %rdi
+	mov $smp_init_ipi, %eax
+	mov %ax, (%rdi)
+	mov %cs, %ax
+	mov %ax, 2(%rdi)
+	movw $0x8e00, 4(%rdi)
+	shr $16, %eax
+	mov %ax, 6(%rdi)
+
+	mov $(APIC_BASE + APIC_REG_IPI_VECTOR), %dx
+	mov $ipi_vector, %eax
+	out %eax, %dx
+
+	mov $(APIC_BASE + APIC_REG_NCPU), %dx
+	in %dx, %eax
+	mov %eax, %ecx
+	mov $1, %esi
+smp_loop:
+	cmp %esi, %ecx
+	je smp_init_done
+
+	mov $(APIC_BASE + APIC_REG_SEND_IPI), %dx
+	mov %esi, %eax
+	out %eax, %dx
+
+	inc %esi
+	jmp smp_loop
+smp_init_done:
+	ret
diff --git a/user/test/x86/irq.S b/user/test/x86/irq.S
new file mode 100644
--- /dev/null
+++ b/user/test/x86/irq.S
@@ -0,0 +1,118 @@
+// irq test program.  assumes outb $irq, $0xff generates an interrupt $irq.
+
+#include "print.h"
+	
+.text
+	PRINT "irq test"
+	mov $stack_top, %rsp
+
+	call setup_gdt
+	
+	mov %ds, %ax
+	mov %ax, %ds  // check ds descriptor is okay
+
+	mov $irq_handler, %rdx
+	mov $0x20, %eax
+	call setup_idt_entry
+
+	lidt idt_descriptor
+
+	PRINT "software interrupt"
+	int $0x20
+
+	sti
+	nop
+
+	PRINT "injecting interrupt with interrupts enabled"
+	
+	mov $0x20, %al
+	outb %al, $0xff // inject interrupt
+
+	nop
+	nop
+	nop
+	PRINT "after injection"
+
+	cli
+
+	PRINT "injecting interrupt with interrupts disabled"
+	
+	mov $0x20, %al
+	outb %al, $0xff // inject interrupt
+
+	// no interrupt here (disabled)
+	nop
+	nop
+	PRINT "enabling interrupts"
+	nop
+	nop
+	sti
+	out %al, $0x80 // blocked by sti
+	// interrupt here
+	out %al, $0x80 
+
+	PRINT "after injection"
+	nop
+	nop
+	
+	hlt
+	
+irq_handler:
+	PRINT "interrupt handler"
+	iretq
+	
+setup_idt_entry:	// %rax: irq %rdx: handler
+	shl $4, %rax
+	mov %dx, idt(%rax)
+	shr $16, %rdx
+	mov %cs, 2+idt(%rax)
+	mov %dx, 6+idt(%rax)
+	shr $16, %rdx
+	mov %edx, 8+idt(%rax)
+	movw $0x8e00, 4+idt(%rax)
+	ret
+
+setup_gdt:
+	mov $0, %eax
+	mov %cs, %ax
+	andl $~7, %eax
+	movl $0xffff, gdt(%rax)
+	movl $0xaf9b00, 4+gdt(%rax)
+
+	mov $0, %eax
+	mov %ds, %ax
+	andl $~7, %eax
+	movl $0xffff, gdt(%rax)
+	movl $0x8f9300, 4+gdt(%rax)
+
+	lgdt gdt_descriptor
+	ret
+	
+.data
+	
+.align 16
+
+idt:	
+	. = . + 256 * 16
+
+idt_descriptor:
+	.word . - idt - 1
+	.quad idt
+
+.align 8
+	
+gdt:
+	. = . + 256 * 8
+
+gdt_descriptor:
+	.word . - gdt - 1
+	.quad gdt 
+
+	
+.align 4096
+stack_base:
+	. = . + 4096
+stack_top:
+	
+
+
diff --git a/user/test/x86/memtest1.S b/user/test/x86/memtest1.S
new file mode 100644
--- /dev/null
+++ b/user/test/x86/memtest1.S
@@ -0,0 +1,44 @@
+.text
+	
+start:
+	mov    $0x1000,%r8
+	mov    $0x0a,%ecx
+
+init_page:
+	dec    %ecx
+	jne    no_io
+	mov    $0x0,%al
+	out    %al,$0x80
+	mov    $0x0a,%ecx
+
+no_io:
+	mov    %r8,(%r8)
+	add    $0x1000,%r8
+	cmp    $0x8000000,%r8
+	jne    init_page
+	mov    $0x1000,%r8
+	mov    $0x0a,%ecx
+
+test_loop:
+	dec    %ecx
+	jne    no_io2
+	mov    $0x0,%al
+	out    %al,$0x80
+	mov    $0x0a,%ecx
+
+no_io2:
+	mov    (%r8),%r9
+	cmp    %r8,%r9
+	jne    err
+	add    $0x1000,%r8
+	cmp    $0x8000000,%r8
+	jne    test_loop
+	mov    $0x1000,%r8
+	jmp    test_loop
+
+err:
+	mov    $0xffffffffffffffff,%r12
+	mov    $0xffffffffffffffff,%r13
+	mov    $0x0,%al
+	out    %al,$0x80
+	jmp    err
diff --git a/user/test/x86/print.S b/user/test/x86/print.S
new file mode 100644
--- /dev/null
+++ b/user/test/x86/print.S
@@ -0,0 +1,31 @@
+
+#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
diff --git a/user/test/x86/print.h b/user/test/x86/print.h
new file mode 100644
--- /dev/null
+++ b/user/test/x86/print.h
@@ -0,0 +1,19 @@
+#ifndef PRINT_H
+#define PRINT_H
+
+.macro PRINT text
+
+.data
+
+333: .asciz "\text\n"
+
+.previous
+
+	push %rdi
+	lea 333b, %rdi
+	call print
+	pop %rdi
+
+.endm
+
+#endif
diff --git a/user/test/x86/printf.c b/user/test/x86/printf.c
new file mode 100644
--- /dev/null
+++ b/user/test/x86/printf.c
@@ -0,0 +1,169 @@
+#include "printf.h"
+#include "smp.h"
+#include <stdarg.h>
+
+static struct spinlock lock;
+
+void print(const char *s);
+
+typedef struct pstream {
+    char *buffer;
+    int remain;
+    int added;
+} pstream_t;
+
+static void addchar(pstream_t *p, char c)
+{
+    if (p->remain) {
+	*p->buffer++ = c;
+	--p->remain;
+    }
+    ++p->added;
+}
+
+void print_str(pstream_t *p, const char *s)
+{
+    while (*s)
+	addchar(p, *s++);
+}
+
+static char digits[16] = "0123456789abcdef";
+
+void print_int(pstream_t *ps, long n, int base)
+{
+    char buf[sizeof(long) * 3 + 2], *p = buf;
+    int s = 0, i;
+    
+    if (n < 0) {
+	n = -n;
+	s = 1;
+    }
+
+    while (n) {
+	*p++ = digits[n % base];
+	n /= base;
+    }
+    
+    if (s)
+	*p++ = '-';
+
+    if (p == buf)
+	*p++ = '0';
+    
+    for (i = 0; i < (p - buf) / 2; ++i) {
+	char tmp;
+
+	tmp = buf[i];
+	buf[i] = p[-1-i];
+	p[-1-i] = tmp;
+    }
+
+    *p = 0;
+
+    print_str(ps, buf);
+}
+
+void print_unsigned(pstream_t *ps, unsigned long n, int base)
+{
+    char buf[sizeof(long) * 3 + 1], *p = buf;
+    int i;
+    
+    while (n) {
+	*p++ = digits[n % base];
+	n /= base;
+    }
+    
+    if (p == buf)
+	*p++ = '0';
+    
+    for (i = 0; i < (p - buf) / 2; ++i) {
+	char tmp;
+
+	tmp = buf[i];
+	buf[i] = p[-1-i];
+	p[-1-i] = tmp;
+    }
+
+    *p = 0;
+
+    print_str(ps, buf);
+}
+
+int vsnprintf(char *buf, int size, const char *fmt, va_list va)
+{
+    int n;
+    pstream_t s;
+
+    s.buffer = buf;
+    s.remain = size - 1;
+    s.added = 0;
+    while (*fmt) {
+	char f = *fmt++;
+
+	if (f != '%') {
+	    addchar(&s, f);
+	    continue;
+	}
+	f = *fmt++;
+	switch (f) {
+	case '%':
+	    addchar(&s, '%');
+	    break;
+	case '\0':
+	    --fmt;
+	    break;
+	case 'd':
+	    print_int(&s, va_arg(va, int), 10);
+	    break;
+	case 'x':
+	    print_unsigned(&s, va_arg(va, int), 16);
+	    break;
+	case 'p':
+	    print_str(&s, "0x");
+	    print_unsigned(&s, (unsigned long)va_arg(va, void *), 16);
+	    break;
+	case 's':
+	    print_str(&s, va_arg(va, const char *));
+	    break;
+	default:
+	    addchar(&s, f);
+	    break;
+	}
+    }
+    *s.buffer = 0;
+    ++s.added;
+    return s.added;
+}
+
+
+int snprintf(char *buf, int size, const char *fmt, ...)
+{
+    va_list va;
+    int r;
+
+    va_start(va, fmt);
+    r = vsnprintf(buf, size, fmt, va);
+    va_end(va);
+    return r;
+}
+
+void print_serial(const char *buf)
+{
+    while (*buf)
+	asm volatile ("out %%al, $0xf1" : : "a"(*buf++));
+}
+
+int printf(const char *fmt, ...)
+{
+    va_list va;
+    char buf[2000];
+    int r;
+
+    va_start(va, fmt);
+    r = vsnprintf(buf, sizeof buf, fmt, va);
+    va_end(va);
+    spin_lock(&lock);
+    print_serial(buf);
+    spin_unlock(&lock);
+    return r;
+}
diff --git a/user/test/x86/printf.h b/user/test/x86/printf.h
new file mode 100644
--- /dev/null
+++ b/user/test/x86/printf.h
@@ -0,0 +1,2 @@
+
+int printf(const char *fmt, ...);
diff --git a/user/test/x86/sieve.c b/user/test/x86/sieve.c
new file mode 100644
--- /dev/null
+++ b/user/test/x86/sieve.c
@@ -0,0 +1,89 @@
+#include "vm.h"
+
+void print(const char *text);
+
+void printi(int n)
+{
+    char buf[10], *p = buf;
+    int s = 0, i;
+    
+    if (n < 0) {
+	n = -n;
+	s = 1;
+    }
+
+    while (n) {
+	*p++ = '0' + n % 10;
+	n /= 10;
+    }
+    
+    if (s)
+	*p++ = '-';
+
+    if (p == buf)
+	*p++ = '0';
+    
+    for (i = 0; i < (p - buf) / 2; ++i) {
+	char tmp;
+
+	tmp = buf[i];
+	buf[i] = p[-1-i];
+	p[-1-i] = tmp;
+    }
+
+    *p = 0;
+
+    print(buf);
+}
+
+int sieve(char* data, int size)
+{
+    int i, j, r = 0;
+
+    for (i = 0; i < size; ++i)
+	data[i] = 1;
+
+    data[0] = data[1] = 0;
+
+    for (i = 2; i < size; ++i)
+	if (data[i]) {
+	    ++r;
+	    for (j = i*2; j < size; j += i)
+		data[j] = 0;
+	}
+    return r;
+}
+
+void test_sieve(const char *msg, char *data, int size)
+{
+    int r;
+
+    print(msg);
+    print(": ");
+    r = sieve(data, size);
+    printi(r);
+    print("\n");
+}
+
+#define STATIC_SIZE 1000000
+#define VSIZE 100000000
+char static_data[STATIC_SIZE];
+
+int main()
+{
+    void *v;
+    int i;
+
+    print("starting sieve\n");
+    test_sieve("static", static_data, STATIC_SIZE);
+    setup_vm();
+    print("mapped: ");
+    test_sieve("mapped", static_data, STATIC_SIZE);
+    for (i = 0; i < 30; ++i) {
+	v = vmalloc(VSIZE);
+	test_sieve("virtual", v, VSIZE);
+	vfree(v);
+    }
+    
+    return 0;
+}
diff --git a/user/test/x86/simple.S b/user/test/x86/simple.S
new file mode 100644
--- /dev/null
+++ b/user/test/x86/simple.S
@@ -0,0 +1,13 @@
+
+	.text
+
+	mov $0, %al
+	mov $10000, %ebx
+1:
+	mov %rbx, %rcx
+2:	
+	loop 2b
+	out %al, $0x80
+	inc %al
+	add $10000, %rbx
+	jmp 1b
diff --git a/user/test/x86/smp.c b/user/test/x86/smp.c
new file mode 100644
--- /dev/null
+++ b/user/test/x86/smp.c
@@ -0,0 +1,151 @@
+
+
+#include "smp.h"
+#include "apic.h"
+#include "printf.h"
+
+#define IPI_VECTOR 0x20
+
+static int apic_read(int reg)
+{
+    unsigned short port = APIC_BASE + reg;
+    unsigned v;
+
+    asm volatile ("in %1, %0" : "=a"(v) : "d"(port));
+    return v;
+}
+
+static void apic_write(int reg, unsigned v)
+{
+    unsigned short port = APIC_BASE + reg;
+
+    asm volatile ("out %0, %1" : : "a"(v), "d"(port));
+}
+
+static int apic_get_cpu_count()
+{
+    return apic_read(APIC_REG_NCPU);
+}
+
+static int apic_get_id()
+{
+    return apic_read(APIC_REG_ID);
+}
+
+static void apic_set_ipi_vector(int vector)
+{
+    apic_write(APIC_REG_IPI_VECTOR, vector);
+}
+
+static void apic_send_ipi(int cpu)
+{
+    apic_write(APIC_REG_SEND_IPI, cpu);
+}
+
+static struct spinlock ipi_lock;
+static void (*ipi_function)(void *data);
+static void *ipi_data;
+static volatile int ipi_done;
+
+static __attribute__((used)) void ipi()
+{
+    ipi_function(ipi_data);
+    ipi_done = 1;
+}
+
+asm (
+     "ipi_entry: \n"
+     "   call ipi \n"
+#ifndef __x86_64__
+     "   iret"
+#else
+     "   iretq"
+#endif
+     );
+
+
+static void set_ipi_descriptor(void (*ipi_entry)(void))
+{
+    unsigned short *desc = (void *)(IPI_VECTOR * sizeof(long) * 2);
+    unsigned short cs;
+    unsigned long ipi = (unsigned long)ipi_entry;
+
+    asm ("mov %%cs, %0" : "=r"(cs));
+    desc[0] = ipi;
+    desc[1] = cs;
+    desc[2] = 0x8e00;
+    desc[3] = ipi >> 16;
+#ifdef __x86_64__
+    desc[4] = ipi >> 32;
+    desc[5] = ipi >> 48;
+    desc[6] = 0;
+    desc[7] = 0;
+#endif
+}
+
+void spin_lock(struct spinlock *lock)
+{
+    int v = 1;
+
+    do {
+	asm volatile ("xchg %1, %0" : "+m"(lock->v), "+r"(v));
+    } while (v);
+    asm volatile ("" : : : "memory");
+}
+
+void spin_unlock(struct spinlock *lock)
+{
+    asm volatile ("" : : : "memory");
+    lock->v = 0;
+}
+
+int cpu_count(void)
+{
+    return apic_get_cpu_count();
+}
+
+int smp_id(void)
+{
+    return apic_get_id();
+}
+
+void on_cpu(int cpu, void (*function)(void *data), void *data)
+{
+    spin_lock(&ipi_lock);
+    if (cpu == apic_get_id())
+	function(data);
+    else {
+	ipi_function = function;
+	ipi_data = data;
+	apic_send_ipi(cpu);
+	while (!ipi_done)
+	    ;
+	ipi_done = 0;
+    }
+    spin_unlock(&ipi_lock);
+}
+
+static void (*smp_main_func)(void);
+static volatile int smp_main_running;
+
+asm ("smp_init_entry: \n"
+     "incl smp_main_running \n"
+     "sti \n"
+     "call *smp_main_func");
+
+void smp_init(void (*smp_main)(void))
+{
+    int i;
+    void smp_init_entry(void);
+    void ipi_entry(void);
+
+    apic_set_ipi_vector(IPI_VECTOR);
+    set_ipi_descriptor(smp_init_entry);
+    smp_main_func = smp_main;
+    for (i = 1; i < cpu_count(); ++i) {
+	apic_send_ipi(i);
+	while (smp_main_running < i)
+	    ;
+    }
+    set_ipi_descriptor(ipi_entry);
+}
diff --git a/user/test/x86/smp.h b/user/test/x86/smp.h
new file mode 100644
--- /dev/null
+++ b/user/test/x86/smp.h
@@ -0,0 +1,16 @@
+#ifndef __SMP_H
+#define __SMP_H
+
+struct spinlock {
+    int v;
+};
+
+void smp_init(void (*smp_main)(void));
+
+int cpu_count(void);
+int smp_id(void);
+void on_cpu(int cpu, void (*function)(void *data), void *data);
+void spin_lock(struct spinlock *lock);
+void spin_unlock(struct spinlock *lock);
+
+#endif
diff --git a/user/test/x86/smptest.c b/user/test/x86/smptest.c
new file mode 100644
--- /dev/null
+++ b/user/test/x86/smptest.c
@@ -0,0 +1,32 @@
+
+#include "smp.h"
+#include "printf.h"
+
+static void ipi_test(void *data)
+{
+    int n = (long)data;
+
+    printf("ipi called, cpu %d\n", n);
+    if (n != smp_id())
+	printf("but wrong cpu %d\n", smp_id());
+}
+
+static void smp_main(void)
+{
+    printf("smp main %d\n", smp_id());
+    while (1)
+	asm volatile ("hlt" : : : "memory");
+}
+
+int main()
+{
+    int ncpus;
+    int i;
+
+    smp_init(smp_main);
+    ncpus = cpu_count();
+    printf("found %d cpus\n", ncpus);
+    for (i = 0; i < ncpus; ++i)
+	on_cpu(i, ipi_test, (void *)(long)i);
+    return 0;
+}
diff --git a/user/test/x86/stringio.S b/user/test/x86/stringio.S
new file mode 100644
--- /dev/null
+++ b/user/test/x86/stringio.S
@@ -0,0 +1,31 @@
+
+.data
+
+.macro str name, value
+
+\name :	.long 1f-2f
+2:	.ascii "\value"
+1:	
+.endm	
+
+	str "forward", "forward"
+	str "backward", "backward"
+		
+.text
+
+
+	cld
+	movl forward, %ecx
+	lea  4+forward, %rsi
+	movw $1, %dx
+	rep outsb
+
+	std
+	movl backward, %ecx
+	lea 4+backward-1(%rcx), %rsi
+	movw $2, %dx
+	rep outsb
+	
+	hlt
+
+
diff --git a/user/test/x86/test32.S b/user/test/x86/test32.S
new file mode 100644
--- /dev/null
+++ b/user/test/x86/test32.S
@@ -0,0 +1,8 @@
+.code32
+
+.text
+
+1:
+	mov $0x12, %al
+	out %al, $0x80
+	jmp 1b
diff --git a/user/test/x86/vm.c b/user/test/x86/vm.c
new file mode 100644
--- /dev/null
+++ b/user/test/x86/vm.c
@@ -0,0 +1,249 @@
+
+#include "vm.h"
+
+void print(const char *s);
+
+#define PAGE_SIZE 4096ul
+#define LARGE_PAGE_SIZE (512 * PAGE_SIZE)
+
+static void *free = 0;
+static void *vfree_top = 0;
+
+static unsigned long virt_to_phys(const void *virt) 
+{ 
+    return (unsigned long)virt;
+}
+
+static void *phys_to_virt(unsigned long phys)
+{
+    return (void *)phys;
+}
+
+void *memset(void *data, int c, unsigned long len)
+{
+    char *s = data;
+
+    while (len--)
+	*s++ = c;
+
+    return data;
+}
+
+static void free_memory(void *mem, unsigned long size)
+{
+    while (size >= PAGE_SIZE) {
+	*(void **)mem = free;
+	free = mem;
+	mem += PAGE_SIZE;
+	size -= PAGE_SIZE;
+    }
+}
+
+void *alloc_page()
+{
+    void *p;
+
+    if (!free)
+	return 0;
+    
+    p = free;
+    free = *(void **)free;
+
+    return p;
+}
+
+void free_page(void *page)
+{
+    *(void **)page = free;
+    free = page;
+}
+
+extern char edata;
+static unsigned long end_of_memory;
+
+#define PTE_PRESENT (1ull << 0)
+#define PTE_PSE     (1ull << 7)
+#define PTE_WRITE   (1ull << 1)
+#define PTE_ADDR    (0xffffffffff000ull)
+
+static void install_pte(unsigned long *cr3, 
+			int pte_level, 
+			void *virt,
+			unsigned long pte)
+{
+    int level;
+    unsigned long *pt = cr3;
+    unsigned offset;
+
+    for (level = 4; level > pte_level; --level) {
+	offset = ((unsigned long)virt >> ((level-1) * 9 + 12)) & 511;
+	if (!(pt[offset] & PTE_PRESENT)) {
+	    unsigned long *new_pt = alloc_page();
+	    memset(new_pt, 0, PAGE_SIZE);
+	    pt[offset] = virt_to_phys(new_pt) | PTE_PRESENT | PTE_WRITE;
+	}
+	pt = phys_to_virt(pt[offset] & 0xffffffffff000ull);
+    }
+    offset = ((unsigned long)virt >> (((level-1) * 9) + 12)) & 511;
+    pt[offset] = pte;
+}
+
+static unsigned long get_pte(unsigned long *cr3, void *virt)
+{
+    int level;
+    unsigned long *pt = cr3, pte;
+    unsigned offset;
+
+    for (level = 4; level > 1; --level) {
+	offset = ((unsigned long)virt >> (((level-1) * 9) + 12)) & 511;
+	pte = pt[offset];
+	if (!(pte & PTE_PRESENT))
+	    return 0;
+	if (level == 2 && (pte & PTE_PSE))
+	    return pte;
+	pt = phys_to_virt(pte & 0xffffffffff000ull);
+    }
+    offset = ((unsigned long)virt >> (((level-1) * 9) + 12)) & 511;
+    pte = pt[offset];
+    return pte;
+}
+
+static void install_large_page(unsigned long *cr3, 
+			       unsigned long phys,
+			       void *virt)
+{
+    install_pte(cr3, 2, virt, phys | PTE_PRESENT | PTE_WRITE | PTE_PSE);
+}
+
+static void install_page(unsigned long *cr3, 
+			 unsigned long phys,
+			 void *virt)
+{
+    install_pte(cr3, 1, virt, phys | PTE_PRESENT | PTE_WRITE);
+}
+
+static inline void load_cr3(unsigned long cr3)
+{
+    asm ( "mov %0, %%cr3" : : "r"(cr3) );
+}
+
+static inline unsigned long read_cr3()
+{
+    unsigned long cr3;
+
+    asm volatile ( "mov %%cr3, %0" : "=r"(cr3) );
+    return cr3;
+}
+
+static inline void load_cr0(unsigned long cr0)
+{
+    asm volatile ( "mov %0, %%cr0" : : "r"(cr0) );
+}
+
+static inline unsigned long read_cr0()
+{
+    unsigned long cr0;
+
+    asm volatile ( "mov %%cr0, %0" : "=r"(cr0) );
+    return cr0;
+}
+
+static inline void load_cr4(unsigned long cr4)
+{
+    asm volatile ( "mov %0, %%cr4" : : "r"(cr4) );
+}
+
+static inline unsigned long read_cr4()
+{
+    unsigned long cr4;
+
+    asm volatile ( "mov %%cr4, %0" : "=r"(cr4) );
+    return cr4;
+}
+
+struct gdt_table_descr
+{
+    unsigned short len;
+    unsigned long *table;
+} __attribute__((packed));
+
+static inline void load_gdt(unsigned long *table, int nent)
+{
+    struct gdt_table_descr descr;
+
+    descr.len = nent * 8 - 1;
+    descr.table = table;
+    asm volatile ( "lgdt %0" : : "m"(descr) );
+}
+
+#define SEG_CS_32 8
+#define SEG_CS_64 16
+
+struct ljmp {
+    void *ofs;
+    unsigned short seg;
+};
+
+static void setup_mmu(unsigned long len)
+{
+    unsigned long *cr3 = alloc_page();
+    unsigned long phys = 0;
+
+    memset(cr3, 0, PAGE_SIZE);
+    while (phys + LARGE_PAGE_SIZE <= len) {
+	install_large_page(cr3, phys, (void *)phys);
+	phys += LARGE_PAGE_SIZE;
+    }
+    while (phys + PAGE_SIZE <= len) {
+	install_page(cr3, phys, (void *)phys);
+	phys += PAGE_SIZE;
+    }
+    
+    load_cr3(virt_to_phys(cr3));
+    print("paging enabled\n");
+}
+
+static unsigned int inl(unsigned short port)
+{
+    unsigned int val;
+    asm volatile("inl %w1, %0" : "=a"(val) : "Nd"(port));
+    return val;
+}
+
+void setup_vm()
+{
+    end_of_memory = inl(0xd1);
+    free_memory(&edata, end_of_memory - (unsigned long)&edata);
+    setup_mmu(end_of_memory);
+}
+
+void *vmalloc(unsigned long size)
+{
+    void *mem, *p;
+    unsigned pages;
+
+    size += sizeof(unsigned long);
+    
+    size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+    vfree_top -= size;
+    mem = p = vfree_top;
+    pages = size / PAGE_SIZE;
+    while (pages--) {
+	install_page(phys_to_virt(read_cr3()), virt_to_phys(alloc_page()), p);
+	p += PAGE_SIZE;
+    }
+    *(unsigned long *)mem = size;
+    mem += sizeof(unsigned long);
+    return mem;
+}
+
+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;
+	size -= PAGE_SIZE;
+    }
+}
diff --git a/user/test/x86/vm.h b/user/test/x86/vm.h
new file mode 100644
--- /dev/null
+++ b/user/test/x86/vm.h
@@ -0,0 +1,9 @@
+#ifndef VM_H
+#define VM_H
+
+void setup_vm();
+
+void *vmalloc(unsigned long size);
+void vfree(void *mem);
+
+#endif
diff --git a/user/test/x86/vmexit.c b/user/test/x86/vmexit.c
new file mode 100644
--- /dev/null
+++ b/user/test/x86/vmexit.c
@@ -0,0 +1,32 @@
+
+#include "printf.h"
+
+static inline unsigned long long rdtsc()
+{
+	long long r;
+
+#ifdef __x86_64__
+	unsigned a, d;
+
+	asm volatile ("rdtsc" : "=a"(a), "=d"(d));
+	r = a | ((long long)d << 32);
+#else
+	asm volatile ("rdtsc" : "=A"(r));
+#endif
+	return r;
+}
+
+#define N (1 << 22)
+
+int main()
+{
+	int i;
+	unsigned long long t1, t2;
+
+	t1 = rdtsc();
+	for (i = 0; i < N; ++i)
+		asm volatile ("cpuid" : : : "eax", "ebx", "ecx", "edx");
+	t2 = rdtsc();
+	printf("vmexit latency: %d\n", (int)((t2 - t1) / N));
+	return 0;
+}

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/

  parent reply	other threads:[~2007-10-24  3:26 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-10-24  3:26 [PATCH 0 of 2] [v2] Another attempt to Consolidate x86 makefiles & tests jyoung5-r/Jw6+rmf7HQT0dZR+AlfA
2007-10-24  3:26 ` [PATCH 1 of 2] consolidate x86 user makefiles jyoung5-r/Jw6+rmf7HQT0dZR+AlfA
2007-10-24 14:32   ` [kvm-ppc-devel] " Hollis Blanchard
2007-10-24  3:26 ` jyoung5-r/Jw6+rmf7HQT0dZR+AlfA [this message]
2007-10-24 14:32   ` [kvm-ppc-devel] [PATCH 2 of 2] Move all x86 specific tests to there own directory Hollis Blanchard
2007-10-25 18:12 ` [PATCH 0 of 2] [v2] Another attempt to Consolidate x86 makefiles & tests Avi Kivity
     [not found]   ` <4720DC70.6090607-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2007-10-25 18:37     ` userspace repositories Hollis Blanchard
2007-10-25 18:40       ` Avi Kivity
     [not found]         ` <4720E312.3060400-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2007-10-25 19:01           ` Hollis Blanchard
2007-10-25 19:03             ` Avi Kivity

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1335122fbf8be195a699.1193196400@thinkpad \
    --to=jyoung5-r/jw6+rmf7hqt0dzr+alfa@public.gmane.org \
    --cc=kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org \
    --cc=kvm-ppc-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox