From: Jerone Young <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] This patch moves x86 specific tests to there own directory
Date: Tue, 23 Oct 2007 15:42:00 -0500 [thread overview]
Message-ID: <5cd9f474ff2b1e717527.1193172120@thinkpad> (raw)
In-Reply-To: <patchbomb.1193172118@thinkpad>
# HG changeset patch
# User Jerone Young <jyoung5-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
# Date 1193171508 18000
# Node ID 5cd9f474ff2b1e7175278d4bcd3e885f1b294d98
# Parent 4f7e88d410070f9b49236fad68533ca4352981f6
This patch moves 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,13 +17,13 @@ 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
@@ -36,29 +38,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,5 +1,6 @@ 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
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
@@ -11,6 +11,33 @@ libkvm.a: kvmctl.o
balloon_ctl: balloon_ctl.o
-flatfiles_tests-common = test/bootstrap test/vmexit.flat test/smp.flat
+flatfiles_tests-common = $(TEST_DIR)/bootstrap \
+ $(TEST_DIR)/vmexit.flat \
+ $(TEST_DIR)/smp.flat
-flatfiles: $(flatfiles_tests-common) $(flatfile_tests))
+flatfiles: $(flatfiles_tests-common) $(flatfile_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,5 +1,6 @@ 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
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/
prev parent reply other threads:[~2007-10-23 20:42 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-10-23 20:41 [PATCH 0 of 2] x86 user directory refactoring Jerone Young
2007-10-23 20:41 ` [PATCH 1 of 2] [mq]: x86_user_make_changes Jerone Young
2007-10-23 21:10 ` [kvm-ppc-devel] " Hollis Blanchard
2007-10-24 2:55 ` Jerone Young
2007-10-23 20:42 ` Jerone Young [this message]
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=5cd9f474ff2b1e717527.1193172120@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.