Commit Graph
371 Commits
Author SHA1 Message Date
Frédéric Desbiens b0ad67bae9 Brought the Cortex-R52 examples under the LLVM check, and fixed two blockers (#604)
#600 added a line reporting which example builds the LLVM check passes over, and
cortex_r52 was on it: its examples are driven by CMake rather than by a
build_threadx.sh pair, so the linking stage never touched them. Covering them
turned up two reasons they could not have been built with anything but GNU.

.arch armv8-r has no portable spelling. GNU as accepts it, and LLVM's integrated
assembler rejects every variant -- armv8-r, armv8r, armv8-r+crc -- with "Unknown
Arch: armv8-r". There is nothing to substitute, so the directive is gone from
entry.S and tx_initialize_low_level.S; -mcpu=cortex-r52 already selects the
architecture, both toolchain files pass it, and the directive only restated it.
Worth noting where this hid: the assembly stage walks ports/*/gnu/src, so example
assembly had never been assembled by LLVM at all.

-Wl,--no-warn-rwx-segments is GNU ld only, added in binutils 2.39. ld.lld does
not warn about RWX segments and rejects the flag outright, failing the link with
"unknown argument". It is now selected on CMAKE_C_COMPILER_ID rather than spelled
into all six targets, and the reason it exists at all -- a bare-metal image has
one flat DRAM region and leaves access control to the MPU -- moves to the one
place that sets it.

cmake/cortex_r52_clang.cmake is the toolchain file. It names the tools as found
on PATH, which is what CI uses, then pins $HOME/toolchains if that directory
exists, mirroring how cortex_r52.cmake pins the GNU toolchain and for the same
reason. Falling back rather than requiring the pinned path keeps the file usable
on a machine that keeps clang elsewhere. THREADX_TOOLCHAIN stays "gnu": there is
no clang port directory, this builds the gnu sources with a different compiler,
which is what the whole check does for every other Arm port.

check_clang.sh gains a fourth stage for CMake-driven examples, and no longer
reports cortex_r52 as a gap. It reads the image list out of the generated ninja
graph rather than repeating it, so adding a target cannot escape the check, and
filters out the cmake_object_order_depends_target_* phonies -- counting those
reported ten images where there are five.

Verified with Arm Toolchain for Embedded 22.1.0, the version the workflow pins.
All five images link, and all five then run and pass on FVP_BaseR_AEMv8R:
boot_check, demo_m2, demo_m3, demo_threadx and demo_mpu. That is a step beyond
the AArch64 examples, which are link-verified only. The full check reports 711 of
711 assembly sources, 185 of 185 common C sources for each of nine cores, 42 of 42
script-driven examples and 5 of 5 CMake images, leaving only cortex_a5_smp,
cortex_a7_smp and cortex_a9_smp listed as having no driver.

GNU is unaffected: the same five images build with no warnings and the FVP test
suite passes 5 of 5.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-11 19:53:11 -04:00
Frédéric Desbiens 31fbe21d20 Removed developer machine paths from the shipped project files (#603)
The Arm Development Studio launch configurations and the IAR project files
carried absolute paths from the machines they were last opened on: four
individuals' home directories, a Broadcom support build tree, and directories
such as C:\release\threadx, C:\temp1702\tx and D:\threadx. They are published in
the repository and none of them resolves for anyone else.

In the launch files all of it is saved session state, which files that were never
opened in a debugger simply do not have:

  breakpoints                  72 files, saved breakpoints anchored to source
                               paths under cortex_a35 on one machine. Emptied
                               rather than deleted, matching the 27 launch files
                               that already carry an empty list.
  scripts_view_script_links    70 files, a scripts view cache. The script the
                               launch actually runs is named one line earlier
                               through ${workspace_loc:...}, which is portable.
  substitutePath               65 files, source lookup remapping. 30 map a path
                               to itself, and the rest point at one machine's
                               copy of libgloss or a build directory.
  TREE_NODE_PROPERTIES         39 files, which rows the variables view had
                               expanded.
  DebugCommandLine.History      2 files, the debug console command history,
                               including a typed absolute path.

The two IAR cases are not session state and are corrected rather than removed:

  IarchiveOutput               23 files. The librarian output path pointed at
                               another machine, so the library was written
                               outside the project. Set to ###Unitialized###,
                               which 86 other option blocks already use, letting
                               IAR derive $EXE_DIR$\$PROJ_FNAME$.a.
  IlinkIcfFile                  1 file. The linker configuration file is load
                               bearing, so the file name is kept and the path
                               made project relative, as 33 other option blocks
                               spell it.

Seven of the files are ports_arch templates, so the generators would otherwise
have copied the paths back.

Verified: all 162 launch and IAR project files in the tree parse as well-formed
XML afterwards, no tracked launch or project file mentions any of the four user
names, and scripts/check_ports.sh passes, so the templates and their generated
copies still agree.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-11 19:39:41 -04:00
Frédéric Desbiens c78c080139 Made the ARMv8-A debug launch configurations name their own core (#602)
Two identifiers in the Arm Development Studio launch configurations still said
A35 in every AArch64 port, because the generator's patch table could not reach
them.

The config database taxonomy id is spelt in lower case in the launch files,
/platform/armfvp/base_a35x4, but the search string read base_A35x4. Both
generators are case sensitive here, sed in update.sh and -creplace in
update.ps1, so the rule matched nothing and all 27 ports kept the A35 taxonomy
id while the platform name and model beside it named the right core. That the
rule exists at all shows the substitution was intended, and the ARMv7-A
generator does the same thing correctly, which is why its ports carry a per-core
ve_cortex_a<n>x1 id.

The SMP launch files name the activity "Cortex-A35x4 SMP" where the ThreadX ones
say "Debug Cortex-A35", so the existing activity rule reached the ThreadX ports
only and every SMP port advertised an A35 activity. Add a rule that matches the
" SMP" suffix, which also keeps it from rewriting the FVP model name that the
line above already handles.

Both changes are mirrored in update.ps1, which stays equivalent to update.sh.

Verified by regenerating: 50 launch files change and nothing else, 100 lines of
taxonomy id across 24 ThreadX and 26 SMP files, and 52 lines of activity name
across the 26 SMP files. No other attribute in those files moves, so the new
" SMP" rule does not touch the model name. The two Cortex-A35 ports are
untouched, as they must be, since substituting A35 for A35 is a no-op.
scripts/check_ports.sh passes, so the result is reproducible.

This cannot be exercised here: confirming that Arm Development Studio resolves
the per-core taxonomy ids needs Arm Development Studio. The change rests on the
platform name and model already naming the core, on the patch rule's existence,
and on the ARMv7-A ports having shipped per-core ids all along.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-11 16:20:48 -04:00
Frédéric Desbiens 96b1638fe4 Gave the Armv8-M examples a linkable sample and fixed what stopped them (#601)
The Cortex-M23, M33, M55 and M85 examples each shipped a build_threadx.sh with
no build_threadx_sample.sh, so scripts/check_clang.sh skipped all four at its
linking stage: the whole Armv8-M family had no example-link coverage. Adding the
missing script surfaced five separate reasons why none of them could have linked.

ports/cortex_m23/gnu/src/tx_initialize_low_level.S referenced
Image$$ARM_LIB_STACK$$ZI$$Limit and __Vectors, which are Arm toolchain
scatter-load names that no GNU linker defines. This is a GNU port, so it now
uses __RAM_segment_used_end__ and _vectors, as the Cortex-M33 version already
does. The Cortex-A ports mention Image$$ZI$$Limit only inside a comment; this
was a live relocation.

The Cortex-M23 crt0 needed unified assembler syntax. The Armv7-M file it derives
from carries no .syntax directive, so GNU as reads it in the legacy divided
syntax, where a Thumb data-processing instruction sets the flags whether or not
the mnemonic says so, and "mov r2, #0" assembles to 2200, MOVS. LLVM implements
unified syntax only, where those mnemonics mean the non-flag-setting forms that
Armv8-M Baseline does not have. Disassembling the Cortex-M4 object confirms GNU
already emits 2200 movs, 1a52 subs and 3001 adds, so spelling them out changes
no encoding. The flags carry meaning: crt0_memory_copy branches on the result of
"subs r2, r2, r1" and again on "subs r2, #1".

Cortex-M23 has no SVC_Handler to name in its vector table. Its library is built
-DTX_SINGLE_MODE_NON_SECURE, and tx_thread_schedule.S defines that handler only
when neither TX_SINGLE_MODE_SECURE nor TX_SINGLE_MODE_NON_SECURE is set, so the
SVCall slot takes __tx_BadHandler. The table also uses the CMSIS handler names
throughout, because that is what the Armv8-M ports export: the Armv7-M table
references __tx_SVCallHandler and __tx_SysTickHandler, which resolve to nothing
here.

The other three needed a C library. tx_thread_secure_stack.c calls malloc and
free, which pulls the allocator in, and the sample scripts already defined
SYSCALL_LIB for exactly that without ever passing it to the linker. Their linker
scripts now also provide end and _end, which newlib's libnosys _sbrk wants, and
__heap_start and __heap_end, which picolibc wants instead.

Cortex-M55 and M85 build with the hard-float ABI now, in both the library and
the sample. Arm Toolchain for Embedded ships no soft-float MVE multilib and says
so plainly: "No library available for MVE with soft-float ABI." The library and
the sample have to agree, and -mfloat-abi=hard is what check_clang.sh already
uses for these two cores in PORT_TARGET.

Verified with GNU 13.2.1 and Arm Toolchain for Embedded 22.1.0. Every port links
under both: Cortex-M23 at 206,136 and 312,636 bytes, M33 at 305,856 and 320,696,
M55 at 306,228 and 320,664, M85 at 306,240 and 320,668. check_clang.sh now
reports 42 of 42 example builds linking, up from 38, and no longer lists any port
as carrying build_threadx.sh without build_threadx_sample.sh. The images are
link-verified only and have not been executed, as with the AArch64 examples.

Only .sh drivers are added. Cortex-M23 has a build_threadx.bat with no sample
counterpart and the other three have no .bat at all; adding untested Windows
scripts belongs in its own change.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-11 14:00:54 -04:00
Frédéric Desbiens 8031d8b9bb Enrolled the Cortex-R52 port in the LLVM C check and exposed the skipped examples (#600)
Two gaps in check_clang.sh, both of which made the Cortex-R52 port look better
covered than it was.

C_CORES gains cortex_r52. That list is described as one core per architecture
profile, and Armv8-R AArch32 is a profile rather than a variant of Armv7-R: the
port is written by hand instead of generated from ports_arch, so cortex_r5 does
not stand in for its tx_port.h. The assembly was already covered, since #593
added the PORT_TARGET entry, but the common C sources had never been compiled
against that header.

The example stage skipped any directory lacking both driver scripts, and did so
in silence. A port absent from the count reads as covered, which is how the two
CMake based example builds under ports/cortex_r52 looked like part of the total
while never being built. The stage now reports what it passed over, in the two
distinct cases that exist. The comment above EXAMPLES_EXPECTED_TO_FAIL already
asks for gaps to stay visible; this makes the code agree with it.

Four Cortex-M ports turn out to carry build_threadx.sh with no
build_threadx_sample.sh, so they were skipped despite having a driver:
cortex_m23, cortex_m33, cortex_m55 and cortex_m85. Reported, not fixed. Whether
those want a sample script is a separate question.

The expected-to-fail test now runs before the Arm test rather than after. arm9
and arm11 are on that list but carry no PORT_TARGET entry, so testing for Arm
first dropped them from the report entirely, reintroducing the same silence for
two ports that were already being named.

Verified with Arm Toolchain for Embedded 22.1.0, the version CI pins: 711 of 711
assembly sources, 185 of 185 common C sources for each of the nine cores
including cortex_r52, and 38 of 38 example builds linking, so the built set is
unchanged by this commit. The remaining driverless ports report as cortex_r52,
cortex_a5_smp, cortex_a7_smp and cortex_a9_smp, the three A profile SMP ports
having no example scripts and the R52 examples being driven by CMake. --help
still frames the intended lines, since the additions sit below the range it
selects by number.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-11 13:51:01 -04:00
Frédéric Desbiens b87a62d218 Brought Cortex-A34 and the A78 SMP port under the ARMv8-A generator (#599)
ports/cortex_a34, ports_smp/cortex_a34_smp and ports_smp/cortex_a78_smp were
absent from the ARMv8-A generator's core list, so ports_arch never reached them
and scripts/check_ports.sh could not detect that they had drifted. They had.

The two Cortex-A34 ports sat two releases behind the shared sources, at 6.1.10
against 6.3.0. The difference is not only banners: tx_initialize_low_level.S
lacked the SUB x1, x1, #15 that precedes the BIC when the system stack pointer
is recorded, so the value stored was the incoming SP rather than the first
16-byte boundary below it. The Arm Development Studio example was missing
GICv3_aliases.h, which every other port's GICv3_gicc.h includes to reach the
interrupt controller registers through the stringify indirection.

The Cortex-A78 SMP port had never had its debug launch configuration patched at
all. It still named the A35 platform and model, so Debug Cortex-A35,
Base_A35x4 and FVP_Base_Cortex-A35x4 would have started an A35 model for an A78
port.

Add cortex_a34 to the core list. Cortex-A78 cannot go in the same list, because
the generator walks cores against port sets and would then create a
ports/cortex_a78 that the tree has never had; give it a separate SMP-only list
consulted only for the tx_smp port set. Both changes are mirrored in update.ps1,
which stays equivalent to update.sh.

Verified by regenerating: exactly these three port directories change, 116 files
modified and 13 added, and no already-covered core moves, so the core list was
the only thing holding them back. scripts/check_ports.sh passes, which now means
these three are checked for reproducibility for the first time.
scripts/check_clang.sh reports 38 of 38 example builds linked, the three new
ports included.

readme_threadx.txt is not added here. Only the two Cortex-A35 template ports
carry it; the other 23 AArch64 ports do not, so its absence from Cortex-A34 is
the tree's norm rather than drift, and supplying it everywhere is separate work.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-11 09:57:55 -04:00
Frédéric Desbiens 13722fe702 Repaired the garbled description at the top of check_clang.sh (#598)
The comment block describing what the script does was left half-rewritten when
the example link stage was added to it: one sentence ends mid-clause and the
word "profile" appears twice, once as the tail of a sentence that was meant to
be replaced.

Say the three stages plainly instead, and keep the point the truncated sentence
was making, that only the linking stage needs a target C library. This block is
what --help prints, so the damage was user visible.

Comment only; no behaviour change. Verified that --help still frames the
intended lines, since it selects them by number.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-11 09:22:30 -04:00
Frédéric Desbiens 51ca412b36 Added build scripts for the AArch64 examples, which had none (#597)
The AArch64 examples could only be built through the Arm Development Studio
project files beside them. There was no script, so nothing in CI or on a
developer's machine could build them, and the sources they need were never
named anywhere: vectors.S, v8_aarch64.S and v8_utils.S were present but
unreferenced, which is why a hand written link failed on GetCPUID, GetAffinity,
InvalidateUDCaches and ZeroBlock. Those four are defined in v8_aarch64.S and
v8_utils.S, in the tree all along.

Add one pair of scripts, in ports_arch so every AArch64 port receives them.
Both derive the -mcpu value and the kernel source directory from the port
directory they sit in, so a single pair serves the twelve ThreadX ports and the
twelve SMP ports, the latter building against common_smp and picking up the C
sources those ports carry alongside the assembly. TOOLCHAIN=atfe selects Arm
Toolchain for Embedded in place of the GNU toolchain, as it does for the ARMv7
example scripts.

One symbol genuinely had no definition. startup.S calls
initialise_monitor_handles to open the standard file handles over a debugger
connection; the GNU toolchain provides it in libgloss through
--specs=rdimon.specs, while picolibc has no equivalent and neither does the
LLVM toolchain's semihosting library. semihost_stub.S supplies a weak no-op,
linked for that toolchain only, so a real definition always wins.

Extend scripts/check_clang.sh to cover ports_smp as well as ports, since the
example builds now exist there too.

Verified by building every AArch64 example with Arm Toolchain for Embedded:
twelve ThreadX ports at 314,744 to 315,256 bytes of text and twelve SMP ports
at 325,304 to 325,880. scripts/check_clang.sh now reports 35 of 35 example
builds linking with none failing, the twenty-four new ones plus the eleven that
already built. The images have not been executed: the sample
targets the Base platform peripheral addresses, which the available emulator
does not provide.

Cortex-A34, and the Cortex-A34 and A78 SMP ports, are left out. They are not in
the generator's core list, so they receive nothing from ports_arch and cannot be
checked for reproducibility either. Bringing them in rewrites 114 files in those
three directories, which deserves its own change.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-11 08:54:04 -04:00
Frédéric Desbiens 08eff8061c Made the Cortex-A12, A15 and A17 examples link with an LLVM toolchain (#596)
Those three sample scripts compiled crt0.S and reset.S but named neither on the
link line, and omitted -nostartfiles, so the toolchain was also free to link its
own startup. Under GNU that produced a working image; under an LLVM toolchain
picolibc's crt0 was pulled in and wanted __data_start, __data_source,
__data_size, __bss_size, __stack, __tls_base and __arm32_tls_tcb_offset, none of
which the linker script defines.

Defining picolibc's contract in the shared linker script was tried first and
abandoned: it reaches into ABI constants that cannot be verified here, and it is
unnecessary, because the in-tree crt0.S is already a complete startup for this
script. It sets up the stack and zeroes BSS between __bss_start__ and
__bss_end__, and .data carries no AT() so there is nothing to copy.

So the three scripts now pass -nostartfiles and name crt0.o and reset.o, which
is what the four sibling A profile cores already do and what these scripts were
evidently compiling those files for.

Both the old and the new GNU images contain the in-tree startup, __vectors from
reset.S and _mainCRTStartup from crt0.S, so the startup was already being used
through implicit startup file resolution rather than an explicit operand. How
that resolution happened without the objects being named is not accounted for
here, which is itself the argument for naming them: the same implicit behaviour
does not hold across toolchains, and that is why the LLVM link failed.

Add a readme to each of the three example directories. Their
tx_initialize_low_level.S is the generic ARMv7-A skeleton, 300 lines and
identical across all three, with no interrupt controller programming, no timer
and no vector table installation, where the A5, A7, A8 and A9 examples have all
three and ship the matching Versatile Express support files. These three
therefore demonstrate that the port builds; they will not receive a timer tick.
Nothing in the tree said so, which invites the assumption that they are
equivalent.

Verified with both toolchains for all three cores. GNU links at 41,276 bytes of
text, down from 41,768 because the unused toolchain startup is no longer
included, and Arm Toolchain for Embedded links at 37,982 where it previously
could not link at all. The resulting image is structurally sound: entry at
_start, __vectors at address zero, and a BSS range in RAM. It has not been
executed. scripts/check_clang.sh now links eleven of eleven example builds.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-10 17:41:23 -04:00
Frédéric Desbiens a8aebc5206 Completed the Cortex-M0 barriers and made its example build with both toolchains (#595)
Two unrelated Cortex-M0 gaps, both left over from earlier work.

The memory barriers from #523 reached the Cortex-M0 gnu port but not its ac6 or
iar siblings, in either the inline system return in tx_port.h or the assembly
routine. Both take the same GNU or IAR code path, and iar already carried the
entry barrier, so the missing pieces were the entry pair for ac6 and the barrier
after restoring the interrupt posture for both. All three tools now match.

The Cortex-M0 example could not link with any toolchain. cortexm0_crt0.S
references 23 linker script symbols and the script defined only 12 of them, so
__text_start__, __text_end__, __text_load_start__, the rodata and fast section
symbols, and the ctors and dtors load addresses were all unresolved. The
Cortex-M4 script defines all 23, including a .fast section with no content whose
symbols exist so that the startup copy is a no-op, and its comment says as much.
The Cortex-M0 script is brought to that same shape.

That left the example failing under LLVM only, on instructions that ARMv6-M can
encode just one way. The file declared .code 16 but no syntax mode, so GNU as
used the legacy divided syntax in which a plain add or sub sets the flags
implicitly, while LLVM implements unified syntax only and rejected the
non-flag-setting spelling. Declaring .syntax unified and writing movs, adds and
subs makes both assemblers agree, and the encodings GNU produces are byte
identical before and after, verified by disassembling both objects.

The Cortex-M0 example now links with GNU at 22,520 bytes of text and with Arm
Toolchain for Embedded at 22,866, so it comes off the list of examples not
expected to link and scripts/check_clang.sh now links eight of eight.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-10 17:34:13 -04:00
Frédéric Desbiens f3ab36dacc Made the example builds work with LLVM, and fixed four that were broken on Linux (#594)
* Made the example builds work with LLVM, and fixed four that were broken on Linux

The gnu example builds are the natural LLVM path: Arm Toolchain for Embedded is
LLVM based, consumes GNU ld linker scripts, and needs none of the scatter files
or Arm DS projects the ac6 examples carry. So rather than port the ac6 examples,
teach the gnu scripts to drive either toolchain.

Each script now selects the toolchain from a TOOLCHAIN variable that defaults to
gnu, so every existing invocation behaves exactly as before. TOOLCHAIN=atfe
switches the compiler, adds the target triple, passes the entry symbol through
to the linker rather than to the driver, and links the toolchain's own
semihosting library in place of --specs=nosys.specs, which is a GCC spec file
mechanism with no LLVM equivalent. That last choice avoids adding a syscall stub
source to every example.

The scripts are parameterised rather than duplicated. Copies of build scripts
would drift the first time one side was edited, which is the failure this
repository has just spent several changes recovering from.

Four sample scripts could not run on a case-sensitive filesystem at all. They
compiled MP_PrivateTimer.s and V7.s while the files on disk are
MP_PrivateTimer.S and v7.s, and the Cortex-A5 and A9 scripts named MP_GIC.s
where the file is MP_GIC.S. The link lines named V7.o accordingly. Corrected to
match the files, which is why the Cortex-A5, A7, A8 and A9 examples now build on
Linux where before they could not.

Extend scripts/check_clang.sh to link the example builds as well as compile the
sources, since compiling proves the sources parse while only linking exercises
entry symbols, linker scripts and the C library together.

Eight examples are listed as not expected to link, each with its reason, so the
gaps stay visible rather than being silently skipped. Five of them fail with the
GNU toolchain too and are therefore not LLVM problems: the Cortex-M0 example's
crt0 references __text_load_start__, __text_start__ and __text_end__, which its
linker script never defines, while the Cortex-M4 script defines the equivalents;
the arm9, arm11, Cortex-R4 and Cortex-R5 examples need newlib multilib variants
that are not present in every GNU toolchain packaging. The Cortex-A12, A15 and
A17 examples fail only with LLVM, because their link line omits -nostartfiles so
the toolchain's own crt0 is linked and wants picolibc's __data_start,
__data_source, __data_size and __bss_size, which their linker script does not
define.

Verified by building every example with both toolchains. Seven link with both:
Cortex-A5, A7, A8, A9, M3, M4 and M7. The GNU results are unchanged where they
worked before, and now also succeed for the four scripts with the case bug.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>

* Resolved the compiler path before running the example builds

The example stage runs each build script from inside its own directory, so a
relative path passed with --clang stopped resolving there and every example
build failed instantly. Local runs passed an absolute path and did not show it;
the CI job passes a path relative to the workspace root, which did.

Resolve the compiler to an absolute path once, before any directory change, and
print it so the toolchain in use is visible in the log.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>

* Parameterised the archiver as well, and stopped the check hiding failures

The toolchain selection covered the compiler but not arm-none-eabi-ar, which the
scripts invoke 628 times to assemble the library archive. A machine with an LLVM
toolchain and no GNU one therefore could not build any example, which is exactly
the situation in CI: the runner has no Arm GNU toolchain installed. Local runs
had one, so this only appeared once the job ran.

Select the archiver alongside the compiler, taking llvm-ar from beside clang in
the toolchain. The four scripts that call arm-none-eabi-ld directly are left
alone: they are arm9, arm11, Cortex-R4 and Cortex-R5, all already listed as not
expected to link, and their invocations are specific to GNU ld in ways that
parameterising would not resolve.

The check reported "example build produced no image" and then filtered the log
for lines containing "error", which hid the actual cause, since a missing tool
reports "command not found" or "No such file or directory". It now prints the
tail of the log. That filtering cost two CI round trips to diagnose something
the first run already knew.

Verified by shadowing arm-none-eabi-gcc, arm-none-eabi-ar, arm-none-eabi-ld and
the aarch64 equivalents with stubs that fail loudly, then running the whole
check: all 711 sources assemble, all eight profiles compile and all seven
example builds link without any GNU tool being invoked. The GNU default path
still produces an identical image. The diagnostics were confirmed by pointing
the archiver at a name that does not exist and checking that the reason appears.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-10 15:10:34 -04:00
Frédéric Desbiens 68eb205768 Made the Arm ports build with LLVM, and added a check that keeps them that way (#593)
The gnu ports are only ever built with GNU tooling, and GNU as accepts several
non-canonical forms that LLVM's assembler rejects. Nothing noticed, because
nothing built them with anything else. This matters beyond clang itself: Arm
Toolchain for Embedded is LLVM based and is the successor to Arm Compiler 6, so
these are the code paths ac6 users move onto.

Seven files needed changing, none of which alters the emitted code:

LDREX and STREX take no offset in A32 state; the #imm form is Thumb-2 only. GNU
as drops the redundant zero, LLVM rejects it. Removed from the Cortex-A5, A7 and
A9 SMP protect routines.

ARMv8-M Baseline has no flag-preserving MOV immediate, so GNU as already emits
MOVS. Writing MOVS in the two Cortex-M23 sources says what the assembler was
doing anyway. One of them sits in a branch only compiled for the single mode
secure configurations, which is why it had never surfaced.

The Cortex-M0 schedule routine wrote LDR r0, =#0x10000000 with a stray hash,
which its own sibling file already wrote correctly.

The Cortex-M0 system return routine selected the numbered subsection .text 32,
which makes LLVM place the constant pool beyond the range a Thumb-1 PC relative
load can reach. Plain .text fixes it and GNU accepts either form. The reason is
recorded in the file, since 32 files pair a numbered subsection with a literal
pool load and the rest only escape because Thumb-2 and A32 have far more range.

Add scripts/check_clang.sh, which assembles every Arm gnu port source and
compiles the common C sources for one core per architecture profile, and a
clang_check workflow that installs Arm Toolchain for Embedded and runs it. The
toolchain version is pinned and checksum verified, for the same reason the
runner image is pinned.

The port directory to target mapping in that script is explicit rather than
prefix matched. Prefix matching is what makes cortex_a5 also match cortex_a53
and cortex_a55, which are AArch64, and assembling those as ARM32 produces
hundreds of misleading errors; that mistake cost real time while measuring this,
so the reason is recorded next to the table.

Verified with Arm Toolchain for Embedded 22.1.0: 711 of 711 assembly sources
assemble and 185 of 185 C sources compile for all eight profiles, against 6
assembly failures before the change. arm-none-eabi-gcc still assembles all 315
ARM32 sources, so nothing regressed for GNU. The check was confirmed to fail
when any one of the fixes is reverted.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-10 11:40:54 -04:00
Frédéric Desbiens f23a1807a2 Added bash A profile update scripts and restored ports_arch as their source (#592)
The ARMv7-A and ARMv8-A ports are generated by update.ps1, which needs
PowerShell, so the cortex-a job in ports_arch_check ran on a Windows image and
nobody could reproduce it locally on Linux. Add update.sh beside each
update.ps1, with the same cores, compilers, copy sets and patches, and move the
job to the same Linux image as everything else.

The bash scripts were checked against the PowerShell ones by comparing what
each reports as drifted. They agree exactly on the 63 files the Windows job
last reported, and differ on 12 more, which turn out to be a defect in
update.ps1 rather than in the port. Its two .cproject patterns are written as
'value=`"cortex-a7`"' with backticks that survive into the pattern, so that
replacement has never matched, while the neighbouring Cortex-A7.NoFPU pattern
has no backticks and always worked. The result is that the AC6 example builds
for the A5, A8, A9, A12, A15 and A17 cores name cortex-a7 as their CPU while
their FPU string is correct. The bash scripts do what the PowerShell ones
intended, so regenerating corrects those twelve files.

Restore ports_arch as the source for the rest. The implementation of
_tx_thread_smp_time_get from #555 was applied to the twenty four generated SMP
ports and never to ports_arch, which still held MOV x0, #0 with a FIXME
comment, so regenerating would have replaced a working generic timer read with
a stub. That implementation now lives in the source. The remaining differences
are cosmetic and resolve in favour of the source: a trailing blank line in 38
copies of tx_thread_schedule.S and comment spacing in one tx_port.h.

Note that the Cortex-A VFP fix is already present in ports_arch and was never
at risk, contrary to what the description of the port consistency checks change
said before this was measured.

Extend scripts/check_ports.sh to run the A profile generators too, and make it
fail when a generator fails or is missing rather than reporting a clean tree,
which would have been a false pass.

Pin every workflow to ubuntu-24.04. ubuntu-latest already resolves to that
image, so nothing changes today, but a future migration becomes a deliberate
commit rather than something that happens underneath the -m32 builds.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-09 10:55:29 -04:00
Frédéric Desbiens 08b120d2bc Added port consistency checks and wired them into CI and release preparation (#591)
Three defects reached the repository through the port trees recently, and each
of them is mechanically detectable without a cross compiler. Add
scripts/check_ports.sh, which looks for exactly those three, and give CI and
the release process the same command a contributor can run locally.

The generated Cortex-M ports must be reproducible from ports_arch. Fixes were
applied to the generated copies instead of the source for eight months, and the
next run of the copy scripts would have reverted them.

Preprocessor directives must balance. A fix left the Cortex-M85 IAR tx_port.h
with one more #endif than #if, so that header could not compile.

No port header may carry a statement outside a function body. A fix left a
second, headerless copy of a function body in the Cortex-M4 AC6 tx_port.h,
which is issue 569. The check tracks brace depth while skipping preprocessor
lines, multi-line macro bodies and comments, and reports assignments,
dereferences and control statements that land at file scope. Headers under
example_build are excluded, since those trees vendor third party SDK code.

A fourth section reports, without failing the run, on port families that have
no copy script and so cannot be checked for reproducibility. It currently
observes that the Cortex-M0 ac5, ac6 and keil ports lack the barriers their gnu
and iar siblings have.

ports_arch_check now calls the script rather than inlining a copy and diff, so
CI and the command line check the same things by the same definition, and the
workflow now triggers on pull requests to dev as well as master. Triggering on
master alone is why the drift went unseen. prepare_release.sh runs the checks
before it branches or rewrites anything, and stops if they fail, with
SKIP_PORT_CHECKS=1 as the escape hatch.

Each check was verified by reintroducing the defect it exists to catch and
confirming that the script fails, then confirming it passes on a clean tree.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-09 10:48:29 -04:00
Frédéric Desbiens eb4ec4e3b5 Restored ports_arch as the source of truth for the Cortex-M ports (#590)
The Cortex-M ports under ports/ are generated. scripts/copy_armv7_m.sh copies
one tx_port.h and the per tool sources to fifteen M3, M4 and M7 targets, and
scripts/copy_armv8_m.sh does the same for nine M33, M55 and M85 targets. The
ports_arch_check workflow runs both scripts and fails if the tree is not
reproducible, so those copies are meant never to be edited directly.

They were. Every Cortex-M fix since #523 was applied to the generated copies
and not to the source, so the source fell behind and the check went red:
running the three scripts on dev changes 35 files. The check triggers only on
pull requests targeting master, which is why nothing caught it while the fixes
were merged into dev.

Left alone, the next run of these scripts would have reverted three separate
pieces of work: the memory barriers and clobbers from #523, the correction of
the IAR assembly header to use the assembler's own comment syntax, and the move
of tx_initialize_low_level.S into example_build for the M33, M55 and M85 GNU
ports from #514.

Bring the sources up to what the ports carry today, and regenerate. Two
behavioural changes come with that, both deliberate. The barriers from #523
reach the ac5 and keil variants of M3, M4 and M7, which were outside the scope
of that fix and never received it. The barrier that follows restoring the
interrupt posture, which #523 gave only to the GNU ports because GNU was the
only toolchain that could be tested, now applies to every tool; the identical
asm statement already shipped in the AC6 and IAR ports, so this adds a pipeline
flush rather than any new compiler exposure.

Regenerating also drops a stray #endif at the end of the Cortex-M85 IAR
tx_port.h, added by #523, which left that header with one more #endif than #if
and unable to compile. Every other ARMv8-M port was balanced.

Verified that the scripts are idempotent afterwards, that ports_arch_check
would pass, that no port loses a barrier or a clobber, that every regenerated
header is preprocessor balanced, and that every Cortex-M port covered by the
two scripts now carries the entry barrier.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-09 10:42:54 -04:00
Frédéric Desbiens cbdf924d6b Removed the duplicated function body in the Cortex-M4 AC6 port (#589)
_tx_thread_system_return_inline() in the Cortex-M4 AC6 tx_port.h was followed
by a second, orphaned copy of its own body. The copy had no function header, so
it declared interrupt_save at file scope and then placed statements there,
which does not compile. It is also the older version of the body, without the
dsb and isb barriers, so it was left behind rather than intended: the barriers
were added by commit 33efad3f and the previous text was not removed.

Delete the orphaned copy. What remains is the same body every sibling port
carries: after this change ports/cortex_m4/ac6/inc/tx_port.h differs from
ports/cortex_m4/iar/inc/tx_port.h and ports/cortex_m7/ac6/inc/tx_port.h only in
the port name in the banner and the version string, as it should.

Verified by compiling the function in isolation, which fails on the file scope
statements before the change and is clean afterwards, and by a structural scan
of all 208 tx_port.h files in the repository confirming this was the only
occurrence.

Fixes https://github.com/eclipse-threadx/threadx/issues/569

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-09 10:12:09 -04:00
Frédéric Desbiens cfed1d8095 Fixed the kernel object leaks on the static creation error paths (#584)
xQueueCreateStatic() and xTaskCreateStatic() take their storage from the
caller, so neither leaks memory, but both create ThreadX objects and both
return NULL when a later step fails. The caller is left without a handle and
cannot call the matching delete function, so any object already created stays
registered in the kernel, pointing into a caller buffer that the application
is now free to reuse or discard.

Three paths were affected. xQueueCreateStatic() abandoned the read semaphore
when the write semaphore could not be created. xTaskCreateStatic() abandoned
the notification semaphore when the thread could not be created, and abandoned
both the semaphore and the thread when the thread could not be resumed.

Delete what was already created before returning on each of them. The resume
path terminates the thread before deleting it, since a thread created with
TX_DONT_START is suspended rather than terminated, which is the same order the
idle task uses when it reaps a deleted task.

Extend the regression suite to cover all three paths, and add thread resume to
the set of entry points the harness can force to fail. Each static failure case
now uses its own control block, so a future regression on one path cannot carry
damage into the next case and report misleading counts there.

Verified against the layer as it stands on dev, where the three new checks fail
with the objects left behind, and against the fixed layer, where the suite
passes.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-09 08:44:30 -04:00
Frédéric Desbiens f3df5f9dde Added a regression suite for the FreeRTOS compatibility layer (#583)
* Fixed the resource leaks on the xQueueCreate error paths

xQueueCreate() allocated the queue descriptor and its backing memory, then
created two ThreadX semaphores, and returned NULL on either semaphore failure
without releasing anything. Since no handle reached the caller, vQueueDelete()
could not be used to recover, so both allocations were lost. A failure on the
second semaphore additionally abandoned the read semaphore it had already
created, leaving a live ThreadX control block inside freed memory.

Release the backing memory and the descriptor on both paths, and delete the
read semaphore before returning when the write semaphore cannot be created.
This is the teardown order vQueueDelete() already uses, and it matches the
cleanup xTaskCreate() performs on its own error paths.

Verified with a fault injection harness that intercepts the ThreadX byte pool
and semaphore entry points to force tx_semaphore_create() to fail on a chosen
call. On a read semaphore failure the layer previously performed 2 allocations
and 0 releases, and on a write semaphore failure 2 allocations, 0 releases and
0 semaphore deletions. It now performs 2 releases in both cases and deletes
the read semaphore in the second, with the byte pool restored to its prior
state.

Fixes https://github.com/eclipse-threadx/threadx/issues/570

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>

* Added a regression suite for the FreeRTOS compatibility layer

The compatibility layer had no tests in this repository, which is awkward for
its creation functions in particular. Each of them takes one or two byte pool
allocations for its bookkeeping and then creates ThreadX kernel objects, and
each returns NULL when a kernel object cannot be created. The caller is left
without a handle, so it cannot call the matching delete function, and anything
the layer failed to release is gone until the system restarts. A leaking
version and a correct version are indistinguishable from the outside, which is
how the leak in issue 570 went unnoticed.

Add a suite that counts what the layer takes and gives back. A test asks the
harness to fail a chosen kernel creation call, then checks the number of byte
pool allocations, releases, object creations and object deletions performed.
The ThreadX entry points are intercepted with the linker's --wrap so that
tx_freertos.c is compiled exactly as it ships, with no test hooks in it. Note
that tx_api.h maps the public API onto the error checking entry points, so the
_txe_ symbols are the ones wrapped. Coverage is the creation and teardown paths
of queues, tasks, semaphores, mutexes, event groups and timers, including a
regression test for the two paths fixed for issue 570.

The suite follows the layout of the existing ThreadX and SMP suites, is
registered with ctest, and runs in CI through the shared regression template.
It is built 32 bit because the Linux port defines ULONG as unsigned int on
x86_64 while the layer passes pointers through ULONG arguments, so a 64 bit
build truncates them. It is Linux only because --wrap has no MSVC equivalent,
and the CMake configuration says so rather than failing at link time.

Validated by building the suite against the layer as it stands before the
issue 570 fix, where the two expected checks fail with the leaked counts, and
against the fixed layer, where all three tests pass.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-09 08:03:16 -04:00
Frédéric Desbiens 5481fc75a0 Fixed the resource leaks on the xQueueCreate error paths (#582)
xQueueCreate() allocated the queue descriptor and its backing memory, then
created two ThreadX semaphores, and returned NULL on either semaphore failure
without releasing anything. Since no handle reached the caller, vQueueDelete()
could not be used to recover, so both allocations were lost. A failure on the
second semaphore additionally abandoned the read semaphore it had already
created, leaving a live ThreadX control block inside freed memory.

Release the backing memory and the descriptor on both paths, and delete the
read semaphore before returning when the write semaphore cannot be created.
This is the teardown order vQueueDelete() already uses, and it matches the
cleanup xTaskCreate() performs on its own error paths.

Verified with a fault injection harness that intercepts the ThreadX byte pool
and semaphore entry points to force tx_semaphore_create() to fail on a chosen
call. On a read semaphore failure the layer previously performed 2 allocations
and 0 releases, and on a write semaphore failure 2 allocations, 0 releases and
0 semaphore deletions. It now performs 2 releases in both cases and deletes
the read semaphore in the second, with the byte pool restored to its prior
state.

Fixes https://github.com/eclipse-threadx/threadx/issues/570

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-09 07:28:19 -04:00
Frédéric Desbiens 2b0e4e44b9 Hardened the module converter utilities against malformed input (#580)
* Hardened the module converter utilities against malformed input

While reviewing the code_buffer leak reported in issue 571, three further
pre-existing defects turned up in the same host-side utilities.

The four ELF area allocations in module_to_binary.c and module_to_c_array.c
were unchecked, and every elf_object_read() return value was discarded, so a
truncated or crafted ELF file was read into whatever the allocation and the
reads happened to leave behind. Check each allocation, distinguishing a NULL
return for an empty area from a genuine failure, and abandon the conversion
with exit code 5 on an allocation failure and exit code 6 on a read failure.

Validate the section string table index taken from the ELF header before it
is used to subscript the section header area. AddressSanitizer confirms that
an out-of-range index produced a heap buffer overflow in both tools.

Correct the address format specifiers in module_to_c_array.c and
module_binary_to_c_array.c, which passed an unsigned long to %08X, and close
the source file on the invalid format path of module_binary_to_c_array.c.
The unused current_total local is removed. All three utilities now build
warning free with gcc -std=c99 -Wall -Wextra, and the code they emit is
unchanged byte for byte on valid input.

Refresh the version banners of all three tools, on the console and in the
header written into the generated C arrays, to the 2024 Microsoft Corp and
2026 Eclipse ThreadX contributors copyrights and version v6.5.2.202603. The
banners still advertised v5.8 and v5.4 with a 2018 build date. The .exe
suffix is dropped from the tool names, since these tools build on Linux too.

Related to https://github.com/eclipse-threadx/threadx/issues/571

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>

* Added the missing licence header to module_binary_to_c_array.c

The file carried no copyright or licence header at all, unlike the two other
converter utilities in the same directory. Use the same MIT header they carry,
since the three tools share an origin.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-08 08:09:06 -04:00
Frédéric Desbiens bd8d30f23b Fixed code_buffer leak in the module converter utilities (#581)
The host-side module converter utilities allocated code_buffer inside the
loop over the ELF code sections and never released it, so every code
section in the input ELF leaked one buffer. The malloc() result was also
unchecked, so a failed allocation passed a null pointer on to
elf_object_read() and crashed the tool.

Release the buffer at the end of each iteration and report a clean failure
with exit code 5 when the allocation does not succeed. Verified with
AddressSanitizer on a two-code-section input: 128 bytes leaked in 2
allocations before, none after, with byte-identical output.

Fixes https://github.com/eclipse-threadx/threadx/issues/571

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-08 08:01:38 -04:00
Frédéric Desbiens f84dd3d2aa Added Cortex-R52 port with Armv8-R AEM FVP example build (#579)
Added a ThreadX port for Arm Cortex-R52 with the GNU toolchain

Adds ports/cortex_r52/gnu together with a CMake build, an example build for the
freely available Armv8-R AEM FVP, and an automated test suite.

The port is EL2-aware by construction.  Cortex-R52 always implements EL2 and
resets into it, so the reset path configures EL2, installs both the EL2 and EL1
vector tables, and only then drops to EL1 to run the kernel.  Keeping that
structure from the start lets partitioning work reuse the boot path rather than
replace it; TX_R52_BOOT_AT_EL1 skips the EL2 stage where a vendor monitor has
already dropped privilege.

This is also the first R-profile port in the tree with a working CMake build.
cmake/cortex_a9.cmake exists but ports/cortex_a9/gnu/CMakeLists.txt is empty, so
no A- or R-profile port could be built this way before.

Contents:

  - Kernel port: 16 assembly sources plus tx_port.h, seeded from the
    Cortex-R5/GNU port.
  - Build: cmake/cortex_r52.cmake and the port CMakeLists.txt, with soft/hard
    float, VFP, FIQ and IRQ/FIQ nesting options.
  - Example BSP: EL2 to EL1 boot, GICv3, generic timer, PMSAv8-R MPU,
    semihosting and PL011 consoles.
  - Tests: six images registered with CTest, each judging itself and
    terminating the model.
  - tx_port_offset_check.c: compile-time assertions on the TX_THREAD offsets
    the assembly reaches by hard-coded displacement.  This is the same defect
    class fixed for Cortex-R4/R5 in #578; nothing in the toolchain ties those
    literals to the C structure.

Two facts were established by experiment rather than taken from documentation,
and are recorded in the code and the readme because both are traps:

  - PRBAR.AP bit order is reversed relative to th
    AArch64 macro set: the low bit is read-only and the high bit grants EL0
    access.  Programming four disjoint regions, one per encoding, and
    attempting a privileged write to each gave 0b
    and 0b10 allowed.  Using the AArch64 ordering
    as read-only and silently accept writes, because region coverage is still
    enforced: an unmapped address faults while a "read-only" region does not.
  - The generic timer PPI is INTID 30, recorded from ICC_IAR1 after enabling
    the whole PPI range 25-31, rather than assume

Model behaviour that a silicon port must revisit: the FVP leaves CNTFRQ at zero
with the system counter stopped, so the BSP programs both; CNTHCTL.PL1PCTEN,
CNTHCTL.PL1PCEN and ICC_HSRE must be set at EL2 or EL1 accesses trap; and
tx_thread_vfp_enable() sets only a per-thread software flag, so enabling the FPU
hardware (CPACR, FPEXC.EN) is the board support package's responsibility, not
the kernel's.  The FVP reports MIDR 0x410FD0F0, an architecture envelope model
rather than a Cortex-R52, so it validates architecture and not implementation.
Nothing in the port is gated on MIDR.

Changes outside ports/cortex_r52, three and all small: cmake/cortex_r52.cmake is
a new toolchain file; CMakeLists.txt gains enable_testing() at the top level,
without which add_test() in a subdirectory generat
the root never references, so ctest reports no tests from the build root; and
.gitignore covers build directories and __pycache__.

Verification: all six images build warning-free a
FVP_BaseR_AEMv8R in three configurations -- protection off, protection and
caches on, and both together with hard-float VFP.  Six build-option
combinations build clean and pass the tick-and-preemption demo at run time.

The tests assert behaviour rather than configuration, which is what caught the
problems above: the cooperative demo asserts the order of execution, because
counting alone cannot distinguish working context switches from one thread
running to completion, and the MPU test provokes real faults, because reading
SCTLR back only proves a bit was set.

The 96-test regression suite is host-side and pas
configurations on the Linux port.  It is not cross-run here: it validates
portable kernel logic, while the port-specific risk is the assembly, which the
FVP images exercise.  Structural coverage is therefore not claimed.

Deliberate deviations: passing a string literal to tx_thread_create reports a
discarded const qualifier from common/inc/tx_api.
CHAR *; demo_threadx.c keeps the shipped sample's int main() so the demo body
stays byte-identical to it; and the floating-point test compares exactly on
purpose, since a tolerance would mask a restored
wrong.

Not included: modules support, split-mode SMP and
support. The example targets the FVP only, and NXP S32Z280 bring-up is
separate work; the readme flags what to re-verify there.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-08 08:00:01 -04:00
Frédéric Desbiens 2baae7c57f Fixed VFP issues on Cortex-R4 and R5 ports (#578)
* Fixed missing VFP thread extension on Cortex-R4 and R5 ports

Building cortex_r4/gnu, cortex_r5/gnu or cortex_r5/ac6 with
TX_ENABLE_VFP_SUPPORT corrupts memory. The assembly in
tx_thread_schedule, tx_thread_system_return and tx_thread_context_restore
reads and writes a per-thread VFP enable flag as [thread, #144], but every
TX_THREAD_EXTENSION in these ports' tx_port.h was empty, so no such member
existed.

Offset 144 in the resulting TX_THREAD is tx_thread_filex_ptr, so the
damage runs both ways:

  - tx_thread_vfp_enable() stores 1 into tx_thread_filex_ptr, after which
    FileX dereferences 0x1;
  - conversely, once FileX sets that pointer the context switch reads it as
    "floating point enabled" and starts pushing about 132 bytes of
    floating-point context onto a thread stack never sized for it, then
    restores unrelated data into the D registers.

sizeof(TX_THREAD) is 180 on these ports, so 144 is a live member rather
than padding past the end of the structure.

What makes this dangerous is that it is silent. The defect was reproduced
at runtime by reverting the Cortex-R52 port -- which inherited the same
assembly and the same hard-coded 144 from the R5 port -- to this state and
running its floating-point demo on the Armv8-R AEM FVP. Every
floating-point value was still preserved exactly and no corruption was
reported across interrupts, because a non-zero filex_ptr reads as "enabled"
and the context switch dutifully saves and restores. The only visible
damage was tx_thread_filex_ptr reading 0x00000001. In other words the
feature you enabled appears to work, and what breaks is an unrelated
pointer that nothing notices until FileX is introduced. With the field
present the same demo reports the sentinel intact.

This appears to be drift rather than a deliberate limitation. All fourteen
Armv7-A port and toolchain combinations define the field and contain the
VFP code paths. The R-profile family is inconsistent in both directions:
these three have the code paths without the field, while cortex_r4/ac5,
cortex_r4/ac6, cortex_r4/iar, cortex_r5/ghs, cortex_r5/iar, cortex_r7/ghs
and cortex_r8_smp/ac5 define the field but contain no VFP code paths.

The fix follows the Armv7-A ports exactly: TX_THREAD_EXTENSION_2 carries
tx_thread_vfp_enable, and tx_thread_vfp_enable/disable are declared. The
field is defined unconditionally rather than under TX_ENABLE_VFP_SUPPORT
because the offset is hard-coded in assembly, so a conditional member
would shift every following field and be correct in only one
configuration. No assembly changes are needed: 144 is already correct once
the member exists.

Verified with GCC 14.3: on all three ports tx_thread_vfp_enable now lands
at exactly offset 144, matching the assembly, with tx_thread_filex_ptr
moved to 148. The library builds cleanly for cortex_r4/gnu and
cortex_r5/gnu both with and without TX_ENABLE_VFP_SUPPORT, and the VFP
save and restore instructions appear in the port assembly only when it is
requested. cortex_r5/ac6 is verified by offset and inspection only, as
that toolchain was not available here. Runtime verification was performed
on Armv8-R as described above rather than on R4/R5 silicon; upstream QEMU's
xlnx-zcu102 machine holds its Cortex-R5F cores in reset, so no R5 target
was available.

ABI note for release documentation: adding the member moves
tx_thread_filex_ptr and everything after it by four bytes and grows
TX_THREAD from 180 to 184 bytes. This is the layout the Armv7-A ports
already have, so the change aligns R-profile with A-profile rather than
introducing a new one, but kernel awareness and TraceX tooling that
hard-codes offsets will need rebuilding.

Follow-up worth considering separately: nothing in the toolchain ties the
literal 144 in the assembly to the C structure, which is what allowed this
to go unnoticed. A compile-time assertion per port turns any recurrence
into a build failure -- when the experiment above reverted the field, that
assertion failed the build before a corrupting binary could be produced.
ports/cortex_r52/gnu/src/tx_port_offset_check.c is a working reference.


* Added compile-time offset checks to the Cortex-R4 and R5 ports

Nothing in the toolchain connects the structure offsets hard-coded in the
port assembly to the C definition of TX_THREAD, which is what allowed the
missing VFP thread extension to go unnoticed. These files assert the
offsets that the context-switch path depends on, so a recurrence becomes a
build failure instead of memory corruption discovered later at runtime.

Three offsets are asserted: the VFP enable flag at 144, the thread stack
pointer at 8 and the run counter at 4. The stack pointer and run counter
precede every extension macro in TX_THREAD, so they are stable by
construction. Offset 144 was checked against the build options that could
plausibly move it -- stack checking, event trace, event logging,
performance info and TX_NOT_INTERRUPTABLE -- and is unchanged by all of
them, because the only conditional member nearby guards
tx_thread_filex_ptr, which follows the extension, and
TX_THREAD_USER_EXTENSION appears much later in the structure. The
assertions therefore cannot misfire on a legitimate configuration.

C99 has no _Static_assert, so a negative array dimension is used. Each
file compiles clean under -std=c99 -pedantic -Wall -Wextra and emits zero
bytes of code or data.

Verified that the checks actually catch regressions rather than merely
compiling: asserting a deliberately wrong offset is rejected on all three
ports, and removing the VFP field again fails the build outright with a
message naming the missing member.

These ports have no CMake build of their own, so the files take effect
only in builds that compile everything under src/. That is still
worthwhile given they cost nothing and emit nothing. Extending the same
technique to the remaining ports is deliberately left as separate work: it
requires reading each port's assembly to attribute every hard-coded
literal to the right structure, and copying assertions without that
analysis would risk asserting wrong offsets.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-08-06 10:05:33 -04:00
Frédéric DesbiensandCopilot 190c4d6be4 Flagged txm_module_object_pointer_get as deprecated (#562)
Added #pragma message compile-time warning to the module library
source and updated the DESCRIPTION blocks in both the library and
manager implementations.

Reason: this wrapper passes UINT_MAX as the name-buffer length to
the underlying extended search. The comparison loop can therefore
read past the end of a short name buffer, which is undefined
behaviour. Callers should use txm_module_object_pointer_get_extended()
and supply the actual buffer length.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-27 10:30:49 -04:00
Frédéric DesbiensandCopilot 92ce0754ed Marked txm_module_object_deallocate as deprecated (#559)
Added a compile-time #pragma message warning to the module library
source so that any module that includes or compiles this file receives
an explicit deprecation notice at build time.

Updated the internal documentation block in the manager-side
implementation to explain that this function must not be called directly
and that calling it on a live object causes a use-after-free.

The Module Manager dispatch layer already releases pool memory
automatically after a successful tx_*_delete() call. Module authors
should remove any explicit call to txm_module_object_deallocate().

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-27 10:30:29 -04:00
Frédéric Desbiens d2de89df18 Merge remote-tracking branch 'origin/master' into dev 2026-07-22 13:36:18 -04:00
Frédéric Desbiens 44d7c95c58 Updated SECURITY.md (#566)
cortex_m / Cortex M0 build (push) Has been cancelled
cortex_m / Cortex M3 build (push) Has been cancelled
cortex_m / Cortex M4 build (push) Has been cancelled
cortex_m / Cortex M7 build (push) Has been cancelled
regression_test / tx (push) Has been cancelled
regression_test / smp (push) Has been cancelled
regression_test / deploy (push) Has been cancelled
2026-06-30 17:31:42 -04:00
Frédéric DesbiensandCodex a33f6efc48 Updated Cortex-R4 Thumb bit immediates (#565)
Use explicit immediate syntax when testing the Thumb bit in AC6 Cortex-R4 stack build assembly.

Co-authored-by: Codex <codex@openai.com>
2026-06-29 16:22:52 -04:00
Frédéric DesbiensandCodex 3fcfb4e4c9 Updated Cortex-M BASEPRI zero immediates (#564)
Use explicit immediate syntax when clearing BASEPRI in GNU and AC6 Cortex-M scheduler assembly.

Co-authored-by: Codex <codex@openai.com>
2026-06-29 16:07:12 -04:00
d9e7dfea89 Add SysTick counter reset in Cortex-M ports (#561)
* Add SysTick counter reset in Cortex-M ports

The SysTick counter value (SYST_CVR @0xE000E018) is indeterminate after
reset. Without clearing it prior to enabling the counter, the first tick
interval becomes unpredictable.

* Fixed missing comment and added generated-by header in Cortex-M0/AC6 port

Added the missing inline comment on the LDR r1, =0 instruction
(Build value for SysTick reset) and the required AI-generated
attribution comment under the copyright header.

---------

Co-authored-by: Frédéric Desbiens <frederic.desbiens@eclipse-foundation.org>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-24 12:16:51 -04:00
Frédéric DesbiensandCodex 2dfe5acfb0 Fixed ARMv8 SMP time sources (#555)
Follow up on the issue-541 execution profiling work. PR #553 fixed SMP execution profile total-time aggregation, and PR #554 fixed Armv7/R SMP timestamp hooks that used decrementing private timers.

This change addresses the remaining related gap in ARMv8-A SMP ports: their timestamp hooks returned zero, which left execution profiling and trace timestamps without a progressing time source. Replace those stubs with the architectural generic physical counter, CNTPCT_EL0, across the ARMv8-A SMP GNU, AC6, IAR, and GHS variants.

The local ARMv8 AArch64 system timer example already uses CNTPCT_EL0 for physical count reads, so this keeps the SMP timestamp hook aligned with the existing port examples while preserving the 32-bit ULONG return contract.

Co-authored-by: Codex <codex@openai.com>
2026-06-22 08:27:10 -04:00
Frédéric DesbiensandCodex 32a68cc69a Fixed private-timer timestamp issue in several ports (A5, A7, A9, R8) (#554)
* Fixed Cortex-A9 SMP time source

Updated Cortex-A9 SMP timestamp reads to use the global timer low counter instead of the decrementing private timer counter. Applied the change to GNU and AC5 ports.

* Fixed remaining Arm SMP time sources

Updated Cortex-A5, Cortex-A7, and Cortex-R8 SMP timestamp hooks so execution profiling uses incrementing time sources instead of the decrementing private timer count register.

Cortex-A5 and Cortex-R8 now read the global timer count low register, matching the Cortex-A9 fix. Cortex-A7 now reads the generic timer physical count register.

---------

Co-authored-by: Codex <codex@openai.com>
2026-06-22 08:07:16 -04:00
Frédéric DesbiensandCodex b880ffeada Fixed SMP execution profile total getters (#553)
Updated the SMP execution profile aggregate getters to copy each core's total into the matching output array element. Added a focused regression test for thread, ISR, and idle total getters.

Co-authored-by: Codex <codex@openai.com>
2026-06-22 08:03:46 -04:00
franco 859c098747 Fix nested comment warning in RX GCC ports (#550)
The RX GCC assembly port contains an unclosed C-style comment in tx_thread_context_save.S. Because .S files are passed through the C preprocessor before assembly, the nested comment can trigger GCC warnings.

Close the affected comment block without changing assembly instructions or runtime behavior.

Signed-off-by: FranCDoc <fchiesadoc@gmail.com>
2026-06-16 10:26:26 -04:00
Frédéric Desbiens b91b03b9e7 Merge pull request #548 from eclipse-threadx/dev
cortex_m / Cortex M0 build (push) Has been cancelled
cortex_m / Cortex M3 build (push) Has been cancelled
cortex_m / Cortex M4 build (push) Has been cancelled
cortex_m / Cortex M7 build (push) Has been cancelled
regression_test / tx (push) Has been cancelled
regression_test / smp (push) Has been cancelled
regression_test / deploy (push) Has been cancelled
Merge changes for the v6.5.1.202602a release
v6.5.1.202602a_rel
2026-06-08 17:08:34 +02:00
Frédéric DesbiensandCopilot df30b8b96e Release 6.5.1.202602a preparation (#547)
* Updated version number constants

* Updated port version strings

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-08 16:59:04 +02:00
Frédéric Desbiens 5a07bdac35 Fix/issue 545 basepri endif (#546)
* Fixed #else replaced with #endif in tx_port.h for cortex_m3/m4/m7 gnu/ac6/iar ports

In the __set_basepri_value/#ifdef TX_PORT_USE_BASEPRI block, an #else
directive was incorrectly replaced with #endif in a prior commit.
This caused the TX_PORT_USE_BASEPRI guard to close prematurely and
left __enable_interrupts unconditionally visible (or triggered an
orphaned #endif / missing #endif error at compile time).

Affected ports: cortex_m3/ac6, cortex_m3/iar, cortex_m4/ac6,
cortex_m4/gnu, cortex_m4/iar, cortex_m7/ac6, cortex_m7/gnu,
cortex_m7/iar.

For cortex_m3/gnu and cortex_m4/gnu the fix restores the #else and
the existing second #endif now correctly closes the block.
For the ac6/iar variants of m3/m4 and all m7 variants, the #else is
restored and a missing closing #endif is added after __enable_interrupts.

Also adds Linux shell build scripts (build_threadx.sh and
build_threadx_sample.sh) for the cortex_m3/gnu, cortex_m4/gnu, and
cortex_m7/gnu example_build directories as Linux equivalents of the
existing .bat files.


* Fixed missing linker script symbols in cortex_m4/gnu example_build

cortexm4_crt0.S references several symbols that were absent from
sample_threadx.ld, causing undefined-reference linker errors when
building the sample:

- __text_load_start__, __text_start__, __text_end__
- __rodata_load_start__, __rodata_start__, __rodata_end__
- __fast_load_start__, __fast_start__, __fast_end__
- __ctors_load_start__, __dtors_load_start__

Changes:
- Added __text_start__/__text_end__ bounds to the .text section and
  __text_load_start__ via LOADADDR(.text).
- Moved .rodata out of .text into its own section with start/end/load
  
- Added __ctors_load_start__ and __dtors_load_start__ markers within
  .text (load address == VMA since the section is XIP in FLASH; the
  crt0 copy call becomes a no-op).
- Added an empty .fast section in RAM with __fast_load_start__ pointing
  to __fast_start__ so the crt0 fast-copy call is a no-op.


* Added Linux build scripts and fixed path bug in cortex_m23 for all ports changed between v6.5.0 and v6.5.1

Added build_threadx.sh (and build_threadx_sample.sh where applicable)
as Linux equivalents of the Windows .bat scripts for all GNU-toolchain
ports touched between v6.5.0.202601_rel and v6.5.1.202602_rel:

  arm9, arm11, cortex_a5/a7/a8/a9/a12/a15/a17,
  cortex_m0, cortex_m23, cortex_r4, cortex_r5

For cortex_m33/m55/m85 (which had no .bat equivalent), build_threadx.sh
was written from scratch using the port CMakeLists.txt source lists and
the correct CPU flags (-mcpu=cortex-m33/m55/m85 -mthumb).

Also fixed a pre-existing bug in cortex_m23/gnu/example_build/
build_threadx.bat (and the generated .sh): tx_thread_stack_error_handler.c
and tx_thread_stack_error_notify.c were referenced as ../src/ (port
directory) instead of ../../../../common/src/ where they actually live.

All 16 newly added build_threadx.sh scripts were verified to compile
successfully with arm-none-eabi-gcc 13.2.1.

---------
Closes #545
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-08 16:51:08 +02:00
Frédéric Desbiens 87ab09cce3 Merge pull request #544 from eclipse-threadx/dev
cortex_m / Cortex M0 build (push) Has been cancelled
cortex_m / Cortex M3 build (push) Has been cancelled
cortex_m / Cortex M4 build (push) Has been cancelled
cortex_m / Cortex M7 build (push) Has been cancelled
regression_test / tx (push) Has been cancelled
regression_test / smp (push) Has been cancelled
regression_test / deploy (push) Has been cancelled
Merging changes for the v.6.5.1.202602 release
v6.5.1.202602_rel
2026-06-08 10:01:32 +02:00
Frédéric DesbiensandCopilot 730b61874b Added copyright headers to files missing them
Applied the standard MIT license header to all project-owned C, header,
assembly, shell, and Python files that were missing a copyright notice.
Third-party, toolchain startup, and auto-generated files were excluded.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-06 21:48:06 +02:00
Frédéric DesbiensandCopilot de1c6e9bbe Release 6.5.1.202602 preparation (#543)
* Updated version number constants
* Updated port version strings

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-03 16:55:01 -04:00
Frédéric DesbiensandCopilot e2834b3618 Added a release preparation script (#542)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-03 16:35:28 -04:00
Frédéric DesbiensandCopilot 518127b2e9 cmake: fixed THREADX_ARCH undefined when building as standalone library (#540)
CMake loads the toolchain file during the first project() call.
Variables set in the toolchain (THREADX_ARCH, THREADX_TOOLCHAIN) were
therefore not visible before project() was invoked.  Commit 2c16114a
moved project() after those checks to conditionally select LANGUAGES and
CMAKE_TRY_COMPILE_TARGET_TYPE for Windows, which broke standalone builds
that rely on the toolchain to supply THREADX_ARCH.

Fixed by calling project(threadx LANGUAGES C) first so the toolchain is
sourced, then checking THREADX_ARCH, then conditionally enabling ASM via
enable_language(ASM) for non-Windows ports.  The CMAKE_TRY_COMPILE_TARGET_TYPE
override was removed from CMakeLists.txt because every toolchain file in
cmake/ already sets it to STATIC_LIBRARY where needed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-29 08:50:52 -04:00
Frédéric DesbiensandCopilot d4b9448f84 Added riscv-none-elf-rv32imc toolchain file for xPack (risc-v32) (#539)
Add cmake/riscv-none-elf-rv32imc.cmake targeting the xPack
riscv-none-elf-gcc toolchain with rv32imc_zicsr/ilp32 ABI for
bare-metal CORE-V MCU builds.

Update cmake/riscv32-unknown-elf-rv32imc.cmake to correctly target
rv32gc/ilp32d (matching riscv-collab riscv32-elf ABI) for QEMU
regression tests.

Update cmake/riscv64-gcc-rv32imc.cmake compat alias to include
the new riscv-none-elf-rv32imc.cmake.

Update CORE-V MCU example_build: build.sh exports xPack PATH,
install_deps.sh downloads xPack 15.2.0-1, README.md reflects new
toolchain name/path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-27 17:06:37 -04:00
Frédéric DesbiensandCopilot 6061c43f96 Removed clz.c workaround; use riscv32-unknown-elf toolchain (#538)
bsp/clz.c provided a weak __clzsi2 fallback to work around the missing
rv32 multilib in the riscv-collab riscv64-unknown-elf toolchain.  Since
cmake/riscv32-unknown-elf-rv32imc.cmake now uses the dedicated riscv32-
unknown-elf-gcc toolchain (riscv-collab riscv32-elf release), which ships
a native rv32/ilp32 libgcc with all required helpers, the workaround is
no longer needed.

Remove bsp/clz.c and its entry in CMakeLists.txt.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-27 12:00:47 -04:00
Frédéric Desbiens 4a7343159b Merge branch 'master' into dev 2026-05-27 11:50:17 -04:00
Frédéric DesbiensandCopilot 80cbaadfaf cmake: rename rv32 toolchain file to riscv32-unknown-elf-rv32imc.cmake (#537)
Renamed cmake/riscv64-gcc-rv32imc.cmake to the accurate name
cmake/riscv32-unknown-elf-rv32imc.cmake and switch the compiler
from riscv64-unknown-elf-gcc to riscv32-unknown-elf-gcc.

The riscv-collab riscv64-elf toolchain has no rv32 multilib and
will fail to link soft-float and integer helpers (__clzsi2, __muldf3,
etc.) when building for -march=rv32imc_zicsr -mabi=ilp32.  The
dedicated riscv32-unknown-elf-gcc (riscv-collab riscv32-elf release,
installed to /opt/riscv by scripts/install_riscv.sh) ships the correct
native rv32/ilp32 libgcc — analogous to arm-none-eabi-gcc for Cortex-M.

The old filename is kept as a two-line compatibility alias that includes
the new file, so any out-of-tree users who hardcode the old path still work.

Also update:
- core_v_mcu/build.sh: reference new cmake filename
- core_v_mcu/README.md: update prerequisites table and toolchain docs

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-27 11:33:28 -04:00
Frédéric DesbiensandCopilot 223556219+Copilot@users.noreply.github.com 7486de06c8 Refactored, consolidated, and cleaned up RV32/RV64 ports (#536)
risc-v: refactor, consolidate, and fix RV32/RV64 ports

Consolidates the RISC-V 32-bit and 64-bit GNU/Clang port sources, fixes two
pre-existing assembly bugs discovered during testing, and hardens the build
infrastructure for both the regression suite and the CORE-V MCU example.

--- Port consolidation (RV32 GNU + Clang) ---

 - Delete ports/risc-v32/clang/src/ (8 .S files had no Clang-specific
 directives; diverged from GNU only due to missing bug fixes). The Clang
 port CMakeLists.txt now compiles from ../gnu/src/.
 - Change .global -> .weak for _tx_initialize_low_level in gnu/src/ to allow
 BSP-level override without a linker conflict (adopted from Clang port).
 - Create ports/risc-v32/common/tx_port_riscv32_common.h with all definitions
 shared between GNU and Clang ports. Reduce both tx_port.h files to thin
 wrappers.
 - Add a prominent comment in risc-v64/gnu/inc/tx_port.h explaining why
 LONG/ULONG are intentionally 32-bit on RV64 (ThreadX ABI requirement,
 mirrors win64/MSVC LLP64).

--- Shared CMake helper ---

 - Add cmake/threadx_riscv_port.cmake with threadx_add_riscv_port(). All
 three port CMakeLists.txt files are reduced to ~8 lines each. Include path
 is relative to CMAKE_CURRENT_LIST_DIR so the helper works whether ports
 are built standalone or as a subdirectory of the test framework.

--- Shared example-build drivers ---

 - Create canonical driver files under ports/risc-v_common/:
  inc/csr.h                  (uintptr_t-based; portable RV32 + RV64)
  example_build/plic/        (plic.c, plic.h)
  example_build/uart/        (uart_qemu_ns16550.c/h; static inline putc_nolock)
  example_build/trap/        (trap_qemu.c; XLEN-portable mcause constants)
 - Replace per-example copies with symlinks in all qemu_virt and cva6_ariane
 example directories.
 - Fix OS_IS_INTERRUPT typo (was OS_IS_INTERUPT) in shared trap_qemu.c.
 - Gate print_hex() behind TX_RISCV_TRAP_DEBUG.

--- Bug fixes in RV32 assembly ---

tx_thread_schedule.S:

 - Solicited-return FP path: reload t0 from the mepc stack slot before
 csrw mepc, t0. After the FP restore block, t0 held the fcsr value (0 for
 new threads), which caused mepc = 0 and an immediate instruction-address
 fault on the first context switch.
 - Same path: reload t0 from the mstatus stack slot before csrw mstatus, t0
 to avoid writing the stale fcsr value into mstatus.

tx_thread_system_return.S:

 - FP callee-saved registers were saved unconditionally before the mstatus.FS
 check, causing an illegal instruction trap (mcause=0x2) when a thread with
 FS=Off (lazy FPU, thread has never used FP) voluntarily yielded.
 - Apply the same FS guard pattern used in tx_thread_context_save.S: read
 mstatus first, isolate FS[1:0], and skip fsw/fsd if FS == Off.

Both bugs were pre-existing on origin/dev and are unrelated to the
consolidation changes.

--- RV64 64-bit pointer compatibility ---

 - Add TX_TIMER_INTERNAL_EXTENSION, TX_THREAD_CREATE_TIMEOUT_SETUP, and
 TX_THREAD_TIMEOUT_POINTER_SETUP to risc-v64/gnu/inc/tx_port.h to store the
 thread timeout pointer in a VOID
  * extension field rather than truncating it
 into a 32-bit ULONG. Mirrors the win64 port pattern.
 - Define TX_TIMER_EXTENSION_PTR_DEFINED as a portable sentinel.
 - Update threadx_thread_basic_execution_test.c guard from #if defined(_WIN64)
 to #if defined(_WIN64) || defined(TX_TIMER_EXTENSION_PTR_DEFINED).
 - Disable -Wconversion for the RV64 test build: ULONG = unsigned int (32-bit)
 is intentional for ThreadX ABI but triggers spurious warnings when sizeof()
 (8 bytes on RV64) appears in arithmetic with ULONG in common/src/.

--- Regression suite cmake fixes ---

test/tx/cmake/riscv/regression/CMakeLists.txt:

 - Build testcontrol_weak_defaults.c as a separate OBJECT library and include
 it in every test executable via $<TARGET_OBJECTS:>. GNU ld does not extract
 objects from a static archive to satisfy weak symbols, so bundling it in
 test_utility was insufficient for the standalone
 threadx_initialize_kernel_setup_test.

test/tx/cmake/regression/CMakeLists.txt,
test/smp/cmake/regression/CMakeLists.txt:

 - Same fix applied to the Linux and SMP regression builds. The symbols
 abort_all_threads_suspended_on_mutex, suspend_lowest_priority, and
 abort_and_resume_byte_allocating_thread were introduced by the win64 merge
 and left the standalone test unlinkable.

--- CORE-V MCU toolchain and build fixes ---

cmake/riscv64-gcc-rv32imc.cmake:

 - Resolve riscv64-unknown-elf-gcc via PATH so the riscv-collab toolchain in
 /opt/riscv/bin is preferred when it appears first.

ports/risc-v32/gnu/example_build/core_v_mcu/bsp/clz.c (new):

 - The riscv-collab toolchain is built without rv32 multilib, so its libgcc
 does not define __clzsi2 (the helper emitted for __builtin_clz() in fll.c).
 Add a weak __clzsi2 fallback so the build is self-contained with any
 riscv64-unknown-elf toolchain. The weak attribute yields to a
 libgcc-provided strong symbol when the Ubuntu multilib package is used.

core_v_mcu/CMakeLists.txt:

 - Add bsp/clz.c to sources.
 - Reference CMAKE_TOOLCHAIN_FILE via message(STATUS) to suppress the false-
 positive "Manually-specified variables were not used by the project" CMake
 warning and to show the active toolchain at configure time.

--- Housekeeping ---

 - Rename azrtos_test_* -> threadx_test_* (eliminate Azure RTOS branding).
 - Add RV64 QEMU CI test script:
  ports/risc-v64/gnu/example_build/qemu_virt/test/
  threadx_test_tx_gnu_riscv64_qemu.py
 - Normalize entry.s -> entry.S in all 4 example directories.
 - .gitignore: exclude build_m7/ and .codex local artifacts.
 - CI: comment out the riscv regression workflow job and remove it from the
 deploy job's needs list (preserved in-place for easy re-enablement).

--- Verified ---

 - 95/95 RV32 regression tests pass (QEMU virt)
 - 95/95 RV64 regression tests pass (QEMU virt)
 - All 5 Linux build configurations build cleanly (default_build_coverage,
 disable_notify_callbacks_build, stack_checking_build,
 stack_checking_rand_fill_build, trace_build)
 - CORE-V MCU example_build links cleanly with /opt/riscv toolchain

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com
2026-05-27 10:30:57 -04:00
Frédéric Desbiens 2c16114a45 Added win64 ports of ThreadX and ThreadX SMP (#529)
Windows x64 port and regression suite

 This PR adds the Windows x64 (Win64) simulation port for both the standalone
 and SMP variants of ThreadX, along with the full CMake build and test
 infrastructure needed to run the regression suite on Windows.


 New ports

 Win64 standalone (ports/win64/vs_2022): self-contained Windows simulation
 port using Win32 threading primitives as virtual cores. Includes CMake
 integration, build/test scripts, and MSVC project files.

 Win64 SMP (ports/win64_smp/vs_2022): multi-core Windows simulation port.
 Supports up to 4 virtual cores backed by Windows host threads.


 Scheduler and timer improvements

 The initial port used coarse polling and synchronous SuspendThread/ResumeThread
 pairs throughout the scheduler hot path. Several rounds of optimization reduced
 the SMP regression suite runtime from ~150 s to ~78 s (-48%), with no
 regressions:

 - Replaced scheduler polling with an event-driven wake path; switched the
   simulated timer to one-shot rearming to eliminate catch-up ticks.
 - Skip SuspendThread when _tx_thread_preempt_disable != 0 (new suspension
   type 3) -- the primary optimization, yielding up to 7.9x speedup on
   preemption-heavy tests.
 - Skip SuspendThread when a thread is spinning on the Win32 critical section
   (suspension type 4), and fix a stale-TLS bug in
   _tx_win32_critical_section_obtain that could stamp mutex_access on the
   wrong virtual core.
 - Added a 2 ms scheduler event timeout (matching the Linux SMP port) to
   prevent stalls on any missed SetEvent.
 - Enabled high-resolution waitable timers (SetWaitableTimerEx) for accurate
   100 Hz tick cadence.
 - Increased TX_WIN32_CONTENTION_PAUSE_COUNT from 64 to 256 to reduce
   SwitchToThread overhead under heavy CS contention.


 Build and test infrastructure

 - Hardened the Windows build wrapper (scripts/build_tx.ps1): invoke Ninja
   directly for Ninja build trees, fix timeout detection, add a default build
   timeout, and limit fallback replay to real timeout cases.
 - Added -Clean support to Windows test scripts to remove stale CTest state
   before each run.
 - Skip Visual Studio DevShell re-entry when the active MSVC environment
   already matches the requested architecture.
 - Fixed scripts/build_tx.sh (Linux) regression source generation: replaced
   brittle exact-string insertion with line-based matching so the interrupt
   dispatcher hook is inserted reliably for both simulator ports.


 Test suite updates

 - Introduced test/tx/regression/threadx_test_port.h with portable macros
   (TX_TEST_POINTER_WORD, TX_TEST_STORE_POINTER) for storing pointers in test
   arrays on 64-bit targets where ULONG remains 32-bit.
 - Adjusted pool-capacity and pointer-storage patterns in regression tests to
   use ALIGN_TYPE-sized slots, making the suite correct on 64-bit hosts.
 - Restored stricter event flag, sleep, and timer expectations now that
   port-level fixes make prior Windows accommodations unnecessary.
 - Tightened SMP watchdog and clean-build timeout defaults.


 Version metadata

 Updated Win32, Win64, and Win64 SMP port version strings to 6.5.1.202602.

 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
 Co-authored-by: Codex (gpt 5.5) <codex@openai.com>
2026-05-26 17:17:40 -04:00
Wei-Chen LaiWei-Chen Lai Winstonllllai@users.noreply.github.comFrédéric Desbiens frederic.desbiens@eclipse-foundation.orgCopilot 223556219+Copilot@users.noreply.github.com
e031a3d506 Implemented lazy FPU, GP relaxation, and QEMU automation for GNU port in arch/risc-v32 (#513)
This PR adds three functional improvements to the RISC-V 32-bit GNU port.

Lazy FPU stacking (tx_thread_context_save.S, tx_thread_context_restore.S, tx_thread_schedule.S): FP register save/restore is now skipped whenmstatus.FS is Off, reducing context switch overhead for threads that do not use floating point.

GP relaxation (cmake/riscv32_gnu.cmake, entry.s, link.lds): Enables the -mrelax compiler flag and defines __global_pointer$ in the linker script.The entry stub initializes gp at startup. gp is not saved or restored during context switches.

WFI in idle loop (tx_thread_schedule.S): The scheduler issues wfi when no thread is ready, replacing busy-waiting with a low-power sleep.

A Python/QEMU/GDB functional test runner is added under ports/risc-v32/gnu/example_build/qemu_virt/test/. It validates context switching, FPUcontext preservation, timer interrupts, and preemption. To run:

cd ports/risc-v32/gnu/example_build/qemu_virt
make check-functional-riscv32

Tested on QEMU virt machine (rv32gc).

Co-authored-by: Wei-Chen Lai Winstonllllai@users.noreply.github.com
Co-authored-by: Frédéric Desbiens frederic.desbiens@eclipse-foundation.org
Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com
2026-05-25 16:43:24 -04:00
Christos Papadopoulos 5b1b740a66 Reverted ULONG to be 4 bytes long, fixing missaligment issue in the current port (#534)
* Reverted RISCV-64 port

* Fixed wrong load/store instructions used
2026-05-25 16:12:33 -04:00