From b6a8ccb73a37c44028ddc4fc7c1500792e0f1cf4 Mon Sep 17 00:00:00 2001 From: Arnaud de Grandmaison Date: Wed, 18 Sep 2024 15:45:39 +0200 Subject: [PATCH 1/2] Add the LLVM Embedded Toolchain to the full image. While being mostly about Cortex-M devices, the LLVM Embedded Toolchain for Arm (https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm) provides an LLVM based bare-metal toolchain that provides support for aarch64. This is useful when one want to experiment in a lightweight fashion with new architectural features for example which do not require a full software stack, but still benefit from a baremetal toolchain with a standard library and semi-hosting support. As the executables may conflict with other llvm / clang installed binaries on the search path, the LLVM_ET is *not* added to the search path. Instead, the environment variable TCH_LLVM_ET_PATH is provided and the user should use it in his build scripts. I had to pass RT at starmap time as it seems that on my Mac at least global variables are not shared amongst processes and I was getting 'None' for IMAGE and RUNTIME. Those 2 have been merged into a single RT global variable to avoid duplication and risks of mismatches. Misc fixes in genassets.sh while being there. Signed-off-by: Arnaud de Grandmaison --- config/semihosting-app.yaml | 24 +++++++++++++++++ docker/Dockerfile.full | 12 +++++++++ docker/build.sh | 11 ++++++++ test/genassets.sh | 2 +- test/test.py | 38 +++++++++++++++++--------- test/tests/HelloWorld/HelloWorld.yaml | 39 +++++++++++++++++++++++++++ test/tests/HelloWorld/Makefile | 24 +++++++++++++++++ test/tests/HelloWorld/hello.c | 7 +++++ 8 files changed, 144 insertions(+), 13 deletions(-) create mode 100644 config/semihosting-app.yaml create mode 100644 test/tests/HelloWorld/HelloWorld.yaml create mode 100644 test/tests/HelloWorld/Makefile create mode 100644 test/tests/HelloWorld/hello.c diff --git a/config/semihosting-app.yaml b/config/semihosting-app.yaml new file mode 100644 index 0000000..8531a53 --- /dev/null +++ b/config/semihosting-app.yaml @@ -0,0 +1,24 @@ +# Copyright (c) 2024, Arm Limited. +# SPDX-License-Identifier: MIT + +%YAML 1.2 +--- +description: >- + Arm Architecture Envelope Model FVP configured for experimenting with SME2 + in baremetal mode. + +run: + name: FVP_Base_RevC-2xAEMvA + + rtvars: + PROGRAM: + type: path + value: "" + ARGS: + type: str + value: "" + + params: + --application cluster0.cpu0: ${rtvar:PROGRAM} + -C cluster0.cpu0.semihosting-cmd_line: "\"${rtvar:PROGRAM} ${rtvar:ARGS}\"" + diff --git a/docker/Dockerfile.full b/docker/Dockerfile.full index e007691..1c04f83 100644 --- a/docker/Dockerfile.full +++ b/docker/Dockerfile.full @@ -72,3 +72,15 @@ RUN apt-get install --assume-yes --no-install-recommends --option=debug::pkgProb libasound-dev:arm64 \ liburing-dev:arm64 \ libz-dev:arm64 + +# Install the LLVM ET toolchain. +ARG TCH_LLVM_ET_PKG_NAME +ARG TCH_LLVM_ET_PATH +COPY assets/${TCH_LLVM_ET_PKG_NAME} /tools/. +RUN cd /tools \ + && if [ "${TCH_LLVM_ET_PKG_NAME}" != "none" ]; then \ + tar xf ${TCH_LLVM_ET_PKG_NAME}; \ + fi \ + && rm ${TCH_LLVM_ET_PKG_NAME} \ + && cd - +ENV TCH_LLVM_ET_PATH="/tools/${TCH_LLVM_ET_PATH}" diff --git a/docker/build.sh b/docker/build.sh index 48f5fd7..ca23146 100755 --- a/docker/build.sh +++ b/docker/build.sh @@ -105,6 +105,9 @@ if [ "${ARCH}" = "x86_64" ]; then TCH_LLVM_PKG_URL=https://github.com/llvm/llvm-project/releases/download/llvmorg-15.0.6 TCH_LLVM_PKG_NAME=clang+llvm-15.0.6-x86_64-linux-gnu-ubuntu-18.04.tar.xz TCH_LLVM_PATH=clang+llvm-15.0.6-x86_64-linux-gnu-ubuntu-18.04/bin + TCH_LLVM_ET_PKG_URL=https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases/download/release-18.1.3 + TCH_LLVM_ET_PKG_NAME=LLVM-ET-Arm-18.1.3-Linux-x86_64.tar.xz + TCH_LLVM_ET_PATH=LLVM-ET-Arm-18.1.3-Linux-x86_64 TCH_PKG_URL_AARCH32=https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel TCH_PKG_NAME_AARCH32=arm-gnu-toolchain-13.2.rel1-x86_64-arm-none-eabi.tar.xz TCH_PATH_AARCH32=arm-gnu-toolchain-13.2.Rel1-x86_64-arm-none-eabi/bin @@ -119,6 +122,9 @@ elif [ "${ARCH}" = "aarch64" ] || [ "${ARCH}" = "arm64" ]; then TCH_LLVM_PKG_URL=https://github.com/llvm/llvm-project/releases/download/llvmorg-15.0.6 TCH_LLVM_PKG_NAME=clang+llvm-15.0.6-aarch64-linux-gnu.tar.xz TCH_LLVM_PATH=clang+llvm-15.0.6-aarch64-linux-gnu/bin + TCH_LLVM_ET_PKG_URL=https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases/download/release-18.1.3 + TCH_LLVM_ET_PKG_NAME=LLVM-ET-Arm-18.1.3-Linux-Aarch64.tar.xz + TCH_LLVM_ET_PATH=LLVM-ET-Arm-18.1.3-Linux-AArch64 TCH_PKG_URL_AARCH32=https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel TCH_PKG_NAME_AARCH32=arm-gnu-toolchain-13.2.rel1-aarch64-arm-none-eabi.tar.xz TCH_PATH_AARCH32=arm-gnu-toolchain-13.2.Rel1-aarch64-arm-none-eabi/bin @@ -151,6 +157,7 @@ cd ${ROOT} mkdir -p assets wget_or_cache assets/${TCH_PKG_NAME_AARCH64} ${TCH_PKG_URL_AARCH64}/${TCH_PKG_NAME_AARCH64} wget_or_cache assets/${TCH_LLVM_PKG_NAME} ${TCH_LLVM_PKG_URL}/${TCH_LLVM_PKG_NAME} +wget_or_cache assets/${TCH_LLVM_ET_PKG_NAME} ${TCH_LLVM_ET_PKG_URL}/${TCH_LLVM_ET_PKG_NAME} wget_or_cache assets/${TCH_PKG_NAME_AARCH32} ${TCH_PKG_URL_AARCH32}/${TCH_PKG_NAME_AARCH32} wget_or_cache assets/${FVP_PKG_NAME} ${FVP_PKG_URL}/${FVP_PKG_NAME} @@ -181,6 +188,8 @@ if [ "${DRIVER}" = "docker" ]; then --build-arg=TCH_PATH_AARCH32=${TCH_PATH_AARCH32} \ --build-arg=TCH_LLVM_PKG_NAME=${TCH_LLVM_PKG_NAME} \ --build-arg=TCH_LLVM_PATH=${TCH_LLVM_PATH} \ + --build-arg=TCH_LLVM_ET_PKG_NAME=${TCH_LLVM_ET_PKG_NAME} \ + --build-arg=TCH_LLVM_ET_PATH=${TCH_LLVM_ET_PATH} \ --file=Dockerfile.full \ --tag=${REGISTRY}/base-full-nofvp:${VERSION}-${ARCH} \ . @@ -227,6 +236,8 @@ elif [ "${DRIVER}" = "kaniko" ]; then --build-arg=TCH_PATH_AARCH32=${TCH_PATH_AARCH32} \ --build-arg=TCH_LLVM_PKG_NAME=${TCH_LLVM_PKG_NAME} \ --build-arg=TCH_LLVM_PATH=${TCH_LLVM_PATH} \ + --build-arg=TCH_LLVM_ET_PKG_NAME=${TCH_LLVM_ET_PKG_NAME} \ + --build-arg=TCH_LLVM_ET_PATH=${TCH_LLVM_ET_PATH} \ --dockerfile=Dockerfile.full \ --destination=${REGISTRY}/base-full-nofvp:${VERSION}-${ARCH} \ --context=. diff --git a/test/genassets.sh b/test/genassets.sh index bb3a9b9..42458da 100755 --- a/test/genassets.sh +++ b/test/genassets.sh @@ -16,7 +16,7 @@ The following parameters are valid: -h Show this help -R Specify the choice for shrinkwrap runtime. Defaults to 'docker' -n Dryrun mode for shrinkwrap build - -v Versbose mode for shrinkwrap build + -v Verbose mode for shrinkwrap build " RUNTIME=docker diff --git a/test/test.py b/test/test.py index e39b59e..1b09efd 100755 --- a/test/test.py +++ b/test/test.py @@ -15,8 +15,7 @@ from xml.sax.saxutils import escape, quoteattr import yaml -RUNTIME = None -IMAGE = None +RT = None FVPJOBS = None @@ -27,6 +26,20 @@ KERNEL = os.path.join(ASSETS, 'Image') BOOTWRAPPER = os.path.join(ASSETS, 'linux-system.axf') ROOTFS = os.path.join(ASSETS, 'rootfs.ext4') +# Look for local tests in $CWD/tests, and add them to SHRINKWRAP_CONFIG. +TESTS_DIR = os.path.join(SCRIPTDIR, 'tests') +SHRINKWRAP_CONFIG = list() +os_shrinkwrap_config = os.getenv('SHRINKWRAP_CONFIG') +if os_shrinkwrap_config: + SHRINKWRAP_CONFIG.append(os_shrinkwrap_config) + +for dirname in os.listdir(TESTS_DIR): + dir = os.path.join(TESTS_DIR, dirname) + if os.path.isdir(dir): + SHRINKWRAP_CONFIG.append(dir) + +if SHRINKWRAP_CONFIG: + os.putenv('SHRINKWRAP_CONFIG', ':'.join(SHRINKWRAP_CONFIG)) ARCH_LATEST = 'v9.5' CONFIGS = [ @@ -128,6 +141,11 @@ CONFIGS = [ }, }, }, + { + 'config': 'HelloWorld.yaml', + 'btvars': {}, + 'rtvars': {}, + }, ] @@ -254,7 +272,6 @@ def build_configs(configs, overlay=None, btvarss=None): status = 'pass' error = None - rt = f'-R {RUNTIME} -I {IMAGE}' cleanargs = f'{" ".join(configs)} {f"-o {overlay}" if overlay else ""}' if btvarss is None: @@ -279,8 +296,8 @@ def build_configs(configs, overlay=None, btvarss=None): buildargs = f'{tmpfilename} {f"-o {overlay}" if overlay else ""}' try: - run(f'shrinkwrap {rt} clean {cleanargs}', None) - run(f'shrinkwrap {rt} buildall {buildargs}', None) + run(f'shrinkwrap {RT} clean {cleanargs}', None) + run(f'shrinkwrap {RT} buildall {buildargs}', None) except Exception as e: status = 'fail' error = str(e) @@ -296,7 +313,7 @@ def build_configs(configs, overlay=None, btvarss=None): } for config, btvars in zip(configs, btvarss)] -def run_config(config, overlay, rtvars, tag, capture): +def run_config(config, rt, overlay, rtvars, tag, capture): def make_rtcmds(rtvars): return ' '.join([f'-r {k}={v}' for k, v in rtvars.items()]) @@ -313,7 +330,6 @@ def run_config(config, overlay, rtvars, tag, capture): 'tag': tag, } - rt = f'-R {RUNTIME} -I {IMAGE}' overlay = f'-o {overlay}' if overlay else '' args = f'{config} {overlay} {runargs}' @@ -339,7 +355,7 @@ def run_configs(configs, overlay=None, rtvarss=None): params = [] for config, _rtvars in zip(configs, rtvarss): for tag, rtvars in _rtvars.items(): - params.append((config, overlay, rtvars, tag, FVPJOBS > 1)) + params.append((config, RT, overlay, rtvars, tag, FVPJOBS > 1)) with mp.Pool(processes=FVPJOBS) as pool: for result, stdout in pool.starmap(run_config, params): @@ -422,11 +438,9 @@ def main(): args = parser.parse_args() - global RUNTIME - global IMAGE + global RT global FVPJOBS - RUNTIME = args.runtime - IMAGE = args.image + RT = f'-R {args.runtime} -I {args.image}' FVPJOBS = args.fvpjobs do_main(args) diff --git a/test/tests/HelloWorld/HelloWorld.yaml b/test/tests/HelloWorld/HelloWorld.yaml new file mode 100644 index 0000000..4ea60b9 --- /dev/null +++ b/test/tests/HelloWorld/HelloWorld.yaml @@ -0,0 +1,39 @@ +# Copyright (c) 2024, Arm Limited. +# SPDX-License-Identifier: MIT + +%YAML 1.2 +--- +description: >- + An example baremetal app, the famous 'Hello, world !'. + +layers: + - arch/v9.2.yaml + - semihosting-app.yaml + +concrete: true + +build: + + HelloWorld: + sourcedir: ${param:configdir} + + build: + - make BUILD_DIR=${param:builddir} + + artifacts: + PROGRAM: ${param:builddir}/hello + +run: + + params: + -C bp.secure_memory: 0 + + # FVP Performance tweaks. + -C cache_state_modelled: 0 # Disable d-cache and i-cache state for all components + -C cluster0.check_memory_attributes: 0 # Disable checking that SW-set memory attributes conform to architecturally required constraints + -C cluster1.check_memory_attributes: 0 + + # Misc FVP controls. + -C bp.vis.disable_visualisation: 1 + -C bp.ve_sysregs.exit_on_shutdown: 1 # SYS_CFG_SHUTDOWN exits simulation + --stat: null diff --git a/test/tests/HelloWorld/Makefile b/test/tests/HelloWorld/Makefile new file mode 100644 index 0000000..fd047db --- /dev/null +++ b/test/tests/HelloWorld/Makefile @@ -0,0 +1,24 @@ +ifndef TCH_LLVM_ET_PATH +$(error TCH_LLVM_ET_PATH is not set) +endif + +ifndef BUILD_DIR +$(error BUILD_DIR is not set) +endif + +CC=${TCH_LLVM_ET_PATH}/bin/clang + +CFLAGS=--target=aarch64-none-elf -march=armv9.2-a -fno-exceptions -fno-rtti -std=c99 -O2 -Wall +LDFLAGS=-lcrt0-semihost -lsemihost -Wl,--defsym=__boot_flash=0x80000000 -Wl,--defsym=__flash=0x80001000 -Wl,--defsym=__ram=0x81000000 -T picolibc.ld + +all: ${BUILD_DIR}/hello + +${BUILD_DIR}/%: %.c + ${CC} ${CFLAGS} ${LDFLAGS} -o $@ $< + +.PHONY: clean realclean +clean: + -rm ${BUILD_DIR}/hello ${BUILD_DIR}/*.o + +realclean: + -rm -Rf ${BUILD_DIR} diff --git a/test/tests/HelloWorld/hello.c b/test/tests/HelloWorld/hello.c new file mode 100644 index 0000000..28ecea9 --- /dev/null +++ b/test/tests/HelloWorld/hello.c @@ -0,0 +1,7 @@ +#include +#include + +int main(int argc, char *argv[]) { + printf("Hello, world !\n"); + return EXIT_SUCCESS; +} -- GitLab From f75f30f8885b939be062479cb2c60c2efa8a295d Mon Sep 17 00:00:00 2001 From: Arnaud de Grandmaison Date: Thu, 14 Nov 2024 12:03:17 +0100 Subject: [PATCH 2/2] Add an overlay to emit a tarmac trace. This is a generally useful overlay that could be used quite often to get a Tarmac trace from the FVP, for debugging for example: $ shrinkwrap run --overlay tarmac-trace.yaml --rtvar TARMAC_TRACE_FILE=my_trace.tarmac The TARMAC_TRACE_FILE has a default value (trace.tarmac) so the trace file name can be left out of the shrinkwrap invocation. Signed-off-by: Arnaud de Grandmaison --- config/tarmac-trace.yaml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 config/tarmac-trace.yaml diff --git a/config/tarmac-trace.yaml b/config/tarmac-trace.yaml new file mode 100644 index 0000000..fc8e13c --- /dev/null +++ b/config/tarmac-trace.yaml @@ -0,0 +1,22 @@ +# Copyright (c) 2024, Arm Limited. +# SPDX-License-Identifier: MIT + +%YAML 1.2 +--- +description: >- + Make the FVP emit a tarmac trace. + +run: + + rtvars: + TARMAC_TRACE_FILE: + type: path + value: "trace.tarmac" + + params: + # Enable Tarmac trace. Use some leading spaces to fool shrinkwrap's handling of plugins and + # reduce the likelyhood of a clash with another plugin requested by another overlay or a + # user defined yaml configuration file. + ' --plugin': $$(dirname $$(which FVP_Base_RevC-2xAEMvA))/../../plugins/$$(basename $$(dirname $$(which FVP_Base_RevC-2xAEMvA)))/TarmacTrace.so + -C TRACE.TarmacTrace.trace-file: ${rtvar:TARMAC_TRACE_FILE} + -- GitLab