All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/17] kvm-unit-tests/arm: initial drop
@ 2014-01-21 16:21 Andrew Jones
  2014-01-21 16:21 ` [PATCH 01/17] remove unused files Andrew Jones
                   ` (18 more replies)
  0 siblings, 19 replies; 47+ messages in thread
From: Andrew Jones @ 2014-01-21 16:21 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: christoffer.dall

This is a v3 of a series that introduces arm to kvm-unit-tests.
First, it does some tidying up of the repo. Then, it adds support
for virtio-testdev. Next, it adds the basic infrastructure for
booting a test case (guest), and adds a single simple test,
which is a self-test. Finally, it adds support for vectors and
self-tests for that support.

This initial drop doesn't require kvmarm. Only qemu-system-arm,
recent enough to have mach-virt, and the virtio-testdev patch[1],
is required.

[1] http://lists.nongnu.org/archive/html/qemu-devel/2013-12/msg00690.html

These patches are also available from a git repo here
https://github.com/rhdrjones/kvm-unit-tests/commits/arm-branch/master

Andrew Jones (16):
  remove unused files
  makefile and run_tests tweaks
  clean root dir of all x86-ness
  gitignore: Ignore more
  add 'make cscope' support
  Add halt() and some error codes
  move x86's simple heap management to common code
  Introduce libio to common code for io read/write
  libfdt: Import libfdt source
  libfdt: get libfdt to build
  add support for device trees
  Introduce virtio-testdev
  arm: initial drop
  printf: support field padding
  arm: add useful headers from the linux kernel
  arm: vectors support

Christoffer Dall (1):
  arm: Add IO accessors to avoid register-writeback

 .gitignore                   |    6 +
 Makefile                     |   50 +-
 README                       |   55 +-
 arm/cstart.S                 |  196 ++++++
 arm/flat.lds                 |   23 +
 arm/run                      |   19 +
 arm/selftest.c               |  149 +++++
 arm/unittests.cfg            |   29 +
 config-i386.mak              |   13 -
 config-ia64.mak              |    7 -
 config-powerpc-440.mak       |   15 -
 config-powerpc.mak           |   39 --
 config-x86-common.mak        |  122 ----
 config-x86_64.mak            |   14 -
 config/config-arm.mak        |   80 +++
 config/config-i386.mak       |   12 +
 config/config-x86-common.mak |  121 ++++
 config/config-x86_64.mak     |   13 +
 configure                    |   27 +-
 docs/testdev.txt             |   11 +
 flat.lds                     |   21 -
 formats                      |   31 -
 iotable.c                    |   53 --
 iotable.h                    |   40 --
 kvmtrace.c                   |  706 --------------------
 kvmtrace_format              |  532 ---------------
 lib/argv.c                   |    6 +
 lib/arm/asm-offsets.h        |   27 +
 lib/arm/cp15.h               |   36 +
 lib/arm/eabi_compat.c        |   20 +
 lib/arm/io.c                 |   44 ++
 lib/arm/io.h                 |   78 +++
 lib/arm/processor.c          |  103 +++
 lib/arm/processor.h          |   35 +
 lib/arm/ptrace.h             |  100 +++
 lib/arm/setup.c              |   46 ++
 lib/arm/sysinfo.h            |   12 +
 lib/devicetree.c             |  257 +++++++
 lib/devicetree.h             |   95 +++
 lib/errno.h                  |   22 +
 lib/fwcfg.c                  |   58 --
 lib/heap.c                   |   45 ++
 lib/heap.h                   |    8 +
 lib/libcflat.h               |   13 +-
 lib/libfdt/Makefile.libfdt   |   10 +
 lib/libfdt/README            |    4 +
 lib/libfdt/fdt.c             |  250 +++++++
 lib/libfdt/fdt.h             |  111 ++++
 lib/libfdt/fdt_empty_tree.c  |   84 +++
 lib/libfdt/fdt_ro.c          |  573 ++++++++++++++++
 lib/libfdt/fdt_rw.c          |  492 ++++++++++++++
 lib/libfdt/fdt_strerror.c    |   96 +++
 lib/libfdt/fdt_sw.c          |  256 +++++++
 lib/libfdt/fdt_wip.c         |  118 ++++
 lib/libfdt/libfdt.h          | 1514 ++++++++++++++++++++++++++++++++++++++++++
 lib/libfdt/libfdt_env.h      |  112 ++++
 lib/libfdt/libfdt_internal.h |   95 +++
 lib/libfdt/version.lds       |   60 ++
 lib/libio.h                  |  177 +++++
 lib/panic.c                  |   13 -
 lib/powerpc/44x/map.c        |   51 --
 lib/powerpc/44x/timebase.S   |   28 -
 lib/powerpc/44x/timebase.h   |   25 -
 lib/powerpc/44x/tlbwe.S      |   29 -
 lib/powerpc/io.c             |   35 -
 lib/printf.c                 |   82 ++-
 lib/string.c                 |   51 ++
 lib/virtio-testdev.c         |  139 ++++
 lib/virtio-testdev.h         |    9 +
 lib/virtio.c                 |  126 ++++
 lib/virtio.h                 |   74 +++
 lib/x86/vm.c                 |   33 +-
 main-ppc.c                   |  383 -----------
 powerpc/44x/tlbsx.S          |   33 -
 powerpc/44x/tlbwe.S          |   27 -
 powerpc/44x/tlbwe_16KB.S     |   35 -
 powerpc/44x/tlbwe_hole.S     |   27 -
 powerpc/cstart.S             |   38 --
 powerpc/exit.c               |   23 -
 powerpc/helloworld.c         |   27 -
 powerpc/io.S                 |   32 -
 powerpc/spin.S               |    4 -
 powerpc/sprg.S               |    7 -
 run_tests.sh                 |   19 +-
 scripts/arm/asm-offsets.c    |   40 ++
 testdev.txt                  |   14 -
 x86-run                      |   41 --
 x86/README                   |   60 +-
 x86/flat.lds                 |   21 +
 x86/print.h                  |   19 -
 x86/run                      |   41 ++
 x86/run-kvm-unit-tests       |    6 -
 92 files changed, 6267 insertions(+), 2666 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
 delete mode 100644 config-i386.mak
 delete mode 100644 config-ia64.mak
 delete mode 100644 config-powerpc-440.mak
 delete mode 100644 config-powerpc.mak
 delete mode 100644 config-x86-common.mak
 delete mode 100644 config-x86_64.mak
 create mode 100644 config/config-arm.mak
 create mode 100644 config/config-i386.mak
 create mode 100644 config/config-x86-common.mak
 create mode 100644 config/config-x86_64.mak
 create mode 100644 docs/testdev.txt
 delete mode 100644 flat.lds
 delete mode 100644 formats
 delete mode 100644 iotable.c
 delete mode 100644 iotable.h
 delete mode 100644 kvmtrace.c
 delete mode 100755 kvmtrace_format
 create mode 100644 lib/arm/asm-offsets.h
 create mode 100644 lib/arm/cp15.h
 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/processor.c
 create mode 100644 lib/arm/processor.h
 create mode 100644 lib/arm/ptrace.h
 create mode 100644 lib/arm/setup.c
 create mode 100644 lib/arm/sysinfo.h
 create mode 100644 lib/devicetree.c
 create mode 100644 lib/devicetree.h
 create mode 100644 lib/errno.h
 delete mode 100644 lib/fwcfg.c
 create mode 100644 lib/heap.c
 create mode 100644 lib/heap.h
 create mode 100644 lib/libfdt/Makefile.libfdt
 create mode 100644 lib/libfdt/README
 create mode 100644 lib/libfdt/fdt.c
 create mode 100644 lib/libfdt/fdt.h
 create mode 100644 lib/libfdt/fdt_empty_tree.c
 create mode 100644 lib/libfdt/fdt_ro.c
 create mode 100644 lib/libfdt/fdt_rw.c
 create mode 100644 lib/libfdt/fdt_strerror.c
 create mode 100644 lib/libfdt/fdt_sw.c
 create mode 100644 lib/libfdt/fdt_wip.c
 create mode 100644 lib/libfdt/libfdt.h
 create mode 100644 lib/libfdt/libfdt_env.h
 create mode 100644 lib/libfdt/libfdt_internal.h
 create mode 100644 lib/libfdt/version.lds
 create mode 100644 lib/libio.h
 delete mode 100644 lib/panic.c
 delete mode 100644 lib/powerpc/44x/map.c
 delete mode 100644 lib/powerpc/44x/timebase.S
 delete mode 100644 lib/powerpc/44x/timebase.h
 delete mode 100644 lib/powerpc/44x/tlbwe.S
 delete mode 100644 lib/powerpc/io.c
 create mode 100644 lib/virtio-testdev.c
 create mode 100644 lib/virtio-testdev.h
 create mode 100644 lib/virtio.c
 create mode 100644 lib/virtio.h
 delete mode 100644 main-ppc.c
 delete mode 100644 powerpc/44x/tlbsx.S
 delete mode 100644 powerpc/44x/tlbwe.S
 delete mode 100644 powerpc/44x/tlbwe_16KB.S
 delete mode 100644 powerpc/44x/tlbwe_hole.S
 delete mode 100644 powerpc/cstart.S
 delete mode 100644 powerpc/exit.c
 delete mode 100644 powerpc/helloworld.c
 delete mode 100644 powerpc/io.S
 delete mode 100644 powerpc/spin.S
 delete mode 100644 powerpc/sprg.S
 create mode 100644 scripts/arm/asm-offsets.c
 delete mode 100644 testdev.txt
 delete mode 100755 x86-run
 create mode 100644 x86/flat.lds
 delete mode 100644 x86/print.h
 create mode 100755 x86/run
 delete mode 100644 x86/run-kvm-unit-tests

-- 
1.8.1.4


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH 01/17] remove unused files
  2014-01-21 16:21 [PATCH 00/17] kvm-unit-tests/arm: initial drop Andrew Jones
@ 2014-01-21 16:21 ` Andrew Jones
  2014-01-21 16:21 ` [PATCH 02/17] makefile and run_tests tweaks Andrew Jones
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 47+ messages in thread
From: Andrew Jones @ 2014-01-21 16:21 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: christoffer.dall

There are several unused files, primarily because powerpc is an unused
arch. The exceptions are config-ia64.mak, which is also an unused arch
file, lib/fwcfg.c, lib/panic.c, x86/print.h and x86/run-kvm-unit-tests,
which are just unused. Remove them all in order to tidy things up.

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 Makefile                   |   8 +-
 config-ia64.mak            |   7 -
 config-powerpc-440.mak     |  15 -
 config-powerpc.mak         |  39 ---
 formats                    |  31 --
 iotable.c                  |  53 ----
 iotable.h                  |  40 ---
 kvmtrace.c                 | 706 ---------------------------------------------
 kvmtrace_format            | 532 ----------------------------------
 lib/fwcfg.c                |  58 ----
 lib/libcflat.h             |   1 -
 lib/panic.c                |  13 -
 lib/powerpc/44x/map.c      |  51 ----
 lib/powerpc/44x/timebase.S |  28 --
 lib/powerpc/44x/timebase.h |  25 --
 lib/powerpc/44x/tlbwe.S    |  29 --
 lib/powerpc/io.c           |  35 ---
 main-ppc.c                 | 383 ------------------------
 powerpc/44x/tlbsx.S        |  33 ---
 powerpc/44x/tlbwe.S        |  27 --
 powerpc/44x/tlbwe_16KB.S   |  35 ---
 powerpc/44x/tlbwe_hole.S   |  27 --
 powerpc/cstart.S           |  38 ---
 powerpc/exit.c             |  23 --
 powerpc/helloworld.c       |  27 --
 powerpc/io.S               |  32 --
 powerpc/spin.S             |   4 -
 powerpc/sprg.S             |   7 -
 x86/print.h                |  19 --
 x86/run-kvm-unit-tests     |   6 -
 30 files changed, 1 insertion(+), 2331 deletions(-)
 delete mode 100644 config-ia64.mak
 delete mode 100644 config-powerpc-440.mak
 delete mode 100644 config-powerpc.mak
 delete mode 100644 formats
 delete mode 100644 iotable.c
 delete mode 100644 iotable.h
 delete mode 100644 kvmtrace.c
 delete mode 100755 kvmtrace_format
 delete mode 100644 lib/fwcfg.c
 delete mode 100644 lib/panic.c
 delete mode 100644 lib/powerpc/44x/map.c
 delete mode 100644 lib/powerpc/44x/timebase.S
 delete mode 100644 lib/powerpc/44x/timebase.h
 delete mode 100644 lib/powerpc/44x/tlbwe.S
 delete mode 100644 lib/powerpc/io.c
 delete mode 100644 main-ppc.c
 delete mode 100644 powerpc/44x/tlbsx.S
 delete mode 100644 powerpc/44x/tlbwe.S
 delete mode 100644 powerpc/44x/tlbwe_16KB.S
 delete mode 100644 powerpc/44x/tlbwe_hole.S
 delete mode 100644 powerpc/cstart.S
 delete mode 100644 powerpc/exit.c
 delete mode 100644 powerpc/helloworld.c
 delete mode 100644 powerpc/io.S
 delete mode 100644 powerpc/spin.S
 delete mode 100644 powerpc/sprg.S
 delete mode 100644 x86/print.h
 delete mode 100644 x86/run-kvm-unit-tests

diff --git a/Makefile b/Makefile
index b6e87598721a6..278791dbbef23 100644
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,6 @@ libgcc := $(shell $(CC) --print-libgcc-file-name)
 
 libcflat := lib/libcflat.a
 cflatobjs := \
-	lib/panic.o \
 	lib/printf.o \
 	lib/string.o
 cflatobjs += lib/argv.o
@@ -39,11 +38,6 @@ autodepend-flags = -MMD -MF $(dir $*).$(notdir $*).d
 LDFLAGS += $(CFLAGS)
 LDFLAGS += -pthread -lrt
 
-kvmtrace_objs= kvmtrace.o
-
-kvmtrace: $(kvmtrace_objs)
-	$(CC) $(LDFLAGS) $^ -o $@
-
 $(libcflat): $(cflatobjs)
 	$(AR) rcs $@ $^
 
@@ -57,4 +51,4 @@ install:
 	install $(tests_and_config) $(DESTDIR)
 
 clean: arch_clean
-	$(RM) kvmtrace *.o *.a .*.d $(libcflat) $(cflatobjs)
+	$(RM) *.o *.a .*.d $(libcflat) $(cflatobjs)
diff --git a/config-ia64.mak b/config-ia64.mak
deleted file mode 100644
index d9350fcc5a9ec..0000000000000
--- a/config-ia64.mak
+++ /dev/null
@@ -1,7 +0,0 @@
-bits = 64
-CFLAGS += -m64
-CFLAGS += -D__ia64__
-CFLAGS += -I../include/ia64
-
-all:
-
diff --git a/config-powerpc-440.mak b/config-powerpc-440.mak
deleted file mode 100644
index bb8597153b30e..0000000000000
--- a/config-powerpc-440.mak
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-# for some reason binutils hates tlbsx unless we say we're 405  :(
-CFLAGS += -Wa,-m405 -I lib/powerpc/44x
-
-cflatobjs += \
-	lib/powerpc/44x/map.o \
-	lib/powerpc/44x/tlbwe.o \
-	lib/powerpc/44x/timebase.o
-
-simpletests += \
-	powerpc/44x/tlbsx.bin \
-	powerpc/44x/tlbwe_16KB.bin \
-	powerpc/44x/tlbwe_hole.bin \
-	powerpc/44x/tlbwe.bin
diff --git a/config-powerpc.mak b/config-powerpc.mak
deleted file mode 100644
index d053569b8aa3c..0000000000000
--- a/config-powerpc.mak
+++ /dev/null
@@ -1,39 +0,0 @@
-CFLAGS += -I../include/powerpc
-CFLAGS += -Wa,-mregnames -I lib
-CFLAGS += -ffreestanding
-
-cstart := powerpc/cstart.o
-
-cflatobjs += \
-	lib/powerpc/io.o
-
-$(libcflat): LDFLAGS += -nostdlib
-
-# these tests do not use libcflat
-simpletests := \
-	powerpc/spin.bin \
-	powerpc/io.bin \
-	powerpc/sprg.bin
-
-# theses tests use cstart.o, libcflat, and libgcc
-tests := \
-	powerpc/exit.bin \
-	powerpc/helloworld.bin
-
-include config-powerpc-$(PROCESSOR).mak
-
-
-all: kvmtrace kvmctl $(libcflat) $(simpletests) $(tests)
-
-$(simpletests): %.bin: %.o
-	$(CC) -nostdlib $^ -Wl,-T,flat.lds -o $@
-
-$(tests): %.bin: $(cstart) %.o $(libcflat)
-	$(CC) -nostdlib $^ $(libgcc) -Wl,-T,flat.lds -o $@
-
-kvmctl_objs = main-ppc.o iotable.o ../libkvm/libkvm.a
-
-arch_clean:
-	$(RM) $(simpletests) $(tests) $(cstart)
-	$(RM) $(patsubst %.bin, %.elf, $(simpletests) $(tests))
-	$(RM) $(patsubst %.bin, %.o, $(simpletests) $(tests))
diff --git a/formats b/formats
deleted file mode 100644
index 7f4ebdbcedaa2..0000000000000
--- a/formats
+++ /dev/null
@@ -1,31 +0,0 @@
-0x00000000  %(ts)d (+%(relts)12d)  unknown (0x%(event)016x) vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ 0x%(1)08x 0x%(2)08x 0x%(3)08x 0x%(4)08x 0x%(5)08x ]
-
-0x00010001  %(ts)d (+%(relts)12d)  VMENTRY       vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x
-0x00010002  %(ts)d (+%(relts)12d)  VMEXIT        vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ exitcode = 0x%(1)08x, rip = 0x%(3)08x %(2)08x ]
-0x00020001  %(ts)d (+%(relts)12d)  PAGE_FAULT    vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ errorcode = 0x%(1)08x, virt = 0x%(3)08x %(2)08x ]
-0x00020002  %(ts)d (+%(relts)12d)  INJ_VIRQ      vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ vector = 0x%(1)02x ]
-0x00020003  %(ts)d (+%(relts)12d)  REDELIVER_EVT vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ vector = 0x%(1)02x ]
-0x00020004  %(ts)d (+%(relts)12d)  PEND_INTR     vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ vector = 0x%(1)02x ]
-0x00020005  %(ts)d (+%(relts)12d)  IO_READ       vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ port = 0x%(1)04x, size = %(2)d ]
-0x00020006  %(ts)d (+%(relts)12d)  IO_WRITE      vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ port = 0x%(1)04x, size = %(2)d ]
-0x00020007  %(ts)d (+%(relts)12d)  CR_READ       vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ CR# = %(1)d, value = 0x%(3)08x %(2)08x ]
-0x00020008  %(ts)d (+%(relts)12d)  CR_WRITE      vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ CR# = %(1)d, value = 0x%(3)08x %(2)08x ]
-0x00020009  %(ts)d (+%(relts)12d)  DR_READ       vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ DR# = %(1)d, value = 0x%(2)08x ]
-0x0002000A  %(ts)d (+%(relts)12d)  DR_WRITE      vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ DR# = %(1)d, value = 0x%(2)08x ]
-0x0002000B  %(ts)d (+%(relts)12d)  MSR_READ      vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ MSR# = 0x%(1)08x, data = 0x%(3)08x %(2)08x ]
-0x0002000C  %(ts)d (+%(relts)12d)  MSR_WRITE     vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ MSR# = 0x%(1)08x, data = 0x%(3)08x %(2)08x ]
-0x0002000D  %(ts)d (+%(relts)12d)  CPUID         vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ func = 0x%(1)08x, eax = 0x%(2)08x, ebx = 0x%(3)08x, ecx = 0x%(4)08x edx = 0x%(5)08x]
-0x0002000E  %(ts)d (+%(relts)12d)  INTR          vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ vector = 0x%(1)02x ]
-0x0002000F  %(ts)d (+%(relts)12d)  NMI           vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x
-0x00020010  %(ts)d (+%(relts)12d)  VMMCALL       vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ func = 0x%(1)08x ]
-0x00020011  %(ts)d (+%(relts)12d)  HLT           vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x
-0x00020012  %(ts)d (+%(relts)12d)  CLTS          vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x
-0x00020013  %(ts)d (+%(relts)12d)  LMSW          vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ value = 0x%(1)08x ]
-0x00020014  %(ts)d (+%(relts)12d)  APIC_ACCESS   vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ offset = 0x%(1)08x ]
-0x00020015  %(ts)d (+%(relts)12d)  TDP_FAULT     vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ errorcode = 0x%(1)08x, virt = 0x%(3)08x %(2)08x ]
-# ppc: tlb traces
-0x00020016  GTLB_WRITE    vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ index = 0x%(1)08x, tid = 0x%(2)08x, word1=0x%(3)08x, word2=0x%(4)08x, word3=0x%(5)08x ]
-0x00020017  STLB_WRITE    vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ index = 0x%(1)08x, tid = 0x%(2)08x, word1=0x%(3)08x, word2=0x%(4)08x, word3=0x%(5)08x ]
-0x00020018  STLB_INVAL    vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ index = 0x%(1)08x, tid = 0x%(2)08x, word1=0x%(3)08x, word2=0x%(4)08x, word3=0x%(5)08x ]
-# ppc: instruction emulation - this type is handled more complex in kvmtrace_format, but listed to show the eventid and transported data
-#0x00020019  %(ts)d (+%(relts)12d)  PPC_INSTR     vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ instr = 0x%(1)08x, pc = 0x%(2)08x, emul = 0x%(3)08x, nsec = %(4)08d ]
diff --git a/iotable.c b/iotable.c
deleted file mode 100644
index 91a5016c42005..0000000000000
--- a/iotable.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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
- *
- * Authors:
- *
- *  Avi Kivity <avi@qumranet.com>
- *  Yaniv Kamay <yaniv@qumranet.com>
- *
- * This work is licensed under the GNU LGPL license, version 2.
- */
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <errno.h>
-
-#include "iotable.h"
-
-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;
-}
diff --git a/iotable.h b/iotable.h
deleted file mode 100644
index cb18f23789be1..0000000000000
--- a/iotable.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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
- *
- * Authors:
- *
- *  Avi Kivity <avi@qumranet.com>
- *  Yaniv Kamay <yaniv@qumranet.com>
- *
- * This work is licensed under the GNU LGPL license, version 2.
- */
-
-#include <stdint.h>
-
-#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];
-};
-
-struct io_table_entry *io_table_lookup(struct io_table *io_table,
-                                       uint64_t addr);
-int io_table_register(struct io_table *io_table, uint64_t start, uint64_t size,
-                      io_table_handler_t *handler, void *opaque);
diff --git a/kvmtrace.c b/kvmtrace.c
deleted file mode 100644
index de3c1897f4660..0000000000000
--- a/kvmtrace.c
+++ /dev/null
@@ -1,706 +0,0 @@
-/*
- * kvm tracing application
- *
- * This tool is used for collecting trace buffer data
- * for kvm trace.
- *
- * Based on blktrace 0.99.3
- *
- * Copyright (C) 2005 Jens Axboe <axboe@suse.de>
- * Copyright (C) 2006 Jens Axboe <axboe@kernel.dk>
- * Copyright (C) 2008 Eric Liu <eric.e.liu@intel.com>
- *
- * This work is licensed under the GNU LGPL license, version 2.
- */
-
-#define _GNU_SOURCE
-
-#include <pthread.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/param.h>
-#include <sys/statfs.h>
-#include <sys/poll.h>
-#include <sys/mman.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <getopt.h>
-#include <errno.h>
-#include <sched.h>
-
-#ifndef __user
-#define __user
-#endif
-#include <linux/kvm.h>
-
-static char kvmtrace_version[] = "0.1";
-
-/*
- * You may want to increase this even more, if you are logging at a high
- * rate and see skipped/missed events
- */
-#define BUF_SIZE	(512 * 1024)
-#define BUF_NR		(8)
-
-#define OFILE_BUF	(128 * 1024)
-
-#define DEBUGFS_TYPE	0x64626720
-
-#define max(a, b)	((a) > (b) ? (a) : (b))
-
-#define S_OPTS	"r:o:w:?Vb:n:D:"
-static struct option l_opts[] = {
-	{
-		.name = "relay",
-		.has_arg = required_argument,
-		.flag = NULL,
-		.val = 'r'
-	},
-	{
-		.name = "output",
-		.has_arg = required_argument,
-		.flag = NULL,
-		.val = 'o'
-	},
-	{
-		.name = "stopwatch",
-		.has_arg = required_argument,
-		.flag = NULL,
-		.val = 'w'
-	},
-	{
-		.name = "version",
-		.has_arg = no_argument,
-		.flag = NULL,
-		.val = 'V'
-	},
-	{
-		.name = "buffer-size",
-		.has_arg = required_argument,
-		.flag = NULL,
-		.val = 'b'
-	},
-	{
-		.name = "num-sub-buffers",
-		.has_arg = required_argument,
-		.flag = NULL,
-		.val = 'n'
-	},
-	{
-		.name = "output-dir",
-		.has_arg = required_argument,
-		.flag = NULL,
-		.val = 'D'
-	},
-	{
-		.name = NULL,
-	}
-};
-
-struct thread_information {
-	int cpu;
-	pthread_t thread;
-
-	int fd;
-	char fn[MAXPATHLEN + 64];
-
-	FILE *ofile;
-	char *ofile_buffer;
-
-	int (*get_subbuf)(struct thread_information *, unsigned int);
-	int (*read_data)(struct thread_information *, void *, unsigned int);
-
-	unsigned long long data_read;
-
-	struct kvm_trace_information *trace_info;
-
-	int exited;
-
-	/*
-	 * mmap controlled output files
-	 */
-	unsigned long long fs_size;
-	unsigned long long fs_max_size;
-	unsigned long fs_off;
-	void *fs_buf;
-	unsigned long fs_buf_len;
-
-};
-
-struct kvm_trace_information {
-	int fd;
-	volatile int trace_started;
-	unsigned long lost_records;
-	struct thread_information *threads;
-	unsigned long buf_size;
-	unsigned long buf_nr;
-};
-
-static struct kvm_trace_information trace_information;
-
-static int ncpus;
-static char default_debugfs_path[] = "/sys/kernel/debug";
-
-/* command line option globals */
-static char *debugfs_path;
-static char *output_name;
-static char *output_dir;
-static int stop_watch;
-static unsigned long buf_size = BUF_SIZE;
-static unsigned long buf_nr = BUF_NR;
-static unsigned int page_size;
-
-#define for_each_cpu_online(cpu) \
-	for (cpu = 0; cpu < ncpus; cpu++)
-#define for_each_tip(tip, i) \
-	for (i = 0, tip = trace_information.threads; i < ncpus; i++, tip++)
-
-#define is_done()	(*(volatile int *)(&done))
-static volatile int done;
-
-#define is_trace_stopped()	(*(volatile int *)(&trace_stopped))
-static volatile int trace_stopped;
-
-static void exit_trace(int status);
-
-static void handle_sigint(__attribute__((__unused__)) int sig)
-{
-	ioctl(trace_information.fd, KVM_TRACE_PAUSE);
-	done = 1;
-}
-
-static int get_lost_records()
-{
-	int fd;
-	char tmp[MAXPATHLEN + 64];
-
-	snprintf(tmp, sizeof(tmp), "%s/kvm/lost_records", debugfs_path);
-	fd = open(tmp, O_RDONLY);
-	if (fd < 0) {
-		/*
-		 * this may be ok, if the kernel doesn't support dropped counts
-		 */
-		if (errno == ENOENT)
-			return 0;
-
-		fprintf(stderr, "Couldn't open dropped file %s\n", tmp);
-		return -1;
-	}
-
-	if (read(fd, tmp, sizeof(tmp)) < 0) {
-		perror(tmp);
-		close(fd);
-		return -1;
-	}
-	close(fd);
-
-	return atoi(tmp);
-}
-
-static void wait_for_data(struct thread_information *tip, int timeout)
-{
-	struct pollfd pfd = { .fd = tip->fd, .events = POLLIN };
-
-	while (!is_done()) {
-		if (poll(&pfd, 1, timeout) < 0) {
-			perror("poll");
-			break;
-		}
-		if (pfd.revents & POLLIN)
-			break;
-	}
-}
-
-static int read_data(struct thread_information *tip, void *buf,
-			  unsigned int len)
-{
-	int ret = 0;
-
-	do {
-		wait_for_data(tip, 100);
-
-		ret = read(tip->fd, buf, len);
-
-		if (!ret)
-			continue;
-		else if (ret > 0)
-			return ret;
-		else {
-			if (errno != EAGAIN) {
-				perror(tip->fn);
-				fprintf(stderr, "Thread %d failed read of %s\n",
-					tip->cpu, tip->fn);
-				break;
-			}
-			continue;
-		}
-	} while (!is_done());
-
-	return ret;
-
-}
-
-/*
- * For file output, truncate and mmap the file appropriately
- */
-static int mmap_subbuf(struct thread_information *tip, unsigned int maxlen)
-{
-	int ofd = fileno(tip->ofile);
-	int ret;
-	unsigned long nr;
-	unsigned long size;
-
-	/*
-	 * extend file, if we have to. use chunks of 16 subbuffers.
-	 */
-	if (tip->fs_off + maxlen > tip->fs_buf_len) {
-		if (tip->fs_buf) {
-			munlock(tip->fs_buf, tip->fs_buf_len);
-			munmap(tip->fs_buf, tip->fs_buf_len);
-			tip->fs_buf = NULL;
-		}
-
-		tip->fs_off = tip->fs_size & (page_size - 1);
-		nr = max(16, tip->trace_info->buf_nr);
-		size = tip->trace_info->buf_size;
-		tip->fs_buf_len = (nr * size) - tip->fs_off;
-		tip->fs_max_size += tip->fs_buf_len;
-
-		if (ftruncate(ofd, tip->fs_max_size) < 0) {
-			perror("ftruncate");
-			return -1;
-		}
-
-		tip->fs_buf = mmap(NULL, tip->fs_buf_len, PROT_WRITE,
-				   MAP_SHARED, ofd, tip->fs_size - tip->fs_off);
-		if (tip->fs_buf == MAP_FAILED) {
-			perror("mmap");
-			return -1;
-		}
-		mlock(tip->fs_buf, tip->fs_buf_len);
-	}
-
-	ret = tip->read_data(tip, tip->fs_buf + tip->fs_off, maxlen);
-	if (ret >= 0) {
-		tip->data_read += ret;
-		tip->fs_size += ret;
-		tip->fs_off += ret;
-		return 0;
-	}
-
-	return -1;
-}
-
-static void tip_ftrunc_final(struct thread_information *tip)
-{
-	/*
-	 * truncate to right size and cleanup mmap
-	 */
-	if (tip->ofile) {
-		int ofd = fileno(tip->ofile);
-
-		if (tip->fs_buf)
-			munmap(tip->fs_buf, tip->fs_buf_len);
-
-		ftruncate(ofd, tip->fs_size);
-	}
-}
-
-static void *thread_main(void *arg)
-{
-	struct thread_information *tip = arg;
-	pid_t pid = getpid();
-	cpu_set_t cpu_mask;
-
-	CPU_ZERO(&cpu_mask);
-	CPU_SET((tip->cpu), &cpu_mask);
-
-	if (sched_setaffinity(pid, sizeof(cpu_mask), &cpu_mask) == -1) {
-		perror("sched_setaffinity");
-		exit_trace(1);
-	}
-
-	snprintf(tip->fn, sizeof(tip->fn), "%s/kvm/trace%d",
-			debugfs_path, tip->cpu);
-	tip->fd = open(tip->fn, O_RDONLY);
-	if (tip->fd < 0) {
-		perror(tip->fn);
-		fprintf(stderr, "Thread %d failed open of %s\n", tip->cpu,
-			tip->fn);
-		exit_trace(1);
-	}
-	while (!is_done()) {
-		if (tip->get_subbuf(tip, tip->trace_info->buf_size) < 0)
-			break;
-	}
-
-	/*
-	 * trace is stopped, pull data until we get a short read
-	 */
-	while (tip->get_subbuf(tip, tip->trace_info->buf_size) > 0)
-		;
-
-	tip_ftrunc_final(tip);
-	tip->exited = 1;
-	return NULL;
-}
-
-static int fill_ofname(struct thread_information *tip, char *dst)
-{
-	struct stat sb;
-	int len = 0;
-
-	if (output_dir)
-		len = sprintf(dst, "%s/", output_dir);
-	else
-		len = sprintf(dst, "./");
-
-	if (stat(dst, &sb) < 0) {
-		if (errno != ENOENT) {
-			perror("stat");
-			return 1;
-		}
-		if (mkdir(dst, 0755) < 0) {
-			perror(dst);
-			fprintf(stderr, "Can't make output dir\n");
-			return 1;
-		}
-	}
-
-	sprintf(dst + len, "%s.kvmtrace.%d", output_name, tip->cpu);
-
-	return 0;
-}
-
-static void fill_ops(struct thread_information *tip)
-{
-	tip->get_subbuf = mmap_subbuf;
-	tip->read_data = read_data;
-}
-
-static void close_thread(struct thread_information *tip)
-{
-	if (tip->fd != -1)
-		close(tip->fd);
-	if (tip->ofile)
-		fclose(tip->ofile);
-	if (tip->ofile_buffer)
-		free(tip->ofile_buffer);
-
-	tip->fd = -1;
-	tip->ofile = NULL;
-	tip->ofile_buffer = NULL;
-}
-
-static int tip_open_output(struct thread_information *tip)
-{
-	int mode, vbuf_size;
-	char op[NAME_MAX];
-
-	if (fill_ofname(tip, op))
-		return 1;
-
-	tip->ofile = fopen(op, "w+");
-	mode = _IOFBF;
-	vbuf_size = OFILE_BUF;
-
-	if (tip->ofile == NULL) {
-		perror(op);
-		return 1;
-	}
-
-	tip->ofile_buffer = malloc(vbuf_size);
-	if (setvbuf(tip->ofile, tip->ofile_buffer, mode, vbuf_size)) {
-		perror("setvbuf");
-		close_thread(tip);
-		return 1;
-	}
-
-	fill_ops(tip);
-	return 0;
-}
-
-static int start_threads(int cpu)
-{
-	struct thread_information *tip;
-
-	tip = trace_information.threads + cpu;
-	tip->cpu = cpu;
-	tip->trace_info = &trace_information;
-	tip->fd = -1;
-
-	if (tip_open_output(tip))
-	    return 1;
-
-	if (pthread_create(&tip->thread, NULL, thread_main, tip)) {
-		perror("pthread_create");
-		close_thread(tip);
-		return 1;
-	}
-
-	return 0;
-}
-
-static void stop_threads()
-{
-	struct thread_information *tip;
-	unsigned long ret;
-	int i;
-
-	for_each_tip(tip, i) {
-		if (tip->thread)
-			(void) pthread_join(tip->thread, (void *) &ret);
-		close_thread(tip);
-	}
-}
-
-static int start_trace(void)
-{
-	int fd;
-	struct kvm_user_trace_setup kuts;
-
-	fd = trace_information.fd = open("/dev/kvm", O_RDWR);
-	if (fd == -1) {
-		perror("/dev/kvm");
-		return 1;
-	}
-
-	memset(&kuts, 0, sizeof(kuts));
-	kuts.buf_size = trace_information.buf_size = buf_size;
-	kuts.buf_nr = trace_information.buf_nr = buf_nr;
-
-	if (ioctl(trace_information.fd , KVM_TRACE_ENABLE, &kuts) < 0) {
-		perror("KVM_TRACE_ENABLE");
-		close(fd);
-		return 1;
-	}
-	trace_information.trace_started = 1;
-
-	return 0;
-}
-
-static void cleanup_trace(void)
-{
-	if (trace_information.fd == -1)
-		return;
-
-	trace_information.lost_records = get_lost_records();
-
-	if (trace_information.trace_started) {
-		trace_information.trace_started = 0;
-		if (ioctl(trace_information.fd, KVM_TRACE_DISABLE) < 0)
-			perror("KVM_TRACE_DISABLE");
-	}
-
-	close(trace_information.fd);
-	trace_information.fd  = -1;
-}
-
-static void stop_all_traces(void)
-{
-	if (!is_trace_stopped()) {
-		trace_stopped = 1;
-		stop_threads();
-		cleanup_trace();
-	}
-}
-
-static void exit_trace(int status)
-{
-	stop_all_traces();
-	exit(status);
-}
-
-static int start_kvm_trace(void)
-{
-	int i, size;
-	struct thread_information *tip;
-
-	size = ncpus * sizeof(struct thread_information);
-	tip = malloc(size);
-	if (!tip) {
-		fprintf(stderr, "Out of memory, threads (%d)\n", size);
-		return 1;
-	}
-	memset(tip, 0, size);
-	trace_information.threads = tip;
-
-	if (start_trace())
-		return 1;
-
-	for_each_cpu_online(i) {
-		if (start_threads(i)) {
-			fprintf(stderr, "Failed to start worker threads\n");
-			break;
-		}
-	}
-
-	if (i != ncpus) {
-		stop_threads();
-		cleanup_trace();
-		return 1;
-	}
-
-	return 0;
-}
-
-static void wait_for_threads(void)
-{
-	struct thread_information *tip;
-	int i, tips_running;
-
-	do {
-		tips_running = 0;
-		usleep(100000);
-
-		for_each_tip(tip, i)
-			tips_running += !tip->exited;
-
-	} while (tips_running);
-}
-
-static void show_stats(void)
-{
-	struct thread_information *tip;
-	unsigned long long data_read;
-	int i;
-
-	data_read = 0;
-	for_each_tip(tip, i) {
-		printf("  CPU%3d: %8llu KiB data\n",
-			tip->cpu, (tip->data_read + 1023) >> 10);
-		data_read += tip->data_read;
-	}
-
-	printf("  Total:  lost %lu, %8llu KiB data\n",
-		trace_information.lost_records, (data_read + 1023) >> 10);
-
-	if (trace_information.lost_records)
-		fprintf(stderr, "You have lost records, "
-				"consider using a larger buffer size (-b)\n");
-}
-
-static char usage_str[] = \
-	"[ -r debugfs path ] [ -D output dir ] [ -b buffer size ]\n" \
-	"[ -n number of buffers] [ -o <output file> ] [ -w time  ] [ -V ]\n\n" \
-	"\t-r Path to mounted debugfs, defaults to /sys/kernel/debug\n" \
-	"\t-o File(s) to send output to\n" \
-	"\t-D Directory to prepend to output file names\n" \
-	"\t-w Stop after defined time, in seconds\n" \
-	"\t-b Sub buffer size in KiB\n" \
-	"\t-n Number of sub buffers\n" \
-	"\t-V Print program version info\n\n";
-
-static void show_usage(char *prog)
-{
-	fprintf(stderr, "Usage: %s %s %s", prog, kvmtrace_version, usage_str);
-	exit(EXIT_FAILURE);
-}
-
-void parse_args(int argc, char **argv)
-{
-	int c;
-
-	while ((c = getopt_long(argc, argv, S_OPTS, l_opts, NULL)) >= 0) {
-		switch (c) {
-		case 'r':
-			debugfs_path = optarg;
-			break;
-		case 'o':
-			output_name = optarg;
-			break;
-		case 'w':
-			stop_watch = atoi(optarg);
-			if (stop_watch <= 0) {
-				fprintf(stderr,
-					"Invalid stopwatch value (%d secs)\n",
-					stop_watch);
-				exit(EXIT_FAILURE);
-			}
-			break;
-		case 'V':
-			printf("%s version %s\n", argv[0], kvmtrace_version);
-			exit(EXIT_SUCCESS);
-		case 'b':
-			buf_size = strtoul(optarg, NULL, 10);
-			if (buf_size <= 0 || buf_size > 16*1024) {
-				fprintf(stderr,
-					"Invalid buffer size (%lu)\n",
-					buf_size);
-				exit(EXIT_FAILURE);
-			}
-			buf_size <<= 10;
-			break;
-		case 'n':
-			buf_nr = strtoul(optarg, NULL, 10);
-			if (buf_nr <= 0) {
-				fprintf(stderr,
-					"Invalid buffer nr (%lu)\n", buf_nr);
-				exit(EXIT_FAILURE);
-			}
-			break;
-		case 'D':
-			output_dir = optarg;
-			break;
-		default:
-			show_usage(argv[0]);
-		}
-	}
-
-	if (optind < argc || output_name == NULL)
-		show_usage(argv[0]);
-}
-
-int main(int argc, char *argv[])
-{
-	struct statfs st;
-
-	parse_args(argc, argv);
-
-	if (!debugfs_path)
-		debugfs_path = default_debugfs_path;
-
-	if (statfs(debugfs_path, &st) < 0) {
-		perror("statfs");
-		fprintf(stderr, "%s does not appear to be a valid path\n",
-			debugfs_path);
-		return 1;
-	} else if (st.f_type != (long) DEBUGFS_TYPE) {
-		fprintf(stderr, "%s does not appear to be a debug filesystem,"
-			" please mount debugfs.\n",
-			debugfs_path);
-		return 1;
-	}
-
-	page_size = getpagesize();
-
-	ncpus = sysconf(_SC_NPROCESSORS_ONLN);
-	if (ncpus < 0) {
-		fprintf(stderr, "sysconf(_SC_NPROCESSORS_ONLN) failed\n");
-		return 1;
-	}
-
-	signal(SIGINT, handle_sigint);
-	signal(SIGHUP, handle_sigint);
-	signal(SIGTERM, handle_sigint);
-	signal(SIGALRM, handle_sigint);
-	signal(SIGPIPE, SIG_IGN);
-
-	if (start_kvm_trace() != 0)
-		return 1;
-
-	if (stop_watch)
-		alarm(stop_watch);
-
-	wait_for_threads();
-	stop_all_traces();
-	show_stats();
-
-	return 0;
-}
diff --git a/kvmtrace_format b/kvmtrace_format
deleted file mode 100755
index 6556475f726c4..0000000000000
--- a/kvmtrace_format
+++ /dev/null
@@ -1,532 +0,0 @@
-#!/usr/bin/env python
-
-# by Mark Williamson, (C) 2004 Intel Research Cambridge
-
-# Program for reformatting trace buffer output according to user-supplied rules
-
-import re, sys, string, signal, struct, os, getopt, operator
-
-PREFIX = '/usr'
-DATADIR = os.path.join(PREFIX, 'share')
-KVMDIR = os.path.join(DATADIR, 'kvm')
-FORMATS_FILE = os.path.join(KVMDIR, 'formats')
-
-def usage():
-    print >> sys.stderr, \
-          "Usage: " + sys.argv[0] + """ defs-file
-          Parses trace data in binary format, as output by kvmtrace and
-          reformats it according to the rules in a file of definitions.  The
-          rules in this file should have the format ({ and } show grouping
-          and are not part of the syntax):
-
-          {event_id}{whitespace}{text format string}
-
-          The textual format string may include format specifiers, such as:
-            %(ts)d, %(event)d, %(pid)d %(vcpu)d %(1)d, %(2)d,
-	    %(3)d, %(4)d, %(5)d
-          [ the 'd' format specifier outputs in decimal, alternatively 'x'
-            will output in hexadecimal and 'o' will output in octal ]
-
-          Which correspond to the event ID, timestamp counter, pid
-	  , vcpu and the 5 data fields from the trace record.  There should be
-	  one such rule for each type of event.
-          Depending on your system and the volume of trace buffer data,
-          this script may not be able to keep up with the output of kvmtrace
-          if it is piped directly.  In these circumstances you should have
-          kvmtrace output to a file for processing off-line.
-
-          kvmtrace_format has the following additional switches
-          -s     - if this switch is set additional trace statistics are
-                   created and printed at the end of the output
-          """
-    sys.exit(1)
-
-def read_defs(defs_file):
-    defs = {}
-
-    fd = open(defs_file)
-
-    reg = re.compile('(\S+)\s+(\S.*)')
-
-    while True:
-        line = fd.readline()
-        if not line:
-            break
-
-        if line[0] == '#' or line[0] == '\n':
-            continue
-
-        m = reg.match(line)
-
-        if not m: print >> sys.stderr, "Bad format file" ; sys.exit(1)
-
-        defs[str(eval(m.group(1)))] = m.group(2)
-
-    return defs
-
-def sighand(x,y):
-    global interrupted
-    interrupted = 1
-
-# ppc instruction decoding for event type 0x00020019 (PPC_INSTR)
-# some globals for statistic summaries
-stat_ppc_instr_mnemonic = {};
-stat_ppc_instr_spr = {};
-stat_ppc_instr_dcr = {};
-stat_ppc_instr_tlb = {};
-
-def ppc_instr_print_summary(sortedlist, colname):
-	print "\n\n%14s + %10s" % (colname, "count")
-	print "%s" % (15*"-"+"+"+11*"-")
-	sum = 0
-	for value, key in sortedlist:
-		sum += key
-		print "%14s | %10d" % (value, key)
-	print "%14s = %10d" % ("sum", sum)
-
-
-def ppc_instr_summary():
-	# don't print empty statistics
-        if stat_ppc_instr_mnemonic:
-		ppc_instr_print_summary(sorted(stat_ppc_instr_mnemonic.iteritems(), key=operator.itemgetter(1), reverse=True), "mnemonic")
-        if stat_ppc_instr_spr:
-		ppc_instr_print_summary(sorted(stat_ppc_instr_spr.iteritems(), key=operator.itemgetter(1), reverse=True), "mnemonic-spr")
-        if stat_ppc_instr_dcr:
-		ppc_instr_print_summary(sorted(stat_ppc_instr_dcr.iteritems(), key=operator.itemgetter(1), reverse=True), "mnemonic-dcr")
-        if stat_ppc_instr_tlb:
-		ppc_instr_print_summary(sorted(stat_ppc_instr_tlb.iteritems(), key=operator.itemgetter(1), reverse=True), "mnemonic-tlb")
-
-def get_op(instr):
-        return (instr >> 26);
-
-def get_xop(instr):
-        return (instr >> 1) & 0x3ff;
-
-def get_sprn(instr):
-	return ((instr >> 16) & 0x1f) | ((instr >> 6) & 0x3e0)
-
-def get_dcrn(instr):
-	return ((instr >> 16) & 0x1f) | ((instr >> 6) & 0x3e0);
-
-def get_tlbwe_type(instr):
-	ws = (instr >> 11) & 0x1f;
-	if ws == 0:
-		return "PAGEID"
-	elif ws == 1:
-		return "XLAT"
-	elif ws == 2:
-		return "ATTRIB"
-	else:
-		return "UNKNOWN"
-
-def get_name(instr):
-	if get_op(instr)==3:
-		return "trap"
-	elif get_op(instr)==19:
-		if get_xop(instr) == 50:
-			return "rfi"
-		else:
-			return "unknown"
-	elif get_op(instr)==31:
-		if get_xop(instr) == 83:
-			return "mfmsr"
-
-		elif get_xop(instr) == 87:
-			return "lbzx"
-
-		elif get_xop(instr) == 131:
-			return "wrtee"
-
-		elif get_xop(instr) == 146:
-			return "mtmsr"
-
-		elif get_xop(instr) == 163:
-			return "wrteei"
-
-		elif get_xop(instr) == 215:
-			return "stbx"
-
-		elif get_xop(instr) == 247:
-			return "stbux"
-
-		elif get_xop(instr) == 279:
-			return "lhzx"
-
-		elif get_xop(instr) == 311:
-			return "lhzux"
-
-		elif get_xop(instr) == 323:
-			return "mfdcr"
-
-		elif get_xop(instr) == 339:
-			return "mfspr"
-
-		elif get_xop(instr) == 407:
-			return "sthx"
-
-		elif get_xop(instr) == 439:
-			return "sthux"
-
-		elif get_xop(instr) == 451:
-			return "mtdcr"
-
-		elif get_xop(instr) == 467:
-			return "mtspr"
-
-		elif get_xop(instr) == 470:
-			return "dcbi"
-
-		elif get_xop(instr) == 534:
-			return "lwbrx"
-
-		elif get_xop(instr) == 566:
-			return "tlbsync"
-
-		elif get_xop(instr) == 662:
-			return "stwbrx"
-
-		elif get_xop(instr) == 978:
-			return "tlbwe"
-
-		elif get_xop(instr) == 914:
-			return "tlbsx"
-
-		elif get_xop(instr) == 790:
-			return "lhbrx"
-
-		elif get_xop(instr) == 918:
-			return "sthbrx"
-
-		elif get_xop(instr) == 966:
-			return "iccci"
-
-		else:
-			return "unknown"
-
-	elif get_op(instr) == 32:
-		return "lwz"
-
-	elif get_op(instr) == 33:
-		return "lwzu"
-
-	elif get_op(instr) == 34:
-		return "lbz"
-
-	elif get_op(instr) == 35:
-		return "lbzu"
-
-	elif get_op(instr) == 36:
-		return "stw"
-
-	elif get_op(instr) == 37:
-		return "stwu"
-
-	elif get_op(instr) == 38:
-		return "stb"
-
-	elif get_op(instr) == 39:
-		return "stbu"
-
-	elif get_op(instr) == 40:
-		return "lhz"
-
-	elif get_op(instr) == 41:
-		return "lhzu"
-
-	elif get_op(instr) == 44:
-		return "sth"
-
-	elif get_op(instr) == 45:
-		return "sthu"
-
-	else:
-		return "unknown"
-
-def get_sprn_name(sprn):
-		if sprn == 0x01a:
-			return "SRR0"
-		elif sprn == 0x01b:
-			return "SRR1"
-		elif sprn == 0x3b2:
-			return "MMUCR"
-		elif sprn == 0x030:
-			return "PID"
-		elif sprn == 0x03f:
-			return "IVPR"
-		elif sprn == 0x3b3:
-			return "CCR0"
-		elif sprn == 0x378:
-			return "CCR1"
-		elif sprn == 0x11f:
-			return "PVR"
-		elif sprn == 0x03d:
-			return "DEAR"
-		elif sprn == 0x03e:
-			return "ESR"
-		elif sprn == 0x134:
-			return "DBCR0"
-		elif sprn == 0x135:
-			return "DBCR1"
-		elif sprn == 0x11c:
-			return "TBWL"
-		elif sprn == 0x11d:
-			return "TBWU"
-		elif sprn == 0x016:
-			return "DEC"
-		elif sprn == 0x150:
-			return "TSR"
-		elif sprn == 0x154:
-			return "TCR"
-		elif sprn == 0x110:
-			return "SPRG0"
-		elif sprn == 0x111:
-			return "SPRG1"
-		elif sprn == 0x112:
-			return "SPRG2"
-		elif sprn == 0x113:
-			return "SPRG3"
-		elif sprn == 0x114:
-			return "SPRG4"
-		elif sprn == 0x115:
-			return "SPRG5"
-		elif sprn == 0x116:
-			return "SPRG6"
-		elif sprn == 0x117:
-			return "SPRG7"
-		elif sprn == 0x190:
-			return "IVOR0"
-		elif sprn == 0x191:
-			return "IVOR1"
-		elif sprn == 0x192:
-			return "IVOR2"
-		elif sprn == 0x193:
-			return "IVOR3"
-		elif sprn == 0x194:
-			return "IVOR4"
-		elif sprn == 0x195:
-			return "IVOR5"
-		elif sprn == 0x196:
-			return "IVOR6"
-		elif sprn == 0x197:
-			return "IVOR7"
-		elif sprn == 0x198:
-			return "IVOR8"
-		elif sprn == 0x199:
-			return "IVOR9"
-		elif sprn == 0x19a:
-			return "IVOR10"
-		elif sprn == 0x19b:
-			return "IVOR11"
-		elif sprn == 0x19c:
-			return "IVOR12"
-		elif sprn == 0x19d:
-			return "IVOR13"
-		elif sprn == 0x19e:
-			return "IVOR14"
-		elif sprn == 0x19f:
-			return "IVOR15"
-		else:
-			return "UNKNOWN"
-
-def get_special(instr):
-	name = get_name(instr);
-	if stat_ppc_instr_mnemonic.has_key(name):
-		stat_ppc_instr_mnemonic[name] += 1
-	else:
-		stat_ppc_instr_mnemonic[name] = 1
-
-	if get_op(instr) == 31:
-		if (get_xop(instr) == 339) or (get_xop(instr) == 467):
-			sprn = get_sprn(instr);
-			sprn_name = get_sprn_name(sprn);
-			stat_idx = name+"-"+sprn_name
-			if stat_ppc_instr_spr.has_key(stat_idx):
-				stat_ppc_instr_spr[stat_idx] += 1
-			else:
-				stat_ppc_instr_spr[stat_idx] = 1
-			return ("- sprn 0x%03x %8s" % (sprn, sprn_name))
-		elif (get_xop(instr) == 323 ) or (get_xop(instr) == 451):
-			dcrn = get_dcrn(instr);
-			stat_idx = name+"-"+("%04X"%dcrn)
-			if stat_ppc_instr_dcr.has_key(stat_idx):
-				stat_ppc_instr_dcr[stat_idx] += 1
-			else:
-				stat_ppc_instr_dcr[stat_idx] = 1
-			return ("- dcrn 0x%03x" % dcrn)
-		elif (get_xop(instr) == 978 ) or (get_xop(instr) == 451):
-			tlbwe_type = get_tlbwe_type(instr)
-			stat_idx = name+"-"+tlbwe_type
-			if stat_ppc_instr_tlb.has_key(stat_idx):
-				stat_ppc_instr_tlb[stat_idx] += 1
-			else:
-				stat_ppc_instr_tlb[stat_idx] = 1
-			return ("- ws -> %8s" % tlbwe_type)
-	return ""
-
-##### Main code
-
-summary = False
-
-try:
-    opts, arg = getopt.getopt(sys.argv[1:], "sc:" )
-    for opt in opts:
-        if opt[0] == '-s' : summary = True
-
-except getopt.GetoptError:
-    usage()
-
-signal.signal(signal.SIGTERM, sighand)
-signal.signal(signal.SIGHUP,  sighand)
-signal.signal(signal.SIGINT,  sighand)
-
-interrupted = 0
-
-if len(arg) > 0:
-    defs = read_defs(arg[0])
-else:
-    defs = read_defs(FORMATS_FILE)
-
-# structure of trace record (as output by kvmtrace):
-# HDR(I) {TSC(Q)} D1(I) D2(I) D3(I) D4(I) D5(I)
-#
-# HDR consists of EVENT:28:, n_data:3:, ts_in:1:
-# pid:32, vcpu_id:32
-# EVENT means Event ID
-# n_data means number of data (like D1, D2, ...)
-# ts_in means Timestamp data exists(1) or not(0).
-# if ts_in == 0, TSC(Q) does not exists.
-#
-HDRREC = "<III"
-TSCREC = "<Q"
-D1REC  = "<I"
-D2REC  = "<II"
-D3REC  = "<III"
-D4REC  = "<IIII"
-D5REC  = "<IIIII"
-KMAGIC  = "<I"
-
-last_ts = 0
-
-i=0
-
-while not interrupted:
-    try:
-        i=i+1
-
-        if i == 1:
-            line = sys.stdin.read(struct.calcsize(KMAGIC))
-            if not line:
-                break
-            kmgc = struct.unpack(KMAGIC, line)[0]
-
-            #firstly try to parse data file as little endian
-            # if "kvmtrace-metadata".kmagic != kmagic
-            # then data file must be big endian"
-            if kmgc != 0x12345678:
-                if kmgc != 0x78563412:
-                    print >> sys.stderr, "Bad data file: magic number error."
-                    break;
-                else:
-                    HDRREC = ">III"
-                    TSCREC = ">Q"
-                    D1REC  = ">I"
-                    D2REC  = ">II"
-                    D3REC  = ">III"
-                    D4REC  = ">IIII"
-                    D5REC  = ">IIIII"
-            continue
-
-        line = sys.stdin.read(struct.calcsize(HDRREC))
-        if not line:
-            break
-	(event, pid, vcpu_id) = struct.unpack(HDRREC, line)
-
-        n_data = event >> 28 & 0x7
-        ts_in = event >> 31
-
-        d1 = 0
-        d2 = 0
-        d3 = 0
-        d4 = 0
-        d5 = 0
-
-        ts = 0
-
-        if ts_in == 1:
-            line = sys.stdin.read(struct.calcsize(TSCREC))
-            if not line:
-                break
-            ts = struct.unpack(TSCREC, line)[0]
-        if n_data == 1:
-            line = sys.stdin.read(struct.calcsize(D1REC))
-            if not line:
-                break
-            d1 = struct.unpack(D1REC, line)[0]
-        if n_data == 2:
-            line = sys.stdin.read(struct.calcsize(D2REC))
-            if not line:
-                break
-            (d1, d2) = struct.unpack(D2REC, line)
-        if n_data == 3:
-            line = sys.stdin.read(struct.calcsize(D3REC))
-            if not line:
-                break
-            (d1, d2, d3) = struct.unpack(D3REC, line)
-        if n_data == 4:
-            line = sys.stdin.read(struct.calcsize(D4REC))
-            if not line:
-                break
-            (d1, d2, d3, d4) = struct.unpack(D4REC, line)
-        if n_data == 5:
-            line = sys.stdin.read(struct.calcsize(D5REC))
-            if not line:
-                break
-            (d1, d2, d3, d4, d5) = struct.unpack(D5REC, line)
-
-	event &= 0x0fffffff
-
-        # provide relative TSC
-
-        if last_ts > 0 and ts_in == 1:
-            relts = ts - last_ts
-        else:
-            relts = 0
-
-        if ts_in == 1:
-            last_ts = ts
-
-        args = {'ts'   : ts,
-                'event' : event,
-                'relts': relts,
-		'pid'   : pid,
-		'vcpu'  : vcpu_id,
-                '1'     : d1,
-                '2'     : d2,
-                '3'     : d3,
-                '4'     : d4,
-                '5'     : d5    }
-
-        # some event types need more than just formats mapping they are if/elif
-        # chained here and the last default else is the mapping via formats
-        if event == 0x00020019:
-            pdata = (ts, relts, vcpu_id, pid, d1, d2, d3, get_name(d1), get_special(d1))
-            print "%d (+%12d)  PPC_INSTR vcpu = 0x%08x  pid = 0x%08x [ instr = 0x%08x, pc = 0x%08x, emul = %01d, mnemonic = %8s %s" % pdata
-        else:
-            try:
-                if defs.has_key(str(event)):
-                    print defs[str(event)] % args
-                else:
-                    if defs.has_key(str(0)): print defs[str(0)] % args
-            except TypeError:
-                if defs.has_key(str(event)):
-                    print defs[str(event)]
-                    print args
-                else:
-                    if defs.has_key(str(0)):
-                        print defs[str(0)]
-                        print args
-
-    except IOError, struct.error: sys.exit()
-
-if summary:
-	ppc_instr_summary()
diff --git a/lib/fwcfg.c b/lib/fwcfg.c
deleted file mode 100644
index dc34d299df766..0000000000000
--- a/lib/fwcfg.c
+++ /dev/null
@@ -1,58 +0,0 @@
-
-void qemu_cfg_select(int f)
-{
-    outw(QEMU_CFG_CTL_PORT, f);
-}
-
-int qemu_cfg_port_probe()
-{
-    char *sig = "QEMU";
-    int i;
-
-    qemu_cfg_select(QEMU_CFG_SIGNATURE);
-
-    for (i = 0; i < 4; i++)
-        if (inb(QEMU_CFG_DATA_PORT) != sig[i])
-            return 0;
-
-    return 1;
-}
-
-void qemu_cfg_read(uint8_t *buf, int len)
-{
-    while (len--)
-        *(buf++) = inb(QEMU_CFG_DATA_PORT);
-}
-
-uint8_t qemu_cfg_get8(void)
-{
-    uint8_t ret;
-
-    qemu_cfg_read(&ret, 1);
-    return ret;
-}
-
-uint16_t qemu_cfg_get16(void)
-{
-    uint16_t ret;
-
-    qemu_cfg_read((uint8_t*)&ret, 2);
-    return le16_to_cpu(ret);
-}
-
-uint64_t qemu_cfg_get32(void)
-{
-    uint32_t ret;
-
-    qemu_cfg_read((uint8_t*)&ret, 4);
-    return le32_to_cpu(ret);
-}
-
-uint64_t qemu_cfg_get64(void)
-{
-    uint64_t ret;
-
-    qemu_cfg_read((uint8_t*)&ret, 8);
-    return le64_to_cpu(ret);
-}
-
diff --git a/lib/libcflat.h b/lib/libcflat.h
index fadc33d30f85b..140c172e77d54 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -38,7 +38,6 @@ typedef _Bool bool;
 #define false 0
 
 extern void exit(int code);
-extern void panic(char *fmt, ...);
 
 extern unsigned long strlen(const char *buf);
 extern char *strcat(char *dest, const char *src);
diff --git a/lib/panic.c b/lib/panic.c
deleted file mode 100644
index 6e0b29ebed503..0000000000000
--- a/lib/panic.c
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "libcflat.h"
-
-void panic(char *fmt, ...)
-{
-	va_list va;
-	char buf[2000];
-
-	va_start(va, fmt);
-	vsnprintf(buf, sizeof(buf), fmt, va);
-	va_end(va);
-	puts(buf);
-	exit(-1);
-}
diff --git a/lib/powerpc/44x/map.c b/lib/powerpc/44x/map.c
deleted file mode 100644
index 113434d2f1b4d..0000000000000
--- a/lib/powerpc/44x/map.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- * Copyright IBM Corp. 2008
- *
- * Authors: Hollis Blanchard <hollisb@us.ibm.com>
- */
-
-#include "libcflat.h"
-
-#define TLB_SIZE 64
-
-extern void tlbwe(unsigned int index,
-		  unsigned char tid,
-		  unsigned int word0,
-		  unsigned int word1,
-		  unsigned int word2);
-
-unsigned int next_free_index;
-
-#define PAGE_SHIFT 12
-#define PAGE_MASK (~((1<<PAGE_SHIFT)-1))
-
-#define V (1<<9)
-
-void map(unsigned long vaddr, unsigned long paddr)
-{
-	unsigned int w0, w1, w2;
-
-	/* We don't install exception handlers, so we can't handle TLB misses,
-	 * so we can't loop around and overwrite entry 0. */
-	if (next_free_index++ >= TLB_SIZE)
-		panic("TLB overflow");
-
-	w0 = (vaddr & PAGE_MASK) | V;
-	w1 = paddr & PAGE_MASK;
-	w2 = 0x3;
-
-	tlbwe(next_free_index, 0, w0, w1, w2);
-}
diff --git a/lib/powerpc/44x/timebase.S b/lib/powerpc/44x/timebase.S
deleted file mode 100644
index 385904da3c161..0000000000000
--- a/lib/powerpc/44x/timebase.S
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- * Copyright IBM Corp. 2008
- *
- * Authors: Hollis Blanchard <hollisb@us.ibm.com>
- */
-
-/* unsigned long long mftb(void); */
-.global mftb
-mftb:
-	mftbu	r5
-	mftbl 	r4
-	mftbu 	r3
-	cmpw 	r3, r5
-	bne 	mftb
-	blr
diff --git a/lib/powerpc/44x/timebase.h b/lib/powerpc/44x/timebase.h
deleted file mode 100644
index ce85347bd17c5..0000000000000
--- a/lib/powerpc/44x/timebase.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- * Copyright IBM Corp. 2008
- *
- * Authors: Hollis Blanchard <hollisb@us.ibm.com>
- */
-
-#ifndef __TIMEBASE_H__
-#define __TIMEBASE_H__
-
-unsigned long long mftb(void);
-
-#endif /* __TIMEBASE_H__ */
diff --git a/lib/powerpc/44x/tlbwe.S b/lib/powerpc/44x/tlbwe.S
deleted file mode 100644
index 3790374eb5c61..0000000000000
--- a/lib/powerpc/44x/tlbwe.S
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- * Copyright IBM Corp. 2008
- *
- * Authors: Hollis Blanchard <hollisb@us.ibm.com>
- */
-
-#define SPRN_MMUCR 0x3b2
-
-/* tlbwe(uint index, uint8_t tid, uint word0, uint word1, uint word2) */
-.global tlbwe
-tlbwe:
-	mtspr	SPRN_MMUCR, r4
-	tlbwe	r5, r3, 0
-	tlbwe	r6, r3, 1
-	tlbwe	r7, r3, 2
-	blr
diff --git a/lib/powerpc/io.c b/lib/powerpc/io.c
deleted file mode 100644
index 8bd239521f25f..0000000000000
--- a/lib/powerpc/io.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- * Copyright IBM Corp. 2008
- *
- * Authors: Hollis Blanchard <hollisb@us.ibm.com>
- */
-
-#include "libcflat.h"
-
-#define BASE 0xf0000000
-#define _putc ((volatile char *)(BASE))
-#define _exit ((volatile char *)(BASE+1))
-
-void puts(const char *s)
-{
-	while (*s != '\0')
-		*_putc = *s++;
-}
-
-void exit(int code)
-{
-	*_exit = code;
-}
diff --git a/main-ppc.c b/main-ppc.c
deleted file mode 100644
index 5af59f846ef07..0000000000000
--- a/main-ppc.c
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * 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 <avi@qumranet.com>
- *  Yaniv Kamay <yaniv@qumranet.com>
- *  Hollis Blanchard <hollisb@us.ibm.com>
- *
- * 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>
-
-#include "iotable.h"
-
-static int gettid(void)
-{
-	return syscall(__NR_gettid);
-}
-
-kvm_context_t kvm;
-
-#define IPI_SIGNAL (SIGRTMIN + 4)
-
-struct io_table mmio_table;
-
-static int ncpus = 1;
-static sem_t exited_sem;
-static __thread int vcpu;
-static sigset_t kernel_sigmask;
-static sigset_t ipi_sigmask;
-static uint64_t memory_size = 128 * 1024 * 1024;
-
-struct vcpu_info {
-	pid_t tid;
-};
-
-struct vcpu_info *vcpus;
-
-/* Must match flat.lds linker script */
-#define VM_TEST_LOAD_ADDRESS 0x100000
-
-static int test_debug(void *opaque, void *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, void *vcpu)
-{
-}
-
-static int test_pre_kvm_run(void *opaque, void *vcpu)
-{
-	return 0;
-}
-
-static int mmio_handler(void *opaque, int len, int is_write, uint64_t offset,
-                        uint64_t *data)
-{
-	int r = 0;
-
-	switch (offset) {
-	case 0: /* putc */
-		putc(*(char *)data, stdout);
-		fflush(stdout);
-		break;
-	case 1: /* exit */
-		r = *(char *)data;
-		break;
-	default:
-		printf("%s: offset %"PRIx64" len %d data %"PRIx64"\n",
-		       __func__, offset, len, *(uint64_t *)data);
-		r = -EINVAL;
-	}
-
-	return r;
-}
-
-static int test_mem_read(void *opaque, uint64_t addr, uint8_t *data, int len)
-{
-	struct io_table_entry *iodev;
-
-#if 0
-	printf("%s: addr %"PRIx64" len %d\n", __func__, addr, len);
-#endif
-
-	iodev = io_table_lookup(&mmio_table, addr);
-	if (!iodev) {
-		printf("couldn't find device\n");
-		return -ENODEV;
-	}
-
-	return iodev->handler(iodev->opaque, len, 0, addr - iodev->start,
-	                      (uint64_t *)data);
-}
-
-static int test_mem_write(void *opaque, uint64_t addr, uint8_t *data, int len)
-{
-	struct io_table_entry *iodev;
-
-#if 0
-	printf("%s: addr %"PRIx64" len %d data %"PRIx64"\n",
-	       __func__, addr, len, *(uint64_t *)data);
-#endif
-
-	iodev = io_table_lookup(&mmio_table, addr);
-	if (!iodev) {
-		printf("couldn't find device\n");
-		return -ENODEV;
-	}
-
-	return iodev->handler(iodev->opaque, len, 1, addr - iodev->start,
-	                      (uint64_t *)data);
-}
-
-static int test_dcr_read(int vcpu, uint32_t dcrn, uint32_t *data)
-{
-	printf("%s: dcrn %04X\n", __func__, dcrn);
-	*data = 0;
-	return 0;
-}
-
-static int test_dcr_write(int vcpu, uint32_t dcrn, uint32_t data)
-{
-	printf("%s: dcrn %04X data %04X\n", __func__, dcrn, 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,
-	.powerpc_dcr_read = test_dcr_read,
-	.powerpc_dcr_write = test_dcr_write,
-};
-
-static unsigned long load_file(void *mem, const char *fname, int inval_icache)
-{
-	ssize_t 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");
-		printf("read %d bytes\n", bytes);
-		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)
-{
-	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);
-}
-
-static void *do_create_vcpu(void *_n)
-{
-	struct kvm_regs regs;
-	int n = (long)_n;
-
-	kvm_create_vcpu(kvm, n);
-	init_vcpu(n);
-
-	kvm_get_regs(kvm, n, &regs);
-	regs.pc = VM_TEST_LOAD_ADDRESS;
-	kvm_set_regs(kvm, n, &regs);
-
-	kvm_run(kvm, n, &vcpus[n]);
-	sem_post(&exited_sem);
-	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-ppc@vger.kernel.org>.\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 + VM_TEST_LOAD_ADDRESS, argv[optind], 1);
-	sync_caches(vm_mem + VM_TEST_LOAD_ADDRESS, len);
-
-	io_table_register(&mmio_table, 0xf0000000, 64, mmio_handler, NULL);
-
-	sem_init(&exited_sem, 0, 0);
-	for (i = 0; i < ncpus; ++i)
-		start_vcpu(i);
-	/* Wait for all vcpus to exit. */
-	for (i = 0; i < ncpus; ++i)
-		sem_wait(&exited_sem);
-
-	return 0;
-}
diff --git a/powerpc/44x/tlbsx.S b/powerpc/44x/tlbsx.S
deleted file mode 100644
index b15874b18b74c..0000000000000
--- a/powerpc/44x/tlbsx.S
+++ /dev/null
@@ -1,33 +0,0 @@
-#define SPRN_MMUCR 0x3b2
-
-#define TLBWORD0 0x10000210
-#define TLBWORD1 0x10000000
-#define TLBWORD2 0x00000003
-
-.global _start
-_start:
-	li	r4, 0
-	mtspr	SPRN_MMUCR, r4
-
-	li	r3, 23
-
-	lis	r4, TLBWORD0@h
-	ori	r4, r4, TLBWORD0@l
-	tlbwe	r4, r3, 0
-
-	lis	r4, TLBWORD1@h
-	ori	r4, r4, TLBWORD1@l
-	tlbwe	r4, r3, 1
-
-	lis	r4, TLBWORD2@h
-	ori	r4, r4, TLBWORD2@l
-	tlbwe	r4, r3, 2
-
-	lis	r4, 0x1000
-	tlbsx	r5, r4, r0
-	cmpwi	r5, 23
-	beq	good
-	trap
-
-good:
-	b	.
diff --git a/powerpc/44x/tlbwe.S b/powerpc/44x/tlbwe.S
deleted file mode 100644
index ec6ef5c57fc47..0000000000000
--- a/powerpc/44x/tlbwe.S
+++ /dev/null
@@ -1,27 +0,0 @@
-#define SPRN_MMUCR 0x3b2
-
-/* Create a mapping at 4MB */
-#define TLBWORD0 0x00400210
-#define TLBWORD1 0x00400000
-#define TLBWORD2 0x00000003
-
-.global _start
-_start:
-	li	r4, 0
-	mtspr	SPRN_MMUCR, r4
-
-	li	r3, 23
-
-	lis	r4, TLBWORD0@h
-	ori	r4, r4, TLBWORD0@l
-	tlbwe	r4, r3, 0
-
-	lis	r4, TLBWORD1@h
-	ori	r4, r4, TLBWORD1@l
-	tlbwe	r4, r3, 1
-
-	lis	r4, TLBWORD2@h
-	ori	r4, r4, TLBWORD2@l
-	tlbwe	r4, r3, 2
-
-	b	.
diff --git a/powerpc/44x/tlbwe_16KB.S b/powerpc/44x/tlbwe_16KB.S
deleted file mode 100644
index 1bd10bf17a187..0000000000000
--- a/powerpc/44x/tlbwe_16KB.S
+++ /dev/null
@@ -1,35 +0,0 @@
-#define SPRN_MMUCR 0x3b2
-
-/* 16KB mapping at 4MB */
-#define TLBWORD0 0x00400220
-#define TLBWORD1 0x00400000
-#define TLBWORD2 0x00000003
-
-.global _start
-_start:
-	li	r4, 0
-	mtspr	SPRN_MMUCR, r4
-
-	li	r3, 5
-
-	lis	r4, TLBWORD0@h
-	ori	r4, r4, TLBWORD0@l
-	tlbwe	r4, r3, 0
-
-	lis	r4, TLBWORD1@h
-	ori	r4, r4, TLBWORD1@l
-	tlbwe	r4, r3, 1
-
-	lis	r4, TLBWORD2@h
-	ori	r4, r4, TLBWORD2@l
-	tlbwe	r4, r3, 2
-
-	/* load from 4MB */
-	lis	r3, 0x0040
-	lwz	r4, 0(r3)
-
-	/* load from 4MB+8KB */
-	ori	r3, r3, 0x2000
-	lwz	r4, 0(r3)
-
-	b	.
diff --git a/powerpc/44x/tlbwe_hole.S b/powerpc/44x/tlbwe_hole.S
deleted file mode 100644
index 5efd30357daa9..0000000000000
--- a/powerpc/44x/tlbwe_hole.S
+++ /dev/null
@@ -1,27 +0,0 @@
-#define SPRN_MMUCR 0x3b2
-
-/* Try to map real address 1GB. */
-#define TLBWORD0 0x40000210
-#define TLBWORD1 0x40000000
-#define TLBWORD2 0x00000003
-
-.global _start
-_start:
-	li	r4, 0
-	mtspr	SPRN_MMUCR, r4
-
-	li	r3, 23
-
-	lis	r4, TLBWORD0@h
-	ori	r4, r4, TLBWORD0@l
-	tlbwe	r4, r3, 0
-
-	lis	r4, TLBWORD1@h
-	ori	r4, r4, TLBWORD1@l
-	tlbwe	r4, r3, 1
-
-	lis	r4, TLBWORD2@h
-	ori	r4, r4, TLBWORD2@l
-	tlbwe	r4, r3, 2
-
-	b	.
diff --git a/powerpc/cstart.S b/powerpc/cstart.S
deleted file mode 100644
index 70a0e9fcd47c9..0000000000000
--- a/powerpc/cstart.S
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- * Copyright IBM Corp. 2008
- *
- * Authors: Hollis Blanchard <hollisb@us.ibm.com>
- */
-
-#define OUTPUT_VADDR 0xf0000000
-#define OUTPUT_PADDR 0xf0000000
-
-.globl _start
-_start:
-	/* In the future we might need to assign a stack and zero BSS here. */
-
-	/* Map the debug page 1:1. */
-	lis	r3, OUTPUT_VADDR@h
-	ori	r3, r3, OUTPUT_VADDR@l
-	lis	r4, OUTPUT_PADDR@h
-	ori	r4, r4, OUTPUT_PADDR@l
-	bl	map
-
-	/* Call main() and pass return code to exit(). */
-	bl	main
-	bl	exit
-
-	b	.
diff --git a/powerpc/exit.c b/powerpc/exit.c
deleted file mode 100644
index 804ee04d9f88e..0000000000000
--- a/powerpc/exit.c
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- * Copyright IBM Corp. 2008
- *
- * Authors: Hollis Blanchard <hollisb@us.ibm.com>
- */
-
-int main(void)
-{
-	return 1;
-}
diff --git a/powerpc/helloworld.c b/powerpc/helloworld.c
deleted file mode 100644
index f8630f7c5381f..0000000000000
--- a/powerpc/helloworld.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- * Copyright IBM Corp. 2008
- *
- * Authors: Deepa Srinivasan <deepas@us.ibm.com>
- */
-
-#include "libcflat.h"
-
-int main()
-{
-	printf("Hello World\n");
-
-	return 1;
-}
diff --git a/powerpc/io.S b/powerpc/io.S
deleted file mode 100644
index 97567cb6c73f2..0000000000000
--- a/powerpc/io.S
+++ /dev/null
@@ -1,32 +0,0 @@
-#define SPRN_MMUCR 0x3b2
-
-#define TLBWORD0 0xf0000210
-#define TLBWORD1 0xf0000000
-#define TLBWORD2 0x00000003
-
-.global _start
-_start:
-	li	r4, 0
-	mtspr	SPRN_MMUCR, r4
-
-	li	r3, 2
-
-	lis	r4, TLBWORD0@h
-	ori	r4, r4, TLBWORD0@l
-	tlbwe	r4, r3, 0
-
-	lis	r4, TLBWORD1@h
-	ori	r4, r4, TLBWORD1@l
-	tlbwe	r4, r3, 1
-
-	lis	r4, TLBWORD2@h
-	ori	r4, r4, TLBWORD2@l
-	tlbwe	r4, r3, 2
-
-	lis	r3, 0xf000
-	lis	r4, 0x1234
-	ori	r4, r4, 0x5678
-	stb	r4, 0(r3)
-	lbz	r5, 0(r3)
-
-	b	.
diff --git a/powerpc/spin.S b/powerpc/spin.S
deleted file mode 100644
index 4406641c2711c..0000000000000
--- a/powerpc/spin.S
+++ /dev/null
@@ -1,4 +0,0 @@
-
-.global _start
-_start:
-	b	.
diff --git a/powerpc/sprg.S b/powerpc/sprg.S
deleted file mode 100644
index d0414a480342a..0000000000000
--- a/powerpc/sprg.S
+++ /dev/null
@@ -1,7 +0,0 @@
-
-.global _start
-_start:
-	li	r3, 42
-	mtsprg	0, r3
-	mfsprg	r4, 0
-	b	.
diff --git a/x86/print.h b/x86/print.h
deleted file mode 100644
index d5bd2f9978dc4..0000000000000
--- a/x86/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/x86/run-kvm-unit-tests b/x86/run-kvm-unit-tests
deleted file mode 100644
index fed925a3d70fe..0000000000000
--- a/x86/run-kvm-unit-tests
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/python
-
-import sys, os, os.path
-
-prog = sys.argv[0]
-dir = os.path.dirname(prog)
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 02/17] makefile and run_tests tweaks
  2014-01-21 16:21 [PATCH 00/17] kvm-unit-tests/arm: initial drop Andrew Jones
  2014-01-21 16:21 ` [PATCH 01/17] remove unused files Andrew Jones
@ 2014-01-21 16:21 ` Andrew Jones
  2014-01-21 16:21 ` [PATCH 03/17] clean root dir of all x86-ness Andrew Jones
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 47+ messages in thread
From: Andrew Jones @ 2014-01-21 16:21 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: christoffer.dall

- remove a redundant '-display none'
- remove a redundant -g from CFLAGS
- remove a useless -I../include/x86 from CFLAGS
- remove lib autodep files on make clean

- v3: reword run_tests.sh help text [Christoffer Dall]

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 Makefile              | 11 ++++++-----
 config-x86-common.mak | 16 +++++++---------
 run_tests.sh          |  6 +++---
 x86/README            | 38 +++++++++++++++++++++++++++++++-------
 4 files changed, 47 insertions(+), 24 deletions(-)

diff --git a/Makefile b/Makefile
index 278791dbbef23..4bb69427caeba 100644
--- a/Makefile
+++ b/Makefile
@@ -6,15 +6,15 @@ DESTDIR := $(PREFIX)/share/qemu/tests
 .PHONY: arch_clean clean
 
 #make sure env CFLAGS variable is not used
-CFLAGS = -g
+CFLAGS =
 
 libgcc := $(shell $(CC) --print-libgcc-file-name)
 
 libcflat := lib/libcflat.a
 cflatobjs := \
+	lib/argv.o \
 	lib/printf.o \
 	lib/string.o
-cflatobjs += lib/argv.o
 
 #include architecure specific make rules
 include config-$(ARCH).mak
@@ -25,8 +25,9 @@ include config-$(ARCH).mak
 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 += -O1
-CFLAGS += $(autodepend-flags) -g -fomit-frame-pointer -Wall
+CFLAGS += -g
+CFLAGS += $(autodepend-flags) -Wall
+CFLAGS += $(call cc-option, -fomit-frame-pointer, "")
 CFLAGS += $(call cc-option, -fno-stack-protector, "")
 CFLAGS += $(call cc-option, -fno-stack-protector-all, "")
 CFLAGS += -I.
@@ -51,4 +52,4 @@ install:
 	install $(tests_and_config) $(DESTDIR)
 
 clean: arch_clean
-	$(RM) *.o *.a .*.d $(libcflat) $(cflatobjs)
+	$(RM) *.o *.a .*.d lib/.*.d $(libcflat) $(cflatobjs)
diff --git a/config-x86-common.mak b/config-x86-common.mak
index bf88c672de472..7e481192a0737 100644
--- a/config-x86-common.mak
+++ b/config-x86-common.mak
@@ -1,13 +1,9 @@
 #This is a make file with common rules for both x86 & x86-64
 
-CFLAGS += -I../include/x86
-
 all: test_cases
 
-cflatobjs += \
-	lib/x86/io.o \
-	lib/x86/smp.o
-
+cflatobjs += lib/x86/io.o
+cflatobjs += lib/x86/smp.o
 cflatobjs += lib/x86/vm.o
 cflatobjs += lib/x86/fwcfg.o
 cflatobjs += lib/x86/apic.o
@@ -20,15 +16,17 @@ $(libcflat): LDFLAGS += -nostdlib
 $(libcflat): CFLAGS += -ffreestanding -I lib
 
 CFLAGS += -m$(bits)
+CFLAGS += -O1
 
 libgcc := $(shell $(CC) -m$(bits) --print-libgcc-file-name)
 
 FLATLIBS = lib/libcflat.a $(libgcc)
 %.elf: %.o $(FLATLIBS) flat.lds
-	$(CC) $(CFLAGS) -nostdlib -o $@ -Wl,-T,flat.lds $(filter %.o, $^) $(FLATLIBS)
+	$(CC) $(CFLAGS) -nostdlib -o $@ -Wl,-T,flat.lds \
+		$(filter %.o, $^) $(FLATLIBS)
 
 %.flat: %.elf
-	objcopy -O elf32-i386 $^ $@
+	$(OBJCOPY) -O elf32-i386 $^ $@
 
 tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \
                $(TEST_DIR)/smptest.flat  $(TEST_DIR)/port80.flat \
@@ -105,7 +103,7 @@ $(TEST_DIR)/vmx.elf: $(cstart.o) $(TEST_DIR)/vmx.o $(TEST_DIR)/vmx_tests.o
 
 arch_clean:
 	$(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat $(TEST_DIR)/*.elf \
-	$(TEST_DIR)/.*.d $(TEST_DIR)/lib/.*.d $(TEST_DIR)/lib/*.o
+	$(TEST_DIR)/.*.d lib/x86/.*.d
 
 api/%.o: CFLAGS += -m32
 
diff --git a/run_tests.sh b/run_tests.sh
index 55ecac5bed3a4..e5f960958866e 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -27,7 +27,7 @@ function run()
         return
     fi
 
-	cmdline="./x86-run $kernel -smp $smp -display none $opts"
+	cmdline="./x86-run $kernel -smp $smp $opts"
     if [ $verbose != 0 ]; then
         echo $cmdline
     fi
@@ -92,8 +92,8 @@ Usage: $0 [-g group] [-h] [-v]
     -h: Output this help text
     -v: Enables verbose mode
 
-Set the environment variable QEMU=/path/to/qemu-system-x86_64 to allow the
-internally used x86-run to pick up the right qemu binary.
+Set the environment variable QEMU=/path/to/qemu-system-ARCH to specify
+the appropriate qemu binary for ARCH-run.
 
 EOF
 }
diff --git a/x86/README b/x86/README
index d644abdf31708..c7ec8d593ede5 100644
--- a/x86/README
+++ b/x86/README
@@ -1,3 +1,24 @@
+
+Tests for x86 architecture are run as kernel images for qemu that supports
+multiboot format. Tests use an infrastructure called from the bios code.
+The infrastructure initialize the system/cpu's, switch to long-mode and calls
+the 'main' function of the individual test. Tests uses a qemu's virtual test
+device, named testdev, for services like printing, exiting, query memory
+size etc. See file docs/testdev.txt for more details.
+
+An example of a test invocation:
+Using qemu-kvm:
+
+qemu-kvm -device testdev,chardev=testlog \
+         -chardev file,id=testlog,path=msr.out \
+         -serial stdio -kernel ./x86/msr.flat
+This invocation runs the msr test case. The test outputs to stdio.
+
+Using qemu (supported since qemu 1.3):
+qemu-system-x86_64 -enable-kvm -device pc-testdev -serial stdio \
+                   -device isa-debug-exit,iobase=0xf4,iosize=0x4 \
+                   -kernel ./x86/msr.flat
+
 Tests in this directory and what they do:
 
 access: lots of page table related access (pte/pde) (read/write)
@@ -6,11 +27,14 @@ emulator: move to/from regs, cmps, push, pop, to/from cr8, smsw and lmsw
 hypercall: intel and amd hypercall insn
 msr: write to msr (only KERNEL_GS_BASE for now)
 port80: lots of out to port 80
-realmode: goes back to realmode, shld, push/pop, mov immediate, cmp immediate, add immediate,
-         io, eflags instructions (clc, cli, etc.), jcc short, jcc near, call, long jmp, xchg
-sieve: heavy memory access with no paging and with paging static and with paging vmalloc'ed
-smptest: run smp_id() on every cpu and compares return value to number
-tsc: write to tsc(0) and write to tsc(100000000000) and read it back
-vmexit: long loops for each: cpuid, vmcall, mov_from_cr8, mov_to_cr8, inl_pmtimer, ipi, ipi+halt
+realmode: goes back to realmode, shld, push/pop, mov immediate, cmp immediate,
+          add immediate, io, eflags instructions (clc, cli, etc.), jcc short,
+          jcc near, call, long jmp, xchg
+sieve:    heavy memory access with no paging and with paging static and with
+          paging vmalloc'ed
+smptest:  run smp_id() on every cpu and compares return value to number
+tsc:      write to tsc(0) and write to tsc(100000000000) and read it back
+vmexit:   long loops for each: cpuid, vmcall, mov_from_cr8, mov_to_cr8,
+          inl_pmtimer, ipi, ipi+halt
 kvmclock_test: test of wallclock, monotonic cycle and performance of kvmclock
-pcid: basic functionality test of PCID/INVPCID feature
\ No newline at end of file
+pcid:          basic functionality test of PCID/INVPCID feature
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 03/17] clean root dir of all x86-ness
  2014-01-21 16:21 [PATCH 00/17] kvm-unit-tests/arm: initial drop Andrew Jones
  2014-01-21 16:21 ` [PATCH 01/17] remove unused files Andrew Jones
  2014-01-21 16:21 ` [PATCH 02/17] makefile and run_tests tweaks Andrew Jones
@ 2014-01-21 16:21 ` Andrew Jones
  2014-01-21 16:21 ` [PATCH 04/17] gitignore: Ignore more Andrew Jones
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 47+ messages in thread
From: Andrew Jones @ 2014-01-21 16:21 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: christoffer.dall

Remove all references to x86 from the root dir (except from in
configure).  Also remove references from the root dir README
by moving that documentation to the x86/README, and touch up
the READMEs at the same time.

Signed-off-by: Andrew Jones <drjones@redhat.com>

---
v2:
 - tests' images => test images [Christoffer Dall]

TODO:
 - more documentation is still needed, we should add
   * an overview of the framework
   * improve the quickstart guide for running the tests
   * add a quickstart guide for developing tests
---
 Makefile                     |   7 ++-
 README                       |  55 +++++++++-----------
 config-i386.mak              |  13 -----
 config-x86-common.mak        | 120 -------------------------------------------
 config-x86_64.mak            |  14 -----
 config/config-i386.mak       |  12 +++++
 config/config-x86-common.mak | 120 +++++++++++++++++++++++++++++++++++++++++++
 config/config-x86_64.mak     |  13 +++++
 configure                    |  17 ++++++
 docs/testdev.txt             |  11 ++++
 flat.lds                     |  21 --------
 run_tests.sh                 |  15 +++---
 testdev.txt                  |  14 -----
 x86-run                      |  41 ---------------
 x86/README                   |  42 +++++++++------
 x86/flat.lds                 |  21 ++++++++
 x86/run                      |  41 +++++++++++++++
 17 files changed, 293 insertions(+), 284 deletions(-)
 delete mode 100644 config-i386.mak
 delete mode 100644 config-x86-common.mak
 delete mode 100644 config-x86_64.mak
 create mode 100644 config/config-i386.mak
 create mode 100644 config/config-x86-common.mak
 create mode 100644 config/config-x86_64.mak
 create mode 100644 docs/testdev.txt
 delete mode 100644 flat.lds
 delete mode 100644 testdev.txt
 delete mode 100755 x86-run
 create mode 100644 x86/flat.lds
 create mode 100755 x86/run

diff --git a/Makefile b/Makefile
index 4bb69427caeba..fa95d66386d49 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@ cflatobjs := \
 	lib/string.o
 
 #include architecure specific make rules
-include config-$(ARCH).mak
+include config/config-$(ARCH).mak
 
 # cc-option
 # Usage: OP_CFLAGS+=$(call cc-option, -falign-functions=0, -malign-functions=0)
@@ -30,7 +30,6 @@ CFLAGS += $(autodepend-flags) -Wall
 CFLAGS += $(call cc-option, -fomit-frame-pointer, "")
 CFLAGS += $(call cc-option, -fno-stack-protector, "")
 CFLAGS += $(call cc-option, -fno-stack-protector-all, "")
-CFLAGS += -I.
 
 CXXFLAGS += $(CFLAGS)
 
@@ -45,11 +44,11 @@ $(libcflat): $(cflatobjs)
 %.o: %.S
 	$(CC) $(CFLAGS) -c -nostdlib -o $@ $<
 
--include .*.d */.*.d */*/.*.d
+-include */.*.d */*/.*.d
 
 install:
 	mkdir -p $(DESTDIR)
 	install $(tests_and_config) $(DESTDIR)
 
 clean: arch_clean
-	$(RM) *.o *.a .*.d lib/.*.d $(libcflat) $(cflatobjs)
+	$(RM) lib/.*.d $(libcflat) $(cflatobjs)
diff --git a/README b/README
index db525e3bbb79d..0174679c05021 100644
--- a/README
+++ b/README
@@ -1,36 +1,27 @@
 This directory contains sources for a kvm test suite.
 
-Tests for x86 architecture are run as kernel images for qemu that supports multiboot format.
-Tests uses an infrastructure called from the bios code. The infrastructure initialize the system/cpu's,
-switch to long-mode and calls the 'main' function of the individual test.
-Tests uses a qemu's virtual test device, named testdev, for services like printing, exiting, query memory size etc.
-See file testdev.txt for more details.
-
-To create the tests' images just type 'make' in this directory.
-Tests' images created in ./<ARCH>/*.flat
-
-An example of a test invocation:
-Using qemu-kvm:
-
-qemu-kvm -device testdev,chardev=testlog -chardev file,id=testlog,path=msr.out -serial stdio -kernel ./x86/msr.flat
-This invocation runs the msr test case. The test outputs to stdio.
-
-Using qemu (supported since qemu 1.3):
-qemu-system-x86_64 -enable-kvm -device pc-testdev -serial stdio -device isa-debug-exit,iobase=0xf4,iosize=0x4 -kernel ./x86/msr.flat
-
-Or use a runner script to detect the correct invocation:
-./x86-run ./x86/msr.flat
-To select a specific qemu binary, specify the QEMU=<path> environment:
-QEMU=/tmp/qemu/x86_64-softmmu/qemu-system-x86_64 ./x86-run ./x86/msr.flat
-
-The exit status of the binary (and the script) is inconsistent: with
-qemu-system, after the unittest is done, the exit status of qemu is 1,
-different from the 'old style' qemu-kvm, whose exit status in successful
-completion is 0.
+To create the test images do
+  ./configure
+  make
+in this directory. Test images are created in ./<ARCH>/*.flat
+
+Then use the runner script to detect the correct invocation and
+invoke the test, e.g.
+  ./x86-run ./x86/msr.flat
+or
+  ./run_tests.sh
+to run them all.
+
+To select a specific qemu binary, specify the QEMU=<path>
+environment, e.g.
+  QEMU=/tmp/qemu/x86_64-softmmu/qemu-system-x86_64 ./x86-run ./x86/msr.flat
 
 Directory structure:
-.:  Makefile and config files for the tests
-./lib: general services for the tests
-./lib/<ARCH>: architecture dependent services for the tests
-./<ARCH>: the sources of the tests and the created objects/images
-
+.:		Makefile and config files for the tests
+./config:	config files for the tests
+./docs:		documentation files
+./lib:		general services for the tests
+./lib/<ARCH>:	architecture dependent services for the tests
+./<ARCH>:	the sources of the tests and the created objects/images
+
+See <ARCH>/README for arch specific documentation.
diff --git a/config-i386.mak b/config-i386.mak
deleted file mode 100644
index de52f3d53cff8..0000000000000
--- a/config-i386.mak
+++ /dev/null
@@ -1,13 +0,0 @@
-TEST_DIR=x86
-cstart.o = $(TEST_DIR)/cstart.o
-bits = 32
-ldarch = elf32-i386
-CFLAGS += -D__i386__
-CFLAGS += -I $(KERNELDIR)/include
-
-tests = $(TEST_DIR)/taskswitch.flat $(TEST_DIR)/taskswitch2.flat
-
-include config-x86-common.mak
-
-$(TEST_DIR)/taskswitch.elf: $(cstart.o) $(TEST_DIR)/taskswitch.o
-$(TEST_DIR)/taskswitch2.elf: $(cstart.o) $(TEST_DIR)/taskswitch2.o
diff --git a/config-x86-common.mak b/config-x86-common.mak
deleted file mode 100644
index 7e481192a0737..0000000000000
--- a/config-x86-common.mak
+++ /dev/null
@@ -1,120 +0,0 @@
-#This is a make file with common rules for both x86 & x86-64
-
-all: test_cases
-
-cflatobjs += lib/x86/io.o
-cflatobjs += lib/x86/smp.o
-cflatobjs += lib/x86/vm.o
-cflatobjs += lib/x86/fwcfg.o
-cflatobjs += lib/x86/apic.o
-cflatobjs += lib/x86/atomic.o
-cflatobjs += lib/x86/desc.o
-cflatobjs += lib/x86/isr.o
-cflatobjs += lib/x86/pci.o
-
-$(libcflat): LDFLAGS += -nostdlib
-$(libcflat): CFLAGS += -ffreestanding -I lib
-
-CFLAGS += -m$(bits)
-CFLAGS += -O1
-
-libgcc := $(shell $(CC) -m$(bits) --print-libgcc-file-name)
-
-FLATLIBS = lib/libcflat.a $(libgcc)
-%.elf: %.o $(FLATLIBS) flat.lds
-	$(CC) $(CFLAGS) -nostdlib -o $@ -Wl,-T,flat.lds \
-		$(filter %.o, $^) $(FLATLIBS)
-
-%.flat: %.elf
-	$(OBJCOPY) -O elf32-i386 $^ $@
-
-tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \
-               $(TEST_DIR)/smptest.flat  $(TEST_DIR)/port80.flat \
-               $(TEST_DIR)/realmode.flat $(TEST_DIR)/msr.flat \
-               $(TEST_DIR)/hypercall.flat $(TEST_DIR)/sieve.flat \
-               $(TEST_DIR)/kvmclock_test.flat  $(TEST_DIR)/eventinj.flat \
-               $(TEST_DIR)/s3.flat $(TEST_DIR)/pmu.flat \
-               $(TEST_DIR)/tsc_adjust.flat $(TEST_DIR)/asyncpf.flat \
-               $(TEST_DIR)/init.flat
-
-ifdef API
-tests-common += api/api-sample
-tests-common += api/dirty-log
-tests-common += api/dirty-log-perf
-endif
-
-tests_and_config = $(TEST_DIR)/*.flat $(TEST_DIR)/unittests.cfg
-
-test_cases: $(tests-common) $(tests)
-
-$(TEST_DIR)/%.o: CFLAGS += -std=gnu99 -ffreestanding -I lib -I lib/x86
-
-$(TEST_DIR)/access.elf: $(cstart.o) $(TEST_DIR)/access.o
-
-$(TEST_DIR)/hypercall.elf: $(cstart.o) $(TEST_DIR)/hypercall.o
-
-$(TEST_DIR)/sieve.elf: $(cstart.o) $(TEST_DIR)/sieve.o
-
-$(TEST_DIR)/vmexit.elf: $(cstart.o) $(TEST_DIR)/vmexit.o
-
-$(TEST_DIR)/smptest.elf: $(cstart.o) $(TEST_DIR)/smptest.o
-
-$(TEST_DIR)/emulator.elf: $(cstart.o) $(TEST_DIR)/emulator.o
-
-$(TEST_DIR)/port80.elf: $(cstart.o) $(TEST_DIR)/port80.o
-
-$(TEST_DIR)/tsc.elf: $(cstart.o) $(TEST_DIR)/tsc.o
-
-$(TEST_DIR)/tsc_adjust.elf: $(cstart.o) $(TEST_DIR)/tsc_adjust.o
-
-$(TEST_DIR)/apic.elf: $(cstart.o) $(TEST_DIR)/apic.o
-
-$(TEST_DIR)/init.elf: $(cstart.o) $(TEST_DIR)/init.o
-
-$(TEST_DIR)/realmode.elf: $(TEST_DIR)/realmode.o
-	$(CC) -m32 -nostdlib -o $@ -Wl,-T,$(TEST_DIR)/realmode.lds $^
-
-$(TEST_DIR)/realmode.o: bits = 32
-
-$(TEST_DIR)/msr.elf: $(cstart.o) $(TEST_DIR)/msr.o
-
-$(TEST_DIR)/idt_test.elf: $(cstart.o) $(TEST_DIR)/idt_test.o
-
-$(TEST_DIR)/xsave.elf: $(cstart.o) $(TEST_DIR)/xsave.o
-
-$(TEST_DIR)/rmap_chain.elf: $(cstart.o) $(TEST_DIR)/rmap_chain.o
-
-$(TEST_DIR)/svm.elf: $(cstart.o)
-
-$(TEST_DIR)/kvmclock_test.elf: $(cstart.o) $(TEST_DIR)/kvmclock.o \
-                                $(TEST_DIR)/kvmclock_test.o
-
-$(TEST_DIR)/eventinj.elf: $(cstart.o) $(TEST_DIR)/eventinj.o
-
-$(TEST_DIR)/s3.elf: $(cstart.o) $(TEST_DIR)/s3.o
-
-$(TEST_DIR)/pmu.elf: $(cstart.o) $(TEST_DIR)/pmu.o
-
-$(TEST_DIR)/asyncpf.elf: $(cstart.o) $(TEST_DIR)/asyncpf.o
-
-$(TEST_DIR)/pcid.elf: $(cstart.o) $(TEST_DIR)/pcid.o
-
-$(TEST_DIR)/vmx.elf: $(cstart.o) $(TEST_DIR)/vmx.o $(TEST_DIR)/vmx_tests.o
-
-arch_clean:
-	$(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat $(TEST_DIR)/*.elf \
-	$(TEST_DIR)/.*.d lib/x86/.*.d
-
-api/%.o: CFLAGS += -m32
-
-api/%: LDLIBS += -lstdc++ -lboost_thread-mt -lpthread -lrt
-api/%: LDFLAGS += -m32
-
-api/libapi.a: api/kvmxx.o api/identity.o api/exception.o api/memmap.o
-	$(AR) rcs $@ $^
-
-api/api-sample: api/api-sample.o api/libapi.a
-
-api/dirty-log: api/dirty-log.o api/libapi.a
-
-api/dirty-log-perf: api/dirty-log-perf.o api/libapi.a
diff --git a/config-x86_64.mak b/config-x86_64.mak
deleted file mode 100644
index bb8ee89713abd..0000000000000
--- a/config-x86_64.mak
+++ /dev/null
@@ -1,14 +0,0 @@
-TEST_DIR=x86
-cstart.o = $(TEST_DIR)/cstart64.o
-bits = 64
-ldarch = elf64-x86-64
-CFLAGS += -D__x86_64__
-
-tests = $(TEST_DIR)/access.flat $(TEST_DIR)/apic.flat \
-	  $(TEST_DIR)/emulator.flat $(TEST_DIR)/idt_test.flat \
-	  $(TEST_DIR)/xsave.flat $(TEST_DIR)/rmap_chain.flat \
-	  $(TEST_DIR)/pcid.flat
-tests += $(TEST_DIR)/svm.flat
-tests += $(TEST_DIR)/vmx.flat
-
-include config-x86-common.mak
diff --git a/config/config-i386.mak b/config/config-i386.mak
new file mode 100644
index 0000000000000..82fed0f5a48b0
--- /dev/null
+++ b/config/config-i386.mak
@@ -0,0 +1,12 @@
+cstart.o = $(TEST_DIR)/cstart.o
+bits = 32
+ldarch = elf32-i386
+CFLAGS += -D__i386__
+CFLAGS += -I $(KERNELDIR)/include
+
+tests = $(TEST_DIR)/taskswitch.flat $(TEST_DIR)/taskswitch2.flat
+
+include config/config-x86-common.mak
+
+$(TEST_DIR)/taskswitch.elf: $(cstart.o) $(TEST_DIR)/taskswitch.o
+$(TEST_DIR)/taskswitch2.elf: $(cstart.o) $(TEST_DIR)/taskswitch2.o
diff --git a/config/config-x86-common.mak b/config/config-x86-common.mak
new file mode 100644
index 0000000000000..917cbbf801a65
--- /dev/null
+++ b/config/config-x86-common.mak
@@ -0,0 +1,120 @@
+#This is a make file with common rules for both x86 & x86-64
+
+all: test_cases
+
+cflatobjs += lib/x86/io.o
+cflatobjs += lib/x86/smp.o
+cflatobjs += lib/x86/vm.o
+cflatobjs += lib/x86/fwcfg.o
+cflatobjs += lib/x86/apic.o
+cflatobjs += lib/x86/atomic.o
+cflatobjs += lib/x86/desc.o
+cflatobjs += lib/x86/isr.o
+cflatobjs += lib/x86/pci.o
+
+$(libcflat): LDFLAGS += -nostdlib
+$(libcflat): CFLAGS += -ffreestanding -I lib
+
+CFLAGS += -m$(bits)
+CFLAGS += -O1
+
+libgcc := $(shell $(CC) -m$(bits) --print-libgcc-file-name)
+
+FLATLIBS = lib/libcflat.a $(libgcc)
+%.elf: %.o $(FLATLIBS) x86/flat.lds
+	$(CC) $(CFLAGS) -nostdlib -o $@ -Wl,-T,x86/flat.lds \
+		$(filter %.o, $^) $(FLATLIBS)
+
+%.flat: %.elf
+	$(OBJCOPY) -O elf32-i386 $^ $@
+
+tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \
+               $(TEST_DIR)/smptest.flat  $(TEST_DIR)/port80.flat \
+               $(TEST_DIR)/realmode.flat $(TEST_DIR)/msr.flat \
+               $(TEST_DIR)/hypercall.flat $(TEST_DIR)/sieve.flat \
+               $(TEST_DIR)/kvmclock_test.flat  $(TEST_DIR)/eventinj.flat \
+               $(TEST_DIR)/s3.flat $(TEST_DIR)/pmu.flat \
+               $(TEST_DIR)/tsc_adjust.flat $(TEST_DIR)/asyncpf.flat \
+               $(TEST_DIR)/init.flat
+
+ifdef API
+tests-common += api/api-sample
+tests-common += api/dirty-log
+tests-common += api/dirty-log-perf
+endif
+
+tests_and_config = $(TEST_DIR)/*.flat $(TEST_DIR)/unittests.cfg
+
+test_cases: $(tests-common) $(tests)
+
+$(TEST_DIR)/%.o: CFLAGS += -std=gnu99 -ffreestanding -I lib -I lib/x86
+
+$(TEST_DIR)/access.elf: $(cstart.o) $(TEST_DIR)/access.o
+
+$(TEST_DIR)/hypercall.elf: $(cstart.o) $(TEST_DIR)/hypercall.o
+
+$(TEST_DIR)/sieve.elf: $(cstart.o) $(TEST_DIR)/sieve.o
+
+$(TEST_DIR)/vmexit.elf: $(cstart.o) $(TEST_DIR)/vmexit.o
+
+$(TEST_DIR)/smptest.elf: $(cstart.o) $(TEST_DIR)/smptest.o
+
+$(TEST_DIR)/emulator.elf: $(cstart.o) $(TEST_DIR)/emulator.o
+
+$(TEST_DIR)/port80.elf: $(cstart.o) $(TEST_DIR)/port80.o
+
+$(TEST_DIR)/tsc.elf: $(cstart.o) $(TEST_DIR)/tsc.o
+
+$(TEST_DIR)/tsc_adjust.elf: $(cstart.o) $(TEST_DIR)/tsc_adjust.o
+
+$(TEST_DIR)/apic.elf: $(cstart.o) $(TEST_DIR)/apic.o
+
+$(TEST_DIR)/init.elf: $(cstart.o) $(TEST_DIR)/init.o
+
+$(TEST_DIR)/realmode.elf: $(TEST_DIR)/realmode.o
+	$(CC) -m32 -nostdlib -o $@ -Wl,-T,$(TEST_DIR)/realmode.lds $^
+
+$(TEST_DIR)/realmode.o: bits = 32
+
+$(TEST_DIR)/msr.elf: $(cstart.o) $(TEST_DIR)/msr.o
+
+$(TEST_DIR)/idt_test.elf: $(cstart.o) $(TEST_DIR)/idt_test.o
+
+$(TEST_DIR)/xsave.elf: $(cstart.o) $(TEST_DIR)/xsave.o
+
+$(TEST_DIR)/rmap_chain.elf: $(cstart.o) $(TEST_DIR)/rmap_chain.o
+
+$(TEST_DIR)/svm.elf: $(cstart.o)
+
+$(TEST_DIR)/kvmclock_test.elf: $(cstart.o) $(TEST_DIR)/kvmclock.o \
+                                $(TEST_DIR)/kvmclock_test.o
+
+$(TEST_DIR)/eventinj.elf: $(cstart.o) $(TEST_DIR)/eventinj.o
+
+$(TEST_DIR)/s3.elf: $(cstart.o) $(TEST_DIR)/s3.o
+
+$(TEST_DIR)/pmu.elf: $(cstart.o) $(TEST_DIR)/pmu.o
+
+$(TEST_DIR)/asyncpf.elf: $(cstart.o) $(TEST_DIR)/asyncpf.o
+
+$(TEST_DIR)/pcid.elf: $(cstart.o) $(TEST_DIR)/pcid.o
+
+$(TEST_DIR)/vmx.elf: $(cstart.o) $(TEST_DIR)/vmx.o $(TEST_DIR)/vmx_tests.o
+
+arch_clean:
+	$(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat $(TEST_DIR)/*.elf \
+	$(TEST_DIR)/.*.d lib/x86/.*.d
+
+api/%.o: CFLAGS += -m32
+
+api/%: LDLIBS += -lstdc++ -lboost_thread-mt -lpthread -lrt
+api/%: LDFLAGS += -m32
+
+api/libapi.a: api/kvmxx.o api/identity.o api/exception.o api/memmap.o
+	$(AR) rcs $@ $^
+
+api/api-sample: api/api-sample.o api/libapi.a
+
+api/dirty-log: api/dirty-log.o api/libapi.a
+
+api/dirty-log-perf: api/dirty-log-perf.o api/libapi.a
diff --git a/config/config-x86_64.mak b/config/config-x86_64.mak
new file mode 100644
index 0000000000000..f089b05a178c3
--- /dev/null
+++ b/config/config-x86_64.mak
@@ -0,0 +1,13 @@
+cstart.o = $(TEST_DIR)/cstart64.o
+bits = 64
+ldarch = elf64-x86-64
+CFLAGS += -D__x86_64__
+
+tests = $(TEST_DIR)/access.flat $(TEST_DIR)/apic.flat \
+	  $(TEST_DIR)/emulator.flat $(TEST_DIR)/idt_test.flat \
+	  $(TEST_DIR)/xsave.flat $(TEST_DIR)/rmap_chain.flat \
+	  $(TEST_DIR)/pcid.flat
+tests += $(TEST_DIR)/svm.flat
+tests += $(TEST_DIR)/vmx.flat
+
+include config/config-x86-common.mak
diff --git a/configure b/configure
index d0c62e24dd1d2..6cfc64943f6e6 100755
--- a/configure
+++ b/configure
@@ -15,6 +15,7 @@ usage() {
 	Usage: $0 [options]
 
 	Options include:
+	    --test-dir=DIR         the main directory for tests ($arch)
 	    --arch=ARCH            architecture to compile for ($arch)
 	    --cross-prefix=PREFIX  cross compiler prefix
 	    --cc=CC		   c compiler to use ($cc)
@@ -33,6 +34,9 @@ while [[ "$1" = -* ]]; do
 	opt="${opt%%=*}"
     fi
     case "$opt" in
+	--test-dir)
+	    testdir="$arg"
+	    ;;
 	--prefix)
 	    prefix="$arg"
 	    ;;
@@ -62,6 +66,18 @@ while [[ "$1" = -* ]]; do
 	    ;;
     esac
 done
+if [ -z "$testdir" -a \( "$arch" = "i386" -o "$arch" = "x86_64" \) ]; then
+    testdir=x86
+elif [ -z "$testdir" ]; then
+    testdir=$arch
+fi
+if [ ! -d $testdir ]; then
+    echo "$testdir does not exist!"
+    exit 1
+fi
+if [ -f $testdir/run ]; then
+    ln -fs $testdir/run $testdir-run
+fi
 
 # check for dependent 32 bit libraries
 cat << EOF > lib_test.c
@@ -89,4 +105,5 @@ LD=$cross_prefix$ld
 OBJCOPY=$cross_prefix$objcopy
 AR=$cross_prefix$ar
 API=$api
+TEST_DIR=$testdir
 EOF
diff --git a/docs/testdev.txt b/docs/testdev.txt
new file mode 100644
index 0000000000000..854b5c774b60c
--- /dev/null
+++ b/docs/testdev.txt
@@ -0,0 +1,11 @@
+This file describes the virtual device of qemu for supporting this test suite.
+
+Services supplied by the testdev device:
+
+serial output: write only, on io port 0xf1
+exit process: write only, on io port 0xf4, value used as exit code
+ram size: read-only, on io port 0xd1, 4 bytes' size
+irq line setting: write only, on io ports 0x2000 - 0x2018, value to set/clear
+simple io: read/write, on io port 0xe0, 1/2/4 bytes
+
+Test device used a char device for actual output
diff --git a/flat.lds b/flat.lds
deleted file mode 100644
index a278b56c9a4e3..0000000000000
--- a/flat.lds
+++ /dev/null
@@ -1,21 +0,0 @@
-SECTIONS
-{
-    . = 4M + SIZEOF_HEADERS;
-    stext = .;
-    .text : { *(.init) *(.text) *(.text.*) }
-    . = ALIGN(4K);
-    .data : {
-          *(.data)
-          exception_table_start = .;
-          *(.data.ex)
-	  exception_table_end = .;
-	  }
-    . = ALIGN(16);
-    .rodata : { *(.rodata) }
-    . = ALIGN(16);
-    .bss : { *(.bss) }
-    . = ALIGN(4K);
-    edata = .;
-}
-
-ENTRY(start)
diff --git a/run_tests.sh b/run_tests.sh
index e5f960958866e..63fd469c611ac 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -1,8 +1,10 @@
 #!/bin/bash
 
-testroot=x86
-config=$testroot/unittests.cfg
-qemu=${qemu:-qemu-system-x86_64}
+# As it happens, config.mak is valid shell script code, too :-)
+source config.mak
+
+config=$TEST_DIR/unittests.cfg
+qemu=${QEMU:-qemu-system-$ARCH}
 verbose=0
 
 function run()
@@ -27,7 +29,7 @@ function run()
         return
     fi
 
-	cmdline="./x86-run $kernel -smp $smp $opts"
+	cmdline="./$TEST_DIR-run $kernel -smp $smp $opts"
     if [ $verbose != 0 ]; then
         echo $cmdline
     fi
@@ -65,7 +67,7 @@ function run_all()
             groups=""
             arch=""
         elif [[ $line =~ ^file\ *=\ *(.*)$ ]]; then
-            kernel=$testroot/${BASH_REMATCH[1]}
+            kernel=$TEST_DIR/${BASH_REMATCH[1]}
         elif [[ $line =~ ^smp\ *=\ *(.*)$ ]]; then
             smp=${BASH_REMATCH[1]}
         elif [[ $line =~ ^extra_params\ *=\ *(.*)$ ]]; then
@@ -98,9 +100,6 @@ the appropriate qemu binary for ARCH-run.
 EOF
 }
 
-# As it happens, config.mak is valid shell script code, too :-)
-source config.mak
-
 echo > test.log
 while getopts "g:hv" opt; do
     case $opt in
diff --git a/testdev.txt b/testdev.txt
deleted file mode 100644
index ac436efadb633..0000000000000
--- a/testdev.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-This file describes the virtual device of qemu for supporting this test suite.
-
-Services supplied by the testdev device:
-
-serial output: write only, on io port 0xf1
-exit process: write only, on io port 0xf4, value used as exit code
-ram size: read-only, on io port 0xd1, 4 bytes' size
-irq line setting: write only, on io ports 0x2000 - 0x2018, value to set/clear
-simple io: read/write, on io port 0xe0, 1/2/4 bytes
-
-Test device used a char device for actual output
-
-
-
diff --git a/x86-run b/x86-run
deleted file mode 100755
index 646c5770ed03f..0000000000000
--- a/x86-run
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/bin/bash
-
-qemukvm="${QEMU:-qemu-kvm}"
-qemusystem="${QEMU:-qemu-system-x86_64}"
-if
-	${qemukvm} -device '?' 2>&1 | grep -F -e \"testdev\" -e \"pc-testdev\" > /dev/null;
-then
-	qemu="${qemukvm}"
-else
-	if
-		${qemusystem} -device '?' 2>&1 | grep -F -e \"testdev\" -e \"pc-testdev\" > /dev/null;
-	then
-		qemu="${qemusystem}"
-	else
-		echo QEMU binary ${QEMU} has no support for test device. Exiting.
-		exit 2
-	fi
-fi
-
-if
-	${qemu} -device '?' 2>&1 | grep -F "pci-testdev" > /dev/null;
-then
-	pci_testdev="-device pci-testdev"
-else
-	pci_testdev=""
-fi
-
-if
-	${qemu} -device '?' 2>&1 | grep -F "pc-testdev" > /dev/null;
-then
-	pc_testdev="-device pc-testdev -device isa-debug-exit,iobase=0xf4,iosize=0x4"
-else
-	pc_testdev="-device testdev,chardev=testlog -chardev file,id=testlog,path=msr.out"
-fi
-
-command="${qemu} -enable-kvm $pc_testdev -display none -serial stdio $pci_testdev -kernel"
-echo ${command} "$@"
-${command} "$@"
-ret=$?
-echo Return value from qemu: $ret
-exit $ret
diff --git a/x86/README b/x86/README
index c7ec8d593ede5..c1507378cce53 100644
--- a/x86/README
+++ b/x86/README
@@ -21,20 +21,28 @@ qemu-system-x86_64 -enable-kvm -device pc-testdev -serial stdio \
 
 Tests in this directory and what they do:
 
-access: lots of page table related access (pte/pde) (read/write)
-apic: enable x2apic, self ipi, ioapic intr, ioapic simultaneous
-emulator: move to/from regs, cmps, push, pop, to/from cr8, smsw and lmsw
-hypercall: intel and amd hypercall insn
-msr: write to msr (only KERNEL_GS_BASE for now)
-port80: lots of out to port 80
-realmode: goes back to realmode, shld, push/pop, mov immediate, cmp immediate,
-          add immediate, io, eflags instructions (clc, cli, etc.), jcc short,
-          jcc near, call, long jmp, xchg
-sieve:    heavy memory access with no paging and with paging static and with
-          paging vmalloc'ed
-smptest:  run smp_id() on every cpu and compares return value to number
-tsc:      write to tsc(0) and write to tsc(100000000000) and read it back
-vmexit:   long loops for each: cpuid, vmcall, mov_from_cr8, mov_to_cr8,
-          inl_pmtimer, ipi, ipi+halt
-kvmclock_test: test of wallclock, monotonic cycle and performance of kvmclock
-pcid:          basic functionality test of PCID/INVPCID feature
+  access:	lots of page table related access (pte/pde) (read/write)
+  apic:		enable x2apic, self ipi, ioapic intr, ioapic simultaneous
+  emulator:	move to/from regs, cmps, push, pop, to/from cr8, smsw and lmsw
+  hypercall:	intel and amd hypercall insn
+  msr:		write to msr (only KERNEL_GS_BASE for now)
+  port80:	lots of out to port 80
+  realmode:	goes back to realmode, shld, push/pop, mov immediate,
+		cmp immediate, add immediate, io, eflags instructions
+		(clc, cli, etc.), jcc short, jcc near, call, long jmp, xchg
+  sieve:	heavy memory access with no paging and with paging static and
+		with paging vmalloc'ed
+  smptest:	run smp_id() on every cpu and compares return value to number
+  tsc:		write to tsc(0) and write to tsc(100000000000) and read it back
+  vmexit:	long loops for each: cpuid, vmcall, mov_from_cr8, mov_to_cr8,
+		inl_pmtimer, ipi, ipi+halt
+  kvmclock_test: test of wallclock, monotonic cycle and performance of kvmclock
+  pcid:		basic functionality test of PCID/INVPCID featureThis directory
+		contains sources for a kvm test suite.
+
+Legacy notes:
+
+  The exit status of the binary (and the script) is inconsistent: with
+  qemu-system, after the unittest is done, the exit status of qemu is 1,
+  different from the 'old style' qemu-kvm, whose exit status in successful
+  completion is 0.
diff --git a/x86/flat.lds b/x86/flat.lds
new file mode 100644
index 0000000000000..a278b56c9a4e3
--- /dev/null
+++ b/x86/flat.lds
@@ -0,0 +1,21 @@
+SECTIONS
+{
+    . = 4M + SIZEOF_HEADERS;
+    stext = .;
+    .text : { *(.init) *(.text) *(.text.*) }
+    . = ALIGN(4K);
+    .data : {
+          *(.data)
+          exception_table_start = .;
+          *(.data.ex)
+	  exception_table_end = .;
+	  }
+    . = ALIGN(16);
+    .rodata : { *(.rodata) }
+    . = ALIGN(16);
+    .bss : { *(.bss) }
+    . = ALIGN(4K);
+    edata = .;
+}
+
+ENTRY(start)
diff --git a/x86/run b/x86/run
new file mode 100755
index 0000000000000..646c5770ed03f
--- /dev/null
+++ b/x86/run
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+qemukvm="${QEMU:-qemu-kvm}"
+qemusystem="${QEMU:-qemu-system-x86_64}"
+if
+	${qemukvm} -device '?' 2>&1 | grep -F -e \"testdev\" -e \"pc-testdev\" > /dev/null;
+then
+	qemu="${qemukvm}"
+else
+	if
+		${qemusystem} -device '?' 2>&1 | grep -F -e \"testdev\" -e \"pc-testdev\" > /dev/null;
+	then
+		qemu="${qemusystem}"
+	else
+		echo QEMU binary ${QEMU} has no support for test device. Exiting.
+		exit 2
+	fi
+fi
+
+if
+	${qemu} -device '?' 2>&1 | grep -F "pci-testdev" > /dev/null;
+then
+	pci_testdev="-device pci-testdev"
+else
+	pci_testdev=""
+fi
+
+if
+	${qemu} -device '?' 2>&1 | grep -F "pc-testdev" > /dev/null;
+then
+	pc_testdev="-device pc-testdev -device isa-debug-exit,iobase=0xf4,iosize=0x4"
+else
+	pc_testdev="-device testdev,chardev=testlog -chardev file,id=testlog,path=msr.out"
+fi
+
+command="${qemu} -enable-kvm $pc_testdev -display none -serial stdio $pci_testdev -kernel"
+echo ${command} "$@"
+${command} "$@"
+ret=$?
+echo Return value from qemu: $ret
+exit $ret
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 04/17] gitignore: Ignore more
  2014-01-21 16:21 [PATCH 00/17] kvm-unit-tests/arm: initial drop Andrew Jones
                   ` (2 preceding siblings ...)
  2014-01-21 16:21 ` [PATCH 03/17] clean root dir of all x86-ness Andrew Jones
@ 2014-01-21 16:21 ` Andrew Jones
  2014-01-21 16:21 ` [PATCH 05/17] add 'make cscope' support Andrew Jones
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 47+ messages in thread
From: Andrew Jones @ 2014-01-21 16:21 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: christoffer.dall

Ignore files generated from building and running.

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 .gitignore | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/.gitignore b/.gitignore
index ed857b7811847..6ec6518047fba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,8 +2,14 @@
 *.a
 *.d
 *.o
+*.elf
 *.flat
 .pc
 patches
 .stgit-*
 cscope.*
+*.swp
+/config.mak
+/*-run
+/test.log
+/msr.out
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 05/17] add 'make cscope' support
  2014-01-21 16:21 [PATCH 00/17] kvm-unit-tests/arm: initial drop Andrew Jones
                   ` (3 preceding siblings ...)
  2014-01-21 16:21 ` [PATCH 04/17] gitignore: Ignore more Andrew Jones
@ 2014-01-21 16:21 ` Andrew Jones
  2014-02-02  2:22   ` Christoffer Dall
  2014-01-21 16:21 ` [PATCH 06/17] Add halt() and some error codes Andrew Jones
                   ` (13 subsequent siblings)
  18 siblings, 1 reply; 47+ messages in thread
From: Andrew Jones @ 2014-01-21 16:21 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: christoffer.dall

Add a Makefile target to quickly generate arch-specific cscope
for kvm-unit-tests. Assumes a mostly flat directory structure,
i.e. uses '-maxdepth 1' in the file search.

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 Makefile | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index fa95d66386d49..283655957f39f 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ include config.mak
 
 DESTDIR := $(PREFIX)/share/qemu/tests
 
-.PHONY: arch_clean clean
+.PHONY: arch_clean clean cscope
 
 #make sure env CFLAGS variable is not used
 CFLAGS =
@@ -52,3 +52,10 @@ install:
 
 clean: arch_clean
 	$(RM) lib/.*.d $(libcflat) $(cflatobjs)
+
+cscope: common_dirs = lib
+cscope:
+	rm -f ./cscope.*
+	find $(TEST_DIR) lib/$(TEST_DIR) $(common_dirs) -maxdepth 1 \
+		-name "*.[chsS]" -print | sed 's,^\./,,' > ./cscope.files
+	cscope -bk
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 06/17] Add halt() and some error codes
  2014-01-21 16:21 [PATCH 00/17] kvm-unit-tests/arm: initial drop Andrew Jones
                   ` (4 preceding siblings ...)
  2014-01-21 16:21 ` [PATCH 05/17] add 'make cscope' support Andrew Jones
@ 2014-01-21 16:21 ` Andrew Jones
  2014-02-02  2:23   ` Christoffer Dall
  2014-01-21 16:21 ` [PATCH 07/17] move x86's simple heap management to common code Andrew Jones
                   ` (12 subsequent siblings)
  18 siblings, 1 reply; 47+ messages in thread
From: Andrew Jones @ 2014-01-21 16:21 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: christoffer.dall

Define a halt function that can be implemented by the test framework
for use on error paths before exit() works. Also add some error codes
that can be passed to halt() in case the serial isn't working either.
Then, on register inspection of the halted guest we may be able to
quickly determine the problem without having to find the halt()
call-site. The error codes may of course also be used with exit().

Signed-off-by: Andrew Jones <drjones@redhat.com>

---
v2:
 - keep the error numbers more consistent with the standard numbers
---
 lib/errno.h    | 22 ++++++++++++++++++++++
 lib/libcflat.h |  2 ++
 2 files changed, 24 insertions(+)
 create mode 100644 lib/errno.h

diff --git a/lib/errno.h b/lib/errno.h
new file mode 100644
index 0000000000000..f60845cdc61f6
--- /dev/null
+++ b/lib/errno.h
@@ -0,0 +1,22 @@
+#ifndef _ERRNO_H_
+#define _ERRNO_H_
+/*
+ * Define some error codes for the test framework's use. qemu
+ * exits with ((code << 1) | 1) when this framework calls
+ * exit(code), so we reserve codes 64 to 126. 127 is left
+ * for exit(-1).
+ *
+ * (Ab)use the standard E* names for syntax highlighting...
+ * The errno descriptions in [] are for non-standard semantics.
+ */
+#define EINTR	(64 + 4)	/* [unhandled exception] */
+#define EIO	(64 + 5)	/* I/O error */
+#define ENXIO	(64 + 6)	/* No such device or address [no serial] */
+#define ENOEXEC	(64 + 8)	/* Exec format error [bad flat file] */
+#define ENOMEM	(64 + 12)	/* Out of memory */
+#define ENODEV	(64 + 19)	/* No such device */
+#define EINVAL	(64 + 22)	/* Invalid argument */
+#define ENOSPC	(64 + 28)	/* No space left on device */
+#define ERANGE	(64 + 34)	/* Math result not representable
+				   [divide by zero] */
+#endif
diff --git a/lib/libcflat.h b/lib/libcflat.h
index 140c172e77d54..a1be635ab4ee9 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -37,6 +37,7 @@ typedef _Bool bool;
 #define true 1
 #define false 0
 
+extern void halt(int code);
 extern void exit(int code);
 
 extern unsigned long strlen(const char *buf);
@@ -57,4 +58,5 @@ extern long atol(const char *ptr);
 #define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
 
 #define NULL ((void *)0UL)
+#include "errno.h"
 #endif
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 07/17] move x86's simple heap management to common code
  2014-01-21 16:21 [PATCH 00/17] kvm-unit-tests/arm: initial drop Andrew Jones
                   ` (5 preceding siblings ...)
  2014-01-21 16:21 ` [PATCH 06/17] Add halt() and some error codes Andrew Jones
@ 2014-01-21 16:21 ` Andrew Jones
  2014-02-02  2:23   ` Christoffer Dall
  2014-01-21 16:21 ` [PATCH 08/17] Introduce libio to common code for io read/write Andrew Jones
                   ` (11 subsequent siblings)
  18 siblings, 1 reply; 47+ messages in thread
From: Andrew Jones @ 2014-01-21 16:21 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: christoffer.dall

v3: fixed Christoffer's nits

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 config/config-x86-common.mak |  1 +
 lib/heap.c                   | 45 ++++++++++++++++++++++++++++++++++++++++++++
 lib/heap.h                   |  8 ++++++++
 lib/x86/vm.c                 | 33 ++------------------------------
 4 files changed, 56 insertions(+), 31 deletions(-)
 create mode 100644 lib/heap.c
 create mode 100644 lib/heap.h

diff --git a/config/config-x86-common.mak b/config/config-x86-common.mak
index 917cbbf801a65..8a78f7a6c8849 100644
--- a/config/config-x86-common.mak
+++ b/config/config-x86-common.mak
@@ -2,6 +2,7 @@
 
 all: test_cases
 
+cflatobjs += lib/heap.o
 cflatobjs += lib/x86/io.o
 cflatobjs += lib/x86/smp.o
 cflatobjs += lib/x86/vm.o
diff --git a/lib/heap.c b/lib/heap.c
new file mode 100644
index 0000000000000..e2dcb8f26e8f8
--- /dev/null
+++ b/lib/heap.c
@@ -0,0 +1,45 @@
+#include "libcflat.h"
+
+static size_t pagesize;
+static void *free_head;
+
+void heap_init(void *start, size_t size, size_t page_size)
+{
+	unsigned long s = (unsigned long)start;
+	void *p = start;
+
+	pagesize = page_size;
+
+	/* page-align start of heap */
+	if (s & (pagesize - 1)) {
+		s += pagesize;
+		s &= ~(pagesize - 1);
+		p = (void *)s;
+	}
+
+	/* link free pages */
+	while (size >= pagesize) {
+		*(void **)p = free_head;
+		free_head = p;
+		p += pagesize;
+		size -= pagesize;
+	}
+}
+
+void *alloc_page(void)
+{
+	void *p;
+
+	if (!free_head)
+		return NULL;
+
+	p = free_head;
+	free_head = *(void **)free_head;
+	return p;
+}
+
+void free_page(void *page)
+{
+	*(void **)page = free_head;
+	free_head = page;
+}
diff --git a/lib/heap.h b/lib/heap.h
new file mode 100644
index 0000000000000..78b893021ae92
--- /dev/null
+++ b/lib/heap.h
@@ -0,0 +1,8 @@
+#ifndef _HEAP_H_
+#define _HEAP_H_
+#include "libcflat.h"
+
+extern void heap_init(void *start, size_t size, size_t page_size);
+extern void *alloc_page(void);
+extern void free_page(void *page);
+#endif
diff --git a/lib/x86/vm.c b/lib/x86/vm.c
index 188bf57587aa7..725cfe33259c2 100644
--- a/lib/x86/vm.c
+++ b/lib/x86/vm.c
@@ -1,6 +1,7 @@
 #include "fwcfg.h"
 #include "vm.h"
 #include "libcflat.h"
+#include "heap.h"
 
 #define PAGE_SIZE 4096ul
 #ifdef __x86_64__
@@ -9,38 +10,8 @@
 #define LARGE_PAGE_SIZE (1024 * PAGE_SIZE)
 #endif
 
-static void *free = 0;
 static void *vfree_top = 0;
 
-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;
 
@@ -185,7 +156,7 @@ static void setup_mmu(unsigned long len)
 void setup_vm()
 {
     end_of_memory = fwcfg_get_u64(FW_CFG_RAM_SIZE);
-    free_memory(&edata, end_of_memory - (unsigned long)&edata);
+    heap_init(&edata, end_of_memory - (unsigned long)&edata, PAGE_SIZE);
     setup_mmu(end_of_memory);
 }
 
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 08/17] Introduce libio to common code for io read/write
  2014-01-21 16:21 [PATCH 00/17] kvm-unit-tests/arm: initial drop Andrew Jones
                   ` (6 preceding siblings ...)
  2014-01-21 16:21 ` [PATCH 07/17] move x86's simple heap management to common code Andrew Jones
@ 2014-01-21 16:21 ` Andrew Jones
  2014-02-02  2:24   ` Christoffer Dall
  2014-01-21 16:21 ` [PATCH 10/17] libfdt: get libfdt to build Andrew Jones
                   ` (10 subsequent siblings)
  18 siblings, 1 reply; 47+ messages in thread
From: Andrew Jones @ 2014-01-21 16:21 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: christoffer.dall

v3:
 - get rid of CONFIG_64BIT, replace with asserts
 - get rid of {read,write}_len()
 - fix bad *64_to_cpu macros

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 lib/libio.h | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 173 insertions(+)
 create mode 100644 lib/libio.h

diff --git a/lib/libio.h b/lib/libio.h
new file mode 100644
index 0000000000000..6adc6a7bbee61
--- /dev/null
+++ b/lib/libio.h
@@ -0,0 +1,173 @@
+#ifndef _LIBIO_H_
+#define _LIBIO_H_
+/*
+ * Adapted from the Linux kernel's include/asm-generic/io.h and
+ * arch/arm/include/asm/io.h
+ */
+#include "libcflat.h"
+
+#ifndef NDEBUG
+#define LIBIO_ASSERT(expr) do { \
+	if (!(expr)) printf("%s:%d: assert failed!\n", __FILE__, __LINE__);\
+} while (0)
+#else
+#define LIBIO_ASSERT(expr) do { } while (0)
+#endif
+
+typedef u32 compat_ptr_t;
+
+/*
+ * Use compat_ptr() on 64-bit arches when casting 32-bit
+ * addresses to pointers in order to avoid compiler warnings.
+ */
+static inline void *compat_ptr(compat_ptr_t ptr)
+{
+	return (void *)(unsigned long)ptr;
+}
+
+static inline compat_ptr_t ptr_to_compat(void *ptr)
+{
+	return (u32)(unsigned long)ptr;
+}
+
+#ifndef __raw_readb
+static inline u8 __raw_readb(const volatile void *addr)
+{
+	return *(const volatile u8 *)addr;
+}
+#endif
+
+#ifndef __raw_readw
+static inline u16 __raw_readw(const volatile void *addr)
+{
+	return *(const volatile u16 *)addr;
+}
+#endif
+
+#ifndef __raw_readl
+static inline u32 __raw_readl(const volatile void *addr)
+{
+	return *(const volatile u32 *)addr;
+}
+#endif
+
+#ifndef __raw_readq
+static inline u64 __raw_readq(const volatile void *addr)
+{
+	LIBIO_ASSERT(sizeof(unsigned long) == sizeof(u64));
+	return *(const volatile u64 *)addr;
+}
+#endif
+
+#ifndef __raw_writeb
+static inline void __raw_writeb(u8 b, volatile void *addr)
+{
+	*(volatile u8 *)addr = b;
+}
+#endif
+
+#ifndef __raw_writew
+static inline void __raw_writew(u16 b, volatile void *addr)
+{
+	*(volatile u16 *)addr = b;
+}
+#endif
+
+#ifndef __raw_writel
+static inline void __raw_writel(u32 b, volatile void *addr)
+{
+	*(volatile u32 *)addr = b;
+}
+#endif
+
+#ifndef __raw_writeq
+static inline void __raw_writeq(u64 b, volatile void *addr)
+{
+	LIBIO_ASSERT(sizeof(unsigned long) == sizeof(u64));
+	*(volatile u64 *)addr = b;
+}
+#endif
+
+#ifndef __bswap16
+static inline u16 __bswap16(u16 x)
+{
+	return ((x >> 8) & 0xff) | ((x & 0xff) << 8);
+}
+#endif
+
+#ifndef __bswap32
+static inline u32 __bswap32(u32 x)
+{
+	return ((x & 0xff000000) >> 24) | ((x & 0x00ff0000) >>  8) |
+	       ((x & 0x0000ff00) <<  8) | ((x & 0x000000ff) << 24);
+}
+#endif
+
+#ifndef __bswap64
+static inline u64 __bswap64(u64 x)
+{
+	return ((x & 0x00000000000000ffULL) << 56) |
+	       ((x & 0x000000000000ff00ULL) << 40) |
+	       ((x & 0x0000000000ff0000ULL) << 24) |
+	       ((x & 0x00000000ff000000ULL) <<  8) |
+	       ((x & 0x000000ff00000000ULL) >>  8) |
+	       ((x & 0x0000ff0000000000ULL) >> 24) |
+	       ((x & 0x00ff000000000000ULL) >> 40) |
+	       ((x & 0xff00000000000000ULL) >> 56);
+}
+#endif
+
+#ifndef cpu_is_be
+#define cpu_is_be 0
+#endif
+
+#define le16_to_cpu(x) \
+	({ u16 __r = cpu_is_be ? __bswap16(x) : (x); __r; })
+#define cpu_to_le16 le16_to_cpu
+
+#define le32_to_cpu(x) \
+	({ u32 __r = cpu_is_be ? __bswap32(x) : (x); __r; })
+#define cpu_to_le32 le32_to_cpu
+
+#define le64_to_cpu(x) \
+	({ u64 __r = cpu_is_be ? __bswap64(x) : (x); __r; })
+#define cpu_to_le64 le64_to_cpu
+
+#define be16_to_cpu(x) \
+	({ u16 __r = !cpu_is_be ? __bswap16(x) : (x); __r; })
+#define cpu_to_be16 be16_to_cpu
+
+#define be32_to_cpu(x) \
+	({ u32 __r = !cpu_is_be ? __bswap32(x) : (x); __r; })
+#define cpu_to_be32 be32_to_cpu
+
+#define be64_to_cpu(x) \
+	({ u64 __r = !cpu_is_be ? __bswap64(x) : (x); __r; })
+#define cpu_to_be64 be64_to_cpu
+
+#ifndef rmb
+#define rmb() do { } while (0)
+#endif
+#ifndef wmb
+#define wmb() do { } while (0)
+#endif
+
+#define readb(addr) \
+	({ u8 __r = __raw_readb(addr); rmb(); __r; })
+#define readw(addr) \
+	({ u16 __r = le16_to_cpu(__raw_readw(addr)); rmb(); __r; })
+#define readl(addr) \
+	({ u32 __r = le32_to_cpu(__raw_readl(addr)); rmb(); __r; })
+#define readq(addr) \
+	({ u64 __r = le64_to_cpu(__raw_readq(addr)); rmb(); __r; })
+
+#define writeb(b, addr) \
+	({ wmb(); __raw_writeb(b, addr); })
+#define writew(b, addr) \
+	({ wmb(); __raw_writew(cpu_to_le16(b), addr); })
+#define writel(b, addr) \
+	({ wmb(); __raw_writel(cpu_to_le32(b), addr); })
+#define writeq(b, addr) \
+	({ wmb(); __raw_writeq(cpu_to_le64(b), addr); })
+
+#endif
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 10/17] libfdt: get libfdt to build
  2014-01-21 16:21 [PATCH 00/17] kvm-unit-tests/arm: initial drop Andrew Jones
                   ` (7 preceding siblings ...)
  2014-01-21 16:21 ` [PATCH 08/17] Introduce libio to common code for io read/write Andrew Jones
@ 2014-01-21 16:21 ` Andrew Jones
  2014-02-02  2:25   ` Christoffer Dall
  2014-01-21 16:21 ` [PATCH 11/17] add support for device trees Andrew Jones
                   ` (9 subsequent siblings)
  18 siblings, 1 reply; 47+ messages in thread
From: Andrew Jones @ 2014-01-21 16:21 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: christoffer.dall

Add string functions needed for libfdt, modify libfdt_env.h
for this environment, and add a make target.

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 Makefile                | 23 +++++++++++++++++++++-
 lib/libcflat.h          |  4 ++++
 lib/libfdt/libfdt_env.h | 25 ++++++++++++------------
 lib/string.c            | 51 +++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 90 insertions(+), 13 deletions(-)

diff --git a/Makefile b/Makefile
index 283655957f39f..94c565242c1b7 100644
--- a/Makefile
+++ b/Makefile
@@ -16,6 +16,13 @@ cflatobjs := \
 	lib/printf.o \
 	lib/string.o
 
+# libfdt paths
+LIBFDT_objdir = lib/libfdt
+LIBFDT_srcdir = lib/libfdt
+LIBFDT_archive = $(LIBFDT_objdir)/libfdt.a
+LIBFDT_include = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_INCLUDES))
+LIBFDT_version = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_VERSION))
+
 #include architecure specific make rules
 include config/config-$(ARCH).mak
 
@@ -41,6 +48,20 @@ LDFLAGS += -pthread -lrt
 $(libcflat): $(cflatobjs)
 	$(AR) rcs $@ $^
 
+include $(LIBFDT_srcdir)/Makefile.libfdt
+
+.PHONY: libfdt
+libfdt: $(LIBFDT_archive)
+
+$(LIBFDT_archive): CFLAGS += -ffreestanding -I lib -I lib/libfdt -Wno-sign-compare
+$(LIBFDT_archive): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
+	$(AR) rcs $@ $^
+
+libfdt_clean:
+	$(RM) $(LIBFDT_archive) \
+	$(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS)) \
+	$(LIBFDT_objdir)/.*.d
+
 %.o: %.S
 	$(CC) $(CFLAGS) -c -nostdlib -o $@ $<
 
@@ -53,7 +74,7 @@ install:
 clean: arch_clean
 	$(RM) lib/.*.d $(libcflat) $(cflatobjs)
 
-cscope: common_dirs = lib
+cscope: common_dirs = lib lib/libfdt
 cscope:
 	rm -f ./cscope.*
 	find $(TEST_DIR) lib/$(TEST_DIR) $(common_dirs) -maxdepth 1 \
diff --git a/lib/libcflat.h b/lib/libcflat.h
index a1be635ab4ee9..2cde64a560956 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -43,6 +43,7 @@ extern void exit(int code);
 extern unsigned long strlen(const char *buf);
 extern char *strcat(char *dest, const char *src);
 extern int strcmp(const char *a, const char *b);
+extern char *strchr(const char *s, int c);
 
 extern int printf(const char *fmt, ...);
 extern int vsnprintf(char *buf, int size, const char *fmt, va_list va);
@@ -51,6 +52,9 @@ extern void puts(const char *s);
 
 extern void *memset(void *s, int c, size_t n);
 extern void *memcpy(void *dest, const void *src, size_t n);
+extern int memcmp(const void *s1, const void *s2, size_t n);
+extern void *memmove(void *dest, const void *src, size_t n);
+extern void *memchr(const void *s, int c, size_t n);
 
 extern long atol(const char *ptr);
 #define ARRAY_SIZE(_a)  (sizeof(_a)/sizeof((_a)[0]))
diff --git a/lib/libfdt/libfdt_env.h b/lib/libfdt/libfdt_env.h
index 9dea97dfff818..46fcb6c29045f 100644
--- a/lib/libfdt/libfdt_env.h
+++ b/lib/libfdt/libfdt_env.h
@@ -52,9 +52,16 @@
  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <stddef.h>
-#include <stdint.h>
-#include <string.h>
+#include "libcflat.h"
+#include "libio.h"
+
+#ifndef HAVE_UINTS
+typedef u8 uint8_t;
+typedef u16 uint16_t;
+typedef u32 uint32_t;
+typedef u64 uint64_t;
+typedef unsigned long uintptr_t;
+#endif
 
 #ifdef __CHECKER__
 #define __force __attribute__((force))
@@ -68,14 +75,9 @@ typedef uint16_t __bitwise fdt16_t;
 typedef uint32_t __bitwise fdt32_t;
 typedef uint64_t __bitwise fdt64_t;
 
-#define EXTRACT_BYTE(x, n)	((unsigned long long)((uint8_t *)&x)[n])
-#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1))
-#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \
-			 (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3))
-#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \
-			 (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \
-			 (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \
-			 (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7))
+#define CPU_TO_FDT16 cpu_to_be16
+#define CPU_TO_FDT32 cpu_to_be32
+#define CPU_TO_FDT64 cpu_to_be64
 
 static inline uint16_t fdt16_to_cpu(fdt16_t x)
 {
@@ -106,6 +108,5 @@ static inline fdt64_t cpu_to_fdt64(uint64_t x)
 #undef CPU_TO_FDT64
 #undef CPU_TO_FDT32
 #undef CPU_TO_FDT16
-#undef EXTRACT_BYTE
 
 #endif /* _LIBFDT_ENV_H */
diff --git a/lib/string.c b/lib/string.c
index 3a9caf720bf2b..234f96f4442f7 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -31,6 +31,17 @@ int strcmp(const char *a, const char *b)
     return *a - *b;
 }
 
+char *strchr(const char *s, int c)
+{
+    unsigned char chr = (unsigned char)c;
+    int n = strlen(s) + 1;
+
+    while (n--)
+	if (*s++ == chr)
+	    return (char *)(s - 1);
+    return NULL;
+}
+
 void *memset(void *s, int c, size_t n)
 {
     size_t i;
@@ -54,6 +65,46 @@ void *memcpy(void *dest, const void *src, size_t n)
     return dest;
 }
 
+int memcmp(const void *s1, const void *s2, size_t n)
+{
+    const unsigned char *a = s1, *b = s2;
+    int ret = 0;
+
+    while (n--) {
+	ret = *a - *b;
+	if (ret)
+	    break;
+	++a, ++b;
+    }
+    return ret;
+}
+
+void *memmove(void *dest, const void *src, size_t n)
+{
+    const unsigned char *s = src;
+    unsigned char *d = dest;
+
+    if (d <= s) {
+	while (n--)
+	    *d++ = *s++;
+    } else {
+	d += n, s += n;
+	while (n--)
+	    *--d = *--s;
+    }
+    return dest;
+}
+
+void *memchr(const void *s, int c, size_t n)
+{
+    const unsigned char *str = s, chr = (unsigned char)c;
+
+    while (n--)
+	if (*str++ == chr)
+	    return (void *)(str - 1);
+    return NULL;
+}
+
 long atol(const char *ptr)
 {
     long acc = 0;
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 11/17] add support for device trees
  2014-01-21 16:21 [PATCH 00/17] kvm-unit-tests/arm: initial drop Andrew Jones
                   ` (8 preceding siblings ...)
  2014-01-21 16:21 ` [PATCH 10/17] libfdt: get libfdt to build Andrew Jones
@ 2014-01-21 16:21 ` Andrew Jones
  2014-02-02  2:27   ` Christoffer Dall
  2014-01-21 16:21 ` [PATCH 12/17] Introduce virtio-testdev Andrew Jones
                   ` (8 subsequent siblings)
  18 siblings, 1 reply; 47+ messages in thread
From: Andrew Jones @ 2014-01-21 16:21 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: christoffer.dall

Add some device tree functions, built on libfdt, to the common
code in order to facilitate the extraction of boot info and device
base addresses. These functions are generic and arch-neutral. It's
expected that more functions will be added as more information
from the device tree is needed.

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 lib/devicetree.c | 257 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/devicetree.h |  95 ++++++++++++++++++++
 lib/libcflat.h   |   1 +
 3 files changed, 353 insertions(+)
 create mode 100644 lib/devicetree.c
 create mode 100644 lib/devicetree.h

diff --git a/lib/devicetree.c b/lib/devicetree.c
new file mode 100644
index 0000000000000..a9ab7ed367704
--- /dev/null
+++ b/lib/devicetree.c
@@ -0,0 +1,257 @@
+#include "libcflat.h"
+#include "libfdt/libfdt.h"
+#include "devicetree.h"
+
+static const void *fdt;
+
+const char *dt_strerror(int errval)
+{
+	if (errval == -EINVAL)
+		return "Invalid argument";
+	return fdt_strerror(errval);
+}
+
+int dt_set(const void *fdt_ptr)
+{
+	int ret = fdt_check_header(fdt_ptr);
+	if (ret == 0)
+		fdt = fdt_ptr;
+	return ret;
+}
+
+const void *dt_get(void)
+{
+	return fdt;
+}
+
+int dt_get_bootargs_ptr(char **bootargs)
+{
+	const struct fdt_property *prop;
+	int node, err;
+
+	node = fdt_path_offset(fdt, "/chosen");
+	if (node < 0)
+		return node;
+
+	prop = fdt_get_property(fdt, node, "bootargs", &err);
+	if (prop)
+		*bootargs = (char *)prop->data;
+	else if (err != -FDT_ERR_NOTFOUND)
+		return err;
+
+	return 0;
+}
+
+int dt_bus_default_match(const struct dt_bus *bus __unused,
+			 int nodeoffset __unused)
+{
+	/* just select first node found */
+	return 1;
+}
+
+int dt_bus_default_translate(const struct dt_bus *bus __unused,
+			     struct dt_reg *reg, void **addr, size_t *size)
+{
+	u64 temp64;
+
+	if (!reg || !addr)
+		return -EINVAL;
+
+	/*
+	 * default translate only understands u32 (<1> <1>) and
+	 * u64 (<2> <1>|<2>) addresses
+	 */
+	if (reg->nr_address_cells < 1
+			|| reg->nr_address_cells > 2
+			|| reg->nr_size_cells < 1
+			|| reg->nr_size_cells > 2)
+		return -EINVAL;
+
+	if (reg->nr_address_cells == 2)
+		temp64 = ((u64)reg->address_cells[0] << 32)
+					| reg->address_cells[1];
+	else
+		temp64 = reg->address_cells[0];
+
+	/*
+	 * If we're 32-bit, then the upper word of a two word
+	 * address better be zero.
+	 */
+	if (sizeof(void *) == sizeof(u32) && reg->nr_address_cells > 1
+			&& reg->address_cells[0] != 0)
+		return -EINVAL;
+
+	*addr = (void *)(unsigned long)temp64;
+
+	if (size) {
+		if (reg->nr_size_cells == 2)
+			temp64 = ((u64)reg->size_cells[0] << 32)
+						| reg->size_cells[1];
+		else
+			temp64 = reg->size_cells[0];
+
+		if (sizeof(size_t) == sizeof(u32) && reg->nr_size_cells > 1
+				&& reg->size_cells[0] != 0)
+			return -EINVAL;
+
+		*size = (size_t)temp64;
+	}
+
+	return 0;
+}
+
+const struct dt_bus dt_default_bus = {
+	.name = "default",
+	.match = dt_bus_default_match,
+	.translate = dt_bus_default_translate,
+};
+
+void dt_bus_init_defaults(struct dt_bus *bus, const char *name)
+{
+	*bus = dt_default_bus;
+	bus->name = name;
+}
+
+int dt_bus_find_device_compatible(const struct dt_bus *bus,
+				  const char *compatible)
+{
+	int node, ret;
+
+	if (!bus || !bus->match)
+		return -EINVAL;
+
+	node = fdt_node_offset_by_compatible(fdt, -1, compatible);
+
+	while (node >= 0) {
+		if ((ret = bus->match(bus, node)) < 0)
+			return ret;
+		else if (ret)
+			break;
+		node = fdt_node_offset_by_compatible(fdt, node, compatible);
+	}
+
+	return node;
+}
+
+static int __dt_get_num_cells(int node, u32 *address_cells, u32 *size_cells)
+{
+	const struct fdt_property *prop;
+	u32 *data;
+	int err;
+
+	prop = fdt_get_property(fdt, node, "#address-cells", &err);
+	if (!prop && err == -FDT_ERR_NOTFOUND) {
+
+		node = fdt_parent_offset(fdt, node);
+		if (node < 0)
+			return node;
+
+		return __dt_get_num_cells(node, address_cells, size_cells);
+
+	} else if (!prop) {
+		return err;
+	}
+
+	data = (u32 *)prop->data;
+	*address_cells = fdt32_to_cpu(*data);
+
+	prop = fdt_get_property(fdt, node, "#size-cells", &err);
+	if (!prop) {
+		printf("we can read #address-cells, but not #size-cells?\n");
+		return err;
+	}
+
+	data = (u32 *)prop->data;
+	*size_cells = fdt32_to_cpu(*data);
+
+	return 0;
+}
+
+int dt_get_num_cells(int nodeoffset, u32 *address_cells, u32 *size_cells)
+{
+	if (!address_cells || !size_cells)
+		return -EINVAL;
+	return __dt_get_num_cells(nodeoffset, address_cells, size_cells);
+}
+
+int dt_get_reg(int nodeoffset, int regidx, u32 *address_cells,
+	       u32 *size_cells, struct dt_reg *reg)
+{
+	const struct fdt_property *prop;
+	u32 *data, regsz, i;
+	int err;
+
+	if (!address_cells || !size_cells || !reg)
+		return -EINVAL;
+
+	memset(reg, 0, sizeof(struct dt_reg));
+
+	/*
+	 * We assume #size-cells == 0 means translation is impossible,
+	 * reserving it to indicate that we don't know what #address-cells
+	 * and #size-cells are yet, and thus must try to get them from the
+	 * parent.
+	 */
+	if (*size_cells == 0 && (err = dt_get_num_cells(nodeoffset,
+					address_cells, size_cells)) < 0)
+		return err;
+
+	prop = fdt_get_property(fdt, nodeoffset, "reg", &err);
+	if (prop == NULL)
+		return err;
+
+	regsz = (*address_cells + *size_cells) * sizeof(u32);
+
+	if ((regidx + 1) * regsz > prop->len)
+		return -EINVAL;
+
+	data = (u32 *)(prop->data + regidx * regsz);
+
+	for (i = 0; i < *address_cells; ++i, ++data)
+		reg->address_cells[i] = fdt32_to_cpu(*data);
+	for (i = 0; i < *size_cells; ++i, ++data)
+		reg->size_cells[i] = fdt32_to_cpu(*data);
+
+	reg->nr_address_cells = *address_cells;
+	reg->nr_size_cells = *size_cells;
+
+	return 0;
+}
+
+int __dt_bus_translate_reg(int nodeoffset, const struct dt_bus *bus,
+			   int regidx, u32 *address_cells, u32 *size_cells,
+			   void **addr, size_t *size)
+{
+	struct dt_reg reg;
+	int ret;
+
+	if (!bus || !bus->translate)
+		return -EINVAL;
+
+	ret = dt_get_reg(nodeoffset, regidx, address_cells, size_cells, &reg);
+	if (ret < 0)
+		return ret;
+
+	return bus->translate(bus, &reg, addr, size);
+}
+
+int dt_bus_translate_reg(int nodeoffset, const struct dt_bus *bus,
+			 int regidx, void **addr, size_t *size)
+{
+	/*
+	 * size_cells == 0 tells dt_get_reg to get address_cells
+	 * and size_cells from the parent node
+	 */
+	u32 address_cells, size_cells = 0;
+	return __dt_bus_translate_reg(nodeoffset, bus, regidx,
+			&address_cells, &size_cells, addr, size);
+}
+
+int dt_get_memory_params(void **start, size_t *size)
+{
+	int node = fdt_path_offset(fdt, "/memory");
+	if (node < 0)
+		return node;
+
+	return dt_bus_translate_reg(node, &dt_default_bus, 0, start, size);
+}
diff --git a/lib/devicetree.h b/lib/devicetree.h
new file mode 100644
index 0000000000000..1f2d61b46a308
--- /dev/null
+++ b/lib/devicetree.h
@@ -0,0 +1,95 @@
+#ifndef _DEVICETREE_H_
+#define _DEVICETREE_H_
+#include "libcflat.h"
+
+/*
+ * set/get the fdt pointer
+ */
+extern int dt_set(const void *fdt_ptr);
+extern const void *dt_get(void);
+
+/*
+ * bootinfo accessors
+ */
+extern int dt_get_bootargs_ptr(char **bootargs);
+extern int dt_get_memory_params(void **start, size_t *size);
+
+#define MAX_ADDRESS_CELLS	4
+#define MAX_SIZE_CELLS		4
+struct dt_reg {
+	u32 nr_address_cells;
+	u32 nr_size_cells;
+	u32 address_cells[MAX_ADDRESS_CELLS];
+	u32 size_cells[MAX_SIZE_CELLS];
+};
+
+struct dt_bus {
+	const char *name;
+	int (*match)(const struct dt_bus *bus, int nodeoffset);
+	/*
+	 * match() returns
+	 *  - a positive value on match
+	 *  - zero on no match
+	 *  - a negative value on error
+	 */
+	int (*translate)(const struct dt_bus *bus, struct dt_reg *reg,
+			  void **addr, size_t *size);
+	/*
+	 * translate() returns
+	 *  - zero on success
+	 *  - a negative value on error
+	 */
+	void *private;
+};
+
+extern const struct dt_bus dt_default_bus;
+extern void dt_bus_init_defaults(struct dt_bus *bus, const char *name);
+extern int dt_bus_default_match(const struct dt_bus *bus, int nodeoffset);
+extern int dt_bus_default_translate(const struct dt_bus *bus,
+				    struct dt_reg *reg, void **addr,
+				    size_t *size);
+
+/*
+ * find an fdt device node compatible with @compatible using match()
+ * from the given bus @bus.
+ */
+extern int dt_bus_find_device_compatible(const struct dt_bus *bus,
+					 const char *compatible);
+
+/*
+ * translate the reg indexed by @regidx of the "reg" property of the
+ * device node at @nodeoffset using translate() from the given bus @bus.
+ * returns the translation in @addr and @size
+ */
+extern int dt_bus_translate_reg(int nodeoffset, const struct dt_bus *bus,
+				int regidx, void **addr, size_t *size);
+
+/*
+ * same as dt_bus_translate_reg, but uses the given @address_cells and
+ * @size_cells rather than pulling them from the parent of @nodeoffset
+ */
+extern int __dt_bus_translate_reg(int nodeoffset, const struct dt_bus *bus,
+				  int regidx, u32 *address_cells,
+				  u32 *size_cells, void **addr,
+				  size_t *size);
+
+/*
+ * read the "reg" property of @nodeoffset, which is defined by @address_cells
+ * and @size_cells, and store the reg indexed by @regidx into @reg
+ */
+extern int dt_get_reg(int nodeoffset, int regidx, u32 *address_cells,
+		      u32 *size_cells, struct dt_reg *reg);
+
+/*
+ * searches up the devicetree for @address_cells and @size_cells,
+ * starting from @nodeoffset
+ */
+extern int dt_find_num_cells(int nodeoffset, u32 *address_cells,
+			    u32 *size_cells);
+
+/*
+ * convert devicetree errors to strings
+ */
+extern const char *dt_strerror(int errval);
+
+#endif
diff --git a/lib/libcflat.h b/lib/libcflat.h
index 2cde64a560956..fdaaf2a8ab31d 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -61,6 +61,7 @@ extern long atol(const char *ptr);
 
 #define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
 
+#define __unused __attribute__((__unused__))
 #define NULL ((void *)0UL)
 #include "errno.h"
 #endif
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 12/17] Introduce virtio-testdev
  2014-01-21 16:21 [PATCH 00/17] kvm-unit-tests/arm: initial drop Andrew Jones
                   ` (9 preceding siblings ...)
  2014-01-21 16:21 ` [PATCH 11/17] add support for device trees Andrew Jones
@ 2014-01-21 16:21 ` Andrew Jones
  2014-02-02  2:27   ` Christoffer Dall
  2014-01-21 16:21 ` [PATCH 13/17] arm: initial drop Andrew Jones
                   ` (7 subsequent siblings)
  18 siblings, 1 reply; 47+ messages in thread
From: Andrew Jones @ 2014-01-21 16:21 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: christoffer.dall

virtio-testdev is a communication channel to qemu through virtio that
can be used by test code to send commands. The only command currently
implemented is EXIT, which allows the test code to exit with a given
status code.

Signed-off-by: Andrew Jones <drjones@redhat.com>

---
v3:
 - switched from iomaps to devicetree
 - fixed Christoffer's nits
 - don't call halt() explicitly, let exit() fall back to it
 - vm_{get,set} now {read,write} byte by byte like the kernel
v2:
 - use readl/writel framework (libio) [Christoffer Dall]
 - keep the virtio abstraction in virtio-testdev [Alexander Graf]
---
 lib/libcflat.h       |   3 ++
 lib/virtio-testdev.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/virtio-testdev.h |   9 ++++
 lib/virtio.c         | 126 ++++++++++++++++++++++++++++++++++++++++++++++
 lib/virtio.h         |  74 +++++++++++++++++++++++++++
 5 files changed, 351 insertions(+)
 create mode 100644 lib/virtio-testdev.c
 create mode 100644 lib/virtio-testdev.h
 create mode 100644 lib/virtio.c
 create mode 100644 lib/virtio.h

diff --git a/lib/libcflat.h b/lib/libcflat.h
index fdaaf2a8ab31d..84b8783bacfdc 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -60,6 +60,9 @@ extern long atol(const char *ptr);
 #define ARRAY_SIZE(_a)  (sizeof(_a)/sizeof((_a)[0]))
 
 #define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
+#define container_of(ptr, type, member) ({				\
+		const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
+		(type *)( (char *)__mptr - offsetof(type,member) );})
 
 #define __unused __attribute__((__unused__))
 #define NULL ((void *)0UL)
diff --git a/lib/virtio-testdev.c b/lib/virtio-testdev.c
new file mode 100644
index 0000000000000..d4a69ede12a7a
--- /dev/null
+++ b/lib/virtio-testdev.c
@@ -0,0 +1,139 @@
+#include "libcflat.h"
+#include "virtio.h"
+
+#define TESTDEV_MAJOR_VER 1
+#define TESTDEV_MINOR_VER 1
+
+#define VIRTIO_ID_TESTDEV 0xffff
+
+#define CONFIG_SIZE 64
+
+enum {
+	VERSION = 1,
+	CLEAR,
+	EXIT,
+};
+
+#define TOKEN_OFFSET		0x0
+#define NARGS_OFFSET		0x4
+#define NRETS_OFFSET		0x8
+#define ARG_OFFSET(n)		(0xc + (n) * 4)
+#define __RET_OFFSET(nargs, n)	(ARG_OFFSET(nargs) + (n) * 4)
+
+static struct virtio_dev *testdev;
+
+static u32 testdev_readl(unsigned offset)
+{
+	if (offset > (CONFIG_SIZE - 4)) {
+		printf("%s: offset 0x%x to big!\n", __func__, offset);
+		exit(EINVAL);
+	}
+
+	return virtio_config_readl(testdev, offset);
+}
+
+static void testdev_writel(unsigned offset, u32 val)
+{
+	if (offset > (CONFIG_SIZE - 4)) {
+		printf("%s: offset 0x%x to big!\n", __func__, offset);
+		exit(EINVAL);
+	}
+
+	virtio_config_writel(testdev, offset, val);
+}
+
+/*
+ * We have to write all args; nargs, nrets, ... first to avoid executing
+ * the token's operation until all args are in place. Then issue the op,
+ * and then read the return values. Reading the return values (or just
+ * sanity checking by reading token) will read a zero into qemu's copy
+ * of the token, which allows us to prepare additional ops without
+ * re-executing the last one.
+ */
+void virtio_testdev(u32 token, u32 nargs, u32 nrets, ...)
+{
+	va_list va;
+	unsigned off;
+	u32 n;
+
+	if (!testdev)
+		return;
+
+	testdev_writel(NARGS_OFFSET, nargs);
+	testdev_writel(NRETS_OFFSET, nrets);
+
+	va_start(va, nrets);
+
+	off = ARG_OFFSET(0);
+	n = nargs;
+	while (n--) {
+		testdev_writel(off, va_arg(va, unsigned));
+		off += 4;
+	}
+
+	/* this runs the op, but then resets token to zero */
+	testdev_writel(TOKEN_OFFSET, token);
+
+	/* sanity check */
+	if (testdev_readl(TOKEN_OFFSET) != 0) {
+		printf("virtio-testdev token should always read as zero!\n");
+		exit(EIO);
+	}
+
+	off = __RET_OFFSET(nargs, 0);
+	n = nrets;
+	while (n--) {
+		u32 *r = va_arg(va, unsigned *);
+		*r = testdev_readl(off);
+		off += 4;
+	}
+
+	va_end(va);
+}
+
+void virtio_testdev_version(u32 *version)
+{
+	virtio_testdev(VERSION, 0, 1, version);
+}
+
+void virtio_testdev_clear(void)
+{
+	virtio_testdev(CLEAR, 0, 0);
+}
+
+void virtio_testdev_exit(int code)
+{
+	virtio_testdev(EXIT, 1, 0, code);
+}
+
+void virtio_testdev_init(void)
+{
+	u16 major, minor;
+	u32 version;
+
+	testdev = virtio_bind(VIRTIO_ID_TESTDEV);
+	if (testdev == NULL) {
+		printf("Can't find virtio-testdev. "
+		       "Is '-device virtio-testdev' "
+		       "on the qemu command line?\n");
+		exit(ENODEV);
+	}
+
+	virtio_testdev_version(&version);
+	major = version >> 16;
+	minor = version & 0xffff;
+
+	if (major != TESTDEV_MAJOR_VER || minor < TESTDEV_MINOR_VER) {
+		char *u = "qemu";
+		if (major > TESTDEV_MAJOR_VER)
+			u = "kvm-unit-tests";
+		printf("Incompatible version of virtio-testdev: major = %d, "
+		       "minor = %d\n", major, minor);
+		printf("Update %s.\n", u);
+		exit(ENODEV);
+	}
+
+	if (minor > TESTDEV_MINOR_VER)
+		printf("testdev has new features. "
+		       "An update of kvm-unit-tests may be possible.\n");
+}
diff --git a/lib/virtio-testdev.h b/lib/virtio-testdev.h
new file mode 100644
index 0000000000000..c10bbfb591d0b
--- /dev/null
+++ b/lib/virtio-testdev.h
@@ -0,0 +1,9 @@
+#ifndef _VIRTIO_TESTDEV_H_
+#define _VIRTIO_TESTDEV_H_
+#include "libcflat.h"
+
+extern void virtio_testdev_init(void);
+extern void virtio_testdev_version(u32 *version);
+extern void virtio_testdev_clear(void);
+extern void virtio_testdev_exit(int code);
+#endif
diff --git a/lib/virtio.c b/lib/virtio.c
new file mode 100644
index 0000000000000..8abc8b2399a08
--- /dev/null
+++ b/lib/virtio.c
@@ -0,0 +1,126 @@
+#include "libcflat.h"
+#include "devicetree.h"
+#include "libio.h"
+#include "heap.h"
+#include "virtio.h"
+
+struct virtio_dt_device_data {
+	u32 device;
+	struct dt_bus *bus;
+	int node;
+	/* cached variables */
+	u32 address_cells, size_cells;
+};
+
+static void virtio_dt_device_data_init(struct virtio_dt_device_data *data,
+				       u32 device, struct dt_bus *bus)
+{
+	memset(data, 0, sizeof(struct virtio_dt_device_data));
+	data->device = device;
+	data->bus = bus;
+}
+
+static int vm_dt_bus_match(const struct dt_bus *bus, int nodeoffset);
+static struct virtio_dev *vm_bind(struct virtio_dt_device_data *data);
+
+struct virtio_dev *virtio_bind(u32 device)
+{
+	struct virtio_dt_device_data data;
+	struct dt_bus bus;
+	const char *compatible;
+
+	/*
+	 * currently we only support virtio-mmio
+	 */
+	compatible = "virtio,mmio";
+	dt_bus_init_defaults(&bus, compatible);
+	bus.match = vm_dt_bus_match;
+	bus.private = (void *)&data;
+	virtio_dt_device_data_init(&data, device, &bus);
+
+	data.node = dt_bus_find_device_compatible(&bus, compatible);
+	if (data.node < 0) {
+		printf("virtio bind for device id 0x%x failed, "
+		       "fdt_error: %s\n", device, dt_strerror(data.node));
+		return NULL;
+	}
+
+	return vm_bind(&data);
+}
+
+static int virtio_dt_bus_translate_reg(int nodeoffset,
+				       const struct dt_bus *bus,
+				       int regidx, void **addr,
+				       size_t *size)
+{
+	struct virtio_dt_device_data *data =
+		(struct virtio_dt_device_data *)bus->private;
+
+	return __dt_bus_translate_reg(nodeoffset, bus, regidx,
+			&data->address_cells, &data->size_cells, addr, size);
+}
+
+/******************************************************
+ * virtio_mmio
+ ******************************************************/
+
+static int vm_dt_bus_match(const struct dt_bus *bus, int nodeoffset)
+{
+	struct virtio_dt_device_data *data =
+		(struct virtio_dt_device_data *)bus->private;
+	void *addr;
+	int ret;
+
+	ret = virtio_dt_bus_translate_reg(nodeoffset, bus, 0, &addr, NULL);
+	if (ret < 0) {
+		printf("can't get reg! fdt_error: %s\n", dt_strerror(ret));
+		return ret;
+	}
+
+	return readl(addr + VIRTIO_MMIO_DEVICE_ID) == data->device;
+}
+
+#define to_virtio_mmio_dev(vdev_ptr) \
+	container_of(vdev_ptr, struct virtio_mmio_dev, vdev)
+
+static void vm_get(struct virtio_dev *vdev, unsigned offset,
+		   void *buf, unsigned len)
+{
+	struct virtio_mmio_dev *vmdev = to_virtio_mmio_dev(vdev);
+	u8 *p = buf;
+	unsigned i;
+
+	for (i = 0; i < len; ++i)
+		p[i] = readb(vmdev->base + VIRTIO_MMIO_CONFIG + offset + i);
+}
+
+static void vm_set(struct virtio_dev *vdev, unsigned offset,
+		   const void *buf, unsigned len)
+{
+	struct virtio_mmio_dev *vmdev = to_virtio_mmio_dev(vdev);
+	const u8 *p = buf;
+	unsigned i;
+
+	for (i = 0; i < len; ++i)
+		writeb(p[i], vmdev->base + VIRTIO_MMIO_CONFIG + offset + i);
+}
+
+static struct virtio_dev *vm_bind(struct virtio_dt_device_data *data)
+{
+	struct virtio_mmio_dev *vmdev;
+	void *page;
+
+	page = alloc_page();
+	vmdev = page;
+	vmdev->vdev.config = page + sizeof(struct virtio_mmio_dev);
+
+	vmdev->vdev.id.device = data->device;
+	vmdev->vdev.id.vendor = -1;
+	vmdev->vdev.config->get = vm_get;
+	vmdev->vdev.config->set = vm_set;
+
+	(void)virtio_dt_bus_translate_reg(data->node, data->bus, 0,
+						&vmdev->base, NULL);
+
+	return &vmdev->vdev;
+}
diff --git a/lib/virtio.h b/lib/virtio.h
new file mode 100644
index 0000000000000..c30a8dcd105cd
--- /dev/null
+++ b/lib/virtio.h
@@ -0,0 +1,74 @@
+#ifndef _VIRTIO_H_
+#define _VIRTIO_H_
+#include "libcflat.h"
+
+#define VIRTIO_MMIO_DEVICE_ID	0x008
+#define VIRTIO_MMIO_CONFIG	0x100
+
+struct virtio_devid {
+	u32 device;
+	u32 vendor;
+};
+
+struct virtio_dev {
+	struct virtio_devid id;
+	struct virtio_conf_ops *config;
+};
+
+struct virtio_conf_ops {
+	void (*get)(struct virtio_dev *vdev, unsigned offset,
+		    void *buf, unsigned len);
+	void (*set)(struct virtio_dev *vdev, unsigned offset,
+		    const void *buf, unsigned len);
+};
+
+struct virtio_mmio_dev {
+	struct virtio_dev vdev;
+	void *base;
+};
+
+static inline u8
+virtio_config_readb(struct virtio_dev *vdev, unsigned offset)
+{
+	u8 val;
+	vdev->config->get(vdev, offset, &val, 1);
+	return val;
+}
+
+static inline u16
+virtio_config_readw(struct virtio_dev *vdev, unsigned offset)
+{
+	u16 val;
+	vdev->config->get(vdev, offset, &val, 2);
+	return val;
+}
+
+static inline u32
+virtio_config_readl(struct virtio_dev *vdev, unsigned offset)
+{
+	u32 val;
+	vdev->config->get(vdev, offset, &val, 4);
+	return val;
+}
+
+static inline void
+virtio_config_writeb(struct virtio_dev *vdev, unsigned offset, u8 val)
+{
+	vdev->config->set(vdev, offset, &val, 1);
+}
+
+static inline void
+virtio_config_writew(struct virtio_dev *vdev, unsigned offset, u16 val)
+{
+	vdev->config->set(vdev, offset, &val, 2);
+}
+
+static inline void
+virtio_config_writel(struct virtio_dev *vdev, unsigned offset, u32 val)
+{
+	vdev->config->set(vdev, offset, &val, 4);
+}
+
+extern struct virtio_dev *virtio_bind(u32 device);
+
+#endif
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 13/17] arm: initial drop
  2014-01-21 16:21 [PATCH 00/17] kvm-unit-tests/arm: initial drop Andrew Jones
                   ` (10 preceding siblings ...)
  2014-01-21 16:21 ` [PATCH 12/17] Introduce virtio-testdev Andrew Jones
@ 2014-01-21 16:21 ` Andrew Jones
  2014-02-02  2:28   ` Christoffer Dall
  2014-01-21 16:22 ` [PATCH 14/17] arm: Add IO accessors to avoid register-writeback Andrew Jones
                   ` (6 subsequent siblings)
  18 siblings, 1 reply; 47+ messages in thread
From: Andrew Jones @ 2014-01-21 16:21 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: christoffer.dall

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 <drjones@redhat.com>

---
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 <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 ...
+
+[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 <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=$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;
 
 /*
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 14/17] arm: Add IO accessors to avoid register-writeback
  2014-01-21 16:21 [PATCH 00/17] kvm-unit-tests/arm: initial drop Andrew Jones
                   ` (11 preceding siblings ...)
  2014-01-21 16:21 ` [PATCH 13/17] arm: initial drop Andrew Jones
@ 2014-01-21 16:22 ` Andrew Jones
  2014-01-21 16:22 ` [PATCH 15/17] printf: support field padding Andrew Jones
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 47+ messages in thread
From: Andrew Jones @ 2014-01-21 16:22 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: christoffer.dall

From: Christoffer Dall <christoffer.dall@linaro.org>

Add IO accessor functions to the arm library functions to avoid
register-writeback IO accessors that are not yet supported by the
kernel.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 lib/arm/io.h | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/lib/arm/io.h b/lib/arm/io.h
index 0284552f6ef1f..533a47069bb39 100644
--- a/lib/arm/io.h
+++ b/lib/arm/io.h
@@ -1,6 +1,9 @@
 #ifndef _ARM_IO_H_
 #define _ARM_IO_H_
 
+#define __iomem
+#define __force
+
 #define __bswap16 bswap16
 static inline u16 bswap16(u16 val)
 {
@@ -17,5 +20,59 @@ static inline u32 bswap32(u32 val)
 	return ret;
 }
 
+#define __raw_readb __raw_readb
+static inline u8 __raw_readb(const volatile void __iomem *addr)
+{
+	u8 val;
+	asm volatile("ldrb %1, %0"
+		     : "+Qo" (*(volatile u8 __force *)addr),
+		       "=r" (val));
+	return val;
+}
+
+#define __raw_readw __raw_readw
+static inline u16 __raw_readw(const volatile void __iomem *addr)
+{
+	u16 val;
+	asm volatile("ldrh %1, %0"
+		     : "+Q" (*(volatile u16 __force *)addr),
+		       "=r" (val));
+	return val;
+}
+
+#define __raw_readl __raw_readl
+static inline u32 __raw_readl(const volatile void __iomem *addr)
+{
+	u32 val;
+	asm volatile("ldr %1, %0"
+		     : "+Qo" (*(volatile u32 __force *)addr),
+		       "=r" (val));
+	return val;
+}
+
+#define __raw_writeb __raw_writeb
+static inline void __raw_writeb(u8 val, volatile void __iomem *addr)
+{
+	asm volatile("strb %1, %0"
+		     : "+Qo" (*(volatile u8 __force *)addr)
+		     : "r" (val));
+}
+
+#define __raw_writew __raw_writew
+static inline void __raw_writew(u16 val, volatile void __iomem *addr)
+{
+	asm volatile("strh %1, %0"
+		     : "+Q" (*(volatile u16 __force *)addr)
+		     : "r" (val));
+}
+
+#define __raw_writel __raw_writel
+static inline void __raw_writel(u32 val, volatile void __iomem *addr)
+{
+	asm volatile("str %1, %0"
+		     : "+Qo" (*(volatile u32 __force *)addr)
+		     : "r" (val));
+}
+
 #include "libio.h"
 #endif
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 15/17] printf: support field padding
  2014-01-21 16:21 [PATCH 00/17] kvm-unit-tests/arm: initial drop Andrew Jones
                   ` (12 preceding siblings ...)
  2014-01-21 16:22 ` [PATCH 14/17] arm: Add IO accessors to avoid register-writeback Andrew Jones
@ 2014-01-21 16:22 ` Andrew Jones
  2014-02-02  2:28   ` Christoffer Dall
  2014-01-21 16:22 ` [PATCH 16/17] arm: add useful headers from the linux kernel Andrew Jones
                   ` (4 subsequent siblings)
  18 siblings, 1 reply; 47+ messages in thread
From: Andrew Jones @ 2014-01-21 16:22 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: christoffer.dall

Support format flags for field padding, such as "%08x", allowing
register dumps to be easier on the eyes.

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 lib/printf.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 68 insertions(+), 14 deletions(-)

diff --git a/lib/printf.c b/lib/printf.c
index 867eb1926f742..89308fb26b7d2 100644
--- a/lib/printf.c
+++ b/lib/printf.c
@@ -6,6 +6,11 @@ typedef struct pstream {
     int added;
 } pstream_t;
 
+typedef struct strprops {
+    char pad;
+    int npad;
+} strprops_t;
+
 static void addchar(pstream_t *p, char c)
 {
     if (p->remain) {
@@ -15,15 +20,35 @@ static void addchar(pstream_t *p, char c)
     ++p->added;
 }
 
-void print_str(pstream_t *p, const char *s)
+void print_str(pstream_t *p, const char *s, strprops_t props)
 {
+    const char *s_orig = s;
+    int npad = props.npad;
+
+    if (npad > 0) {
+	npad -= strlen(s_orig);
+	while (npad > 0) {
+	    addchar(p, props.pad);
+	    --npad;
+	}
+    }
+
     while (*s)
 	addchar(p, *s++);
+
+    if (npad < 0) {
+	props.pad = ' '; /* ignore '0' flag with '-' flag */
+	npad += strlen(s_orig);
+	while (npad < 0) {
+	    addchar(p, props.pad);
+	    ++npad;
+	}
+    }
 }
 
 static char digits[16] = "0123456789abcdef";
 
-void print_int(pstream_t *ps, long long n, int base)
+void print_int(pstream_t *ps, long long n, int base, strprops_t props)
 {
     char buf[sizeof(long) * 3 + 2], *p = buf;
     int s = 0, i;
@@ -54,10 +79,11 @@ void print_int(pstream_t *ps, long long n, int base)
 
     *p = 0;
 
-    print_str(ps, buf);
+    print_str(ps, buf, props);
 }
 
-void print_unsigned(pstream_t *ps, unsigned long long n, int base)
+void print_unsigned(pstream_t *ps, unsigned long long n, int base,
+		    strprops_t props)
 {
     char buf[sizeof(long) * 3 + 1], *p = buf;
     int i;
@@ -80,7 +106,23 @@ void print_unsigned(pstream_t *ps, unsigned long long n, int base)
 
     *p = 0;
 
-    print_str(ps, buf);
+    print_str(ps, buf, props);
+}
+
+static int fmtnum(const char **fmt)
+{
+    const char *f = *fmt;
+    int len = 0, num;
+
+    if (*f == '-')
+	++f, ++len;
+
+    while (*f >= '0' && *f <= '9')
+	++f, ++len;
+
+    num = atol(*fmt);
+    *fmt += len;
+    return num;
 }
 
 int vsnprintf(char *buf, int size, const char *fmt, va_list va)
@@ -93,6 +135,9 @@ int vsnprintf(char *buf, int size, const char *fmt, va_list va)
     while (*fmt) {
 	char f = *fmt++;
 	int nlong = 0;
+	strprops_t props;
+	memset(&props, 0, sizeof(props));
+	props.pad = ' ';
 
 	if (f != '%') {
 	    addchar(&s, f);
@@ -110,41 +155,50 @@ int vsnprintf(char *buf, int size, const char *fmt, va_list va)
 	case '\0':
 	    --fmt;
 	    break;
+	case '0':
+	    props.pad = '0';
+	    ++fmt;
+	    /* fall through */
+	case '1'...'9':
+	case '-':
+	    --fmt;
+	    props.npad = fmtnum(&fmt);
+	    goto morefmt;
 	case 'l':
 	    ++nlong;
 	    goto morefmt;
 	case 'd':
 	    switch (nlong) {
 	    case 0:
-		print_int(&s, va_arg(va, int), 10);
+		print_int(&s, va_arg(va, int), 10, props);
 		break;
 	    case 1:
-		print_int(&s, va_arg(va, long), 10);
+		print_int(&s, va_arg(va, long), 10, props);
 		break;
 	    default:
-		print_int(&s, va_arg(va, long long), 10);
+		print_int(&s, va_arg(va, long long), 10, props);
 		break;
 	    }
 	    break;
 	case 'x':
 	    switch (nlong) {
 	    case 0:
-		print_unsigned(&s, va_arg(va, unsigned), 16);
+		print_unsigned(&s, va_arg(va, unsigned), 16, props);
 		break;
 	    case 1:
-		print_unsigned(&s, va_arg(va, unsigned long), 16);
+		print_unsigned(&s, va_arg(va, unsigned long), 16, props);
 		break;
 	    default:
-		print_unsigned(&s, va_arg(va, unsigned long long), 16);
+		print_unsigned(&s, va_arg(va, unsigned long long), 16, props);
 		break;
 	    }
 	    break;
 	case 'p':
-	    print_str(&s, "0x");
-	    print_unsigned(&s, (unsigned long)va_arg(va, void *), 16);
+	    print_str(&s, "0x", props);
+	    print_unsigned(&s, (unsigned long)va_arg(va, void *), 16, props);
 	    break;
 	case 's':
-	    print_str(&s, va_arg(va, const char *));
+	    print_str(&s, va_arg(va, const char *), props);
 	    break;
 	default:
 	    addchar(&s, f);
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 16/17] arm: add useful headers from the linux kernel
  2014-01-21 16:21 [PATCH 00/17] kvm-unit-tests/arm: initial drop Andrew Jones
                   ` (13 preceding siblings ...)
  2014-01-21 16:22 ` [PATCH 15/17] printf: support field padding Andrew Jones
@ 2014-01-21 16:22 ` Andrew Jones
  2014-02-02  2:29   ` Christoffer Dall
  2014-01-21 16:22 ` [PATCH 17/17] arm: vectors support Andrew Jones
                   ` (3 subsequent siblings)
  18 siblings, 1 reply; 47+ messages in thread
From: Andrew Jones @ 2014-01-21 16:22 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: christoffer.dall

We're going to need PSR bit defines and pt_regs. We'll also need
pt_regs offsets in assembly code. This patch adapts the linux
kernel's ptrace.h and asm-offsets to this framework. Even though
lib/arm/asm-offsets.h is a generated file, we still commit it,
as it's unlikely to change. Also adapt cp15.h from the kernel,
since we'll need bit defines from there too.

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 config/config-arm.mak     |  20 ++++++++--
 lib/arm/asm-offsets.h     |  27 +++++++++++++
 lib/arm/cp15.h            |  36 +++++++++++++++++
 lib/arm/ptrace.h          | 100 ++++++++++++++++++++++++++++++++++++++++++++++
 scripts/arm/asm-offsets.c |  40 +++++++++++++++++++
 5 files changed, 219 insertions(+), 4 deletions(-)
 create mode 100644 lib/arm/asm-offsets.h
 create mode 100644 lib/arm/cp15.h
 create mode 100644 lib/arm/ptrace.h
 create mode 100644 scripts/arm/asm-offsets.c

diff --git a/config/config-arm.mak b/config/config-arm.mak
index 3480003f0ac13..a863b3e3511c9 100644
--- a/config/config-arm.mak
+++ b/config/config-arm.mak
@@ -32,10 +32,9 @@ 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)
+	PROCESSOR = cortex-a15
 endif
+CFLAGS += -mcpu=$(PROCESSOR)
 
 libgcc := $(shell $(CC) -m$(ARCH) --print-libgcc-file-name)
 start_addr := $(shell printf "%x\n" $$(( $(phys_base) + $(kernel_offset) )))
@@ -62,6 +61,19 @@ $(TEST_DIR)/%.o: CFLAGS += -std=gnu99 -ffreestanding $(includedirs)
 
 $(TEST_DIR)/selftest.elf: $(cstart.o) $(TEST_DIR)/selftest.o
 
-arch_clean: libfdt_clean
+arch_clean: libfdt_clean scripts_clean
 	$(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat $(TEST_DIR)/*.elf \
 	$(libeabi) $(eabiobjs) $(TEST_DIR)/.*.d lib/arm/.*.d
+
+.PHONY: scripts_clean asm-offsets
+
+scripts_clean:
+	$(RM) scripts/arm/.*.d scripts/arm/*.o \
+	scripts/arm/*.flat scripts/arm/*.elf
+
+asm-offsets: scripts/arm/asm-offsets.flat
+	$(QEMU) -device virtio-testdev -display none -serial stdio \
+		-M virt -cpu $(PROCESSOR) \
+		-kernel $^ > lib/arm/asm-offsets.h || true
+scripts/arm/asm-offsets.elf: $(cstart.o) scripts/arm/asm-offsets.o
+scripts/arm/%.o: CFLAGS += -std=gnu99 -ffreestanding $(includedirs)
diff --git a/lib/arm/asm-offsets.h b/lib/arm/asm-offsets.h
new file mode 100644
index 0000000000000..b43be20ef8377
--- /dev/null
+++ b/lib/arm/asm-offsets.h
@@ -0,0 +1,27 @@
+#ifndef _ARM_ASM_OFFSETS_H_
+#define _ARM_ASM_OFFSETS_H_
+/*
+ * Generated file. Regenerate with 'make asm-offsets'
+ */
+
+#define S_R0	0x0
+#define S_R1	0x4
+#define S_R2	0x8
+#define S_R3	0xc
+#define S_R4	0x10
+#define S_R5	0x14
+#define S_R6	0x18
+#define S_R7	0x1c
+#define S_R8	0x20
+#define S_R9	0x24
+#define S_R10	0x28
+#define S_FP	0x2c
+#define S_IP	0x30
+#define S_SP	0x34
+#define S_LR	0x38
+#define S_PC	0x3c
+#define S_PSR	0x40
+#define S_OLD_R0	0x44
+#define S_FRAME_SIZE	0x48
+
+#endif /* _ARM_ASM_OFFSETS_H_ */
diff --git a/lib/arm/cp15.h b/lib/arm/cp15.h
new file mode 100644
index 0000000000000..6a8a29aadb008
--- /dev/null
+++ b/lib/arm/cp15.h
@@ -0,0 +1,36 @@
+#ifndef _ARM_CP15_H_
+#define _ARM_CP15_H_
+/*
+ * From Linux kernel arch/arm/include/asm/cp15.h
+ *
+ * CR1 bits (CP#15 CR1)
+ */
+#define CR_M	(1 << 0)	/* MMU enable				*/
+#define CR_A	(1 << 1)	/* Alignment abort enable		*/
+#define CR_C	(1 << 2)	/* Dcache enable			*/
+#define CR_W	(1 << 3)	/* Write buffer enable			*/
+#define CR_P	(1 << 4)	/* 32-bit exception handler		*/
+#define CR_D	(1 << 5)	/* 32-bit data address range		*/
+#define CR_L	(1 << 6)	/* Implementation defined		*/
+#define CR_B	(1 << 7)	/* Big endian				*/
+#define CR_S	(1 << 8)	/* System MMU protection		*/
+#define CR_R	(1 << 9)	/* ROM MMU protection			*/
+#define CR_F	(1 << 10)	/* Implementation defined		*/
+#define CR_Z	(1 << 11)	/* Implementation defined		*/
+#define CR_I	(1 << 12)	/* Icache enable			*/
+#define CR_V	(1 << 13)	/* Vectors relocated to 0xffff0000	*/
+#define CR_RR	(1 << 14)	/* Round Robin cache replacement	*/
+#define CR_L4	(1 << 15)	/* LDR pc can set T bit			*/
+#define CR_DT	(1 << 16)
+#define CR_HA	(1 << 17)	/* Hardware management of Access Flag	*/
+#define CR_IT	(1 << 18)
+#define CR_ST	(1 << 19)
+#define CR_FI	(1 << 21)	/* Fast interrupt (lower latency mode)	*/
+#define CR_U	(1 << 22)	/* Unaligned access operation		*/
+#define CR_XP	(1 << 23)	/* Extended page tables			*/
+#define CR_VE	(1 << 24)	/* Vectored interrupts			*/
+#define CR_EE	(1 << 25)	/* Exception (Big) Endian		*/
+#define CR_TRE	(1 << 28)	/* TEX remap enable			*/
+#define CR_AFE	(1 << 29)	/* Access flag enable			*/
+#define CR_TE	(1 << 30)	/* Thumb exception enable		*/
+#endif
diff --git a/lib/arm/ptrace.h b/lib/arm/ptrace.h
new file mode 100644
index 0000000000000..3c8781508a72e
--- /dev/null
+++ b/lib/arm/ptrace.h
@@ -0,0 +1,100 @@
+#ifndef _ARM_PTRACE_H_
+#define _ARM_PTRACE_H_
+/*
+ * Adapted from Linux kernel headers
+ *   arch/arm/include/asm/ptrace.h
+ *   arch/arm/include/uapi/asm/ptrace.h
+ */
+
+/*
+ * PSR bits
+ */
+#define USR_MODE	0x00000010
+#define SVC_MODE	0x00000013
+#define FIQ_MODE	0x00000011
+#define IRQ_MODE	0x00000012
+#define ABT_MODE	0x00000017
+#define HYP_MODE	0x0000001a
+#define UND_MODE	0x0000001b
+#define SYSTEM_MODE	0x0000001f
+#define MODE32_BIT	0x00000010
+#define MODE_MASK	0x0000001f
+
+#define PSR_T_BIT	0x00000020	/* >= V4T, but not V7M */
+#define PSR_F_BIT	0x00000040	/* >= V4, but not V7M */
+#define PSR_I_BIT	0x00000080	/* >= V4, but not V7M */
+#define PSR_A_BIT	0x00000100	/* >= V6, but not V7M */
+#define PSR_E_BIT	0x00000200	/* >= V6, but not V7M */
+#define PSR_J_BIT	0x01000000	/* >= V5J, but not V7M */
+#define PSR_Q_BIT	0x08000000	/* >= V5E, including V7M */
+#define PSR_V_BIT	0x10000000
+#define PSR_C_BIT	0x20000000
+#define PSR_Z_BIT	0x40000000
+#define PSR_N_BIT	0x80000000
+
+/*
+ * Groups of PSR bits
+ */
+#define PSR_f		0xff000000	/* Flags                */
+#define PSR_s		0x00ff0000	/* Status               */
+#define PSR_x		0x0000ff00	/* Extension            */
+#define PSR_c		0x000000ff	/* Control              */
+
+/*
+ * ARMv7 groups of PSR bits
+ */
+#define APSR_MASK	0xf80f0000	/* N, Z, C, V, Q and GE flags */
+#define PSR_ISET_MASK	0x01000010	/* ISA state (J, T) mask */
+#define PSR_IT_MASK	0x0600fc00	/* If-Then execution state mask */
+#define PSR_ENDIAN_MASK	0x00000200	/* Endianness state mask */
+
+#ifndef __ASSEMBLY__
+#include "libcflat.h"
+
+struct pt_regs {
+	unsigned long uregs[18];
+};
+
+#define ARM_cpsr	uregs[16]
+#define ARM_pc		uregs[15]
+#define ARM_lr		uregs[14]
+#define ARM_sp		uregs[13]
+#define ARM_ip		uregs[12]
+#define ARM_fp		uregs[11]
+#define ARM_r10		uregs[10]
+#define ARM_r9		uregs[9]
+#define ARM_r8		uregs[8]
+#define ARM_r7		uregs[7]
+#define ARM_r6		uregs[6]
+#define ARM_r5		uregs[5]
+#define ARM_r4		uregs[4]
+#define ARM_r3		uregs[3]
+#define ARM_r2		uregs[2]
+#define ARM_r1		uregs[1]
+#define ARM_r0		uregs[0]
+#define ARM_ORIG_r0	uregs[17]
+
+#define user_mode(regs) \
+	(((regs)->ARM_cpsr & 0xf) == 0)
+
+#define processor_mode(regs) \
+	((regs)->ARM_cpsr & MODE_MASK)
+
+#define interrupts_enabled(regs) \
+	(!((regs)->ARM_cpsr & PSR_I_BIT))
+
+#define fast_interrupts_enabled(regs) \
+	(!((regs)->ARM_cpsr & PSR_F_BIT))
+
+#define MAX_REG_OFFSET (offsetof(struct pt_regs, ARM_ORIG_r0))
+
+static inline unsigned long regs_get_register(struct pt_regs *regs,
+					      unsigned int offset)
+{
+	if (offset > MAX_REG_OFFSET)
+		return 0;
+	return *(unsigned long *)((unsigned long)regs + offset);
+}
+
+#endif /* __ASSEMBLY__ */
+#endif /* _ARM_PTRACE_H_ */
diff --git a/scripts/arm/asm-offsets.c b/scripts/arm/asm-offsets.c
new file mode 100644
index 0000000000000..03b22da907d58
--- /dev/null
+++ b/scripts/arm/asm-offsets.c
@@ -0,0 +1,40 @@
+/*
+ * Adapted from arch/arm/kernel/asm-offsets.c
+ */
+#include "libcflat.h"
+#include "arm/ptrace.h"
+
+#define P(sym, val) \
+	printf("#define " #sym "\t0x%x\n", val)
+
+int main(void)
+{
+	printf("#ifndef _ARM_ASM_OFFSETS_H_\n");
+	printf("#define _ARM_ASM_OFFSETS_H_\n");
+	printf("/*\n");
+	printf(" * Generated file. Regenerate with 'make asm-offsets'\n");
+	printf(" */\n");
+	printf("\n");
+	P(S_R0, offsetof(struct pt_regs, ARM_r0));
+	P(S_R1, offsetof(struct pt_regs, ARM_r1));
+	P(S_R2, offsetof(struct pt_regs, ARM_r2));
+	P(S_R3, offsetof(struct pt_regs, ARM_r3));
+	P(S_R4, offsetof(struct pt_regs, ARM_r4));
+	P(S_R5, offsetof(struct pt_regs, ARM_r5));
+	P(S_R6, offsetof(struct pt_regs, ARM_r6));
+	P(S_R7, offsetof(struct pt_regs, ARM_r7));
+	P(S_R8, offsetof(struct pt_regs, ARM_r8));
+	P(S_R9, offsetof(struct pt_regs, ARM_r9));
+	P(S_R10, offsetof(struct pt_regs, ARM_r10));
+	P(S_FP, offsetof(struct pt_regs, ARM_fp));
+	P(S_IP, offsetof(struct pt_regs, ARM_ip));
+	P(S_SP, offsetof(struct pt_regs, ARM_sp));
+	P(S_LR, offsetof(struct pt_regs, ARM_lr));
+	P(S_PC, offsetof(struct pt_regs, ARM_pc));
+	P(S_PSR, offsetof(struct pt_regs, ARM_cpsr));
+	P(S_OLD_R0, offsetof(struct pt_regs, ARM_ORIG_r0));
+	P(S_FRAME_SIZE, sizeof(struct pt_regs));
+	printf("\n");
+	printf("#endif /* _ARM_ASM_OFFSETS_H_ */\n");
+	return 0;
+}
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 17/17] arm: vectors support
  2014-01-21 16:21 [PATCH 00/17] kvm-unit-tests/arm: initial drop Andrew Jones
                   ` (14 preceding siblings ...)
  2014-01-21 16:22 ` [PATCH 16/17] arm: add useful headers from the linux kernel Andrew Jones
@ 2014-01-21 16:22 ` Andrew Jones
  2014-02-02  2:29   ` Christoffer Dall
       [not found] ` <CABWnSnPMc_CrH8N28TScBVvQmCk+XD-bVWvdmJAxxVczHsVx_g@mail.gmail.com>
                   ` (2 subsequent siblings)
  18 siblings, 1 reply; 47+ messages in thread
From: Andrew Jones @ 2014-01-21 16:22 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: christoffer.dall

Add support for tests to use exception handlers.

v2 -> v3:
- squashed in 'arm: Simplify exceptions_init in cstart.S' from
  Christoffer Dall
- suggested function name changes and comment additions [Christoffer Dall]
- fix a bug with stack restore from usr mode exceptions that Christoffer
  pointed out. Add a get_sp() accessor too.

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 arm/cstart.S          | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++
 arm/flat.lds          |   7 ++-
 arm/selftest.c        | 119 +++++++++++++++++++++++++++++++++++
 arm/unittests.cfg     |  20 +++++-
 config/config-arm.mak |   1 +
 lib/arm/processor.c   | 103 +++++++++++++++++++++++++++++++
 lib/arm/processor.h   |  35 +++++++++++
 lib/libcflat.h        |   2 +
 8 files changed, 453 insertions(+), 2 deletions(-)
 create mode 100644 lib/arm/processor.c
 create mode 100644 lib/arm/processor.h

diff --git a/arm/cstart.S b/arm/cstart.S
index 4de04b62c28c2..74674fd41c1b3 100644
--- a/arm/cstart.S
+++ b/arm/cstart.S
@@ -1,3 +1,7 @@
+#define __ASSEMBLY__
+#include "arm/asm-offsets.h"
+#include "arm/ptrace.h"
+#include "arm/cp15.h"
 
 .arm
 
@@ -10,6 +14,13 @@ start:
 	 * See the kernel doc Documentation/arm/Booting
 	 */
 	ldr	sp, =stacktop
+	push	{r0-r3}
+
+	/* set up vector table and mode stacks */
+	bl	exceptions_init
+
+	/* complete setup */
+	pop	{r0-r3}
 	bl	setup
 
 	/* start the test */
@@ -20,9 +31,166 @@ start:
 	bl	exit
 	b	halt
 
+.macro set_mode_stack mode, stack
+	add	\stack, #S_FRAME_SIZE
+	msr	cpsr_c, #(\mode | PSR_I_BIT | PSR_F_BIT)
+	mov	sp, \stack
+.endm
+
+exceptions_init:
+	mrc	p15, 0, r2, c1, c0, 0	@ read SCTLR
+	bic	r2, #CR_V		@ SCTLR.V := 0
+	mcr	p15, 0, r2, c1, c0, 0	@ write SCTLR
+	ldr	r2, =vector_table
+	mcr	p15, 0, r2, c12, c0, 0	@ write VBAR
+
+	mrs	r2, cpsr
+	ldr	r1, =exception_stacks
+		/* first frame for svc mode */
+	set_mode_stack	UND_MODE, r1
+	set_mode_stack	ABT_MODE, r1
+	set_mode_stack	IRQ_MODE, r1
+	set_mode_stack	FIQ_MODE, r1
+	msr	cpsr_cxsf, r2	@ back to svc mode
+	mov	pc, lr
+
 .text
 
 .globl halt
 halt:
 1:	wfi
 	b	1b
+
+/*
+ * Vector stubs.
+ * Simplified version of the Linux kernel implementation
+ *   arch/arm/kernel/entry-armv.S
+ *
+ * Each mode has an S_FRAME_SIZE sized stack initialized
+ * in exceptions_init
+ */
+.macro vector_stub, name, vec, mode, correction=0
+.align 5
+vector_\name:
+.if \correction
+	sub	lr, lr, #\correction
+.endif
+	/*
+	 * Save r0, r1, lr_<exception> (parent PC)
+	 * and spsr_<exception> (parent CPSR)
+	 */
+	str	r0, [sp, #S_R0]
+	str	r1, [sp, #S_R1]
+	str	lr, [sp, #S_PC]
+	mrs	r0, spsr
+	str	r0, [sp, #S_PSR]
+
+	/* Prepare for SVC32 mode. */
+	mrs	r0, cpsr
+	bic	r0, #MODE_MASK
+	orr	r0, #SVC_MODE
+	msr	spsr_cxsf, r0
+
+	/* Branch to handler in SVC mode */
+	mov	r0, #\vec
+	mov	r1, sp
+	ldr	lr, =vector_common
+	movs	pc, lr
+.endm
+
+vector_stub 	rst,	0, UND_MODE
+vector_stub	und,	1, UND_MODE
+vector_stub	pabt,	3, ABT_MODE, 4
+vector_stub	dabt,	4, ABT_MODE, 8
+vector_stub	irq,	6, IRQ_MODE, 4
+vector_stub	fiq,	7, FIQ_MODE, 4
+
+.align 5
+vector_svc:
+	/*
+	 * Save r0, r1, lr_<exception> (parent PC)
+	 * and spsr_<exception> (parent CPSR)
+	 */
+	push	{ r1 }
+	ldr	r1, =exception_stacks
+	str	r0, [r1, #S_R0]
+	pop	{ r0 }
+	str	r0, [r1, #S_R1]
+	str	lr, [r1, #S_PC]
+	mrs	r0, spsr
+	str	r0, [r1, #S_PSR]
+
+	/*
+	 * Branch to handler, still in SVC mode.
+	 * r0 := 2 is the svc vector number.
+	 */
+	mov	r0, #2
+	ldr	lr, =vector_common
+	mov	pc, lr
+
+vector_common:
+	/* make room for pt_regs */
+	sub	sp, #S_FRAME_SIZE
+	tst	sp, #4			@ check stack alignment
+	subne	sp, #4
+
+	/* store registers r0-r12 */
+	stmia	sp, { r0-r12 }		@ stored wrong r0 and r1, fix later
+
+	/* get registers saved in the stub */
+	ldr	r2, [r1, #S_R0]		@ r0
+	ldr	r3, [r1, #S_R1]		@ r1
+	ldr	r4, [r1, #S_PC] 	@ lr_<exception> (parent PC)
+	ldr	r5, [r1, #S_PSR]	@ spsr_<exception> (parent CPSR)
+
+	/* fix r0 and r1 */
+	str	r2, [sp, #S_R0]
+	str	r3, [sp, #S_R1]
+
+	/* store sp_svc, if we were in usr mode we'll fix this later */
+	add	r6, sp, #S_FRAME_SIZE
+	addne	r6, #4			@ stack wasn't aligned
+	str	r6, [sp, #S_SP]
+
+	str	lr, [sp, #S_LR]		@ store lr_svc, fix later for usr mode
+	str	r4, [sp, #S_PC]		@ store lr_<exception>
+	str	r5, [sp, #S_PSR]	@ store spsr_<exception>
+
+	/* set ORIG_r0 */
+	mov	r2, #-1
+	str	r2, [sp, #S_OLD_R0]
+
+	/* if we were in usr mode then we need sp_usr and lr_usr instead */
+	and	r1, r5, #MODE_MASK
+	cmp	r1, #USR_MODE
+	bne	1f
+	add	r1, sp, #S_SP
+	stmia	r1, { sp,lr }^
+
+	/* Call the handler. r0 is the vector number, r1 := pt_regs */
+1:	mov	r1, sp
+	bl	do_handle_exception
+
+	/* make sure we restore sp_svc and lr_svc on mode change */
+	str	r6, [sp, #S_SP]
+	str	lr, [sp, #S_LR]
+
+	/* return from exception */
+	msr	spsr_cxsf, r5
+	ldmia	sp, { r0-pc }^
+
+.align 5
+vector_addrexcptn:
+	b	vector_addrexcptn
+
+.section .text.ex
+.align 5
+vector_table:
+	b	vector_rst
+	b	vector_und
+	b	vector_svc
+	b	vector_pabt
+	b	vector_dabt
+	b	vector_addrexcptn	@ should never happen
+	b	vector_irq
+	b	vector_fiq
diff --git a/arm/flat.lds b/arm/flat.lds
index 3e5d72e24989b..ee9fc0ab79abc 100644
--- a/arm/flat.lds
+++ b/arm/flat.lds
@@ -3,7 +3,12 @@ SECTIONS
 {
     .text : { *(.init) *(.text) *(.text.*) }
     . = ALIGN(4K);
-    .data : { *(.data) }
+    .data : {
+        exception_stacks = .;
+        . += 4K;
+        exception_stacks_end = .;
+        *(.data)
+    }
     . = ALIGN(16);
     .rodata : { *(.rodata) }
     . = ALIGN(16);
diff --git a/arm/selftest.c b/arm/selftest.c
index 3d47a16cbcfad..96ebfe3454e63 100644
--- a/arm/selftest.c
+++ b/arm/selftest.c
@@ -1,9 +1,119 @@
 #include "libcflat.h"
 #include "arm/sysinfo.h"
+#include "arm/ptrace.h"
+#include "arm/processor.h"
+#include "arm/asm-offsets.h"
 
 #define PASS 0
 #define FAIL 1
 
+static struct pt_regs expected_regs;
+/*
+ * Capture the current register state and execute an instruction
+ * that causes an exception. The test handler will check that its
+ * capture of the current register state matches the capture done
+ * here.
+ *
+ * NOTE: update clobber list if passed insns needs more than r0,r1
+ */
+#define test_exception(pre_insns, excptn_insn, post_insns)	\
+	asm volatile(						\
+		pre_insns "\n"					\
+		"mov	r0, %0\n"				\
+		"stmia	r0, { r0-lr }\n"			\
+		"mrs	r1, cpsr\n"				\
+		"str	r1, [r0, #" __stringify(S_PSR) "]\n"	\
+		"mov	r1, #-1\n"				\
+		"str	r1, [r0, #" __stringify(S_OLD_R0) "]\n"	\
+		"add	r1, pc, #8\n"				\
+		"str	r1, [r0, #" __stringify(S_R1) "]\n"	\
+		"str	r1, [r0, #" __stringify(S_PC) "]\n"	\
+		excptn_insn "\n"				\
+		post_insns "\n"					\
+	:: "r" (&expected_regs) : "r0", "r1")
+
+static bool check_regs(struct pt_regs *regs)
+{
+	unsigned i;
+
+	/* exception handlers should always run in svc mode */
+	if (current_mode() != SVC_MODE)
+		return false;
+
+	for (i = 0; i < ARRAY_SIZE(regs->uregs); ++i) {
+		if (regs->uregs[i] != expected_regs.uregs[i])
+			return false;
+	}
+
+	return true;
+}
+
+static bool und_works;
+static void und_handler(struct pt_regs *regs)
+{
+	und_works = check_regs(regs);
+}
+
+static bool check_und(void)
+{
+	install_exception_handler(EXCPTN_UND, und_handler);
+
+	/* issue an instruction to a coprocessor we don't have */
+	test_exception("", "mcr p2, 0, r0, c0, c0", "");
+
+	install_exception_handler(EXCPTN_UND, NULL);
+
+	return und_works;
+}
+
+static bool svc_works;
+static void svc_handler(struct pt_regs *regs)
+{
+	u32 svc = *(u32 *)(regs->ARM_pc - 4) & 0xffffff;
+
+	if (processor_mode(regs) == SVC_MODE) {
+		/*
+		 * When issuing an svc from supervisor mode lr_svc will
+		 * get corrupted. So before issuing the svc, callers must
+		 * always push it on the stack. We pushed it to offset 4.
+		 */
+		regs->ARM_lr = *(unsigned long *)(regs->ARM_sp + 4);
+	}
+
+	svc_works = check_regs(regs) && svc == 123;
+}
+
+static bool check_svc(void)
+{
+	install_exception_handler(EXCPTN_SVC, svc_handler);
+
+	if (current_mode() == SVC_MODE) {
+		/*
+		 * An svc from supervisor mode will corrupt lr_svc and
+		 * spsr_svc. We need to save/restore them separately.
+		 */
+		test_exception(
+			"mrs	r0, spsr\n"
+			"push	{ r0,lr }\n",
+			"svc	#123\n",
+			"pop	{ r0,lr }\n"
+			"msr	spsr_cxsf, r0\n"
+		);
+	} else {
+		test_exception("", "svc #123", "");
+	}
+
+	install_exception_handler(EXCPTN_SVC, NULL);
+
+	return svc_works;
+}
+
+static void check_vectors(void)
+{
+	int ret = check_und() && check_svc() ? PASS : FAIL;
+	exit(ret);
+}
+
 static void assert_enough_args(int nargs, int needed)
 {
 	if (nargs < needed) {
@@ -24,6 +134,15 @@ int main(int argc, char **argv)
 
 		if (mem_size/1024/1024 == (size_t)atol(argv[1]))
 			ret = PASS;
+
+	} else if (strcmp(argv[0], "vectors") == 0) {
+
+		check_vectors(); /* doesn't return */
+
+	} else if (strcmp(argv[0], "vectors_usr") == 0) {
+
+		start_usr(check_vectors); /* doesn't return */
+
 	}
 
 	return ret;
diff --git a/arm/unittests.cfg b/arm/unittests.cfg
index aff684892e90b..75e2a2e3d25bc 100644
--- a/arm/unittests.cfg
+++ b/arm/unittests.cfg
@@ -6,6 +6,24 @@
 # 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]
+#
+# The selftest group tests the initial booting of a guest, as well as
+# the test framework itself.
+#
+# Test bootinfo reading; configured mem-size should equal expected mem-size
+[selftest_mem]
 file = selftest.flat
 extra_params = -m 256 -append 'mem 256'
+groups = selftest
+
+# Test vector setup and exception handling (svc mode).
+[selftest_vectors]
+file = selftest.flat
+extra_params = -append 'vectors'
+groups = selftest
+
+# Test vector setup and exception handling (usr mode).
+[selftest_vectors_usr]
+file = selftest.flat
+extra_params = -append 'vectors_usr'
+groups = selftest
diff --git a/config/config-arm.mak b/config/config-arm.mak
index a863b3e3511c9..99349bf8b0c6b 100644
--- a/config/config-arm.mak
+++ b/config/config-arm.mak
@@ -16,6 +16,7 @@ cflatobjs += \
 	lib/virtio.o \
 	lib/virtio-testdev.o \
 	lib/arm/io.o \
+	lib/arm/processor.o \
 	lib/arm/setup.o
 
 libeabi := lib/arm/libeabi.a
diff --git a/lib/arm/processor.c b/lib/arm/processor.c
new file mode 100644
index 0000000000000..1fededee6977f
--- /dev/null
+++ b/lib/arm/processor.c
@@ -0,0 +1,103 @@
+#include "libcflat.h"
+#include "arm/processor.h"
+#include "arm/sysinfo.h"
+#include "arm/ptrace.h"
+#include "heap.h"
+
+static const char *processor_modes[] = {
+	"USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" ,
+	"UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
+	"UK8_26" , "UK9_26" , "UK10_26", "UK11_26",
+	"UK12_26", "UK13_26", "UK14_26", "UK15_26",
+	"USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" ,
+	"UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" ,
+	"UK8_32" , "UK9_32" , "UK10_32", "UND_32" ,
+	"UK12_32", "UK13_32", "UK14_32", "SYS_32"
+};
+
+static char *vector_names[] = {
+	"rst", "und", "svc", "pabt", "dabt", "addrexcptn", "irq", "fiq"
+};
+
+void show_regs(struct pt_regs *regs)
+{
+	unsigned long flags;
+	char buf[64];
+
+	printf("pc : [<%08lx>]    lr : [<%08lx>]    psr: %08lx\n"
+	       "sp : %08lx  ip : %08lx  fp : %08lx\n",
+		regs->ARM_pc, regs->ARM_lr, regs->ARM_cpsr,
+		regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
+	printf("r10: %08lx  r9 : %08lx  r8 : %08lx\n",
+		regs->ARM_r10, regs->ARM_r9, regs->ARM_r8);
+	printf("r7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\n",
+		regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4);
+	printf("r3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\n",
+		regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0);
+
+	flags = regs->ARM_cpsr;
+	buf[0] = flags & PSR_N_BIT ? 'N' : 'n';
+	buf[1] = flags & PSR_Z_BIT ? 'Z' : 'z';
+	buf[2] = flags & PSR_C_BIT ? 'C' : 'c';
+	buf[3] = flags & PSR_V_BIT ? 'V' : 'v';
+	buf[4] = '\0';
+
+	printf("Flags: %s  IRQs o%s  FIQs o%s  Mode %s\n",
+		buf, interrupts_enabled(regs) ? "n" : "ff",
+		fast_interrupts_enabled(regs) ? "n" : "ff",
+		processor_modes[processor_mode(regs)]);
+
+	if (!user_mode(regs)) {
+		unsigned int ctrl, transbase, dac;
+		asm volatile(
+			"mrc p15, 0, %0, c1, c0\n"
+			"mrc p15, 0, %1, c2, c0\n"
+			"mrc p15, 0, %2, c3, c0\n"
+		: "=r" (ctrl), "=r" (transbase), "=r" (dac));
+		printf("Control: %08x  Table: %08x  DAC: %08x\n",
+			ctrl, transbase, dac);
+	}
+}
+
+void *get_sp(void)
+{
+	register unsigned long sp asm("sp");
+	return (void *)sp;
+}
+
+static exception_fn exception_handlers[EXCPTN_MAX];
+
+void install_exception_handler(enum vector v, exception_fn fn)
+{
+	if (v < EXCPTN_MAX)
+		exception_handlers[v] = fn;
+}
+
+void do_handle_exception(enum vector v, struct pt_regs *regs)
+{
+	if (v < EXCPTN_MAX && exception_handlers[v]) {
+		exception_handlers[v](regs);
+		return;
+	}
+
+	if (v < EXCPTN_MAX)
+		printf("Unhandled exception %d (%s)\n", v, vector_names[v]);
+	else
+		printf("%s called with vector=%d\n", __func__, v);
+	printf("Exception frame registers:\n");
+	show_regs(regs);
+	exit(EINTR);
+}
+
+void start_usr(void (*func)(void))
+{
+	void *sp_usr = alloc_page() + PAGE_SIZE;
+	asm volatile(
+		"mrs	r0, cpsr\n"
+		"bic	r0, #" __stringify(MODE_MASK) "\n"
+		"orr	r0, #" __stringify(USR_MODE) "\n"
+		"msr	cpsr_c, r0\n"
+		"mov	sp, %0\n"
+		"mov	pc, %1\n"
+	:: "r" (sp_usr), "r" (func) : "r0");
+}
diff --git a/lib/arm/processor.h b/lib/arm/processor.h
new file mode 100644
index 0000000000000..12c1902de97fd
--- /dev/null
+++ b/lib/arm/processor.h
@@ -0,0 +1,35 @@
+#ifndef _ARM_PROCESSOR_H_
+#define _ARM_PROCESSOR_H_
+#include "libcflat.h"
+#include "ptrace.h"
+
+enum vector {
+	EXCPTN_RST,
+	EXCPTN_UND,
+	EXCPTN_SVC,
+	EXCPTN_PABT,
+	EXCPTN_DABT,
+	EXCPTN_ADDREXCPTN,
+	EXCPTN_IRQ,
+	EXCPTN_FIQ,
+	EXCPTN_MAX,
+};
+
+typedef void (*exception_fn)(struct pt_regs *);
+extern void install_exception_handler(enum vector v, exception_fn fn);
+
+extern void show_regs(struct pt_regs *regs);
+extern void *get_sp(void);
+
+extern void start_usr(void (*func)(void));
+
+static inline unsigned long current_cpsr(void)
+{
+	unsigned long cpsr;
+	asm volatile("mrs %0, cpsr" : "=r" (cpsr));
+	return cpsr;
+}
+
+#define current_mode() (current_cpsr() & MODE_MASK)
+
+#endif
diff --git a/lib/libcflat.h b/lib/libcflat.h
index 84b8783bacfdc..3d47a3331b7fc 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -65,6 +65,8 @@ extern long atol(const char *ptr);
 		(type *)( (char *)__mptr - offsetof(type,member) );})
 
 #define __unused __attribute__((__unused__))
+#define __stringify_1(x...)	#x
+#define __stringify(x...)	__stringify_1(x)
 #define NULL ((void *)0UL)
 #include "errno.h"
 #endif
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: [PATCH 00/17] kvm-unit-tests/arm: initial drop
       [not found] ` <CABWnSnPMc_CrH8N28TScBVvQmCk+XD-bVWvdmJAxxVczHsVx_g@mail.gmail.com>
@ 2014-01-29 15:35   ` Andrew Jones
  0 siblings, 0 replies; 47+ messages in thread
From: Andrew Jones @ 2014-01-29 15:35 UTC (permalink / raw)
  To: María Soler Heredia; +Cc: kvmarm, kvm

On Tue, Jan 28, 2014 at 07:16:11PM +0100, María Soler Heredia wrote:
> Hello Andrew,
> 
> I have been experimenting a little with your tests and I have some comments
> and questions. I have already compiled and run versions v1 and v2, which
> work with kvm disabled, but I cannot run v3 using the same qemu, version
> 1.6.90 with these two sets of patches:
> 
>    - http://lists.nongnu.org/archive/html/qemu-devel/2013-09/msg02142.html(Adds
> 'virt' platform)
>    - http://lists.nongnu.org/archive/html/qemu-devel/2013-10/msg01815.html(Introduces
> virtio-testdev)
> 
> that you indicated on [PATCH 0/9] kvm-unit-tests/arm: initial drop.
> 
> >  Only qemu-system-arm, recent enough to have mach-virt, and the
> > virtio-testdev patch[1],
> > is required.
> >
> > [1] http://lists.nongnu.org/archive/html/qemu-devel/2013-12/msg00690.html
> >
> 
> Then I thought maybe the problem was that my qemu was too old, so I
> upgraded to version 1.7.50, the newest available version at git://
> git.qemu-project.org/qemu.git and applied patch[1] but it seems to be
> incompatible with that version of qemu, since it doesn't compile:
> -------------------------------------------------------------------------------------------------------------------------------------------
> hw/virtio/virtio-testdev.c: In function 'virtio_testdev_class_init':
> hw/virtio/virtio-testdev.c:136:8: error: 'VirtioDeviceClass' has no member
> named 'init'
> -------------------------------------------------------------------------------------------------------------------------------------------

The latest git://git.qemu.org/qemu.git with the v3 of virtio-testdev that
I just sent[*] works for me. virtio-testdev needed to be converted from init
to realize.

[*] http://lists.nongnu.org/archive/html/qemu-devel/2014-01/msg04041.html

> 
> I modified hw/virtio/virtio-testdev.c to stop this error from happening,
> but it won't run the already compiled (with qemu 1.6.90) v1 and v2 or make
> a runnable version of either v1, v2 or v3 when recompiling them.
> 
> The error that I get when I run the v3 of the test (with qemu 1.6.90) is as
> follows:
> 
> $ ./run_tests.sh -v
> ./arm-run arm/selftest.flat -smp 1 -m 256 -append 'mem 256'
> qemu: fatal: Trying to execute code outside RAM or ROM at 0x00000000
> 
> R00=fffffff7 R01=00000000 R02=00000000 R03=2ff20112
> R04=00000000 R05=00000000 R06=00000000 R07=00000000
> R08=00000000 R09=00000000 R10=00000000 R11=00000000
> R12=00000000 R13=40017ff8 R14=080117b0 R15=00000000
> PSR=a00001d3 N-C- A svc32
> s00=00000000 s01=00000000 d00=0000000000000000
> ...
> s62=00000000 s63=00000000 d31=0000000000000000
> FPSCR: 00000000
> ./arm-run: line 16:  4839 Aborted                 (core dumped) $command
> "$@"
> FAIL selftest_mem
> ./arm-run arm/selftest.flat -smp 1 -append 'vectors'
> qemu: fatal: Trying to execute code outside RAM or ROM at 0x00000000
> 
> R00=fffffff7 R01=00000000 R02=00000000 R03=2ff20112
> R04=00000000 R05=00000000 R06=00000000 R07=00000000
> R08=00000000 R09=00000000 R10=00000000 R11=00000000
> R12=00000000 R13=40017ff8 R14=080117b0 R15=00000000
> PSR=a00001d3 N-C- A svc32
> s00=00000000 s01=00000000 d00=0000000000000000
> ...
> s62=00000000 s63=00000000 d31=0000000000000000
> FPSCR: 00000000
> ./arm-run: line 16:  4845 Aborted                 (core dumped) $command
> "$@"
> FAIL selftest_vectors
> ./arm-run arm/selftest.flat -smp 1 -append 'vectors_usr'
> qemu: fatal: Trying to execute code outside RAM or ROM at 0x00000000
> 
> R00=fffffff7 R01=00000000 R02=00000000 R03=2ff20112
> R04=00000000 R05=00000000 R06=00000000 R07=00000000
> R08=00000000 R09=00000000 R10=00000000 R11=00000000
> R12=00000000 R13=40017ff8 R14=080117b0 R15=00000000
> PSR=a00001d3 N-C- A svc32
> s00=00000000 s01=00000000 d00=0000000000000000
> ...
> s62=00000000 s63=00000000 d31=0000000000000000
> FPSCR: 00000000
> ./arm-run: line 16:  4851 Aborted                 (core dumped) $command
> "$@"
> FAIL selftest_vectors_usr
> 
> Am I using the wrong qemu? Is there a new dependency that is not mentioned
> and that may cause this problem? Any other ideas on why this could happen?

Are you sure you have the latest mach-virt patches for qemu? v3 of
kvm-unit-tests/arm sets the load address to 0x40000000, which matches the
latest mach-virt.

I can run these tests on my x86_64 machine, without kvm enabled, as well as
on an armv7 machine with kvm enabled. Are you still running on the
FastModel? I never got around to setting one up to see if that works or not.

thanks,
drew

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 00/17] kvm-unit-tests/arm: initial drop
  2014-01-21 16:21 [PATCH 00/17] kvm-unit-tests/arm: initial drop Andrew Jones
                   ` (16 preceding siblings ...)
       [not found] ` <CABWnSnPMc_CrH8N28TScBVvQmCk+XD-bVWvdmJAxxVczHsVx_g@mail.gmail.com>
@ 2014-02-02  2:22 ` Christoffer Dall
  2014-02-03 13:24   ` Andrew Jones
       [not found] ` <1390321323-1855-10-git-send-email-drjones@redhat.com>
  18 siblings, 1 reply; 47+ messages in thread
From: Christoffer Dall @ 2014-02-02  2:22 UTC (permalink / raw)
  To: Andrew Jones; +Cc: kvmarm, kvm

On Tue, Jan 21, 2014 at 05:21:46PM +0100, Andrew Jones wrote:
> This is a v3 of a series that introduces arm to kvm-unit-tests.

Just a meta-comment:

It would be helpful if you include the "v3" in your subjects so it's
easy to go back and track previous review comments.

git format-patch --subject-prefix "PATCH v3"

is your friend here.

-Christoffer

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 05/17] add 'make cscope' support
  2014-01-21 16:21 ` [PATCH 05/17] add 'make cscope' support Andrew Jones
@ 2014-02-02  2:22   ` Christoffer Dall
  2014-02-03 13:25     ` Andrew Jones
  0 siblings, 1 reply; 47+ messages in thread
From: Christoffer Dall @ 2014-02-02  2:22 UTC (permalink / raw)
  To: Andrew Jones; +Cc: kvmarm, kvm

On Tue, Jan 21, 2014 at 05:21:51PM +0100, Andrew Jones wrote:
> Add a Makefile target to quickly generate arch-specific cscope
> for kvm-unit-tests. Assumes a mostly flat directory structure,
> i.e. uses '-maxdepth 1' in the file search.
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> ---
>  Makefile | 9 ++++++++-
>  1 file changed, 8 insertions(+), 1 deletion(-)
> 
> diff --git a/Makefile b/Makefile
> index fa95d66386d49..283655957f39f 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -3,7 +3,7 @@ include config.mak
>  
>  DESTDIR := $(PREFIX)/share/qemu/tests
>  
> -.PHONY: arch_clean clean
> +.PHONY: arch_clean clean cscope
>  
>  #make sure env CFLAGS variable is not used
>  CFLAGS =
> @@ -52,3 +52,10 @@ install:
>  
>  clean: arch_clean
>  	$(RM) lib/.*.d $(libcflat) $(cflatobjs)
> +
> +cscope: common_dirs = lib
> +cscope:
> +	rm -f ./cscope.*
> +	find $(TEST_DIR) lib/$(TEST_DIR) $(common_dirs) -maxdepth 1 \
> +		-name "*.[chsS]" -print | sed 's,^\./,,' > ./cscope.files

shouldn't you use single quotes for the -name pattern to avoid any
substitutions here?

> +	cscope -bk
> -- 
> 1.8.1.4
> 

Otherwise:
Acked-by: Christoffer Dall <christoffer.dall@linaro.org>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 06/17] Add halt() and some error codes
  2014-01-21 16:21 ` [PATCH 06/17] Add halt() and some error codes Andrew Jones
@ 2014-02-02  2:23   ` Christoffer Dall
  0 siblings, 0 replies; 47+ messages in thread
From: Christoffer Dall @ 2014-02-02  2:23 UTC (permalink / raw)
  To: Andrew Jones; +Cc: kvmarm, kvm

On Tue, Jan 21, 2014 at 05:21:52PM +0100, Andrew Jones wrote:
> Define a halt function that can be implemented by the test framework
> for use on error paths before exit() works. Also add some error codes
> that can be passed to halt() in case the serial isn't working either.
> Then, on register inspection of the halted guest we may be able to
> quickly determine the problem without having to find the halt()
> call-site. The error codes may of course also be used with exit().
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> 
Acked-by: Christoffer Dall <christoffer.dall@linaro.org>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 07/17] move x86's simple heap management to common code
  2014-01-21 16:21 ` [PATCH 07/17] move x86's simple heap management to common code Andrew Jones
@ 2014-02-02  2:23   ` Christoffer Dall
  0 siblings, 0 replies; 47+ messages in thread
From: Christoffer Dall @ 2014-02-02  2:23 UTC (permalink / raw)
  To: Andrew Jones; +Cc: kvmarm, kvm

On Tue, Jan 21, 2014 at 05:21:53PM +0100, Andrew Jones wrote:
> v3: fixed Christoffer's nits
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>

Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 08/17] Introduce libio to common code for io read/write
  2014-01-21 16:21 ` [PATCH 08/17] Introduce libio to common code for io read/write Andrew Jones
@ 2014-02-02  2:24   ` Christoffer Dall
  2014-02-03 13:51     ` Andrew Jones
  0 siblings, 1 reply; 47+ messages in thread
From: Christoffer Dall @ 2014-02-02  2:24 UTC (permalink / raw)
  To: Andrew Jones; +Cc: kvmarm, kvm

On Tue, Jan 21, 2014 at 05:21:54PM +0100, Andrew Jones wrote:
> v3:
>  - get rid of CONFIG_64BIT, replace with asserts
>  - get rid of {read,write}_len()
>  - fix bad *64_to_cpu macros

note that putting the changelog after the "---" prevents it from
getting committed, but I'm not sure if there are different
conventions for the unit-tests framework.

> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> ---
>  lib/libio.h | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 173 insertions(+)
>  create mode 100644 lib/libio.h
> 
> diff --git a/lib/libio.h b/lib/libio.h
> new file mode 100644
> index 0000000000000..6adc6a7bbee61
> --- /dev/null
> +++ b/lib/libio.h
> @@ -0,0 +1,173 @@
> +#ifndef _LIBIO_H_
> +#define _LIBIO_H_
> +/*
> + * Adapted from the Linux kernel's include/asm-generic/io.h and
> + * arch/arm/include/asm/io.h
> + */
> +#include "libcflat.h"
> +
> +#ifndef NDEBUG
> +#define LIBIO_ASSERT(expr) do { \
> +	if (!(expr)) printf("%s:%d: assert failed!\n", __FILE__, __LINE__);\
> +} while (0)
> +#else
> +#define LIBIO_ASSERT(expr) do { } while (0)
> +#endif
> +
> +typedef u32 compat_ptr_t;
> +
> +/*
> + * Use compat_ptr() on 64-bit arches when casting 32-bit

arches? architectures? archs?

> + * addresses to pointers in order to avoid compiler warnings.
> + */
> +static inline void *compat_ptr(compat_ptr_t ptr)
> +{
> +	return (void *)(unsigned long)ptr;
> +}
> +
> +static inline compat_ptr_t ptr_to_compat(void *ptr)
> +{
> +	return (u32)(unsigned long)ptr;
> +}
> +
> +#ifndef __raw_readb
> +static inline u8 __raw_readb(const volatile void *addr)
> +{
> +	return *(const volatile u8 *)addr;
> +}
> +#endif
> +
> +#ifndef __raw_readw
> +static inline u16 __raw_readw(const volatile void *addr)
> +{
> +	return *(const volatile u16 *)addr;
> +}
> +#endif
> +
> +#ifndef __raw_readl
> +static inline u32 __raw_readl(const volatile void *addr)
> +{
> +	return *(const volatile u32 *)addr;
> +}
> +#endif
> +
> +#ifndef __raw_readq
> +static inline u64 __raw_readq(const volatile void *addr)
> +{
> +	LIBIO_ASSERT(sizeof(unsigned long) == sizeof(u64));
> +	return *(const volatile u64 *)addr;
> +}
> +#endif
> +
> +#ifndef __raw_writeb
> +static inline void __raw_writeb(u8 b, volatile void *addr)
> +{
> +	*(volatile u8 *)addr = b;
> +}
> +#endif
> +
> +#ifndef __raw_writew
> +static inline void __raw_writew(u16 b, volatile void *addr)
> +{
> +	*(volatile u16 *)addr = b;
> +}
> +#endif
> +
> +#ifndef __raw_writel
> +static inline void __raw_writel(u32 b, volatile void *addr)
> +{
> +	*(volatile u32 *)addr = b;
> +}
> +#endif
> +
> +#ifndef __raw_writeq
> +static inline void __raw_writeq(u64 b, volatile void *addr)
> +{
> +	LIBIO_ASSERT(sizeof(unsigned long) == sizeof(u64));
> +	*(volatile u64 *)addr = b;
> +}
> +#endif
> +
> +#ifndef __bswap16
> +static inline u16 __bswap16(u16 x)
> +{
> +	return ((x >> 8) & 0xff) | ((x & 0xff) << 8);
> +}
> +#endif
> +
> +#ifndef __bswap32
> +static inline u32 __bswap32(u32 x)
> +{
> +	return ((x & 0xff000000) >> 24) | ((x & 0x00ff0000) >>  8) |
> +	       ((x & 0x0000ff00) <<  8) | ((x & 0x000000ff) << 24);
> +}
> +#endif
> +
> +#ifndef __bswap64
> +static inline u64 __bswap64(u64 x)
> +{
> +	return ((x & 0x00000000000000ffULL) << 56) |
> +	       ((x & 0x000000000000ff00ULL) << 40) |
> +	       ((x & 0x0000000000ff0000ULL) << 24) |
> +	       ((x & 0x00000000ff000000ULL) <<  8) |
> +	       ((x & 0x000000ff00000000ULL) >>  8) |
> +	       ((x & 0x0000ff0000000000ULL) >> 24) |
> +	       ((x & 0x00ff000000000000ULL) >> 40) |
> +	       ((x & 0xff00000000000000ULL) >> 56);
> +}
> +#endif
> +
> +#ifndef cpu_is_be
> +#define cpu_is_be 0
> +#endif
> +
> +#define le16_to_cpu(x) \
> +	({ u16 __r = cpu_is_be ? __bswap16(x) : (x); __r; })
> +#define cpu_to_le16 le16_to_cpu
> +
> +#define le32_to_cpu(x) \
> +	({ u32 __r = cpu_is_be ? __bswap32(x) : (x); __r; })
> +#define cpu_to_le32 le32_to_cpu
> +
> +#define le64_to_cpu(x) \
> +	({ u64 __r = cpu_is_be ? __bswap64(x) : (x); __r; })
> +#define cpu_to_le64 le64_to_cpu
> +
> +#define be16_to_cpu(x) \
> +	({ u16 __r = !cpu_is_be ? __bswap16(x) : (x); __r; })
> +#define cpu_to_be16 be16_to_cpu
> +
> +#define be32_to_cpu(x) \
> +	({ u32 __r = !cpu_is_be ? __bswap32(x) : (x); __r; })
> +#define cpu_to_be32 be32_to_cpu
> +
> +#define be64_to_cpu(x) \
> +	({ u64 __r = !cpu_is_be ? __bswap64(x) : (x); __r; })
> +#define cpu_to_be64 be64_to_cpu
> +
> +#ifndef rmb
> +#define rmb() do { } while (0)
> +#endif
> +#ifndef wmb
> +#define wmb() do { } while (0)
> +#endif
> +
> +#define readb(addr) \
> +	({ u8 __r = __raw_readb(addr); rmb(); __r; })
> +#define readw(addr) \
> +	({ u16 __r = le16_to_cpu(__raw_readw(addr)); rmb(); __r; })
> +#define readl(addr) \
> +	({ u32 __r = le32_to_cpu(__raw_readl(addr)); rmb(); __r; })
> +#define readq(addr) \
> +	({ u64 __r = le64_to_cpu(__raw_readq(addr)); rmb(); __r; })
> +
> +#define writeb(b, addr) \
> +	({ wmb(); __raw_writeb(b, addr); })
> +#define writew(b, addr) \
> +	({ wmb(); __raw_writew(cpu_to_le16(b), addr); })
> +#define writel(b, addr) \
> +	({ wmb(); __raw_writel(cpu_to_le32(b), addr); })
> +#define writeq(b, addr) \
> +	({ wmb(); __raw_writeq(cpu_to_le64(b), addr); })
> +
> +#endif

so these definitions always assume that your device is LE, which is
probably true for ARM and x86 for now, but if we ever use this on PPC or
want to test ARM BE with a BE QEMU, will it still work?

(There's some trickery with virtio and endianness that I don't remember
100%, so if we assume this ever only reads and writes to virtio space,
we may be in the clear.)

Otherwise:

Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 09/17] libfdt: Import libfdt source
       [not found] ` <1390321323-1855-10-git-send-email-drjones@redhat.com>
@ 2014-02-02  2:25   ` Christoffer Dall
  0 siblings, 0 replies; 47+ messages in thread
From: Christoffer Dall @ 2014-02-02  2:25 UTC (permalink / raw)
  To: Andrew Jones; +Cc: kvmarm, kvm

On Tue, Jan 21, 2014 at 05:21:55PM +0100, Andrew Jones wrote:
> This adds the applicable libfdt source files (unmodified) and a
> README to explain where the source came from. The README says
> 
>   The code in this directory is originally imported from the libfdt
>   directory of git://git.jdl.com/software/dtc.git - version 1.4.0.
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>

FWIW: Acked-by: Christoffer Dall <christoffer.dall@linaro.org>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 10/17] libfdt: get libfdt to build
  2014-01-21 16:21 ` [PATCH 10/17] libfdt: get libfdt to build Andrew Jones
@ 2014-02-02  2:25   ` Christoffer Dall
  2014-02-03 13:57     ` Andrew Jones
  0 siblings, 1 reply; 47+ messages in thread
From: Christoffer Dall @ 2014-02-02  2:25 UTC (permalink / raw)
  To: Andrew Jones; +Cc: kvmarm, kvm

On Tue, Jan 21, 2014 at 05:21:56PM +0100, Andrew Jones wrote:
> Add string functions needed for libfdt, modify libfdt_env.h
> for this environment, and add a make target.

The endianness changes you're making to CPU_TO_FDTxx are not trivial to
review.  A motivational commit text here would have been immensely
helpful.

> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> ---
>  Makefile                | 23 +++++++++++++++++++++-
>  lib/libcflat.h          |  4 ++++
>  lib/libfdt/libfdt_env.h | 25 ++++++++++++------------
>  lib/string.c            | 51 +++++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 90 insertions(+), 13 deletions(-)
> 
> diff --git a/Makefile b/Makefile
> index 283655957f39f..94c565242c1b7 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -16,6 +16,13 @@ cflatobjs := \
>  	lib/printf.o \
>  	lib/string.o
>  
> +# libfdt paths
> +LIBFDT_objdir = lib/libfdt
> +LIBFDT_srcdir = lib/libfdt
> +LIBFDT_archive = $(LIBFDT_objdir)/libfdt.a
> +LIBFDT_include = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_INCLUDES))
> +LIBFDT_version = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_VERSION))
> +
>  #include architecure specific make rules
>  include config/config-$(ARCH).mak
>  
> @@ -41,6 +48,20 @@ LDFLAGS += -pthread -lrt
>  $(libcflat): $(cflatobjs)
>  	$(AR) rcs $@ $^
>  
> +include $(LIBFDT_srcdir)/Makefile.libfdt
> +
> +.PHONY: libfdt
> +libfdt: $(LIBFDT_archive)
> +
> +$(LIBFDT_archive): CFLAGS += -ffreestanding -I lib -I lib/libfdt -Wno-sign-compare
> +$(LIBFDT_archive): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
> +	$(AR) rcs $@ $^
> +
> +libfdt_clean:
> +	$(RM) $(LIBFDT_archive) \
> +	$(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS)) \
> +	$(LIBFDT_objdir)/.*.d
> +
>  %.o: %.S
>  	$(CC) $(CFLAGS) -c -nostdlib -o $@ $<
>  
> @@ -53,7 +74,7 @@ install:
>  clean: arch_clean
>  	$(RM) lib/.*.d $(libcflat) $(cflatobjs)
>  
> -cscope: common_dirs = lib
> +cscope: common_dirs = lib lib/libfdt
>  cscope:
>  	rm -f ./cscope.*
>  	find $(TEST_DIR) lib/$(TEST_DIR) $(common_dirs) -maxdepth 1 \
> diff --git a/lib/libcflat.h b/lib/libcflat.h
> index a1be635ab4ee9..2cde64a560956 100644
> --- a/lib/libcflat.h
> +++ b/lib/libcflat.h
> @@ -43,6 +43,7 @@ extern void exit(int code);
>  extern unsigned long strlen(const char *buf);
>  extern char *strcat(char *dest, const char *src);
>  extern int strcmp(const char *a, const char *b);
> +extern char *strchr(const char *s, int c);
>  
>  extern int printf(const char *fmt, ...);
>  extern int vsnprintf(char *buf, int size, const char *fmt, va_list va);
> @@ -51,6 +52,9 @@ extern void puts(const char *s);
>  
>  extern void *memset(void *s, int c, size_t n);
>  extern void *memcpy(void *dest, const void *src, size_t n);
> +extern int memcmp(const void *s1, const void *s2, size_t n);
> +extern void *memmove(void *dest, const void *src, size_t n);
> +extern void *memchr(const void *s, int c, size_t n);
>  
>  extern long atol(const char *ptr);
>  #define ARRAY_SIZE(_a)  (sizeof(_a)/sizeof((_a)[0]))
> diff --git a/lib/libfdt/libfdt_env.h b/lib/libfdt/libfdt_env.h
> index 9dea97dfff818..46fcb6c29045f 100644
> --- a/lib/libfdt/libfdt_env.h
> +++ b/lib/libfdt/libfdt_env.h
> @@ -52,9 +52,16 @@
>   *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
>   */
>  
> -#include <stddef.h>
> -#include <stdint.h>
> -#include <string.h>
> +#include "libcflat.h"
> +#include "libio.h"
> +
> +#ifndef HAVE_UINTS
> +typedef u8 uint8_t;
> +typedef u16 uint16_t;
> +typedef u32 uint32_t;
> +typedef u64 uint64_t;
> +typedef unsigned long uintptr_t;
> +#endif
>  
>  #ifdef __CHECKER__
>  #define __force __attribute__((force))
> @@ -68,14 +75,9 @@ typedef uint16_t __bitwise fdt16_t;
>  typedef uint32_t __bitwise fdt32_t;
>  typedef uint64_t __bitwise fdt64_t;
>  
> -#define EXTRACT_BYTE(x, n)	((unsigned long long)((uint8_t *)&x)[n])
> -#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1))
> -#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \
> -			 (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3))
> -#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \
> -			 (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \
> -			 (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \
> -			 (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7))
> +#define CPU_TO_FDT16 cpu_to_be16
> +#define CPU_TO_FDT32 cpu_to_be32
> +#define CPU_TO_FDT64 cpu_to_be64
>  
>  static inline uint16_t fdt16_to_cpu(fdt16_t x)
>  {
> @@ -106,6 +108,5 @@ static inline fdt64_t cpu_to_fdt64(uint64_t x)
>  #undef CPU_TO_FDT64
>  #undef CPU_TO_FDT32
>  #undef CPU_TO_FDT16
> -#undef EXTRACT_BYTE
>  
>  #endif /* _LIBFDT_ENV_H */
> diff --git a/lib/string.c b/lib/string.c
> index 3a9caf720bf2b..234f96f4442f7 100644
> --- a/lib/string.c
> +++ b/lib/string.c
> @@ -31,6 +31,17 @@ int strcmp(const char *a, const char *b)
>      return *a - *b;
>  }
>  
> +char *strchr(const char *s, int c)
> +{
> +    unsigned char chr = (unsigned char)c;

why unsigned?

> +    int n = strlen(s) + 1;

why scan the string twice?  couldn't the whole function be written:

{
char chr = (char)c;
while (*s != '\0' && *s != chr)
	s++;
return (*s != chr) ? NULL : (char *)s;
}

> +
> +    while (n--)
> +	if (*s++ == chr)
> +	    return (char *)(s - 1);
> +    return NULL;
> +}
> +
>  void *memset(void *s, int c, size_t n)
>  {
>      size_t i;
> @@ -54,6 +65,46 @@ void *memcpy(void *dest, const void *src, size_t n)
>      return dest;
>  }
>  
> +int memcmp(const void *s1, const void *s2, size_t n)
> +{
> +    const unsigned char *a = s1, *b = s2;
> +    int ret = 0;
> +
> +    while (n--) {
> +	ret = *a - *b;
> +	if (ret)
> +	    break;
> +	++a, ++b;
> +    }
> +    return ret;
> +}
> +
> +void *memmove(void *dest, const void *src, size_t n)
> +{
> +    const unsigned char *s = src;
> +    unsigned char *d = dest;
> +
> +    if (d <= s) {
> +	while (n--)
> +	    *d++ = *s++;
> +    } else {
> +	d += n, s += n;
> +	while (n--)
> +	    *--d = *--s;
> +    }
> +    return dest;
> +}
> +
> +void *memchr(const void *s, int c, size_t n)
> +{
> +    const unsigned char *str = s, chr = (unsigned char)c;
> +
> +    while (n--)
> +	if (*str++ == chr)
> +	    return (void *)(str - 1);
> +    return NULL;
> +}
> +
>  long atol(const char *ptr)
>  {
>      long acc = 0;
> -- 
> 1.8.1.4
> 

Otherwise:

Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 11/17] add support for device trees
  2014-01-21 16:21 ` [PATCH 11/17] add support for device trees Andrew Jones
@ 2014-02-02  2:27   ` Christoffer Dall
  2014-02-03 15:31     ` Andrew Jones
  0 siblings, 1 reply; 47+ messages in thread
From: Christoffer Dall @ 2014-02-02  2:27 UTC (permalink / raw)
  To: Andrew Jones; +Cc: kvmarm, kvm

On Tue, Jan 21, 2014 at 05:21:57PM +0100, Andrew Jones wrote:
> Add some device tree functions, built on libfdt, to the common
> code in order to facilitate the extraction of boot info and device
> base addresses. These functions are generic and arch-neutral. It's
> expected that more functions will be added as more information
> from the device tree is needed.

You're doing a bit more than that, you're introducing a couple of
concepts such as a bus and reg structures, which are concepts above DT,
which could use a bit of clarification.  In particular this patch is a
bit hard to review on its own, because you cannot see how things are
supposed to be used without looking at subsequent patches...

I'm not a DT expert, but here goes the best I can do...

> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> ---
>  lib/devicetree.c | 257 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  lib/devicetree.h |  95 ++++++++++++++++++++
>  lib/libcflat.h   |   1 +
>  3 files changed, 353 insertions(+)
>  create mode 100644 lib/devicetree.c
>  create mode 100644 lib/devicetree.h
> 
> diff --git a/lib/devicetree.c b/lib/devicetree.c
> new file mode 100644
> index 0000000000000..a9ab7ed367704
> --- /dev/null
> +++ b/lib/devicetree.c
> @@ -0,0 +1,257 @@
> +#include "libcflat.h"
> +#include "libfdt/libfdt.h"
> +#include "devicetree.h"
> +
> +static const void *fdt;
> +
> +const char *dt_strerror(int errval)
> +{
> +	if (errval == -EINVAL)
> +		return "Invalid argument";
> +	return fdt_strerror(errval);
> +}
> +
> +int dt_set(const void *fdt_ptr)
> +{
> +	int ret = fdt_check_header(fdt_ptr);
> +	if (ret == 0)
> +		fdt = fdt_ptr;
> +	return ret;
> +}
> +
> +const void *dt_get(void)
> +{
> +	return fdt;
> +}
> +
> +int dt_get_bootargs_ptr(char **bootargs)
> +{
> +	const struct fdt_property *prop;
> +	int node, err;
> +
> +	node = fdt_path_offset(fdt, "/chosen");
> +	if (node < 0)
> +		return node;
> +
> +	prop = fdt_get_property(fdt, node, "bootargs", &err);
> +	if (prop)
> +		*bootargs = (char *)prop->data;
> +	else if (err != -FDT_ERR_NOTFOUND)
> +		return err;
> +
> +	return 0;
> +}
> +
> +int dt_bus_default_match(const struct dt_bus *bus __unused,
> +			 int nodeoffset __unused)
> +{
> +	/* just select first node found */
> +	return 1;
> +}
> +
> +int dt_bus_default_translate(const struct dt_bus *bus __unused,
> +			     struct dt_reg *reg, void **addr, size_t *size)
> +{

I don't think you want addr to be a void **, but a phys_addr_t, see note
about ARM 32-bit LPAE below.

> +	u64 temp64;
> +
> +	if (!reg || !addr)
> +		return -EINVAL;

defensive programming?

> +
> +	/*
> +	 * default translate only understands u32 (<1> <1>) and
> +	 * u64 (<2> <1>|<2>) addresses
> +	 */
> +	if (reg->nr_address_cells < 1
> +			|| reg->nr_address_cells > 2
> +			|| reg->nr_size_cells < 1
> +			|| reg->nr_size_cells > 2)
> +		return -EINVAL;
> +
> +	if (reg->nr_address_cells == 2)
> +		temp64 = ((u64)reg->address_cells[0] << 32)
> +					| reg->address_cells[1];
> +	else
> +		temp64 = reg->address_cells[0];

I would use braces on these statements given the multi-line first
statement.

> +
> +	/*
> +	 * If we're 32-bit, then the upper word of a two word
> +	 * address better be zero.
> +	 */

not necessarily, on ARM 32-bit LPAE you have 40-bit physical addresses
but 32-bit virtual address pointers...

> +	if (sizeof(void *) == sizeof(u32) && reg->nr_address_cells > 1
> +			&& reg->address_cells[0] != 0)
> +		return -EINVAL;
> +
> +	*addr = (void *)(unsigned long)temp64;
> +
> +	if (size) {
> +		if (reg->nr_size_cells == 2)
> +			temp64 = ((u64)reg->size_cells[0] << 32)
> +						| reg->size_cells[1];
> +		else
> +			temp64 = reg->size_cells[0];
> +
> +		if (sizeof(size_t) == sizeof(u32) && reg->nr_size_cells > 1
> +				&& reg->size_cells[0] != 0)
> +			return -EINVAL;

same as above.

> +
> +		*size = (size_t)temp64;

hmmm, I feel like I just read this code.  Maybe you can have a static
little helper funciton to actually read your values.

> +	}
> +
> +	return 0;
> +}
> +
> +const struct dt_bus dt_default_bus = {
> +	.name = "default",
> +	.match = dt_bus_default_match,
> +	.translate = dt_bus_default_translate,
> +};
> +
> +void dt_bus_init_defaults(struct dt_bus *bus, const char *name)
> +{
> +	*bus = dt_default_bus;
> +	bus->name = name;
> +}
> +
> +int dt_bus_find_device_compatible(const struct dt_bus *bus,
> +				  const char *compatible)
> +{
> +	int node, ret;
> +
> +	if (!bus || !bus->match)
> +		return -EINVAL;

see __dt_bus_translate_reg below

> +
> +	node = fdt_node_offset_by_compatible(fdt, -1, compatible);
> +
> +	while (node >= 0) {
> +		if ((ret = bus->match(bus, node)) < 0)
> +			return ret;
> +		else if (ret)
> +			break;
> +		node = fdt_node_offset_by_compatible(fdt, node, compatible);
> +	}
> +
> +	return node;
> +}
> +
> +static int __dt_get_num_cells(int node, u32 *address_cells, u32 *size_cells)
> +{
> +	const struct fdt_property *prop;
> +	u32 *data;
> +	int err;
> +
> +	prop = fdt_get_property(fdt, node, "#address-cells", &err);
> +	if (!prop && err == -FDT_ERR_NOTFOUND) {
> +
> +		node = fdt_parent_offset(fdt, node);
> +		if (node < 0)
> +			return node;
> +
> +		return __dt_get_num_cells(node, address_cells, size_cells);

you're doing recursive calls with a severly limited stack space, you
should probably at least check your depth and catch errors at a
reasonable level.

It's probably cleaner to just have an iterative lookup of the node with
#address_cells in it (in which you can also verify that is also has a
#size-cells in it) and then pass that to the function that actually
reads it.

> +
> +	} else if (!prop) {
> +		return err;
> +	}
> +
> +	data = (u32 *)prop->data;
> +	*address_cells = fdt32_to_cpu(*data);
> +
> +	prop = fdt_get_property(fdt, node, "#size-cells", &err);
> +	if (!prop) {
> +		printf("we can read #address-cells, but not #size-cells?\n");
> +		return err;
> +	}
> +
> +	data = (u32 *)prop->data;
> +	*size_cells = fdt32_to_cpu(*data);
> +
> +	return 0;
> +}
> +
> +int dt_get_num_cells(int nodeoffset, u32 *address_cells, u32 *size_cells)
> +{
> +	if (!address_cells || !size_cells)
> +		return -EINVAL;

defensive programming?

> +	return __dt_get_num_cells(nodeoffset, address_cells, size_cells);
> +}
> +
> +int dt_get_reg(int nodeoffset, int regidx, u32 *address_cells,
> +	       u32 *size_cells, struct dt_reg *reg)
> +{
> +	const struct fdt_property *prop;
> +	u32 *data, regsz, i;
> +	int err;
> +
> +	if (!address_cells || !size_cells || !reg)
> +		return -EINVAL;

defensive programming?

> +
> +	memset(reg, 0, sizeof(struct dt_reg));

sizeof(*reg)

> +
> +	/*
> +	 * We assume #size-cells == 0 means translation is impossible,

hmm, this won't work for the cpus' reg properties for example.  I would
just assume (and document) that this function always takes valid
address_cells and size_cells (as u32 instead of u32 *).  I get that
you're trying to do some caching (from reading later patches), but that
should still be possible to do externally.

If you really really want to, then you should use address_cells, but I'm
not sure if it's actually valid for any bindings to have address_cells
== 0 and size_cells >0.  If you have conventions like this, it should be
clearly documented on the function itself!

> +	 * reserving it to indicate that we don't know what #address-cells
> +	 * and #size-cells are yet, and thus must try to get them from the
> +	 * parent.
> +	 */
> +	if (*size_cells == 0 && (err = dt_get_num_cells(nodeoffset,
> +					address_cells, size_cells)) < 0)
> +		return err;
> +
> +	prop = fdt_get_property(fdt, nodeoffset, "reg", &err);
> +	if (prop == NULL)
> +		return err;
> +
> +	regsz = (*address_cells + *size_cells) * sizeof(u32);
> +
> +	if ((regidx + 1) * regsz > prop->len)
> +		return -EINVAL;
> +
> +	data = (u32 *)(prop->data + regidx * regsz);
> +
> +	for (i = 0; i < *address_cells; ++i, ++data)
> +		reg->address_cells[i] = fdt32_to_cpu(*data);
> +	for (i = 0; i < *size_cells; ++i, ++data)
> +		reg->size_cells[i] = fdt32_to_cpu(*data);
> +
> +	reg->nr_address_cells = *address_cells;
> +	reg->nr_size_cells = *size_cells;
> +
> +	return 0;
> +}
> +
> +int __dt_bus_translate_reg(int nodeoffset, const struct dt_bus *bus,
> +			   int regidx, u32 *address_cells, u32 *size_cells,
> +			   void **addr, size_t *size)
> +{
> +	struct dt_reg reg;
> +	int ret;
> +
> +	if (!bus || !bus->translate)
> +		return -EINVAL;

The !bus seems overly defensive again.

The !bus->translate may be helpful here, but since we're returning a
bunch of -EINVALs you should probably put a debug statement in the error
catching part, so devs can easily enable debugging and figure out where
things are going wrong.

That is, if anyone would ever call this with a bus without translate on
there...

> +
> +	ret = dt_get_reg(nodeoffset, regidx, address_cells, size_cells, &reg);
> +	if (ret < 0)
> +		return ret;
> +
> +	return bus->translate(bus, &reg, addr, size);
> +}
> +
> +int dt_bus_translate_reg(int nodeoffset, const struct dt_bus *bus,
> +			 int regidx, void **addr, size_t *size)
> +{
> +	/*
> +	 * size_cells == 0 tells dt_get_reg to get address_cells
> +	 * and size_cells from the parent node
> +	 */
> +	u32 address_cells, size_cells = 0;
> +	return __dt_bus_translate_reg(nodeoffset, bus, regidx,
> +			&address_cells, &size_cells, addr, size);
> +}
> +
> +int dt_get_memory_params(void **start, size_t *size)

again, memory can exit beyond the 32-bit mark on ARM LPAE systems.

> +{
> +	int node = fdt_path_offset(fdt, "/memory");
> +	if (node < 0)
> +		return node;
> +
> +	return dt_bus_translate_reg(node, &dt_default_bus, 0, start, size);
> +}
> diff --git a/lib/devicetree.h b/lib/devicetree.h
> new file mode 100644
> index 0000000000000..1f2d61b46a308
> --- /dev/null
> +++ b/lib/devicetree.h
> @@ -0,0 +1,95 @@
> +#ifndef _DEVICETREE_H_
> +#define _DEVICETREE_H_
> +#include "libcflat.h"
> +
> +/*
> + * set/get the fdt pointer
> + */
> +extern int dt_set(const void *fdt_ptr);
> +extern const void *dt_get(void);
> +
> +/*
> + * bootinfo accessors
> + */
> +extern int dt_get_bootargs_ptr(char **bootargs);
> +extern int dt_get_memory_params(void **start, size_t *size);

There's no documentation to these functions?

> +
> +#define MAX_ADDRESS_CELLS	4
> +#define MAX_SIZE_CELLS		4
> +struct dt_reg {
> +	u32 nr_address_cells;
> +	u32 nr_size_cells;
> +	u32 address_cells[MAX_ADDRESS_CELLS];
> +	u32 size_cells[MAX_SIZE_CELLS];
> +};

dt_reg?  Is this for dt-bindings that specify the reg property?  A
comment would be nice.

> +
> +struct dt_bus {
> +	const char *name;
> +	int (*match)(const struct dt_bus *bus, int nodeoffset);
> +	/*
> +	 * match() returns
> +	 *  - a positive value on match
> +	 *  - zero on no match
> +	 *  - a negative value on error
> +	 */

what does match do?  (I know by reading the code, but it should be
documented)

consider using defines for the return values, so your client code can
be:

if (bus->match(bus, node) == BUS_MATCH_SUCCESS)
	break;

> +	int (*translate)(const struct dt_bus *bus, struct dt_reg *reg,
> +			  void **addr, size_t *size);
> +	/*
> +	 * translate() returns
> +	 *  - zero on success
> +	 *  - a negative value on error
> +	 */

ditto

> +	void *private;

what is this field meant to contain?  A hint about drivers passing
information to translate() and match() would be helpful.

> +};
> +
> +extern const struct dt_bus dt_default_bus;
> +extern void dt_bus_init_defaults(struct dt_bus *bus, const char *name);
> +extern int dt_bus_default_match(const struct dt_bus *bus, int nodeoffset);
> +extern int dt_bus_default_translate(const struct dt_bus *bus,
> +				    struct dt_reg *reg, void **addr,
> +				    size_t *size);
> +
> +/*
> + * find an fdt device node compatible with @compatible using match()
> + * from the given bus @bus.
> + */
> +extern int dt_bus_find_device_compatible(const struct dt_bus *bus,
> +					 const char *compatible);
> +
> +/*
> + * translate the reg indexed by @regidx of the "reg" property of the
> + * device node at @nodeoffset using translate() from the given bus @bus.
> + * returns the translation in @addr and @size
> + */

define 'translate' in the comment (into an address).

> +extern int dt_bus_translate_reg(int nodeoffset, const struct dt_bus *bus,
> +				int regidx, void **addr, size_t *size);
> +
> +/*
> + * same as dt_bus_translate_reg, but uses the given @address_cells and
> + * @size_cells rather than pulling them from the parent of @nodeoffset
> + */
> +extern int __dt_bus_translate_reg(int nodeoffset, const struct dt_bus *bus,
> +				  int regidx, u32 *address_cells,
> +				  u32 *size_cells, void **addr,
> +				  size_t *size);
> +
> +/*
> + * read the "reg" property of @nodeoffset, which is defined by @address_cells
> + * and @size_cells, and store the reg indexed by @regidx into @reg
> + */
> +extern int dt_get_reg(int nodeoffset, int regidx, u32 *address_cells,
> +		      u32 *size_cells, struct dt_reg *reg);
> +
> +/*
> + * searches up the devicetree for @address_cells and @size_cells,
> + * starting from @nodeoffset
> + */
> +extern int dt_find_num_cells(int nodeoffset, u32 *address_cells,
> +			    u32 *size_cells);

not defined?

> +
> +/*
> + * convert devicetree errors to strings
> + */
> +extern const char *dt_strerror(int errval);
> +
> +#endif
> diff --git a/lib/libcflat.h b/lib/libcflat.h
> index 2cde64a560956..fdaaf2a8ab31d 100644
> --- a/lib/libcflat.h
> +++ b/lib/libcflat.h
> @@ -61,6 +61,7 @@ extern long atol(const char *ptr);
>  
>  #define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
>  
> +#define __unused __attribute__((__unused__))
>  #define NULL ((void *)0UL)
>  #include "errno.h"
>  #endif
> -- 
> 1.8.1.4
> 

Thanks,
-- 
Christoffer

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 12/17] Introduce virtio-testdev
  2014-01-21 16:21 ` [PATCH 12/17] Introduce virtio-testdev Andrew Jones
@ 2014-02-02  2:27   ` Christoffer Dall
  2014-02-03 15:44     ` Andrew Jones
  0 siblings, 1 reply; 47+ messages in thread
From: Christoffer Dall @ 2014-02-02  2:27 UTC (permalink / raw)
  To: Andrew Jones; +Cc: kvmarm, kvm

On Tue, Jan 21, 2014 at 05:21:58PM +0100, Andrew Jones wrote:
> virtio-testdev is a communication channel to qemu through virtio that
> can be used by test code to send commands. The only command currently
> implemented is EXIT, which allows the test code to exit with a given
> status code.
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> 
> ---
> v3:
>  - switched from iomaps to devicetree
>  - fixed Christoffer's nits
>  - don't call halt() explicitly, let exit() fall back to it
>  - vm_{get,set} now {read,write} byte by byte like the kernel
> v2:
>  - use readl/writel framework (libio) [Christoffer Dall]
>  - keep the virtio abstraction in virtio-testdev [Alexander Graf]
> ---
>  lib/libcflat.h       |   3 ++
>  lib/virtio-testdev.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  lib/virtio-testdev.h |   9 ++++
>  lib/virtio.c         | 126 ++++++++++++++++++++++++++++++++++++++++++++++
>  lib/virtio.h         |  74 +++++++++++++++++++++++++++
>  5 files changed, 351 insertions(+)
>  create mode 100644 lib/virtio-testdev.c
>  create mode 100644 lib/virtio-testdev.h
>  create mode 100644 lib/virtio.c
>  create mode 100644 lib/virtio.h
> 
> diff --git a/lib/libcflat.h b/lib/libcflat.h
> index fdaaf2a8ab31d..84b8783bacfdc 100644
> --- a/lib/libcflat.h
> +++ b/lib/libcflat.h
> @@ -60,6 +60,9 @@ extern long atol(const char *ptr);
>  #define ARRAY_SIZE(_a)  (sizeof(_a)/sizeof((_a)[0]))
>  
>  #define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
> +#define container_of(ptr, type, member) ({				\
> +		const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
> +		(type *)( (char *)__mptr - offsetof(type,member) );})
>  
>  #define __unused __attribute__((__unused__))
>  #define NULL ((void *)0UL)
> diff --git a/lib/virtio-testdev.c b/lib/virtio-testdev.c
> new file mode 100644
> index 0000000000000..d4a69ede12a7a
> --- /dev/null
> +++ b/lib/virtio-testdev.c
> @@ -0,0 +1,139 @@
> +#include "libcflat.h"
> +#include "virtio.h"
> +
> +#define TESTDEV_MAJOR_VER 1
> +#define TESTDEV_MINOR_VER 1
> +
> +#define VIRTIO_ID_TESTDEV 0xffff
> +
> +#define CONFIG_SIZE 64
> +
> +enum {
> +	VERSION = 1,
> +	CLEAR,
> +	EXIT,
> +};
> +
> +#define TOKEN_OFFSET		0x0
> +#define NARGS_OFFSET		0x4
> +#define NRETS_OFFSET		0x8
> +#define ARG_OFFSET(n)		(0xc + (n) * 4)
> +#define __RET_OFFSET(nargs, n)	(ARG_OFFSET(nargs) + (n) * 4)
> +
> +static struct virtio_dev *testdev;
> +
> +static u32 testdev_readl(unsigned offset)
> +{
> +	if (offset > (CONFIG_SIZE - 4)) {
> +		printf("%s: offset 0x%x to big!\n", __func__, offset);
> +		exit(EINVAL);
> +	}
> +
> +	return virtio_config_readl(testdev, offset);
> +}
> +
> +static void testdev_writel(unsigned offset, u32 val)
> +{
> +	if (offset > (CONFIG_SIZE - 4)) {
> +		printf("%s: offset 0x%x to big!\n", __func__, offset);
> +		exit(EINVAL);
> +	}
> +
> +	virtio_config_writel(testdev, offset, val);
> +}
> +
> +/*
> + * We have to write all args; nargs, nrets, ... first to avoid executing
> + * the token's operation until all args are in place. Then issue the op,
> + * and then read the return values. Reading the return values (or just
> + * sanity checking by reading token) will read a zero into qemu's copy
> + * of the token, which allows us to prepare additional ops without
> + * re-executing the last one.
> + */
> +void virtio_testdev(u32 token, u32 nargs, u32 nrets, ...)
> +{
> +	va_list va;
> +	unsigned off;
> +	u32 n;
> +
> +	if (!testdev)
> +		return;
> +
> +	testdev_writel(NARGS_OFFSET, nargs);
> +	testdev_writel(NRETS_OFFSET, nrets);
> +
> +	va_start(va, nrets);
> +
> +	off = ARG_OFFSET(0);
> +	n = nargs;
> +	while (n--) {
> +		testdev_writel(off, va_arg(va, unsigned));
> +		off += 4;
> +	}
> +
> +	/* this runs the op, but then resets token to zero */
> +	testdev_writel(TOKEN_OFFSET, token);
> +
> +	/* sanity check */
> +	if (testdev_readl(TOKEN_OFFSET) != 0) {
> +		printf("virtio-testdev token should always read as zero!\n");
> +		exit(EIO);
> +	}
> +
> +	off = __RET_OFFSET(nargs, 0);
> +	n = nrets;
> +	while (n--) {
> +		u32 *r = va_arg(va, unsigned *);
> +		*r = testdev_readl(off);
> +		off += 4;
> +	}
> +
> +	va_end(va);
> +}
> +
> +void virtio_testdev_version(u32 *version)
> +{
> +	virtio_testdev(VERSION, 0, 1, version);
> +}
> +
> +void virtio_testdev_clear(void)
> +{
> +	virtio_testdev(CLEAR, 0, 0);
> +}
> +
> +void virtio_testdev_exit(int code)
> +{
> +	virtio_testdev(EXIT, 1, 0, code);
> +}
> +
> +void virtio_testdev_init(void)
> +{
> +	u16 major, minor;
> +	u32 version;
> +
> +	testdev = virtio_bind(VIRTIO_ID_TESTDEV);
> +	if (testdev == NULL) {
> +		printf("Can't find virtio-testdev. "
> +		       "Is '-device virtio-testdev' "
> +		       "on the qemu command line?\n");
> +		exit(ENODEV);
> +	}
> +
> +	virtio_testdev_version(&version);
> +	major = version >> 16;
> +	minor = version & 0xffff;
> +
> +	if (major != TESTDEV_MAJOR_VER || minor < TESTDEV_MINOR_VER) {
> +		char *u = "qemu";
> +		if (major > TESTDEV_MAJOR_VER)
> +			u = "kvm-unit-tests";
> +		printf("Incompatible version of virtio-testdev: major = %d, "
> +		       "minor = %d\n", major, minor);
> +		printf("Update %s.\n", u);
> +		exit(ENODEV);
> +	}
> +
> +	if (minor > TESTDEV_MINOR_VER)
> +		printf("testdev has new features. "
> +		       "An update of kvm-unit-tests may be possible.\n");
> +}
> diff --git a/lib/virtio-testdev.h b/lib/virtio-testdev.h
> new file mode 100644
> index 0000000000000..c10bbfb591d0b
> --- /dev/null
> +++ b/lib/virtio-testdev.h
> @@ -0,0 +1,9 @@
> +#ifndef _VIRTIO_TESTDEV_H_
> +#define _VIRTIO_TESTDEV_H_
> +#include "libcflat.h"
> +
> +extern void virtio_testdev_init(void);
> +extern void virtio_testdev_version(u32 *version);
> +extern void virtio_testdev_clear(void);
> +extern void virtio_testdev_exit(int code);
> +#endif
> diff --git a/lib/virtio.c b/lib/virtio.c
> new file mode 100644
> index 0000000000000..8abc8b2399a08
> --- /dev/null
> +++ b/lib/virtio.c
> @@ -0,0 +1,126 @@
> +#include "libcflat.h"
> +#include "devicetree.h"
> +#include "libio.h"
> +#include "heap.h"
> +#include "virtio.h"
> +
> +struct virtio_dt_device_data {
> +	u32 device;
> +	struct dt_bus *bus;
> +	int node;
> +	/* cached variables */
> +	u32 address_cells, size_cells;
> +};
> +
> +static void virtio_dt_device_data_init(struct virtio_dt_device_data *data,
> +				       u32 device, struct dt_bus *bus)
> +{
> +	memset(data, 0, sizeof(struct virtio_dt_device_data));
> +	data->device = device;
> +	data->bus = bus;
> +}
> +
> +static int vm_dt_bus_match(const struct dt_bus *bus, int nodeoffset);
> +static struct virtio_dev *vm_bind(struct virtio_dt_device_data *data);
> +
> +struct virtio_dev *virtio_bind(u32 device)
> +{
> +	struct virtio_dt_device_data data;
> +	struct dt_bus bus;
> +	const char *compatible;
> +
> +	/*
> +	 * currently we only support virtio-mmio
> +	 */
> +	compatible = "virtio,mmio";
> +	dt_bus_init_defaults(&bus, compatible);
> +	bus.match = vm_dt_bus_match;
> +	bus.private = (void *)&data;
> +	virtio_dt_device_data_init(&data, device, &bus);
> +
> +	data.node = dt_bus_find_device_compatible(&bus, compatible);
> +	if (data.node < 0) {
> +		printf("virtio bind for device id 0x%x failed, "
> +		       "fdt_error: %s\n", device, dt_strerror(data.node));
> +		return NULL;
> +	}
> +
> +	return vm_bind(&data);
> +}
> +
> +static int virtio_dt_bus_translate_reg(int nodeoffset,
> +				       const struct dt_bus *bus,
> +				       int regidx, void **addr,
> +				       size_t *size)

so this is really virtio_dt_bus_get_addr right?

> +{
> +	struct virtio_dt_device_data *data =
> +		(struct virtio_dt_device_data *)bus->private;
> +
> +	return __dt_bus_translate_reg(nodeoffset, bus, regidx,
> +			&data->address_cells, &data->size_cells, addr, size);
> +}
> +
> +/******************************************************
> + * virtio_mmio
> + ******************************************************/
> +
> +static int vm_dt_bus_match(const struct dt_bus *bus, int nodeoffset)
> +{
> +	struct virtio_dt_device_data *data =
> +		(struct virtio_dt_device_data *)bus->private;
> +	void *addr;
> +	int ret;
> +
> +	ret = virtio_dt_bus_translate_reg(nodeoffset, bus, 0, &addr, NULL);
> +	if (ret < 0) {
> +		printf("can't get reg! fdt_error: %s\n", dt_strerror(ret));
> +		return ret;
> +	}
> +
> +	return readl(addr + VIRTIO_MMIO_DEVICE_ID) == data->device;
> +}
> +
> +#define to_virtio_mmio_dev(vdev_ptr) \
> +	container_of(vdev_ptr, struct virtio_mmio_dev, vdev)
> +
> +static void vm_get(struct virtio_dev *vdev, unsigned offset,
> +		   void *buf, unsigned len)
> +{
> +	struct virtio_mmio_dev *vmdev = to_virtio_mmio_dev(vdev);
> +	u8 *p = buf;
> +	unsigned i;
> +
> +	for (i = 0; i < len; ++i)
> +		p[i] = readb(vmdev->base + VIRTIO_MMIO_CONFIG + offset + i);
> +}
> +
> +static void vm_set(struct virtio_dev *vdev, unsigned offset,
> +		   const void *buf, unsigned len)
> +{
> +	struct virtio_mmio_dev *vmdev = to_virtio_mmio_dev(vdev);
> +	const u8 *p = buf;
> +	unsigned i;
> +
> +	for (i = 0; i < len; ++i)
> +		writeb(p[i], vmdev->base + VIRTIO_MMIO_CONFIG + offset + i);
> +}
> +
> +static struct virtio_dev *vm_bind(struct virtio_dt_device_data *data)
> +{
> +	struct virtio_mmio_dev *vmdev;
> +	void *page;
> +
> +	page = alloc_page();
> +	vmdev = page;
> +	vmdev->vdev.config = page + sizeof(struct virtio_mmio_dev);
> +
> +	vmdev->vdev.id.device = data->device;
> +	vmdev->vdev.id.vendor = -1;
> +	vmdev->vdev.config->get = vm_get;
> +	vmdev->vdev.config->set = vm_set;
> +
> +	(void)virtio_dt_bus_translate_reg(data->node, data->bus, 0,
> +						&vmdev->base, NULL);

didn't you already do this in vm_dt_bus_mach() ?

> +
> +	return &vmdev->vdev;
> +}
> diff --git a/lib/virtio.h b/lib/virtio.h
> new file mode 100644
> index 0000000000000..c30a8dcd105cd
> --- /dev/null
> +++ b/lib/virtio.h
> @@ -0,0 +1,74 @@
> +#ifndef _VIRTIO_H_
> +#define _VIRTIO_H_
> +#include "libcflat.h"
> +
> +#define VIRTIO_MMIO_DEVICE_ID	0x008
> +#define VIRTIO_MMIO_CONFIG	0x100
> +
> +struct virtio_devid {
> +	u32 device;
> +	u32 vendor;
> +};
> +
> +struct virtio_dev {
> +	struct virtio_devid id;
> +	struct virtio_conf_ops *config;
> +};
> +
> +struct virtio_conf_ops {
> +	void (*get)(struct virtio_dev *vdev, unsigned offset,
> +		    void *buf, unsigned len);
> +	void (*set)(struct virtio_dev *vdev, unsigned offset,
> +		    const void *buf, unsigned len);
> +};
> +
> +struct virtio_mmio_dev {
> +	struct virtio_dev vdev;
> +	void *base;
> +};
> +
> +static inline u8
> +virtio_config_readb(struct virtio_dev *vdev, unsigned offset)
> +{
> +	u8 val;
> +	vdev->config->get(vdev, offset, &val, 1);
> +	return val;
> +}
> +
> +static inline u16
> +virtio_config_readw(struct virtio_dev *vdev, unsigned offset)
> +{
> +	u16 val;
> +	vdev->config->get(vdev, offset, &val, 2);
> +	return val;
> +}
> +
> +static inline u32
> +virtio_config_readl(struct virtio_dev *vdev, unsigned offset)
> +{
> +	u32 val;
> +	vdev->config->get(vdev, offset, &val, 4);
> +	return val;
> +}
> +
> +static inline void
> +virtio_config_writeb(struct virtio_dev *vdev, unsigned offset, u8 val)
> +{
> +	vdev->config->set(vdev, offset, &val, 1);
> +}
> +
> +static inline void
> +virtio_config_writew(struct virtio_dev *vdev, unsigned offset, u16 val)
> +{
> +	vdev->config->set(vdev, offset, &val, 2);
> +}
> +
> +static inline void
> +virtio_config_writel(struct virtio_dev *vdev, unsigned offset, u32 val)
> +{
> +	vdev->config->set(vdev, offset, &val, 4);
> +}
> +
> +extern struct virtio_dev *virtio_bind(u32 device);
> +
> +#endif
> -- 
> 1.8.1.4
> 

otherwise:

Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 13/17] arm: initial drop
  2014-01-21 16:21 ` [PATCH 13/17] arm: initial drop Andrew Jones
@ 2014-02-02  2:28   ` Christoffer Dall
  2014-02-03 15:55     ` Andrew Jones
  0 siblings, 1 reply; 47+ messages in thread
From: Christoffer Dall @ 2014-02-02  2:28 UTC (permalink / raw)
  To: Andrew Jones; +Cc: kvmarm, kvm

On Tue, Jan 21, 2014 at 05:21:59PM +0100, Andrew Jones wrote:
> 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 <drjones@redhat.com>
> 
> ---

[...]

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

const char *bootargs?

> +
> +static void read_bootinfo(const void *fdt)
> +{
> +	int ret;
> +

[...]

Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 15/17] printf: support field padding
  2014-01-21 16:22 ` [PATCH 15/17] printf: support field padding Andrew Jones
@ 2014-02-02  2:28   ` Christoffer Dall
  0 siblings, 0 replies; 47+ messages in thread
From: Christoffer Dall @ 2014-02-02  2:28 UTC (permalink / raw)
  To: Andrew Jones; +Cc: kvmarm, kvm

On Tue, Jan 21, 2014 at 05:22:01PM +0100, Andrew Jones wrote:
> Support format flags for field padding, such as "%08x", allowing
> register dumps to be easier on the eyes.
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>

Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 16/17] arm: add useful headers from the linux kernel
  2014-01-21 16:22 ` [PATCH 16/17] arm: add useful headers from the linux kernel Andrew Jones
@ 2014-02-02  2:29   ` Christoffer Dall
  2014-02-03 16:46     ` Andrew Jones
  0 siblings, 1 reply; 47+ messages in thread
From: Christoffer Dall @ 2014-02-02  2:29 UTC (permalink / raw)
  To: Andrew Jones; +Cc: kvmarm, kvm

On Tue, Jan 21, 2014 at 05:22:02PM +0100, Andrew Jones wrote:
> We're going to need PSR bit defines and pt_regs. We'll also need
> pt_regs offsets in assembly code. This patch adapts the linux
> kernel's ptrace.h and asm-offsets to this framework. Even though
> lib/arm/asm-offsets.h is a generated file, we still commit it,
> as it's unlikely to change. Also adapt cp15.h from the kernel,
> since we'll need bit defines from there too.
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> ---

[...]

> +
> +asm-offsets: scripts/arm/asm-offsets.flat
> +	$(QEMU) -device virtio-testdev -display none -serial stdio \
> +		-M virt -cpu $(PROCESSOR) \
> +		-kernel $^ > lib/arm/asm-offsets.h || true

I still disagree with this requirement to have the correct version of
qemu on the build machine.

[...]

-Christoffer

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 17/17] arm: vectors support
  2014-01-21 16:22 ` [PATCH 17/17] arm: vectors support Andrew Jones
@ 2014-02-02  2:29   ` Christoffer Dall
  2014-02-03 16:50     ` Andrew Jones
  0 siblings, 1 reply; 47+ messages in thread
From: Christoffer Dall @ 2014-02-02  2:29 UTC (permalink / raw)
  To: Andrew Jones; +Cc: kvmarm, kvm

On Tue, Jan 21, 2014 at 05:22:03PM +0100, Andrew Jones wrote:
> Add support for tests to use exception handlers.
> 
> v2 -> v3:
> - squashed in 'arm: Simplify exceptions_init in cstart.S' from
>   Christoffer Dall
> - suggested function name changes and comment additions [Christoffer Dall]
> - fix a bug with stack restore from usr mode exceptions that Christoffer
>   pointed out. Add a get_sp() accessor too.

hmmm, how did you address this, the only change I can see is using r6
instead of r2, which I'm not sure how changes anything.

The problem is that your ldmia is replacing the usr sp, not the svc sp,
so maybe you need to do ldmia sp!, [ r0 - pc ]^ (don't remember if that
particular combination works) or you need to do something more fancy...

Otherwise this is looking good.

Thanks,
Christoffer

> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> ---
>  arm/cstart.S          | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  arm/flat.lds          |   7 ++-
>  arm/selftest.c        | 119 +++++++++++++++++++++++++++++++++++
>  arm/unittests.cfg     |  20 +++++-
>  config/config-arm.mak |   1 +
>  lib/arm/processor.c   | 103 +++++++++++++++++++++++++++++++
>  lib/arm/processor.h   |  35 +++++++++++
>  lib/libcflat.h        |   2 +
>  8 files changed, 453 insertions(+), 2 deletions(-)
>  create mode 100644 lib/arm/processor.c
>  create mode 100644 lib/arm/processor.h
> 
> diff --git a/arm/cstart.S b/arm/cstart.S
> index 4de04b62c28c2..74674fd41c1b3 100644
> --- a/arm/cstart.S
> +++ b/arm/cstart.S
> @@ -1,3 +1,7 @@
> +#define __ASSEMBLY__
> +#include "arm/asm-offsets.h"
> +#include "arm/ptrace.h"
> +#include "arm/cp15.h"
>  
>  .arm
>  
> @@ -10,6 +14,13 @@ start:
>  	 * See the kernel doc Documentation/arm/Booting
>  	 */
>  	ldr	sp, =stacktop
> +	push	{r0-r3}
> +
> +	/* set up vector table and mode stacks */
> +	bl	exceptions_init
> +
> +	/* complete setup */
> +	pop	{r0-r3}
>  	bl	setup
>  
>  	/* start the test */
> @@ -20,9 +31,166 @@ start:
>  	bl	exit
>  	b	halt
>  
> +.macro set_mode_stack mode, stack
> +	add	\stack, #S_FRAME_SIZE
> +	msr	cpsr_c, #(\mode | PSR_I_BIT | PSR_F_BIT)
> +	mov	sp, \stack
> +.endm
> +
> +exceptions_init:
> +	mrc	p15, 0, r2, c1, c0, 0	@ read SCTLR
> +	bic	r2, #CR_V		@ SCTLR.V := 0
> +	mcr	p15, 0, r2, c1, c0, 0	@ write SCTLR
> +	ldr	r2, =vector_table
> +	mcr	p15, 0, r2, c12, c0, 0	@ write VBAR
> +
> +	mrs	r2, cpsr
> +	ldr	r1, =exception_stacks
> +		/* first frame for svc mode */
> +	set_mode_stack	UND_MODE, r1
> +	set_mode_stack	ABT_MODE, r1
> +	set_mode_stack	IRQ_MODE, r1
> +	set_mode_stack	FIQ_MODE, r1
> +	msr	cpsr_cxsf, r2	@ back to svc mode
> +	mov	pc, lr
> +
>  .text
>  
>  .globl halt
>  halt:
>  1:	wfi
>  	b	1b
> +
> +/*
> + * Vector stubs.
> + * Simplified version of the Linux kernel implementation
> + *   arch/arm/kernel/entry-armv.S
> + *
> + * Each mode has an S_FRAME_SIZE sized stack initialized
> + * in exceptions_init
> + */
> +.macro vector_stub, name, vec, mode, correction=0
> +.align 5
> +vector_\name:
> +.if \correction
> +	sub	lr, lr, #\correction
> +.endif
> +	/*
> +	 * Save r0, r1, lr_<exception> (parent PC)
> +	 * and spsr_<exception> (parent CPSR)
> +	 */
> +	str	r0, [sp, #S_R0]
> +	str	r1, [sp, #S_R1]
> +	str	lr, [sp, #S_PC]
> +	mrs	r0, spsr
> +	str	r0, [sp, #S_PSR]
> +
> +	/* Prepare for SVC32 mode. */
> +	mrs	r0, cpsr
> +	bic	r0, #MODE_MASK
> +	orr	r0, #SVC_MODE
> +	msr	spsr_cxsf, r0
> +
> +	/* Branch to handler in SVC mode */
> +	mov	r0, #\vec
> +	mov	r1, sp
> +	ldr	lr, =vector_common
> +	movs	pc, lr
> +.endm
> +
> +vector_stub 	rst,	0, UND_MODE
> +vector_stub	und,	1, UND_MODE
> +vector_stub	pabt,	3, ABT_MODE, 4
> +vector_stub	dabt,	4, ABT_MODE, 8
> +vector_stub	irq,	6, IRQ_MODE, 4
> +vector_stub	fiq,	7, FIQ_MODE, 4
> +
> +.align 5
> +vector_svc:
> +	/*
> +	 * Save r0, r1, lr_<exception> (parent PC)
> +	 * and spsr_<exception> (parent CPSR)
> +	 */
> +	push	{ r1 }
> +	ldr	r1, =exception_stacks
> +	str	r0, [r1, #S_R0]
> +	pop	{ r0 }
> +	str	r0, [r1, #S_R1]
> +	str	lr, [r1, #S_PC]
> +	mrs	r0, spsr
> +	str	r0, [r1, #S_PSR]
> +
> +	/*
> +	 * Branch to handler, still in SVC mode.
> +	 * r0 := 2 is the svc vector number.
> +	 */
> +	mov	r0, #2
> +	ldr	lr, =vector_common
> +	mov	pc, lr
> +
> +vector_common:
> +	/* make room for pt_regs */
> +	sub	sp, #S_FRAME_SIZE
> +	tst	sp, #4			@ check stack alignment
> +	subne	sp, #4
> +
> +	/* store registers r0-r12 */
> +	stmia	sp, { r0-r12 }		@ stored wrong r0 and r1, fix later
> +
> +	/* get registers saved in the stub */
> +	ldr	r2, [r1, #S_R0]		@ r0
> +	ldr	r3, [r1, #S_R1]		@ r1
> +	ldr	r4, [r1, #S_PC] 	@ lr_<exception> (parent PC)
> +	ldr	r5, [r1, #S_PSR]	@ spsr_<exception> (parent CPSR)
> +
> +	/* fix r0 and r1 */
> +	str	r2, [sp, #S_R0]
> +	str	r3, [sp, #S_R1]
> +
> +	/* store sp_svc, if we were in usr mode we'll fix this later */
> +	add	r6, sp, #S_FRAME_SIZE
> +	addne	r6, #4			@ stack wasn't aligned
> +	str	r6, [sp, #S_SP]
> +
> +	str	lr, [sp, #S_LR]		@ store lr_svc, fix later for usr mode
> +	str	r4, [sp, #S_PC]		@ store lr_<exception>
> +	str	r5, [sp, #S_PSR]	@ store spsr_<exception>
> +
> +	/* set ORIG_r0 */
> +	mov	r2, #-1
> +	str	r2, [sp, #S_OLD_R0]
> +
> +	/* if we were in usr mode then we need sp_usr and lr_usr instead */
> +	and	r1, r5, #MODE_MASK
> +	cmp	r1, #USR_MODE
> +	bne	1f
> +	add	r1, sp, #S_SP
> +	stmia	r1, { sp,lr }^
> +
> +	/* Call the handler. r0 is the vector number, r1 := pt_regs */
> +1:	mov	r1, sp
> +	bl	do_handle_exception
> +
> +	/* make sure we restore sp_svc and lr_svc on mode change */
> +	str	r6, [sp, #S_SP]
> +	str	lr, [sp, #S_LR]
> +
> +	/* return from exception */
> +	msr	spsr_cxsf, r5
> +	ldmia	sp, { r0-pc }^
> +
> +.align 5
> +vector_addrexcptn:
> +	b	vector_addrexcptn
> +
> +.section .text.ex
> +.align 5
> +vector_table:
> +	b	vector_rst
> +	b	vector_und
> +	b	vector_svc
> +	b	vector_pabt
> +	b	vector_dabt
> +	b	vector_addrexcptn	@ should never happen
> +	b	vector_irq
> +	b	vector_fiq
> diff --git a/arm/flat.lds b/arm/flat.lds
> index 3e5d72e24989b..ee9fc0ab79abc 100644
> --- a/arm/flat.lds
> +++ b/arm/flat.lds
> @@ -3,7 +3,12 @@ SECTIONS
>  {
>      .text : { *(.init) *(.text) *(.text.*) }
>      . = ALIGN(4K);
> -    .data : { *(.data) }
> +    .data : {
> +        exception_stacks = .;
> +        . += 4K;
> +        exception_stacks_end = .;
> +        *(.data)
> +    }
>      . = ALIGN(16);
>      .rodata : { *(.rodata) }
>      . = ALIGN(16);
> diff --git a/arm/selftest.c b/arm/selftest.c
> index 3d47a16cbcfad..96ebfe3454e63 100644
> --- a/arm/selftest.c
> +++ b/arm/selftest.c
> @@ -1,9 +1,119 @@
>  #include "libcflat.h"
>  #include "arm/sysinfo.h"
> +#include "arm/ptrace.h"
> +#include "arm/processor.h"
> +#include "arm/asm-offsets.h"
>  
>  #define PASS 0
>  #define FAIL 1
>  
> +static struct pt_regs expected_regs;
> +/*
> + * Capture the current register state and execute an instruction
> + * that causes an exception. The test handler will check that its
> + * capture of the current register state matches the capture done
> + * here.
> + *
> + * NOTE: update clobber list if passed insns needs more than r0,r1
> + */
> +#define test_exception(pre_insns, excptn_insn, post_insns)	\
> +	asm volatile(						\
> +		pre_insns "\n"					\
> +		"mov	r0, %0\n"				\
> +		"stmia	r0, { r0-lr }\n"			\
> +		"mrs	r1, cpsr\n"				\
> +		"str	r1, [r0, #" __stringify(S_PSR) "]\n"	\
> +		"mov	r1, #-1\n"				\
> +		"str	r1, [r0, #" __stringify(S_OLD_R0) "]\n"	\
> +		"add	r1, pc, #8\n"				\
> +		"str	r1, [r0, #" __stringify(S_R1) "]\n"	\
> +		"str	r1, [r0, #" __stringify(S_PC) "]\n"	\
> +		excptn_insn "\n"				\
> +		post_insns "\n"					\
> +	:: "r" (&expected_regs) : "r0", "r1")
> +
> +static bool check_regs(struct pt_regs *regs)
> +{
> +	unsigned i;
> +
> +	/* exception handlers should always run in svc mode */
> +	if (current_mode() != SVC_MODE)
> +		return false;
> +
> +	for (i = 0; i < ARRAY_SIZE(regs->uregs); ++i) {
> +		if (regs->uregs[i] != expected_regs.uregs[i])
> +			return false;
> +	}
> +
> +	return true;
> +}
> +
> +static bool und_works;
> +static void und_handler(struct pt_regs *regs)
> +{
> +	und_works = check_regs(regs);
> +}
> +
> +static bool check_und(void)
> +{
> +	install_exception_handler(EXCPTN_UND, und_handler);
> +
> +	/* issue an instruction to a coprocessor we don't have */
> +	test_exception("", "mcr p2, 0, r0, c0, c0", "");
> +
> +	install_exception_handler(EXCPTN_UND, NULL);
> +
> +	return und_works;
> +}
> +
> +static bool svc_works;
> +static void svc_handler(struct pt_regs *regs)
> +{
> +	u32 svc = *(u32 *)(regs->ARM_pc - 4) & 0xffffff;
> +
> +	if (processor_mode(regs) == SVC_MODE) {
> +		/*
> +		 * When issuing an svc from supervisor mode lr_svc will
> +		 * get corrupted. So before issuing the svc, callers must
> +		 * always push it on the stack. We pushed it to offset 4.
> +		 */
> +		regs->ARM_lr = *(unsigned long *)(regs->ARM_sp + 4);
> +	}
> +
> +	svc_works = check_regs(regs) && svc == 123;
> +}
> +
> +static bool check_svc(void)
> +{
> +	install_exception_handler(EXCPTN_SVC, svc_handler);
> +
> +	if (current_mode() == SVC_MODE) {
> +		/*
> +		 * An svc from supervisor mode will corrupt lr_svc and
> +		 * spsr_svc. We need to save/restore them separately.
> +		 */
> +		test_exception(
> +			"mrs	r0, spsr\n"
> +			"push	{ r0,lr }\n",
> +			"svc	#123\n",
> +			"pop	{ r0,lr }\n"
> +			"msr	spsr_cxsf, r0\n"
> +		);
> +	} else {
> +		test_exception("", "svc #123", "");
> +	}
> +
> +	install_exception_handler(EXCPTN_SVC, NULL);
> +
> +	return svc_works;
> +}
> +
> +static void check_vectors(void)
> +{
> +	int ret = check_und() && check_svc() ? PASS : FAIL;
> +	exit(ret);
> +}
> +
>  static void assert_enough_args(int nargs, int needed)
>  {
>  	if (nargs < needed) {
> @@ -24,6 +134,15 @@ int main(int argc, char **argv)
>  
>  		if (mem_size/1024/1024 == (size_t)atol(argv[1]))
>  			ret = PASS;
> +
> +	} else if (strcmp(argv[0], "vectors") == 0) {
> +
> +		check_vectors(); /* doesn't return */
> +
> +	} else if (strcmp(argv[0], "vectors_usr") == 0) {
> +
> +		start_usr(check_vectors); /* doesn't return */
> +
>  	}
>  
>  	return ret;
> diff --git a/arm/unittests.cfg b/arm/unittests.cfg
> index aff684892e90b..75e2a2e3d25bc 100644
> --- a/arm/unittests.cfg
> +++ b/arm/unittests.cfg
> @@ -6,6 +6,24 @@
>  # 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]
> +#
> +# The selftest group tests the initial booting of a guest, as well as
> +# the test framework itself.
> +#
> +# Test bootinfo reading; configured mem-size should equal expected mem-size
> +[selftest_mem]
>  file = selftest.flat
>  extra_params = -m 256 -append 'mem 256'
> +groups = selftest
> +
> +# Test vector setup and exception handling (svc mode).
> +[selftest_vectors]
> +file = selftest.flat
> +extra_params = -append 'vectors'
> +groups = selftest
> +
> +# Test vector setup and exception handling (usr mode).
> +[selftest_vectors_usr]
> +file = selftest.flat
> +extra_params = -append 'vectors_usr'
> +groups = selftest
> diff --git a/config/config-arm.mak b/config/config-arm.mak
> index a863b3e3511c9..99349bf8b0c6b 100644
> --- a/config/config-arm.mak
> +++ b/config/config-arm.mak
> @@ -16,6 +16,7 @@ cflatobjs += \
>  	lib/virtio.o \
>  	lib/virtio-testdev.o \
>  	lib/arm/io.o \
> +	lib/arm/processor.o \
>  	lib/arm/setup.o
>  
>  libeabi := lib/arm/libeabi.a
> diff --git a/lib/arm/processor.c b/lib/arm/processor.c
> new file mode 100644
> index 0000000000000..1fededee6977f
> --- /dev/null
> +++ b/lib/arm/processor.c
> @@ -0,0 +1,103 @@
> +#include "libcflat.h"
> +#include "arm/processor.h"
> +#include "arm/sysinfo.h"
> +#include "arm/ptrace.h"
> +#include "heap.h"
> +
> +static const char *processor_modes[] = {
> +	"USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" ,
> +	"UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
> +	"UK8_26" , "UK9_26" , "UK10_26", "UK11_26",
> +	"UK12_26", "UK13_26", "UK14_26", "UK15_26",
> +	"USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" ,
> +	"UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" ,
> +	"UK8_32" , "UK9_32" , "UK10_32", "UND_32" ,
> +	"UK12_32", "UK13_32", "UK14_32", "SYS_32"
> +};
> +
> +static char *vector_names[] = {
> +	"rst", "und", "svc", "pabt", "dabt", "addrexcptn", "irq", "fiq"
> +};
> +
> +void show_regs(struct pt_regs *regs)
> +{
> +	unsigned long flags;
> +	char buf[64];
> +
> +	printf("pc : [<%08lx>]    lr : [<%08lx>]    psr: %08lx\n"
> +	       "sp : %08lx  ip : %08lx  fp : %08lx\n",
> +		regs->ARM_pc, regs->ARM_lr, regs->ARM_cpsr,
> +		regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
> +	printf("r10: %08lx  r9 : %08lx  r8 : %08lx\n",
> +		regs->ARM_r10, regs->ARM_r9, regs->ARM_r8);
> +	printf("r7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\n",
> +		regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4);
> +	printf("r3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\n",
> +		regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0);
> +
> +	flags = regs->ARM_cpsr;
> +	buf[0] = flags & PSR_N_BIT ? 'N' : 'n';
> +	buf[1] = flags & PSR_Z_BIT ? 'Z' : 'z';
> +	buf[2] = flags & PSR_C_BIT ? 'C' : 'c';
> +	buf[3] = flags & PSR_V_BIT ? 'V' : 'v';
> +	buf[4] = '\0';
> +
> +	printf("Flags: %s  IRQs o%s  FIQs o%s  Mode %s\n",
> +		buf, interrupts_enabled(regs) ? "n" : "ff",
> +		fast_interrupts_enabled(regs) ? "n" : "ff",
> +		processor_modes[processor_mode(regs)]);
> +
> +	if (!user_mode(regs)) {
> +		unsigned int ctrl, transbase, dac;
> +		asm volatile(
> +			"mrc p15, 0, %0, c1, c0\n"
> +			"mrc p15, 0, %1, c2, c0\n"
> +			"mrc p15, 0, %2, c3, c0\n"
> +		: "=r" (ctrl), "=r" (transbase), "=r" (dac));
> +		printf("Control: %08x  Table: %08x  DAC: %08x\n",
> +			ctrl, transbase, dac);
> +	}
> +}
> +
> +void *get_sp(void)
> +{
> +	register unsigned long sp asm("sp");
> +	return (void *)sp;
> +}
> +
> +static exception_fn exception_handlers[EXCPTN_MAX];
> +
> +void install_exception_handler(enum vector v, exception_fn fn)
> +{
> +	if (v < EXCPTN_MAX)
> +		exception_handlers[v] = fn;
> +}
> +
> +void do_handle_exception(enum vector v, struct pt_regs *regs)
> +{
> +	if (v < EXCPTN_MAX && exception_handlers[v]) {
> +		exception_handlers[v](regs);
> +		return;
> +	}
> +
> +	if (v < EXCPTN_MAX)
> +		printf("Unhandled exception %d (%s)\n", v, vector_names[v]);
> +	else
> +		printf("%s called with vector=%d\n", __func__, v);
> +	printf("Exception frame registers:\n");
> +	show_regs(regs);
> +	exit(EINTR);
> +}
> +
> +void start_usr(void (*func)(void))
> +{
> +	void *sp_usr = alloc_page() + PAGE_SIZE;
> +	asm volatile(
> +		"mrs	r0, cpsr\n"
> +		"bic	r0, #" __stringify(MODE_MASK) "\n"
> +		"orr	r0, #" __stringify(USR_MODE) "\n"
> +		"msr	cpsr_c, r0\n"
> +		"mov	sp, %0\n"
> +		"mov	pc, %1\n"
> +	:: "r" (sp_usr), "r" (func) : "r0");
> +}
> diff --git a/lib/arm/processor.h b/lib/arm/processor.h
> new file mode 100644
> index 0000000000000..12c1902de97fd
> --- /dev/null
> +++ b/lib/arm/processor.h
> @@ -0,0 +1,35 @@
> +#ifndef _ARM_PROCESSOR_H_
> +#define _ARM_PROCESSOR_H_
> +#include "libcflat.h"
> +#include "ptrace.h"
> +
> +enum vector {
> +	EXCPTN_RST,
> +	EXCPTN_UND,
> +	EXCPTN_SVC,
> +	EXCPTN_PABT,
> +	EXCPTN_DABT,
> +	EXCPTN_ADDREXCPTN,
> +	EXCPTN_IRQ,
> +	EXCPTN_FIQ,
> +	EXCPTN_MAX,
> +};
> +
> +typedef void (*exception_fn)(struct pt_regs *);
> +extern void install_exception_handler(enum vector v, exception_fn fn);
> +
> +extern void show_regs(struct pt_regs *regs);
> +extern void *get_sp(void);
> +
> +extern void start_usr(void (*func)(void));
> +
> +static inline unsigned long current_cpsr(void)
> +{
> +	unsigned long cpsr;
> +	asm volatile("mrs %0, cpsr" : "=r" (cpsr));
> +	return cpsr;
> +}
> +
> +#define current_mode() (current_cpsr() & MODE_MASK)
> +
> +#endif
> diff --git a/lib/libcflat.h b/lib/libcflat.h
> index 84b8783bacfdc..3d47a3331b7fc 100644
> --- a/lib/libcflat.h
> +++ b/lib/libcflat.h
> @@ -65,6 +65,8 @@ extern long atol(const char *ptr);
>  		(type *)( (char *)__mptr - offsetof(type,member) );})
>  
>  #define __unused __attribute__((__unused__))
> +#define __stringify_1(x...)	#x
> +#define __stringify(x...)	__stringify_1(x)
>  #define NULL ((void *)0UL)
>  #include "errno.h"
>  #endif
> -- 
> 1.8.1.4
> 

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 00/17] kvm-unit-tests/arm: initial drop
  2014-02-02  2:22 ` Christoffer Dall
@ 2014-02-03 13:24   ` Andrew Jones
       [not found]     ` <CALxX4v-h+gOCZDukCnGK_GUQepu07KYw4BGjzjGNgA0SdDcLNw@mail.gmail.com>
  0 siblings, 1 reply; 47+ messages in thread
From: Andrew Jones @ 2014-02-03 13:24 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: kvmarm, kvm

On Sat, Feb 01, 2014 at 06:22:03PM -0800, Christoffer Dall wrote:
> On Tue, Jan 21, 2014 at 05:21:46PM +0100, Andrew Jones wrote:
> > This is a v3 of a series that introduces arm to kvm-unit-tests.
> 
> Just a meta-comment:
> 
> It would be helpful if you include the "v3" in your subjects so it's
> easy to go back and track previous review comments.
> 
> git format-patch --subject-prefix "PATCH v3"
> 

I meant to do that... v4 will get the right subject.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 05/17] add 'make cscope' support
  2014-02-02  2:22   ` Christoffer Dall
@ 2014-02-03 13:25     ` Andrew Jones
  0 siblings, 0 replies; 47+ messages in thread
From: Andrew Jones @ 2014-02-03 13:25 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: kvmarm, kvm

On Sat, Feb 01, 2014 at 06:22:58PM -0800, Christoffer Dall wrote:
> On Tue, Jan 21, 2014 at 05:21:51PM +0100, Andrew Jones wrote:
> > Add a Makefile target to quickly generate arch-specific cscope
> > for kvm-unit-tests. Assumes a mostly flat directory structure,
> > i.e. uses '-maxdepth 1' in the file search.
> > 
> > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > ---
> >  Makefile | 9 ++++++++-
> >  1 file changed, 8 insertions(+), 1 deletion(-)
> > 
> > diff --git a/Makefile b/Makefile
> > index fa95d66386d49..283655957f39f 100644
> > --- a/Makefile
> > +++ b/Makefile
> > @@ -3,7 +3,7 @@ include config.mak
> >  
> >  DESTDIR := $(PREFIX)/share/qemu/tests
> >  
> > -.PHONY: arch_clean clean
> > +.PHONY: arch_clean clean cscope
> >  
> >  #make sure env CFLAGS variable is not used
> >  CFLAGS =
> > @@ -52,3 +52,10 @@ install:
> >  
> >  clean: arch_clean
> >  	$(RM) lib/.*.d $(libcflat) $(cflatobjs)
> > +
> > +cscope: common_dirs = lib
> > +cscope:
> > +	rm -f ./cscope.*
> > +	find $(TEST_DIR) lib/$(TEST_DIR) $(common_dirs) -maxdepth 1 \
> > +		-name "*.[chsS]" -print | sed 's,^\./,,' > ./cscope.files
> 
> shouldn't you use single quotes for the -name pattern to avoid any
> substitutions here?
> 

sure, will do

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 08/17] Introduce libio to common code for io read/write
  2014-02-02  2:24   ` Christoffer Dall
@ 2014-02-03 13:51     ` Andrew Jones
  2014-02-03 16:30       ` Christoffer Dall
  0 siblings, 1 reply; 47+ messages in thread
From: Andrew Jones @ 2014-02-03 13:51 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: kvmarm, kvm

On Sat, Feb 01, 2014 at 06:24:51PM -0800, Christoffer Dall wrote:
> On Tue, Jan 21, 2014 at 05:21:54PM +0100, Andrew Jones wrote:
> > v3:
> >  - get rid of CONFIG_64BIT, replace with asserts
> >  - get rid of {read,write}_len()
> >  - fix bad *64_to_cpu macros
> 
> note that putting the changelog after the "---" prevents it from
> getting committed, but I'm not sure if there are different
> conventions for the unit-tests framework.

I'll drop the '---' in the v4 patches

> 
> > 
> > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > ---
> >  lib/libio.h | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 173 insertions(+)
> >  create mode 100644 lib/libio.h
> > 
> > diff --git a/lib/libio.h b/lib/libio.h
> > new file mode 100644
> > index 0000000000000..6adc6a7bbee61
> > --- /dev/null
> > +++ b/lib/libio.h
> > @@ -0,0 +1,173 @@
> > +#ifndef _LIBIO_H_
> > +#define _LIBIO_H_
> > +/*
> > + * Adapted from the Linux kernel's include/asm-generic/io.h and
> > + * arch/arm/include/asm/io.h
> > + */
> > +#include "libcflat.h"
> > +
> > +#ifndef NDEBUG
> > +#define LIBIO_ASSERT(expr) do { \
> > +	if (!(expr)) printf("%s:%d: assert failed!\n", __FILE__, __LINE__);\
> > +} while (0)
> > +#else
> > +#define LIBIO_ASSERT(expr) do { } while (0)
> > +#endif
> > +
> > +typedef u32 compat_ptr_t;
> > +
> > +/*
> > + * Use compat_ptr() on 64-bit arches when casting 32-bit
> 
> arches? architectures? archs?

kernel code has 88 archs and 55 arches, I guess we could go with
archs by majority rules, but I prefer arches.

> 
> > + * addresses to pointers in order to avoid compiler warnings.
> > + */
> > +static inline void *compat_ptr(compat_ptr_t ptr)
> > +{
> > +	return (void *)(unsigned long)ptr;
> > +}
> > +
> > +static inline compat_ptr_t ptr_to_compat(void *ptr)
> > +{
> > +	return (u32)(unsigned long)ptr;
> > +}
> > +
> > +#ifndef __raw_readb
> > +static inline u8 __raw_readb(const volatile void *addr)
> > +{
> > +	return *(const volatile u8 *)addr;
> > +}
> > +#endif
> > +
> > +#ifndef __raw_readw
> > +static inline u16 __raw_readw(const volatile void *addr)
> > +{
> > +	return *(const volatile u16 *)addr;
> > +}
> > +#endif
> > +
> > +#ifndef __raw_readl
> > +static inline u32 __raw_readl(const volatile void *addr)
> > +{
> > +	return *(const volatile u32 *)addr;
> > +}
> > +#endif
> > +
> > +#ifndef __raw_readq
> > +static inline u64 __raw_readq(const volatile void *addr)
> > +{
> > +	LIBIO_ASSERT(sizeof(unsigned long) == sizeof(u64));
> > +	return *(const volatile u64 *)addr;
> > +}
> > +#endif
> > +
> > +#ifndef __raw_writeb
> > +static inline void __raw_writeb(u8 b, volatile void *addr)
> > +{
> > +	*(volatile u8 *)addr = b;
> > +}
> > +#endif
> > +
> > +#ifndef __raw_writew
> > +static inline void __raw_writew(u16 b, volatile void *addr)
> > +{
> > +	*(volatile u16 *)addr = b;
> > +}
> > +#endif
> > +
> > +#ifndef __raw_writel
> > +static inline void __raw_writel(u32 b, volatile void *addr)
> > +{
> > +	*(volatile u32 *)addr = b;
> > +}
> > +#endif
> > +
> > +#ifndef __raw_writeq
> > +static inline void __raw_writeq(u64 b, volatile void *addr)
> > +{
> > +	LIBIO_ASSERT(sizeof(unsigned long) == sizeof(u64));
> > +	*(volatile u64 *)addr = b;
> > +}
> > +#endif
> > +
> > +#ifndef __bswap16
> > +static inline u16 __bswap16(u16 x)
> > +{
> > +	return ((x >> 8) & 0xff) | ((x & 0xff) << 8);
> > +}
> > +#endif
> > +
> > +#ifndef __bswap32
> > +static inline u32 __bswap32(u32 x)
> > +{
> > +	return ((x & 0xff000000) >> 24) | ((x & 0x00ff0000) >>  8) |
> > +	       ((x & 0x0000ff00) <<  8) | ((x & 0x000000ff) << 24);
> > +}
> > +#endif
> > +
> > +#ifndef __bswap64
> > +static inline u64 __bswap64(u64 x)
> > +{
> > +	return ((x & 0x00000000000000ffULL) << 56) |
> > +	       ((x & 0x000000000000ff00ULL) << 40) |
> > +	       ((x & 0x0000000000ff0000ULL) << 24) |
> > +	       ((x & 0x00000000ff000000ULL) <<  8) |
> > +	       ((x & 0x000000ff00000000ULL) >>  8) |
> > +	       ((x & 0x0000ff0000000000ULL) >> 24) |
> > +	       ((x & 0x00ff000000000000ULL) >> 40) |
> > +	       ((x & 0xff00000000000000ULL) >> 56);
> > +}
> > +#endif
> > +
> > +#ifndef cpu_is_be
> > +#define cpu_is_be 0
> > +#endif
> > +
> > +#define le16_to_cpu(x) \
> > +	({ u16 __r = cpu_is_be ? __bswap16(x) : (x); __r; })
> > +#define cpu_to_le16 le16_to_cpu
> > +
> > +#define le32_to_cpu(x) \
> > +	({ u32 __r = cpu_is_be ? __bswap32(x) : (x); __r; })
> > +#define cpu_to_le32 le32_to_cpu
> > +
> > +#define le64_to_cpu(x) \
> > +	({ u64 __r = cpu_is_be ? __bswap64(x) : (x); __r; })
> > +#define cpu_to_le64 le64_to_cpu
> > +
> > +#define be16_to_cpu(x) \
> > +	({ u16 __r = !cpu_is_be ? __bswap16(x) : (x); __r; })
> > +#define cpu_to_be16 be16_to_cpu
> > +
> > +#define be32_to_cpu(x) \
> > +	({ u32 __r = !cpu_is_be ? __bswap32(x) : (x); __r; })
> > +#define cpu_to_be32 be32_to_cpu
> > +
> > +#define be64_to_cpu(x) \
> > +	({ u64 __r = !cpu_is_be ? __bswap64(x) : (x); __r; })
> > +#define cpu_to_be64 be64_to_cpu
> > +
> > +#ifndef rmb
> > +#define rmb() do { } while (0)
> > +#endif
> > +#ifndef wmb
> > +#define wmb() do { } while (0)
> > +#endif
> > +
> > +#define readb(addr) \
> > +	({ u8 __r = __raw_readb(addr); rmb(); __r; })
> > +#define readw(addr) \
> > +	({ u16 __r = le16_to_cpu(__raw_readw(addr)); rmb(); __r; })
> > +#define readl(addr) \
> > +	({ u32 __r = le32_to_cpu(__raw_readl(addr)); rmb(); __r; })
> > +#define readq(addr) \
> > +	({ u64 __r = le64_to_cpu(__raw_readq(addr)); rmb(); __r; })
> > +
> > +#define writeb(b, addr) \
> > +	({ wmb(); __raw_writeb(b, addr); })
> > +#define writew(b, addr) \
> > +	({ wmb(); __raw_writew(cpu_to_le16(b), addr); })
> > +#define writel(b, addr) \
> > +	({ wmb(); __raw_writel(cpu_to_le32(b), addr); })
> > +#define writeq(b, addr) \
> > +	({ wmb(); __raw_writeq(cpu_to_le64(b), addr); })
> > +
> > +#endif
> 
> so these definitions always assume that your device is LE, which is
> probably true for ARM and x86 for now, but if we ever use this on PPC or
> want to test ARM BE with a BE QEMU, will it still work?

I don't know if it'll be an issue or not. Let's cross that bridge when we
get to it. We can alway move/duplicate these accessors into each arch
specific io.h file, when necessary.

> 
> (There's some trickery with virtio and endianness that I don't remember
> 100%, so if we assume this ever only reads and writes to virtio space,
> we may be in the clear.)

The virtio spec is switching to everything LE, I believe, so the above
should be good for virtio devices anyway.


> 
> Otherwise:
> 
> Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 10/17] libfdt: get libfdt to build
  2014-02-02  2:25   ` Christoffer Dall
@ 2014-02-03 13:57     ` Andrew Jones
  0 siblings, 0 replies; 47+ messages in thread
From: Andrew Jones @ 2014-02-03 13:57 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: kvmarm, kvm

On Sat, Feb 01, 2014 at 06:25:37PM -0800, Christoffer Dall wrote:
> On Tue, Jan 21, 2014 at 05:21:56PM +0100, Andrew Jones wrote:
> > Add string functions needed for libfdt, modify libfdt_env.h
> > for this environment, and add a make target.
> 
> The endianness changes you're making to CPU_TO_FDTxx are not trivial to
> review.  A motivational commit text here would have been immensely
> helpful.

I'll improve the commit message in the next round.

> 
> > 
> > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > ---
> >  Makefile                | 23 +++++++++++++++++++++-
> >  lib/libcflat.h          |  4 ++++
> >  lib/libfdt/libfdt_env.h | 25 ++++++++++++------------
> >  lib/string.c            | 51 +++++++++++++++++++++++++++++++++++++++++++++++++
> >  4 files changed, 90 insertions(+), 13 deletions(-)
> > 
> > diff --git a/Makefile b/Makefile
> > index 283655957f39f..94c565242c1b7 100644
> > --- a/Makefile
> > +++ b/Makefile
> > @@ -16,6 +16,13 @@ cflatobjs := \
> >  	lib/printf.o \
> >  	lib/string.o
> >  
> > +# libfdt paths
> > +LIBFDT_objdir = lib/libfdt
> > +LIBFDT_srcdir = lib/libfdt
> > +LIBFDT_archive = $(LIBFDT_objdir)/libfdt.a
> > +LIBFDT_include = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_INCLUDES))
> > +LIBFDT_version = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_VERSION))
> > +
> >  #include architecure specific make rules
> >  include config/config-$(ARCH).mak
> >  
> > @@ -41,6 +48,20 @@ LDFLAGS += -pthread -lrt
> >  $(libcflat): $(cflatobjs)
> >  	$(AR) rcs $@ $^
> >  
> > +include $(LIBFDT_srcdir)/Makefile.libfdt
> > +
> > +.PHONY: libfdt
> > +libfdt: $(LIBFDT_archive)
> > +
> > +$(LIBFDT_archive): CFLAGS += -ffreestanding -I lib -I lib/libfdt -Wno-sign-compare
> > +$(LIBFDT_archive): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
> > +	$(AR) rcs $@ $^
> > +
> > +libfdt_clean:
> > +	$(RM) $(LIBFDT_archive) \
> > +	$(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS)) \
> > +	$(LIBFDT_objdir)/.*.d
> > +
> >  %.o: %.S
> >  	$(CC) $(CFLAGS) -c -nostdlib -o $@ $<
> >  
> > @@ -53,7 +74,7 @@ install:
> >  clean: arch_clean
> >  	$(RM) lib/.*.d $(libcflat) $(cflatobjs)
> >  
> > -cscope: common_dirs = lib
> > +cscope: common_dirs = lib lib/libfdt
> >  cscope:
> >  	rm -f ./cscope.*
> >  	find $(TEST_DIR) lib/$(TEST_DIR) $(common_dirs) -maxdepth 1 \
> > diff --git a/lib/libcflat.h b/lib/libcflat.h
> > index a1be635ab4ee9..2cde64a560956 100644
> > --- a/lib/libcflat.h
> > +++ b/lib/libcflat.h
> > @@ -43,6 +43,7 @@ extern void exit(int code);
> >  extern unsigned long strlen(const char *buf);
> >  extern char *strcat(char *dest, const char *src);
> >  extern int strcmp(const char *a, const char *b);
> > +extern char *strchr(const char *s, int c);
> >  
> >  extern int printf(const char *fmt, ...);
> >  extern int vsnprintf(char *buf, int size, const char *fmt, va_list va);
> > @@ -51,6 +52,9 @@ extern void puts(const char *s);
> >  
> >  extern void *memset(void *s, int c, size_t n);
> >  extern void *memcpy(void *dest, const void *src, size_t n);
> > +extern int memcmp(const void *s1, const void *s2, size_t n);
> > +extern void *memmove(void *dest, const void *src, size_t n);
> > +extern void *memchr(const void *s, int c, size_t n);
> >  
> >  extern long atol(const char *ptr);
> >  #define ARRAY_SIZE(_a)  (sizeof(_a)/sizeof((_a)[0]))
> > diff --git a/lib/libfdt/libfdt_env.h b/lib/libfdt/libfdt_env.h
> > index 9dea97dfff818..46fcb6c29045f 100644
> > --- a/lib/libfdt/libfdt_env.h
> > +++ b/lib/libfdt/libfdt_env.h
> > @@ -52,9 +52,16 @@
> >   *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> >   */
> >  
> > -#include <stddef.h>
> > -#include <stdint.h>
> > -#include <string.h>
> > +#include "libcflat.h"
> > +#include "libio.h"
> > +
> > +#ifndef HAVE_UINTS
> > +typedef u8 uint8_t;
> > +typedef u16 uint16_t;
> > +typedef u32 uint32_t;
> > +typedef u64 uint64_t;
> > +typedef unsigned long uintptr_t;
> > +#endif
> >  
> >  #ifdef __CHECKER__
> >  #define __force __attribute__((force))
> > @@ -68,14 +75,9 @@ typedef uint16_t __bitwise fdt16_t;
> >  typedef uint32_t __bitwise fdt32_t;
> >  typedef uint64_t __bitwise fdt64_t;
> >  
> > -#define EXTRACT_BYTE(x, n)	((unsigned long long)((uint8_t *)&x)[n])
> > -#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1))
> > -#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \
> > -			 (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3))
> > -#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \
> > -			 (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \
> > -			 (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \
> > -			 (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7))
> > +#define CPU_TO_FDT16 cpu_to_be16
> > +#define CPU_TO_FDT32 cpu_to_be32
> > +#define CPU_TO_FDT64 cpu_to_be64
> >  
> >  static inline uint16_t fdt16_to_cpu(fdt16_t x)
> >  {
> > @@ -106,6 +108,5 @@ static inline fdt64_t cpu_to_fdt64(uint64_t x)
> >  #undef CPU_TO_FDT64
> >  #undef CPU_TO_FDT32
> >  #undef CPU_TO_FDT16
> > -#undef EXTRACT_BYTE
> >  
> >  #endif /* _LIBFDT_ENV_H */
> > diff --git a/lib/string.c b/lib/string.c
> > index 3a9caf720bf2b..234f96f4442f7 100644
> > --- a/lib/string.c
> > +++ b/lib/string.c
> > @@ -31,6 +31,17 @@ int strcmp(const char *a, const char *b)
> >      return *a - *b;
> >  }
> >  
> > +char *strchr(const char *s, int c)
> > +{
> > +    unsigned char chr = (unsigned char)c;
> 
> why unsigned?

no good answer for you. I'll redo this function.

> 
> > +    int n = strlen(s) + 1;
> 
> why scan the string twice?  couldn't the whole function be written:
> 
> {
> char chr = (char)c;
> while (*s != '\0' && *s != chr)
> 	s++;
> return (*s != chr) ? NULL : (char *)s;
> }
> 
> > +
> > +    while (n--)
> > +	if (*s++ == chr)
> > +	    return (char *)(s - 1);
> > +    return NULL;
> > +}
> > +
> >  void *memset(void *s, int c, size_t n)
> >  {
> >      size_t i;
> > @@ -54,6 +65,46 @@ void *memcpy(void *dest, const void *src, size_t n)
> >      return dest;
> >  }
> >  
> > +int memcmp(const void *s1, const void *s2, size_t n)
> > +{
> > +    const unsigned char *a = s1, *b = s2;
> > +    int ret = 0;
> > +
> > +    while (n--) {
> > +	ret = *a - *b;
> > +	if (ret)
> > +	    break;
> > +	++a, ++b;
> > +    }
> > +    return ret;
> > +}
> > +
> > +void *memmove(void *dest, const void *src, size_t n)
> > +{
> > +    const unsigned char *s = src;
> > +    unsigned char *d = dest;
> > +
> > +    if (d <= s) {
> > +	while (n--)
> > +	    *d++ = *s++;
> > +    } else {
> > +	d += n, s += n;
> > +	while (n--)
> > +	    *--d = *--s;
> > +    }
> > +    return dest;
> > +}
> > +
> > +void *memchr(const void *s, int c, size_t n)
> > +{
> > +    const unsigned char *str = s, chr = (unsigned char)c;
> > +
> > +    while (n--)
> > +	if (*str++ == chr)
> > +	    return (void *)(str - 1);
> > +    return NULL;
> > +}
> > +
> >  long atol(const char *ptr)
> >  {
> >      long acc = 0;
> > -- 
> > 1.8.1.4
> > 
> 
> Otherwise:
> 
> Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 11/17] add support for device trees
  2014-02-02  2:27   ` Christoffer Dall
@ 2014-02-03 15:31     ` Andrew Jones
  2014-02-03 16:36       ` Christoffer Dall
  0 siblings, 1 reply; 47+ messages in thread
From: Andrew Jones @ 2014-02-03 15:31 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: kvmarm, kvm

On Sat, Feb 01, 2014 at 06:27:15PM -0800, Christoffer Dall wrote:
> On Tue, Jan 21, 2014 at 05:21:57PM +0100, Andrew Jones wrote:
> > Add some device tree functions, built on libfdt, to the common
> > code in order to facilitate the extraction of boot info and device
> > base addresses. These functions are generic and arch-neutral. It's
> > expected that more functions will be added as more information
> > from the device tree is needed.
> 
> You're doing a bit more than that, you're introducing a couple of
> concepts such as a bus and reg structures, which are concepts above DT,
> which could use a bit of clarification.  In particular this patch is a
> bit hard to review on its own, because you cannot see how things are
> supposed to be used without looking at subsequent patches...

True, but I'm not sure how I can improve things, other than add some
better documentation to the code in this patch, which I'll do for v4.

> 
> I'm not a DT expert, but here goes the best I can do...
> 
> > 
> > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > ---
> >  lib/devicetree.c | 257 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  lib/devicetree.h |  95 ++++++++++++++++++++
> >  lib/libcflat.h   |   1 +
> >  3 files changed, 353 insertions(+)
> >  create mode 100644 lib/devicetree.c
> >  create mode 100644 lib/devicetree.h
> > 
> > diff --git a/lib/devicetree.c b/lib/devicetree.c
> > new file mode 100644
> > index 0000000000000..a9ab7ed367704
> > --- /dev/null
> > +++ b/lib/devicetree.c
> > @@ -0,0 +1,257 @@
> > +#include "libcflat.h"
> > +#include "libfdt/libfdt.h"
> > +#include "devicetree.h"
> > +
> > +static const void *fdt;
> > +
> > +const char *dt_strerror(int errval)
> > +{
> > +	if (errval == -EINVAL)
> > +		return "Invalid argument";
> > +	return fdt_strerror(errval);
> > +}
> > +
> > +int dt_set(const void *fdt_ptr)
> > +{
> > +	int ret = fdt_check_header(fdt_ptr);
> > +	if (ret == 0)
> > +		fdt = fdt_ptr;
> > +	return ret;
> > +}
> > +
> > +const void *dt_get(void)
> > +{
> > +	return fdt;
> > +}
> > +
> > +int dt_get_bootargs_ptr(char **bootargs)
> > +{
> > +	const struct fdt_property *prop;
> > +	int node, err;
> > +
> > +	node = fdt_path_offset(fdt, "/chosen");
> > +	if (node < 0)
> > +		return node;
> > +
> > +	prop = fdt_get_property(fdt, node, "bootargs", &err);
> > +	if (prop)
> > +		*bootargs = (char *)prop->data;
> > +	else if (err != -FDT_ERR_NOTFOUND)
> > +		return err;
> > +
> > +	return 0;
> > +}
> > +
> > +int dt_bus_default_match(const struct dt_bus *bus __unused,
> > +			 int nodeoffset __unused)
> > +{
> > +	/* just select first node found */
> > +	return 1;
> > +}
> > +
> > +int dt_bus_default_translate(const struct dt_bus *bus __unused,
> > +			     struct dt_reg *reg, void **addr, size_t *size)
> > +{
> 
> I don't think you want addr to be a void **, but a phys_addr_t, see note
> about ARM 32-bit LPAE below.

Oh right. I'll get this straightened out.

> 
> > +	u64 temp64;
> > +
> > +	if (!reg || !addr)
> > +		return -EINVAL;
> 
> defensive programming?

yeah, on second thought, it doesn't make sense to worry about this.
I'll rip all of it out.

> 
> > +
> > +	/*
> > +	 * default translate only understands u32 (<1> <1>) and
> > +	 * u64 (<2> <1>|<2>) addresses
> > +	 */
> > +	if (reg->nr_address_cells < 1
> > +			|| reg->nr_address_cells > 2
> > +			|| reg->nr_size_cells < 1
> > +			|| reg->nr_size_cells > 2)
> > +		return -EINVAL;
> > +
> > +	if (reg->nr_address_cells == 2)
> > +		temp64 = ((u64)reg->address_cells[0] << 32)
> > +					| reg->address_cells[1];
> > +	else
> > +		temp64 = reg->address_cells[0];
> 
> I would use braces on these statements given the multi-line first
> statement.
> 
> > +
> > +	/*
> > +	 * If we're 32-bit, then the upper word of a two word
> > +	 * address better be zero.
> > +	 */
> 
> not necessarily, on ARM 32-bit LPAE you have 40-bit physical addresses
> but 32-bit virtual address pointers...
> 
> > +	if (sizeof(void *) == sizeof(u32) && reg->nr_address_cells > 1
> > +			&& reg->address_cells[0] != 0)
> > +		return -EINVAL;
> > +
> > +	*addr = (void *)(unsigned long)temp64;
> > +
> > +	if (size) {
> > +		if (reg->nr_size_cells == 2)
> > +			temp64 = ((u64)reg->size_cells[0] << 32)
> > +						| reg->size_cells[1];
> > +		else
> > +			temp64 = reg->size_cells[0];
> > +
> > +		if (sizeof(size_t) == sizeof(u32) && reg->nr_size_cells > 1
> > +				&& reg->size_cells[0] != 0)
> > +			return -EINVAL;
> 
> same as above.
> 
> > +
> > +		*size = (size_t)temp64;
> 
> hmmm, I feel like I just read this code.  Maybe you can have a static
> little helper funciton to actually read your values.

ok

> 
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +const struct dt_bus dt_default_bus = {
> > +	.name = "default",
> > +	.match = dt_bus_default_match,
> > +	.translate = dt_bus_default_translate,
> > +};
> > +
> > +void dt_bus_init_defaults(struct dt_bus *bus, const char *name)
> > +{
> > +	*bus = dt_default_bus;
> > +	bus->name = name;
> > +}
> > +
> > +int dt_bus_find_device_compatible(const struct dt_bus *bus,
> > +				  const char *compatible)
> > +{
> > +	int node, ret;
> > +
> > +	if (!bus || !bus->match)
> > +		return -EINVAL;
> 
> see __dt_bus_translate_reg below
> 
> > +
> > +	node = fdt_node_offset_by_compatible(fdt, -1, compatible);
> > +
> > +	while (node >= 0) {
> > +		if ((ret = bus->match(bus, node)) < 0)
> > +			return ret;
> > +		else if (ret)
> > +			break;
> > +		node = fdt_node_offset_by_compatible(fdt, node, compatible);
> > +	}
> > +
> > +	return node;
> > +}
> > +
> > +static int __dt_get_num_cells(int node, u32 *address_cells, u32 *size_cells)
> > +{
> > +	const struct fdt_property *prop;
> > +	u32 *data;
> > +	int err;
> > +
> > +	prop = fdt_get_property(fdt, node, "#address-cells", &err);
> > +	if (!prop && err == -FDT_ERR_NOTFOUND) {
> > +
> > +		node = fdt_parent_offset(fdt, node);
> > +		if (node < 0)
> > +			return node;
> > +
> > +		return __dt_get_num_cells(node, address_cells, size_cells);
> 
> you're doing recursive calls with a severly limited stack space, you
> should probably at least check your depth and catch errors at a
> reasonable level.

Good point on the stack use. I'll get rid of the recursion.

> 
> It's probably cleaner to just have an iterative lookup of the node with
> #address_cells in it (in which you can also verify that is also has a
> #size-cells in it) and then pass that to the function that actually
> reads it.
> 
> > +
> > +	} else if (!prop) {
> > +		return err;
> > +	}
> > +
> > +	data = (u32 *)prop->data;
> > +	*address_cells = fdt32_to_cpu(*data);
> > +
> > +	prop = fdt_get_property(fdt, node, "#size-cells", &err);
> > +	if (!prop) {
> > +		printf("we can read #address-cells, but not #size-cells?\n");
> > +		return err;
> > +	}
> > +
> > +	data = (u32 *)prop->data;
> > +	*size_cells = fdt32_to_cpu(*data);
> > +
> > +	return 0;
> > +}
> > +
> > +int dt_get_num_cells(int nodeoffset, u32 *address_cells, u32 *size_cells)
> > +{
> > +	if (!address_cells || !size_cells)
> > +		return -EINVAL;
> 
> defensive programming?
> 
> > +	return __dt_get_num_cells(nodeoffset, address_cells, size_cells);
> > +}
> > +
> > +int dt_get_reg(int nodeoffset, int regidx, u32 *address_cells,
> > +	       u32 *size_cells, struct dt_reg *reg)
> > +{
> > +	const struct fdt_property *prop;
> > +	u32 *data, regsz, i;
> > +	int err;
> > +
> > +	if (!address_cells || !size_cells || !reg)
> > +		return -EINVAL;
> 
> defensive programming?
> 
> > +
> > +	memset(reg, 0, sizeof(struct dt_reg));
> 
> sizeof(*reg)
> 
> > +
> > +	/*
> > +	 * We assume #size-cells == 0 means translation is impossible,
> 
> hmm, this won't work for the cpus' reg properties for example.  I would
> just assume (and document) that this function always takes valid
> address_cells and size_cells (as u32 instead of u32 *).  I get that
> you're trying to do some caching (from reading later patches), but that
> should still be possible to do externally.

cpus will need their own 'dt_get_cpuids', built on a 'dt_for_each_cpu',
or some such, and wouldn't use this function. Other than cpus, I think
this is a safe convention. Although, that said, I'll look into cleaning
up the interface a bit, while maintaining ease of use and the ability to
cache.

> 
> If you really really want to, then you should use address_cells, but I'm
> not sure if it's actually valid for any bindings to have address_cells
> == 0 and size_cells >0.  If you have conventions like this, it should be
> clearly documented on the function itself!
> 
> > +	 * reserving it to indicate that we don't know what #address-cells
> > +	 * and #size-cells are yet, and thus must try to get them from the
> > +	 * parent.
> > +	 */
> > +	if (*size_cells == 0 && (err = dt_get_num_cells(nodeoffset,
> > +					address_cells, size_cells)) < 0)
> > +		return err;
> > +
> > +	prop = fdt_get_property(fdt, nodeoffset, "reg", &err);
> > +	if (prop == NULL)
> > +		return err;
> > +
> > +	regsz = (*address_cells + *size_cells) * sizeof(u32);
> > +
> > +	if ((regidx + 1) * regsz > prop->len)
> > +		return -EINVAL;
> > +
> > +	data = (u32 *)(prop->data + regidx * regsz);
> > +
> > +	for (i = 0; i < *address_cells; ++i, ++data)
> > +		reg->address_cells[i] = fdt32_to_cpu(*data);
> > +	for (i = 0; i < *size_cells; ++i, ++data)
> > +		reg->size_cells[i] = fdt32_to_cpu(*data);
> > +
> > +	reg->nr_address_cells = *address_cells;
> > +	reg->nr_size_cells = *size_cells;
> > +
> > +	return 0;
> > +}
> > +
> > +int __dt_bus_translate_reg(int nodeoffset, const struct dt_bus *bus,
> > +			   int regidx, u32 *address_cells, u32 *size_cells,
> > +			   void **addr, size_t *size)
> > +{
> > +	struct dt_reg reg;
> > +	int ret;
> > +
> > +	if (!bus || !bus->translate)
> > +		return -EINVAL;
> 
> The !bus seems overly defensive again.
> 
> The !bus->translate may be helpful here, but since we're returning a
> bunch of -EINVALs you should probably put a debug statement in the error
> catching part, so devs can easily enable debugging and figure out where
> things are going wrong.
> 
> That is, if anyone would ever call this with a bus without translate on
> there...
> 
> > +
> > +	ret = dt_get_reg(nodeoffset, regidx, address_cells, size_cells, &reg);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	return bus->translate(bus, &reg, addr, size);
> > +}
> > +
> > +int dt_bus_translate_reg(int nodeoffset, const struct dt_bus *bus,
> > +			 int regidx, void **addr, size_t *size)
> > +{
> > +	/*
> > +	 * size_cells == 0 tells dt_get_reg to get address_cells
> > +	 * and size_cells from the parent node
> > +	 */
> > +	u32 address_cells, size_cells = 0;
> > +	return __dt_bus_translate_reg(nodeoffset, bus, regidx,
> > +			&address_cells, &size_cells, addr, size);
> > +}
> > +
> > +int dt_get_memory_params(void **start, size_t *size)
> 
> again, memory can exit beyond the 32-bit mark on ARM LPAE systems.
> 
> > +{
> > +	int node = fdt_path_offset(fdt, "/memory");
> > +	if (node < 0)
> > +		return node;
> > +
> > +	return dt_bus_translate_reg(node, &dt_default_bus, 0, start, size);
> > +}
> > diff --git a/lib/devicetree.h b/lib/devicetree.h
> > new file mode 100644
> > index 0000000000000..1f2d61b46a308
> > --- /dev/null
> > +++ b/lib/devicetree.h
> > @@ -0,0 +1,95 @@
> > +#ifndef _DEVICETREE_H_
> > +#define _DEVICETREE_H_
> > +#include "libcflat.h"
> > +
> > +/*
> > + * set/get the fdt pointer
> > + */
> > +extern int dt_set(const void *fdt_ptr);
> > +extern const void *dt_get(void);
> > +
> > +/*
> > + * bootinfo accessors
> > + */
> > +extern int dt_get_bootargs_ptr(char **bootargs);
> > +extern int dt_get_memory_params(void **start, size_t *size);
> 
> There's no documentation to these functions?

I was thinking the names were self-documenting, but can add comments
above them with a couple more details.

> 
> > +
> > +#define MAX_ADDRESS_CELLS	4
> > +#define MAX_SIZE_CELLS		4
> > +struct dt_reg {
> > +	u32 nr_address_cells;
> > +	u32 nr_size_cells;
> > +	u32 address_cells[MAX_ADDRESS_CELLS];
> > +	u32 size_cells[MAX_SIZE_CELLS];
> > +};
> 
> dt_reg?  Is this for dt-bindings that specify the reg property?  A
> comment would be nice.

I would have liked this to be private to devicetree.c, but as
translate is bus specific we need a way for buses to get "raw"
regs from the dt. I'll comment this better.

> 
> > +
> > +struct dt_bus {
> > +	const char *name;
> > +	int (*match)(const struct dt_bus *bus, int nodeoffset);
> > +	/*
> > +	 * match() returns
> > +	 *  - a positive value on match
> > +	 *  - zero on no match
> > +	 *  - a negative value on error
> > +	 */
> 
> what does match do?  (I know by reading the code, but it should be
> documented)
> 
> consider using defines for the return values, so your client code can
> be:
> 
> if (bus->match(bus, node) == BUS_MATCH_SUCCESS)
> 	break;

ok

> 
> > +	int (*translate)(const struct dt_bus *bus, struct dt_reg *reg,
> > +			  void **addr, size_t *size);
> > +	/*
> > +	 * translate() returns
> > +	 *  - zero on success
> > +	 *  - a negative value on error
> > +	 */
> 
> ditto
> 
> > +	void *private;
> 
> what is this field meant to contain?  A hint about drivers passing
> information to translate() and match() would be helpful.

ok

> 
> > +};
> > +
> > +extern const struct dt_bus dt_default_bus;
> > +extern void dt_bus_init_defaults(struct dt_bus *bus, const char *name);
> > +extern int dt_bus_default_match(const struct dt_bus *bus, int nodeoffset);
> > +extern int dt_bus_default_translate(const struct dt_bus *bus,
> > +				    struct dt_reg *reg, void **addr,
> > +				    size_t *size);
> > +
> > +/*
> > + * find an fdt device node compatible with @compatible using match()
> > + * from the given bus @bus.
> > + */
> > +extern int dt_bus_find_device_compatible(const struct dt_bus *bus,
> > +					 const char *compatible);
> > +
> > +/*
> > + * translate the reg indexed by @regidx of the "reg" property of the
> > + * device node at @nodeoffset using translate() from the given bus @bus.
> > + * returns the translation in @addr and @size
> > + */
> 
> define 'translate' in the comment (into an address).

ok

> 
> > +extern int dt_bus_translate_reg(int nodeoffset, const struct dt_bus *bus,
> > +				int regidx, void **addr, size_t *size);
> > +
> > +/*
> > + * same as dt_bus_translate_reg, but uses the given @address_cells and
> > + * @size_cells rather than pulling them from the parent of @nodeoffset
> > + */
> > +extern int __dt_bus_translate_reg(int nodeoffset, const struct dt_bus *bus,
> > +				  int regidx, u32 *address_cells,
> > +				  u32 *size_cells, void **addr,
> > +				  size_t *size);
> > +
> > +/*
> > + * read the "reg" property of @nodeoffset, which is defined by @address_cells
> > + * and @size_cells, and store the reg indexed by @regidx into @reg
> > + */
> > +extern int dt_get_reg(int nodeoffset, int regidx, u32 *address_cells,
> > +		      u32 *size_cells, struct dt_reg *reg);
> > +
> > +/*
> > + * searches up the devicetree for @address_cells and @size_cells,
> > + * starting from @nodeoffset
> > + */
> > +extern int dt_find_num_cells(int nodeoffset, u32 *address_cells,
> > +			    u32 *size_cells);
> 
> not defined?

Oops, s/_find_/_get_/

> 
> > +
> > +/*
> > + * convert devicetree errors to strings
> > + */
> > +extern const char *dt_strerror(int errval);
> > +
> > +#endif
> > diff --git a/lib/libcflat.h b/lib/libcflat.h
> > index 2cde64a560956..fdaaf2a8ab31d 100644
> > --- a/lib/libcflat.h
> > +++ b/lib/libcflat.h
> > @@ -61,6 +61,7 @@ extern long atol(const char *ptr);
> >  
> >  #define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
> >  
> > +#define __unused __attribute__((__unused__))
> >  #define NULL ((void *)0UL)
> >  #include "errno.h"
> >  #endif
> > -- 
> > 1.8.1.4
> > 
> 
> Thanks,
> -- 
> Christoffer

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 12/17] Introduce virtio-testdev
  2014-02-02  2:27   ` Christoffer Dall
@ 2014-02-03 15:44     ` Andrew Jones
  2014-02-03 16:41       ` Christoffer Dall
  0 siblings, 1 reply; 47+ messages in thread
From: Andrew Jones @ 2014-02-03 15:44 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: kvmarm, kvm

On Sat, Feb 01, 2014 at 06:27:37PM -0800, Christoffer Dall wrote:
> On Tue, Jan 21, 2014 at 05:21:58PM +0100, Andrew Jones wrote:
> > virtio-testdev is a communication channel to qemu through virtio that
> > can be used by test code to send commands. The only command currently
> > implemented is EXIT, which allows the test code to exit with a given
> > status code.
> > 
> > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > 
> > ---
> > v3:
> >  - switched from iomaps to devicetree
> >  - fixed Christoffer's nits
> >  - don't call halt() explicitly, let exit() fall back to it
> >  - vm_{get,set} now {read,write} byte by byte like the kernel
> > v2:
> >  - use readl/writel framework (libio) [Christoffer Dall]
> >  - keep the virtio abstraction in virtio-testdev [Alexander Graf]
> > ---
> >  lib/libcflat.h       |   3 ++
> >  lib/virtio-testdev.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >  lib/virtio-testdev.h |   9 ++++
> >  lib/virtio.c         | 126 ++++++++++++++++++++++++++++++++++++++++++++++
> >  lib/virtio.h         |  74 +++++++++++++++++++++++++++
> >  5 files changed, 351 insertions(+)
> >  create mode 100644 lib/virtio-testdev.c
> >  create mode 100644 lib/virtio-testdev.h
> >  create mode 100644 lib/virtio.c
> >  create mode 100644 lib/virtio.h
> > 
> > diff --git a/lib/libcflat.h b/lib/libcflat.h
> > index fdaaf2a8ab31d..84b8783bacfdc 100644
> > --- a/lib/libcflat.h
> > +++ b/lib/libcflat.h
> > @@ -60,6 +60,9 @@ extern long atol(const char *ptr);
> >  #define ARRAY_SIZE(_a)  (sizeof(_a)/sizeof((_a)[0]))
> >  
> >  #define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
> > +#define container_of(ptr, type, member) ({				\
> > +		const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
> > +		(type *)( (char *)__mptr - offsetof(type,member) );})
> >  
> >  #define __unused __attribute__((__unused__))
> >  #define NULL ((void *)0UL)
> > diff --git a/lib/virtio-testdev.c b/lib/virtio-testdev.c
> > new file mode 100644
> > index 0000000000000..d4a69ede12a7a
> > --- /dev/null
> > +++ b/lib/virtio-testdev.c
> > @@ -0,0 +1,139 @@
> > +#include "libcflat.h"
> > +#include "virtio.h"
> > +
> > +#define TESTDEV_MAJOR_VER 1
> > +#define TESTDEV_MINOR_VER 1
> > +
> > +#define VIRTIO_ID_TESTDEV 0xffff
> > +
> > +#define CONFIG_SIZE 64
> > +
> > +enum {
> > +	VERSION = 1,
> > +	CLEAR,
> > +	EXIT,
> > +};
> > +
> > +#define TOKEN_OFFSET		0x0
> > +#define NARGS_OFFSET		0x4
> > +#define NRETS_OFFSET		0x8
> > +#define ARG_OFFSET(n)		(0xc + (n) * 4)
> > +#define __RET_OFFSET(nargs, n)	(ARG_OFFSET(nargs) + (n) * 4)
> > +
> > +static struct virtio_dev *testdev;
> > +
> > +static u32 testdev_readl(unsigned offset)
> > +{
> > +	if (offset > (CONFIG_SIZE - 4)) {
> > +		printf("%s: offset 0x%x to big!\n", __func__, offset);
> > +		exit(EINVAL);
> > +	}
> > +
> > +	return virtio_config_readl(testdev, offset);
> > +}
> > +
> > +static void testdev_writel(unsigned offset, u32 val)
> > +{
> > +	if (offset > (CONFIG_SIZE - 4)) {
> > +		printf("%s: offset 0x%x to big!\n", __func__, offset);
> > +		exit(EINVAL);
> > +	}
> > +
> > +	virtio_config_writel(testdev, offset, val);
> > +}
> > +
> > +/*
> > + * We have to write all args; nargs, nrets, ... first to avoid executing
> > + * the token's operation until all args are in place. Then issue the op,
> > + * and then read the return values. Reading the return values (or just
> > + * sanity checking by reading token) will read a zero into qemu's copy
> > + * of the token, which allows us to prepare additional ops without
> > + * re-executing the last one.
> > + */
> > +void virtio_testdev(u32 token, u32 nargs, u32 nrets, ...)
> > +{
> > +	va_list va;
> > +	unsigned off;
> > +	u32 n;
> > +
> > +	if (!testdev)
> > +		return;
> > +
> > +	testdev_writel(NARGS_OFFSET, nargs);
> > +	testdev_writel(NRETS_OFFSET, nrets);
> > +
> > +	va_start(va, nrets);
> > +
> > +	off = ARG_OFFSET(0);
> > +	n = nargs;
> > +	while (n--) {
> > +		testdev_writel(off, va_arg(va, unsigned));
> > +		off += 4;
> > +	}
> > +
> > +	/* this runs the op, but then resets token to zero */
> > +	testdev_writel(TOKEN_OFFSET, token);
> > +
> > +	/* sanity check */
> > +	if (testdev_readl(TOKEN_OFFSET) != 0) {
> > +		printf("virtio-testdev token should always read as zero!\n");
> > +		exit(EIO);
> > +	}
> > +
> > +	off = __RET_OFFSET(nargs, 0);
> > +	n = nrets;
> > +	while (n--) {
> > +		u32 *r = va_arg(va, unsigned *);
> > +		*r = testdev_readl(off);
> > +		off += 4;
> > +	}
> > +
> > +	va_end(va);
> > +}
> > +
> > +void virtio_testdev_version(u32 *version)
> > +{
> > +	virtio_testdev(VERSION, 0, 1, version);
> > +}
> > +
> > +void virtio_testdev_clear(void)
> > +{
> > +	virtio_testdev(CLEAR, 0, 0);
> > +}
> > +
> > +void virtio_testdev_exit(int code)
> > +{
> > +	virtio_testdev(EXIT, 1, 0, code);
> > +}
> > +
> > +void virtio_testdev_init(void)
> > +{
> > +	u16 major, minor;
> > +	u32 version;
> > +
> > +	testdev = virtio_bind(VIRTIO_ID_TESTDEV);
> > +	if (testdev == NULL) {
> > +		printf("Can't find virtio-testdev. "
> > +		       "Is '-device virtio-testdev' "
> > +		       "on the qemu command line?\n");
> > +		exit(ENODEV);
> > +	}
> > +
> > +	virtio_testdev_version(&version);
> > +	major = version >> 16;
> > +	minor = version & 0xffff;
> > +
> > +	if (major != TESTDEV_MAJOR_VER || minor < TESTDEV_MINOR_VER) {
> > +		char *u = "qemu";
> > +		if (major > TESTDEV_MAJOR_VER)
> > +			u = "kvm-unit-tests";
> > +		printf("Incompatible version of virtio-testdev: major = %d, "
> > +		       "minor = %d\n", major, minor);
> > +		printf("Update %s.\n", u);
> > +		exit(ENODEV);
> > +	}
> > +
> > +	if (minor > TESTDEV_MINOR_VER)
> > +		printf("testdev has new features. "
> > +		       "An update of kvm-unit-tests may be possible.\n");
> > +}
> > diff --git a/lib/virtio-testdev.h b/lib/virtio-testdev.h
> > new file mode 100644
> > index 0000000000000..c10bbfb591d0b
> > --- /dev/null
> > +++ b/lib/virtio-testdev.h
> > @@ -0,0 +1,9 @@
> > +#ifndef _VIRTIO_TESTDEV_H_
> > +#define _VIRTIO_TESTDEV_H_
> > +#include "libcflat.h"
> > +
> > +extern void virtio_testdev_init(void);
> > +extern void virtio_testdev_version(u32 *version);
> > +extern void virtio_testdev_clear(void);
> > +extern void virtio_testdev_exit(int code);
> > +#endif
> > diff --git a/lib/virtio.c b/lib/virtio.c
> > new file mode 100644
> > index 0000000000000..8abc8b2399a08
> > --- /dev/null
> > +++ b/lib/virtio.c
> > @@ -0,0 +1,126 @@
> > +#include "libcflat.h"
> > +#include "devicetree.h"
> > +#include "libio.h"
> > +#include "heap.h"
> > +#include "virtio.h"
> > +
> > +struct virtio_dt_device_data {
> > +	u32 device;
> > +	struct dt_bus *bus;
> > +	int node;
> > +	/* cached variables */
> > +	u32 address_cells, size_cells;
> > +};
> > +
> > +static void virtio_dt_device_data_init(struct virtio_dt_device_data *data,
> > +				       u32 device, struct dt_bus *bus)
> > +{
> > +	memset(data, 0, sizeof(struct virtio_dt_device_data));
> > +	data->device = device;
> > +	data->bus = bus;
> > +}
> > +
> > +static int vm_dt_bus_match(const struct dt_bus *bus, int nodeoffset);
> > +static struct virtio_dev *vm_bind(struct virtio_dt_device_data *data);
> > +
> > +struct virtio_dev *virtio_bind(u32 device)
> > +{
> > +	struct virtio_dt_device_data data;
> > +	struct dt_bus bus;
> > +	const char *compatible;
> > +
> > +	/*
> > +	 * currently we only support virtio-mmio
> > +	 */
> > +	compatible = "virtio,mmio";
> > +	dt_bus_init_defaults(&bus, compatible);
> > +	bus.match = vm_dt_bus_match;
> > +	bus.private = (void *)&data;
> > +	virtio_dt_device_data_init(&data, device, &bus);
> > +
> > +	data.node = dt_bus_find_device_compatible(&bus, compatible);
> > +	if (data.node < 0) {
> > +		printf("virtio bind for device id 0x%x failed, "
> > +		       "fdt_error: %s\n", device, dt_strerror(data.node));
> > +		return NULL;
> > +	}
> > +
> > +	return vm_bind(&data);
> > +}
> > +
> > +static int virtio_dt_bus_translate_reg(int nodeoffset,
> > +				       const struct dt_bus *bus,
> > +				       int regidx, void **addr,
> > +				       size_t *size)
> 
> so this is really virtio_dt_bus_get_addr right?

right. Actually, we could probably always assume regidx will be zero,
remove that param, and then rename this.

> 
> > +{
> > +	struct virtio_dt_device_data *data =
> > +		(struct virtio_dt_device_data *)bus->private;
> > +
> > +	return __dt_bus_translate_reg(nodeoffset, bus, regidx,
> > +			&data->address_cells, &data->size_cells, addr, size);
> > +}
> > +
> > +/******************************************************
> > + * virtio_mmio
> > + ******************************************************/
> > +
> > +static int vm_dt_bus_match(const struct dt_bus *bus, int nodeoffset)
> > +{
> > +	struct virtio_dt_device_data *data =
> > +		(struct virtio_dt_device_data *)bus->private;
> > +	void *addr;
> > +	int ret;
> > +
> > +	ret = virtio_dt_bus_translate_reg(nodeoffset, bus, 0, &addr, NULL);
> > +	if (ret < 0) {
> > +		printf("can't get reg! fdt_error: %s\n", dt_strerror(ret));
> > +		return ret;
> > +	}
> > +
> > +	return readl(addr + VIRTIO_MMIO_DEVICE_ID) == data->device;
> > +}
> > +
> > +#define to_virtio_mmio_dev(vdev_ptr) \
> > +	container_of(vdev_ptr, struct virtio_mmio_dev, vdev)
> > +
> > +static void vm_get(struct virtio_dev *vdev, unsigned offset,
> > +		   void *buf, unsigned len)
> > +{
> > +	struct virtio_mmio_dev *vmdev = to_virtio_mmio_dev(vdev);
> > +	u8 *p = buf;
> > +	unsigned i;
> > +
> > +	for (i = 0; i < len; ++i)
> > +		p[i] = readb(vmdev->base + VIRTIO_MMIO_CONFIG + offset + i);
> > +}
> > +
> > +static void vm_set(struct virtio_dev *vdev, unsigned offset,
> > +		   const void *buf, unsigned len)
> > +{
> > +	struct virtio_mmio_dev *vmdev = to_virtio_mmio_dev(vdev);
> > +	const u8 *p = buf;
> > +	unsigned i;
> > +
> > +	for (i = 0; i < len; ++i)
> > +		writeb(p[i], vmdev->base + VIRTIO_MMIO_CONFIG + offset + i);
> > +}
> > +
> > +static struct virtio_dev *vm_bind(struct virtio_dt_device_data *data)
> > +{
> > +	struct virtio_mmio_dev *vmdev;
> > +	void *page;
> > +
> > +	page = alloc_page();
> > +	vmdev = page;
> > +	vmdev->vdev.config = page + sizeof(struct virtio_mmio_dev);
> > +
> > +	vmdev->vdev.id.device = data->device;
> > +	vmdev->vdev.id.vendor = -1;
> > +	vmdev->vdev.config->get = vm_get;
> > +	vmdev->vdev.config->set = vm_set;
> > +
> > +	(void)virtio_dt_bus_translate_reg(data->node, data->bus, 0,
> > +						&vmdev->base, NULL);
> 
> didn't you already do this in vm_dt_bus_mach() ?

yes, but we didn't save the result, so we need to go back to the
node's reg property again and get it. At least we know which node
to go to and {address,size}_cells are cached. Hmm, we might as
well add an addr field to virtio_dt_device_data, allowing match
to save it there. I'll do that.

> 
> > +
> > +	return &vmdev->vdev;
> > +}
> > diff --git a/lib/virtio.h b/lib/virtio.h
> > new file mode 100644
> > index 0000000000000..c30a8dcd105cd
> > --- /dev/null
> > +++ b/lib/virtio.h
> > @@ -0,0 +1,74 @@
> > +#ifndef _VIRTIO_H_
> > +#define _VIRTIO_H_
> > +#include "libcflat.h"
> > +
> > +#define VIRTIO_MMIO_DEVICE_ID	0x008
> > +#define VIRTIO_MMIO_CONFIG	0x100
> > +
> > +struct virtio_devid {
> > +	u32 device;
> > +	u32 vendor;
> > +};
> > +
> > +struct virtio_dev {
> > +	struct virtio_devid id;
> > +	struct virtio_conf_ops *config;
> > +};
> > +
> > +struct virtio_conf_ops {
> > +	void (*get)(struct virtio_dev *vdev, unsigned offset,
> > +		    void *buf, unsigned len);
> > +	void (*set)(struct virtio_dev *vdev, unsigned offset,
> > +		    const void *buf, unsigned len);
> > +};
> > +
> > +struct virtio_mmio_dev {
> > +	struct virtio_dev vdev;
> > +	void *base;
> > +};
> > +
> > +static inline u8
> > +virtio_config_readb(struct virtio_dev *vdev, unsigned offset)
> > +{
> > +	u8 val;
> > +	vdev->config->get(vdev, offset, &val, 1);
> > +	return val;
> > +}
> > +
> > +static inline u16
> > +virtio_config_readw(struct virtio_dev *vdev, unsigned offset)
> > +{
> > +	u16 val;
> > +	vdev->config->get(vdev, offset, &val, 2);
> > +	return val;
> > +}
> > +
> > +static inline u32
> > +virtio_config_readl(struct virtio_dev *vdev, unsigned offset)
> > +{
> > +	u32 val;
> > +	vdev->config->get(vdev, offset, &val, 4);
> > +	return val;
> > +}
> > +
> > +static inline void
> > +virtio_config_writeb(struct virtio_dev *vdev, unsigned offset, u8 val)
> > +{
> > +	vdev->config->set(vdev, offset, &val, 1);
> > +}
> > +
> > +static inline void
> > +virtio_config_writew(struct virtio_dev *vdev, unsigned offset, u16 val)
> > +{
> > +	vdev->config->set(vdev, offset, &val, 2);
> > +}
> > +
> > +static inline void
> > +virtio_config_writel(struct virtio_dev *vdev, unsigned offset, u32 val)
> > +{
> > +	vdev->config->set(vdev, offset, &val, 4);
> > +}
> > +
> > +extern struct virtio_dev *virtio_bind(u32 device);
> > +
> > +#endif
> > -- 
> > 1.8.1.4
> > 
> 
> otherwise:
> 
> Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 13/17] arm: initial drop
  2014-02-02  2:28   ` Christoffer Dall
@ 2014-02-03 15:55     ` Andrew Jones
  0 siblings, 0 replies; 47+ messages in thread
From: Andrew Jones @ 2014-02-03 15:55 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: kvmarm, kvm

On Sat, Feb 01, 2014 at 06:28:26PM -0800, Christoffer Dall wrote:
> On Tue, Jan 21, 2014 at 05:21:59PM +0100, Andrew Jones wrote:
> > 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 <drjones@redhat.com>
> > 
> > ---
> 
> [...]
> 
> > 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;
> 
> const char *bootargs?

ok

> 
> > +
> > +static void read_bootinfo(const void *fdt)
> > +{
> > +	int ret;
> > +
> 
> [...]
> 
> Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 08/17] Introduce libio to common code for io read/write
  2014-02-03 13:51     ` Andrew Jones
@ 2014-02-03 16:30       ` Christoffer Dall
  0 siblings, 0 replies; 47+ messages in thread
From: Christoffer Dall @ 2014-02-03 16:30 UTC (permalink / raw)
  To: Andrew Jones; +Cc: kvmarm, kvm

On Mon, Feb 03, 2014 at 02:51:15PM +0100, Andrew Jones wrote:
> On Sat, Feb 01, 2014 at 06:24:51PM -0800, Christoffer Dall wrote:
> > On Tue, Jan 21, 2014 at 05:21:54PM +0100, Andrew Jones wrote:
> > > v3:
> > >  - get rid of CONFIG_64BIT, replace with asserts
> > >  - get rid of {read,write}_len()
> > >  - fix bad *64_to_cpu macros
> > 
> > note that putting the changelog after the "---" prevents it from
> > getting committed, but I'm not sure if there are different
> > conventions for the unit-tests framework.
> 
> I'll drop the '---' in the v4 patches
> 

no, I meant that the v3 changelog should be below the '---' not above it
- we don't want to commit a changelog to git.

> > 
> > > 
> > > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > > ---
> > >  lib/libio.h | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > >  1 file changed, 173 insertions(+)
> > >  create mode 100644 lib/libio.h
> > > 
> > > diff --git a/lib/libio.h b/lib/libio.h
> > > new file mode 100644
> > > index 0000000000000..6adc6a7bbee61
> > > --- /dev/null
> > > +++ b/lib/libio.h
> > > @@ -0,0 +1,173 @@
> > > +#ifndef _LIBIO_H_
> > > +#define _LIBIO_H_
> > > +/*
> > > + * Adapted from the Linux kernel's include/asm-generic/io.h and
> > > + * arch/arm/include/asm/io.h
> > > + */
> > > +#include "libcflat.h"
> > > +
> > > +#ifndef NDEBUG
> > > +#define LIBIO_ASSERT(expr) do { \
> > > +	if (!(expr)) printf("%s:%d: assert failed!\n", __FILE__, __LINE__);\
> > > +} while (0)
> > > +#else
> > > +#define LIBIO_ASSERT(expr) do { } while (0)
> > > +#endif
> > > +
> > > +typedef u32 compat_ptr_t;
> > > +
> > > +/*
> > > + * Use compat_ptr() on 64-bit arches when casting 32-bit
> > 
> > arches? architectures? archs?
> 
> kernel code has 88 archs and 55 arches, I guess we could go with
> archs by majority rules, but I prefer arches.
> 

fair enough, I associated a national park.  Bike shedding on my part
anyway.

> > 
> > > + * addresses to pointers in order to avoid compiler warnings.
> > > + */
> > > +static inline void *compat_ptr(compat_ptr_t ptr)
> > > +{
> > > +	return (void *)(unsigned long)ptr;
> > > +}
> > > +
> > > +static inline compat_ptr_t ptr_to_compat(void *ptr)
> > > +{
> > > +	return (u32)(unsigned long)ptr;
> > > +}
> > > +
> > > +#ifndef __raw_readb
> > > +static inline u8 __raw_readb(const volatile void *addr)
> > > +{
> > > +	return *(const volatile u8 *)addr;
> > > +}
> > > +#endif
> > > +
> > > +#ifndef __raw_readw
> > > +static inline u16 __raw_readw(const volatile void *addr)
> > > +{
> > > +	return *(const volatile u16 *)addr;
> > > +}
> > > +#endif
> > > +
> > > +#ifndef __raw_readl
> > > +static inline u32 __raw_readl(const volatile void *addr)
> > > +{
> > > +	return *(const volatile u32 *)addr;
> > > +}
> > > +#endif
> > > +
> > > +#ifndef __raw_readq
> > > +static inline u64 __raw_readq(const volatile void *addr)
> > > +{
> > > +	LIBIO_ASSERT(sizeof(unsigned long) == sizeof(u64));
> > > +	return *(const volatile u64 *)addr;
> > > +}
> > > +#endif
> > > +
> > > +#ifndef __raw_writeb
> > > +static inline void __raw_writeb(u8 b, volatile void *addr)
> > > +{
> > > +	*(volatile u8 *)addr = b;
> > > +}
> > > +#endif
> > > +
> > > +#ifndef __raw_writew
> > > +static inline void __raw_writew(u16 b, volatile void *addr)
> > > +{
> > > +	*(volatile u16 *)addr = b;
> > > +}
> > > +#endif
> > > +
> > > +#ifndef __raw_writel
> > > +static inline void __raw_writel(u32 b, volatile void *addr)
> > > +{
> > > +	*(volatile u32 *)addr = b;
> > > +}
> > > +#endif
> > > +
> > > +#ifndef __raw_writeq
> > > +static inline void __raw_writeq(u64 b, volatile void *addr)
> > > +{
> > > +	LIBIO_ASSERT(sizeof(unsigned long) == sizeof(u64));
> > > +	*(volatile u64 *)addr = b;
> > > +}
> > > +#endif
> > > +
> > > +#ifndef __bswap16
> > > +static inline u16 __bswap16(u16 x)
> > > +{
> > > +	return ((x >> 8) & 0xff) | ((x & 0xff) << 8);
> > > +}
> > > +#endif
> > > +
> > > +#ifndef __bswap32
> > > +static inline u32 __bswap32(u32 x)
> > > +{
> > > +	return ((x & 0xff000000) >> 24) | ((x & 0x00ff0000) >>  8) |
> > > +	       ((x & 0x0000ff00) <<  8) | ((x & 0x000000ff) << 24);
> > > +}
> > > +#endif
> > > +
> > > +#ifndef __bswap64
> > > +static inline u64 __bswap64(u64 x)
> > > +{
> > > +	return ((x & 0x00000000000000ffULL) << 56) |
> > > +	       ((x & 0x000000000000ff00ULL) << 40) |
> > > +	       ((x & 0x0000000000ff0000ULL) << 24) |
> > > +	       ((x & 0x00000000ff000000ULL) <<  8) |
> > > +	       ((x & 0x000000ff00000000ULL) >>  8) |
> > > +	       ((x & 0x0000ff0000000000ULL) >> 24) |
> > > +	       ((x & 0x00ff000000000000ULL) >> 40) |
> > > +	       ((x & 0xff00000000000000ULL) >> 56);
> > > +}
> > > +#endif
> > > +
> > > +#ifndef cpu_is_be
> > > +#define cpu_is_be 0
> > > +#endif
> > > +
> > > +#define le16_to_cpu(x) \
> > > +	({ u16 __r = cpu_is_be ? __bswap16(x) : (x); __r; })
> > > +#define cpu_to_le16 le16_to_cpu
> > > +
> > > +#define le32_to_cpu(x) \
> > > +	({ u32 __r = cpu_is_be ? __bswap32(x) : (x); __r; })
> > > +#define cpu_to_le32 le32_to_cpu
> > > +
> > > +#define le64_to_cpu(x) \
> > > +	({ u64 __r = cpu_is_be ? __bswap64(x) : (x); __r; })
> > > +#define cpu_to_le64 le64_to_cpu
> > > +
> > > +#define be16_to_cpu(x) \
> > > +	({ u16 __r = !cpu_is_be ? __bswap16(x) : (x); __r; })
> > > +#define cpu_to_be16 be16_to_cpu
> > > +
> > > +#define be32_to_cpu(x) \
> > > +	({ u32 __r = !cpu_is_be ? __bswap32(x) : (x); __r; })
> > > +#define cpu_to_be32 be32_to_cpu
> > > +
> > > +#define be64_to_cpu(x) \
> > > +	({ u64 __r = !cpu_is_be ? __bswap64(x) : (x); __r; })
> > > +#define cpu_to_be64 be64_to_cpu
> > > +
> > > +#ifndef rmb
> > > +#define rmb() do { } while (0)
> > > +#endif
> > > +#ifndef wmb
> > > +#define wmb() do { } while (0)
> > > +#endif
> > > +
> > > +#define readb(addr) \
> > > +	({ u8 __r = __raw_readb(addr); rmb(); __r; })
> > > +#define readw(addr) \
> > > +	({ u16 __r = le16_to_cpu(__raw_readw(addr)); rmb(); __r; })
> > > +#define readl(addr) \
> > > +	({ u32 __r = le32_to_cpu(__raw_readl(addr)); rmb(); __r; })
> > > +#define readq(addr) \
> > > +	({ u64 __r = le64_to_cpu(__raw_readq(addr)); rmb(); __r; })
> > > +
> > > +#define writeb(b, addr) \
> > > +	({ wmb(); __raw_writeb(b, addr); })
> > > +#define writew(b, addr) \
> > > +	({ wmb(); __raw_writew(cpu_to_le16(b), addr); })
> > > +#define writel(b, addr) \
> > > +	({ wmb(); __raw_writel(cpu_to_le32(b), addr); })
> > > +#define writeq(b, addr) \
> > > +	({ wmb(); __raw_writeq(cpu_to_le64(b), addr); })
> > > +
> > > +#endif
> > 
> > so these definitions always assume that your device is LE, which is
> > probably true for ARM and x86 for now, but if we ever use this on PPC or
> > want to test ARM BE with a BE QEMU, will it still work?
> 
> I don't know if it'll be an issue or not. Let's cross that bridge when we
> get to it. We can alway move/duplicate these accessors into each arch
> specific io.h file, when necessary.
> 

ok, I can live with that.

> > 
> > (There's some trickery with virtio and endianness that I don't remember
> > 100%, so if we assume this ever only reads and writes to virtio space,
> > we may be in the clear.)
> 
> The virtio spec is switching to everything LE, I believe, so the above
> should be good for virtio devices anyway.
> 
> 
yep.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 11/17] add support for device trees
  2014-02-03 15:31     ` Andrew Jones
@ 2014-02-03 16:36       ` Christoffer Dall
  0 siblings, 0 replies; 47+ messages in thread
From: Christoffer Dall @ 2014-02-03 16:36 UTC (permalink / raw)
  To: Andrew Jones; +Cc: kvmarm, kvm

On Mon, Feb 03, 2014 at 04:31:24PM +0100, Andrew Jones wrote:
> On Sat, Feb 01, 2014 at 06:27:15PM -0800, Christoffer Dall wrote:
> > On Tue, Jan 21, 2014 at 05:21:57PM +0100, Andrew Jones wrote:

[...]

> > > +
> > > +int dt_get_reg(int nodeoffset, int regidx, u32 *address_cells,
> > > +	       u32 *size_cells, struct dt_reg *reg)
> > > +{
> > > +	const struct fdt_property *prop;
> > > +	u32 *data, regsz, i;
> > > +	int err;
> > > +
> > > +	if (!address_cells || !size_cells || !reg)
> > > +		return -EINVAL;
> > 
> > defensive programming?
> > 
> > > +
> > > +	memset(reg, 0, sizeof(struct dt_reg));
> > 
> > sizeof(*reg)
> > 
> > > +
> > > +	/*
> > > +	 * We assume #size-cells == 0 means translation is impossible,
> > 
> > hmm, this won't work for the cpus' reg properties for example.  I would
> > just assume (and document) that this function always takes valid
> > address_cells and size_cells (as u32 instead of u32 *).  I get that
> > you're trying to do some caching (from reading later patches), but that
> > should still be possible to do externally.
> 
> cpus will need their own 'dt_get_cpuids', built on a 'dt_for_each_cpu',
> or some such, and wouldn't use this function. Other than cpus, I think
> this is a safe convention. Although, that said, I'll look into cleaning
> up the interface a bit, while maintaining ease of use and the ability to
> cache.
> 

well, your function is called dt_get_reg and is generally exported from
lib/devicetree.c, so there's nothing here suggesting this can only be
used for a reg property for a certain type of devices.  cpus is an
example of a node that has #size-cells == 0 and has a perfectly valid
reg property.

The fact that you don't plan on using this function to iterate CPUs
doesn't mean that somebody else will not, or we will add another binding
that will use same convention, and now this funciton has to be
refactored.

If this function was virtio_get_reg, it would be a different story...

> > 
> > If you really really want to, then you should use address_cells, but I'm
> > not sure if it's actually valid for any bindings to have address_cells
> > == 0 and size_cells >0.  If you have conventions like this, it should be
> > clearly documented on the function itself!
> > 

[...]

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 12/17] Introduce virtio-testdev
  2014-02-03 15:44     ` Andrew Jones
@ 2014-02-03 16:41       ` Christoffer Dall
  0 siblings, 0 replies; 47+ messages in thread
From: Christoffer Dall @ 2014-02-03 16:41 UTC (permalink / raw)
  To: Andrew Jones; +Cc: kvmarm, kvm

On Mon, Feb 03, 2014 at 04:44:31PM +0100, Andrew Jones wrote:
> On Sat, Feb 01, 2014 at 06:27:37PM -0800, Christoffer Dall wrote:
> > On Tue, Jan 21, 2014 at 05:21:58PM +0100, Andrew Jones wrote:
> > > virtio-testdev is a communication channel to qemu through virtio that
> > > can be used by test code to send commands. The only command currently
> > > implemented is EXIT, which allows the test code to exit with a given
> > > status code.
> > > 
> > > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > > 
> > > ---
> > > v3:
> > >  - switched from iomaps to devicetree
> > >  - fixed Christoffer's nits
> > >  - don't call halt() explicitly, let exit() fall back to it
> > >  - vm_{get,set} now {read,write} byte by byte like the kernel
> > > v2:
> > >  - use readl/writel framework (libio) [Christoffer Dall]
> > >  - keep the virtio abstraction in virtio-testdev [Alexander Graf]
> > > ---
> > >  lib/libcflat.h       |   3 ++
> > >  lib/virtio-testdev.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++
> > >  lib/virtio-testdev.h |   9 ++++
> > >  lib/virtio.c         | 126 ++++++++++++++++++++++++++++++++++++++++++++++
> > >  lib/virtio.h         |  74 +++++++++++++++++++++++++++
> > >  5 files changed, 351 insertions(+)
> > >  create mode 100644 lib/virtio-testdev.c
> > >  create mode 100644 lib/virtio-testdev.h
> > >  create mode 100644 lib/virtio.c
> > >  create mode 100644 lib/virtio.h
> > > 
> > > diff --git a/lib/libcflat.h b/lib/libcflat.h
> > > index fdaaf2a8ab31d..84b8783bacfdc 100644
> > > --- a/lib/libcflat.h
> > > +++ b/lib/libcflat.h
> > > @@ -60,6 +60,9 @@ extern long atol(const char *ptr);
> > >  #define ARRAY_SIZE(_a)  (sizeof(_a)/sizeof((_a)[0]))
> > >  
> > >  #define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
> > > +#define container_of(ptr, type, member) ({				\
> > > +		const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
> > > +		(type *)( (char *)__mptr - offsetof(type,member) );})
> > >  
> > >  #define __unused __attribute__((__unused__))
> > >  #define NULL ((void *)0UL)
> > > diff --git a/lib/virtio-testdev.c b/lib/virtio-testdev.c
> > > new file mode 100644
> > > index 0000000000000..d4a69ede12a7a
> > > --- /dev/null
> > > +++ b/lib/virtio-testdev.c
> > > @@ -0,0 +1,139 @@
> > > +#include "libcflat.h"
> > > +#include "virtio.h"
> > > +
> > > +#define TESTDEV_MAJOR_VER 1
> > > +#define TESTDEV_MINOR_VER 1
> > > +
> > > +#define VIRTIO_ID_TESTDEV 0xffff
> > > +
> > > +#define CONFIG_SIZE 64
> > > +
> > > +enum {
> > > +	VERSION = 1,
> > > +	CLEAR,
> > > +	EXIT,
> > > +};
> > > +
> > > +#define TOKEN_OFFSET		0x0
> > > +#define NARGS_OFFSET		0x4
> > > +#define NRETS_OFFSET		0x8
> > > +#define ARG_OFFSET(n)		(0xc + (n) * 4)
> > > +#define __RET_OFFSET(nargs, n)	(ARG_OFFSET(nargs) + (n) * 4)
> > > +
> > > +static struct virtio_dev *testdev;
> > > +
> > > +static u32 testdev_readl(unsigned offset)
> > > +{
> > > +	if (offset > (CONFIG_SIZE - 4)) {
> > > +		printf("%s: offset 0x%x to big!\n", __func__, offset);
> > > +		exit(EINVAL);
> > > +	}
> > > +
> > > +	return virtio_config_readl(testdev, offset);
> > > +}
> > > +
> > > +static void testdev_writel(unsigned offset, u32 val)
> > > +{
> > > +	if (offset > (CONFIG_SIZE - 4)) {
> > > +		printf("%s: offset 0x%x to big!\n", __func__, offset);
> > > +		exit(EINVAL);
> > > +	}
> > > +
> > > +	virtio_config_writel(testdev, offset, val);
> > > +}
> > > +
> > > +/*
> > > + * We have to write all args; nargs, nrets, ... first to avoid executing
> > > + * the token's operation until all args are in place. Then issue the op,
> > > + * and then read the return values. Reading the return values (or just
> > > + * sanity checking by reading token) will read a zero into qemu's copy
> > > + * of the token, which allows us to prepare additional ops without
> > > + * re-executing the last one.
> > > + */
> > > +void virtio_testdev(u32 token, u32 nargs, u32 nrets, ...)
> > > +{
> > > +	va_list va;
> > > +	unsigned off;
> > > +	u32 n;
> > > +
> > > +	if (!testdev)
> > > +		return;
> > > +
> > > +	testdev_writel(NARGS_OFFSET, nargs);
> > > +	testdev_writel(NRETS_OFFSET, nrets);
> > > +
> > > +	va_start(va, nrets);
> > > +
> > > +	off = ARG_OFFSET(0);
> > > +	n = nargs;
> > > +	while (n--) {
> > > +		testdev_writel(off, va_arg(va, unsigned));
> > > +		off += 4;
> > > +	}
> > > +
> > > +	/* this runs the op, but then resets token to zero */
> > > +	testdev_writel(TOKEN_OFFSET, token);
> > > +
> > > +	/* sanity check */
> > > +	if (testdev_readl(TOKEN_OFFSET) != 0) {
> > > +		printf("virtio-testdev token should always read as zero!\n");
> > > +		exit(EIO);
> > > +	}
> > > +
> > > +	off = __RET_OFFSET(nargs, 0);
> > > +	n = nrets;
> > > +	while (n--) {
> > > +		u32 *r = va_arg(va, unsigned *);
> > > +		*r = testdev_readl(off);
> > > +		off += 4;
> > > +	}
> > > +
> > > +	va_end(va);
> > > +}
> > > +
> > > +void virtio_testdev_version(u32 *version)
> > > +{
> > > +	virtio_testdev(VERSION, 0, 1, version);
> > > +}
> > > +
> > > +void virtio_testdev_clear(void)
> > > +{
> > > +	virtio_testdev(CLEAR, 0, 0);
> > > +}
> > > +
> > > +void virtio_testdev_exit(int code)
> > > +{
> > > +	virtio_testdev(EXIT, 1, 0, code);
> > > +}
> > > +
> > > +void virtio_testdev_init(void)
> > > +{
> > > +	u16 major, minor;
> > > +	u32 version;
> > > +
> > > +	testdev = virtio_bind(VIRTIO_ID_TESTDEV);
> > > +	if (testdev == NULL) {
> > > +		printf("Can't find virtio-testdev. "
> > > +		       "Is '-device virtio-testdev' "
> > > +		       "on the qemu command line?\n");
> > > +		exit(ENODEV);
> > > +	}
> > > +
> > > +	virtio_testdev_version(&version);
> > > +	major = version >> 16;
> > > +	minor = version & 0xffff;
> > > +
> > > +	if (major != TESTDEV_MAJOR_VER || minor < TESTDEV_MINOR_VER) {
> > > +		char *u = "qemu";
> > > +		if (major > TESTDEV_MAJOR_VER)
> > > +			u = "kvm-unit-tests";
> > > +		printf("Incompatible version of virtio-testdev: major = %d, "
> > > +		       "minor = %d\n", major, minor);
> > > +		printf("Update %s.\n", u);
> > > +		exit(ENODEV);
> > > +	}
> > > +
> > > +	if (minor > TESTDEV_MINOR_VER)
> > > +		printf("testdev has new features. "
> > > +		       "An update of kvm-unit-tests may be possible.\n");
> > > +}
> > > diff --git a/lib/virtio-testdev.h b/lib/virtio-testdev.h
> > > new file mode 100644
> > > index 0000000000000..c10bbfb591d0b
> > > --- /dev/null
> > > +++ b/lib/virtio-testdev.h
> > > @@ -0,0 +1,9 @@
> > > +#ifndef _VIRTIO_TESTDEV_H_
> > > +#define _VIRTIO_TESTDEV_H_
> > > +#include "libcflat.h"
> > > +
> > > +extern void virtio_testdev_init(void);
> > > +extern void virtio_testdev_version(u32 *version);
> > > +extern void virtio_testdev_clear(void);
> > > +extern void virtio_testdev_exit(int code);
> > > +#endif
> > > diff --git a/lib/virtio.c b/lib/virtio.c
> > > new file mode 100644
> > > index 0000000000000..8abc8b2399a08
> > > --- /dev/null
> > > +++ b/lib/virtio.c
> > > @@ -0,0 +1,126 @@
> > > +#include "libcflat.h"
> > > +#include "devicetree.h"
> > > +#include "libio.h"
> > > +#include "heap.h"
> > > +#include "virtio.h"
> > > +
> > > +struct virtio_dt_device_data {
> > > +	u32 device;
> > > +	struct dt_bus *bus;
> > > +	int node;
> > > +	/* cached variables */
> > > +	u32 address_cells, size_cells;
> > > +};
> > > +
> > > +static void virtio_dt_device_data_init(struct virtio_dt_device_data *data,
> > > +				       u32 device, struct dt_bus *bus)
> > > +{
> > > +	memset(data, 0, sizeof(struct virtio_dt_device_data));
> > > +	data->device = device;
> > > +	data->bus = bus;
> > > +}
> > > +
> > > +static int vm_dt_bus_match(const struct dt_bus *bus, int nodeoffset);
> > > +static struct virtio_dev *vm_bind(struct virtio_dt_device_data *data);
> > > +
> > > +struct virtio_dev *virtio_bind(u32 device)
> > > +{
> > > +	struct virtio_dt_device_data data;
> > > +	struct dt_bus bus;
> > > +	const char *compatible;
> > > +
> > > +	/*
> > > +	 * currently we only support virtio-mmio
> > > +	 */
> > > +	compatible = "virtio,mmio";
> > > +	dt_bus_init_defaults(&bus, compatible);
> > > +	bus.match = vm_dt_bus_match;
> > > +	bus.private = (void *)&data;
> > > +	virtio_dt_device_data_init(&data, device, &bus);
> > > +
> > > +	data.node = dt_bus_find_device_compatible(&bus, compatible);
> > > +	if (data.node < 0) {
> > > +		printf("virtio bind for device id 0x%x failed, "
> > > +		       "fdt_error: %s\n", device, dt_strerror(data.node));
> > > +		return NULL;
> > > +	}
> > > +
> > > +	return vm_bind(&data);
> > > +}
> > > +
> > > +static int virtio_dt_bus_translate_reg(int nodeoffset,
> > > +				       const struct dt_bus *bus,
> > > +				       int regidx, void **addr,
> > > +				       size_t *size)
> > 
> > so this is really virtio_dt_bus_get_addr right?
> 
> right. Actually, we could probably always assume regidx will be zero,
> remove that param, and then rename this.
> 
> > 
> > > +{
> > > +	struct virtio_dt_device_data *data =
> > > +		(struct virtio_dt_device_data *)bus->private;
> > > +
> > > +	return __dt_bus_translate_reg(nodeoffset, bus, regidx,
> > > +			&data->address_cells, &data->size_cells, addr, size);
> > > +}
> > > +
> > > +/******************************************************
> > > + * virtio_mmio
> > > + ******************************************************/
> > > +
> > > +static int vm_dt_bus_match(const struct dt_bus *bus, int nodeoffset)
> > > +{
> > > +	struct virtio_dt_device_data *data =
> > > +		(struct virtio_dt_device_data *)bus->private;
> > > +	void *addr;
> > > +	int ret;
> > > +
> > > +	ret = virtio_dt_bus_translate_reg(nodeoffset, bus, 0, &addr, NULL);
> > > +	if (ret < 0) {
> > > +		printf("can't get reg! fdt_error: %s\n", dt_strerror(ret));
> > > +		return ret;
> > > +	}
> > > +
> > > +	return readl(addr + VIRTIO_MMIO_DEVICE_ID) == data->device;
> > > +}
> > > +
> > > +#define to_virtio_mmio_dev(vdev_ptr) \
> > > +	container_of(vdev_ptr, struct virtio_mmio_dev, vdev)
> > > +
> > > +static void vm_get(struct virtio_dev *vdev, unsigned offset,
> > > +		   void *buf, unsigned len)
> > > +{
> > > +	struct virtio_mmio_dev *vmdev = to_virtio_mmio_dev(vdev);
> > > +	u8 *p = buf;
> > > +	unsigned i;
> > > +
> > > +	for (i = 0; i < len; ++i)
> > > +		p[i] = readb(vmdev->base + VIRTIO_MMIO_CONFIG + offset + i);
> > > +}
> > > +
> > > +static void vm_set(struct virtio_dev *vdev, unsigned offset,
> > > +		   const void *buf, unsigned len)
> > > +{
> > > +	struct virtio_mmio_dev *vmdev = to_virtio_mmio_dev(vdev);
> > > +	const u8 *p = buf;
> > > +	unsigned i;
> > > +
> > > +	for (i = 0; i < len; ++i)
> > > +		writeb(p[i], vmdev->base + VIRTIO_MMIO_CONFIG + offset + i);
> > > +}
> > > +
> > > +static struct virtio_dev *vm_bind(struct virtio_dt_device_data *data)
> > > +{
> > > +	struct virtio_mmio_dev *vmdev;
> > > +	void *page;
> > > +
> > > +	page = alloc_page();
> > > +	vmdev = page;
> > > +	vmdev->vdev.config = page + sizeof(struct virtio_mmio_dev);
> > > +
> > > +	vmdev->vdev.id.device = data->device;
> > > +	vmdev->vdev.id.vendor = -1;
> > > +	vmdev->vdev.config->get = vm_get;
> > > +	vmdev->vdev.config->set = vm_set;
> > > +
> > > +	(void)virtio_dt_bus_translate_reg(data->node, data->bus, 0,
> > > +						&vmdev->base, NULL);
> > 
> > didn't you already do this in vm_dt_bus_mach() ?
> 
> yes, but we didn't save the result, so we need to go back to the
> node's reg property again and get it. At least we know which node
> to go to and {address,size}_cells are cached. Hmm, we might as
> well add an addr field to virtio_dt_device_data, allowing match
> to save it there. I'll do that.
> 

on second read, either way will work.  Perhaps just a comment explaining
why we read out data twice would work otherwise.  Up to you.

> > 
> > > +
> > > +	return &vmdev->vdev;
> > > +}
> > > diff --git a/lib/virtio.h b/lib/virtio.h
> > > new file mode 100644
> > > index 0000000000000..c30a8dcd105cd
> > > --- /dev/null
> > > +++ b/lib/virtio.h
> > > @@ -0,0 +1,74 @@
> > > +#ifndef _VIRTIO_H_
> > > +#define _VIRTIO_H_
> > > +#include "libcflat.h"
> > > +
> > > +#define VIRTIO_MMIO_DEVICE_ID	0x008
> > > +#define VIRTIO_MMIO_CONFIG	0x100
> > > +
> > > +struct virtio_devid {
> > > +	u32 device;
> > > +	u32 vendor;
> > > +};
> > > +
> > > +struct virtio_dev {
> > > +	struct virtio_devid id;
> > > +	struct virtio_conf_ops *config;
> > > +};
> > > +
> > > +struct virtio_conf_ops {
> > > +	void (*get)(struct virtio_dev *vdev, unsigned offset,
> > > +		    void *buf, unsigned len);
> > > +	void (*set)(struct virtio_dev *vdev, unsigned offset,
> > > +		    const void *buf, unsigned len);
> > > +};
> > > +
> > > +struct virtio_mmio_dev {
> > > +	struct virtio_dev vdev;
> > > +	void *base;
> > > +};
> > > +
> > > +static inline u8
> > > +virtio_config_readb(struct virtio_dev *vdev, unsigned offset)
> > > +{
> > > +	u8 val;
> > > +	vdev->config->get(vdev, offset, &val, 1);
> > > +	return val;
> > > +}
> > > +
> > > +static inline u16
> > > +virtio_config_readw(struct virtio_dev *vdev, unsigned offset)
> > > +{
> > > +	u16 val;
> > > +	vdev->config->get(vdev, offset, &val, 2);
> > > +	return val;
> > > +}
> > > +
> > > +static inline u32
> > > +virtio_config_readl(struct virtio_dev *vdev, unsigned offset)
> > > +{
> > > +	u32 val;
> > > +	vdev->config->get(vdev, offset, &val, 4);
> > > +	return val;
> > > +}
> > > +
> > > +static inline void
> > > +virtio_config_writeb(struct virtio_dev *vdev, unsigned offset, u8 val)
> > > +{
> > > +	vdev->config->set(vdev, offset, &val, 1);
> > > +}
> > > +
> > > +static inline void
> > > +virtio_config_writew(struct virtio_dev *vdev, unsigned offset, u16 val)
> > > +{
> > > +	vdev->config->set(vdev, offset, &val, 2);
> > > +}
> > > +
> > > +static inline void
> > > +virtio_config_writel(struct virtio_dev *vdev, unsigned offset, u32 val)
> > > +{
> > > +	vdev->config->set(vdev, offset, &val, 4);
> > > +}
> > > +
> > > +extern struct virtio_dev *virtio_bind(u32 device);
> > > +
> > > +#endif
> > > -- 
> > > 1.8.1.4
> > > 
> > 
> > otherwise:
> > 
> > Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 16/17] arm: add useful headers from the linux kernel
  2014-02-02  2:29   ` Christoffer Dall
@ 2014-02-03 16:46     ` Andrew Jones
  2014-02-03 17:38       ` Christoffer Dall
  0 siblings, 1 reply; 47+ messages in thread
From: Andrew Jones @ 2014-02-03 16:46 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: kvmarm, kvm

On Sat, Feb 01, 2014 at 06:29:05PM -0800, Christoffer Dall wrote:
> On Tue, Jan 21, 2014 at 05:22:02PM +0100, Andrew Jones wrote:
> > We're going to need PSR bit defines and pt_regs. We'll also need
> > pt_regs offsets in assembly code. This patch adapts the linux
> > kernel's ptrace.h and asm-offsets to this framework. Even though
> > lib/arm/asm-offsets.h is a generated file, we still commit it,
> > as it's unlikely to change. Also adapt cp15.h from the kernel,
> > since we'll need bit defines from there too.
> > 
> > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > ---
> 
> [...]
> 
> > +
> > +asm-offsets: scripts/arm/asm-offsets.flat
> > +	$(QEMU) -device virtio-testdev -display none -serial stdio \
> > +		-M virt -cpu $(PROCESSOR) \
> > +		-kernel $^ > lib/arm/asm-offsets.h || true
> 
> I still disagree with this requirement to have the correct version of
> qemu on the build machine.

Ah sorry, I forgot about this one. I'll steal more from the kernel
on the asm-offsets generation to improve this for v4.


> 
> [...]
> 
> -Christoffer

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 17/17] arm: vectors support
  2014-02-02  2:29   ` Christoffer Dall
@ 2014-02-03 16:50     ` Andrew Jones
  2014-02-03 21:19       ` Christoffer Dall
  0 siblings, 1 reply; 47+ messages in thread
From: Andrew Jones @ 2014-02-03 16:50 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: kvmarm, kvm

On Sat, Feb 01, 2014 at 06:29:27PM -0800, Christoffer Dall wrote:
> On Tue, Jan 21, 2014 at 05:22:03PM +0100, Andrew Jones wrote:
> > Add support for tests to use exception handlers.
> > 
> > v2 -> v3:
> > - squashed in 'arm: Simplify exceptions_init in cstart.S' from
> >   Christoffer Dall
> > - suggested function name changes and comment additions [Christoffer Dall]
> > - fix a bug with stack restore from usr mode exceptions that Christoffer
> >   pointed out. Add a get_sp() accessor too.
> 
> hmmm, how did you address this, the only change I can see is using r6
> instead of r2, which I'm not sure how changes anything.

It also adds

	/* make sure we restore sp_svc and lr_svc on mode change */
	str	r6, [sp, #S_SP]
	str	lr, [sp, #S_LR]

lower down. Needed to switch to r6 from r2 for that

> 
> The problem is that your ldmia is replacing the usr sp, not the svc sp,
> so maybe you need to do ldmia sp!, [ r0 - pc ]^ (don't remember if that
> particular combination works) or you need to do something more fancy...

I'm not sure about the magic ! + ^ stuff, but what I've done does fix
the problem. I tested before/after the fix (actually that's why I also
added the get_sp).

> 
> Otherwise this is looking good.

Thanks!! v4 coming soon.

> 
> Thanks,
> Christoffer
> 
> > 
> > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > ---
> >  arm/cstart.S          | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++
> >  arm/flat.lds          |   7 ++-
> >  arm/selftest.c        | 119 +++++++++++++++++++++++++++++++++++
> >  arm/unittests.cfg     |  20 +++++-
> >  config/config-arm.mak |   1 +
> >  lib/arm/processor.c   | 103 +++++++++++++++++++++++++++++++
> >  lib/arm/processor.h   |  35 +++++++++++
> >  lib/libcflat.h        |   2 +
> >  8 files changed, 453 insertions(+), 2 deletions(-)
> >  create mode 100644 lib/arm/processor.c
> >  create mode 100644 lib/arm/processor.h
> > 
> > diff --git a/arm/cstart.S b/arm/cstart.S
> > index 4de04b62c28c2..74674fd41c1b3 100644
> > --- a/arm/cstart.S
> > +++ b/arm/cstart.S
> > @@ -1,3 +1,7 @@
> > +#define __ASSEMBLY__
> > +#include "arm/asm-offsets.h"
> > +#include "arm/ptrace.h"
> > +#include "arm/cp15.h"
> >  
> >  .arm
> >  
> > @@ -10,6 +14,13 @@ start:
> >  	 * See the kernel doc Documentation/arm/Booting
> >  	 */
> >  	ldr	sp, =stacktop
> > +	push	{r0-r3}
> > +
> > +	/* set up vector table and mode stacks */
> > +	bl	exceptions_init
> > +
> > +	/* complete setup */
> > +	pop	{r0-r3}
> >  	bl	setup
> >  
> >  	/* start the test */
> > @@ -20,9 +31,166 @@ start:
> >  	bl	exit
> >  	b	halt
> >  
> > +.macro set_mode_stack mode, stack
> > +	add	\stack, #S_FRAME_SIZE
> > +	msr	cpsr_c, #(\mode | PSR_I_BIT | PSR_F_BIT)
> > +	mov	sp, \stack
> > +.endm
> > +
> > +exceptions_init:
> > +	mrc	p15, 0, r2, c1, c0, 0	@ read SCTLR
> > +	bic	r2, #CR_V		@ SCTLR.V := 0
> > +	mcr	p15, 0, r2, c1, c0, 0	@ write SCTLR
> > +	ldr	r2, =vector_table
> > +	mcr	p15, 0, r2, c12, c0, 0	@ write VBAR
> > +
> > +	mrs	r2, cpsr
> > +	ldr	r1, =exception_stacks
> > +		/* first frame for svc mode */
> > +	set_mode_stack	UND_MODE, r1
> > +	set_mode_stack	ABT_MODE, r1
> > +	set_mode_stack	IRQ_MODE, r1
> > +	set_mode_stack	FIQ_MODE, r1
> > +	msr	cpsr_cxsf, r2	@ back to svc mode
> > +	mov	pc, lr
> > +
> >  .text
> >  
> >  .globl halt
> >  halt:
> >  1:	wfi
> >  	b	1b
> > +
> > +/*
> > + * Vector stubs.
> > + * Simplified version of the Linux kernel implementation
> > + *   arch/arm/kernel/entry-armv.S
> > + *
> > + * Each mode has an S_FRAME_SIZE sized stack initialized
> > + * in exceptions_init
> > + */
> > +.macro vector_stub, name, vec, mode, correction=0
> > +.align 5
> > +vector_\name:
> > +.if \correction
> > +	sub	lr, lr, #\correction
> > +.endif
> > +	/*
> > +	 * Save r0, r1, lr_<exception> (parent PC)
> > +	 * and spsr_<exception> (parent CPSR)
> > +	 */
> > +	str	r0, [sp, #S_R0]
> > +	str	r1, [sp, #S_R1]
> > +	str	lr, [sp, #S_PC]
> > +	mrs	r0, spsr
> > +	str	r0, [sp, #S_PSR]
> > +
> > +	/* Prepare for SVC32 mode. */
> > +	mrs	r0, cpsr
> > +	bic	r0, #MODE_MASK
> > +	orr	r0, #SVC_MODE
> > +	msr	spsr_cxsf, r0
> > +
> > +	/* Branch to handler in SVC mode */
> > +	mov	r0, #\vec
> > +	mov	r1, sp
> > +	ldr	lr, =vector_common
> > +	movs	pc, lr
> > +.endm
> > +
> > +vector_stub 	rst,	0, UND_MODE
> > +vector_stub	und,	1, UND_MODE
> > +vector_stub	pabt,	3, ABT_MODE, 4
> > +vector_stub	dabt,	4, ABT_MODE, 8
> > +vector_stub	irq,	6, IRQ_MODE, 4
> > +vector_stub	fiq,	7, FIQ_MODE, 4
> > +
> > +.align 5
> > +vector_svc:
> > +	/*
> > +	 * Save r0, r1, lr_<exception> (parent PC)
> > +	 * and spsr_<exception> (parent CPSR)
> > +	 */
> > +	push	{ r1 }
> > +	ldr	r1, =exception_stacks
> > +	str	r0, [r1, #S_R0]
> > +	pop	{ r0 }
> > +	str	r0, [r1, #S_R1]
> > +	str	lr, [r1, #S_PC]
> > +	mrs	r0, spsr
> > +	str	r0, [r1, #S_PSR]
> > +
> > +	/*
> > +	 * Branch to handler, still in SVC mode.
> > +	 * r0 := 2 is the svc vector number.
> > +	 */
> > +	mov	r0, #2
> > +	ldr	lr, =vector_common
> > +	mov	pc, lr
> > +
> > +vector_common:
> > +	/* make room for pt_regs */
> > +	sub	sp, #S_FRAME_SIZE
> > +	tst	sp, #4			@ check stack alignment
> > +	subne	sp, #4
> > +
> > +	/* store registers r0-r12 */
> > +	stmia	sp, { r0-r12 }		@ stored wrong r0 and r1, fix later
> > +
> > +	/* get registers saved in the stub */
> > +	ldr	r2, [r1, #S_R0]		@ r0
> > +	ldr	r3, [r1, #S_R1]		@ r1
> > +	ldr	r4, [r1, #S_PC] 	@ lr_<exception> (parent PC)
> > +	ldr	r5, [r1, #S_PSR]	@ spsr_<exception> (parent CPSR)
> > +
> > +	/* fix r0 and r1 */
> > +	str	r2, [sp, #S_R0]
> > +	str	r3, [sp, #S_R1]
> > +
> > +	/* store sp_svc, if we were in usr mode we'll fix this later */
> > +	add	r6, sp, #S_FRAME_SIZE
> > +	addne	r6, #4			@ stack wasn't aligned
> > +	str	r6, [sp, #S_SP]
> > +
> > +	str	lr, [sp, #S_LR]		@ store lr_svc, fix later for usr mode
> > +	str	r4, [sp, #S_PC]		@ store lr_<exception>
> > +	str	r5, [sp, #S_PSR]	@ store spsr_<exception>
> > +
> > +	/* set ORIG_r0 */
> > +	mov	r2, #-1
> > +	str	r2, [sp, #S_OLD_R0]
> > +
> > +	/* if we were in usr mode then we need sp_usr and lr_usr instead */
> > +	and	r1, r5, #MODE_MASK
> > +	cmp	r1, #USR_MODE
> > +	bne	1f
> > +	add	r1, sp, #S_SP
> > +	stmia	r1, { sp,lr }^
> > +
> > +	/* Call the handler. r0 is the vector number, r1 := pt_regs */
> > +1:	mov	r1, sp
> > +	bl	do_handle_exception
> > +
> > +	/* make sure we restore sp_svc and lr_svc on mode change */
> > +	str	r6, [sp, #S_SP]
> > +	str	lr, [sp, #S_LR]
> > +
> > +	/* return from exception */
> > +	msr	spsr_cxsf, r5
> > +	ldmia	sp, { r0-pc }^
> > +
> > +.align 5
> > +vector_addrexcptn:
> > +	b	vector_addrexcptn
> > +
> > +.section .text.ex
> > +.align 5
> > +vector_table:
> > +	b	vector_rst
> > +	b	vector_und
> > +	b	vector_svc
> > +	b	vector_pabt
> > +	b	vector_dabt
> > +	b	vector_addrexcptn	@ should never happen
> > +	b	vector_irq
> > +	b	vector_fiq
> > diff --git a/arm/flat.lds b/arm/flat.lds
> > index 3e5d72e24989b..ee9fc0ab79abc 100644
> > --- a/arm/flat.lds
> > +++ b/arm/flat.lds
> > @@ -3,7 +3,12 @@ SECTIONS
> >  {
> >      .text : { *(.init) *(.text) *(.text.*) }
> >      . = ALIGN(4K);
> > -    .data : { *(.data) }
> > +    .data : {
> > +        exception_stacks = .;
> > +        . += 4K;
> > +        exception_stacks_end = .;
> > +        *(.data)
> > +    }
> >      . = ALIGN(16);
> >      .rodata : { *(.rodata) }
> >      . = ALIGN(16);
> > diff --git a/arm/selftest.c b/arm/selftest.c
> > index 3d47a16cbcfad..96ebfe3454e63 100644
> > --- a/arm/selftest.c
> > +++ b/arm/selftest.c
> > @@ -1,9 +1,119 @@
> >  #include "libcflat.h"
> >  #include "arm/sysinfo.h"
> > +#include "arm/ptrace.h"
> > +#include "arm/processor.h"
> > +#include "arm/asm-offsets.h"
> >  
> >  #define PASS 0
> >  #define FAIL 1
> >  
> > +static struct pt_regs expected_regs;
> > +/*
> > + * Capture the current register state and execute an instruction
> > + * that causes an exception. The test handler will check that its
> > + * capture of the current register state matches the capture done
> > + * here.
> > + *
> > + * NOTE: update clobber list if passed insns needs more than r0,r1
> > + */
> > +#define test_exception(pre_insns, excptn_insn, post_insns)	\
> > +	asm volatile(						\
> > +		pre_insns "\n"					\
> > +		"mov	r0, %0\n"				\
> > +		"stmia	r0, { r0-lr }\n"			\
> > +		"mrs	r1, cpsr\n"				\
> > +		"str	r1, [r0, #" __stringify(S_PSR) "]\n"	\
> > +		"mov	r1, #-1\n"				\
> > +		"str	r1, [r0, #" __stringify(S_OLD_R0) "]\n"	\
> > +		"add	r1, pc, #8\n"				\
> > +		"str	r1, [r0, #" __stringify(S_R1) "]\n"	\
> > +		"str	r1, [r0, #" __stringify(S_PC) "]\n"	\
> > +		excptn_insn "\n"				\
> > +		post_insns "\n"					\
> > +	:: "r" (&expected_regs) : "r0", "r1")
> > +
> > +static bool check_regs(struct pt_regs *regs)
> > +{
> > +	unsigned i;
> > +
> > +	/* exception handlers should always run in svc mode */
> > +	if (current_mode() != SVC_MODE)
> > +		return false;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(regs->uregs); ++i) {
> > +		if (regs->uregs[i] != expected_regs.uregs[i])
> > +			return false;
> > +	}
> > +
> > +	return true;
> > +}
> > +
> > +static bool und_works;
> > +static void und_handler(struct pt_regs *regs)
> > +{
> > +	und_works = check_regs(regs);
> > +}
> > +
> > +static bool check_und(void)
> > +{
> > +	install_exception_handler(EXCPTN_UND, und_handler);
> > +
> > +	/* issue an instruction to a coprocessor we don't have */
> > +	test_exception("", "mcr p2, 0, r0, c0, c0", "");
> > +
> > +	install_exception_handler(EXCPTN_UND, NULL);
> > +
> > +	return und_works;
> > +}
> > +
> > +static bool svc_works;
> > +static void svc_handler(struct pt_regs *regs)
> > +{
> > +	u32 svc = *(u32 *)(regs->ARM_pc - 4) & 0xffffff;
> > +
> > +	if (processor_mode(regs) == SVC_MODE) {
> > +		/*
> > +		 * When issuing an svc from supervisor mode lr_svc will
> > +		 * get corrupted. So before issuing the svc, callers must
> > +		 * always push it on the stack. We pushed it to offset 4.
> > +		 */
> > +		regs->ARM_lr = *(unsigned long *)(regs->ARM_sp + 4);
> > +	}
> > +
> > +	svc_works = check_regs(regs) && svc == 123;
> > +}
> > +
> > +static bool check_svc(void)
> > +{
> > +	install_exception_handler(EXCPTN_SVC, svc_handler);
> > +
> > +	if (current_mode() == SVC_MODE) {
> > +		/*
> > +		 * An svc from supervisor mode will corrupt lr_svc and
> > +		 * spsr_svc. We need to save/restore them separately.
> > +		 */
> > +		test_exception(
> > +			"mrs	r0, spsr\n"
> > +			"push	{ r0,lr }\n",
> > +			"svc	#123\n",
> > +			"pop	{ r0,lr }\n"
> > +			"msr	spsr_cxsf, r0\n"
> > +		);
> > +	} else {
> > +		test_exception("", "svc #123", "");
> > +	}
> > +
> > +	install_exception_handler(EXCPTN_SVC, NULL);
> > +
> > +	return svc_works;
> > +}
> > +
> > +static void check_vectors(void)
> > +{
> > +	int ret = check_und() && check_svc() ? PASS : FAIL;
> > +	exit(ret);
> > +}
> > +
> >  static void assert_enough_args(int nargs, int needed)
> >  {
> >  	if (nargs < needed) {
> > @@ -24,6 +134,15 @@ int main(int argc, char **argv)
> >  
> >  		if (mem_size/1024/1024 == (size_t)atol(argv[1]))
> >  			ret = PASS;
> > +
> > +	} else if (strcmp(argv[0], "vectors") == 0) {
> > +
> > +		check_vectors(); /* doesn't return */
> > +
> > +	} else if (strcmp(argv[0], "vectors_usr") == 0) {
> > +
> > +		start_usr(check_vectors); /* doesn't return */
> > +
> >  	}
> >  
> >  	return ret;
> > diff --git a/arm/unittests.cfg b/arm/unittests.cfg
> > index aff684892e90b..75e2a2e3d25bc 100644
> > --- a/arm/unittests.cfg
> > +++ b/arm/unittests.cfg
> > @@ -6,6 +6,24 @@
> >  # 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]
> > +#
> > +# The selftest group tests the initial booting of a guest, as well as
> > +# the test framework itself.
> > +#
> > +# Test bootinfo reading; configured mem-size should equal expected mem-size
> > +[selftest_mem]
> >  file = selftest.flat
> >  extra_params = -m 256 -append 'mem 256'
> > +groups = selftest
> > +
> > +# Test vector setup and exception handling (svc mode).
> > +[selftest_vectors]
> > +file = selftest.flat
> > +extra_params = -append 'vectors'
> > +groups = selftest
> > +
> > +# Test vector setup and exception handling (usr mode).
> > +[selftest_vectors_usr]
> > +file = selftest.flat
> > +extra_params = -append 'vectors_usr'
> > +groups = selftest
> > diff --git a/config/config-arm.mak b/config/config-arm.mak
> > index a863b3e3511c9..99349bf8b0c6b 100644
> > --- a/config/config-arm.mak
> > +++ b/config/config-arm.mak
> > @@ -16,6 +16,7 @@ cflatobjs += \
> >  	lib/virtio.o \
> >  	lib/virtio-testdev.o \
> >  	lib/arm/io.o \
> > +	lib/arm/processor.o \
> >  	lib/arm/setup.o
> >  
> >  libeabi := lib/arm/libeabi.a
> > diff --git a/lib/arm/processor.c b/lib/arm/processor.c
> > new file mode 100644
> > index 0000000000000..1fededee6977f
> > --- /dev/null
> > +++ b/lib/arm/processor.c
> > @@ -0,0 +1,103 @@
> > +#include "libcflat.h"
> > +#include "arm/processor.h"
> > +#include "arm/sysinfo.h"
> > +#include "arm/ptrace.h"
> > +#include "heap.h"
> > +
> > +static const char *processor_modes[] = {
> > +	"USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" ,
> > +	"UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
> > +	"UK8_26" , "UK9_26" , "UK10_26", "UK11_26",
> > +	"UK12_26", "UK13_26", "UK14_26", "UK15_26",
> > +	"USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" ,
> > +	"UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" ,
> > +	"UK8_32" , "UK9_32" , "UK10_32", "UND_32" ,
> > +	"UK12_32", "UK13_32", "UK14_32", "SYS_32"
> > +};
> > +
> > +static char *vector_names[] = {
> > +	"rst", "und", "svc", "pabt", "dabt", "addrexcptn", "irq", "fiq"
> > +};
> > +
> > +void show_regs(struct pt_regs *regs)
> > +{
> > +	unsigned long flags;
> > +	char buf[64];
> > +
> > +	printf("pc : [<%08lx>]    lr : [<%08lx>]    psr: %08lx\n"
> > +	       "sp : %08lx  ip : %08lx  fp : %08lx\n",
> > +		regs->ARM_pc, regs->ARM_lr, regs->ARM_cpsr,
> > +		regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
> > +	printf("r10: %08lx  r9 : %08lx  r8 : %08lx\n",
> > +		regs->ARM_r10, regs->ARM_r9, regs->ARM_r8);
> > +	printf("r7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\n",
> > +		regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4);
> > +	printf("r3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\n",
> > +		regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0);
> > +
> > +	flags = regs->ARM_cpsr;
> > +	buf[0] = flags & PSR_N_BIT ? 'N' : 'n';
> > +	buf[1] = flags & PSR_Z_BIT ? 'Z' : 'z';
> > +	buf[2] = flags & PSR_C_BIT ? 'C' : 'c';
> > +	buf[3] = flags & PSR_V_BIT ? 'V' : 'v';
> > +	buf[4] = '\0';
> > +
> > +	printf("Flags: %s  IRQs o%s  FIQs o%s  Mode %s\n",
> > +		buf, interrupts_enabled(regs) ? "n" : "ff",
> > +		fast_interrupts_enabled(regs) ? "n" : "ff",
> > +		processor_modes[processor_mode(regs)]);
> > +
> > +	if (!user_mode(regs)) {
> > +		unsigned int ctrl, transbase, dac;
> > +		asm volatile(
> > +			"mrc p15, 0, %0, c1, c0\n"
> > +			"mrc p15, 0, %1, c2, c0\n"
> > +			"mrc p15, 0, %2, c3, c0\n"
> > +		: "=r" (ctrl), "=r" (transbase), "=r" (dac));
> > +		printf("Control: %08x  Table: %08x  DAC: %08x\n",
> > +			ctrl, transbase, dac);
> > +	}
> > +}
> > +
> > +void *get_sp(void)
> > +{
> > +	register unsigned long sp asm("sp");
> > +	return (void *)sp;
> > +}
> > +
> > +static exception_fn exception_handlers[EXCPTN_MAX];
> > +
> > +void install_exception_handler(enum vector v, exception_fn fn)
> > +{
> > +	if (v < EXCPTN_MAX)
> > +		exception_handlers[v] = fn;
> > +}
> > +
> > +void do_handle_exception(enum vector v, struct pt_regs *regs)
> > +{
> > +	if (v < EXCPTN_MAX && exception_handlers[v]) {
> > +		exception_handlers[v](regs);
> > +		return;
> > +	}
> > +
> > +	if (v < EXCPTN_MAX)
> > +		printf("Unhandled exception %d (%s)\n", v, vector_names[v]);
> > +	else
> > +		printf("%s called with vector=%d\n", __func__, v);
> > +	printf("Exception frame registers:\n");
> > +	show_regs(regs);
> > +	exit(EINTR);
> > +}
> > +
> > +void start_usr(void (*func)(void))
> > +{
> > +	void *sp_usr = alloc_page() + PAGE_SIZE;
> > +	asm volatile(
> > +		"mrs	r0, cpsr\n"
> > +		"bic	r0, #" __stringify(MODE_MASK) "\n"
> > +		"orr	r0, #" __stringify(USR_MODE) "\n"
> > +		"msr	cpsr_c, r0\n"
> > +		"mov	sp, %0\n"
> > +		"mov	pc, %1\n"
> > +	:: "r" (sp_usr), "r" (func) : "r0");
> > +}
> > diff --git a/lib/arm/processor.h b/lib/arm/processor.h
> > new file mode 100644
> > index 0000000000000..12c1902de97fd
> > --- /dev/null
> > +++ b/lib/arm/processor.h
> > @@ -0,0 +1,35 @@
> > +#ifndef _ARM_PROCESSOR_H_
> > +#define _ARM_PROCESSOR_H_
> > +#include "libcflat.h"
> > +#include "ptrace.h"
> > +
> > +enum vector {
> > +	EXCPTN_RST,
> > +	EXCPTN_UND,
> > +	EXCPTN_SVC,
> > +	EXCPTN_PABT,
> > +	EXCPTN_DABT,
> > +	EXCPTN_ADDREXCPTN,
> > +	EXCPTN_IRQ,
> > +	EXCPTN_FIQ,
> > +	EXCPTN_MAX,
> > +};
> > +
> > +typedef void (*exception_fn)(struct pt_regs *);
> > +extern void install_exception_handler(enum vector v, exception_fn fn);
> > +
> > +extern void show_regs(struct pt_regs *regs);
> > +extern void *get_sp(void);
> > +
> > +extern void start_usr(void (*func)(void));
> > +
> > +static inline unsigned long current_cpsr(void)
> > +{
> > +	unsigned long cpsr;
> > +	asm volatile("mrs %0, cpsr" : "=r" (cpsr));
> > +	return cpsr;
> > +}
> > +
> > +#define current_mode() (current_cpsr() & MODE_MASK)
> > +
> > +#endif
> > diff --git a/lib/libcflat.h b/lib/libcflat.h
> > index 84b8783bacfdc..3d47a3331b7fc 100644
> > --- a/lib/libcflat.h
> > +++ b/lib/libcflat.h
> > @@ -65,6 +65,8 @@ extern long atol(const char *ptr);
> >  		(type *)( (char *)__mptr - offsetof(type,member) );})
> >  
> >  #define __unused __attribute__((__unused__))
> > +#define __stringify_1(x...)	#x
> > +#define __stringify(x...)	__stringify_1(x)
> >  #define NULL ((void *)0UL)
> >  #include "errno.h"
> >  #endif
> > -- 
> > 1.8.1.4
> > 

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 16/17] arm: add useful headers from the linux kernel
  2014-02-03 16:46     ` Andrew Jones
@ 2014-02-03 17:38       ` Christoffer Dall
  0 siblings, 0 replies; 47+ messages in thread
From: Christoffer Dall @ 2014-02-03 17:38 UTC (permalink / raw)
  To: Andrew Jones; +Cc: kvmarm, kvm

On Mon, Feb 03, 2014 at 05:46:08PM +0100, Andrew Jones wrote:
> On Sat, Feb 01, 2014 at 06:29:05PM -0800, Christoffer Dall wrote:
> > On Tue, Jan 21, 2014 at 05:22:02PM +0100, Andrew Jones wrote:
> > > We're going to need PSR bit defines and pt_regs. We'll also need
> > > pt_regs offsets in assembly code. This patch adapts the linux
> > > kernel's ptrace.h and asm-offsets to this framework. Even though
> > > lib/arm/asm-offsets.h is a generated file, we still commit it,
> > > as it's unlikely to change. Also adapt cp15.h from the kernel,
> > > since we'll need bit defines from there too.
> > > 
> > > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > > ---
> > 
> > [...]
> > 
> > > +
> > > +asm-offsets: scripts/arm/asm-offsets.flat
> > > +	$(QEMU) -device virtio-testdev -display none -serial stdio \
> > > +		-M virt -cpu $(PROCESSOR) \
> > > +		-kernel $^ > lib/arm/asm-offsets.h || true
> > 
> > I still disagree with this requirement to have the correct version of
> > qemu on the build machine.
> 
> Ah sorry, I forgot about this one. I'll steal more from the kernel
> on the asm-offsets generation to improve this for v4.
> 
Cool, thanks!

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 17/17] arm: vectors support
  2014-02-03 16:50     ` Andrew Jones
@ 2014-02-03 21:19       ` Christoffer Dall
  2014-02-04  7:12         ` Andrew Jones
  0 siblings, 1 reply; 47+ messages in thread
From: Christoffer Dall @ 2014-02-03 21:19 UTC (permalink / raw)
  To: Andrew Jones; +Cc: kvmarm, kvm

On Mon, Feb 03, 2014 at 05:50:20PM +0100, Andrew Jones wrote:
> On Sat, Feb 01, 2014 at 06:29:27PM -0800, Christoffer Dall wrote:
> > On Tue, Jan 21, 2014 at 05:22:03PM +0100, Andrew Jones wrote:
> > > Add support for tests to use exception handlers.
> > > 
> > > v2 -> v3:
> > > - squashed in 'arm: Simplify exceptions_init in cstart.S' from
> > >   Christoffer Dall
> > > - suggested function name changes and comment additions [Christoffer Dall]
> > > - fix a bug with stack restore from usr mode exceptions that Christoffer
> > >   pointed out. Add a get_sp() accessor too.
> > 
> > hmmm, how did you address this, the only change I can see is using r6
> > instead of r2, which I'm not sure how changes anything.
> 
> It also adds
> 
> 	/* make sure we restore sp_svc and lr_svc on mode change */
> 	str	r6, [sp, #S_SP]
> 	str	lr, [sp, #S_LR]
> 
> lower down. Needed to switch to r6 from r2 for that
> 
> > 
> > The problem is that your ldmia is replacing the usr sp, not the svc sp,
> > so maybe you need to do ldmia sp!, [ r0 - pc ]^ (don't remember if that
> > particular combination works) or you need to do something more fancy...
> 
> I'm not sure about the magic ! + ^ stuff, but what I've done does fix
> the problem. I tested before/after the fix (actually that's why I also
> added the get_sp).
> 

Ah, I know, my original comment was wrong, what you were in fact doing
was restoring the user sp to the svc reg, the write to the CPSR from the
SPSR happens after restoring all the other regs (except the PC)
according to the ldm exception return pseudocode.

ok, I think it's correct now, except for the bit about the lr, see
below.

> > > diff --git a/arm/cstart.S b/arm/cstart.S
> > > index 4de04b62c28c2..74674fd41c1b3 100644
> > > --- a/arm/cstart.S
> > > +++ b/arm/cstart.S
> > > @@ -1,3 +1,7 @@
> > > +#define __ASSEMBLY__
> > > +#include "arm/asm-offsets.h"
> > > +#include "arm/ptrace.h"
> > > +#include "arm/cp15.h"
> > >  
> > >  .arm
> > >  
> > > @@ -10,6 +14,13 @@ start:
> > >  	 * See the kernel doc Documentation/arm/Booting
> > >  	 */
> > >  	ldr	sp, =stacktop
> > > +	push	{r0-r3}
> > > +
> > > +	/* set up vector table and mode stacks */
> > > +	bl	exceptions_init
> > > +
> > > +	/* complete setup */
> > > +	pop	{r0-r3}
> > >  	bl	setup
> > >  
> > >  	/* start the test */
> > > @@ -20,9 +31,166 @@ start:
> > >  	bl	exit
> > >  	b	halt
> > >  
> > > +.macro set_mode_stack mode, stack
> > > +	add	\stack, #S_FRAME_SIZE
> > > +	msr	cpsr_c, #(\mode | PSR_I_BIT | PSR_F_BIT)
> > > +	mov	sp, \stack
> > > +.endm
> > > +
> > > +exceptions_init:
> > > +	mrc	p15, 0, r2, c1, c0, 0	@ read SCTLR
> > > +	bic	r2, #CR_V		@ SCTLR.V := 0
> > > +	mcr	p15, 0, r2, c1, c0, 0	@ write SCTLR
> > > +	ldr	r2, =vector_table
> > > +	mcr	p15, 0, r2, c12, c0, 0	@ write VBAR
> > > +
> > > +	mrs	r2, cpsr
> > > +	ldr	r1, =exception_stacks
> > > +		/* first frame for svc mode */
> > > +	set_mode_stack	UND_MODE, r1
> > > +	set_mode_stack	ABT_MODE, r1
> > > +	set_mode_stack	IRQ_MODE, r1
> > > +	set_mode_stack	FIQ_MODE, r1
> > > +	msr	cpsr_cxsf, r2	@ back to svc mode
> > > +	mov	pc, lr
> > > +
> > >  .text
> > >  
> > >  .globl halt
> > >  halt:
> > >  1:	wfi
> > >  	b	1b
> > > +
> > > +/*
> > > + * Vector stubs.
> > > + * Simplified version of the Linux kernel implementation
> > > + *   arch/arm/kernel/entry-armv.S
> > > + *
> > > + * Each mode has an S_FRAME_SIZE sized stack initialized
> > > + * in exceptions_init
> > > + */
> > > +.macro vector_stub, name, vec, mode, correction=0
> > > +.align 5
> > > +vector_\name:
> > > +.if \correction
> > > +	sub	lr, lr, #\correction
> > > +.endif
> > > +	/*
> > > +	 * Save r0, r1, lr_<exception> (parent PC)
> > > +	 * and spsr_<exception> (parent CPSR)
> > > +	 */
> > > +	str	r0, [sp, #S_R0]
> > > +	str	r1, [sp, #S_R1]
> > > +	str	lr, [sp, #S_PC]
> > > +	mrs	r0, spsr
> > > +	str	r0, [sp, #S_PSR]
> > > +
> > > +	/* Prepare for SVC32 mode. */
> > > +	mrs	r0, cpsr
> > > +	bic	r0, #MODE_MASK
> > > +	orr	r0, #SVC_MODE
> > > +	msr	spsr_cxsf, r0
> > > +
> > > +	/* Branch to handler in SVC mode */
> > > +	mov	r0, #\vec
> > > +	mov	r1, sp
> > > +	ldr	lr, =vector_common
> > > +	movs	pc, lr
> > > +.endm
> > > +
> > > +vector_stub 	rst,	0, UND_MODE
> > > +vector_stub	und,	1, UND_MODE
> > > +vector_stub	pabt,	3, ABT_MODE, 4
> > > +vector_stub	dabt,	4, ABT_MODE, 8
> > > +vector_stub	irq,	6, IRQ_MODE, 4
> > > +vector_stub	fiq,	7, FIQ_MODE, 4
> > > +
> > > +.align 5
> > > +vector_svc:
> > > +	/*
> > > +	 * Save r0, r1, lr_<exception> (parent PC)
> > > +	 * and spsr_<exception> (parent CPSR)
> > > +	 */
> > > +	push	{ r1 }
> > > +	ldr	r1, =exception_stacks
> > > +	str	r0, [r1, #S_R0]
> > > +	pop	{ r0 }
> > > +	str	r0, [r1, #S_R1]
> > > +	str	lr, [r1, #S_PC]
> > > +	mrs	r0, spsr
> > > +	str	r0, [r1, #S_PSR]
> > > +
> > > +	/*
> > > +	 * Branch to handler, still in SVC mode.
> > > +	 * r0 := 2 is the svc vector number.
> > > +	 */
> > > +	mov	r0, #2
> > > +	ldr	lr, =vector_common
> > > +	mov	pc, lr
> > > +
> > > +vector_common:
> > > +	/* make room for pt_regs */
> > > +	sub	sp, #S_FRAME_SIZE
> > > +	tst	sp, #4			@ check stack alignment
> > > +	subne	sp, #4
> > > +
> > > +	/* store registers r0-r12 */
> > > +	stmia	sp, { r0-r12 }		@ stored wrong r0 and r1, fix later
> > > +
> > > +	/* get registers saved in the stub */
> > > +	ldr	r2, [r1, #S_R0]		@ r0
> > > +	ldr	r3, [r1, #S_R1]		@ r1
> > > +	ldr	r4, [r1, #S_PC] 	@ lr_<exception> (parent PC)
> > > +	ldr	r5, [r1, #S_PSR]	@ spsr_<exception> (parent CPSR)
> > > +
> > > +	/* fix r0 and r1 */
> > > +	str	r2, [sp, #S_R0]
> > > +	str	r3, [sp, #S_R1]
> > > +
> > > +	/* store sp_svc, if we were in usr mode we'll fix this later */
> > > +	add	r6, sp, #S_FRAME_SIZE
> > > +	addne	r6, #4			@ stack wasn't aligned
> > > +	str	r6, [sp, #S_SP]
> > > +
> > > +	str	lr, [sp, #S_LR]		@ store lr_svc, fix later for usr mode
> > > +	str	r4, [sp, #S_PC]		@ store lr_<exception>
> > > +	str	r5, [sp, #S_PSR]	@ store spsr_<exception>
> > > +
> > > +	/* set ORIG_r0 */
> > > +	mov	r2, #-1
> > > +	str	r2, [sp, #S_OLD_R0]
> > > +
> > > +	/* if we were in usr mode then we need sp_usr and lr_usr instead */
> > > +	and	r1, r5, #MODE_MASK
> > > +	cmp	r1, #USR_MODE
> > > +	bne	1f
> > > +	add	r1, sp, #S_SP
> > > +	stmia	r1, { sp,lr }^
> > > +
> > > +	/* Call the handler. r0 is the vector number, r1 := pt_regs */
> > > +1:	mov	r1, sp
> > > +	bl	do_handle_exception
> > > +
> > > +	/* make sure we restore sp_svc and lr_svc on mode change */
> > > +	str	r6, [sp, #S_SP]
> > > +	str	lr, [sp, #S_LR]

I don't think store of lr is necessary, lr was just overwritten by the
bl instruction above, and it will get overwritten at exception entry to
SVC mode again.

> > > +
> > > +	/* return from exception */
> > > +	msr	spsr_cxsf, r5
> > > +	ldmia	sp, { r0-pc }^
> > > +
> > > +.align 5
> > > +vector_addrexcptn:
> > > +	b	vector_addrexcptn
> > > +
> > > +.section .text.ex
> > > +.align 5
> > > +vector_table:
> > > +	b	vector_rst
> > > +	b	vector_und
> > > +	b	vector_svc
> > > +	b	vector_pabt
> > > +	b	vector_dabt
> > > +	b	vector_addrexcptn	@ should never happen
> > > +	b	vector_irq
> > > +	b	vector_fiq

[...]

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 17/17] arm: vectors support
  2014-02-03 21:19       ` Christoffer Dall
@ 2014-02-04  7:12         ` Andrew Jones
  0 siblings, 0 replies; 47+ messages in thread
From: Andrew Jones @ 2014-02-04  7:12 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: kvmarm, kvm

On Mon, Feb 03, 2014 at 01:19:26PM -0800, Christoffer Dall wrote:
> On Mon, Feb 03, 2014 at 05:50:20PM +0100, Andrew Jones wrote:
> > On Sat, Feb 01, 2014 at 06:29:27PM -0800, Christoffer Dall wrote:
> > > On Tue, Jan 21, 2014 at 05:22:03PM +0100, Andrew Jones wrote:
> > > > Add support for tests to use exception handlers.
> > > > 
> > > > v2 -> v3:
> > > > - squashed in 'arm: Simplify exceptions_init in cstart.S' from
> > > >   Christoffer Dall
> > > > - suggested function name changes and comment additions [Christoffer Dall]
> > > > - fix a bug with stack restore from usr mode exceptions that Christoffer
> > > >   pointed out. Add a get_sp() accessor too.
> > > 
> > > hmmm, how did you address this, the only change I can see is using r6
> > > instead of r2, which I'm not sure how changes anything.
> > 
> > It also adds
> > 
> > 	/* make sure we restore sp_svc and lr_svc on mode change */
> > 	str	r6, [sp, #S_SP]
> > 	str	lr, [sp, #S_LR]
> > 
> > lower down. Needed to switch to r6 from r2 for that
> > 
> > > 
> > > The problem is that your ldmia is replacing the usr sp, not the svc sp,
> > > so maybe you need to do ldmia sp!, [ r0 - pc ]^ (don't remember if that
> > > particular combination works) or you need to do something more fancy...
> > 
> > I'm not sure about the magic ! + ^ stuff, but what I've done does fix
> > the problem. I tested before/after the fix (actually that's why I also
> > added the get_sp).
> > 
> 
> Ah, I know, my original comment was wrong, what you were in fact doing
> was restoring the user sp to the svc reg, the write to the CPSR from the
> SPSR happens after restoring all the other regs (except the PC)
> according to the ldm exception return pseudocode.
> 
> ok, I think it's correct now, except for the bit about the lr, see
> below.

I agree the lr restore is unnecessary, and I didn't test anything related
to that. I threw it in to balance the switch to sp_usr,lr_usr above, but
can replace that balancing with a comment instead.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 00/17] kvm-unit-tests/arm: initial drop
       [not found]     ` <CALxX4v-h+gOCZDukCnGK_GUQepu07KYw4BGjzjGNgA0SdDcLNw@mail.gmail.com>
@ 2014-02-04  8:33       ` Andrew Jones
  0 siblings, 0 replies; 47+ messages in thread
From: Andrew Jones @ 2014-02-04  8:33 UTC (permalink / raw)
  To: Maria Soler; +Cc: Christoffer Dall, kvmarm, kvm

On Tue, Feb 04, 2014 at 09:19:30AM +0100, Maria Soler wrote:
> On 29 January 2014 16:35, Andrew Jones <drjones@redhat.com> wrote:
> 
> > On Tue, Jan 28, 2014 at 07:16:11PM +0100, María Soler Heredia wrote:
> > > Hello Andrew,
> > >
> > > I have been experimenting a little with your tests and I have some
> > comments
> > > and questions. I have already compiled and run versions v1 and v2, which
> > > work with kvm disabled, but I cannot run v3 using the same qemu, version
> > > 1.6.90 with these two sets of patches:
> > >
> > >    -
> > http://lists.nongnu.org/archive/html/qemu-devel/2013-09/msg02142.html(Adds
> > > 'virt' platform)
> > >    -
> > http://lists.nongnu.org/archive/html/qemu-devel/2013-10/msg01815.html(Introduces
> > > virtio-testdev)
> > >
> > > that you indicated on [PATCH 0/9] kvm-unit-tests/arm: initial drop.
> > >
> > > >  Only qemu-system-arm, recent enough to have mach-virt, and the
> > > > virtio-testdev patch[1],
> > > > is required.
> > > >
> > > > [1]
> > http://lists.nongnu.org/archive/html/qemu-devel/2013-12/msg00690.html
> > > >
> > >
> > > Then I thought maybe the problem was that my qemu was too old, so I
> > > upgraded to version 1.7.50, the newest available version at git://
> > > git.qemu-project.org/qemu.git and applied patch[1] but it seems to be
> > > incompatible with that version of qemu, since it doesn't compile:
> > >
> > -------------------------------------------------------------------------------------------------------------------------------------------
> > > hw/virtio/virtio-testdev.c: In function 'virtio_testdev_class_init':
> > > hw/virtio/virtio-testdev.c:136:8: error: 'VirtioDeviceClass' has no
> > member
> > > named 'init'
> > >
> > -------------------------------------------------------------------------------------------------------------------------------------------
> >
> > The latest git://git.qemu.org/qemu.git with the v3 of virtio-testdev that
> > I just sent[*] works for me. virtio-testdev needed to be converted from
> > init
> > to realize.
> >
> > [*] http://lists.nongnu.org/archive/html/qemu-devel/2014-01/msg04041.html
> >
> > >
> > > I modified hw/virtio/virtio-testdev.c to stop this error from happening,
> > > but it won't run the already compiled (with qemu 1.6.90) v1 and v2 or
> > make
> > > a runnable version of either v1, v2 or v3 when recompiling them.
> > >
> > > The error that I get when I run the v3 of the test (with qemu 1.6.90) is
> > as
> > > follows:
> > >
> > > $ ./run_tests.sh -v
> > > ./arm-run arm/selftest.flat -smp 1 -m 256 -append 'mem 256'
> > > qemu: fatal: Trying to execute code outside RAM or ROM at 0x00000000
> > >
> > > R00=fffffff7 R01=00000000 R02=00000000 R03=2ff20112
> > > R04=00000000 R05=00000000 R06=00000000 R07=00000000
> > > R08=00000000 R09=00000000 R10=00000000 R11=00000000
> > > R12=00000000 R13=40017ff8 R14=080117b0 R15=00000000
> > > PSR=a00001d3 N-C- A svc32
> > > s00=00000000 s01=00000000 d00=0000000000000000
> > > ...
> > > s62=00000000 s63=00000000 d31=0000000000000000
> > > FPSCR: 00000000
> > > ./arm-run: line 16:  4839 Aborted                 (core dumped) $command
> > > "$@"
> > > FAIL selftest_mem
> > > ./arm-run arm/selftest.flat -smp 1 -append 'vectors'
> > > qemu: fatal: Trying to execute code outside RAM or ROM at 0x00000000
> > >
> > > R00=fffffff7 R01=00000000 R02=00000000 R03=2ff20112
> > > R04=00000000 R05=00000000 R06=00000000 R07=00000000
> > > R08=00000000 R09=00000000 R10=00000000 R11=00000000
> > > R12=00000000 R13=40017ff8 R14=080117b0 R15=00000000
> > > PSR=a00001d3 N-C- A svc32
> > > s00=00000000 s01=00000000 d00=0000000000000000
> > > ...
> > > s62=00000000 s63=00000000 d31=0000000000000000
> > > FPSCR: 00000000
> > > ./arm-run: line 16:  4845 Aborted                 (core dumped) $command
> > > "$@"
> > > FAIL selftest_vectors
> > > ./arm-run arm/selftest.flat -smp 1 -append 'vectors_usr'
> > > qemu: fatal: Trying to execute code outside RAM or ROM at 0x00000000
> > >
> > > R00=fffffff7 R01=00000000 R02=00000000 R03=2ff20112
> > > R04=00000000 R05=00000000 R06=00000000 R07=00000000
> > > R08=00000000 R09=00000000 R10=00000000 R11=00000000
> > > R12=00000000 R13=40017ff8 R14=080117b0 R15=00000000
> > > PSR=a00001d3 N-C- A svc32
> > > s00=00000000 s01=00000000 d00=0000000000000000
> > > ...
> > > s62=00000000 s63=00000000 d31=0000000000000000
> > > FPSCR: 00000000
> > > ./arm-run: line 16:  4851 Aborted                 (core dumped) $command
> > > "$@"
> > > FAIL selftest_vectors_usr
> > >
> > > Am I using the wrong qemu? Is there a new dependency that is not
> > mentioned
> > > and that may cause this problem? Any other ideas on why this could
> > happen?
> >
> > Are you sure you have the latest mach-virt patches for qemu? v3 of
> > kvm-unit-tests/arm sets the load address to 0x40000000, which matches the
> > latest mach-virt.
> >
> > I can run these tests on my x86_64 machine, without kvm enabled, as well as
> > on an armv7 machine with kvm enabled. Are you still running on the
> > FastModel? I never got around to setting one up to see if that works or
> > not.
> >
> > thanks,
> > drew
> >
> >
> In deed, everything works fine with that qemu. So my "old qemu" was too old
> and the other one was simply an incompatible version. I wasn't using
> FastModels in this case, although all versions work on FastModels as well.
> The only problem I had with the first version was that I thought I could
> enable kvm, (you know, kvm tests), so I mentioned FastModels in case it was
> part of the problem.
> 
> Thank you very much,
> María.

I'm glad to hear things are working for you now. Will you be submitting
some test code built on top of this framework? If so, can you briefly
describe your plans?

thanks,
drew

^ permalink raw reply	[flat|nested] 47+ messages in thread

end of thread, other threads:[~2014-02-04  8:33 UTC | newest]

Thread overview: 47+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-01-21 16:21 [PATCH 00/17] kvm-unit-tests/arm: initial drop Andrew Jones
2014-01-21 16:21 ` [PATCH 01/17] remove unused files Andrew Jones
2014-01-21 16:21 ` [PATCH 02/17] makefile and run_tests tweaks Andrew Jones
2014-01-21 16:21 ` [PATCH 03/17] clean root dir of all x86-ness Andrew Jones
2014-01-21 16:21 ` [PATCH 04/17] gitignore: Ignore more Andrew Jones
2014-01-21 16:21 ` [PATCH 05/17] add 'make cscope' support Andrew Jones
2014-02-02  2:22   ` Christoffer Dall
2014-02-03 13:25     ` Andrew Jones
2014-01-21 16:21 ` [PATCH 06/17] Add halt() and some error codes Andrew Jones
2014-02-02  2:23   ` Christoffer Dall
2014-01-21 16:21 ` [PATCH 07/17] move x86's simple heap management to common code Andrew Jones
2014-02-02  2:23   ` Christoffer Dall
2014-01-21 16:21 ` [PATCH 08/17] Introduce libio to common code for io read/write Andrew Jones
2014-02-02  2:24   ` Christoffer Dall
2014-02-03 13:51     ` Andrew Jones
2014-02-03 16:30       ` Christoffer Dall
2014-01-21 16:21 ` [PATCH 10/17] libfdt: get libfdt to build Andrew Jones
2014-02-02  2:25   ` Christoffer Dall
2014-02-03 13:57     ` Andrew Jones
2014-01-21 16:21 ` [PATCH 11/17] add support for device trees Andrew Jones
2014-02-02  2:27   ` Christoffer Dall
2014-02-03 15:31     ` Andrew Jones
2014-02-03 16:36       ` Christoffer Dall
2014-01-21 16:21 ` [PATCH 12/17] Introduce virtio-testdev Andrew Jones
2014-02-02  2:27   ` Christoffer Dall
2014-02-03 15:44     ` Andrew Jones
2014-02-03 16:41       ` Christoffer Dall
2014-01-21 16:21 ` [PATCH 13/17] arm: initial drop Andrew Jones
2014-02-02  2:28   ` Christoffer Dall
2014-02-03 15:55     ` Andrew Jones
2014-01-21 16:22 ` [PATCH 14/17] arm: Add IO accessors to avoid register-writeback Andrew Jones
2014-01-21 16:22 ` [PATCH 15/17] printf: support field padding Andrew Jones
2014-02-02  2:28   ` Christoffer Dall
2014-01-21 16:22 ` [PATCH 16/17] arm: add useful headers from the linux kernel Andrew Jones
2014-02-02  2:29   ` Christoffer Dall
2014-02-03 16:46     ` Andrew Jones
2014-02-03 17:38       ` Christoffer Dall
2014-01-21 16:22 ` [PATCH 17/17] arm: vectors support Andrew Jones
2014-02-02  2:29   ` Christoffer Dall
2014-02-03 16:50     ` Andrew Jones
2014-02-03 21:19       ` Christoffer Dall
2014-02-04  7:12         ` Andrew Jones
     [not found] ` <CABWnSnPMc_CrH8N28TScBVvQmCk+XD-bVWvdmJAxxVczHsVx_g@mail.gmail.com>
2014-01-29 15:35   ` [PATCH 00/17] kvm-unit-tests/arm: initial drop Andrew Jones
2014-02-02  2:22 ` Christoffer Dall
2014-02-03 13:24   ` Andrew Jones
     [not found]     ` <CALxX4v-h+gOCZDukCnGK_GUQepu07KYw4BGjzjGNgA0SdDcLNw@mail.gmail.com>
2014-02-04  8:33       ` Andrew Jones
     [not found] ` <1390321323-1855-10-git-send-email-drjones@redhat.com>
2014-02-02  2:25   ` [PATCH 09/17] libfdt: Import libfdt source Christoffer Dall

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.