diff mbox

[8/9] arm: initial drop

Message ID 1381767815-12510-9-git-send-email-drjones@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Andrew Jones Oct. 14, 2013, 4:23 p.m. UTC
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@redhat.com>
---
 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

Comments

Christoffer Dall Oct. 17, 2013, 1:06 a.m. UTC | #1
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@redhat.com>
> ---
>  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@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Andrew Jones Oct. 17, 2013, 10:16 a.m. UTC | #2
On Wed, Oct 16, 2013 at 06:06:35PM -0700, Christoffer Dall wrote:
> > 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 :)

Actually the editor prefers kernel style, I had to keep trying to
force the other style on it, and now see below that I wasn't always
successful. '++expected' should have had just a tab, not a
tab+4spaces...

> > --- /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?

See cstart.S:start 'bl main' below for the who invokes. And
arm/unittests.cfg, also below, for the (poorly documented) test case
definition. You'll see we config the test to have 256G memory, and then
here we confirm that we read the bootinfo correctly, i.e. it says 256G.
There's also a check for pagesize, which isn't really necessary, but as
that info comes from a different ATAG, it (sort of) checks something
else.

> 
> > 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

[snip]

> > 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

[snip]

drew
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Andrew Jones Oct. 17, 2013, 1:28 p.m. UTC | #3
On Thu, Oct 17, 2013 at 12:16:18PM +0200, Andrew Jones wrote:
> On Wed, Oct 16, 2013 at 06:06:35PM -0700, Christoffer Dall wrote:
> > > 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 :)
> 
> Actually the editor prefers kernel style, I had to keep trying to
> force the other style on it, and now see below that I wasn't always
> successful. '++expected' should have had just a tab, not a
> tab+4spaces...
> 
> > > --- /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?
> 
> See cstart.S:start 'bl main' below for the who invokes. And
> arm/unittests.cfg, also below, for the (poorly documented) test case
> definition. You'll see we config the test to have 256G memory, and then
> here we confirm that we read the bootinfo correctly, i.e. it says 256G.

The above 'G's are of course 'M's. Who remapped my keyboard?

drew
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Christoffer Dall Oct. 17, 2013, 6:39 p.m. UTC | #4
On Thu, Oct 17, 2013 at 03:28:15PM +0200, Andrew Jones wrote:
> On Thu, Oct 17, 2013 at 12:16:18PM +0200, Andrew Jones wrote:
> > On Wed, Oct 16, 2013 at 06:06:35PM -0700, Christoffer Dall wrote:
> > > > 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 :)
> > 
> > Actually the editor prefers kernel style, I had to keep trying to
> > force the other style on it, and now see below that I wasn't always
> > successful. '++expected' should have had just a tab, not a
> > tab+4spaces...
> > 
> > > > --- /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?
> > 
> > See cstart.S:start 'bl main' below for the who invokes. And
> > arm/unittests.cfg, also below, for the (poorly documented) test case
> > definition. You'll see we config the test to have 256G memory, and then
> > here we confirm that we read the bootinfo correctly, i.e. it says 256G.

Thanks.

> 
> The above 'G's are of course 'M's. Who remapped my keyboard?
> 
That would be one swanky ARM board.

-Chrsitoffer
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/arm/boot.c b/arm/boot.c
new file mode 100644
index 0000000000000..375e8708a7c54
--- /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;
+}
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);