summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/boards/emulated.rst75
-rw-r--r--Documentation/boards/mips/qemu-malta.rst16
-rw-r--r--Documentation/boards/riscv.rst20
-rw-r--r--Documentation/boards/riscv/barebox-virt32.cfg7
-rw-r--r--Documentation/boards/riscv/barebox-virt64.cfg7
-rw-r--r--Kconfig1
-rw-r--r--Makefile28
-rw-r--r--arch/openrisc/Makefile2
-rw-r--r--commands/Makefile1
-rw-r--r--commands/selftest.c88
-rw-r--r--common/startup.c4
-rw-r--r--images/.gitignore1
-rw-r--r--images/Makefile7
-rw-r--r--images/Makefile.malta10
-rw-r--r--include/bselftest.h74
-rw-r--r--include/stdlib.h5
-rw-r--r--test/.gitignore1
-rw-r--r--test/Kconfig8
-rw-r--r--test/Makefile1
-rw-r--r--test/__init__.py0
-rw-r--r--test/arm/a15@vexpress_defconfig.yaml20
-rw-r--r--test/arm/a9@vexpress_defconfig.yaml20
-rw-r--r--test/arm/qemu_virt64_defconfig.yaml24
l---------test/arm/vexpress_defconfig.yaml1
-rw-r--r--test/arm/virt@vexpress_defconfig.yaml22
-rw-r--r--test/conftest.py27
-rwxr-xr-xtest/emulate.pl528
-rw-r--r--test/kconfig/base.cfg4
-rw-r--r--test/kconfig/full.cfg2
-rw-r--r--test/kconfig/virtio-pci.cfg6
-rw-r--r--test/mips/be@qemu-malta_defconfig.yaml22
-rw-r--r--test/mips/le@qemu-malta_defconfig.yaml25
l---------test/mips/qemu-malta_defconfig.yaml1
-rw-r--r--test/openrisc/generic_defconfig.yaml20
-rw-r--r--test/py/__init__.py0
-rw-r--r--test/py/helper.py38
-rw-r--r--test/py/test_bselftests.py8
-rw-r--r--test/py/test_bthread.py23
-rw-r--r--test/py/test_shell.py36
-rw-r--r--test/riscv/qemu@virt32_defconfig.yaml27
-rw-r--r--test/riscv/qemu@virt64_defconfig.yaml27
-rw-r--r--test/riscv/sifive_defconfig.yaml25
-rw-r--r--test/riscv/tinyemu@virt32_defconfig.yaml22
-rw-r--r--test/riscv/tinyemu@virt64_defconfig.yaml22
l---------test/riscv/virt32_defconfig.yaml1
l---------test/riscv/virt64_defconfig.yaml1
-rw-r--r--test/sandbox/sandbox_defconfig.yaml12
-rw-r--r--test/self/Kconfig39
-rw-r--r--test/self/Makefile4
-rw-r--r--test/self/core.c22
-rw-r--r--test/self/printf.c302
-rw-r--r--test/strategy.py53
l---------test/x86/efi_defconfig.yaml1
-rw-r--r--test/x86/pc@efi_defconfig.yaml31
-rw-r--r--test/x86/q35@efi_defconfig.yaml31
-rw-r--r--test/x86/virtio@efi_defconfig.yaml32
56 files changed, 1810 insertions, 25 deletions
diff --git a/Documentation/boards/emulated.rst b/Documentation/boards/emulated.rst
new file mode 100644
index 0000000000..584883d6ef
--- /dev/null
+++ b/Documentation/boards/emulated.rst
@@ -0,0 +1,75 @@
+Emulated targets
+================
+
+Some targets barebox runs on are virtualized by emulators like QEMU, which
+allows basic testing of barebox functionality without the actual hardware.
+
+Generic DT image
+----------------
+
+Supported for ARM and RISC-V. It generates a barebox image that can
+be booted with the Linux kernel booting convention, which makes
+it suitable to be passed as argument to the QEMU ``-kernel`` option
+(as well as booted just like Linux from barebox or other bootloaders).
+
+The device tree can be passed externally via QEMU's ``-dtb`` option, but
+also the QEMU internal device tree can be used.
+
+The latter can be very useful with :ref:`virtio_sect`, because QEMU will
+fix up the virtio mmio regions into the device tree and barebox will
+discover the devices automatically, analogously to what it does with
+VirtIO over PCI.
+
+test/emulate.pl
+---------------
+
+The ``emulate.pl`` script shipped with barebox can be used to easily
+start VMs. It reads a number of YAML files in ``test/$ARCH``, which
+describe some virtualized targets that barebox is known to run on.
+
+Controlled by command line options, these targets are built with
+tuxmake if available and loaded into the emulator for either interactive
+use or for automated testing with Labgrid ``QEMUDriver``.
+
+.. _tuxmake: https://pypi.org/project/tuxmake/
+.. _Labgrid: https://labgrid.org
+
+Install dependencies for interactive use::
+
+ cpan YAML::XS # or use e.g. libyaml-libyaml-perl on Debian
+ pip3 install tuxmake # optional
+
+Example usage::
+
+ # Switch to barebox source directory
+ cd barebox
+
+ # emulate x86 VM runnig the EFI payload from efi_defconfig
+ ARCH=x86 ./test/emulate.pl efi_defconfig
+
+ # build all MIPS targets known to emulate.pl and exit
+ ARCH=mips ./test/emulate.pl --no-emulate
+
+The script can also be used with a precompiled barebox tree::
+
+ # Switch to build directory
+ export KBUILD_OUTPUT=build
+
+ # run a barebox image built outside tuxmake on an ARM virt machine
+ ARCH=arm ./test/emulate.pl virt@vexpress_defconfig --no-tuxmake
+
+ # run tests instead of starting emulator interactively
+ ARCH=arm ./test/emulate.pl virt@vexpress_defconfig --no-tuxmake --test
+
+``emulate.pl`` also has some knowledge on paravirtualized devices::
+
+ # Run target and pass a block device (here /dev/virtioblk0)
+ ARCH=riscv ./test/emulate.pl --blk=rootfs.ext4 virt64_defconfig
+
+Needed command line options can be passed directly to the
+emulator/``pytest`` as well by placing them behind ``--``::
+
+ # appends -device ? to the command line. Add -n to see the final result
+ ARCH=riscv ./test/emulate.pl virt64_defconfig -- -device ?
+
+For a complete listing of options run ``./test/emulate.pl -h``.
diff --git a/Documentation/boards/mips/qemu-malta.rst b/Documentation/boards/mips/qemu-malta.rst
index e188ae8c64..fd37d5edb2 100644
--- a/Documentation/boards/mips/qemu-malta.rst
+++ b/Documentation/boards/mips/qemu-malta.rst
@@ -10,31 +10,23 @@ QEMU run string:
qemu-system-mips -nodefaults -M malta -m 256 \
-device VGA -serial stdio -monitor null \
- -bios barebox-flash-image
+ -bios ./images/barebox-qemu-malta.img
Little-endian mode
------------------
-Running little-endian Malta is a bit tricky.
In little-endian mode the 32bit words in the boot flash image are swapped,
a neat trick which allows bi-endian firmware.
-You have to swap words of ``zbarebox.bin`` image, e.g.:
-
-.. code-block:: sh
-
- echo arch/mips/pbl/zbarebox.bin \
- | cpio --create \
- | cpio --extract --swap --unconditional
-
-QEMU run string:
+The barebox build generates a second ``./images/barebox-qemu-malta.img.swapped``
+image that can be used in this case, e.g.:
.. code-block:: sh
qemu-system-mipsel -nodefaults -M malta -m 256 \
-device VGA -serial stdio -monitor null \
- -bios barebox-flash-image
+ -bios ./images/barebox-qemu-malta.img.swapped
Using GXemul
diff --git a/Documentation/boards/riscv.rst b/Documentation/boards/riscv.rst
index 387b86c588..53d13550f3 100644
--- a/Documentation/boards/riscv.rst
+++ b/Documentation/boards/riscv.rst
@@ -41,25 +41,25 @@ TinyEMU
-------
TinyEMU can emulate a qemu-virt like machine with a RISC-V 32-, 64-
-and 128-bit CPU. It can run barebox with this sample configuration::
+and 128-bit CPU. It can run 32-bit barebox with this sample configuration:
- /* temu barebox-virt64.cfg */
- {
- version: 1,
- machine: "riscv64",
- memory_size: 256,
- bios: "bbl64.bin",
- kernel: "./images/barebox-dt-2nd.img",
- }
+.. literalinclude:: riscv/barebox-virt32.cfg
+
+as well as 64-bit barebox with this configuration:
+
+.. literalinclude:: riscv/barebox-virt64.cfg
``barebox-dt-2nd.img`` can be generated like with Qemu. Graphical
-output is also supported, but virtio input support is still missing.
+output and input are also supported.
To activate add::
display0: { device: "simplefb", width: 800, height: 600 },
+ input_device: "virtio",
into the config file.
+See https://barebox.org/jsbarebox/?graphic=1 for a live example.
+
Erizo
-----
diff --git a/Documentation/boards/riscv/barebox-virt32.cfg b/Documentation/boards/riscv/barebox-virt32.cfg
new file mode 100644
index 0000000000..5f0eb34eee
--- /dev/null
+++ b/Documentation/boards/riscv/barebox-virt32.cfg
@@ -0,0 +1,7 @@
+{
+ version: 1,
+ machine: "riscv32",
+ memory_size: 256,
+ bios: "bbl32.bin",
+ kernel: "images/barebox-dt-2nd.img",
+}
diff --git a/Documentation/boards/riscv/barebox-virt64.cfg b/Documentation/boards/riscv/barebox-virt64.cfg
new file mode 100644
index 0000000000..45e1cd8308
--- /dev/null
+++ b/Documentation/boards/riscv/barebox-virt64.cfg
@@ -0,0 +1,7 @@
+{
+ version: 1,
+ machine: "riscv64",
+ memory_size: 256,
+ bios: "bbl64.bin",
+ kernel: "images/barebox-dt-2nd.img",
+}
diff --git a/Kconfig b/Kconfig
index 29c32463fb..7c4cf36881 100644
--- a/Kconfig
+++ b/Kconfig
@@ -15,3 +15,4 @@ source "lib/Kconfig"
source "crypto/Kconfig"
source "firmware/Kconfig"
source "scripts/Kconfig"
+source "test/Kconfig"
diff --git a/Makefile b/Makefile
index 2e54fec876..f3a1bcc04c 100644
--- a/Makefile
+++ b/Makefile
@@ -343,11 +343,23 @@ ifeq ($(ARCH),arm64)
SRCARCH := arm
endif
+ifeq ($(ARCH),i386)
+ SRCARCH := x86
+endif
+
+ifeq ($(ARCH),x86_64)
+ SRCARCH := x86
+endif
+
# Support ARCH=ppc for backward compatibility
ifeq ($(ARCH),ppc)
SRCARCH := powerpc
endif
+ifeq ($(ARCH),um)
+ SRCARCH := sandbox
+endif
+
KCONFIG_CONFIG ?= .config
export KCONFIG_CONFIG
@@ -566,7 +578,7 @@ endif
include $(srctree)/scripts/Makefile.lib
# Objects we will link into barebox / subdirs we need to visit
-common-y := common/ drivers/ commands/ lib/ crypto/ net/ fs/ firmware/
+common-y := common/ drivers/ commands/ lib/ crypto/ net/ fs/ firmware/ test/
include $(srctree)/arch/$(SRCARCH)/Makefile
@@ -880,6 +892,20 @@ ifndef CONFIG_PBL_IMAGE
$(call cmd,check_file_size,$@,$(CONFIG_BAREBOX_MAX_IMAGE_SIZE))
endif
+install:
+ifeq ($(INSTALL_PATH),)
+ @echo 'error: INSTALL_PATH undefined' >&2
+ @exit 1
+endif
+ifdef CONFIG_PBL_IMAGE
+ $(Q)$(MAKE) $(build)=images __images_install
+ @install -t "$(INSTALL_PATH)" barebox.bin
+else
+ @install -t "$(INSTALL_PATH)" $(KBUILD_IMAGE)
+endif
+
+PHONY += install
+
# By default the uImage load address is 2MB below CONFIG_TEXT_BASE,
# leaving space for the compressed PBL image at 1MB below CONFIG_TEXT_BASE.
UIMAGE_BASE ?= $(shell printf "0x%08x" $$(($(CONFIG_TEXT_BASE) - 0x200000)))
diff --git a/arch/openrisc/Makefile b/arch/openrisc/Makefile
index 72d7fa3d53..1776f56df9 100644
--- a/arch/openrisc/Makefile
+++ b/arch/openrisc/Makefile
@@ -28,3 +28,5 @@ dts := arch/openrisc/dts
%.dtb: scripts
$(Q)$(MAKE) $(build)=$(dts) $(dts)/$@
+
+KBUILD_IMAGE := barebox
diff --git a/commands/Makefile b/commands/Makefile
index 447349fd15..4b45d266fd 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -130,5 +130,6 @@ obj-$(CONFIG_CMD_SEED) += seed.o
obj-$(CONFIG_CMD_IP_ROUTE_GET) += ip-route-get.o
obj-$(CONFIG_CMD_BTHREAD) += bthread.o
obj-$(CONFIG_CMD_UBSAN) += ubsan.o
+obj-$(CONFIG_CMD_SELFTEST) += selftest.o
UBSAN_SANITIZE_ubsan.o := y
diff --git a/commands/selftest.c b/commands/selftest.c
new file mode 100644
index 0000000000..a10f1467fe
--- /dev/null
+++ b/commands/selftest.c
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#define pr_fmt(fmt) "selftest: " fmt
+
+#include <common.h>
+#include <command.h>
+#include <getopt.h>
+#include <bselftest.h>
+#include <complete.h>
+
+static int run_selftest(const char *match, bool list)
+{
+ struct selftest *test;
+ int matches = 0;
+ int err = 0;
+
+ list_for_each_entry(test, &selftests, list) {
+ if (list) {
+ printf("%s\n", test->name);
+ matches++;
+ continue;
+ }
+
+ if (match && strcmp(test->name, match))
+ continue;
+
+ err |= test->func();
+ matches++;
+ }
+
+ if (!matches) {
+ if (match) {
+ printf("No tests matching '%s' found.\n", match);
+ return -EINVAL;
+ }
+
+ printf("No tests found.\n");
+ }
+
+ return err;
+}
+
+static int do_selftest(int argc, char *argv[])
+{
+ bool list = false;
+ int i, err = 0;
+ int opt;
+
+ while((opt = getopt(argc, argv, "l")) > 0) {
+ switch(opt) {
+ case 'l':
+ list = true;
+ break;
+ default:
+ return COMMAND_ERROR_USAGE;
+ }
+ }
+
+ if (optind == argc) {
+ err = run_selftest(NULL, list);
+ } else {
+ for (i = optind; i < argc; i++) {
+ err = run_selftest(argv[i], list);
+ if (err)
+ goto out;
+ }
+ }
+
+out:
+ return err ? COMMAND_ERROR : COMMAND_SUCCESS;
+}
+
+BAREBOX_CMD_HELP_START(selftest)
+BAREBOX_CMD_HELP_TEXT("Run enabled barebox self-tests")
+BAREBOX_CMD_HELP_TEXT("If run without arguments, all tests are run")
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("Options:")
+BAREBOX_CMD_HELP_OPT ("-l", "list available tests")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(selftest)
+ .cmd = do_selftest,
+ BAREBOX_CMD_DESC("Run selftests")
+ BAREBOX_CMD_OPTS("[-l] [tests..]")
+ BAREBOX_CMD_GROUP(CMD_GRP_MISC)
+ BAREBOX_CMD_COMPLETE(empty_complete)
+ BAREBOX_CMD_HELP(cmd_selftest_help)
+BAREBOX_CMD_END
diff --git a/common/startup.c b/common/startup.c
index 080feebf05..d170cb8a7c 100644
--- a/common/startup.c
+++ b/common/startup.c
@@ -37,6 +37,7 @@
#include <linux/ctype.h>
#include <watchdog.h>
#include <glob.h>
+#include <bselftest.h>
extern initcall_t __barebox_initcalls_start[], __barebox_early_initcalls_end[],
__barebox_initcalls_end[];
@@ -417,6 +418,9 @@ void __noreturn start_barebox(void)
pr_debug("initcalls done\n");
+ if (IS_ENABLED(CONFIG_SELFTEST_AUTORUN))
+ selftests_run();
+
if (barebox_main)
barebox_main();
diff --git a/images/.gitignore b/images/.gitignore
index eafdb44b5b..3a9a77dad1 100644
--- a/images/.gitignore
+++ b/images/.gitignore
@@ -32,3 +32,4 @@ barebox.sum
*.mvebu1img
*.stm32
*.nmon
+*.swapped
diff --git a/images/Makefile b/images/Makefile
index ee1347f6b6..cc330d9575 100644
--- a/images/Makefile
+++ b/images/Makefile
@@ -204,6 +204,11 @@ images: $(image-y-path) $(flash-link) $(flash-list) FORCE
@echo "images built:"
@for i in $(image-y); do echo $$i; done
+__images_install: images
+ @for i in $(image-y-path); do install -t "$(INSTALL_PATH)" $$i; done
+
+PHONY += __images_install
+
$(flash-link): $(link-dest) FORCE
$(call if_changed,ln)
@@ -213,5 +218,5 @@ $(flash-list): $(image-y-path)
clean-files := *.pbl *.pblb *.map start_*.imximg *.img barebox.z start_*.kwbimg \
start_*.kwbuartimg *.socfpgaimg *.mlo *.t20img *.t20img.cfg *.t30img \
*.t30img.cfg *.t124img *.t124img.cfg *.mlospi *.mlo *.mxsbs *.mxssd \
- start_*.simximg start_*.usimximg *.zynqimg *.image
+ start_*.simximg start_*.usimximg *.zynqimg *.image *.swapped
clean-files += pbl.lds
diff --git a/images/Makefile.malta b/images/Makefile.malta
index 5739ec4640..96d7b86b11 100644
--- a/images/Makefile.malta
+++ b/images/Makefile.malta
@@ -1,3 +1,11 @@
+quiet_cmd_bswap32_image = BSWAP4 $@
+ cmd_bswap32_image = cp $< $@ && \
+ truncate -s %4 $@ && \
+ objcopy -I binary --reverse-byte=4 $@
+
+$(obj)/%.img.swapped: $(obj)/%.img FORCE
+ $(call if_changed,bswap32_image)
+
pblb-$(CONFIG_BOARD_QEMU_MALTA) += start_qemu_malta
FILE_barebox-qemu-malta.img = start_qemu_malta.pblb
-image-$(CONFIG_BOARD_QEMU_MALTA) += barebox-qemu-malta.img
+image-$(CONFIG_BOARD_QEMU_MALTA) += barebox-qemu-malta.img barebox-qemu-malta.img.swapped
diff --git a/include/bselftest.h b/include/bselftest.h
new file mode 100644
index 0000000000..21eeba0526
--- /dev/null
+++ b/include/bselftest.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+#ifndef __BSELFTEST_H
+#define __BSELFTEST_H
+
+#include <linux/compiler.h>
+#include <linux/list.h>
+#include <init.h>
+
+enum bselftest_group {
+ BSELFTEST_core
+};
+
+struct selftest {
+ enum bselftest_group group;
+ const char *name;
+ int (*func)(void);
+ struct list_head list;
+};
+
+static inline int selftest_report(unsigned int total_tests, unsigned int failed_tests,
+ unsigned int skipped_tests)
+{
+ if (failed_tests == 0) {
+ if (skipped_tests) {
+ pr_info("skipped %u tests\n", skipped_tests);
+ pr_info("remaining %u tests passed\n", total_tests);
+ } else
+ pr_info("all %u tests passed\n", total_tests);
+ } else
+ pr_err("failed %u out of %u tests\n", failed_tests, total_tests);
+
+ return failed_tests ? -EINVAL : 0;
+}
+
+extern struct list_head selftests;
+
+#define BSELFTEST_GLOBALS() \
+static unsigned int total_tests __initdata; \
+static unsigned int failed_tests __initdata; \
+static unsigned int skipped_tests __initdata
+
+#ifdef CONFIG_SELFTEST
+#define __bselftest_initcall(func) late_initcall(func)
+void selftests_run(void);
+#else
+#define __bselftest_initcall(func)
+static inline void selftests_run(void)
+{
+}
+#endif
+
+#define bselftest(_group, _func) \
+ static int __bselftest_##_func(void) \
+ { \
+ total_tests = failed_tests = skipped_tests = 0; \
+ _func(); \
+ return selftest_report(total_tests, \
+ failed_tests, \
+ skipped_tests); \
+ } \
+ static __maybe_unused \
+ int __init _func##_bselftest_register(void) \
+ { \
+ static struct selftest this = { \
+ .group = BSELFTEST_##_group, \
+ .name = KBUILD_MODNAME, \
+ .func = __bselftest_##_func, \
+ }; \
+ list_add_tail(&this.list, &selftests); \
+ return 0; \
+ } \
+ __bselftest_initcall(_func##_bselftest_register);
+
+#endif
diff --git a/include/stdlib.h b/include/stdlib.h
index d405608724..8eb419e111 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -25,4 +25,9 @@ static inline u32 random32(void)
return ret;
}
+static inline u32 prandom_u32_max(u32 ep_ro)
+{
+ return (u32)(((u64) random32() * ep_ro) >> 32);
+}
+
#endif /* __STDLIB_H */
diff --git a/test/.gitignore b/test/.gitignore
new file mode 100644
index 0000000000..bee8a64b79
--- /dev/null
+++ b/test/.gitignore
@@ -0,0 +1 @@
+__pycache__
diff --git a/test/Kconfig b/test/Kconfig
new file mode 100644
index 0000000000..eece702e68
--- /dev/null
+++ b/test/Kconfig
@@ -0,0 +1,8 @@
+menuconfig TEST
+ bool "Testing"
+
+if TEST
+
+source "test/self/Kconfig"
+
+endif
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 0000000000..1b9eb2171a
--- /dev/null
+++ b/test/Makefile
@@ -0,0 +1 @@
+obj-y += self/
diff --git a/test/__init__.py b/test/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/__init__.py
diff --git a/test/arm/a15@vexpress_defconfig.yaml b/test/arm/a15@vexpress_defconfig.yaml
new file mode 100644
index 0000000000..941e914ab2
--- /dev/null
+++ b/test/arm/a15@vexpress_defconfig.yaml
@@ -0,0 +1,20 @@
+targets:
+ main:
+ drivers:
+ QEMUDriver:
+ qemu_bin: qemu
+ machine: vexpress-a15
+ cpu: cortex-a15
+ memory: 1024M
+ bios: barebox-vexpress-ca15.img
+ extra_args: ''
+ BareboxDriver:
+ prompt: 'barebox@[^:]+:[^ ]+ '
+ bootstring: 'commandline:'
+ BareboxTestStrategy: {}
+images:
+ barebox-vexpress-ca15.img: !template "$LG_BUILDDIR/images/barebox-vexpress-ca15.img"
+tools:
+ qemu: /usr/bin/qemu-system-arm
+imports:
+ - ../strategy.py
diff --git a/test/arm/a9@vexpress_defconfig.yaml b/test/arm/a9@vexpress_defconfig.yaml
new file mode 100644
index 0000000000..fefee153cf
--- /dev/null
+++ b/test/arm/a9@vexpress_defconfig.yaml
@@ -0,0 +1,20 @@
+targets:
+ main:
+ drivers:
+ QEMUDriver:
+ qemu_bin: qemu
+ machine: vexpress-a9
+ cpu: cortex-a9
+ memory: 1024M
+ bios: barebox-vexpress-ca9.img
+ extra_args: ''
+ BareboxDriver:
+ prompt: 'barebox@[^:]+:[^ ]+ '
+ bootstring: 'commandline:'
+ BareboxTestStrategy: {}
+images:
+ barebox-vexpress-ca9.img: !template "$LG_BUILDDIR/images/barebox-vexpress-ca9.img"
+tools:
+ qemu: /usr/bin/qemu-system-arm
+imports:
+ - ../strategy.py
diff --git a/test/arm/qemu_virt64_defconfig.yaml b/test/arm/qemu_virt64_defconfig.yaml
new file mode 100644
index 0000000000..ed308591da
--- /dev/null
+++ b/test/arm/qemu_virt64_defconfig.yaml
@@ -0,0 +1,24 @@
+targets:
+ main:
+ drivers:
+ QEMUDriver:
+ qemu_bin: qemu
+ machine: virt
+ cpu: cortex-a57
+ memory: 1024M
+ kernel: barebox-dt-2nd.img
+ extra_args: ''
+ BareboxDriver:
+ prompt: 'barebox@[^:]+:[^ ]+ '
+ bootstring: 'commandline:'
+ BareboxTestStrategy: {}
+ features:
+ - virtio-mmio
+ runner:
+ tuxmake_arch: arm64
+images:
+ barebox-dt-2nd.img: !template "$LG_BUILDDIR/images/barebox-dt-2nd.img"
+tools:
+ qemu: /usr/bin/qemu-system-aarch64
+imports:
+ - ../strategy.py
diff --git a/test/arm/vexpress_defconfig.yaml b/test/arm/vexpress_defconfig.yaml
new file mode 120000
index 0000000000..732f51b19d
--- /dev/null
+++ b/test/arm/vexpress_defconfig.yaml
@@ -0,0 +1 @@
+a9@vexpress_defconfig.yaml \ No newline at end of file
diff --git a/test/arm/virt@vexpress_defconfig.yaml b/test/arm/virt@vexpress_defconfig.yaml
new file mode 100644
index 0000000000..66ecf20690
--- /dev/null
+++ b/test/arm/virt@vexpress_defconfig.yaml
@@ -0,0 +1,22 @@
+targets:
+ main:
+ drivers:
+ QEMUDriver:
+ qemu_bin: qemu
+ machine: virt
+ cpu: cortex-a7
+ memory: 1024M
+ kernel: barebox-dt-2nd.img
+ extra_args: ''
+ BareboxDriver:
+ prompt: 'barebox@[^:]+:[^ ]+ '
+ bootstring: 'commandline:'
+ BareboxTestStrategy: {}
+ features:
+ - virtio-mmio
+images:
+ barebox-dt-2nd.img: !template "$LG_BUILDDIR/images/barebox-dt-2nd.img"
+tools:
+ qemu: /usr/bin/qemu-system-arm
+imports:
+ - ../strategy.py
diff --git a/test/conftest.py b/test/conftest.py
new file mode 100644
index 0000000000..1a043a91fa
--- /dev/null
+++ b/test/conftest.py
@@ -0,0 +1,27 @@
+import pytest
+import os
+from .py import helper
+
+
+@pytest.fixture(scope='function')
+def barebox(strategy, target):
+ strategy.transition('barebox')
+ return target.get_driver('BareboxDriver')
+
+@pytest.fixture(scope="session")
+def barebox_config(strategy, target):
+ strategy.transition('barebox')
+ command = target.get_driver("BareboxDriver")
+ return helper.get_config(command)
+
+def pytest_configure(config):
+ if 'LG_BUILDDIR' not in os.environ:
+ if 'KBUILD_OUTPUT' in os.environ:
+ os.environ['LG_BUILDDIR'] = os.environ['KBUILD_OUTPUT']
+ elif os.path.isdir('build'):
+ os.environ['LG_BUILDDIR'] = os.path.realpath('build')
+ else:
+ os.environ['LG_BUILDDIR'] = os.getcwd()
+
+ if os.environ['LG_BUILDDIR'] is not None:
+ os.environ['LG_BUILDDIR'] = os.path.realpath(os.environ['LG_BUILDDIR'])
diff --git a/test/emulate.pl b/test/emulate.pl
new file mode 100755
index 0000000000..78c2815884
--- /dev/null
+++ b/test/emulate.pl
@@ -0,0 +1,528 @@
+#!/usr/bin/env perl
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2021 Ahmad Fatoum
+
+use strict;
+use warnings;
+
+use Cwd;
+use File::Basename;
+use File::Spec;
+use File::Temp 'tempdir';
+use Getopt::Long;
+use List::Util 'first';
+use Pod::Usage;
+use YAML::XS 'LoadFile';
+
+my @QEMU_INTERACTIVE_OPTS = qw(-serial mon:stdio -trace file=/dev/null);
+
+my %targets;
+
+for my $arch (glob dirname(__FILE__) . "/*/") {
+ for my $cfg (glob "$arch/*.yaml") {
+ my $linkdest = readlink $cfg // '';
+
+ my $yaml = LoadFile($cfg);
+
+ defined $yaml && exists $yaml->{targets} && exists $yaml->{targets}{main}
+ or die "Invalid structure for $cfg\n";
+
+ my $path = File::Spec->abs2rel($cfg, getcwd);
+ $cfg = basename($cfg);
+ $cfg =~ s/\.yaml$//;
+ $linkdest =~ s{^.*?([^/]+)\.yaml$}{$1};
+
+ $targets{basename $arch}{$cfg} = $yaml->{targets}{main};
+ $targets{basename $arch}{$cfg}{path} = $path;
+ $targets{basename $arch}{$cfg}{tools} = $yaml->{tools};
+ $targets{basename $arch}{$cfg}{images} = $yaml->{images};
+ $targets{basename $arch}{$cfg}{alias} = $linkdest if $linkdest && $linkdest ne $cfg;
+ }
+}
+
+my %arch_aliases = (arm64 => 'arm', x86_64 => 'x86', i386 => 'x86', um => 'sandbox');
+
+my ($dryrun, $help, @blks, $rng, $list, $shell, $runtime, @kconfig_add, $artifacts);
+my ($tuxmake, $emulate, $clean, $extraconsoles, $test, $verbosity) = (1, 1, 1, 0, 0, 1);
+my ($kconfig_base, $kconfig_full) = (1, 0);
+
+my @OPTS;
+
+if (defined (my $idx = first { $ARGV[$_] eq '--' } 0 .. @ARGV - 1)) {
+ @OPTS = splice @ARGV, 1 + $idx;
+}
+
+my @emulate_only = qw/blk console rng/;
+
+GetOptions(
+ 'help|?|h' => \$help,
+ 'dryrun|n' => \$dryrun,
+ 'list|l' => \$list,
+ 'tuxmake!' => \$tuxmake,
+ 'verbosity=i' => \$verbosity,
+ 'artifacts=s' => \$artifacts,
+ 'runtime=s' => \$runtime,
+ 'blk=s@' => \@blks,
+ 'console+' => \$extraconsoles,
+ 'rng' => \$rng,
+ 'emulate!' => \$emulate,
+ 'clean!' => \$clean,
+ 'shell' => \$shell,
+ 'kconfig-base!' => \$kconfig_base,
+ 'kconfig-full!' => \$kconfig_full,
+ 'kconfig-add|K=s@' => \@kconfig_add,
+ 'test' => \$test,
+) or pod2usage(2);
+pod2usage(1) if $help;
+
+if ($test && (@blks || $extraconsoles || $rng)) {
+ die "Virtual devices on command-line not supported with --test\n";
+}
+
+my @ARCH = split /\s/, $ENV{ARCH} // '';
+@ARCH = @ARCH ? @ARCH : keys %targets;
+
+my $success = 0;
+
+for my $arch (@ARCH) {
+ my @targets = @ARGV ? @ARGV : keys %{$targets{$arch}};
+ @targets != 1 && !$tuxmake
+ and die "can't use --no-tuxmake with more than one config\n";
+
+ unless (defined $targets{$arch}) {
+ die "Unknown ARCH=$arch. Supported values:\n",
+ join(', ', keys %targets), "\n";
+ }
+
+ for my $config (@targets) {
+ $arch = $arch_aliases{$arch} // $arch;
+
+ $config = fileparse($config, ".yaml");
+
+ unless (defined $targets{$arch}{$config}) {
+ next;
+ }
+
+ if ($list) {
+ print "ARCH=$arch $config\n";
+ $success += 1;
+ next;
+ }
+
+ if (defined $targets{$arch}{$config}{alias}) {
+ next if grep { /^$targets{$arch}{$config}{alias}$/ } @targets;
+ $config = $targets{$arch}{$config}{alias};
+ redo;
+ }
+
+ print "# $config\n" if $dryrun;
+ $success += process($arch, $config);
+ }
+}
+
+$success > 0
+ or die "No suitable config found. $0 -l to list all built-in.\n";
+
+sub process {
+ my ($ARCH, $defconfig, %keys) = @_;
+ my $target = $targets{$ARCH}{$defconfig};
+
+ if (!exists ($target->{runner}{tuxmake_arch})) {
+ $target->{runner}{tuxmake_arch} = $ARCH;
+ }
+
+ my $dir;
+
+ $dir = tempdir("bareboxbuild-XXXXXXXXXX", TMPDIR => 1, CLEANUP => $clean);
+ report('mkdir', $dir);
+
+ my %opts = (
+ target => $target, builddir => $tuxmake ? $dir : getcwd,
+ defconfig => $defconfig,
+ extra_opts => [map { s/\{config\}/$defconfig/gr } @OPTS],
+ );
+
+ build(%opts) if $tuxmake;
+
+ while (my ($k, $v) = each %{$target->{runner}{download}}) {
+ if ($v =~ m{^[/.]}) {
+ symlink_force($v, "$dir/$k");
+ } else {
+ vsystem('curl', '-L', '--create-dirs', '-o', "$dir/$k", $v) == 0
+ or die "Failed to download resource `$v': $?\n";
+ }
+
+ symlink_force("$dir/$k", "$k") unless $tuxmake;
+ }
+
+ if ($shell) {
+ pushd($dir);
+ system($ENV{SHELL} // "/bin/sh");
+ popd();
+ }
+
+ return 1 unless $emulate;
+
+ if ($tuxmake) {
+ $ENV{KBUILD_OUTPUT} = $dir;
+ print "export KBUILD_OUTPUT=$ENV{KBUILD_OUTPUT}\n" if $dryrun;
+ }
+
+ my $success = $test ? test(%opts) : emulate(%opts);
+
+ report("rm", "-rd", $dir) if $clean && $tuxmake;
+
+ print "\n\n" if $dryrun;
+ return $success;
+}
+
+sub build {
+ my %args = @_;
+ my ($runner, $dir) = ($args{target}{runner}, $args{builddir});
+
+ $args{defconfig} =~ s/[^@]+@//g;
+
+ my @TUXMAKE_ARGS = ('-a', $runner->{tuxmake_arch}, '-k', $args{defconfig});
+
+ if (defined $runner->{kconfig_add}) {
+ for my $cfg (@{$runner->{kconfig_add}}) {
+ push @TUXMAKE_ARGS, "--kconfig-add=$cfg"
+ }
+ }
+
+ push @TUXMAKE_ARGS, "--kconfig-add=test/kconfig/base.cfg" if $kconfig_base || $kconfig_full;
+ push @TUXMAKE_ARGS, "--kconfig-add=test/kconfig/full.cfg" if $kconfig_full;
+
+ for (@kconfig_add) {
+ push @TUXMAKE_ARGS, "--kconfig-add=$_";
+ }
+
+ push @TUXMAKE_ARGS, "--runtime=$runtime" if $runtime;
+
+ push @TUXMAKE_ARGS, '-q' if $verbosity == 0;
+ push @TUXMAKE_ARGS, '-v' if $verbosity == 2;
+
+ vsystem('tuxmake', @TUXMAKE_ARGS, '-b', $dir, '-o',
+ $artifacts // "$dir/artifacts", 'default') == 0
+ or die "Error building: $?\n";
+}
+
+sub emulate {
+ my %args = @_;
+ my %target = %{$args{target}};
+ my @OPTS = @{$args{extra_opts}};
+
+ if (defined $target{drivers}{QEMUDriver}) {
+ my %qemu = %{$target{drivers}{QEMUDriver}};
+ my ($kernel, $bios, $dtb);
+ my $qemu_virtio;
+ my $i;
+
+ $kernel = abs_configpath($qemu{kernel}, \%args);
+ $bios = abs_configpath($qemu{bios}, \%args);
+ $dtb = abs_configpath($qemu{dtb}, \%args);
+
+ my @cmdline = ($target{tools}{$qemu{qemu_bin}},
+ '-M', $qemu{machine}, '-cpu', $qemu{cpu}, '-m', $qemu{memory});
+
+ push @cmdline, '-kernel', $kernel if defined $kernel;
+ push @cmdline, '-bios', $bios if defined $bios;
+ push @cmdline, '-dtb', $dtb if defined $dtb;
+
+ push @cmdline, @QEMU_INTERACTIVE_OPTS;
+ for (split /\s/, $qemu{extra_args}) {
+ push @cmdline, $_;
+ }
+
+ if (has_feature(\%target, 'virtio-pci')) {
+ $qemu_virtio = 'pci,disable-legacy=on,disable-modern=off';
+ push @{$target{features}}, 'pci';
+ push @{$target{features}}, 'virtio';
+ } elsif (has_feature(\%target, 'virtio-mmio')) {
+ $qemu_virtio = 'device';
+ push @{$target{features}}, 'virtio';
+ }
+
+ $i = 0;
+ for my $blk (@blks) {
+ if (has_feature(\%target, 'virtio')) {
+ $blk = rel2abs($blk);
+ push @cmdline,
+ '-drive', "if=none,file=$blk,format=raw,id=hd$i",
+ '-device', "virtio-blk-$qemu_virtio,drive=hd$i";
+ } else {
+ die "--blk unsupported for target\n";
+ }
+ }
+
+ # note that barebox doesn't yet support multiple virtio consoles
+ if ($extraconsoles) {
+ $i = 0;
+
+ if (defined $qemu_virtio) {
+ push @cmdline,
+ '-device', "virtio-serial-$qemu_virtio",
+ '-chardev', "pty,id=virtcon$i",
+ '-device', "virtconsole,chardev=virtcon$i,name=console.virtcon$i";
+
+ $i++;
+ }
+
+ if ($i < $extraconsoles) {
+ # ns16550 serial driver only works with x86 so far
+ if (has_feature(\%target, 'pci')) {
+ for (; $i < $extraconsoles; $i++) {
+ push @cmdline,
+ '-chardev', "pty,id=pcicon$i",
+ '-device', "pci-serial,chardev=pcicon$i";
+ }
+ } else {
+ warn "barebox currently supports only a single extra virtio console\n";
+ }
+ }
+ }
+
+ if (defined $rng) {
+ if (has_feature(\%target, 'virtio')) {
+ push @cmdline, '-device', "virtio-rng-$qemu_virtio";
+ } else {
+ die "--rng unsupported for target\n";
+ }
+ }
+
+ pushd($args{builddir}) if $tuxmake;
+
+ vsystem(@cmdline, @OPTS) == 0 or die "Error running emulator: $?\n";
+
+ } elsif (defined $target{drivers}{TinyEMUDriver}) {
+ my %temu = %{$target{drivers}{TinyEMUDriver}};
+ my $TEMU_CFG;
+ my $i = 0;
+
+ if (exists $temu{config}) {
+ $temu{config} = rel2abs($temu{config});
+ open(my $fh, '<', "$temu{config}")
+ or die "Could not open file '$temu{config}': $!";
+ $TEMU_CFG = do { local $/; <$fh> };
+ }
+
+ print ("$temu{config}\n");
+
+ defined $TEMU_CFG or die "Unknown tinyemu-config\n";
+
+ open(my $fh, '>', "$args{builddir}/tinyemu.cfg")
+ or die "Could not create file 'tinyemu.cfg': $!";
+ print $fh $TEMU_CFG;
+ print "cat >'tinyemu.cfg' <<EOF\n$TEMU_CFG\nEOF\n" if $dryrun;
+
+ for my $blk (@blks) {
+ $blk = rel2abs($blk);
+ $TEMU_CFG =~ s[\}(?!.*\})][drive$i: { file: "$blk" },\n}]ms
+ }
+
+ die "--console unsupported for target\n" if $extraconsoles;
+ die "--rng unsupported for target\n" if defined $rng;
+
+ pushd($args{builddir}) if $tuxmake;
+
+ vsystem($temu{temu_bin}, "tinyemu.cfg", @OPTS) == 0
+ or die "Error running emulator: $?\n";
+ } elsif (defined $target{drivers}{NativeExecutableDriver}) {
+ my %exec = %{$target{drivers}{NativeExecutableDriver}};
+
+ pushd($args{builddir}) if $tuxmake;
+
+ vsystem($exec{command}, @OPTS) == 0 or die "Error running emulator: $?\n";
+ }
+
+ popd() if $tuxmake;
+
+ return 1;
+}
+
+sub test {
+ my %args = @_;
+ my @OPTS = @{$args{extra_opts}};
+ my $pytest;
+ my $dir;
+
+ unless (defined $args{target}{drivers}{QEMUDriver}) {
+ warn "$args{target}{path}: Skipping test, no QEMUDriver\n";
+ return 0;
+ }
+
+ $pytest = `sh -c 'command -v labgrid-pytest'` ? 'labgrid-pytest' : 'pytest';
+
+ unshift @OPTS, "--verbosity=$verbosity";
+
+ vsystem($pytest, '--lg-env', "$args{target}{path}", "test/py", "--verbosity=1",
+ '--lg-log', @OPTS) == 0 or die "Error running 'labgrid-pytest': $?\n";
+
+ return 1;
+}
+
+sub has_feature {
+ defined first { lc($_) eq $_[1] } @{$_[0]->{features}}
+}
+
+sub report {
+ print join(' ', map { /\s/ ? "'$_'" : $_ } @_), "\n" if $dryrun;
+ 0;
+}
+
+sub vsystem {
+ if ($dryrun) {
+ return report(@_);
+ } else {
+ my $ret = system @_;
+ warn "vsystem: $!\n" if $ret == -1;
+ return $ret >> 8;
+ }
+}
+
+sub rel2abs {
+ File::Spec->rel2abs(@_)
+}
+
+sub abs_configpath {
+ my ($path, $args) = @_;
+ my $LG_BUILDDIR;
+
+ return unless defined $path;
+ $path = $args->{target}{images}{$path};
+ return unless defined $path;
+
+ if (exists $ENV{KBUILD_OUTPUT}) {
+ $LG_BUILDDIR = $ENV{KBUILD_OUTPUT};
+ } elsif (-d 'build') {
+ $LG_BUILDDIR = 'build';
+ } else {
+ $LG_BUILDDIR = getcwd();
+ }
+
+ $path =~ s/\$LG_BUILDDIR\b/$LG_BUILDDIR/g;
+
+ return rel2abs($path, $args->{builddir})
+}
+
+sub symlink_force {
+ unlink($_[1]);
+ symlink($_[0], $_[1]);
+}
+
+my @oldcwd;
+
+sub pushd {
+ my ($old, $new) = (getcwd, shift);
+ report ("pushd", $new);
+ push @oldcwd, $old;
+ chdir $new;
+ return $old;
+};
+
+sub popd {
+ report("popd");
+ chdir pop(@oldcwd)
+};
+
+__END__
+
+=head1 NAME
+
+emulate.pl - Build and run barebox under an emulator
+
+=head1 SYNOPSIS
+
+[ARCH=arch] emulate.pl [options] [defconfigs...] [--] [qemu/pytest-opts]
+
+=head1 OPTIONS
+
+Must be run from barebox source directory. If building out-of-tree,
+either set C<KBUILD_OUTPUT> or ensure the out-of-tree directory
+can be reached from a C<build> symlink in the current working
+directory.
+
+=over 8
+
+=item B<-?>, B<-h>, B<--help>
+
+Print this help message and exit
+
+=item B<-n>, B<--dryrun>
+
+Print commands and exit
+
+=item B<-l>, B<--list>
+
+Filter input with list of known targets
+
+=item B<--verbosity>=%u
+
+Specify output verbosity level for both tuxmake and pytest. Default value is 1.
+
+=item B<--no-tuxmake>
+
+Don't rerun tuxkmake. Assumes current working directory is finished build directory
+
+=item B<--artifacts>=%s
+
+Destination directory for the tuxmake artifacts. By default, this is
+the artifacts/ subdirectory in the temporary build directory and is
+not persisted (unless --no-clean is specified).
+
+=item B<--blk>=%s
+
+Pass block device to emulated barebox. Can be specified more than once
+
+=item B<--console>
+
+Pass one Virt I/O console to emulated barebox.
+
+=item B<--rng>
+
+instantiate Virt I/O random number generator
+
+=item B<--no-emulate>
+
+Don't emulate anything and exit directly after build
+
+=item B<--no-clean>
+
+Don't delete temporary working directory after
+
+=item B<--shell>
+
+Open shell in temporary working directory, after build, but before emulation
+
+=item B<--test>
+
+Instead of starting emulator interactively, run it under labgrid-pytest with
+the in-tree python tests.
+
+=item B<--runtime>=%s
+
+Runtime to use for the tuxmake builds. By default, builds are
+run natively on the build host.
+Supported: null, podman-local, podman, docker, docker-local.
+
+=item B<--no-kconfig-base>
+
+Don't apply test/kconfig/base.cfg. This may lead to more tests being
+skipped.
+
+=item B<--kconfig-full>
+
+Applies test/kconfig/full.cfg on top of base.cfg. This enables as much as
+possible to avoid skipping tests for disabled functionality.
+
+=item B<--kconfig_add>=%s, B<-K>=%s
+
+Extra kconfig fragments, merged on top of the defconfig and Kconfig
+fragments described by the YAML. In tree configuration fragment
+(e.g. `test/kconfig/virtio-pci.config`), path to local file, URL,
+`CONFIG_*=[y|m|n]`, or `# CONFIG_* is not set` are supported.
+Can be specified multiple times, and will be merged in the order given.
+
+=back
+
+=cut
diff --git a/test/kconfig/base.cfg b/test/kconfig/base.cfg
new file mode 100644
index 0000000000..6a9f683498
--- /dev/null
+++ b/test/kconfig/base.cfg
@@ -0,0 +1,4 @@
+CONFIG_TEST=y
+CONFIG_SELFTEST=y
+CONFIG_CMD_SELFTEST=y
+CONFIG_SELFTEST_ENABLE_ALL=y
diff --git a/test/kconfig/full.cfg b/test/kconfig/full.cfg
new file mode 100644
index 0000000000..39275768ea
--- /dev/null
+++ b/test/kconfig/full.cfg
@@ -0,0 +1,2 @@
+CONFIG_BTHREAD=y
+CONFIG_CMD_BTHREAD=y
diff --git a/test/kconfig/virtio-pci.cfg b/test/kconfig/virtio-pci.cfg
new file mode 100644
index 0000000000..78237b8fca
--- /dev/null
+++ b/test/kconfig/virtio-pci.cfg
@@ -0,0 +1,6 @@
+CONFIG_VIRTIO_MENU=y
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_VIRTIO_BLK=y
+CONFIG_HWRNG=y
+CONFIG_HW_RANDOM_VIRTIO=y
diff --git a/test/mips/be@qemu-malta_defconfig.yaml b/test/mips/be@qemu-malta_defconfig.yaml
new file mode 100644
index 0000000000..774023cd84
--- /dev/null
+++ b/test/mips/be@qemu-malta_defconfig.yaml
@@ -0,0 +1,22 @@
+targets:
+ main:
+ drivers:
+ QEMUDriver:
+ qemu_bin: qemu
+ machine: malta
+ cpu: M14Kc
+ memory: 256M
+ bios: barebox-qemu-malta.img
+ extra_args: ''
+ BareboxDriver:
+ prompt: 'barebox@[^:]+:[^ ]+ '
+ bootstring: 'commandline:'
+ BareboxTestStrategy: {}
+ features:
+ - virtio-pci
+images:
+ barebox-qemu-malta.img: !template "$LG_BUILDDIR/images/barebox-qemu-malta.img"
+tools:
+ qemu: /usr/bin/qemu-system-mips
+imports:
+ - ../strategy.py
diff --git a/test/mips/le@qemu-malta_defconfig.yaml b/test/mips/le@qemu-malta_defconfig.yaml
new file mode 100644
index 0000000000..8fc8c4dae9
--- /dev/null
+++ b/test/mips/le@qemu-malta_defconfig.yaml
@@ -0,0 +1,25 @@
+targets:
+ main:
+ drivers:
+ QEMUDriver:
+ qemu_bin: qemu
+ machine: malta
+ cpu: M14Kc
+ memory: 256M
+ bios: barebox-qemu-malta.img.swapped
+ extra_args: ''
+ BareboxDriver:
+ prompt: 'barebox@[^:]+:[^ ]+ '
+ bootstring: 'commandline:'
+ BareboxTestStrategy: {}
+ features:
+ - virtio-pci
+ runner:
+ kconfig_add:
+ - CONFIG_CPU_LITTLE_ENDIAN=y
+images:
+ barebox-qemu-malta.img.swapped: !template "$LG_BUILDDIR/images/barebox-qemu-malta.img.swapped"
+tools:
+ qemu: /usr/bin/qemu-system-mipsel
+imports:
+ - ../strategy.py
diff --git a/test/mips/qemu-malta_defconfig.yaml b/test/mips/qemu-malta_defconfig.yaml
new file mode 120000
index 0000000000..481b6e5477
--- /dev/null
+++ b/test/mips/qemu-malta_defconfig.yaml
@@ -0,0 +1 @@
+be@qemu-malta_defconfig.yaml \ No newline at end of file
diff --git a/test/openrisc/generic_defconfig.yaml b/test/openrisc/generic_defconfig.yaml
new file mode 100644
index 0000000000..0a2d4a7a18
--- /dev/null
+++ b/test/openrisc/generic_defconfig.yaml
@@ -0,0 +1,20 @@
+targets:
+ main:
+ drivers:
+ QEMUDriver:
+ qemu_bin: qemu
+ machine: or1k-sim
+ cpu: or1200
+ memory: 256M
+ kernel: barebox
+ extra_args: ''
+ BareboxDriver:
+ prompt: 'barebox@[^:]+:[^ ]+ '
+ bootstring: 'commandline:'
+ BareboxTestStrategy: {}
+images:
+ barebox: !template "$LG_BUILDDIR/barebox"
+tools:
+ qemu: /usr/bin/qemu-system-or1k
+imports:
+ - ../strategy.py
diff --git a/test/py/__init__.py b/test/py/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/py/__init__.py
diff --git a/test/py/helper.py b/test/py/helper.py
new file mode 100644
index 0000000000..4a68e83669
--- /dev/null
+++ b/test/py/helper.py
@@ -0,0 +1,38 @@
+from labgrid.driver import BareboxDriver
+import pytest
+import os
+from itertools import filterfalse
+
+
+def get_config(command):
+ """Returns the enabled config options of barebox, either from
+ a running instance if supported or by looking into .config
+ in the build directory.
+ Args:
+ command (BareboxDriver): An instance of the BareboxDriver
+ Returns:
+ list: list of the enabled config options
+ """
+ assert isinstance(command, BareboxDriver)
+
+ out, err, returncode = command.run("cat /env/data/config")
+ if returncode != 0:
+ try:
+ with open(os.environ['LG_BUILDDIR'] + "/.config") as f:
+ out = f.read().splitlines()
+ except OSError:
+ return set()
+
+ options = set()
+ for line in out:
+ if line and line.startswith("CONFIG_"):
+ options.add(line.split('=')[0])
+ return options
+
+
+def skip_disabled(config, *options):
+ if bool(config):
+ undefined = list(filterfalse(config.__contains__, options))
+
+ if bool(undefined):
+ pytest.skip("skipping test due to disabled " + (",".join(undefined)) + " dependency")
diff --git a/test/py/test_bselftests.py b/test/py/test_bselftests.py
new file mode 100644
index 0000000000..7417e74349
--- /dev/null
+++ b/test/py/test_bselftests.py
@@ -0,0 +1,8 @@
+import pytest
+from .helper import *
+
+def test_bselftest(barebox, barebox_config):
+ skip_disabled(barebox_config, "CONFIG_CMD_SELFTEST")
+
+ stdout, _, returncode = barebox.run('selftest', timeout=30)
+ assert returncode == 0, "selftest failed:\n{}\n".format("\n".join(stdout))
diff --git a/test/py/test_bthread.py b/test/py/test_bthread.py
new file mode 100644
index 0000000000..6e7b4ba500
--- /dev/null
+++ b/test/py/test_bthread.py
@@ -0,0 +1,23 @@
+import pytest
+from .helper import *
+
+def stale_spawners(barebox):
+ threads = barebox.run_check("bthread -i")
+ if len(threads) == 0:
+ return False
+ return len([t for t in threads if t.startswith('spawner')]) > 0
+
+def test_bthread(barebox, barebox_config):
+ skip_disabled(barebox_config, "CONFIG_CMD_BTHREAD")
+
+ assert not stale_spawners(barebox)
+
+ _, _, returncode = barebox.run('bthread -vvvv')
+ assert returncode == 0
+
+ assert not stale_spawners(barebox)
+
+ switches = int(barebox.run_check("bthread -c")[0].split()[0])
+ yields = int(barebox.run_check("bthread -t")[0].split()[0])
+
+ assert yields < switches
diff --git a/test/py/test_shell.py b/test/py/test_shell.py
new file mode 100644
index 0000000000..1af7d597a1
--- /dev/null
+++ b/test/py/test_shell.py
@@ -0,0 +1,36 @@
+import pytest
+from .helper import *
+
+
+def test_barebox_true(barebox, barebox_config):
+ skip_disabled(barebox_config, "CONFIG_CMD_TRUE")
+
+ _, _, returncode = barebox.run('true')
+ assert returncode == 0
+
+def test_barebox_false(barebox, barebox_config):
+ skip_disabled(barebox_config, "CONFIG_CMD_FALSE")
+
+ _, _, returncode = barebox.run('false')
+ assert returncode == 1
+
+def test_barebox_md5sum(barebox, barebox_config):
+ skip_disabled(barebox_config, "CONFIG_CMD_MD5SUM", "CONFIG_CMD_ECHO")
+
+ barebox.run_check("echo -o md5 test")
+ out = barebox.run_check("md5sum md5")
+ assert out == ["d8e8fca2dc0f896fd7cb4cb0031ba249 md5"]
+
+def test_barebox_version(barebox, barebox_config):
+ skip_disabled(barebox_config, "CONFIG_CMD_VERSION")
+
+ stdout, _, returncode = barebox.run('version')
+ assert 'barebox' in stdout[1]
+ assert returncode == 0
+
+def test_barebox_no_err(barebox, barebox_config):
+ skip_disabled(barebox_config, "CONFIG_CMD_DMESG")
+
+ # TODO extend by err once all qemu platforms conform
+ stdout, _, _ = barebox.run('dmesg -l crit,alert,emerg')
+ assert stdout == []
diff --git a/test/riscv/qemu@virt32_defconfig.yaml b/test/riscv/qemu@virt32_defconfig.yaml
new file mode 100644
index 0000000000..5c602635d4
--- /dev/null
+++ b/test/riscv/qemu@virt32_defconfig.yaml
@@ -0,0 +1,27 @@
+targets:
+ main:
+ drivers:
+ QEMUDriver:
+ qemu_bin: qemu
+ machine: virt
+ cpu: rv32
+ memory: 256M
+ kernel: barebox-dt-2nd.img
+ bios: opensbi-riscv32-generic-fw_dynamic.bin
+ extra_args: ''
+ BareboxDriver:
+ prompt: 'barebox@[^:]+:[^ ]+ '
+ bootstring: 'commandline:'
+ BareboxTestStrategy: {}
+ features:
+ - virtio-mmio
+ runner:
+ download:
+ opensbi-riscv32-generic-fw_dynamic.bin: https://github.com/qemu/qemu/blob/v5.2.0/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin?raw=true
+images:
+ barebox-dt-2nd.img: !template "$LG_BUILDDIR/images/barebox-dt-2nd.img"
+ opensbi-riscv32-generic-fw_dynamic.bin: !template "$LG_BUILDDIR/opensbi-riscv32-generic-fw_dynamic.bin"
+tools:
+ qemu: /usr/bin/qemu-system-riscv32
+imports:
+ - ../strategy.py
diff --git a/test/riscv/qemu@virt64_defconfig.yaml b/test/riscv/qemu@virt64_defconfig.yaml
new file mode 100644
index 0000000000..fefbd20e5c
--- /dev/null
+++ b/test/riscv/qemu@virt64_defconfig.yaml
@@ -0,0 +1,27 @@
+targets:
+ main:
+ drivers:
+ QEMUDriver:
+ qemu_bin: qemu
+ machine: virt
+ cpu: rv64
+ memory: 256M
+ kernel: barebox-dt-2nd.img
+ bios: opensbi-riscv64-generic-fw_dynamic.bin
+ extra_args: ''
+ BareboxDriver:
+ prompt: 'barebox@[^:]+:[^ ]+ '
+ bootstring: 'commandline:'
+ BareboxTestStrategy: {}
+ features:
+ - virtio-mmio
+ runner:
+ download:
+ opensbi-riscv64-generic-fw_dynamic.bin: https://github.com/qemu/qemu/blob/v5.2.0/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin?raw=true
+images:
+ barebox-dt-2nd.img: !template "$LG_BUILDDIR/images/barebox-dt-2nd.img"
+ opensbi-riscv64-generic-fw_dynamic.bin: !template "$LG_BUILDDIR/opensbi-riscv64-generic-fw_dynamic.bin"
+tools:
+ qemu: /usr/bin/qemu-system-riscv64
+imports:
+ - ../strategy.py
diff --git a/test/riscv/sifive_defconfig.yaml b/test/riscv/sifive_defconfig.yaml
new file mode 100644
index 0000000000..f7299453a4
--- /dev/null
+++ b/test/riscv/sifive_defconfig.yaml
@@ -0,0 +1,25 @@
+targets:
+ main:
+ drivers:
+ QEMUDriver:
+ qemu_bin: qemu
+ machine: sifive_u
+ cpu: sifive-u54
+ memory: 256M
+ kernel: barebox-hifive-unleashed.img
+ bios: opensbi-riscv64-generic-fw_dynamic.bin
+ extra_args: ''
+ BareboxDriver:
+ prompt: 'barebox@[^:]+:[^ ]+ '
+ bootstring: 'commandline:'
+ BareboxTestStrategy: {}
+ runner:
+ download:
+ opensbi-riscv64-generic-fw_dynamic.bin: https://github.com/qemu/qemu/blob/v5.2.0/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin?raw=true
+images:
+ barebox-hifive-unleashed.img: !template "$LG_BUILDDIR/images/barebox-hifive-unleashed.img"
+ opensbi-riscv64-generic-fw_dynamic.bin: !template "$LG_BUILDDIR/opensbi-riscv64-generic-fw_dynamic.bin"
+tools:
+ qemu: /usr/bin/qemu-system-riscv64
+imports:
+ - ../strategy.py
diff --git a/test/riscv/tinyemu@virt32_defconfig.yaml b/test/riscv/tinyemu@virt32_defconfig.yaml
new file mode 100644
index 0000000000..1102f36aca
--- /dev/null
+++ b/test/riscv/tinyemu@virt32_defconfig.yaml
@@ -0,0 +1,22 @@
+targets:
+ main:
+ drivers:
+ TinyEMUDriver: # not yet supported by labgrid, only for interactive use
+ temu_bin: temu
+ config: ./Documentation/boards/riscv/barebox-virt32.cfg
+ image: barebox-dt-2nd.img
+ BareboxDriver:
+ prompt: 'barebox@[^:]+:[^ ]+ '
+ bootstring: 'commandline:'
+ BareboxTestStrategy: {}
+ features:
+ - virtio-mmio
+ runner:
+ download:
+ bbl32.bin: https://barebox.org/jsbarebox/bbl32.bin
+images:
+ barebox-dt-2nd.img: !template "$LG_BUILDDIR/images/barebox-dt-2nd.img"
+tools:
+ temu: /usr/local/bin/temu
+imports:
+ - ../strategy.py
diff --git a/test/riscv/tinyemu@virt64_defconfig.yaml b/test/riscv/tinyemu@virt64_defconfig.yaml
new file mode 100644
index 0000000000..e9624160ef
--- /dev/null
+++ b/test/riscv/tinyemu@virt64_defconfig.yaml
@@ -0,0 +1,22 @@
+targets:
+ main:
+ drivers:
+ TinyEMUDriver: # not yet supported by labgrid, only for interactive use
+ temu_bin: temu
+ config: ./Documentation/boards/riscv/barebox-virt64.cfg
+ image: barebox-dt-2nd.img
+ BareboxDriver:
+ prompt: 'barebox@[^:]+:[^ ]+ '
+ bootstring: 'commandline:'
+ BareboxTestStrategy: {}
+ features:
+ - virtio-mmio
+ runner:
+ download:
+ bbl64.bin: https://barebox.org/jsbarebox/bbl64.bin
+images:
+ barebox-dt-2nd.img: !template "$LG_BUILDDIR/images/barebox-dt-2nd.img"
+tools:
+ temu: /usr/local/bin/temu
+imports:
+ - ../strategy.py
diff --git a/test/riscv/virt32_defconfig.yaml b/test/riscv/virt32_defconfig.yaml
new file mode 120000
index 0000000000..e9d7237f53
--- /dev/null
+++ b/test/riscv/virt32_defconfig.yaml
@@ -0,0 +1 @@
+qemu@virt32_defconfig.yaml \ No newline at end of file
diff --git a/test/riscv/virt64_defconfig.yaml b/test/riscv/virt64_defconfig.yaml
new file mode 120000
index 0000000000..ab419d5e7f
--- /dev/null
+++ b/test/riscv/virt64_defconfig.yaml
@@ -0,0 +1 @@
+qemu@virt64_defconfig.yaml \ No newline at end of file
diff --git a/test/sandbox/sandbox_defconfig.yaml b/test/sandbox/sandbox_defconfig.yaml
new file mode 100644
index 0000000000..784f491466
--- /dev/null
+++ b/test/sandbox/sandbox_defconfig.yaml
@@ -0,0 +1,12 @@
+targets:
+ main:
+ drivers:
+ NativeExecutableDriver: # not yet supported by labgrid, only for interactive use
+ command: ./barebox
+ image: barebox
+ runner:
+ tuxmake_arch: um
+images:
+ barebox: !template "$LG_BUILDDIR/barebox"
+tools:
+ qemu: /usr/local/bin/temu
diff --git a/test/self/Kconfig b/test/self/Kconfig
new file mode 100644
index 0000000000..73dc6c7b4f
--- /dev/null
+++ b/test/self/Kconfig
@@ -0,0 +1,39 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config SELFTEST
+ bool "Self-tests"
+ help
+ Configures support for in-barebox testing
+
+if SELFTEST
+
+config CMD_SELFTEST
+ bool "selftest command"
+ depends on COMMAND_SUPPORT
+ help
+ Command to run enabled barebox self-tests.
+ If run without arguments, all tests are run
+
+ Usage: selftest [-l] [tests...]
+
+ Options:
+ -l list available tests
+
+config SELFTEST_AUTORUN
+ bool "Run self-tests on startup"
+ help
+ Self tests are run automatically after initcalls are done,
+ but before barebox_main (shell or board-specific startup).
+
+config SELFTEST_ENABLE_ALL
+ bool "Enable all self-tests"
+ select SELFTEST_PRINTF
+ help
+ Selects all self-tests compatible with current configuration
+
+config SELFTEST_PRINTF
+ bool "printf selftest"
+ help
+ Tests barebox vsnprintf() functionality
+
+endif
diff --git a/test/self/Makefile b/test/self/Makefile
new file mode 100644
index 0000000000..b4aa49d6f8
--- /dev/null
+++ b/test/self/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_SELFTEST) += core.o
+obj-$(CONFIG_SELFTEST_PRINTF) += printf.o
diff --git a/test/self/core.c b/test/self/core.c
new file mode 100644
index 0000000000..caa4c27f6d
--- /dev/null
+++ b/test/self/core.c
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#define pr_fmt(fmt) "bselftest: " fmt
+
+#include <common.h>
+#include <bselftest.h>
+
+LIST_HEAD(selftests);
+
+void selftests_run(void)
+{
+ struct selftest *test;
+ int err = 0;
+
+ pr_notice("Configured tests will run now\n");
+
+ list_for_each_entry(test, &selftests, list)
+ err |= test->func();
+
+ if (err)
+ pr_err("Some selftests failed\n");
+}
diff --git a/test/self/printf.c b/test/self/printf.c
new file mode 100644
index 0000000000..52fe6ac0fa
--- /dev/null
+++ b/test/self/printf.c
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Test cases for printf facility.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <common.h>
+#include <bselftest.h>
+#include <linux/kernel.h>
+#include <module.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <linux/string.h>
+#include <errno.h>
+
+#include <linux/bitmap.h>
+
+#define BUF_SIZE 256
+#define PAD_SIZE 16
+#define FILL_CHAR '$'
+
+BSELFTEST_GLOBALS();
+
+static char *test_buffer __initdata;
+static char *alloced_buffer __initdata;
+
+static int __printf(4, 0) __init
+do_test(int bufsize, const char *expect, int elen,
+ const char *fmt, va_list ap)
+{
+ va_list aq;
+ int ret, written;
+
+ total_tests++;
+
+ memset(alloced_buffer, FILL_CHAR, BUF_SIZE + 2*PAD_SIZE);
+ va_copy(aq, ap);
+ ret = vsnprintf(test_buffer, bufsize, fmt, aq);
+ va_end(aq);
+
+ if (ret != elen) {
+ pr_warn("vsnprintf(buf, %d, \"%s\", ...) returned %d, expected %d\n",
+ bufsize, fmt, ret, elen);
+ pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote '%s', expected '%.*s'\n",
+ bufsize, fmt, test_buffer, ret, expect);
+ return 1;
+ }
+
+ if (memchr_inv(alloced_buffer, FILL_CHAR, PAD_SIZE)) {
+ pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote before buffer\n", bufsize, fmt);
+ return 1;
+ }
+
+ if (!bufsize) {
+ if (memchr_inv(test_buffer, FILL_CHAR, BUF_SIZE + PAD_SIZE)) {
+ pr_warn("vsnprintf(buf, 0, \"%s\", ...) wrote to buffer\n",
+ fmt);
+ return 1;
+ }
+ return 0;
+ }
+
+ written = min(bufsize-1, elen);
+ if (test_buffer[written]) {
+ pr_warn("vsnprintf(buf, %d, \"%s\", ...) did not nul-terminate buffer\n",
+ bufsize, fmt);
+ return 1;
+ }
+
+ if (memchr_inv(test_buffer + written + 1, FILL_CHAR, BUF_SIZE + PAD_SIZE - (written + 1))) {
+ pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote beyond the nul-terminator\n",
+ bufsize, fmt);
+ return 1;
+ }
+
+ if (memcmp(test_buffer, expect, written)) {
+ pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote '%s', expected '%.*s'\n",
+ bufsize, fmt, test_buffer, written, expect);
+ return 1;
+ }
+ return 0;
+}
+
+static void __printf(3, 4) __init
+__test(const char *expect, int elen, const char *fmt, ...)
+{
+ va_list ap;
+ int rand;
+ char *p;
+
+ if (elen >= BUF_SIZE) {
+ pr_err("error in test suite: expected output length %d too long. Format was '%s'.\n",
+ elen, fmt);
+ failed_tests++;
+ return;
+ }
+
+ va_start(ap, fmt);
+
+ /*
+ * Every fmt+args is subjected to four tests: Three where we
+ * tell vsnprintf varying buffer sizes (plenty, not quite
+ * enough and 0), and then we also test that bvasprintf would
+ * be able to print it as expected.
+ */
+ failed_tests += do_test(BUF_SIZE, expect, elen, fmt, ap);
+ rand = 1 + prandom_u32_max(elen+1);
+ /* Since elen < BUF_SIZE, we have 1 <= rand <= BUF_SIZE. */
+ failed_tests += do_test(rand, expect, elen, fmt, ap);
+ failed_tests += do_test(0, expect, elen, fmt, ap);
+
+ p = bvasprintf(fmt, ap);
+ if (p) {
+ total_tests++;
+ if (memcmp(p, expect, elen+1)) {
+ pr_warn("bvasprintf(..., \"%s\", ...) returned '%s', expected '%s'\n",
+ fmt, p, expect);
+ failed_tests++;
+ }
+ kfree(p);
+ }
+ va_end(ap);
+}
+
+#define test(expect, fmt, ...) \
+ __test(expect, strlen(expect), fmt, ##__VA_ARGS__)
+
+static void __init
+test_basic(void)
+{
+ /* Work around annoying "warning: zero-length gnu_printf format string". */
+ char nul = '\0';
+
+ test("", &nul);
+ test("100%", "100%%");
+ test("xxx%yyy", "xxx%cyyy", '%');
+ __test("xxx\0yyy", 7, "xxx%cyyy", '\0');
+}
+
+static void __init
+test_number(void)
+{
+ signed char val;
+
+ test("0x1234abcd ", "%#-12x", 0x1234abcd);
+ test(" 0x1234abcd", "%#12x", 0x1234abcd);
+ test("0|001| 12|+123| 1234|-123|-1234", "%d|%03d|%3d|%+d|% d|%+d|% d", 0, 1, 12, 123, 1234, -123, -1234);
+ test("0|1|1|32768|65535", "%hu|%hu|%hu|%hu|%hu", 0, 1, 65537, 32768, -1);
+ test("0|1|1|-32768|-1", "%hd|%hd|%hd|%hd|%hd", 0, 1, 65537, 32768, -1);
+ test("2015122420151225", "%ho%ho%#ho", 1037, 5282, -11627);
+
+ test("2015122420151225", "%ho%ho%#ho", 1037, 5282, -11627);
+
+ /*
+ * POSIX/C99: »The result of converting zero with an explicit
+ * precision of zero shall be no characters.« Hence the output
+ * from the below test should really be "00|0||| ". However,
+ * the kernel's printf also produces a single 0 in that
+ * case. This test case simply documents the current
+ * behaviour.
+ */
+ test("00|0|0|0|0", "%.2d|%.1d|%.0d|%.*d|%1.0d", 0, 0, 0, 0, 0, 0);
+
+ val = -16;
+ test("0xfffffff0|0xf0|0xf0", "%#02x|%#02x|%#02x", val, val & 0xff, (u8)val);
+
+ /* On some platforms, test failure here indicates a misaligned stack */
+ test("0x0807060504030201", "0x%016llx", 0x0807060504030201ULL);
+}
+
+static void __init
+test_string(void)
+{
+ test("", "%s%.0s", "", "123");
+ test("ABCD|abc|123", "%s|%.3s|%.*s", "ABCD", "abcdef", 3, "123456");
+ test("1 | 2|3 | 4|5 ", "%-3s|%3s|%-*s|%*s|%*s", "1", "2", 3, "3", 3, "4", -3, "5");
+ test("1234 ", "%-10.4s", "123456");
+ test(" 1234", "%10.4s", "123456");
+}
+
+#if BITS_PER_LONG == 64
+
+#define PTR_WIDTH 16
+#define PTR ((void *)0xffff0123456789abUL)
+#define PTR_STR "ffff0123456789ab"
+#define PTR_VAL_NO_CRNG "(____ptrval____)"
+#define ZEROS "00000000" /* hex 32 zero bits */
+#define ONES "ffffffff" /* hex 32 one bits */
+
+#else
+
+#define PTR_WIDTH 8
+#define PTR ((void *)0x456789ab)
+#define PTR_STR "456789ab"
+#define PTR_VAL_NO_CRNG "(ptrval)"
+#define ZEROS ""
+#define ONES ""
+
+#endif /* BITS_PER_LONG == 64 */
+
+/*
+ * NULL pointers aren't hashed.
+ */
+static void __init
+null_pointer(void)
+{
+ test(ZEROS "00000000", "%p", NULL);
+ test(ZEROS "00000000", "%px", NULL);
+}
+
+/*
+ * Error pointers aren't hashed.
+ */
+static void __init
+error_pointer(void)
+{
+ test(ONES "fffffff5", "%p", ERR_PTR(-11));
+ test(ONES "fffffff5", "%px", ERR_PTR(-11));
+}
+
+#define PTR_INVALID ((void *)0x000000ab)
+
+static void __init
+invalid_pointer(void)
+{
+ test(ZEROS "000000ab", "%px", PTR_INVALID);
+}
+
+static void __init
+ip4(void)
+{
+ IPaddr_t ip = cpu_to_be32(0x7f000001);
+
+ test("127.0.0.1", "%pI4", &ip);
+}
+
+static void __init
+ip(void)
+{
+ ip4();
+}
+
+static void __init
+uuid(void)
+{
+ const char uuid[16] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+ 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+
+ if (!IS_ENABLED(CONFIG_PRINTF_UUID))
+ return;
+
+ test("00010203-0405-0607-0809-0a0b0c0d0e0f", "%pUb", uuid);
+ test("00010203-0405-0607-0809-0A0B0C0D0E0F", "%pUB", uuid);
+ test("03020100-0504-0706-0809-0a0b0c0d0e0f", "%pUl", uuid);
+ test("03020100-0504-0706-0809-0A0B0C0D0E0F", "%pUL", uuid);
+}
+
+static void __init
+errptr(void)
+{
+ test("error 1234", "%pe", ERR_PTR(-1234));
+ test(sizeof(void *) == 8 ? "00000000000004d2" : "000004d2", "%pe", ERR_PTR(1234));
+
+ /* Check that %pe with a non-ERR_PTR gets treated as ordinary %p. */
+ BUILD_BUG_ON(IS_ERR(PTR));
+
+ if (!IS_ENABLED(CONFIG_ERRNO_MESSAGES))
+ return;
+ test("(Operation not permitted)", "(%pe)", ERR_PTR(-EPERM));
+ test("Requested probe deferral", "%pe", ERR_PTR(-EPROBE_DEFER));
+}
+
+static void __init
+test_pointer(void)
+{
+ null_pointer();
+ error_pointer();
+ invalid_pointer();
+ ip();
+ uuid();
+ errptr();
+}
+
+static void __init test_printf(void)
+{
+ alloced_buffer = malloc(BUF_SIZE + 2*PAD_SIZE);
+ if (!alloced_buffer)
+ return;
+ test_buffer = alloced_buffer + PAD_SIZE;
+
+ test_basic();
+ test_number();
+ test_string();
+ test_pointer();
+
+ free(alloced_buffer);
+}
+
+bselftest(core, test_printf);
+MODULE_AUTHOR("Rasmus Villemoes <linux@rasmusvillemoes.dk>");
+MODULE_LICENSE("GPL");
diff --git a/test/strategy.py b/test/strategy.py
new file mode 100644
index 0000000000..1fe1b7d818
--- /dev/null
+++ b/test/strategy.py
@@ -0,0 +1,53 @@
+import enum
+
+import attr
+
+from labgrid import target_factory, step
+from labgrid.strategy import Strategy, StrategyError
+
+class Status(enum.Enum):
+ unknown = 0
+ off = 1
+ barebox = 2
+
+@target_factory.reg_driver
+@attr.s(eq=False)
+class BareboxTestStrategy(Strategy):
+ """BareboxTestStrategy - Strategy to switch to barebox"""
+ bindings = {
+ "power": "PowerProtocol",
+ "console": "ConsoleProtocol",
+ "barebox": "BareboxDriver",
+ }
+
+ status = attr.ib(default=Status.unknown)
+
+ def __attrs_post_init__(self):
+ super().__attrs_post_init__()
+
+ @step(args=['status'])
+ def transition(self, status, *, step):
+ if not isinstance(status, Status):
+ status = Status[status]
+ if status == Status.unknown:
+ raise StrategyError("can not transition to {}".format(status))
+ elif status == self.status:
+ step.skip("nothing to do")
+ return # nothing to do
+ elif status == Status.off:
+ self.target.deactivate(self.console)
+ self.target.activate(self.power)
+ self.power.off()
+ elif status == Status.barebox:
+ self.transition(Status.off) # pylint: disable=missing-kwoa
+ self.target.activate(self.console)
+ # cycle power
+ self.power.cycle()
+ # interrupt barebox
+ self.target.activate(self.barebox)
+ else:
+ raise StrategyError(
+ "no transition found from {} to {}".
+ format(self.status, status)
+ )
+ self.status = status
diff --git a/test/x86/efi_defconfig.yaml b/test/x86/efi_defconfig.yaml
new file mode 120000
index 0000000000..942dc259d5
--- /dev/null
+++ b/test/x86/efi_defconfig.yaml
@@ -0,0 +1 @@
+pc@efi_defconfig.yaml \ No newline at end of file
diff --git a/test/x86/pc@efi_defconfig.yaml b/test/x86/pc@efi_defconfig.yaml
new file mode 100644
index 0000000000..280f5dcee9
--- /dev/null
+++ b/test/x86/pc@efi_defconfig.yaml
@@ -0,0 +1,31 @@
+targets:
+ main:
+ drivers:
+ QEMUDriver:
+ qemu_bin: qemu
+ machine: pc
+ cpu: Nehalem
+ memory: 1024M
+ kernel: barebox.efi
+ bios: OVMF.fd
+ extra_args: ''
+ BareboxDriver:
+ prompt: 'barebox@[^:]+:[^ ]+ '
+ bootstring: 'commandline:'
+ BareboxTestStrategy: {}
+ features:
+ - pci
+ runner:
+ tuxmake_arch: x86_64
+ kconfig_add:
+ - CONFIG_DRIVER_SERIAL_NS16550=y
+ - CONFIG_CONSOLE_ACTIVATE_FIRST=y # avoid duplicate output
+ download:
+ OVMF.fd: /usr/share/qemu/OVMF.fd
+images:
+ barebox.efi: !template "$LG_BUILDDIR/barebox.efi"
+ OVMF.fd: !template "$LG_BUILDDIR/OVMF.fd"
+tools:
+ qemu: /usr/bin/qemu-system-x86_64
+imports:
+ - ../strategy.py
diff --git a/test/x86/q35@efi_defconfig.yaml b/test/x86/q35@efi_defconfig.yaml
new file mode 100644
index 0000000000..dcb3f604c0
--- /dev/null
+++ b/test/x86/q35@efi_defconfig.yaml
@@ -0,0 +1,31 @@
+targets:
+ main:
+ drivers:
+ QEMUDriver:
+ qemu_bin: qemu
+ machine: q35
+ cpu: Nehalem
+ memory: 1024M
+ kernel: barebox.efi
+ bios: OVMF.fd
+ extra_args: -global ICH9-LPC.noreboot=false
+ BareboxDriver:
+ prompt: 'barebox@[^:]+:[^ ]+ '
+ bootstring: 'commandline:'
+ BareboxTestStrategy: {}
+ features:
+ - pci
+ runner:
+ tuxmake_arch: x86_64
+ kconfig_add:
+ - CONFIG_DRIVER_SERIAL_NS16550=y
+ - CONFIG_CONSOLE_ACTIVATE_FIRST=y # avoid duplicate output
+ download:
+ OVMF.fd: /usr/share/qemu/OVMF.fd
+images:
+ barebox.efi: !template "$LG_BUILDDIR/barebox.efi"
+ OVMF.fd: !template "$LG_BUILDDIR/OVMF.fd"
+tools:
+ qemu: /usr/bin/qemu-system-x86_64
+imports:
+ - ../strategy.py
diff --git a/test/x86/virtio@efi_defconfig.yaml b/test/x86/virtio@efi_defconfig.yaml
new file mode 100644
index 0000000000..326fcbc689
--- /dev/null
+++ b/test/x86/virtio@efi_defconfig.yaml
@@ -0,0 +1,32 @@
+targets:
+ main:
+ drivers:
+ QEMUDriver:
+ qemu_bin: qemu
+ machine: pc
+ cpu: Nehalem
+ memory: 1024M
+ kernel: barebox.efi
+ bios: OVMF.fd
+ extra_args: ''
+ BareboxDriver:
+ prompt: 'barebox@[^:]+:[^ ]+ '
+ bootstring: 'commandline:'
+ BareboxTestStrategy: {}
+ features:
+ - virtio-pci
+ runner:
+ tuxmake_arch: x86_64
+ kconfig_add:
+ - test/kconfig/virtio-pci.cfg
+ - CONFIG_DRIVER_SERIAL_NS16550=y
+ - CONFIG_CONSOLE_ACTIVATE_FIRST=y # avoid duplicate output
+ download:
+ OVMF.fd: /usr/share/qemu/OVMF.fd
+images:
+ barebox.efi: !template "$LG_BUILDDIR/barebox.efi"
+ OVMF.fd: !template "$LG_BUILDDIR/OVMF.fd"
+tools:
+ qemu: /usr/bin/qemu-system-x86_64
+imports:
+ - ../strategy.py