Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/baremetal.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ jobs:
alloc: true
bench: true
opt: no_opt
- runner: ubuntu-latest
name: 'M33-AN524'
makefile: test/baremetal/platform/m33-an524/platform.mk
nix-shell: cross-arm-embedded
func: true
kat: true
acvp: true
alloc: true
bench: true
opt: no_opt
runs-on: ${{ matrix.target.runner }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Expand Down
2 changes: 1 addition & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@
devShells.cross-arm-embedded = util.mkShell {
packages = builtins.attrValues
{
inherit (util) m55-an547;
inherit (util) pqmx;
inherit (config.packages) linters;
inherit (pkgs) gcc-arm-embedded qemu coreutils python3 git;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,36 @@
}:

stdenvNoCC.mkDerivation {
pname = "mldsa-native-m55-an547";
version = "main-2025-10-02";
pname = "mldsa-native-pqmx";
version = "main-2026-02-10";


# Fetch platform files from pqmx (envs/m55-an547)
# Fetch platform files from pqmx
src = fetchFromGitHub {
owner = "slothy-optimizer";
repo = "pqmx";
rev = "4ed493d3cf2af62a08fd9fe36c3472a0dc50ad9f";
hash = "sha256-jLIqwknjRwcoDeEAETlMhRqZQ5a3QGCDZX9DENelGeQ=";
rev = "904451a615dc7926eba07b4f3d1a4137c368bb4a";
hash = "sha256-BjsToEWGlykKIKRfPom84BkD5RfetUKKwRAw3PecebU=";
};

dontBuild = true;

installPhase = ''
mkdir -p $out/platform/m33-an524/src/platform/
cp -r envs/m33-an524/src/platform/. $out/platform/m33-an524/src/platform/
cp integration/*.c $out/platform/m33-an524/src/platform/

mkdir -p $out/platform/m55-an547/src/platform/
cp -r envs/m55-an547/src/platform/. $out/platform/m55-an547/src/platform/
cp integration/*.c $out/platform/m55-an547/src/platform/
'';

setupHook = writeText "setup-hook.sh" ''
export M33_AN524_PATH="$1/platform/m33-an524/src/platform/"
export M55_AN547_PATH="$1/platform/m55-an547/src/platform/"
'';

meta = {
description = "Platform files for the Cortex-M55 (AN547)";
description = "Platform files from pqmx for baremetal targets";
homepage = "https://github.com/slothy-optimizer/pqmx";
};
}
2 changes: 1 addition & 1 deletion nix/util.nix
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ rec {
hol_server = pkgs.callPackage ./hol_light/hol_server.nix { inherit hol_light'; };
s2n_bignum = pkgs.callPackage ./s2n_bignum { };
slothy = pkgs.callPackage ./slothy { python3 = python3-for-slothy; };
m55-an547 = pkgs.callPackage ./m55-an547-arm-none-eabi { };
pqmx = pkgs.callPackage ./pqmx { };

# Helper function to build individual cross toolchains
_individual_toolchain = { name, cross_compilers }:
Expand Down
54 changes: 54 additions & 0 deletions test/baremetal/platform/m33-an524/exec_wrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env python3
# Copyright (c) The mldsa-native project authors
# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT

"""QEMU wrapper for executing Cortex-M33 bare-metal ELF binaries (mps3-an524)."""

import struct as st
import sys
import subprocess
import tempfile
import os


def err(msg, **kwargs):
print(msg, file=sys.stderr, **kwargs)


binpath = sys.argv[1]
args = sys.argv[1:]

# Memory layout: [argc] [offset1] [offset2] ... [string1\0] [string2\0] ...
# M33-AN524 RAM: 0x20000000-0x2001FFFF (128KB)
# Heap ends at: ~0x20000b20
# Stack: 0x20008000-0x2001FFFF (96KB, grows downward)
# Use address after heap but before stack
# cmdline.c CMDLINE_ADDR must match this value
cmdline_offset = 0x20007000
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 tempfile.NamedTemporaryFile(mode="wb", delete=False, suffix=".bin") as fd:
args_file = fd.name
fd.write(binargs)

try:
qemu_cmd = f"qemu-system-arm -M mps3-an524 -cpu cortex-m33 -nographic -semihosting -kernel {binpath} -device loader,file={args_file},addr=0x{cmdline_offset:x}".split()
result = subprocess.run(qemu_cmd, encoding="utf-8", capture_output=True)
finally:
os.unlink(args_file)
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)
76 changes: 76 additions & 0 deletions test/baremetal/platform/m33-an524/platform.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Copyright (c) The mldsa-native project authors
# Copyright (c) The mlkem-native project authors
# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT

PLATFORM_PATH:=test/baremetal/platform/m33-an524

CROSS_PREFIX=arm-none-eabi-
CC=gcc

# Use PMU cycle counting by default
CYCLES ?= PMU

# Reduce iterations for benchmarking
CFLAGS += -DMLD_BENCHMARK_NTESTS=3 -DMLD_BENCHMARK_NITERATIONS=2 -DMLD_BENCHMARK_NWARMUP=3

CFLAGS += -DMLD_CONFIG_REDUCE_RAM -DMLD_BUMP_ALLOC_SIZE=65536

CFLAGS += \
-O3 \
-Wall -Wextra -Wshadow \
-Wno-pedantic \
-Wno-redundant-decls \
-Wno-missing-prototypes \
-Wno-conversion \
-Wno-sign-conversion \
-fno-common \
-ffunction-sections \
-fdata-sections \
--sysroot=$(SYSROOT) \
-DDEVICE=an524 \
-I$(M33_AN524_PATH) \
-I$(M33_AN524_PATH)/m-profile \
-DARMCM33 \
-DSEMIHOSTING \
-DCMDLINE_BASE_ADDR=0x20007000

ARCH_FLAGS += \
-mcpu=cortex-m33 \
-mthumb \
-mfloat-abi=soft

CFLAGS += \
$(ARCH_FLAGS) \
--specs=nosys.specs

CFLAGS += $(CFLAGS_EXTRA)

LDSCRIPT = $(M33_AN524_PATH)/m33-an524.ld

LDFLAGS += \
-Wl,--gc-sections \
-Wl,--no-warn-rwx-segments \
-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)

# Extra sources to be included in test binaries
EXTRA_SOURCES = $(wildcard $(M33_AN524_PATH)/*.c)
# The CMSIS files fail compilation if conversion warnings are enabled
EXTRA_SOURCES_CFLAGS = -Wno-conversion -Wno-sign-conversion

EXEC_WRAPPER := $(realpath $(PLATFORM_PATH)/exec_wrapper.py)
23 changes: 23 additions & 0 deletions test/hal/hal.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,25 @@ uint64_t get_cyclecounter(void)
}

#elif defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8_1M_MAIN__)
/* ARMv8-M cycle counting support */
#if defined(ARMCM33)
/* Cortex-M33: Use DWT cycle counter (no dedicated PMU) */
#include <ARMCM33.h>
#include <system_ARMCM33.h>

void enable_cyclecounter(void)
{
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}

void disable_cyclecounter(void) { DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk; }

uint64_t get_cyclecounter(void) { return DWT->CYCCNT; }

#elif defined(ARMCM55)
/* Cortex-M55: Use dedicated PMU */
#include <ARMCM55.h>
#include <system_ARMCM55.h>
#include "pmu_armv8.h"
Expand All @@ -116,6 +135,10 @@ void disable_cyclecounter(void)

uint64_t get_cyclecounter(void) { return ARM_PMU_Get_CCNTR(); }

#else /* !ARMCM33 && ARMCM55 */
#error "PMU_CYCLES on ARMv8-M requires ARMCM33 or ARMCM55 to be defined"
#endif /* !ARMCM33 && !ARMCM55 */

#elif defined(__riscv)

void enable_cyclecounter(void) {}
Expand Down
2 changes: 2 additions & 0 deletions test/src/test_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ typedef struct
} alloc_info_t;

#define MLD_MAX_IN_FLIGHT_ALLOCS 100
#ifndef MLD_BUMP_ALLOC_SIZE
#define MLD_BUMP_ALLOC_SIZE (128 * 1024) /* 128KB buffer */
#endif

struct test_ctx_t
{
Expand Down