summaryrefslogtreecommitdiff
path: root/payloads
diff options
context:
space:
mode:
authorJakub Czapiga <jacz@semihalf.com>2021-09-15 14:52:45 +0200
committerFelix Held <felix-coreboot@felixheld.de>2021-10-11 12:59:57 +0000
commit3d91b47b425ffb880c0ed6c45fd04ba48d95ca8d (patch)
tree828ac9be4df77c66c9f06435f560e5124db0f9f9 /payloads
parentb40fdbaa648639c2922732e2fa137c3ebcc78e4e (diff)
libpayload: Add mock architecture
Mock architecture can be used to build libpayload using host compiler. It can be enabled by setting ARCH_MOCK=y in the dotconfig. It sets LITTLE_ENDIAN=y, as most machines these days use little-endian CPUs. Libpayload will use HOSTCC as CC, HOSTLD as LD, etc. instead of tools provided by xcompile. Mock architecture configuration can be used by payloads for testing purposes. Thanks to it, tests can be architecture-independent, and can be executed without requiring compatible Kconfig options, e.g. ARCH_ARM64=y for ARM64 machine. However, one has to provide implementation for most architecture-specific functions present in arch/* directories. Signed-off-by: Jakub Czapiga <jacz@semihalf.com> Change-Id: Ie3a6e6f6cad2f8a2e48a8e546d3b79c577653080 Reviewed-on: https://review.coreboot.org/c/coreboot/+/57708 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Julius Werner <jwerner@chromium.org>
Diffstat (limited to 'payloads')
-rw-r--r--payloads/libpayload/Kconfig10
-rw-r--r--payloads/libpayload/Makefile41
-rw-r--r--payloads/libpayload/Makefile.inc1
-rw-r--r--payloads/libpayload/arch/mock/Kconfig16
-rw-r--r--payloads/libpayload/arch/mock/Makefile.inc7
-rw-r--r--payloads/libpayload/arch/mock/head.c3
-rw-r--r--payloads/libpayload/arch/mock/libpayload.ldscript3
-rw-r--r--payloads/libpayload/arch/mock/mock_media.c10
-rw-r--r--payloads/libpayload/arch/mock/virtual.c10
-rwxr-xr-xpayloads/libpayload/bin/lpgcc13
-rw-r--r--payloads/libpayload/include/mock/arch/barrier.h13
-rw-r--r--payloads/libpayload/include/mock/arch/cache.h18
-rw-r--r--payloads/libpayload/include/mock/arch/io.h29
-rw-r--r--payloads/libpayload/include/mock/arch/types.h33
-rw-r--r--payloads/libpayload/include/mock/arch/virtual.h15
-rw-r--r--payloads/libpayload/sample/Makefile5
-rw-r--r--payloads/libpayload/sample/arch_mock/Makefile48
-rw-r--r--payloads/libpayload/sample/arch_mock/hello.c13
-rw-r--r--payloads/libpayload/sample/arch_mock/hello_mocks.c43
19 files changed, 329 insertions, 2 deletions
diff --git a/payloads/libpayload/Kconfig b/payloads/libpayload/Kconfig
index f7d78e069d..382f5af751 100644
--- a/payloads/libpayload/Kconfig
+++ b/payloads/libpayload/Kconfig
@@ -121,6 +121,14 @@ config ARCH_ARM64
help
Support the ARM64 architecture
+config ARCH_MOCK
+ bool "Mock architecture (for unit tests)"
+ help
+ This enables the mock architecture (for unit tests) that is intended
+ to be used for testing purposes, to either test payloads or libpayload itself.
+ It provides necessary headers, but requires mocking (providing implementation
+ for) arch-specific functions.
+
endchoice
config MULTIBOOT
@@ -150,6 +158,7 @@ config BASE_ADDRESS
default 0x04000000 if ARCH_ARM
default 0x80100000 if ARCH_ARM64
default 0x00100000 if ARCH_X86
+ default 0x00000000 if ARCH_MOCK
help
This is the base address for the payload.
@@ -480,3 +489,4 @@ config IO_ADDRESS_SPACE
source "arch/arm/Kconfig"
source "arch/arm64/Kconfig"
source "arch/x86/Kconfig"
+source "arch/mock/Kconfig"
diff --git a/payloads/libpayload/Makefile b/payloads/libpayload/Makefile
index 90f6b23836..923106248c 100644
--- a/payloads/libpayload/Makefile
+++ b/payloads/libpayload/Makefile
@@ -74,6 +74,14 @@ HOSTCC = gcc
HOSTCXX = g++
HOSTCFLAGS := -I$(srck) -I$(objk) -g
HOSTCXXFLAGS := -I$(srck) -I$(objk)
+HOSTAS ?= as
+HOSTLD ?= ld
+HOSTNM ?= nm
+HOSTOBJCOPY ?= objcopy
+HOSTOBJDUMP ?= objdump
+HOSTREADELF ?= readelf
+HOSTSTRIP ?= strip
+HOSTAR ?= ar
DOXYGEN := doxygen
DOXYGEN_OUTPUT_DIR := doxygen
@@ -95,6 +103,7 @@ include $(HAVE_DOTCONFIG)
ARCHDIR-$(CONFIG_LP_ARCH_ARM) := arm
ARCHDIR-$(CONFIG_LP_ARCH_ARM64) := arm64
ARCHDIR-$(CONFIG_LP_ARCH_X86) := x86
+ARCHDIR-$(CONFIG_LP_ARCH_MOCK) := mock
ARCH-y := $(ARCHDIR-y)
@@ -103,6 +112,7 @@ ARCH-y := $(ARCHDIR-y)
ARCH-$(CONFIG_LP_ARCH_ARM) := arm
ARCH-$(CONFIG_LP_ARCH_ARM64) := arm64
ARCH-$(CONFIG_LP_ARCH_X86) := x86_32
+ARCH-$(CONFIG_LP_ARCH_MOCK) := mock
# Three cases where we don't need fully populated $(obj) lists:
# 1. when no .config exists
@@ -129,6 +139,31 @@ real-all: config
else
+ifeq ($(CONFIG_LP_ARCH_MOCK),y)
+
+# Create empty xcompile to satisfy install script
+$(shell echo '' > $(xcompile))
+
+CC := $(HOSTCC)
+CC-mock := $(HOSTCC)
+AS := $(HOSTAS)
+AS-mock := $(HOSTAS)
+LD := $(HOSTLD)
+LD-mock := $(HOSTLD)
+NM := $(HOSTNM)
+NM-mock := $(HOSTNM)
+OBJCOPY := $(HOSTOBJCOPY)
+OBJCOPY-mock := $(HOSTOBJCOPY)
+OBJDUMP := $(HOSTOBJDUMP)
+OBJDUMP-mock := $(HOSTOBJDUMP)
+READELF := $(HOSTREADELF)
+READELF-mock := $(HOSTEADELF)
+STRIP := $(HOSTSTRIP)
+STRIP-mock := $(HOSTSTRIP)
+AR := $(HOSTAR)
+AR-mock := $(HOSTAR)
+else
+
# in addition to the dependency below, create the file if it doesn't exist
# to silence stupid warnings about a file that would be generated anyway.
$(if $(wildcard $(xcompile)),,$(shell \
@@ -152,12 +187,16 @@ OBJDUMP := $(OBJDUMP_$(ARCH-y))
READELF := $(READELF_$(ARCH-y))
STRIP := $(STRIP_$(ARCH-y))
AR := $(AR_$(ARCH-y))
+endif
CFLAGS += -std=gnu11 $(CFLAGS_$(ARCH-y))
ifneq ($(INNER_SCANBUILD),y)
ifeq ($(CONFIG_LP_COMPILER_LLVM_CLANG),y)
-CC:=clang -m32
+CC:=clang
+ifneq ($(CONFIG_LP_ARCH_MOCK),y)
+CC += -m32
+endif
HOSTCC:=clang
endif
endif
diff --git a/payloads/libpayload/Makefile.inc b/payloads/libpayload/Makefile.inc
index a67ba77b67..df0f14298f 100644
--- a/payloads/libpayload/Makefile.inc
+++ b/payloads/libpayload/Makefile.inc
@@ -33,6 +33,7 @@ export KERNELVERSION := 0.2.0
ARCHDIR-$(CONFIG_LP_ARCH_ARM) := arm
ARCHDIR-$(CONFIG_LP_ARCH_ARM64) := arm64
ARCHDIR-$(CONFIG_LP_ARCH_X86) := x86
+ARCHDIR-$(CONFIG_LP_ARCH_MOCK) := mock
DESTDIR ?= install
real-target: lib
diff --git a/payloads/libpayload/arch/mock/Kconfig b/payloads/libpayload/arch/mock/Kconfig
new file mode 100644
index 0000000000..3903a76005
--- /dev/null
+++ b/payloads/libpayload/arch/mock/Kconfig
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+if ARCH_MOCK
+
+config ARCH_MOCK_BIG_ENDIAN
+ bool "Use big-endian for mock architecture"
+ default n
+ help
+ This option enables big-endinan support in the code.
+
+config ARCH_SPECIFIC_OPTIONS
+ def_bool y
+ select LITTLE_ENDIAN if !ARCH_MOCK_BIG_ENDIAN
+ select BIG_ENDIAN if ARCH_MOCK_BIG_ENDIAN
+
+endif
diff --git a/payloads/libpayload/arch/mock/Makefile.inc b/payloads/libpayload/arch/mock/Makefile.inc
new file mode 100644
index 0000000000..f15f0f9f1d
--- /dev/null
+++ b/payloads/libpayload/arch/mock/Makefile.inc
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+head.o-y += head.c
+
+libc-y += virtual.c
+
+libcbfs-$(CONFIG_LP_CBFS) += mock_media.c
diff --git a/payloads/libpayload/arch/mock/head.c b/payloads/libpayload/arch/mock/head.c
new file mode 100644
index 0000000000..55a691f910
--- /dev/null
+++ b/payloads/libpayload/arch/mock/head.c
@@ -0,0 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* This file is empty on purpose. It should not be used. */
diff --git a/payloads/libpayload/arch/mock/libpayload.ldscript b/payloads/libpayload/arch/mock/libpayload.ldscript
new file mode 100644
index 0000000000..6842c9ad5c
--- /dev/null
+++ b/payloads/libpayload/arch/mock/libpayload.ldscript
@@ -0,0 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* This file is empty on purpose. It is present only to satisfy install script */
diff --git a/payloads/libpayload/arch/mock/mock_media.c b/payloads/libpayload/arch/mock/mock_media.c
new file mode 100644
index 0000000000..2bb06edc29
--- /dev/null
+++ b/payloads/libpayload/arch/mock/mock_media.c
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <cbfs.h>
+
+int libpayload_init_default_cbfs_media(struct cbfs_media *media);
+
+__attribute__((weak)) int libpayload_init_default_cbfs_media(struct cbfs_media *media)
+{
+ return -1;
+}
diff --git a/payloads/libpayload/arch/mock/virtual.c b/payloads/libpayload/arch/mock/virtual.c
new file mode 100644
index 0000000000..6f369d2dcb
--- /dev/null
+++ b/payloads/libpayload/arch/mock/virtual.c
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <unistd.h>
+
+unsigned long virtual_offset = 0;
+
+int getpagesize(void)
+{
+ return 4096;
+}
diff --git a/payloads/libpayload/bin/lpgcc b/payloads/libpayload/bin/lpgcc
index c0fe56adf5..3a76f13d17 100755
--- a/payloads/libpayload/bin/lpgcc
+++ b/payloads/libpayload/bin/lpgcc
@@ -91,13 +91,24 @@ if [ "$CONFIG_LP_ARCH_X86" = "y" ]; then
_ARCHEXTRA="-m32 "
_ARCH=x86
fi
+if [ "$CONFIG_LP_ARCH_MOCK" = "y" ]; then
+ _ARCHINCDIR=$_INCDIR/mock
+ _ARCHLIBDIR=$_LIBDIR/mock
+ _ARCHEXTRA=""
+ _ARCH=mock
+fi
if [ -f $_LIBDIR/libpayload.ldscript ]; then
_LDDIR=$_LIBDIR
elif [ -f $BASE/../arch/$_ARCH/libpayload.ldscript ]; then
_LDDIR=$BASE/../arch/$_ARCH
fi
-_LDSCRIPT="-Wl,-T,$_LDDIR/libpayload.ldscript"
+# Host arch should youse default linker script
+if [ "$CONFIG_LP_ARCH_MOCK" = "y" ]; then
+ _LDSCRIPT=""
+else
+ _LDSCRIPT="-Wl,-T,$_LDDIR/libpayload.ldscript"
+fi
trygccoption() {
$DEFAULT_CC $1 -S -xc /dev/null -o /dev/null &> /dev/null
diff --git a/payloads/libpayload/include/mock/arch/barrier.h b/payloads/libpayload/include/mock/arch/barrier.h
new file mode 100644
index 0000000000..aed115bb64
--- /dev/null
+++ b/payloads/libpayload/include/mock/arch/barrier.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __ARCH_BARRIER_H__
+#define __ARCH_BARRIER_H__
+
+/* No memory barrier on mock build */
+#define mb()
+/* No read memory barrier on mock build */
+#define rmb()
+/* No write memory barrier on mock build */
+#define wmb()
+
+#endif /* __ARCH_BARRIER_H__ */
diff --git a/payloads/libpayload/include/mock/arch/cache.h b/payloads/libpayload/include/mock/arch/cache.h
new file mode 100644
index 0000000000..1e71d5e0e2
--- /dev/null
+++ b/payloads/libpayload/include/mock/arch/cache.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __ARCH_CACHE_H__
+#define __ARCH_CACHE_H__
+
+/* No support for cache in the mock architecture */
+
+#define dmb()
+#define dsb()
+#define dcache_clean_all()
+#define dcache_clean_by_mva(addr, len)
+#define dcache_invalidate_all()
+#define dcache_invalidate_by_mva(addr, len)
+#define dcache_clean_invalidate_all()
+#define dcache_clean_invalidate_by_mva(addr, len)
+#define cache_sync_instructions()
+
+#endif /* __ARCH_CACHE_H__ */
diff --git a/payloads/libpayload/include/mock/arch/io.h b/payloads/libpayload/include/mock/arch/io.h
new file mode 100644
index 0000000000..2bb625562e
--- /dev/null
+++ b/payloads/libpayload/include/mock/arch/io.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _ARCH_IO_H
+#define _ARCH_IO_H
+
+#include <inttypes.h>
+
+/* Functions in this file are unimplemented by default. Tests are expected to implement
+ mocks for these functions, if tests will call functions using functions listed below. */
+
+uint8_t readb(volatile const void *_a);
+uint16_t readw(volatile const void *_a);
+uint32_t readl(volatile const void *_a);
+
+void writeb(uint8_t _v, volatile void *_a);
+void writew(uint16_t _v, volatile void *_a);
+void writel(uint32_t _v, volatile void *_a);
+
+uint8_t read8(volatile const void *addr);
+uint16_t read16(volatile const void *addr);
+uint32_t read32(volatile const void *addr);
+uint64_t read64(volatile const void *addr);
+
+void write8(volatile void *addr, uint8_t val);
+void write16(volatile void *addr, uint16_t val);
+void write32(volatile void *addr, uint32_t val);
+void write64(volatile void *addr, uint64_t val);
+
+#endif /* _ARCH_IO_H */
diff --git a/payloads/libpayload/include/mock/arch/types.h b/payloads/libpayload/include/mock/arch/types.h
new file mode 100644
index 0000000000..8f090caa9b
--- /dev/null
+++ b/payloads/libpayload/include/mock/arch/types.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _ARCH_TYPES_H
+#define _ARCH_TYPES_H
+
+typedef unsigned char uint8_t;
+typedef unsigned char u8;
+typedef signed char int8_t;
+typedef signed char s8;
+
+typedef unsigned short uint16_t;
+typedef unsigned short u16;
+typedef signed short int16_t;
+typedef signed short s16;
+
+typedef unsigned int uint32_t;
+typedef unsigned int u32;
+typedef signed int int32_t;
+typedef signed int s32;
+
+typedef unsigned long long uint64_t;
+typedef unsigned long long u64;
+typedef signed long long int64_t;
+typedef signed long long s64;
+
+typedef long time_t;
+typedef long suseconds_t;
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+#endif /* _ARCH_TYPES_H */
diff --git a/payloads/libpayload/include/mock/arch/virtual.h b/payloads/libpayload/include/mock/arch/virtual.h
new file mode 100644
index 0000000000..bf786d5256
--- /dev/null
+++ b/payloads/libpayload/include/mock/arch/virtual.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _ARCH_VIRTUAL_H
+#define _ARCH_VIRTUAL_H
+
+/* virtual_offset has to be declared if used */
+extern unsigned long virtual_offset;
+
+#define virt_to_phys(virt) ((unsigned long)(virt) + virtual_offset)
+#define phys_to_virt(phys) ((void *)((unsigned long)(phys) - virtual_offset))
+
+#define virt_to_bus(addr) virt_to_phys(addr)
+#define bus_to_virt(addr) phys_to_virt(addr)
+
+#endif
diff --git a/payloads/libpayload/sample/Makefile b/payloads/libpayload/sample/Makefile
index 637e45dee1..1249e9a017 100644
--- a/payloads/libpayload/sample/Makefile
+++ b/payloads/libpayload/sample/Makefile
@@ -26,8 +26,13 @@
## SUCH DAMAGE.
##
+
# Sample libpayload Makefile.
include ../.config
+ifeq ($(CONFIG_LP_ARCH_MOCK),y)
+$(error This sample program does not support ARCH_MOCK. Use sample/arch_mock instead)
+endif
+
include ../build/xcompile
ARCH-$(CONFIG_LP_ARCH_ARM) := arm
diff --git a/payloads/libpayload/sample/arch_mock/Makefile b/payloads/libpayload/sample/arch_mock/Makefile
new file mode 100644
index 0000000000..a1e748111e
--- /dev/null
+++ b/payloads/libpayload/sample/arch_mock/Makefile
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+# Sample libpayload Makefile for ARCH_MOCK
+# ARCH_MOCK is not intended to be used with xcompile
+include ../../.config
+
+ifneq ($(CONFIG_LP_ARCH_MOCK),y)
+$(error This example supports ARCH_MOCK only.)
+endif
+
+CC := gcc
+AS := as
+OBJCOPY := objcopy
+LIBPAYLOAD_DIR := ../../install/libpayload
+CFLAGS := -fno-builtin -Wall -Werror -Os \
+ -include $(LIBPAYLOAD_DIR)/include/kconfig.h \
+ -include $(LIBPAYLOAD_DIR)/include/compiler.h \
+ -I $(LIBPAYLOAD_DIR)/include \
+ -I $(LIBPAYLOAD_DIR)/include/mock \
+ -ffunction-sections \
+ -fdata-sections -g3
+LDFLAGS := -Wl,--gc-sections
+TARGET := hello
+OBJS := $(TARGET).o
+OBJS-mock := $(TARGET)_mocks.o
+LIBPAYLOAD-local := libpayload.a
+mocks := console_write
+
+all: $(TARGET).elf
+
+$(TARGET).elf: $(OBJS) $(OBJS-mock) $(LIBPAYLOAD-local)
+ $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBPAYLOAD-local) \
+ -Wl,--exclude-libs,ALL -lc $(OBJS-mock)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+%.S.o: %.S
+ $(AS) --32 -o $@ $<
+
+# Copy libpayload and weaken all mocked symbols
+$(LIBPAYLOAD-local): $(LIBPAYLOAD_DIR)/lib/libpayload.a
+ $(OBJCOPY) $(foreach mock,$(mocks),--weaken-symbol=$(mock)) $< $@
+
+clean:
+ rm -f $(TARGET).elf *.o $(LIBPAYLOAD-local)
+
+distclean: clean
diff --git a/payloads/libpayload/sample/arch_mock/hello.c b/payloads/libpayload/sample/arch_mock/hello.c
new file mode 100644
index 0000000000..5a96e42e75
--- /dev/null
+++ b/payloads/libpayload/sample/arch_mock/hello.c
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* Example file for libpayload. */
+
+#include <libpayload-config.h>
+#include <libpayload.h>
+
+int main(void)
+{
+ printf("Hello world!\n");
+ halt();
+ return 0;
+}
diff --git a/payloads/libpayload/sample/arch_mock/hello_mocks.c b/payloads/libpayload/sample/arch_mock/hello_mocks.c
new file mode 100644
index 0000000000..84e86ff257
--- /dev/null
+++ b/payloads/libpayload/sample/arch_mock/hello_mocks.c
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <libpayload-config.h>
+#include <arch/types.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <stdio.h>
+
+/* Use libc version. calling exit() or abort() would cause infinite recursion */
+__attribute__((noreturn))
+void _exit(int);
+
+__attribute__((noreturn))
+void halt(void)
+{
+ _exit(0);
+}
+
+#define TEST_SYMBOL(symbol, value) asm(".set " #symbol ", " #value "\n\t.globl " #symbol)
+
+#define TEST_REGION(region, size) uint8_t _##region[size]; \
+ TEST_SYMBOL(_e##region, _##region + size); \
+ TEST_SYMBOL(_##region##_size, size)
+
+TEST_REGION(heap, CONFIG_LP_HEAP_SIZE);
+
+uint64_t timer_raw_value(void)
+{
+ return 0;
+}
+
+uint64_t timer_hz(void)
+{
+ return 0;
+}
+
+/* Not present in libpayload. Can be used to write to real stdout. */
+ssize_t write(int fildes, const void *buf, size_t nbyte);
+
+void console_write(const void *buffer, size_t count)
+{
+ write(1, buffer, count);
+}