diff --git a/scripts/tests b/scripts/tests index 6e6f13399f..59a512acb0 100755 --- a/scripts/tests +++ b/scripts/tests @@ -560,6 +560,8 @@ class Tests: log = logger(test_type, scheme_str, self.args.cross_prefix, opt) args = ["make", test_type.make_run_target(scheme)] + if test_type.is_example() is False: + args += [f"OPT={int(opt)}", f"AUTO={int(self.args.auto)}"] if test_type.is_benchmark() is False and test_type.is_example() is False: args += self.make_j() if test_type.make_dir() != "": diff --git a/test/abicheck/abicheck.c b/test/abicheck/abicheck.c index 8b03501939..2400e07a00 100644 --- a/test/abicheck/abicheck.c +++ b/test/abicheck/abicheck.c @@ -22,12 +22,20 @@ static const abicheck_entry_t all_checks[] = {{NULL, NULL}}; /* Return-code convention: see abicheck_common.h. SKIPPED means the kernel * built but the host lacks the runtime capability; the generated check * decides this via mld_sys_check_capability. */ -int main(void) +/* Prototype for a re-#define'd main, to satisfy -Wmissing-prototypes. */ +#if defined(main) +int main(int argc, char *argv[]); +#endif + +int main(int argc, char *argv[]) { int failed_tests = 0; int selftest_failures; const abicheck_entry_t *entry; + (void)argc; + (void)argv; + /* Meta-test the ABI checker before trusting kernel verdicts (see selftest.h). */ selftest_failures = abicheck_selftest(); diff --git a/test/mk/components.mk b/test/mk/components.mk index b61a8185ab..e6328e8a80 100644 --- a/test/mk/components.mk +++ b/test/mk/components.mk @@ -177,16 +177,10 @@ endif # ABI checker ABICHECK_DIR = $(BUILD_DIR)/abicheck -# Map $(ARCH) to the abicheck per-arch subdir name. For most architectures -# the subdir matches $(ARCH); one exception: -# - arm-none-eabi- targets: $(ARCH) = arm (a generic label for the -# bare-metal Cortex-M family). The abicheck subdir is the more specific -# armv81m. -ifeq ($(ARCH),arm) -ABICHECK_ARCH := armv81m -else -ABICHECK_ARCH := $(ARCH) -endif +# A platform can select the ABI independently of make's host/cross ARCH (for +# example, Zephyr owns its target toolchain). Otherwise, use the architecture +# inferred from the compiler prefix. +ABICHECK_ARCH ?= $(ARCH) ABICHECK_SOURCES = test/abicheck/abicheck.c test/abicheck/selftest.c ABICHECK_SOURCES += $(wildcard test/abicheck/$(ABICHECK_ARCH)/abicheck_$(ABICHECK_ARCH).c) @@ -268,4 +262,15 @@ ifneq ($(EXTRA_SOURCES),) $(ABICHECK_EXTRA_OBJS): CFLAGS += $(EXTRA_SOURCES_CFLAGS) endif +ifndef CUSTOM_BUILD $(ABICHECK_DIR)/bin/abicheck: $(ABICHECK_OBJS) $(ABICHECK_EXTRA_OBJS) +else +# Custom builds compile sources through their own build system. Pass the ABI +# checker inputs and flags through the same interface as the other tests, and +# mark this as a standalone checker so the platform does not add libmldsa. +$(ABICHECK_DIR)/bin/abicheck: CUSTOM_BUILD_ABICHECK := 1 +$(ABICHECK_DIR)/bin/abicheck: TEST_SRCS += $(ABICHECK_ALL_SOURCES) +$(ABICHECK_DIR)/bin/abicheck: CFLAGS += \ + $(ABICHECK_ASM_CFLAGS) $(ABICHECK_FULL_API_CFLAGS) +$(ABICHECK_DIR)/bin/abicheck: $(ABICHECK_ALL_SOURCES) $(CUSTOM_BUILD_DEPS) +endif diff --git a/test/mk/rules.mk b/test/mk/rules.mk index 835cbfc326..637fdefb3c 100644 --- a/test/mk/rules.mk +++ b/test/mk/rules.mk @@ -148,9 +148,8 @@ $(BUILD_DIR)/mldsa87/sign_hook/%.S.o: %.S $(CONFIG) $(Q)$(CC) -c -o $@ $(CFLAGS) $< $(BUILD_DIR)/abicheck/bin/%: $(CONFIG) - $(Q)echo " LD $@" $(Q)[ -d $(@D) ] || mkdir -p $(@D) - $(Q)$(LD) $(LDFLAGS) -o $@ $(filter %.o,$^) $(LDLIBS) + $(Q)$(LINK) $(BUILD_DIR)/abicheck/%.c.o: %.c $(CONFIG) $(Q)echo " CC $@" @@ -161,4 +160,3 @@ $(BUILD_DIR)/abicheck/%.S.o: %.S $(CONFIG) $(Q)echo " AS $@" $(Q)[ -d $(@D) ] || mkdir -p $(@D) $(Q)$(CC) -c -o $@ $(CFLAGS) $< - diff --git a/test/zephyr/app/CMakeLists.txt b/test/zephyr/app/CMakeLists.txt index b5d56d4761..5df00ce7ec 100644 --- a/test/zephyr/app/CMakeLists.txt +++ b/test/zephyr/app/CMakeLists.txt @@ -13,15 +13,17 @@ project(mldsa_native_zephyr) # ZEPHYR_NATIVE_ROOT, space separated # ZEPHYR_TEST_CFLAGS - the test binary's CFLAGS (see below); includes the # parameter set (-DMLD_CONFIG_PARAMETER_SET=...) +# ZEPHYR_ABICHECK - build the standalone ABI checker sources without the +# normal mldsa amalgamation set(R ${ZEPHYR_NATIVE_ROOT}) separate_arguments(_test_srcs UNIX_COMMAND "${ZEPHYR_TEST_SRCS}") list(TRANSFORM _test_srcs PREPEND ${R}/) -target_sources(app PRIVATE - ${R}/mldsa/mldsa_native.c - ${_test_srcs} -) +target_sources(app PRIVATE ${_test_srcs}) +if(NOT ZEPHYR_ABICHECK) + target_sources(app PRIVATE ${R}/mldsa/mldsa_native.c) +endif() target_include_directories(app PRIVATE ${R}/mldsa @@ -85,14 +87,14 @@ set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/shim_nucleo_n657x0_q.c # Optional native FIPS202 backend (e.g. Armv8.1-M MVE on Cortex-M55). The # monolithic mldsa_native.c already includes the backend C sources; its # assembly counterpart comes from mldsa_native_asm.S. -if(ZEPHYR_FIPS202_BACKEND) +if(ZEPHYR_FIPS202_BACKEND AND NOT ZEPHYR_ABICHECK) target_sources(app PRIVATE ${R}/mldsa/mldsa_native_asm.S) target_compile_definitions(app PRIVATE MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 "MLD_CONFIG_FIPS202_BACKEND_FILE=\"${ZEPHYR_FIPS202_BACKEND}\"") endif() -# Each test brings its own int main(void); rename it so the selected Zephyr +# Each test brings its own main(); rename it so the selected Zephyr # shim owns main() and can return the test's exit code through the target's # runner. Only the test entrypoint in ZEPHYR_TEST_SRCS defines main(); the # support sources (notrandombytes, hal) don't, so applying the define to all is diff --git a/test/zephyr/exec_wrapper.py b/test/zephyr/exec_wrapper.py index 6e339da7d9..ab66108188 100755 --- a/test/zephyr/exec_wrapper.py +++ b/test/zephyr/exec_wrapper.py @@ -15,6 +15,7 @@ binpath = sys.argv[1] args = sys.argv[2:] machine = os.environ.get("QEMU_MACHINE", "mps3-an547") +timeout = float(os.environ.get("QEMU_TIMEOUT", "300")) semihosting_args = [binpath] + args semihosting_config = "enable=on," + ",".join(f"arg={a}" for a in semihosting_args) @@ -32,7 +33,9 @@ binpath, ] -result = subprocess.run(qemu_cmd, encoding="utf-8", capture_output=True, timeout=300) +result = subprocess.run( + qemu_cmd, encoding="utf-8", capture_output=True, timeout=timeout +) sys.stdout.write(result.stdout) if result.returncode != 0: sys.stderr.write(result.stderr) diff --git a/test/zephyr/platform.mk b/test/zephyr/platform.mk index 03b863ff8c..420ea6adce 100644 --- a/test/zephyr/platform.mk +++ b/test/zephyr/platform.mk @@ -36,6 +36,10 @@ ZEPHYR_BOARD_nucleo-n657x0-q := nucleo_n657x0_q # Cortex-M55 (hardware) ZEPHYR_FIPS202_BACKEND_mps3-an547 := fips202/native/armv81m/mve.h ZEPHYR_FIPS202_BACKEND_nucleo-n657x0-q := fips202/native/armv81m/mve.h +# Zephyr owns target selection, so do not infer its ABI from make's host ARCH. +ZEPHYR_ABICHECK_ARCH_mps3-an547 := armv81m +ABICHECK_ARCH := $(strip $(ZEPHYR_ABICHECK_ARCH_$(ZEPHYR_TARGET))) + ZEPHYR_TARGETS := mps2-an385 mps2-an386 mps2-an500 mps2-an521 mps3-an547 nucleo-n657x0-q ZEPHYR_BOARD := $(ZEPHYR_BOARD_$(ZEPHYR_TARGET)) @@ -55,12 +59,27 @@ endif # file to source prerequisites (it is: the top-level Makefile includes us first). OPT ?= 0 +# Shrink the test iteration counts (the sources default them higher, sized for +# native hardware): QEMU is far slower. Keep these defaults ahead of the build +# key so command-line overrides invalidate binaries built with different counts. +NTESTS ?= 3 +NUM_RANDOM_TESTS ?= 100 + +# Forward the QEMU execution deadline to exec_wrapper.py. Direct wrapper +# invocations use the same default when the variable is absent. +QEMU_TIMEOUT ?= 300 +export QEMU_TIMEOUT + # Native backends are an OPT=1 feature (an547 builds the Armv8.1-M MVE backend). ZEPHYR_FIPS202_BACKEND := $(if $(filter 1,$(OPT)),$(strip $(ZEPHYR_FIPS202_BACKEND_$(ZEPHYR_TARGET)))) ZEPHYR_APP := $(PLATFORM_PATH)/app ZEPHYR_BUILD_DIR := $(BUILD_DIR)/zephyr/$(ZEPHYR_TARGET) ZEPHYR_ACTIVE_TARGET := $(BUILD_DIR)/zephyr/.active-target +ZEPHYR_BUILD_KEY := $(ZEPHYR_TARGET)|OPT=$(OPT) +ZEPHYR_BUILD_KEY := $(ZEPHYR_BUILD_KEY)|FIPS202=$(ZEPHYR_FIPS202_BACKEND) +ZEPHYR_BUILD_KEY := $(ZEPHYR_BUILD_KEY)|NTESTS=$(NTESTS) +ZEPHYR_BUILD_KEY := $(ZEPHYR_BUILD_KEY)|NUM_RANDOM_TESTS=$(NUM_RANDOM_TESTS) ZEPHYR_APP_INPUTS := \ $(ZEPHYR_APP)/CMakeLists.txt \ $(ZEPHYR_APP)/Kconfig \ @@ -79,14 +98,15 @@ ZEPHYR_TARGET_CMAKE_ARGS := $(if $(ZEPHYR_IS_NUCLEO_N657X0_Q),\ # Test binary output paths are shared across ZEPHYR_TARGET values, while the # CMake build directory is target-specific. Keep a lightweight marker containing -# the last requested target, and only touch it when the target changes. Binaries -# depending on this marker are then rebuilt after a target switch without -# forcing a clean rebuild when the target is unchanged. +# the last requested build configuration, and only touch it when that +# configuration changes. Binaries depending on this marker are then rebuilt +# after a target, backend, or test-count switch without forcing a clean rebuild +# when the configuration is unchanged. .PHONY: zephyr_target_marker_force $(ZEPHYR_ACTIVE_TARGET): zephyr_target_marker_force $(Q)[ -d $(@D) ] || mkdir -p $(@D) - $(Q)if [ ! -f $@ ] || [ "$$(cat $@)" != "$(ZEPHYR_TARGET)" ]; then \ - echo "$(ZEPHYR_TARGET)" > $@; \ + $(Q)if [ ! -f $@ ] || [ "$$(cat $@)" != "$(ZEPHYR_BUILD_KEY)" ]; then \ + echo "$(ZEPHYR_BUILD_KEY)" > $@; \ fi # Per-binary CMake build dir, keyed on $(notdir $@) so binaries build in @@ -97,11 +117,10 @@ ZEPHYR_OUT = $(ZEPHYR_BUILD_DIR)/$(notdir $@) # fit comfortably within the Zephyr main-thread stack (see app/prj.conf). CFLAGS += -DMLD_CONFIG_REDUCE_RAM -# Shrink the test iteration counts (the sources default them higher, sized for -# native hardware): QEMU is far slower. On CFLAGS so they forward below. -CFLAGS += -DNTESTS=3 \ +# Put the configurable test counts on CFLAGS so they forward below. +CFLAGS += -DNTESTS=$(NTESTS) \ -DMLD_BENCHMARK_NTESTS=10 -DMLD_BENCHMARK_NITERATIONS=10 -DMLD_BENCHMARK_NWARMUP=10 \ - -DNUM_RANDOM_TESTS=100 + -DNUM_RANDOM_TESTS=$(NUM_RANDOM_TESTS) # The binary's CFLAGS, forwarded to the CMake build (which applies them to the # mldsa amalgamation and test sources alike). '=' not ':=', so the recipe-time @@ -120,6 +139,7 @@ ZEPHYR_TEST_CFLAGS = $(subst \",\\\",$(patsubst -Imldsa,-I$(abspath mldsa),$(CFL ZEPHYR_CMAKE_ENV := env -u CFLAGS -u CXXFLAGS -u CPPFLAGS -u LDFLAGS CUSTOM_BUILD = \ + $(if $(CUSTOM_BUILD_ABICHECK),$(if $(ABICHECK_ARCH),,$(error ABI checking is not supported for ZEPHYR_TARGET=$(ZEPHYR_TARGET)))) \ echo " ZEPHYR $(ZEPHYR_TARGET): $(notdir $@)" && \ $(ZEPHYR_CMAKE_ENV) cmake -GNinja -S $(ZEPHYR_APP) -B $(ZEPHYR_OUT) \ -DBOARD=$(ZEPHYR_BOARD) \ @@ -127,6 +147,7 @@ CUSTOM_BUILD = \ -DZEPHYR_TEST_SRCS="$(strip $(TEST_SRCS))" \ -DZEPHYR_TEST_CFLAGS="$(ZEPHYR_TEST_CFLAGS)" \ -DZEPHYR_FIPS202_BACKEND=$(ZEPHYR_FIPS202_BACKEND) \ + -DZEPHYR_ABICHECK=$(if $(CUSTOM_BUILD_ABICHECK),ON,OFF) \ $(if $(ZEPHYR_FIPS202_BACKEND),-DCONFIG_FIPS202_MVE_BACKEND=y) \ $(ZEPHYR_TARGET_CMAKE_ARGS) \ -DUSER_CACHE_DIR=$(abspath $(ZEPHYR_OUT)/.cache) \ @@ -134,12 +155,20 @@ CUSTOM_BUILD = \ $(ZEPHYR_CMAKE_ENV) cmake --build $(ZEPHYR_OUT) >/dev/null && \ cp $(ZEPHYR_OUT)/zephyr/zephyr.elf $@ +# A native assembly amalgamation can directly include development sources that +# do not appear in LIB_SRCS. The wildcard is empty before the Armv8.1-M x1 +# backend lands and becomes an explicit dependency when that source is present. +ZEPHYR_NATIVE_ASM_INPUTS := mldsa/mldsa_native_asm.S \ + $(wildcard dev/fips202/armv81m_clean/src/keccak_f1600_x1_armv7m.S) + # A custom build links the test sources directly rather than from objects, so # nothing otherwise makes the bins depend on the Zephyr app inputs or the # active-target marker. components.mk attaches CUSTOM_BUILD_DEPS to every test -# binary (in its CUSTOM_BUILD branch), so a CMakeLists/shim/overlay edit or a -# target switch forces a rebuild. Set here (before components.mk is included). -CUSTOM_BUILD_DEPS := $(ZEPHYR_ACTIVE_TARGET) $(ZEPHYR_APP_INPUTS) +# binary (in its CUSTOM_BUILD branch), so an application input, native assembly +# input, target, backend, or test-count change forces a rebuild. Set here before +# components.mk is included. +CUSTOM_BUILD_DEPS := $(ZEPHYR_ACTIVE_TARGET) $(ZEPHYR_APP_INPUTS) \ + $(if $(ZEPHYR_FIPS202_BACKEND),$(ZEPHYR_NATIVE_ASM_INPUTS)) ifeq ($(ZEPHYR_IS_NUCLEO_N657X0_Q),) EXEC_WRAPPER := $(abspath $(PLATFORM_PATH)/exec_wrapper.py)