On Mon, Oct 14, 2013 at 06:23:34PM +0200, Andrew Jones wrote: > This is the initial arm test infrastructure and a first test that > simply 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 <drjones@xxxxxxxxxx> > --- > arm/boot.c | 27 ++++++++++++++++++++ > arm/cstart.S | 47 ++++++++++++++++++++++++++++++++++ > arm/flat.lds | 18 +++++++++++++ > arm/run | 19 ++++++++++++++ > arm/unittests.cfg | 11 ++++++++ > config/config-arm.mak | 62 +++++++++++++++++++++++++++++++++++++++++++++ > configure | 10 ++++++-- > lib/arm/bootinfo.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++ > lib/arm/bootinfo.h | 19 ++++++++++++++ > lib/arm/bswap.h | 30 ++++++++++++++++++++++ > lib/arm/io.c | 26 +++++++++++++++++++ > lib/bswap.h | 4 +++ > lib/libcflat.h | 1 + > 13 files changed, 342 insertions(+), 2 deletions(-) > create mode 100644 arm/boot.c > create mode 100644 arm/cstart.S > create mode 100644 arm/flat.lds > create mode 100755 arm/run > create mode 100644 arm/unittests.cfg > create mode 100644 config/config-arm.mak > create mode 100644 lib/arm/bootinfo.c > create mode 100644 lib/arm/bootinfo.h > create mode 100644 lib/arm/bswap.h > create mode 100644 lib/arm/io.c > > diff --git a/arm/boot.c b/arm/boot.c > new file mode 100644 > index 0000000000000..375e8708a7c54 this file's indentation is also funny, you should really check your editor configuration :) > --- /dev/null > +++ b/arm/boot.c > @@ -0,0 +1,27 @@ > +#include "libcflat.h" > +#include "arm/bootinfo.h" > + > +static bool info_check(u32 var, char *expected) > +{ > + char var_str[9]; > + snprintf(var_str, 9, "%x", var); > + while (*expected == '0' || *expected == 'x') > + ++expected; > + return !strcmp(var_str, expected); > +} > + > +int main(int argc, char **argv) > +{ > + int ret = 0; > + > + if (argc < 3) { > + printf("Not enough arguments. Can't test\n"); > + return 1; > + } > + > + if (!strcmp(argv[0], "info")) > + ret = !info_check(mem32.size, argv[1]) > + || !info_check(core.pagesize, argv[2]); > + > + return ret; > +} I'm actually a little confused, when does this main get invoked and by whom and what are we testing for here? > diff --git a/arm/cstart.S b/arm/cstart.S > new file mode 100644 > index 0000000000000..a65809824d4f1 > --- /dev/null > +++ b/arm/cstart.S > @@ -0,0 +1,47 @@ > + > +#define CR_B (1 << 7) > + > +.arm > + > +.section .init > + > +.globl start > +start: > + /* bootloader params are in r0-r2 */ > + ldr sp, =stacktop > + push { r0-r3 } @push r3 too for 8-byte alignment > + > + mrc p15, 0, r8, c1, c0, 0 @r8 = sctrl > + bl get_endianness > + bl io_init > + > + pop { r0-r3 } > + bl read_bootinfo > + bl __setup_args > + ldr r0, =__argc > + ldr r0, [r0] > + ldr r1, =__argv > + bl main > + bl exit > + b halt > + > +get_endianness: > + and r0, r8, #CR_B > + cmp r0, #0 > + beq 1f > + ldr r1, =cpu_is_be > + mov r0, #1 > + str r0, [r1] > +1: mov pc, lr > + > +.text > + > +.globl halt > +halt: > +1: wfi > + b 1b > + > +.data > + > +.globl cpu_is_be > +cpu_is_be: .word 0 > 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/unittests.cfg b/arm/unittests.cfg > new file mode 100644 > index 0000000000000..fb78cd906839a > --- /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 <params...> # 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 ... > + > +[boot_info] > +file = boot.flat > +extra_params = -m 256 -append 'info 0x10000000 0x1000' > diff --git a/config/config-arm.mak b/config/config-arm.mak > new file mode 100644 > index 0000000000000..066b1f725c5b3 > --- /dev/null > +++ b/config/config-arm.mak > @@ -0,0 +1,62 @@ > +mach = mach-virt > +iodevs = pl011 virtio_mmio > +phys_base = 0x8000000 > + > +cstart.o = $(TEST_DIR)/cstart.o > +bits = 32 > +ldarch = elf32-littlearm > +kernel_offset = 0x10000 > +CFLAGS += -D__arm__ > + > +all: test_cases > + > +cflatobjs += \ > + lib/$(TEST_DIR)/iomaps.gen.o \ > + lib/iomaps.o \ > + lib/virtio-testdev.o \ > + lib/arm/io.o \ > + lib/arm/bootinfo.o > + > +$(libcflat): LDFLAGS += -nostdlib > +$(libcflat): CFLAGS += -ffreestanding -I lib > + > +CFLAGS += -Wextra > +CFLAGS += -marm > +#CFLAGS += -mcpu=$(PROCESSOR) > +CFLAGS += -mcpu=cortex-a15 > +CFLAGS += -O2 > + > +libgcc := $(shell $(CC) -m$(ARCH) --print-libgcc-file-name) > +start_addr := $(shell printf "%x\n" $$(( $(phys_base) + $(kernel_offset) ))) > + > +FLATLIBS = lib/libcflat.a $(libgcc) > +%.elf: %.o $(FLATLIBS) arm/flat.lds > + $(CC) $(CFLAGS) -nostdlib -o $@ \ > + -Wl,-T,arm/flat.lds,--build-id=none,-Ttext=$(start_addr) \ > + $(filter %.o, $^) $(FLATLIBS) > + > +%.flat: %.elf > + $(OBJCOPY) -O binary $^ $@ > + > +tests-common = $(TEST_DIR)/boot.flat > + > +tests_and_config = $(TEST_DIR)/*.flat $(TEST_DIR)/unittests.cfg > + > +test_cases: $(tests-common) $(tests) > + > +$(TEST_DIR)/%.o: CFLAGS += -std=gnu99 -ffreestanding -I lib > + > +$(TEST_DIR)/boot.elf: $(cstart.o) $(TEST_DIR)/boot.o > + > +lib/$(TEST_DIR)/iomaps.gen.c: lib/$(TEST_DIR)/$(mach).dts > + scripts/gen-devtree-iomaps.pl $^ $(iodevs) > $@ > + > +lib/$(TEST_DIR)/mach-virt.dts: dtb = $(subst .dts,.dtb,$@) > +lib/$(TEST_DIR)/mach-virt.dts: > + $(QEMU_BIN) -kernel /dev/null -M virt -machine dumpdtb=$(dtb) > + fdtdump $(dtb) > $@ > + > +arch_clean: > + $(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat $(TEST_DIR)/*.elf \ > + $(TEST_DIR)/.*.d lib/arm/.*.d \ > + lib/$(TEST_DIR)/iomaps.gen.c lib/$(TEST_DIR)/mach-virt.* > diff --git a/configure b/configure > index 6cfc64943f6e6..296c70182ea1d 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 <stdc++.h> > #include <boost_thread-mt.h> > @@ -94,6 +98,7 @@ if [ $exit -eq 0 ]; then > api=true > fi > rm -f lib_test.c > +fi > > cat <<EOF > config.mak > PREFIX=$prefix > @@ -106,4 +111,5 @@ OBJCOPY=$cross_prefix$objcopy > AR=$cross_prefix$ar > API=$api > TEST_DIR=$testdir > +QEMU_BIN=$qemu > EOF > diff --git a/lib/arm/bootinfo.c b/lib/arm/bootinfo.c > new file mode 100644 > index 0000000000000..c362064f661d9 > --- /dev/null > +++ b/lib/arm/bootinfo.c > @@ -0,0 +1,70 @@ > +#include "libcflat.h" > +#include "arm/bootinfo.h" > +#include "arm/bswap.h" > + > +#define FDT_SIG 0xd00dfeed > + > +#define KERNEL_OFFSET 0x00010000 > +#define ATAG_OFFSET 0x00000100 > + > +#define ATAG_CORE 0x54410001 > +#define ATAG_MEM 0x54410002 > +#define ATAG_CMDLINE 0x54410009 > + > +extern void start(void); > +extern char *__args; > + > +u32 mach_type_id; > +struct tag_core core; > +struct tag_mem32 mem32; > + > +static void read_atags(u32 id, u32 *info) > +{ > + u32 *p = info; > + > + if (!p) { > + printf("Can't find bootinfo. mach-type = %x\n", id); > + exit(ENOEXEC); > + } > + > + /* > + * p[0] count of words for the tag > + * p[1] tag id > + * p[2..] tag data > + */ > + for (; p[0] != 0; p += p[0]) > + switch (p[1]) { > + case ATAG_CORE: > + core.flags = p[2]; > + core.pagesize = p[3]; > + core.rootdev = p[4]; > + break; > + case ATAG_MEM: > + mem32.size = p[2]; > + mem32.start = p[3]; > + break; > + case ATAG_CMDLINE: > + __args = (char *)&p[2]; > + break; > + } > +} > + > +#define __unused __attribute__((__unused__)) > + > +void read_bootinfo(u32 arg __unused, u32 id, u32 *info) > +{ > + u32 *atags = NULL; > + > + mach_type_id = id; > + > + if (info[0] == be32_to_cpu(FDT_SIG)) { > + /* > + * fdt reading is not [yet?] implemented. So calculate > + * the ATAGS addr to read that instead. > + */ > + atags = (u32 *)((u32)start - KERNEL_OFFSET + ATAG_OFFSET); > + } else if (info[1] == ATAG_CORE) > + atags = info; > + > + read_atags(id, atags); > +} > diff --git a/lib/arm/bootinfo.h b/lib/arm/bootinfo.h > new file mode 100644 > index 0000000000000..9cf547e4cebeb > --- /dev/null > +++ b/lib/arm/bootinfo.h > @@ -0,0 +1,19 @@ > +#ifndef _BOOTINFO_H_ > +#define _BOOTINFO_H_ > +#include "libcflat.h" > + > +struct tag_core { > + u32 flags; /* bit 0 = read-only */ > + u32 pagesize; > + u32 rootdev; > +}; > + > +struct tag_mem32 { > + u32 size; > + u32 start; /* physical start address */ > +}; > + > +extern u32 mach_type_id; > +extern struct tag_core core; > +extern struct tag_mem32 mem32; > +#endif > diff --git a/lib/arm/bswap.h b/lib/arm/bswap.h > new file mode 100644 > index 0000000000000..9bd16e789fcc5 > --- /dev/null > +++ b/lib/arm/bswap.h > @@ -0,0 +1,30 @@ > +#ifndef _ARM_BSWAP_H_ > +#define _ARM_BSWAP_H_ > +#include "libcflat.h" > + > +extern bool cpu_is_be; > + > +static inline u32 bswap32(u32 val) > +{ > + u32 ret; > + asm volatile("rev %0, %1" : "=r" (ret) : "r" (val)); > + return ret; > +} > + > +static inline u16 bswap16(u16 val) > +{ > + u16 ret; > + asm volatile("rev16 %0, %1" : "=r" (ret) : "r" (val)); > + return ret; > +} > + > +#define be32_to_cpu(x) (cpu_is_be ? x : bswap32(x)) > +#define cpu_to_be32(x) (cpu_is_be ? x : bswap32(x)) > +#define be16_to_cpu(x) (cpu_is_be ? x : bswap16(x)) > +#define cpu_to_be16(x) (cpu_is_be ? x : bswap16(x)) > + > +#define le32_to_cpu(x) (cpu_is_be ? bswap32(x) : x) > +#define cpu_to_le32(x) (cpu_is_be ? bswap32(x) : x) > +#define le16_to_cpu(x) (cpu_is_be ? bswap16(x) : x) > +#define cpu_to_le16(x) (cpu_is_be ? bswap16(x) : x) > +#endif > diff --git a/lib/arm/io.c b/lib/arm/io.c > new file mode 100644 > index 0000000000000..951af60551a4c > --- /dev/null > +++ b/lib/arm/io.c > @@ -0,0 +1,26 @@ > +#include "libcflat.h" > +#include "iomaps.h" > +#include "virtio-testdev.h" > + > +static volatile u8 *uart0_base; > + > +void puts(const char *s) > +{ > + while (*s) > + *uart0_base = *s++; > +} > + > +void exit(int code) > +{ > + virtio_testdev_exit(code); > + halt(code); > +} > + > +void io_init(void) > +{ > + struct iomap *m = iomaps_find("pl011"); > + if (!m) > + halt(ENXIO); > + uart0_base = (u8 *)compat_ptr(m->addrs[0]); > + virtio_testdev_init(); > +} > diff --git a/lib/bswap.h b/lib/bswap.h > index e63c4d37a8b9a..a428ed6c646dd 100644 > --- a/lib/bswap.h > +++ b/lib/bswap.h > @@ -1,7 +1,11 @@ > #ifndef _BSWAP_H_ > #define _BSWAP_H_ > +#ifdef __arm__ > +#include "arm/bswap.h" > +#else > #define le32_to_cpu(x) (x) > #define cpu_to_le32(x) (x) > #define le16_to_cpu(x) (x) > #define cpu_to_le16(x) (x) > #endif > +#endif > diff --git a/lib/libcflat.h b/lib/libcflat.h > index 41791194657d0..dce9a0f516e7e 100644 > --- a/lib/libcflat.h > +++ b/lib/libcflat.h > @@ -55,6 +55,7 @@ extern char *strcat(char *dest, const char *src); > extern int strcmp(const char *a, const char *b); > > extern int printf(const char *fmt, ...); > +extern int snprintf(char *buf, int size, const char *fmt, ...); > extern int vsnprintf(char *buf, int size, const char *fmt, va_list va); > > extern void puts(const char *s); > -- > 1.8.1.4 > -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html