* [PATCH 0 of 2] [v2] Another attempt to Consolidate x86 makefiles & tests
@ 2007-10-24 3:26 jyoung5-r/Jw6+rmf7HQT0dZR+AlfA
2007-10-24 3:26 ` [PATCH 1 of 2] consolidate x86 user makefiles jyoung5-r/Jw6+rmf7HQT0dZR+AlfA
` (2 more replies)
0 siblings, 3 replies; 10+ messages in thread
From: jyoung5-r/Jw6+rmf7HQT0dZR+AlfA @ 2007-10-24 3:26 UTC (permalink / raw)
To: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
Cc: kvm-ppc-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
This is the acutally the 3rd attempt.
These patches consolidate the make files & tests in user director for x86. This
is to allow other architectures easier integration into the kvm source.
Signed-off-by: Jerone Young <jyoung5-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
-------------------------------------------------------------------------
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/
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1 of 2] consolidate x86 user makefiles
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 ` jyoung5-r/Jw6+rmf7HQT0dZR+AlfA
2007-10-24 14:32 ` [kvm-ppc-devel] " Hollis Blanchard
2007-10-24 3:26 ` [PATCH 2 of 2] Move all x86 specific tests to there own directory jyoung5-r/Jw6+rmf7HQT0dZR+AlfA
2007-10-25 18:12 ` [PATCH 0 of 2] [v2] Another attempt to Consolidate x86 makefiles & tests Avi Kivity
2 siblings, 1 reply; 10+ messages in thread
From: jyoung5-r/Jw6+rmf7HQT0dZR+AlfA @ 2007-10-24 3:26 UTC (permalink / raw)
To: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
Cc: kvm-ppc-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
# HG changeset patch
# User Jerone Young <jyoung5-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
# Date 1193196215 18000
# Node ID 556d8fcfcbd72586111f58a1914210e85a9a9d8a
# Parent 707451c0b5ab24ac40bf29885c1b660201eae203
consolidate x86 user makefiles
This patch removes arch specific make rules for x86 & x86-64 out of the
main Makefile. These rules are now moved into config-$(ARCH) and a new
file config-x86-common has been created to consolidate common rules
amongst x86 & x86-64.
This version takes comments from the list into consideration.
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
@@ -15,8 +15,7 @@ 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 += -I $(KERNELDIR)/include $(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, "")
@@ -25,21 +24,6 @@ CXXFLAGS = $(autodepend-flags)
CXXFLAGS = $(autodepend-flags)
autodepend-flags = -MMD -MF $(dir $*).$(notdir $*).d
-
-all: kvmctl libkvm.a flatfiles
-
-kvmctl: LDFLAGS += -pthread -lrt
-
-kvmctl: kvmctl.o main.o
-
-balloon_ctl: balloon_ctl.o
-
-libkvm.a: kvmctl.o
- $(AR) rcs $@ $^
-
-flatfiles-common = test/bootstrap test/vmexit.flat test/smp.flat
-
-flatfiles: $(flatfiles-common) $(flatfiles)
install:
install -D kvmctl.h $(DESTDIR)/$(PREFIX)/include/kvmctl.h
diff --git a/user/config-i386.mak b/user/config-i386.mak
--- a/user/config-i386.mak
+++ b/user/config-i386.mak
@@ -3,5 +3,9 @@ bits = 32
bits = 32
ldarch = elf32-i386
CFLAGS += -m32
+CFLAGS += -D__i386__
+CFLAGS += -I $(KERNELDIR)/include
-flatfiles=
+flatfile_tests=
+
+include config-x86-common.mak
diff --git a/user/config-x86-common.mak b/user/config-x86-common.mak
new file mode 100644
--- /dev/null
+++ b/user/config-x86-common.mak
@@ -0,0 +1,16 @@
+#This is a make file with common rules for both x86 & x86-64
+
+all: kvmctl libkvm.a flatfiles
+
+kvmctl: LDFLAGS += -pthread -lrt
+
+kvmctl: kvmctl.o main.o
+
+libkvm.a: kvmctl.o
+ $(AR) rcs $@ $^
+
+balloon_ctl: balloon_ctl.o
+
+flatfiles_tests-common = test/bootstrap test/vmexit.flat test/smp.flat
+
+flatfiles: $(flatfiles_tests-common) $(flatfile_tests))
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
@@ -3,5 +3,9 @@ bits = 64
bits = 64
ldarch = elf64-x86-64
CFLAGS += -m64
+CFLAGS += -D__x86_64__
+CFLAGS += -I $(KERNELDIR)/include
-flatfiles = test/access.flat test/irq.flat test/sieve.flat test/simple.flat test/stringio.flat test/memtest1.flat
+flatfile_tests = test/access.flat test/irq.flat test/sieve.flat test/simple.flat test/stringio.flat test/memtest1.flat
+
+include config-x86-common.mak
-------------------------------------------------------------------------
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/
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 2 of 2] Move all x86 specific tests to there own directory
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 3:26 ` jyoung5-r/Jw6+rmf7HQT0dZR+AlfA
2007-10-24 14:32 ` [kvm-ppc-devel] " Hollis Blanchard
2007-10-25 18:12 ` [PATCH 0 of 2] [v2] Another attempt to Consolidate x86 makefiles & tests Avi Kivity
2 siblings, 1 reply; 10+ messages in thread
From: jyoung5-r/Jw6+rmf7HQT0dZR+AlfA @ 2007-10-24 3:26 UTC (permalink / raw)
To: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
Cc: kvm-ppc-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
# 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/
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [kvm-ppc-devel] [PATCH 2 of 2] Move all x86 specific tests to there own directory
2007-10-24 3:26 ` [PATCH 2 of 2] Move all x86 specific tests to there own directory jyoung5-r/Jw6+rmf7HQT0dZR+AlfA
@ 2007-10-24 14:32 ` Hollis Blanchard
0 siblings, 0 replies; 10+ messages in thread
From: Hollis Blanchard @ 2007-10-24 14:32 UTC (permalink / raw)
To: jyoung5-r/Jw6+rmf7HQT0dZR+AlfA
Cc: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
kvm-ppc-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
On Tue, 2007-10-23 at 22:26 -0500, jyoung5-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org wrote:
>
> Move all x86 specific tests to there own directory.
>
> Signed-off-by: Jerone Young <jyoung5-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
Acked-by: Hollis Blanchard <hollisb-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
--
Hollis Blanchard
IBM Linux Technology Center
-------------------------------------------------------------------------
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/
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [kvm-ppc-devel] [PATCH 1 of 2] consolidate x86 user makefiles
2007-10-24 3:26 ` [PATCH 1 of 2] consolidate x86 user makefiles jyoung5-r/Jw6+rmf7HQT0dZR+AlfA
@ 2007-10-24 14:32 ` Hollis Blanchard
0 siblings, 0 replies; 10+ messages in thread
From: Hollis Blanchard @ 2007-10-24 14:32 UTC (permalink / raw)
To: jyoung5-r/Jw6+rmf7HQT0dZR+AlfA
Cc: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
kvm-ppc-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
On Tue, 2007-10-23 at 22:26 -0500, jyoung5-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org wrote:
>
> This patch removes arch specific make rules for x86 & x86-64 out of
> the
> main Makefile. These rules are now moved into config-$(ARCH) and a new
> file config-x86-common has been created to consolidate common rules
> amongst x86 & x86-64.
>
> This version takes comments from the list into consideration.
>
> Signed-off-by: Jerone Young <jyoung5-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
Acked-by: Hollis Blanchard <hollisb-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
--
Hollis Blanchard
IBM Linux Technology Center
-------------------------------------------------------------------------
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/
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 0 of 2] [v2] Another attempt to Consolidate x86 makefiles & tests
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 3:26 ` [PATCH 2 of 2] Move all x86 specific tests to there own directory jyoung5-r/Jw6+rmf7HQT0dZR+AlfA
@ 2007-10-25 18:12 ` Avi Kivity
[not found] ` <4720DC70.6090607-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2 siblings, 1 reply; 10+ messages in thread
From: Avi Kivity @ 2007-10-25 18:12 UTC (permalink / raw)
To: jyoung5-r/Jw6+rmf7HQT0dZR+AlfA
Cc: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
kvm-ppc-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
jyoung5-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org wrote:
> This is the acutally the 3rd attempt.
>
> These patches consolidate the make files & tests in user director for x86. This
> is to allow other architectures easier integration into the kvm source.
>
>
Food fight seems to have died down, so I applied both. But please:
- generate patches with '-M' to detect renames. those file moves would
have been much easier on the old eyes.
- make sure your patches don't add trailing whitespace
--
error compiling committee.c: too many arguments to function
-------------------------------------------------------------------------
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/
^ permalink raw reply [flat|nested] 10+ messages in thread
* userspace repositories
[not found] ` <4720DC70.6090607-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
@ 2007-10-25 18:37 ` Hollis Blanchard
2007-10-25 18:40 ` Avi Kivity
0 siblings, 1 reply; 10+ messages in thread
From: Hollis Blanchard @ 2007-10-25 18:37 UTC (permalink / raw)
To: Avi Kivity
Cc: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
kvm-ppc-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
Avi, what do you think about breaking the kvm-userspace repository into
separate kvm-qemu, kvmctl, and libkvm repositories?
--
Hollis Blanchard
IBM Linux Technology Center
-------------------------------------------------------------------------
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/
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: userspace repositories
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>
0 siblings, 1 reply; 10+ messages in thread
From: Avi Kivity @ 2007-10-25 18:40 UTC (permalink / raw)
To: Hollis Blanchard
Cc: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
kvm-ppc-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
Hollis Blanchard wrote:
> Avi, what do you think about breaking the kvm-userspace repository into
> separate kvm-qemu, kvmctl, and libkvm repositories?
>
>
Firstly, I think kvmctl and libkvm should stay together.
I'm not thrilled about breaking up the repositories even more; it makes
bisecting more difficult. Perhaps git's module support can help here.
--
error compiling committee.c: too many arguments to function
-------------------------------------------------------------------------
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/
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: userspace repositories
[not found] ` <4720E312.3060400-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
@ 2007-10-25 19:01 ` Hollis Blanchard
2007-10-25 19:03 ` Avi Kivity
0 siblings, 1 reply; 10+ messages in thread
From: Hollis Blanchard @ 2007-10-25 19:01 UTC (permalink / raw)
To: Avi Kivity
Cc: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
kvm-ppc-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
On Thu, 2007-10-25 at 20:40 +0200, Avi Kivity wrote:
> Hollis Blanchard wrote:
> > Avi, what do you think about breaking the kvm-userspace repository into
> > separate kvm-qemu, kvmctl, and libkvm repositories?
>
> Firstly, I think kvmctl and libkvm should stay together.
Why? As far as I can see, there are currently two independent consumers
of libkvm: qemu and kvmctl. At the very least they should live in
separate directories.
Also, having libkvm on its own means that only one package has to
include kernel headers and deal with that configure mess. The userspace
apps really have no need for that...
--
Hollis Blanchard
IBM Linux Technology Center
-------------------------------------------------------------------------
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/
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: userspace repositories
2007-10-25 19:01 ` Hollis Blanchard
@ 2007-10-25 19:03 ` Avi Kivity
0 siblings, 0 replies; 10+ messages in thread
From: Avi Kivity @ 2007-10-25 19:03 UTC (permalink / raw)
To: Hollis Blanchard
Cc: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
kvm-ppc-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
Hollis Blanchard wrote:
> On Thu, 2007-10-25 at 20:40 +0200, Avi Kivity wrote:
>
>> Hollis Blanchard wrote:
>>
>>> Avi, what do you think about breaking the kvm-userspace repository into
>>> separate kvm-qemu, kvmctl, and libkvm repositories?
>>>
>> Firstly, I think kvmctl and libkvm should stay together.
>>
>
> Why? As far as I can see, there are currently two independent consumers
> of libkvm: qemu and kvmctl. At the very least they should live in
> separate directories.
>
>
They're both small, and tied up together. I'd rather support one small
package than two small packages.
Agree about separate directories.
> Also, having libkvm on its own means that only one package has to
> include kernel headers and deal with that configure mess. The userspace
> apps really have no need for that...
>
kvmctl is intended to be a small test driver, no more.
--
error compiling committee.c: too many arguments to function
-------------------------------------------------------------------------
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/
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2007-10-25 19:03 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [PATCH 2 of 2] Move all x86 specific tests to there own directory jyoung5-r/Jw6+rmf7HQT0dZR+AlfA
2007-10-24 14:32 ` [kvm-ppc-devel] " 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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox