diff --git a/Makefile b/Makefile index 86593360..0e2465a0 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,12 @@ SHELL := /bin/bash all: build +TARGET_PLATFORM ?= +SOURCES= +ifneq ($(TARGET_PLATFORM),) +include test/mk/platform.mk +endif + W := $(EXEC_WRAPPER) # Detect available SHA256 command @@ -61,7 +67,7 @@ run_func_87: func_87 run_func: run_func_44 run_func_65 run_func_87 run_acvp: acvp - python3 ./test/acvp_client.py $(if $(ACVP_VERSION),--version $(ACVP_VERSION)) + EXEC_WRAPPER="$(EXEC_WRAPPER)" python3 ./test/acvp_client.py $(if $(ACVP_VERSION),--version $(ACVP_VERSION)) func_44: $(MLDSA44_DIR)/bin/test_mldsa44 $(Q)echo " FUNC ML-DSA-44: $^" diff --git a/flake.nix b/flake.nix index f8fc1a7a..75669a47 100644 --- a/flake.nix +++ b/flake.nix @@ -67,6 +67,10 @@ packages.toolchains = util.toolchains; packages.toolchains_native = util.toolchains_native; + # Build: Cortex-M55 (AN547) using arm-none-eabi-gcc, platform files from pqmx + packages.m55-an547 = util.m55-an547; + packages.default = config.packages.m55-an547; + devShells.default = util.mkShell { packages = builtins.attrValues { @@ -77,7 +81,13 @@ zig_0_13; } ++ pkgs.lib.optionals (!pkgs.stdenv.isDarwin) [ config.packages.valgrind_varlat ]; }; - + devShells.arm-embedded = util.mkShell { + packages = builtins.attrValues + { + inherit (config.packages) m55-an547; + inherit (pkgs) gcc-arm-embedded qemu coreutils python3; + }; + }; devShells.hol_light = util.mkShell { packages = builtins.attrValues { inherit (config.packages) hol_light s2n_bignum; diff --git a/nix/m55-an547-arm-none-eabi/default.nix b/nix/m55-an547-arm-none-eabi/default.nix new file mode 100644 index 00000000..49799990 --- /dev/null +++ b/nix/m55-an547-arm-none-eabi/default.nix @@ -0,0 +1,44 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +{ stdenvNoCC +, fetchFromGitHub +, ... +}: + +# Builds mldsa-native for Cortex-M55 (AN547) using arm-none-eabi-gcc. +# It fetches the platform support files from slothy-optimizer/pqmx +# instead of using copies in the repository. + +stdenvNoCC.mkDerivation rec { + pname = "mldsa-native-m55-an547"; + version = "unstable-2025-09-17"; + + + # Fetch platform files from pqmx (envs/m55-an547) + src = fetchFromGitHub { + owner = "slothy-optimizer"; + repo = "pqmx"; + rev = "31d3237"; + hash = "sha256-sL3OduAqe6nDmP+jzJ9hePy9GOc3Snw0zC60C5UvplM="; + }; + + patches = [ ./semihosting.patch ]; + + buildPhase = '' + runHook preBuild + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + mkdir -p "$out"/platform/m55-an547/src/platform/ + cp -ru envs/m55-an547/src/platform/. "$out"/platform/m55-an547/src/platform/ + runHook postInstall + ''; + + meta = { + description = "Build of mldsa-native for Cortex-M55 (AN547) using arm-none-eabi-gcc"; + homepage = "https://github.com/slothy-optimizer/pqm4-mx"; + }; +} diff --git a/nix/m55-an547-arm-none-eabi/semihosting.patch b/nix/m55-an547-arm-none-eabi/semihosting.patch new file mode 100644 index 00000000..349f8064 --- /dev/null +++ b/nix/m55-an547-arm-none-eabi/semihosting.patch @@ -0,0 +1,33 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT +diff --git a/envs/m55-an547/src/platform/semihosting.c b/envs/m55-an547/src/platform/semihosting.c +index 221c5f28..08efccf7 100644 +--- a/envs/m55-an547/src/platform/semihosting.c ++++ b/envs/m55-an547/src/platform/semihosting.c +@@ -13,6 +13,9 @@ + static const uint32_t REPORT_EXCEPTION = 0x18; + static const uint32_t ApplicationExit = 0x20026; + ++uint32_t semihosting_syscall(uint32_t nr, const uint32_t arg); ++void __attribute__ ((destructor)) semihosting_exit(void); ++ + // Do a system call towards QEMU or the debugger. + uint32_t semihosting_syscall(uint32_t nr, const uint32_t arg) { + __asm__ volatile ( +@@ -30,6 +33,16 @@ static void __attribute__ ((destructor)) semihosting_exit(void) { + semihosting_syscall(REPORT_EXCEPTION, ApplicationExit); + } + ++void NMI_Handler(void); ++void HardFault_Handler(void); ++void MemManage_Handler(void); ++void BusFault_Handler(void); ++void UsageFault_Handler(void); ++void SecureFault_Handler(void); ++void SVC_Handler(void); ++void DebugMon_Handler(void); ++void PendSV_Handler(void); ++ + void NMI_Handler(void) { + puts("NMI_Handler"); + semihosting_syscall(REPORT_EXCEPTION, ApplicationExit); diff --git a/nix/util.nix b/nix/util.nix index 28a6c27f..c8b21d94 100644 --- a/nix/util.nix +++ b/nix/util.nix @@ -30,6 +30,7 @@ rec { riscv64-gcc = wrap-gcc pkgs.pkgsCross.riscv64; riscv32-gcc = wrap-gcc pkgs.pkgsCross.riscv32; ppc64le-gcc = wrap-gcc pkgs.pkgsCross.powernv; + arm-embedded-gcc = wrap-gcc pkgs.armToolchain; aarch64_be-gcc = (pkgs.callPackage ./aarch64_be-none-linux-gnu-gcc.nix { }); in # NOTE: @@ -102,6 +103,7 @@ rec { hol_light' = pkgs.callPackage ./hol_light { }; s2n_bignum = pkgs.callPackage ./s2n_bignum { }; slothy = pkgs.callPackage ./slothy { }; + m55-an547 = pkgs.callPackage ./m55-an547-arm-none-eabi { }; toolchains = pkgs.symlinkJoin { name = "toolchains"; diff --git a/test/baremetal/platform/m55-an547/exec_wrapper.py b/test/baremetal/platform/m55-an547/exec_wrapper.py new file mode 100755 index 00000000..a9905805 --- /dev/null +++ b/test/baremetal/platform/m55-an547/exec_wrapper.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +import struct as st +import sys +import tempfile +import subprocess + + +def err(msg, **kwargs): + print(msg, file=sys.stderr, **kwargs) + + +binpath = sys.argv[1] +args = sys.argv[1:] +cmdline_offset = 0x70000 + +arg0_offset = cmdline_offset + 4 + len(args) * 4 + +arg_offsets = [sum(map(len, args[:i])) + i + arg0_offset for i in range(len(args))] + +binargs = st.pack( + f"<{1+len(args)}I" + "".join(f"{len(a)+1}s" for a in args), + len(args), + *arg_offsets, + *map(lambda x: x.encode("utf-8"), args), +) +with open("args.bin", "wb") as fd: + fd.write(binargs) + +qemu_cmd = f"qemu-system-arm -M mps3-an547 -semihosting -nographic -semihosting -kernel {binpath} -device loader,file=args.bin,addr=0x{cmdline_offset:x}".split() +result = subprocess.run(qemu_cmd, encoding="utf-8", capture_output=True) +if result.returncode != 0: + err("FAIL!") + err(f"{qemu_cmd} failed with error code {result.returncode}") + err(result.stderr) + exit(1) + +for line in result.stdout.splitlines(): + print(line) diff --git a/test/baremetal/platform/m55-an547/platform.mk b/test/baremetal/platform/m55-an547/platform.mk new file mode 100644 index 00000000..70d6ba85 --- /dev/null +++ b/test/baremetal/platform/m55-an547/platform.mk @@ -0,0 +1,57 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +HAL_SRC_DIR=$(PLATFORM_PATH)/src +HAL_INC_DIR=$(PLATFORM_PATH)/inc + +CROSS_PREFIX=arm-none-eabi- +CC=gcc + +CFLAGS += \ + -O3 \ + -Wall -Wextra -Wshadow \ + -fno-common \ + -ffunction-sections \ + -fdata-sections \ + --sysroot=$(SYSROOT) \ + -DDEVICE=\"an547\" \ + -I$(HAL_INC_DIR) \ + -DARMCM55 \ + +ARCH_FLAGS += \ + -march=armv8.1-m.main+mve.fp \ + -mcpu=cortex-m55 \ + -mthumb \ + -mfloat-abi=hard -mfpu=fpv4-sp-d16 \ + +CFLAGS += \ + $(ARCH_FLAGS) \ + --specs=nosys.specs \ + -g \ + +CFLAGS += $(CFLAGS_EXTRA) + +LDSCRIPT = $(HAL_SRC_DIR)/platform/mps3.ld + +LDFLAGS += \ + -Wl,--gc-sections \ + -L. + +LDFLAGS += \ + --specs=nosys.specs \ + -Wl,--wrap=_open \ + -Wl,--wrap=_close \ + -Wl,--wrap=_read \ + -Wl,--wrap=_write \ + -Wl,--wrap=_fstat \ + -Wl,--wrap=_getpid \ + -Wl,--wrap=_isatty \ + -Wl,--wrap=_kill \ + -Wl,--wrap=_lseek \ + -Wl,--wrap=main \ + -ffreestanding \ + -T$(LDSCRIPT) \ + $(ARCH_FLAGS) + +SOURCES += $(wildcard $(HAL_SRC_DIR)/*.c) $(wildcard $(HAL_SRC_DIR)/*/*.c) +EXEC_WRAPPER := $(PLATFORM_PATH)/exec_wrapper.py diff --git a/test/baremetal/platform/m55-an547/src/cmdline.c b/test/baremetal/platform/m55-an547/src/cmdline.c new file mode 100644 index 00000000..a8674cc6 --- /dev/null +++ b/test/baremetal/platform/m55-an547/src/cmdline.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include +#include +#include "ARMCM55.h" + +typedef struct cmdline_s +{ + int argc; + char *argv[]; +} cmdline_t; + +#define CMDLINE_ADDR ((cmdline_t *)0x70000) + +/* Provide a prototype for the real main that the C library expects. */ +extern int __real_main(int argc, char *argv[]); +int __wrap_main(int unused_argc, char *unused_argv[]); + +#ifdef SEMIHOSTING +extern void initialise_monitor_handles(void); +#endif + +/* Wrap main: build argc/argv from cmdline and forward to __real_main. */ +int __wrap_main(int unused_argc, char *unused_argv[]) +{ + (void)unused_argc; + (void)unused_argv; +#ifdef SEMIHOSTING + initialise_monitor_handles(); +#endif + cmdline_t *cmdline = (cmdline_t *)CMDLINE_ADDR; + return __real_main(cmdline->argc, cmdline->argv); +} diff --git a/test/baremetal/platform/m55-an547/src/libfns.c b/test/baremetal/platform/m55-an547/src/libfns.c new file mode 100644 index 00000000..a68f00da --- /dev/null +++ b/test/baremetal/platform/m55-an547/src/libfns.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include +int __wrap__close(int fd); +int __wrap__fstat(int fd, struct stat *buf); +int __wrap__getpid(void); +int __wrap__isatty(void); +int __wrap__lseek(void); +int __wrap__kill(void); + + +int __wrap__close(int fd) +{ + (void)fd; + semihosting_syscall(REPORT_EXCEPTION, ApplicationExit); + return 0; +} + +int __wrap__fstat(int fd, struct stat *buf) +{ + (void)fd; + (void)buf; + semihosting_syscall(REPORT_EXCEPTION, ApplicationExit); + return 0; +} + +int __wrap__getpid() +{ + semihosting_syscall(REPORT_EXCEPTION, ApplicationExit); + return 0; +} +int __wrap__isatty() +{ + semihosting_syscall(REPORT_EXCEPTION, ApplicationExit); + return 0; +} +int __wrap__lseek() +{ + semihosting_syscall(REPORT_EXCEPTION, ApplicationExit); + return 0; +} +int __wrap__kill() +{ + semihosting_syscall(REPORT_EXCEPTION, ApplicationExit); + return 0; +} diff --git a/test/mk/platform.mk b/test/mk/platform.mk new file mode 100644 index 00000000..32315cb0 --- /dev/null +++ b/test/mk/platform.mk @@ -0,0 +1,9 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +ifeq ($(TARGET_PLATFORM),m55-an547) +PLATFORM_PATH:=test/baremetal/platform/m55-an547 +include $(PLATFORM_PATH)/platform.mk +else +$(error Platform "$(TARGET_PLATFORM)" not supported) +endif diff --git a/test/mk/rules.mk b/test/mk/rules.mk index 67f05fc8..88dd1d1d 100644 --- a/test/mk/rules.mk +++ b/test/mk/rules.mk @@ -5,17 +5,17 @@ $(BUILD_DIR)/mldsa44/bin/%: $(CONFIG) $(Q)echo " LD $@" $(Q)[ -d $(@D) ] || mkdir -p $(@D) - $(Q)$(LD) $(CFLAGS) -o $@ $(filter %.o,$^) $(LDLIBS) + $(Q)$(LD) $(LDFLAGS) -o $@ $(filter %.o,$^) $(LDLIBS) $(BUILD_DIR)/mldsa65/bin/%: $(CONFIG) $(Q)echo " LD $@" $(Q)[ -d $(@D) ] || mkdir -p $(@D) - $(Q)$(LD) $(CFLAGS) -o $@ $(filter %.o,$^) $(LDLIBS) + $(Q)$(LD) $(LDFLAGS) -o $@ $(filter %.o,$^) $(LDLIBS) $(BUILD_DIR)/mldsa87/bin/%: $(CONFIG) $(Q)echo " LD $@" $(Q)[ -d $(@D) ] || mkdir -p $(@D) - $(Q)$(LD) $(CFLAGS) -o $@ $(filter %.o,$^) $(LDLIBS) + $(Q)$(LD) $(LDFLAGS) -o $@ $(filter %.o,$^) $(LDLIBS) $(BUILD_DIR)/%.a: $(CONFIG) $(Q)echo " AR $@"