From patchwork Tue Jan 21 16:21:59 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Jones X-Patchwork-Id: 3519021 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 9E59C9F2E9 for ; Tue, 21 Jan 2014 16:24:15 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 11FCD2015A for ; Tue, 21 Jan 2014 16:24:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5090C20155 for ; Tue, 21 Jan 2014 16:24:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754972AbaAUQYH (ORCPT ); Tue, 21 Jan 2014 11:24:07 -0500 Received: from mx1.redhat.com ([209.132.183.28]:2050 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752730AbaAUQYF (ORCPT ); Tue, 21 Jan 2014 11:24:05 -0500 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s0LGMRsu007857 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Tue, 21 Jan 2014 11:22:28 -0500 Received: from hawk.usersys.redhat.com.com (dhcp-1-167.brq.redhat.com [10.34.1.167]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id s0LGM6NZ007833; Tue, 21 Jan 2014 11:22:26 -0500 From: Andrew Jones To: kvmarm@lists.cs.columbia.edu, kvm@vger.kernel.org Cc: christoffer.dall@linaro.org Subject: [PATCH 13/17] arm: initial drop Date: Tue, 21 Jan 2014 17:21:59 +0100 Message-Id: <1390321323-1855-14-git-send-email-drjones@redhat.com> In-Reply-To: <1390321323-1855-1-git-send-email-drjones@redhat.com> References: <1390321323-1855-1-git-send-email-drjones@redhat.com> X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Spam-Status: No, score=-7.5 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This is the initial arm test framework and a first simple test that checks some bootinfo. kvm isn't needed to run this test. This patch also adds a common build environment variable, $QEMU_BIN, which allows makefiles to call on qemu when needed. Try it out with yum install gcc-arm-linux-gnu dtc export QEMU=[qemu with mach-virt and virtio-testdev] ./configure --cross-prefix=arm-linux-gnu- --arch=arm make ./run_tests.sh Signed-off-by: Andrew Jones Reviewed-by: Christoffer Dall --- v3: - switched to device tree - renamed arm/boot.c to arm/selftest.c - dropped attempt at big endian detection - dropped lib/test_util.* - fixed Christoffer's nits v2: - add eabi utility functions needed for some toolchains, this allows us to drop the divmod hacks that were in v1 - switch to kernel coding style - some refactoring of setup code for heap init - some refactoring of the simple bootinfo test for clarity and reuse opportunity - update base addr for the new mach-virt version --- arm/cstart.S | 28 +++++++++++++++++++++ arm/flat.lds | 18 ++++++++++++++ arm/run | 19 +++++++++++++++ arm/selftest.c | 30 +++++++++++++++++++++++ arm/unittests.cfg | 11 +++++++++ config/config-arm.mak | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++ configure | 10 ++++++-- lib/argv.c | 6 +++++ lib/arm/eabi_compat.c | 20 +++++++++++++++ lib/arm/io.c | 44 +++++++++++++++++++++++++++++++++ lib/arm/io.h | 21 ++++++++++++++++ lib/arm/setup.c | 46 +++++++++++++++++++++++++++++++++++ lib/arm/sysinfo.h | 12 +++++++++ lib/libio.h | 4 +++ 14 files changed, 334 insertions(+), 2 deletions(-) create mode 100644 arm/cstart.S create mode 100644 arm/flat.lds create mode 100755 arm/run create mode 100644 arm/selftest.c create mode 100644 arm/unittests.cfg create mode 100644 config/config-arm.mak create mode 100644 lib/arm/eabi_compat.c create mode 100644 lib/arm/io.c create mode 100644 lib/arm/io.h create mode 100644 lib/arm/setup.c create mode 100644 lib/arm/sysinfo.h diff --git a/arm/cstart.S b/arm/cstart.S new file mode 100644 index 0000000000000..4de04b62c28c2 --- /dev/null +++ b/arm/cstart.S @@ -0,0 +1,28 @@ + +.arm + +.section .init + +.globl start +start: + /* + * bootloader params are in r0-r2 + * See the kernel doc Documentation/arm/Booting + */ + ldr sp, =stacktop + bl setup + + /* start the test */ + ldr r0, =__argc + ldr r0, [r0] + ldr r1, =__argv + bl main + bl exit + b halt + +.text + +.globl halt +halt: +1: wfi + b 1b diff --git a/arm/flat.lds b/arm/flat.lds new file mode 100644 index 0000000000000..3e5d72e24989b --- /dev/null +++ b/arm/flat.lds @@ -0,0 +1,18 @@ + +SECTIONS +{ + .text : { *(.init) *(.text) *(.text.*) } + . = ALIGN(4K); + .data : { *(.data) } + . = ALIGN(16); + .rodata : { *(.rodata) } + . = ALIGN(16); + .bss : { *(.bss) } + . = ALIGN(4K); + edata = .; + . += 8K; + . = ALIGN(4K); + stacktop = .; +} + +ENTRY(start) diff --git a/arm/run b/arm/run new file mode 100755 index 0000000000000..64446e8907564 --- /dev/null +++ b/arm/run @@ -0,0 +1,19 @@ +#!/bin/bash + +qemu="${QEMU:-qemu-system-arm}" +testdev='virtio-testdev' + +if ! $qemu -device '?' 2>&1 | grep $testdev > /dev/null; then + echo \"$qemu\" has no support for the virtio test device. Exiting. + exit 2 +fi + +command="$qemu -device $testdev -display none -serial stdio " +command+="-M virt -cpu cortex-a15 " +#command+="-enable-kvm " +command+="-kernel" +echo $command "$@" +$command "$@" +ret=$? +echo Return value from qemu: $ret +exit $ret diff --git a/arm/selftest.c b/arm/selftest.c new file mode 100644 index 0000000000000..3d47a16cbcfad --- /dev/null +++ b/arm/selftest.c @@ -0,0 +1,30 @@ +#include "libcflat.h" +#include "arm/sysinfo.h" + +#define PASS 0 +#define FAIL 1 + +static void assert_enough_args(int nargs, int needed) +{ + if (nargs < needed) { + printf("Not enough arguments.\n"); + exit(EINVAL); + } +} + +int main(int argc, char **argv) +{ + int ret = FAIL; + + assert_enough_args(argc, 1); + + if (strcmp(argv[0], "mem") == 0) { + + assert_enough_args(argc, 2); + + if (mem_size/1024/1024 == (size_t)atol(argv[1])) + ret = PASS; + } + + return ret; +} diff --git a/arm/unittests.cfg b/arm/unittests.cfg new file mode 100644 index 0000000000000..aff684892e90b --- /dev/null +++ b/arm/unittests.cfg @@ -0,0 +1,11 @@ +# Define your new unittest following the convention: +# [unittest_name] +# file = foo.flat # Name of the flat file to be used +# smp = 2 # Number of processors the VM will use during this test +# extra_params = -append # Additional parameters used +# arch = arm/arm64 # Only if the test case works only on one of them +# groups = group1 group2 # Used to identify test cases with run_tests -g ... + +[selftest] +file = selftest.flat +extra_params = -m 256 -append 'mem 256' diff --git a/config/config-arm.mak b/config/config-arm.mak new file mode 100644 index 0000000000000..3480003f0ac13 --- /dev/null +++ b/config/config-arm.mak @@ -0,0 +1,67 @@ +mach = mach-virt +iodevs = pl011 virtio_mmio +phys_base = 0x40000000 + +cstart.o = $(TEST_DIR)/cstart.o +bits = 32 +ldarch = elf32-littlearm +kernel_offset = 0x10000 +CFLAGS += -D__arm__ + +all: test_cases + +cflatobjs += \ + lib/heap.o \ + lib/devicetree.o \ + lib/virtio.o \ + lib/virtio-testdev.o \ + lib/arm/io.o \ + lib/arm/setup.o + +libeabi := lib/arm/libeabi.a +eabiobjs += \ + lib/arm/eabi_compat.o + +includedirs = -I lib -I lib/libfdt + +$(libcflat) $(libeabi): LDFLAGS += -nostdlib +$(libcflat) $(libeabi): CFLAGS += -ffreestanding $(includedirs) + +CFLAGS += -Wextra +CFLAGS += -marm +CFLAGS += -O2 +ifeq ($(PROCESSOR), $(ARCH)) + # PROCESSOR=ARCH is the default, but there is no 'arm' cpu + CFLAGS += -mcpu=cortex-a15 +else + CFLAGS += -mcpu=$(PROCESSOR) +endif + +libgcc := $(shell $(CC) -m$(ARCH) --print-libgcc-file-name) +start_addr := $(shell printf "%x\n" $$(( $(phys_base) + $(kernel_offset) ))) + +FLATLIBS = $(libcflat) $(LIBFDT_archive) $(libgcc) $(libeabi) +%.elf: %.o $(FLATLIBS) arm/flat.lds + $(CC) $(CFLAGS) -nostdlib -o $@ \ + -Wl,-T,arm/flat.lds,--build-id=none,-Ttext=$(start_addr) \ + $(filter %.o, $^) $(FLATLIBS) + +$(libeabi): $(eabiobjs) + $(AR) rcs $@ $^ + +%.flat: %.elf + $(OBJCOPY) -O binary $^ $@ + +tests-common = $(TEST_DIR)/selftest.flat + +tests_and_config = $(TEST_DIR)/*.flat $(TEST_DIR)/unittests.cfg + +test_cases: $(tests-common) $(tests) + +$(TEST_DIR)/%.o: CFLAGS += -std=gnu99 -ffreestanding $(includedirs) + +$(TEST_DIR)/selftest.elf: $(cstart.o) $(TEST_DIR)/selftest.o + +arch_clean: libfdt_clean + $(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat $(TEST_DIR)/*.elf \ + $(libeabi) $(eabiobjs) $(TEST_DIR)/.*.d lib/arm/.*.d diff --git a/configure b/configure index 6cfc64943f6e6..6df7caad89432 100755 --- a/configure +++ b/configure @@ -6,8 +6,7 @@ cc=gcc ld=ld objcopy=objcopy ar=ar -arch=`uname -m | sed -e s/i.86/i386/` -processor="$arch" +arch=`uname -m | sed -e s/i.86/i386/ | sed -e 's/arm.*/arm/'` cross_prefix= usage() { @@ -17,6 +16,7 @@ usage() { Options include: --test-dir=DIR the main directory for tests ($arch) --arch=ARCH architecture to compile for ($arch) + --processor=PROCESSOR processor to compile for ($arch) --cross-prefix=PREFIX cross compiler prefix --cc=CC c compiler to use ($cc) --ld=LD ld linker to use ($ld) @@ -66,6 +66,9 @@ while [[ "$1" = -* ]]; do ;; esac done +[ -z "$processor" ] && processor="$arch" +qemu="${QEMU:-qemu-system-$arch}" + if [ -z "$testdir" -a \( "$arch" = "i386" -o "$arch" = "x86_64" \) ]; then testdir=x86 elif [ -z "$testdir" ]; then @@ -80,6 +83,7 @@ if [ -f $testdir/run ]; then fi # check for dependent 32 bit libraries +if [ "$arch" = "i386" -o "$arch" = "x86_64" ]; then cat << EOF > lib_test.c #include #include @@ -94,6 +98,7 @@ if [ $exit -eq 0 ]; then api=true fi rm -f lib_test.c +fi cat < config.mak PREFIX=$prefix @@ -106,4 +111,5 @@ OBJCOPY=$cross_prefix$objcopy AR=$cross_prefix$ar API=$api TEST_DIR=$testdir +QEMU=$qemu EOF diff --git a/lib/argv.c b/lib/argv.c index 4ee54a6eeac3e..078a05faffebf 100644 --- a/lib/argv.c +++ b/lib/argv.c @@ -31,3 +31,9 @@ void __setup_args(void) } __argc = argv - __argv; } + +void setup_args(char *args) +{ + __args = args; + __setup_args(); +} diff --git a/lib/arm/eabi_compat.c b/lib/arm/eabi_compat.c new file mode 100644 index 0000000000000..76e04f5543ee1 --- /dev/null +++ b/lib/arm/eabi_compat.c @@ -0,0 +1,20 @@ +/* + * Adapted from u-boot's arch/arm/lib/eabi_compat.c + */ +#include "libcflat.h" + +int raise(int signum __unused) +{ + printf("Divide by zero!\n"); + exit(ERANGE); + return 0; +} + +/* Dummy functions to avoid linker complaints */ +void __aeabi_unwind_cpp_pr0(void) +{ +} + +void __aeabi_unwind_cpp_pr1(void) +{ +} diff --git a/lib/arm/io.c b/lib/arm/io.c new file mode 100644 index 0000000000000..245595b05504a --- /dev/null +++ b/lib/arm/io.c @@ -0,0 +1,44 @@ +#include "libcflat.h" +#include "libio.h" +#include "devicetree.h" +#include "virtio-testdev.h" + +/* + * Use this guess for the pl011 base in order to make an attempt at + * having earlier printf support. We'll overwrite it with the real + * base address that we read from the devicetree later. + */ +#define QEMU_MACH_VIRT_PL011_BASE 0x09000000UL + +static volatile u8 *uart0_base = (u8 *)QEMU_MACH_VIRT_PL011_BASE; + +void puts(const char *s) +{ + while (*s) + writel(*s++, uart0_base); +} + +void exit(int code) +{ + virtio_testdev_exit(code); + halt(code); +} + +void io_init(void) +{ + int node; + + node = dt_bus_find_device_compatible(&dt_default_bus, "arm,pl011"); + if (node < 0) { + printf("can't find pl011 in device tree!\n"); + exit(ENXIO); + } + + if (dt_bus_translate_reg(node, &dt_default_bus, 0, + (void **)&uart0_base, NULL) < 0) { + printf("can't set uart0_base!\n"); + exit(ENXIO); + } + + virtio_testdev_init(); +} diff --git a/lib/arm/io.h b/lib/arm/io.h new file mode 100644 index 0000000000000..0284552f6ef1f --- /dev/null +++ b/lib/arm/io.h @@ -0,0 +1,21 @@ +#ifndef _ARM_IO_H_ +#define _ARM_IO_H_ + +#define __bswap16 bswap16 +static inline u16 bswap16(u16 val) +{ + u16 ret; + asm volatile("rev16 %0, %1" : "=r" (ret) : "r" (val)); + return ret; +} + +#define __bswap32 bswap32 +static inline u32 bswap32(u32 val) +{ + u32 ret; + asm volatile("rev %0, %1" : "=r" (ret) : "r" (val)); + return ret; +} + +#include "libio.h" +#endif diff --git a/lib/arm/setup.c b/lib/arm/setup.c new file mode 100644 index 0000000000000..1db249a1eb94c --- /dev/null +++ b/lib/arm/setup.c @@ -0,0 +1,46 @@ +#include "libcflat.h" +#include "devicetree.h" +#include "arm/sysinfo.h" +#include "heap.h" + +extern void io_init(void); +extern void setup_args(char *args); + +extern unsigned long stacktop; + +void *mem_start; +size_t mem_size; +char *bootargs; + +static void read_bootinfo(const void *fdt) +{ + int ret; + + if ((ret = dt_set(fdt)) != 0) { + printf("setup: fdt sanity checks failed! " + "fdt_error: %s\n", dt_strerror(ret)); + exit(ENOEXEC); + } + + if ((ret = dt_get_bootargs_ptr(&bootargs)) < 0) { + printf("fdt failure: %s\n", dt_strerror(ret)); + exit(ENOEXEC); + } + + if ((ret = dt_get_memory_params(&mem_start, &mem_size)) < 0) { + printf("setup: can't find memory params! " + "fdt_error: %s\n", dt_strerror(ret)); + exit(ENOEXEC); + } +} + +void setup(unsigned long arg __unused, unsigned long id __unused, + const void *fdt) +{ + read_bootinfo(fdt); + heap_init(&stacktop, + (unsigned long)&stacktop - (unsigned long)mem_start, + PAGE_SIZE); + io_init(); + setup_args(bootargs); +} diff --git a/lib/arm/sysinfo.h b/lib/arm/sysinfo.h new file mode 100644 index 0000000000000..a990d406f2792 --- /dev/null +++ b/lib/arm/sysinfo.h @@ -0,0 +1,12 @@ +#ifndef _ARM_SYSINFO_H_ +#define _ARM_SYSINFO_H_ +#include "libcflat.h" + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#define PAGE_MASK (~((1 << PAGE_SHIFT) - 1)) + +extern void *mem_start; +extern size_t mem_size; +extern char *bootargs; +#endif diff --git a/lib/libio.h b/lib/libio.h index 6adc6a7bbee61..f34ad0036bf15 100644 --- a/lib/libio.h +++ b/lib/libio.h @@ -14,6 +14,10 @@ #define LIBIO_ASSERT(expr) do { } while (0) #endif +#ifdef __arm__ +#include "arm/io.h" +#endif + typedef u32 compat_ptr_t; /*