CPU, atomics and runtime assembly contracts¶
This contract covers software mechanisms for M0, M0+, M3, M4, M7, M23, M33, M55 and M85, and the Native model. Implementation starts at Arch; configuration examples and whole-platform boundaries are in Cortex-M support. CPU software support, chip integration and physical acceptance establish separate evidence; adding a CPU profile adds no SoC, Board, peripheral or HIL qualification.
Single source of facts and dependency direction¶
tools/configure/cpu.py validates explicit CPU/IRQ facts and returns immutable CpuProfileIR. The same parser serves whole-SoC and external CPU-runtime assembly, deriving compiler options, atomic backend, IRQ-mask types and maintained FreeRTOS ports. Compiler macros validate the selected instruction set; they cannot replace chip facts for DSP, optional FPU, MVE, cache, MPU, DWT or SAU.
A complete platform generates a static typed factory from exact SoC facts, Board wiring and one external TOML. CPU runtime reads only one runtime.toml and its referenced cpu.json; it generates no vendor driver, linker script, vector table, startup, pin route, device object or factory. Both assemblies forbid CMake cache, runtime register probing or a second default configuration from overriding validated facts.
Arch depends on no SoC, I/O, kernel or vendor SDK. Core acquire/release publication uses compiler load/store directly without Arch. OS and log RMW use Arch atomic ports; optional OS uses Arch’s valid-context and mask mechanisms. Products supply tasks, stacks, TCBs, buffers, memory layout, protection policy and recovery responsibility. CPU-runtime clock_hz is a configuration fact; it neither sets clocks nor generates a monotonic source for request deadlines.
CPU-local exclusion and context¶
nx_arch_irq_save/restore saves and restores incoming PRIMASK; tokens are single-use in strict reverse order on the same CPU/thread. BASEPRI/FAULTMASK remain unchanged where present. Only privileged Thread or configurable IRQ may participate in this exclusion domain. NMI/HardFault are not masked by PRIMASK and must not concurrently access its metadata. Tokens are neither kernel critical-section tokens nor cross-core/security-domain locks. Masked sections update bounded metadata only, with no kernel calls, callbacks, waiting, allocation or payload copies.
nx_arch_irq_masks returns a query snapshot, not a restore token. Baseline M0/M0+/M23 never read absent BASEPRI/FAULTMASK. IPSR identity, privilege and security state are queried separately: exception numbers are not SoC IRQ IDs and do not authorize FreeRTOS ISR APIs. Handler privilege cannot be inferred from the interrupted thread’s CONTROL.nPRIV.
DMB, DSB and ISB preserve their own ordering semantics; they prove neither DMA drain, peripheral idle, cache coherence nor request SETTLED. DWT reads only an explicitly permitted, enabled privileged cycle counter and never enables or resets it. Unavailability returns failure with outputs preserved. Frequency changes, pauses and 32-bit wrap prevent it from replacing monotonic deadline time. Actual IRQ latency, privilege switching and cycle bounds still need target-chip measurement.
Architectural external-IRQ limits are 32 for M0/M0+, 240 for M3/M4/M7/M23, and 480 for M33/M55/M85. SoCs must provide their actual valid vector range; architectural maxima do not replace chip facts. M0/M0+/M23 use two priority bits; Mainline declares 3–8 from facts. System exceptions do not count as external IRQs, and CMSIS register-array capacity is not a processor capability limit. M33 DSP is optional and requires explicit dsp; disabling it generates +nodsp, without substituting compiler defaults for chip facts. M4/M7/M55/M85 have DSP; M0/M0+/M3/M23 do not. Contradictory facts are rejected.
These boundaries were checked against ARM’s M23 TRM, M33 NVIC, M55 NVIC and M85 NVIC. M7/M55/M85 cache lines are 32 bytes; chip implementation of each cache must still be explicitly declared.
32-bit publication and RMW¶
nexus/arch/atomic.h operates only on live, naturally aligned uint32_t objects. Initialization precedes publication; all concurrent accesses use these helpers or compatible compiler atomics, never mixed plain reads/writes. It is not for MMIO and guarantees no atomicity against DMA or other bus masters.
Acquire loads/release stores use compiler atomics on every maintained CPU without masking IRQs. Successful compare/exchange is acq_rel, failure is acquire; failure updates caller-private expected without inventing spurious failure. Fetch add/sub returns the old value with 32-bit modular arithmetic. Owners remain responsible for published-state and payload lifetimes.
M0/M0+ RMW uses a fixed saved-PRIMASK read-modify-write span and restores incoming masks. Only same-CPU privileged Thread/configurable IRQ may participate concurrently; NMI, HardFault, unprivileged threads, other cores, DMA and other security domains cannot access that storage concurrently. This CPU-local mechanism claims neither lock-free nor bus-atomic operation and never silently links libatomic. Its masked span has no loops, callbacks, allocation, blocking or payload copy; a bounded instruction sequence is not measured worst-case cycles.
Other cores use compiler lock-free word RMW. Exclusive instructions may retry; lock-free does not mean a fixed cycle bound. M23 belongs to this backend and must not be classified as M0 merely because it lacks BASEPRI. All accessors must stop before deactivating an object; release/acquire does not automatically reclaim requests, notifications or queues.
Cache and instruction synchronization¶
cache.h separates data clean, invalidate, clean-invalidate and instruction sync. Capabilities come from exact CPU facts; maintained cache-line size is 32 bytes and zero means absent capability. Every operation requires a nonzero whole-line-aligned range, without address/length overflow beyond the 32-bit CPU address space or outward rounding. Callers exclusively own each complete line, exclude other CPUs, DMA and security domains, and keep cache configuration stable.
Only privileged Thread/configurable IRQ is permitted; operations neither automatically mask IRQs nor enable cache. Present but disabled cache returns UNSUPPORTED. Instruction sync checks all relevant caches before any maintenance write, and callers must also prevent execution from the range. Functions neither flush unrelated dirty lines, validate code nor perform global branch-predictor maintenance.
Invalidate may discard dirty data; callers explicitly accept that consequence. DMA-receive maintenance before start and after drain is coordinated by the provider/product. Cache operations themselves neither prove DMA idle nor end request/buffer borrows. Work increases with complete-line count and cannot be broadly called O(1).
cache_control.h separately provides reviewed M7 cold-cache enable/disable; other CPU profiles explicitly return UNSUPPORTED. Range-maintenance capability does not imply global cache-control support. Callers provide zero-initialized, exclusive, noncopied control objects and require privileged Thread, PRIMASK=1, BASEPRI/FAULTMASK=0, excluding DMA, NMI/HardFault and other executors using relevant memory. Only trusted reset or a previously successful owned clean/disable establishes known-clean cold state; zero CCR bits do not prove absence of foreign dirty lines or authorize claiming unknown bootloader state. Memory attributes, execution and coherence policy belong to callers.
Implementation checks M7 identity and actual maintained set/way geometry before taking responsibility for selected I/D caches, saving/restoring CSSELR. Failed readback cannot report success. Partial failure retains owned-mask or selector-restoration responsibility; the same object must remain for disable retries rather than reclaiming foreign state from current CCR. Disable runs only after all providers/DMA drain. The all-set/way D-cache clean through CCR disable uses a stack/call-free leaf with DSB/ISB so final clean cannot create local dirty lines afterward. Work grows with actual set count; fixed latency is not promised. The mechanism preserves incoming masks, discovers no devices, allocates no storage and establishes no complete system DMA-coherence contract.
MPU encoding and single-region programming¶
mpu.h keeps separate v7 size/subregion and v8 base/limit/MAIR formats. Pure encoders are available on any profile and reject invalid/reserved encodings, misalignment and incomplete boundaries without truncation/rounding; failures preserve outputs. Inputs and outputs must not overlap. Encoding proves neither SoC reachability, DMA coherence nor product-permission correctness. Optional M0+ MPU is ARMv6 PMSA with compatible RBAR/RASR format; this does not change its ARMv6-M instruction architecture. M0 provides no MPU programming capability.
Actual region programming requires privileged Thread within this security domain, incoming PRIMASK=1, an already disabled MPU, and caller-exclusive selector/state ownership. Implementation validates profile, fields, actual TYPE region count and context before writing the selected region. It preserves CTRL and incoming RNR, does not enable or clear every region, and accesses no other-world aliases. Handler or enabled-MPU calls are rejected without automatically disabling protection policy.
v8 MAIR updates only the selected byte and preserves neighboring attributes. The caller owns all regions using that attribute and their effective memory policy; implementation performs no cache maintenance. Later MPU enable, reconfiguration and context switching belong to OS or product integration outside Arch. The platform maintains explicitly scoped FreeRTOS MPU user-task integration; the OS contract defines its CPU, task, storage and syscall boundaries. These capabilities cannot be inferred solely from an Arch encoder or single-region programming, or extended to unmaintained combinations.
Security state and SAU¶
security.h queries this image’s explicit single/Secure/NonSecure state. Queries neither authorize cross-world access nor probe/infer real SoC IDAU policy. The SAU encoder validates exact 32-byte base/inclusive-limit and NSC flags, preserving outputs on failure.
Only images explicitly compiled Secure with SAU declared in facts may perform SAU MMIO. Writing/clearing one region requires Secure privileged Thread, incoming PRIMASK=1, disabled SAU and exclusive ownership; actual TYPE region count is checked before writes. CTRL, ALLNS, incoming RNR and other regions are preserved; SAU is not enabled and no cross-world registers are used. NonSecure/single images write no SAU MMIO.
IDAU, overlap rules, Secure boot, NSC veneers, dual-world gateways, shared-resource protocols, keys and secure updates belong to products/chip integration. Compiling Secure-only or standalone NonSecure FreeRTOS kernels does not establish paired-world contexts, Secure-task gateways or user MPU-task isolation. These features have no physical acceptance evidence in this iteration.
Observing NonSecure memory permissions¶
nonsecure.h observes NonSecure unprivileged read or read/write permission over a complete span only from Secure privileged Thread, using actual CMSE instructions and checking security attribution plus NS MPU. It does not dereference pointers and rejects null pointers, zero lengths, address overflow and invalid access; adjacent valid regions may be conservatively rejected. Native, single-state and NonSecure images return UNSUPPORTED. Programmable SAU is not required; fixed IDAU may establish attribution for observation.
Success is only a permission observation at that moment: no pin/copy/borrow, gateway-caller authentication, proof of RAM, DMA reachability, object lifetime, bus firewalls or fault-free actual access; interrupts are not masked and the other world is not frozen. Integrators must exclude MMIO, prevent attribution/mapping changes, separately copy input snapshots and validate outputs before irreversible effects. The independent U575 synchronous dual-world reference explicitly supplies these owner prerequisites; it is not a generic transport for arbitrary user address spaces, asynchronous DMA or NS RTOS. See U575 dual-world contract for exact boundaries.
Verification and supportability¶
GoogleTest/GoogleMock replace hardware at narrow instruction/MMIO boundaries while running production C algorithms, covering invalid field/context rejection before mutation, selector/mask preservation and optional-capability combinations. Native runs real recursive thread exclusion, C11 fences and publication/lifecycle behavior. Native cache/MPU/SAU MMIO returns absent-hardware results while pure encoders remain usable. Models do not execute real NVIC.
Locked ARM compiler gates independently validate macros, ABI, objects, instructions and unresolved symbols across nine cores, then compile selected Core/Arch/OS kernel combinations. Optional FPU/MVE/security combinations execute separately from facts and do not inherit results from one combination. Every run records actual commands, return codes, tool identities and output hashes.
This iteration regenerates execution evidence from current sources; formal clean-source SDK, offline dual builds and candidate sealing still follow qualification. Old-HEAD pass counts, candidates or hardware status cannot be inherited. F407/F470 three-board launch modes remain maintained; G474/H743/U575 reference assemblies separately maintain startup, timebase, GPIO and IRQ UART. G474 adds selected EXTI, H743 fixed-cache configurations and finite TX DMA, and U575 an independent OS-free synchronous dual-world reference. CPU profiles neither generate them nor establish full DMA/cache/security support. M7 cold-cache has actual leaf-instruction gates; U575 dual-world has actual SG/BLXNS, dual-ELF address and LOAD-map gates, yet these cannot prove physical isolation or coherence. All physical HIL remains unexecuted. Software models or successful compilation do not promote a product release.