_tx_initialize_low_level wrote VTOR and derived _tx_thread_system_stack_ptr from
the reset vector on every Cortex-M port. Programming VTOR is the job of the
low-level startup code that runs before the kernel is entered, and doing it again
inside ThreadX silently overrode a vector table that the application, a
bootloader or a firmware update had already installed. It also forced every
application to export a vector table symbol that the kernel itself never needed.
_tx_thread_system_stack_ptr is never read by any Cortex-M port, so the value
copied out of the reset vector served no purpose.
Both blocks are removed from all Cortex-M ports, together with the now-unused
symbol declarations. The GreenHills files keep the NVIC base address load that
the removed block used to leave in r0 for the SysTick setup that follows.
Applications that relied on ThreadX programming VTOR must now set it in their
startup code. The bundled examples link their vector table at address zero and
run on the reset default.
Fixes#370
Assisted-by: Copilot (Opus 5) <noreply@github.com>
* Marked every published ThreadX include directory as SYSTEM so applications no longer get warnings from ThreadX headers
Commit 8c3c08f added the SYSTEM keyword to the target_include_directories
call in common/CMakeLists.txt, but the same call in every port, in the
SMP common directory's consumers, in the POSIX and FreeRTOS compatibility
layers, and for the generated tx_user.h directory was left unchanged.
A consumer building with a strict warning set therefore still saw
diagnostics coming from tx_port.h and from the compatibility layer
headers, which is exactly what the original change set out to avoid.
Added the SYSTEM keyword to all of those calls so CMake emits -isystem
rather than -I for every directory holding a ThreadX public header. The
ARMv7-M, ARMv8-M, ARMv7-A and ARMv8-A architecture sources under
ports_arch were updated alongside the ports they generate, keeping the
two in step.
Directories that are PRIVATE to an example or test build were left as
they are, since nothing is published from them.
Fixes#290
Assisted-by: Copilot (Opus 5) <noreply@github.com>
* Stopped apt-get update being a gate it was never meant to be
apt-get update fails if any configured repository serves a bad index,
including ones this project never reads. The GitHub runner image carries
Google's and Microsoft's apt repositories, and a Hash Sum mismatch from
Google's, their CDN caught mid-publish with the index and the Release
file eight hours apart, failed all three attempts and turned a run red
over a browser nobody was installing.
Made a failed update warn and carry on, leaving apt-get install as the
gate. Nothing is weakened by that: the install still exits on a package
it cannot find, so an unreachable archive still stops the script, one
step later and naming the package it could not get, which is a better
diagnostic than a hash mismatch in a repository nobody asked for.
Disabling third-party sources before updating would keep the update
strict, but this script also runs on a contributor's own machine, and
rewriting someone's apt configuration to suit CI would be worse than
tolerating a stale index for an archive we do not read.
Assisted-by: Copilot (Opus 5) <noreply@github.com>
The idle loop in _tx_thread_schedule masks interrupts before re-reading
_tx_thread_execute_ptr, so that an interrupt cannot make a thread ready
between that read and the WFI and then be lost. With PRIMASK that is safe:
the architecture excludes PRIMASK from the WFI wake-up condition, so the
interrupt still wakes the processor and is taken as soon as the loop
re-enables interrupts.
BASEPRI is not excluded. When TX_PORT_USE_BASEPRI is defined, the mask
written at the top of the loop is still in place at the WFI, so any
interrupt at or below TX_PORT_BASEPRI fails to wake the processor at all.
On a system where every interrupt is managed by ThreadX, that is every
interrupt, and the processor stays in WFI or in the low power mode entered
by tx_low_power_enter until something outside the mask happens.
Set PRIMASK and clear BASEPRI for the duration of the WFI, then restore
BASEPRI and clear PRIMASK. Interrupts remain masked across the whole
window, so the original race is still closed, but the wake-up condition is
now evaluated with BASEPRI clear and any enabled interrupt can end the wait.
A pending interrupt is taken at the CPSIE i, or at the existing unmask
further down the loop if it falls below TX_PORT_BASEPRI.
The change is made in the ARMv7-M and ARMv8-M sources under ports_arch,
including the module manager, and propagated to the generated ports with
the copy scripts. The ghs and keil ports do not implement
TX_PORT_USE_BASEPRI, and Cortex-M0/M0+/M23 have no BASEPRI register, so
those ports are unaffected.
Verified by assembling every patched GNU port for Cortex-M3, M4, M7, M33,
M55 and M85, with and without TX_PORT_USE_BASEPRI, TX_LOW_POWER and
TX_ENABLE_EXECUTION_CHANGE_NOTIFY, and by checking the disassembly of the
idle loop.
Fixes#279
Assisted-by: Copilot (Opus 5) <noreply@github.com>
The IAR multithreaded library support code allocates its file lock
mutexes from an array of _MAX_FLOCK entries, but the wrap-around check
and the exhaustion check in __iar_file_Mtxinit() both compared against
_MAX_LOCK, the bound of the unrelated system lock mutex array.
When _MAX_FLOCK is greater than _MAX_LOCK, the free mutex index wrapped
early and the exhaustion check reported failure while free entries
remained, so *m was set to TX_NULL and the application faulted the first
time a file lock was taken. When _MAX_FLOCK is smaller than _MAX_LOCK,
the free mutex index was allowed to run past the end of
__tx_iar_file_lock_mutexes and the exhaustion check could never fire.
Corrected all four comparisons in each of the 27 copies of tx_iar.c.
Fixes#444
Assisted-by: Copilot (Opus 5) <noreply@github.com>
The BASEPRI-masking path in tx_thread_schedule wrote "MOV r0, 0" rather
than "MOV r0, #0". UAL requires the "#" prefix on an immediate operand.
GNU as and the LLVM-based assemblers accept the unprefixed form and emit
the intended encoding, but stricter assemblers reject it outright, so the
affected ports could not be built with those toolchains.
The GNU and AC6 sources had already been corrected; this brings the IAR
and AC5 sources into line. Verified that both spellings assemble to the
same Thumb-2 encoding (f04f 0000), so this is a source-correctness fix
with no change in generated code or runtime behaviour.
Covers 31 occurrences across the Cortex-M3, M4, M7, M33, M52, M55 and M85
ports, their module manager counterparts, and the shared ARMv7-M and
ARMv8-M architecture sources.
Fixes#461
Assisted-by: Copilot (Opus 5) <noreply@github.com>
Every AArch64 gnu example build failed at the sample link, all 27 of them --
13 under ports/ and 14 under ports_smp/:
libg.a(libc_a-init.o): in function `__libc_init_array':
undefined reference to `_init'
relocation truncated to fit: R_AARCH64_CALL26 against undefined
symbol `_init'
libg.a(libc_a-fini.o): in function `__libc_fini_array':
undefined reference to `_fini'
build_threadx_sample.sh links with -nostartfiles, which is correct for a port
carrying its own reset path, and that drops crti.o and crtn.o along with
everything else. startup.S calls __libc_init_array by design, and newlib's
implementation calls _init, which crti.o is what defines. The AArch32 scripts
are unaffected: they use nosys.specs and never reach __libc_init_array.
The fix links crti.o and crtn.o explicitly, bracketing the object list -- the
first must precede every .init contribution and the second must follow all of
them, so their position is load-bearing rather than stylistic. Both paths come
from the compiler's own -print-file-name, so nothing here hard-codes a
toolchain layout.
The atfe branch sets both to empty, deliberately: picolibc's __libc_init_array
does not call _init, those 27 images link today, and adding crti.o would change
a working link for no reason. That is also why check_clang.sh is green on these
and does not list them as expected to fail -- the LLVM path never reached the
gap, so nothing has ever linked them and failed.
Fixed in ports_arch/ARMv8-A/threadx/ports/gnu/example_build, which is the
single source for both the ports/ and ports_smp/ copies, then regenerated with
update.sh --port-sets tx,tx_smp. The 27 generated copies are in this commit
because ports_arch_check compares them.
Verified: all 27 link with arm-gnu-toolchain 14.3.rel1 aarch64-none-elf, where
0 of 27 did before; _init and _fini disassemble to the expected crti prologue
and crtn epilogue over a ret; check_clang.sh with ATfE 22.1.0 is still green on
all five stages, including the 42 script-driven example builds; check_ports.sh
is green including the reproducibility check.
No regression test: these are link-only example images that no host test
executes. What guards them is check_clang.sh's example stage today, and
check_gcc.sh's, which is the next change and is the reason this was found.
Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
Every Armv8-M port readme ends with
09-30-2020 Initial ThreadX 6.1 version for Cortex-M85 using GNU tools.
with the core name substituted in by scripts/copy_armv8_m.sh. The date is the
shared port's, so each core inherits it whatever its own history: Cortex-M85 was
announced in 2022 and its readme claims a 2020 origin, and any core added later
gets the same treatment the moment its name joins the generator's list.
The rest of the history block is accurate, since it records changes to the shared
files. Only the closing line asserts something per-core. Reword it to describe
the Armv8-M port itself, and say where a given core's real starting point is.
Regenerating updates the twelve readmes for cortex_m33, cortex_m52, cortex_m55
and cortex_m85 across the three toolchains.
Cortex-M52 makes the point: it arrived in #519 and its readme immediately claimed
a 2020 origin for a core announced in 2023.
The ARMv7-M templates say "Initial ThreadX version 6.1.7 for Cortex-M", with no
placeholder to substitute, so they make no per-core claim and are left alone.
Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
The project guidelines ask for CMake and Ninja, but only 15 of the 59 gnu port
directories had a CMakeLists.txt. None of the 27 AArch64 ports had one, so the
architecture whose examples were repaired over the last few changes still could
not be built the way the project says to build it, and nothing in CI could
compile it.
Add a CMakeLists.txt to the 44 that lacked one. Three of them are templates in
ports_arch, because 34 of the 44 are generated: the ARMv7-A and AArch64 source
lists are uniform within each family, so one template per family serves every
core in it and update.sh distributes it. The other 10 ports have no generator
and get their own file.
Add the toolchain files those ports select, following the shape of
cmake/cortex_a9.cmake. AArch64 needs a base file of its own rather than a
variant of arm-none-eabi.cmake: it has no -marm or -mthumb to choose between and
no -mfloat-abi, and aarch64-none-elf-gcc rejects -mlong-calls outright, so that
flag cannot be carried across. The tools are named without a path, unlike
cmake/cortex_r52.cmake which pins one, because pinning 30 files to a single
machine's directory layout is the problem the previous change removed from the
launch configurations.
Three toolchain files cover ports that already had a CMakeLists.txt but no way
to select it: the Armv8-M mainline gnu ports, cortex_m33, cortex_m55 and
cortex_m85. Without cmake/<arch>.cmake the documented invocation cannot reach
them.
The top level needed one fix. It derives the SMP port directory as
<arch>_smp, but ports_smp/linux and ports_smp/win64 predate that convention and
carry no suffix, so those two could never be configured. Fall back to the bare
name when the suffixed directory is absent. The check only fires when the
suffixed directory does not exist, so no port that already resolved changes
behaviour, and ports_smp/win64's existing CMakeLists.txt becomes reachable too.
Verified by configuring and building every one: 53 of 53 static libraries build
with cmake -G Ninja, using Arm GNU Toolchain 14.3.Rel1 for both arm-none-eabi
and aarch64-none-elf. That covers the 44 new ports plus the 9 that already
worked, and includes ports_smp/linux, which failed before the fallback.
scripts/check_ports.sh passes, so the three templates and their 34 generated
copies agree.
Six gnu ports are still outside the CMake build, all for want of a compiler
rather than a CMakeLists.txt: rxv1, rxv2 and rxv3 need the Renesas RX GNU
toolchain and mips32_interaptiv_smp needs a MIPS one, neither of which is
available here, so writing toolchain files for them would mean shipping
untested guesses. risc-v32 and risc-v64 already build through their own
differently named toolchain files.
Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
* 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>
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>
* Unify ThreadX and SMP for ARMv8-A.
* Fix path in pipeline to check ports arch.
* Add ignore folders for ARM DS
* Generate ThreadX and SMP ports for ARMv8-A.
* Ignore untracked files for ports_arch check.
* Use arch instead of CPU to simplify the project management.