From: Hollis B. <ho...@us...> - 2008-01-09 00:12:12
|
When applied after Jerone's kvm_create_kernel_phys_mem() libkvm patch, these patches get the kvm-userspace/user/ test harness building and somewhat working for PowerPC. For the moment it's just a simply binary loader (hence the need for objcopy), but in the future it should be easy to add an ELF or even uImage loader. 3 files changed, 449 insertions(+), 9 deletions(-) user/config-powerpc.mak | 30 ++- user/configure | 2 user/main-ppc.c | 426 +++++++++++++++++++++++++++++++++++++++++++++++ |
From: Hollis B. <ho...@us...> - 2008-01-09 00:09:44
|
# HG changeset patch # User Hollis Blanchard <ho...@us...> # Date 1199836243 21600 # Node ID 2b1946f501613724c363f98cbdfd95248b947657 # Parent 332daa1196f0a74d2ad3c34ed2ca41d5d859b0de Signed-off-by: Hollis Blanchard <ho...@us...> --- 1 file changed, 2 insertions(+) user/configure | 2 ++ diff --git a/user/configure b/user/configure --- a/user/configure +++ b/user/configure @@ -4,6 +4,7 @@ kerneldir=/lib/modules/$(uname -r)/build kerneldir=/lib/modules/$(uname -r)/build cc=gcc ld=ld +objcopy=objcopy arch=`uname -m | sed -e s/i.86/i386/` cross_prefix= @@ -63,4 +64,5 @@ ARCH=$arch ARCH=$arch CC=$cross_prefix$cc LD=$cross_prefix$ld +OBJCOPY=$cross_prefix$objcopy EOF |
From: Hollis B. <ho...@us...> - 2008-01-09 00:09:44
|
# HG changeset patch # User Hollis Blanchard <ho...@us...> # Date 1199836753 21600 # Node ID dd6de019e916f0cc2b4f75afb95a9d28323cb174 # Parent 2b1946f501613724c363f98cbdfd95248b947657 Signed-off-by: Hollis Blanchard <ho...@us...> --- 2 files changed, 447 insertions(+), 9 deletions(-) user/config-powerpc.mak | 30 ++- user/main-ppc.c | 426 +++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/user/config-powerpc.mak b/user/config-powerpc.mak --- a/user/config-powerpc.mak +++ b/user/config-powerpc.mak @@ -1,14 +1,26 @@ TEST_DIR=test/powerpc -TEST_DIR=test/powerpc CFLAGS += -m32 CFLAGS += -D__powerpc__ CFLAGS += -I $(KERNELDIR)/include +# for some reaons binutils hates tlbsx unless we say we're 405 :( +CFLAGS += -Wa,-mregnames,-m405 -tests= $(TEST_DIR)/io.S \ - $(TEST_DIR)/spin.S \ - $(TEST_DIR)/sprg.S \ - $(TEST_DIR)/44x/tlbsx.S \ - $(TEST_DIR)/44x/tlbwe_16KB.S \ - $(TEST_DIR)/44x/tlbwe_hole.S \ - $(TEST_DIR)/44x/tlbwe.S +%.bin: %.o + $(OBJCOPY) -O binary $^ $@ -kvmctl_objs = main.o ../libkvm/libkvm.a +testobjs := \ + io.bin \ + spin.bin \ + sprg.bin \ + 44x/tlbsx.bin \ + 44x/tlbwe_16KB.bin \ + 44x/tlbwe_hole.bin \ + 44x/tlbwe.bin + +tests := $(addprefix test/powerpc/, $(testobjs)) + +all: kvmctl $(tests) + +kvmctl_objs = main-ppc.o ../libkvm/libkvm.a + +arch_clean: + rm -f $(tests) diff --git a/user/main-ppc.c b/user/main-ppc.c new file mode 100644 --- /dev/null +++ b/user/main-ppc.c @@ -0,0 +1,426 @@ +/* + * Kernel-based Virtual Machine test driver + * + * This test driver provides a simple way of testing kvm, without a full + * device model. + * + * Copyright (C) 2006 Qumranet + * Copyright IBM Corp. 2008 + * + * Authors: + * + * Avi Kivity <av...@qu...> + * Yaniv Kamay <ya...@qu...> + * Hollis Blanchard <ho...@us...> + * + * This work is licensed under the GNU LGPL license, version 2. + */ + +#define _GNU_SOURCE + +#include <libkvm.h> + +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <semaphore.h> +#include <sys/types.h> +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <pthread.h> +#include <sys/syscall.h> +#include <linux/unistd.h> +#include <getopt.h> +#include <stdbool.h> +#include <inttypes.h> + +static int gettid(void) +{ + return syscall(__NR_gettid); +} + +kvm_context_t kvm; + +#define MAX_VCPUS 4 + +#define IPI_SIGNAL (SIGRTMIN + 4) + +#define MAX_IO_TABLE 50 + +typedef int (io_table_handler_t)(void *, int, int, uint64_t, uint64_t *); + +struct io_table_entry +{ + uint64_t start; + uint64_t end; + io_table_handler_t *handler; + void *opaque; +}; + +struct io_table +{ + int nr_entries; + struct io_table_entry entries[MAX_IO_TABLE]; +}; + +static int ncpus = 1; +static sem_t init_sem; +static __thread int vcpu; +static sigset_t kernel_sigmask; +static sigset_t ipi_sigmask; +static uint64_t memory_size = 128 * 1024 * 1024; + +static struct io_table pio_table; + +struct vcpu_info { + pid_t tid; +}; + +struct vcpu_info *vcpus; + +struct io_table_entry *io_table_lookup(struct io_table *io_table, uint64_t addr) +{ + int i; + + for (i = 0; i < io_table->nr_entries; i++) { + if (io_table->entries[i].start <= addr && + addr < io_table->entries[i].end) + return &io_table->entries[i]; + } + + return NULL; +} + +int io_table_register(struct io_table *io_table, uint64_t start, uint64_t size, + io_table_handler_t *handler, void *opaque) +{ + struct io_table_entry *entry; + + if (io_table->nr_entries == MAX_IO_TABLE) + return -ENOSPC; + + entry = &io_table->entries[io_table->nr_entries]; + io_table->nr_entries++; + + entry->start = start; + entry->end = start + size; + entry->handler = handler; + entry->opaque = opaque; + + return 0; +} + +static int misc_io(void *opaque, int size, int is_write, + uint64_t addr, uint64_t *value) +{ + static int newline = 1; + + if (!is_write) + *value = -1; + + switch (addr) { + case 0xff: // irq injector + if (is_write) { + printf("injecting interrupt 0x%x\n", (uint8_t)*value); + kvm_inject_irq(kvm, 0, *value); + } + break; + case 0xf1: // serial + if (is_write) { + if (newline) + fputs("GUEST: ", stdout); + putchar(*value); + newline = *value == '\n'; + } + break; + case 0xd1: + if (!is_write) + *value = memory_size; + break; + case 0xf4: // exit + if (is_write) + exit(*value); + break; + } + + return 0; +} + +static int misc_init(void) +{ + int err; + + err = io_table_register(&pio_table, 0xff, 1, misc_io, NULL); + if (err < 0) + return err; + + err = io_table_register(&pio_table, 0xf1, 1, misc_io, NULL); + if (err < 0) + return err; + + err = io_table_register(&pio_table, 0xf4, 1, misc_io, NULL); + if (err < 0) + return err; + + return io_table_register(&pio_table, 0xd1, 1, misc_io, NULL); +} + +static int test_debug(void *opaque, int vcpu) +{ + printf("test_debug\n"); + return 0; +} + +static int test_halt(void *opaque, int vcpu) +{ + int n; + + sigwait(&ipi_sigmask, &n); + return 0; +} + +static int test_io_window(void *opaque) +{ + return 0; +} + +static int test_try_push_interrupts(void *opaque) +{ + return 0; +} + +static void test_post_kvm_run(void *opaque, int vcpu) +{ +} + +static int test_pre_kvm_run(void *opaque, int vcpu) +{ + return 0; +} + +static int test_mem_read(void *opaque, uint64_t addr, uint8_t *data, int len) +{ + printf("%s: addr %"PRIx64" len %d\n", __func__, addr, len); + memset(data, 0, len); + return 0; +} + +static int test_mem_write(void *opaque, uint64_t addr, uint8_t *data, int len) +{ + printf("%s: addr %"PRIx64" len %d data %"PRIx64"\n", + __func__, addr, len, *(uint64_t *)data); + return 0; +} + +static struct kvm_callbacks test_callbacks = { + .mmio_read = test_mem_read, + .mmio_write = test_mem_write, + .debug = test_debug, + .halt = test_halt, + .io_window = test_io_window, + .try_push_interrupts = test_try_push_interrupts, + .post_kvm_run = test_post_kvm_run, + .pre_kvm_run = test_pre_kvm_run, +}; + +static unsigned long load_file(void *mem, const char *fname, int inval_icache) +{ + int r; + int fd; + unsigned long bytes = 0; + + fd = open(fname, O_RDONLY); + if (fd == -1) { + perror("open"); + exit(1); + } + + while ((r = read(fd, mem, 4096)) != -1 && r != 0) { + mem += r; + bytes += r; + } + + if (r == -1) { + perror("read"); + exit(1); + } + + return bytes; +} + +#define ICACHE_LINE_SIZE 32 + +void sync_caches(void *mem, unsigned long len) +{ + unsigned long i; + + for (i = 0; i < len; i += ICACHE_LINE_SIZE) + asm volatile ("dcbst %0, %1" : : "g"(mem), "r"(i)); + asm volatile ("sync"); + for (i = 0; i < len; i += ICACHE_LINE_SIZE) + asm volatile ("icbi %0, %1" : : "g"(mem), "r"(i)); + asm volatile ("sync; isync"); +} + +static void init_vcpu(int n, unsigned long entry) +{ + struct kvm_regs regs = { + .pc = entry, + }; + + kvm_set_regs(kvm, 0, ®s); + + sigemptyset(&ipi_sigmask); + sigaddset(&ipi_sigmask, IPI_SIGNAL); + sigprocmask(SIG_UNBLOCK, &ipi_sigmask, NULL); + sigprocmask(SIG_BLOCK, &ipi_sigmask, &kernel_sigmask); + vcpus[n].tid = gettid(); + vcpu = n; + kvm_set_signal_mask(kvm, n, &kernel_sigmask); + sem_post(&init_sem); +} + +static void *do_create_vcpu(void *_n) +{ + int n = (long)_n; + + kvm_create_vcpu(kvm, n); + init_vcpu(n, 0x0); + kvm_run(kvm, n); + return NULL; +} + +static void start_vcpu(int n) +{ + pthread_t thread; + + pthread_create(&thread, NULL, do_create_vcpu, (void *)(long)n); +} + +static void usage(const char *progname) +{ + fprintf(stderr, +"Usage: %s [OPTIONS] [bootstrap] flatfile\n" +"KVM test harness.\n" +"\n" +" -s, --smp=NUM create a VM with NUM virtual CPUs\n" +" -m, --memory=NUM[GMKB] allocate NUM memory for virtual machine. A suffix\n" +" can be used to change the unit (default: `M')\n" +" -h, --help display this help screen and exit\n" +"\n" +"Report bugs to <kvm...@li...>.\n" + , progname); +} + +static void sig_ignore(int sig) +{ + write(1, "boo\n", 4); +} + +int main(int argc, char **argv) +{ + void *vm_mem; + unsigned long len; + int i; + const char *sopts = "s:phm:"; + struct option lopts[] = { + { "smp", 1, 0, 's' }, + { "memory", 1, 0, 'm' }, + { "help", 0, 0, 'h' }, + { 0 }, + }; + int opt_ind, ch; + int nb_args; + char *endptr; + + while ((ch = getopt_long(argc, argv, sopts, lopts, &opt_ind)) != -1) { + switch (ch) { + case 's': + ncpus = atoi(optarg); + break; + case 'm': + memory_size = strtoull(optarg, &endptr, 0); + switch (*endptr) { + case 'G': case 'g': + memory_size <<= 30; + break; + case '\0': + case 'M': case 'm': + memory_size <<= 20; + break; + case 'K': case 'k': + memory_size <<= 10; + break; + default: + fprintf(stderr, + "Unrecongized memory suffix: %c\n", + *endptr); + exit(1); + } + if (memory_size == 0) { + fprintf(stderr, + "Invalid memory size: 0\n"); + exit(1); + } + break; + case 'h': + usage(argv[0]); + exit(0); + case '?': + default: + fprintf(stderr, + "Try `%s --help' for more information.\n", + argv[0]); + exit(1); + } + } + + nb_args = argc - optind; + if (nb_args < 1 || nb_args > 2) { + fprintf(stderr, + "Incorrect number of arguments.\n" + "Try `%s --help' for more information.\n", + argv[0]); + exit(1); + } + + signal(IPI_SIGNAL, sig_ignore); + + vcpus = calloc(ncpus, sizeof *vcpus); + if (!vcpus) { + fprintf(stderr, "calloc failed\n"); + return 1; + } + + kvm = kvm_init(&test_callbacks, 0); + if (!kvm) { + fprintf(stderr, "kvm_init failed\n"); + return 1; + } + if (kvm_create(kvm, memory_size, &vm_mem) < 0) { + kvm_finalize(kvm); + fprintf(stderr, "kvm_create failed\n"); + return 1; + } + + vm_mem = kvm_create_phys_mem(kvm, 0, memory_size, 0, 1); + + len = load_file(vm_mem, argv[optind], 1); + sync_caches(vm_mem, len); + + misc_init(); + + sem_init(&init_sem, 0, 0); + init_vcpu(0, 0x0); + for (i = 1; i < ncpus; ++i) + start_vcpu(i); + for (i = 0; i < ncpus; ++i) + sem_wait(&init_sem); + + kvm_run(kvm, 0); + + return 0; +} |
From: Avi K. <av...@qu...> - 2008-01-09 08:51:18
|
Hollis Blanchard wrote: > + > +static int misc_init(void) > +{ > + int err; > + > + err = io_table_register(&pio_table, 0xff, 1, misc_io, NULL); > + if (err < 0) > + return err; > + > + err = io_table_register(&pio_table, 0xf1, 1, misc_io, NULL); > + if (err < 0) > + return err; > + > + err = io_table_register(&pio_table, 0xf4, 1, misc_io, NULL); > + if (err < 0) > + return err; > + > + return io_table_register(&pio_table, 0xd1, 1, misc_io, NULL); > +} > I thought ppc doesn't have pio (and certainly doesn't need the random hacks above)? While it's okay to not share code with x86 for the test harness, at least remove the x86 specific parts. -- error compiling committee.c: too many arguments to function |