From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jerone Young Subject: [PATCH 2 of 2] This patch moves x86 specific tests to there own directory Date: Tue, 23 Oct 2007 15:42:00 -0500 Message-ID: <5cd9f474ff2b1e717527.1193172120@thinkpad> References: Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Cc: kvm-ppc-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org To: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org Return-path: In-Reply-To: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: kvm-devel-bounces-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org Errors-To: kvm-devel-bounces-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org List-Id: kvm.vger.kernel.org # HG changeset patch # User Jerone Young # Date 1193171508 18000 # Node ID 5cd9f474ff2b1e7175278d4bcd3e885f1b294d98 # Parent 4f7e88d410070f9b49236fad68533ca4352981f6 This patch moves x86 specific tests to there own directory. Signed-off-by: Jerone Young 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 #include 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 - -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 + +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/