mirror of
https://github.com/eclipse-threadx/threadx.git
synced 2026-10-06 06:59:08 +08:00
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>
This commit is contained in:
@@ -27,3 +27,10 @@ CTestTestfile.cmake
|
||||
# Local build artifacts
|
||||
build_m7/
|
||||
.codex
|
||||
build_r52/
|
||||
__pycache__/
|
||||
*.pyc
|
||||
build_r52_vfp/
|
||||
build_r52_uart/
|
||||
build_r52_mpu/
|
||||
build_r52_all/
|
||||
|
||||
@@ -24,6 +24,13 @@ endif()
|
||||
|
||||
option(THREADX_SMP "Build ThreadX SMP version" OFF)
|
||||
|
||||
# Enable testing at the top level so that tests registered by ports and
|
||||
# example builds further down the tree are discoverable with ctest from the
|
||||
# build root. Without this, add_test() in a subdirectory still generates a
|
||||
# CTestTestfile.cmake there, but the root does not reference it and
|
||||
# "ctest --test-dir <build>" reports no tests at all.
|
||||
enable_testing()
|
||||
|
||||
if(THREADX_SMP)
|
||||
set(TX_PORT_DIR "ports_smp")
|
||||
set(TX_COMMON_DIR "common_smp")
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
# Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
# Some portions generated by Claude Code (Opus 5).
|
||||
#
|
||||
# Toolchain file for Arm Cortex-R52 (Armv8-R, AArch32) using GNU tools.
|
||||
|
||||
# Name of the target
|
||||
set(CMAKE_SYSTEM_NAME Generic)
|
||||
set(CMAKE_SYSTEM_PROCESSOR cortex-r52)
|
||||
|
||||
set(THREADX_ARCH "cortex_r52")
|
||||
set(THREADX_TOOLCHAIN "gnu")
|
||||
|
||||
# Floating-point ABI. Cortex-R52 always implements at least a single-precision
|
||||
# FPU -- GCC rejects "+nofp" for this core and offers only "+nofp.dp" (drop
|
||||
# double precision). There is therefore no FPU-less R52, so the soft-float
|
||||
# baseline selects the soft *ABI* rather than removing the FPU. The hard-float
|
||||
# variant with lazy VFP context save arrives with AR1 milestone M5.
|
||||
if(NOT DEFINED TX_R52_FLOAT_ABI)
|
||||
set(TX_R52_FLOAT_ABI "soft" CACHE STRING "R52 float ABI: soft | hard")
|
||||
endif()
|
||||
|
||||
set(MCPU_FLAGS "-marm -mcpu=cortex-r52")
|
||||
if(TX_R52_FLOAT_ABI STREQUAL "hard")
|
||||
set(VFP_FLAGS "-mfpu=fpv5-d16 -mfloat-abi=hard")
|
||||
else()
|
||||
set(VFP_FLAGS "-mfloat-abi=soft")
|
||||
endif()
|
||||
set(SPEC_FLAGS "--specs=nosys.specs")
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/arm-none-eabi.cmake)
|
||||
|
||||
# Pin the reference cross toolchain (see AGENTS.md, "Compiler"). Absolute paths
|
||||
# are used deliberately so the build does not depend on PATH ordering. Override
|
||||
# with -DARM_TOOLCHAIN_PATH=<dir containing arm-none-eabi-gcc> to build with a
|
||||
# different compiler -- for example the advisory newest-compiler lane.
|
||||
if(NOT DEFINED ARM_TOOLCHAIN_PATH)
|
||||
set(ARM_TOOLCHAIN_PATH
|
||||
"$ENV{HOME}/toolchains/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/bin")
|
||||
endif()
|
||||
if(EXISTS "${ARM_TOOLCHAIN_PATH}/arm-none-eabi-gcc")
|
||||
set(CMAKE_C_COMPILER "${ARM_TOOLCHAIN_PATH}/arm-none-eabi-gcc")
|
||||
set(CMAKE_CXX_COMPILER "${ARM_TOOLCHAIN_PATH}/arm-none-eabi-g++")
|
||||
set(CMAKE_ASM_COMPILER "${ARM_TOOLCHAIN_PATH}/arm-none-eabi-gcc")
|
||||
endif()
|
||||
@@ -0,0 +1,77 @@
|
||||
# Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
# Some portions generated by Claude Code (Opus 5).
|
||||
|
||||
target_sources(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
# {{BEGIN_TARGET_SOURCES}}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_restore.S
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_save.S
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_fiq_context_restore.S
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_fiq_context_save.S
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_fiq_nesting_end.S
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_fiq_nesting_start.S
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_control.S
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_disable.S
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_restore.S
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_irq_nesting_end.S
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_irq_nesting_start.S
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_schedule.S
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_stack_build.S
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_system_return.S
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_vectored_context_save.S
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_interrupt.S
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tx_port_offset_check.c
|
||||
# {{END_TARGET_SOURCES}}
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/inc
|
||||
)
|
||||
|
||||
# Lazy floating-point context save and restore. PUBLIC because the assembly
|
||||
# in the library and the application must agree: the flag changes which
|
||||
# registers the context switch saves, so a mismatched application would either
|
||||
# lose floating-point state or misread the thread control block. Requires a
|
||||
# floating-point ABI, so pair it with -DTX_R52_FLOAT_ABI=hard.
|
||||
option(TX_R52_ENABLE_VFP "Build with lazy VFP context save/restore" OFF)
|
||||
|
||||
# FIQ support and interrupt nesting. These change which registers the
|
||||
# assembly saves and what tx_port.h reports in TX_PORT_SPECIFIC_BUILD_OPTIONS,
|
||||
# so like the VFP flag they must be PUBLIC: library and application have to
|
||||
# agree. FIQ nesting additionally requires FIQ support.
|
||||
option(TX_R52_ENABLE_FIQ "Build with FIQ support" OFF)
|
||||
option(TX_R52_ENABLE_IRQ_NESTING "Build with nested IRQ support" OFF)
|
||||
option(TX_R52_ENABLE_FIQ_NESTING "Build with nested FIQ support" OFF)
|
||||
|
||||
if(TX_R52_ENABLE_FIQ)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC TX_ENABLE_FIQ_SUPPORT)
|
||||
endif()
|
||||
if(TX_R52_ENABLE_IRQ_NESTING)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC TX_ENABLE_IRQ_NESTING)
|
||||
endif()
|
||||
if(TX_R52_ENABLE_FIQ_NESTING)
|
||||
if(NOT TX_R52_ENABLE_FIQ)
|
||||
message(FATAL_ERROR
|
||||
"TX_R52_ENABLE_FIQ_NESTING requires TX_R52_ENABLE_FIQ: nested FIQ "
|
||||
"handling is meaningless without FIQ support compiled in.")
|
||||
endif()
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC TX_ENABLE_FIQ_NESTING)
|
||||
endif()
|
||||
if(TX_R52_ENABLE_VFP)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC TX_ENABLE_VFP_SUPPORT)
|
||||
if(NOT TX_R52_FLOAT_ABI STREQUAL "hard")
|
||||
message(WARNING
|
||||
"TX_R52_ENABLE_VFP is on but TX_R52_FLOAT_ABI is '${TX_R52_FLOAT_ABI}'. "
|
||||
"The compiler will not emit floating-point instructions, so the VFP "
|
||||
"context path will never be exercised. Use -DTX_R52_FLOAT_ABI=hard.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Armv8-R AEM FVP example builds (boot check now, kernel demo from AR1/M2).
|
||||
# Off by default so the default build stays a pure static-library build.
|
||||
option(TX_R52_BUILD_FVP_EXAMPLE "Build the Armv8-R AEM FVP example targets" OFF)
|
||||
if(TX_R52_BUILD_FVP_EXAMPLE)
|
||||
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/example_build/fvp_baser_aemv8r)
|
||||
endif()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,76 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License which is available at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*
|
||||
* AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
|
||||
* The AI-generated portions may be considered public domain (CC0-1.0)
|
||||
* and not subject to the project's licence. The human contributor has
|
||||
* reviewed and verified that the code is correct.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT and CC0-1.0
|
||||
**************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* BOARD SUPPORT RELEASE */
|
||||
/* */
|
||||
/* board.h Cortex-R52/GNU */
|
||||
/* 6.5.2 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Frédéric Desbiens, Eclipse Foundation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* Declarations for the objects that cross the C/assembly boundary in */
|
||||
/* this board support package. */
|
||||
/* */
|
||||
/* These exist because assembly callers do not provide prototypes: */
|
||||
/* entry.S calls bsp_main, _tx_initialize_low_level calls board_init, */
|
||||
/* and __tx_irq_processing_return calls board_irq_handler. Without a */
|
||||
/* header the definitions have external linkage and no visible */
|
||||
/* declaration, which MISRA C:2012 Rule 8.4 prohibits and which */
|
||||
/* -Wmissing-prototypes reports. Declaring them in one place also */
|
||||
/* means a signature change cannot silently disagree with the assembly.*/
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef BOARD_H
|
||||
#define BOARD_H
|
||||
|
||||
/* Application entry, called from entry.S after EL1 setup; never returns. */
|
||||
|
||||
void bsp_main(void);
|
||||
|
||||
/* Interrupt controller and periodic tick bring-up, called from
|
||||
_tx_initialize_low_level while interrupts are still masked. */
|
||||
|
||||
void board_init(void);
|
||||
|
||||
/* Interrupt dispatch, called from __tx_irq_processing_return in entry.S
|
||||
after the interrupted context has been saved. */
|
||||
|
||||
void board_irq_handler(void);
|
||||
|
||||
/* Interrupt observability, maintained by board_irq_handler. */
|
||||
|
||||
extern volatile unsigned long board_irq_count;
|
||||
extern volatile unsigned long board_timer_intid;
|
||||
extern volatile unsigned long board_spurious_count;
|
||||
extern volatile unsigned long board_unexpected_intid;
|
||||
|
||||
/* Counted by the EL2 hyp-trap handler in entry.S; the ZoneX seam. */
|
||||
|
||||
extern volatile unsigned long _hvc_call_count;
|
||||
|
||||
/* Recoverable data-abort support for the MPU enforcement self-test, handled
|
||||
in entry.S. Setting mpu_expect_abort makes the next data abort resume at
|
||||
the instruction following the faulting one instead of halting. */
|
||||
|
||||
extern volatile unsigned long mpu_expect_abort;
|
||||
extern volatile unsigned long mpu_abort_count;
|
||||
|
||||
#endif /* BOARD_H */
|
||||
@@ -0,0 +1,170 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License which is available at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*
|
||||
* AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
|
||||
* The AI-generated portions may be considered public domain (CC0-1.0)
|
||||
* and not subject to the project's licence. The human contributor has
|
||||
* reviewed and verified that the code is correct.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT and CC0-1.0
|
||||
**************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* BOARD SUPPORT RELEASE */
|
||||
/* */
|
||||
/* bsp_boot.c Cortex-R52/GNU */
|
||||
/* 6.5.2 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Frédéric Desbiens, Eclipse Foundation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* AR1 milestone M1 boot check. Verifies that the reset path really */
|
||||
/* configured EL2 and then dropped to EL1, and that the EL2 HVC seam */
|
||||
/* used by ZoneX (AR3) is reachable from EL1 and returns correctly. */
|
||||
/* */
|
||||
/* This deliberately asserts the resulting exception level rather than */
|
||||
/* merely printing a message: "it printed something" does not prove a */
|
||||
/* correct EL2-to-EL1 transition, and AR3 depends on that transition. */
|
||||
/* */
|
||||
/* MISRA C:2012 deviations (justified) */
|
||||
/* */
|
||||
/* Directive 4.3 -- the two asm statements below read CPSR and issue */
|
||||
/* HVC; neither has a standard C equivalent. Both are encapsulated */
|
||||
/* in dedicated one-line functions. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "board.h"
|
||||
#include "console.h"
|
||||
|
||||
/* AArch32 CPSR mode field encodings. */
|
||||
|
||||
#define CPSR_MODE_MASK 0x1FUL
|
||||
#define CPSR_MODE_SVC 0x13UL /* Supervisor -- an EL1 mode */
|
||||
#define CPSR_MODE_HYP 0x1AUL /* Hyp -- EL2 */
|
||||
|
||||
/* Incremented by the EL2 HVC handler in entry.S. */
|
||||
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* read_cpsr -- current program status, including the mode field. */
|
||||
/**************************************************************************/
|
||||
|
||||
static unsigned long read_cpsr(void)
|
||||
{
|
||||
unsigned long value;
|
||||
|
||||
__asm__ volatile("mrs %0, cpsr" : "=r"(value));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* issue_hvc -- call into EL2 through the ZoneX seam and return. */
|
||||
/**************************************************************************/
|
||||
|
||||
static void issue_hvc(void)
|
||||
{
|
||||
__asm__ volatile("hvc #0" : : : "memory");
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* report -- print one labelled check result. */
|
||||
/**************************************************************************/
|
||||
|
||||
static void report(const char *label_ptr, unsigned int passed)
|
||||
{
|
||||
console_puts(label_ptr);
|
||||
console_puts(passed != 0U ? "PASS\n" : "FAIL\n");
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* bsp_main -- entered at EL1 from entry.S. Does not return. */
|
||||
/**************************************************************************/
|
||||
|
||||
void bsp_main(void)
|
||||
{
|
||||
unsigned long cpsr;
|
||||
unsigned long mode;
|
||||
unsigned long hvc_before;
|
||||
unsigned long hvc_after;
|
||||
unsigned int failures = 0U;
|
||||
|
||||
console_puts("\n=== ThreadX AR1/M1 boot check "
|
||||
"(Cortex-R52, Armv8-R AArch32, Armv8-R AEM FVP) ===\n");
|
||||
|
||||
/* Check 1: we are executing at EL1, not still at EL2. */
|
||||
|
||||
cpsr = read_cpsr();
|
||||
mode = cpsr & CPSR_MODE_MASK;
|
||||
|
||||
console_puts("[EL1] CPSR = ");
|
||||
console_puthex(cpsr);
|
||||
console_puts("\n[EL1] CPSR.M = ");
|
||||
console_puthex(mode);
|
||||
console_puts("\n");
|
||||
|
||||
if (mode == CPSR_MODE_SVC)
|
||||
{
|
||||
report("[EL1] running in Supervisor mode (EL1) ", 1U);
|
||||
}
|
||||
else
|
||||
{
|
||||
failures++;
|
||||
if (mode == CPSR_MODE_HYP)
|
||||
{
|
||||
console_puts("[EL1] still in Hyp mode -- ERET to EL1 did not happen FAIL\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
report("[EL1] unexpected CPSR mode ", 0U);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check 2: the EL2 HVC seam is reachable from EL1 and returns. This is
|
||||
what AR3 (ZoneX Phase-0) builds on, so it is verified from AR1. */
|
||||
|
||||
hvc_before = _hvc_call_count;
|
||||
issue_hvc();
|
||||
hvc_after = _hvc_call_count;
|
||||
|
||||
console_puts("[EL1] HVC count before/after = ");
|
||||
console_puthex(hvc_before);
|
||||
console_puts(" / ");
|
||||
console_puthex(hvc_after);
|
||||
console_puts("\n");
|
||||
|
||||
if (hvc_after == (hvc_before + 1UL))
|
||||
{
|
||||
report("[EL1] EL2 HVC seam reachable and returns to EL1 ", 1U);
|
||||
}
|
||||
else
|
||||
{
|
||||
failures++;
|
||||
report("[EL1] EL2 HVC seam did not take effect ", 0U);
|
||||
}
|
||||
|
||||
/* Summary. The exact strings are what the automated runner greps for. */
|
||||
|
||||
if (failures == 0U)
|
||||
{
|
||||
console_puts("\nM1 RESULT: ALL CHECKS PASSED\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
console_puts("\nM1 RESULT: FAILED\n");
|
||||
}
|
||||
|
||||
console_exit(failures);
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License which is available at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*
|
||||
* AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
|
||||
* The AI-generated portions may be considered public domain (CC0-1.0)
|
||||
* and not subject to the project's licence. The human contributor has
|
||||
* reviewed and verified that the code is correct.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT and CC0-1.0
|
||||
**************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* BOARD SUPPORT RELEASE */
|
||||
/* */
|
||||
/* console.c Cortex-R52/GNU */
|
||||
/* 6.5.2 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Frédéric Desbiens, Eclipse Foundation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* Semihosting console for the Armv8-R AEM FVP. Armv8 AArch32 uses */
|
||||
/* HLT 0xF000 as the semihosting trap; the model implements it with no */
|
||||
/* peripheral configuration, which keeps early bring-up independent of */
|
||||
/* the platform memory map. */
|
||||
/* */
|
||||
/* MISRA C:2012 deviations (justified) */
|
||||
/* */
|
||||
/* Directive 4.3 (assembly language shall be encapsulated and isolated)*/
|
||||
/* -- observed rather than violated: the single asm statement lives */
|
||||
/* in semihost_call() and nowhere else in the port. */
|
||||
/* Rule 1.1 / 1.2 (language extensions) */
|
||||
/* -- register-asm bindings and inline assembly are unavoidable to */
|
||||
/* invoke a semihosting trap; no standard C construct expresses it. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "console.h"
|
||||
|
||||
#ifdef TX_R52_CONSOLE_PL011
|
||||
#include "uart_pl011.h"
|
||||
#endif
|
||||
|
||||
/* Semihosting operation numbers (Arm semihosting specification). */
|
||||
|
||||
#define SYS_WRITE0 0x04U
|
||||
#define SYS_EXIT 0x18U
|
||||
|
||||
/* SYS_EXIT reason codes. On AArch32 the parameter is a reason, not an exit
|
||||
status, so a failing run is reported by its printed result line. */
|
||||
|
||||
#define ADP_STOPPED_APPLICATION_EXIT 0x20026U
|
||||
#define ADP_STOPPED_RUN_TIME_ERROR 0x20023U
|
||||
|
||||
/* Number of hexadecimal digits in a 32-bit value. */
|
||||
|
||||
#define HEX_DIGITS 8U
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* semihost_call */
|
||||
/* */
|
||||
/* Issues a single semihosting operation. This is the only assembly in */
|
||||
/* the console driver (MISRA C:2012 Dir 4.3). */
|
||||
/**************************************************************************/
|
||||
|
||||
static int semihost_call(int operation, const void *argument_ptr)
|
||||
{
|
||||
register int result __asm__("r0") = operation;
|
||||
register const void *argument __asm__("r1") = argument_ptr;
|
||||
|
||||
__asm__ volatile("hlt 0xf000"
|
||||
: "+r"(result)
|
||||
: "r"(argument)
|
||||
: "memory");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* console_puts */
|
||||
/**************************************************************************/
|
||||
|
||||
void console_puts(const char *string_ptr)
|
||||
{
|
||||
if (string_ptr == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TX_R52_CONSOLE_PL011
|
||||
|
||||
/* Initialise on first use rather than from board_init, so that images
|
||||
with no ThreadX initialisation path (the M1 boot check) also get a
|
||||
working UART console. */
|
||||
|
||||
static unsigned int initialised = 0U;
|
||||
|
||||
if (initialised == 0U)
|
||||
{
|
||||
pl011_init();
|
||||
initialised = 1U;
|
||||
}
|
||||
|
||||
pl011_puts(string_ptr);
|
||||
|
||||
#else
|
||||
|
||||
(void) semihost_call((int) SYS_WRITE0, string_ptr);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* console_puthex */
|
||||
/**************************************************************************/
|
||||
|
||||
void console_puthex(unsigned long value)
|
||||
{
|
||||
static const char digits[] = "0123456789abcdef";
|
||||
char buffer[3U + HEX_DIGITS]; /* "0x" + digits + NUL */
|
||||
unsigned int index;
|
||||
|
||||
buffer[0] = '0';
|
||||
buffer[1] = 'x';
|
||||
|
||||
for (index = 0U; index < HEX_DIGITS; index++)
|
||||
{
|
||||
unsigned int shift = (HEX_DIGITS - 1U - index) * 4U;
|
||||
|
||||
buffer[2U + index] = digits[(value >> shift) & 0xFUL];
|
||||
}
|
||||
|
||||
buffer[2U + HEX_DIGITS] = '\0';
|
||||
|
||||
console_puts(buffer);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* console_exit */
|
||||
/**************************************************************************/
|
||||
|
||||
/* Note this always uses semihosting, even with the PL011 console selected:
|
||||
SYS_EXIT is how the model is told to stop, which is a debug-channel
|
||||
operation rather than console output. */
|
||||
|
||||
void console_exit(unsigned int status)
|
||||
{
|
||||
unsigned int reason = (status == 0U) ? ADP_STOPPED_APPLICATION_EXIT
|
||||
: ADP_STOPPED_RUN_TIME_ERROR;
|
||||
|
||||
(void) semihost_call((int) SYS_EXIT, (const void *) reason);
|
||||
|
||||
/* The model terminates on the call above; loop defensively in case a
|
||||
host or debug configuration ignores semihosting exit. */
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/* Intentionally empty. */
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License which is available at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*
|
||||
* AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
|
||||
* The AI-generated portions may be considered public domain (CC0-1.0)
|
||||
* and not subject to the project's licence. The human contributor has
|
||||
* reviewed and verified that the code is correct.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT and CC0-1.0
|
||||
**************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* BOARD SUPPORT RELEASE */
|
||||
/* */
|
||||
/* console.h Cortex-R52/GNU */
|
||||
/* 6.5.2 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Frédéric Desbiens, Eclipse Foundation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* Minimal console for the Armv8-R AEM FVP. Backed by semihosting so */
|
||||
/* that early bring-up needs no peripheral base addresses; the PL011 */
|
||||
/* UART implementation arrives in AR1/M3 behind this same interface. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CONSOLE_H
|
||||
#define CONSOLE_H
|
||||
|
||||
/* Write a NUL-terminated string to the console. */
|
||||
|
||||
void console_puts(const char *string_ptr);
|
||||
|
||||
/* Write value as 0x-prefixed, zero-padded 32-bit hexadecimal. */
|
||||
|
||||
void console_puthex(unsigned long value);
|
||||
|
||||
/* Terminate the simulation (semihosting SYS_EXIT). Does not return.
|
||||
Pass/fail is reported through the printed result line rather than a host
|
||||
exit status, because the AArch32 SYS_EXIT reason code is not a status. */
|
||||
|
||||
void console_exit(unsigned int status);
|
||||
|
||||
#endif /* CONSOLE_H */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,186 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License which is available at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*
|
||||
* AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
|
||||
* The AI-generated portions may be considered public domain (CC0-1.0)
|
||||
* and not subject to the project's licence. The human contributor has
|
||||
* reviewed and verified that the code is correct.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT and CC0-1.0
|
||||
**************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* DEMONSTRATION RELEASE */
|
||||
/* */
|
||||
/* demo_verify.c Cortex-R52/GNU */
|
||||
/* 6.5.2 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Frédéric Desbiens, Eclipse Foundation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* AR1 milestone M4: verifies that the standard eight-thread ThreadX */
|
||||
/* demo makes progress on Cortex-R52, then terminates the simulation */
|
||||
/* so the run can be automated. */
|
||||
/* */
|
||||
/* Where M3 proved the tick and a single preemption, this exercises */
|
||||
/* the demo's full object set -- queue, semaphore, mutex, event flags, */
|
||||
/* byte pool and block pool -- across eight threads at five priorities.*/
|
||||
/* Each of the ten demo counters is required to have advanced: a */
|
||||
/* stalled thread (a lost wakeup, a mishandled priority inversion) */
|
||||
/* shows up as a counter still at zero rather than as a plausible- */
|
||||
/* looking run. */
|
||||
/* */
|
||||
/* The verification thread runs at priority 0 so it can always preempt */
|
||||
/* the demo, and spends nearly all its life suspended. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "board.h"
|
||||
#include "console.h"
|
||||
#include "demo_verify.h"
|
||||
|
||||
#define VERIFY_STACK_SIZE 2048
|
||||
|
||||
/* Ticks to let the demo run before checking. thread_0 sleeps 10 ticks per
|
||||
iteration and thread_5 waits on the event flag it sets, so these two are
|
||||
the slowest; 300 ticks (3 s at 100 Hz) gives them ~30 iterations each. */
|
||||
|
||||
#define VERIFY_SETTLE_TICKS 300UL
|
||||
|
||||
/* Counters defined by the standard demo. */
|
||||
|
||||
extern ULONG thread_0_counter;
|
||||
extern ULONG thread_1_counter;
|
||||
extern ULONG thread_1_messages_sent;
|
||||
extern ULONG thread_2_counter;
|
||||
extern ULONG thread_2_messages_received;
|
||||
extern ULONG thread_3_counter;
|
||||
extern ULONG thread_4_counter;
|
||||
extern ULONG thread_5_counter;
|
||||
extern ULONG thread_6_counter;
|
||||
extern ULONG thread_7_counter;
|
||||
|
||||
static TX_THREAD verify_thread;
|
||||
static ULONG verify_stack[VERIFY_STACK_SIZE / sizeof(ULONG)];
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* check_counter -- report one counter and whether it advanced. */
|
||||
/**************************************************************************/
|
||||
|
||||
static UINT check_counter(const char *label_ptr, ULONG value)
|
||||
{
|
||||
console_puts(label_ptr);
|
||||
console_puthex(value);
|
||||
console_puts((value > 0UL) ? " PASS\n" : " FAIL\n");
|
||||
|
||||
return (value > 0UL) ? 0U : 1U;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* verify_thread_entry */
|
||||
/**************************************************************************/
|
||||
|
||||
static void verify_thread_entry(ULONG thread_input)
|
||||
{
|
||||
UINT failures = 0U;
|
||||
ULONG elapsed;
|
||||
|
||||
(void) thread_input;
|
||||
|
||||
console_puts("[verify] letting the standard demo run for ");
|
||||
console_puthex(VERIFY_SETTLE_TICKS);
|
||||
console_puts(" ticks...\n");
|
||||
|
||||
tx_thread_sleep(VERIFY_SETTLE_TICKS);
|
||||
|
||||
elapsed = tx_time_get();
|
||||
|
||||
console_puts("\n[verify] demo counters after settling:\n");
|
||||
|
||||
failures += check_counter(" thread 0 counter = ", thread_0_counter);
|
||||
failures += check_counter(" thread 1 counter = ", thread_1_counter);
|
||||
failures += check_counter(" thread 1 messages sent = ", thread_1_messages_sent);
|
||||
failures += check_counter(" thread 2 counter = ", thread_2_counter);
|
||||
failures += check_counter(" thread 2 messages received = ", thread_2_messages_received);
|
||||
failures += check_counter(" thread 3 counter = ", thread_3_counter);
|
||||
failures += check_counter(" thread 4 counter = ", thread_4_counter);
|
||||
failures += check_counter(" thread 5 counter = ", thread_5_counter);
|
||||
failures += check_counter(" thread 6 counter = ", thread_6_counter);
|
||||
failures += check_counter(" thread 7 counter = ", thread_7_counter);
|
||||
|
||||
/* The queue must not have silently dropped or duplicated messages. */
|
||||
|
||||
console_puts("\n[verify] queue balance (sent >= received) ");
|
||||
if (thread_1_messages_sent >= thread_2_messages_received)
|
||||
{
|
||||
console_puts("PASS\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
failures++;
|
||||
console_puts("FAIL\n");
|
||||
}
|
||||
|
||||
console_puts("[verify] elapsed ticks = ");
|
||||
console_puthex(elapsed);
|
||||
console_puts("\n[verify] tick advanced past the settle period ");
|
||||
if (elapsed >= VERIFY_SETTLE_TICKS)
|
||||
{
|
||||
console_puts("PASS\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
failures++;
|
||||
console_puts("FAIL\n");
|
||||
}
|
||||
|
||||
if (failures == 0U)
|
||||
{
|
||||
console_puts("\nM4 RESULT: ALL CHECKS PASSED\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
console_puts("\nM4 RESULT: FAILED\n");
|
||||
}
|
||||
|
||||
console_exit(failures);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* demo_verify_create */
|
||||
/**************************************************************************/
|
||||
|
||||
void demo_verify_create(void)
|
||||
{
|
||||
/* Priority 0 and its own static stack: the verification thread must be
|
||||
able to preempt every demo thread, and must not perturb the demo's
|
||||
byte-pool allocations. */
|
||||
|
||||
(void) tx_thread_create(&verify_thread, "verify", verify_thread_entry, 0UL,
|
||||
verify_stack, sizeof(verify_stack),
|
||||
0U, 0U, TX_NO_TIME_SLICE, TX_AUTO_START);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* bsp_main -- entered at EL1 from entry.S. Does not return. */
|
||||
/**************************************************************************/
|
||||
|
||||
void bsp_main(void)
|
||||
{
|
||||
console_puts("\n=== ThreadX AR1/M4 standard eight-thread demo "
|
||||
"(Cortex-R52, Armv8-R AArch32, Armv8-R AEM FVP) ===\n");
|
||||
|
||||
tx_kernel_enter();
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License which is available at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*
|
||||
* AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
|
||||
* The AI-generated portions may be considered public domain (CC0-1.0)
|
||||
* and not subject to the project's licence. The human contributor has
|
||||
* reviewed and verified that the code is correct.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT and CC0-1.0
|
||||
**************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* DEMONSTRATION RELEASE */
|
||||
/* */
|
||||
/* demo_verify.h Cortex-R52/GNU */
|
||||
/* 6.5.2 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Frédéric Desbiens, Eclipse Foundation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* Verification harness for the standard ThreadX demo, kept separate */
|
||||
/* so demo_threadx.c stays byte-identical to the shipped sample apart */
|
||||
/* from its header note and a single call to demo_verify_create(). */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DEMO_VERIFY_H
|
||||
#define DEMO_VERIFY_H
|
||||
|
||||
/* Create the verification thread. Called from tx_application_define. */
|
||||
|
||||
void demo_verify_create(void);
|
||||
|
||||
#endif /* DEMO_VERIFY_H */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,61 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License which is available at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*
|
||||
* AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
|
||||
* The AI-generated portions may be considered public domain (CC0-1.0)
|
||||
* and not subject to the project's licence. The human contributor has
|
||||
* reviewed and verified that the code is correct.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT and CC0-1.0
|
||||
**************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* BOARD SUPPORT RELEASE */
|
||||
/* */
|
||||
/* gicv3.h Cortex-R52/GNU */
|
||||
/* 6.5.2 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Frédéric Desbiens, Eclipse Foundation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* GICv3 interrupt controller for Cortex-R52. The CPU interface is */
|
||||
/* reached through AArch32 ICC_* system registers; the Distributor and */
|
||||
/* Redistributor are memory mapped. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GICV3_H
|
||||
#define GICV3_H
|
||||
|
||||
/* Spurious interrupt ID returned by the CPU interface when no interrupt is
|
||||
pending. It must be neither dispatched nor acknowledged with EOI. */
|
||||
|
||||
#define GICV3_SPURIOUS_INTID 1023UL
|
||||
|
||||
/* Bring up the Distributor, this core's Redistributor and the CPU
|
||||
interface. Interrupts remain masked at the PSTATE level. */
|
||||
|
||||
void gicv3_init(void);
|
||||
|
||||
/* Enable one private peripheral interrupt (PPI, INTID 16-31) as a
|
||||
level-sensitive Group 1 interrupt at the given priority. */
|
||||
|
||||
void gicv3_enable_ppi(unsigned int intid, unsigned int priority);
|
||||
|
||||
/* Acknowledge the highest-priority pending Group 1 interrupt, returning its
|
||||
INTID (possibly GICV3_SPURIOUS_INTID). */
|
||||
|
||||
unsigned long gicv3_acknowledge(void);
|
||||
|
||||
/* Signal completion of the interrupt previously acknowledged. */
|
||||
|
||||
void gicv3_end_of_interrupt(unsigned long intid);
|
||||
|
||||
#endif /* GICV3_H */
|
||||
@@ -0,0 +1,113 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License which is available at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*
|
||||
* AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
|
||||
* The AI-generated portions may be considered public domain (CC0-1.0)
|
||||
* and not subject to the project's licence. The human contributor has
|
||||
* reviewed and verified that the code is correct.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT and CC0-1.0
|
||||
**************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* BOARD SUPPORT RELEASE */
|
||||
/* */
|
||||
/* irq_dispatch.c Cortex-R52/GNU */
|
||||
/* 6.5.2 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Frédéric Desbiens, Eclipse Foundation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* Interrupt dispatch for Cortex-R52 on the Armv8-R AEM FVP. Called */
|
||||
/* from __tx_irq_processing_return in entry.S, that is after */
|
||||
/* _tx_thread_context_save has saved the interrupted context and with */
|
||||
/* interrupts still disabled. */
|
||||
/* */
|
||||
/* _tx_timer_interrupt is safe to call from C: it uses only r0-r3 and */
|
||||
/* returns through lr like an ordinary function. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "board.h"
|
||||
#include "gicv3.h"
|
||||
#include "timer.h"
|
||||
|
||||
/* ThreadX periodic timer entry point (assembly, AAPCS-compatible). */
|
||||
|
||||
extern void _tx_timer_interrupt(void);
|
||||
|
||||
/* Observability for the M3 checks. board_timer_intid records the INTID that
|
||||
actually arrived -- this is how the timer PPI was identified during bring-up
|
||||
(see TIMER_PPI_INTID) and it keeps reporting it, so a platform that assigns
|
||||
the timer elsewhere shows up as an unexpected INTID rather than a silent
|
||||
absence of ticks. */
|
||||
|
||||
volatile unsigned long board_irq_count;
|
||||
volatile unsigned long board_timer_intid;
|
||||
volatile unsigned long board_spurious_count;
|
||||
volatile unsigned long board_unexpected_intid;
|
||||
|
||||
|
||||
/* Timer PPI priority. Only the top 5 priority bits are implemented on this
|
||||
model, so the value is a multiple of 8. */
|
||||
|
||||
#define TIMER_PPI_PRIORITY 0xA0U
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* board_init */
|
||||
/* */
|
||||
/* Called from _tx_initialize_low_level. Interrupts are still masked at */
|
||||
/* this point, so the tick cannot be delivered before the kernel is */
|
||||
/* ready for it. */
|
||||
/**************************************************************************/
|
||||
|
||||
void board_init(void)
|
||||
{
|
||||
gicv3_init();
|
||||
gicv3_enable_ppi(TIMER_PPI_INTID, TIMER_PPI_PRIORITY);
|
||||
timer_init();
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* board_irq_handler */
|
||||
/**************************************************************************/
|
||||
|
||||
void board_irq_handler(void)
|
||||
{
|
||||
unsigned long intid = gicv3_acknowledge();
|
||||
|
||||
if (intid == GICV3_SPURIOUS_INTID)
|
||||
{
|
||||
/* No interrupt was actually pending; must not be acknowledged. */
|
||||
|
||||
board_spurious_count++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (intid == (unsigned long) TIMER_PPI_INTID)
|
||||
{
|
||||
board_timer_intid = intid;
|
||||
board_irq_count++;
|
||||
|
||||
/* Re-arm before servicing so the next interval starts immediately;
|
||||
this also deasserts the level-sensitive timer output. */
|
||||
|
||||
timer_reload();
|
||||
_tx_timer_interrupt();
|
||||
}
|
||||
else
|
||||
{
|
||||
board_unexpected_intid = intid;
|
||||
}
|
||||
|
||||
gicv3_end_of_interrupt(intid);
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License which is available at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*
|
||||
* AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
|
||||
* The AI-generated portions may be considered public domain (CC0-1.0)
|
||||
* and not subject to the project's licence. The human contributor has
|
||||
* reviewed and verified that the code is correct.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT and CC0-1.0
|
||||
**************************************************************************/
|
||||
|
||||
/* Linker script for Cortex-R52 on the Armv8-R AEM FVP (BaseR platform).
|
||||
*
|
||||
* The BaseR memory map is the Base platform map with its two 2 GB halves
|
||||
* swapped: Base DRAM at 0x80000000 appears at 0x00000000 here, and the
|
||||
* 0x80000000-0xFFFFFFFF half holds peripherals and is NOT executable by
|
||||
* default. Code must therefore be linked into low DRAM -- linking at
|
||||
* 0x80000000 produces a silent fault loop with no output.
|
||||
*/
|
||||
|
||||
ENTRY(_start)
|
||||
|
||||
__hyp_stack_size__ = 0x0800;
|
||||
__svc_stack_size__ = 0x1000;
|
||||
__irq_stack_size__ = 0x0800;
|
||||
__fiq_stack_size__ = 0x0400;
|
||||
__abt_stack_size__ = 0x0400;
|
||||
__und_stack_size__ = 0x0400;
|
||||
__sys_stack_size__ = 0x0800;
|
||||
|
||||
MEMORY
|
||||
{
|
||||
DRAM (rwx) : ORIGIN = 0x00000000, LENGTH = 0x08000000 /* 128 MB */
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* PMSAv8-R regions have a 64-byte granule and their limits are inclusive,
|
||||
so the code and data areas are separated on a 64-byte boundary. Without
|
||||
this a single region would have to span both, forcing writable code or
|
||||
executable data. */
|
||||
|
||||
. = ALIGN(64);
|
||||
__code_start__ = .;
|
||||
|
||||
.text :
|
||||
{
|
||||
KEEP(*(.vectors_el2))
|
||||
KEEP(*(.vectors_el1))
|
||||
*(.text*)
|
||||
*(.glue_7)
|
||||
*(.glue_7t)
|
||||
} > DRAM
|
||||
|
||||
.rodata :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.rodata*)
|
||||
. = ALIGN(4);
|
||||
} > DRAM
|
||||
|
||||
/* Start the writable area on a protection-region granule.
|
||||
*
|
||||
* The alignment belongs on the output section itself. Two things that
|
||||
* look equivalent do not work: an assignment such as ". = ALIGN(64);"
|
||||
* between sections does not advance a MEMORY region's allocation
|
||||
* pointer, and ". = ALIGN(64);" at the end of .rodata does not extend
|
||||
* that section when no data follows it. In both cases .data keeps its
|
||||
* unaligned address while __data_start__ reports the aligned one, so the
|
||||
* first bytes of .data fall inside the read-only code region. The MPU
|
||||
* caught precisely that: writes to the two variables at the start of
|
||||
* .data faulted, and since one of them is the flag the abort handler
|
||||
* consults, the fault turned itself fatal.
|
||||
*/
|
||||
|
||||
.data ALIGN(64) :
|
||||
{
|
||||
__code_end__ = .; /* code region ends where writable data begins */
|
||||
__data_start__ = .;
|
||||
*(.data*)
|
||||
. = ALIGN(4);
|
||||
} > DRAM
|
||||
|
||||
.bss (NOLOAD) :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__bss_start__ = .;
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
__bss_end__ = .;
|
||||
} > DRAM
|
||||
|
||||
/* One stack per AArch32 processor mode. SP must stay 8-byte aligned
|
||||
(AAPCS), so each region is aligned before its top symbol is taken. */
|
||||
|
||||
.stacks (NOLOAD) :
|
||||
{
|
||||
. = ALIGN(8);
|
||||
. = . + __hyp_stack_size__;
|
||||
__hyp_stack_top = .;
|
||||
|
||||
. = ALIGN(8);
|
||||
. = . + __svc_stack_size__;
|
||||
__svc_stack_top = .;
|
||||
|
||||
. = ALIGN(8);
|
||||
. = . + __irq_stack_size__;
|
||||
__irq_stack_top = .;
|
||||
|
||||
. = ALIGN(8);
|
||||
. = . + __fiq_stack_size__;
|
||||
__fiq_stack_top = .;
|
||||
|
||||
. = ALIGN(8);
|
||||
. = . + __abt_stack_size__;
|
||||
__abt_stack_top = .;
|
||||
|
||||
. = ALIGN(8);
|
||||
. = . + __und_stack_size__;
|
||||
__und_stack_top = .;
|
||||
|
||||
. = ALIGN(8);
|
||||
. = . + __sys_stack_size__;
|
||||
__sys_stack_top = .;
|
||||
} > DRAM
|
||||
|
||||
. = ALIGN(8);
|
||||
_end = .;
|
||||
PROVIDE(end = .);
|
||||
|
||||
/* Writable area for the MPU: data, bss, stacks and the heap that
|
||||
tx_application_define carves out of everything above _end. */
|
||||
|
||||
. = ALIGN(64);
|
||||
__data_end__ = . + 0x00100000; /* 1 MB of heap beyond the image */
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,113 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License which is available at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*
|
||||
* AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
|
||||
* The AI-generated portions may be considered public domain (CC0-1.0)
|
||||
* and not subject to the project's licence. The human contributor has
|
||||
* reviewed and verified that the code is correct.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT and CC0-1.0
|
||||
**************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* BOARD SUPPORT RELEASE */
|
||||
/* */
|
||||
/* mpu.h Cortex-R52/GNU */
|
||||
/* 6.5.2 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Frédéric Desbiens, Eclipse Foundation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* PMSAv8-R memory protection and cache enable for Cortex-R52. */
|
||||
/* */
|
||||
/* The region set is described by a table rather than a sequence of */
|
||||
/* register writes. That is deliberate and is a roadmap decision, not */
|
||||
/* a style preference: AR2 programs a Stage-1 region set per ThreadX */
|
||||
/* module and AR3 programs Stage-2 regions per ZoneX partition, and */
|
||||
/* both reuse this shape. A table can be swapped at a partition */
|
||||
/* switch; open-coded register writes cannot. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef MPU_H
|
||||
#define MPU_H
|
||||
|
||||
/* Access permissions, PRBAR.AP (bits [3:2]).
|
||||
*
|
||||
* These values were CALIBRATED AGAINST THE HARDWARE, not copied from a
|
||||
* reference, because the widely-published Armv8-R AArch64 macro set has the
|
||||
* two bits the other way round (its "read-only, no EL0 access" is 0x2).
|
||||
* Programming four disjoint regions, one per encoding, and attempting a
|
||||
* privileged write to each gave:
|
||||
*
|
||||
* AP=0b00 write allowed AP=0b01 write faulted
|
||||
* AP=0b10 write allowed AP=0b11 write faulted
|
||||
*
|
||||
* so the low bit is read-only and the high bit grants EL0 access. Using the
|
||||
* AArch64 ordering here silently produces writable "read-only" regions: the
|
||||
* MPU still enforces region coverage, so everything appears to work and only
|
||||
* an explicit write-permission test exposes it. Re-calibrate on S32Z280
|
||||
* silicon before trusting these values there.
|
||||
*/
|
||||
|
||||
#define MPU_AP_RW_EL1 0U /* EL1 read/write, EL0 no access */
|
||||
#define MPU_AP_RO_EL1 1U /* EL1 read-only, EL0 no access */
|
||||
#define MPU_AP_RW_EL1_EL0 2U /* EL1 read/write, EL0 read/write */
|
||||
#define MPU_AP_RO_EL1_EL0 3U /* EL1 read-only, EL0 read-only */
|
||||
|
||||
/* Shareability, PRBAR.SH. */
|
||||
|
||||
#define MPU_SH_NON 0U
|
||||
#define MPU_SH_OUTER 2U
|
||||
#define MPU_SH_INNER 3U
|
||||
|
||||
/* Attribute indices into MAIR, PRLAR.AttrIndx. */
|
||||
|
||||
#define MPU_ATTR_NORMAL_WB 0U /* Normal, inner/outer write-back */
|
||||
#define MPU_ATTR_DEVICE 1U /* Device-nGnRnE */
|
||||
|
||||
/* One protection region. The limit is inclusive, matching the hardware. */
|
||||
|
||||
typedef struct MPU_REGION_STRUCT
|
||||
{
|
||||
unsigned long mpu_region_base;
|
||||
unsigned long mpu_region_limit;
|
||||
unsigned char mpu_region_ap;
|
||||
unsigned char mpu_region_execute_never;
|
||||
unsigned char mpu_region_shareability;
|
||||
unsigned char mpu_region_attr_index;
|
||||
const char *mpu_region_name;
|
||||
} MPU_REGION;
|
||||
|
||||
/* Number of regions this implementation provides, from MPUIR. */
|
||||
|
||||
unsigned int mpu_region_count(void);
|
||||
|
||||
/* Program the region table, then enable the MPU and the caches. Returns
|
||||
the number of regions programmed, or 0 if the table does not fit. */
|
||||
|
||||
unsigned int mpu_init(void);
|
||||
|
||||
/* True once SCTLR reports the MPU and both caches enabled. */
|
||||
|
||||
unsigned int mpu_is_enabled(void);
|
||||
unsigned int mpu_caches_enabled(void);
|
||||
|
||||
/* The active table, for reporting. */
|
||||
|
||||
const MPU_REGION *mpu_region_table(unsigned int *count_ptr);
|
||||
|
||||
/* Read back what the hardware holds for one region, so that programming can
|
||||
be verified rather than assumed. */
|
||||
|
||||
void mpu_read_region(unsigned int index, unsigned long *prbar_ptr,
|
||||
unsigned long *prlar_ptr);
|
||||
|
||||
#endif /* MPU_H */
|
||||
@@ -0,0 +1,82 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License which is available at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*
|
||||
* AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
|
||||
* The AI-generated portions may be considered public domain (CC0-1.0)
|
||||
* and not subject to the project's licence. The human contributor has
|
||||
* reviewed and verified that the code is correct.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT and CC0-1.0
|
||||
**************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* BOARD SUPPORT RELEASE */
|
||||
/* */
|
||||
/* platform.h Cortex-R52/GNU */
|
||||
/* 6.5.2 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Frédéric Desbiens, Eclipse Foundation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* Memory map for the Armv8-R AEM FVP (BaseR platform). */
|
||||
/* */
|
||||
/* Every address here was VERIFIED IN-MODEL, not taken from */
|
||||
/* documentation or recollection. The BaseR map is the Base platform */
|
||||
/* map with its two 2 GB halves swapped (so a Base peripheral at X */
|
||||
/* below 0x80000000 appears at X + 0x80000000), and each base was then */
|
||||
/* confirmed by reading its identification register: */
|
||||
/* */
|
||||
/* PL011 UART0 peripheral ID 0x11,0x10,0x24,0x00, and a marker */
|
||||
/* written to it appeared on the host console */
|
||||
/* GIC GICD_PIDR2 = 0x3B and GICR_PIDR2 = 0x3B, i.e. */
|
||||
/* architecture revision 3 = GICv3 */
|
||||
/* Counter CNTFID0 = 0x05F5E100 = 100 MHz, matching the */
|
||||
/* model's bp.refcounter.base_frequency parameter */
|
||||
/* */
|
||||
/* Values are written without integer suffixes so that this header can */
|
||||
/* also be included from preprocessed assembly. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef PLATFORM_H
|
||||
#define PLATFORM_H
|
||||
|
||||
/* PL011 UART0. */
|
||||
|
||||
#define PL011_UART0_BASE 0x9C090000
|
||||
|
||||
/* GICv3. A redistributor is two consecutive 64 KB frames per core: the RD
|
||||
frame carries the identification and wake-up registers, the SGI frame the
|
||||
per-interrupt enable, priority and configuration registers for SGIs/PPIs. */
|
||||
|
||||
#define GICD_BASE 0xAF000000
|
||||
#define GICR_RD_BASE 0xAF100000
|
||||
#define GICR_SGI_BASE 0xAF110000
|
||||
|
||||
/* System counter control frame (CNTControlBase). */
|
||||
|
||||
#define CNT_CONTROL_BASE 0xAA430000
|
||||
|
||||
/* The model resets CNTFRQ to zero and leaves the system counter stopped --
|
||||
bp.refcounter.non_arch_start_at_default=0, documented as "firmware is
|
||||
expected to enable the timer at boot time". This BSP therefore programs
|
||||
both. The value is CNTFID0 read back from the counter control frame. */
|
||||
|
||||
#define SYSTEM_COUNTER_HZ 100000000
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
/* 32-bit device register access. */
|
||||
|
||||
#define REG32(address) (*(volatile unsigned long *)(unsigned long)(address))
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#endif /* PLATFORM_H */
|
||||
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
# Some portions generated by Claude Code (Opus 5).
|
||||
#
|
||||
"""Run a Cortex-R52 image on the Armv8-R AEM FVP and assert its result.
|
||||
|
||||
This runner is deliberately much simpler than the RISC-V/QEMU one, because
|
||||
the platform allows it: the FVP exposes only an Iris server and no GDB stub,
|
||||
so there is nothing to script through a debugger, and every image terminates
|
||||
itself with a semihosting SYS_EXIT. The runner therefore just launches the
|
||||
model, captures its console, and judges the self-reported result.
|
||||
|
||||
A missing result line is treated as FAILURE, never as success: a silent hang
|
||||
or a crash before the first check must not be able to masquerade as a pass.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
PASS_MARK = "ALL CHECKS PASSED"
|
||||
FAIL_MARK = "RESULT: FAILED"
|
||||
FAULT_MARK = "[FAULT]"
|
||||
|
||||
|
||||
def as_text(stream):
|
||||
"""Normalise a captured stream to str.
|
||||
|
||||
subprocess.TimeoutExpired carries its partial output undecoded even when
|
||||
the call used text=True, so the timeout path can hand us bytes where the
|
||||
normal path hands us str. Decoding defensively here keeps the hang
|
||||
report readable instead of raising TypeError inside the error handler.
|
||||
"""
|
||||
if stream is None:
|
||||
return ""
|
||||
if isinstance(stream, bytes):
|
||||
return stream.decode(errors="replace")
|
||||
return stream
|
||||
|
||||
|
||||
def run(elf, fvp, timeout):
|
||||
command = [
|
||||
fvp,
|
||||
"-C", "cluster0.NUM_CORES=1",
|
||||
"-C", "bp.vis.disable_visualisation=1",
|
||||
"-C", "bp.terminal_0.start_telnet=0",
|
||||
# Route UART0 to stdout so PL011-console images are captured too.
|
||||
# Harmless for semihosting images, which do not touch the UART.
|
||||
"-C", "bp.pl011_uart0.out_file=-",
|
||||
"-C", "bp.pl011_uart0.unbuffered_output=1",
|
||||
"-a", elf,
|
||||
]
|
||||
|
||||
print("Running:", " ".join(command), flush=True)
|
||||
|
||||
try:
|
||||
completed = subprocess.run(
|
||||
command, capture_output=True, text=True, timeout=timeout
|
||||
)
|
||||
output = as_text(completed.stdout) + as_text(completed.stderr)
|
||||
except subprocess.TimeoutExpired as expired:
|
||||
print(as_text(expired.stdout) + as_text(expired.stderr))
|
||||
print(
|
||||
f"FAIL: the simulation did not terminate within {timeout}s. "
|
||||
"Every image is expected to exit through semihosting SYS_EXIT, "
|
||||
"so this is a hang, not a slow run.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
|
||||
print(output)
|
||||
|
||||
if FAULT_MARK in output:
|
||||
faults = [line for line in output.splitlines() if FAULT_MARK in line]
|
||||
print("FAIL: unhandled exception reported:", file=sys.stderr)
|
||||
for line in faults:
|
||||
print(" " + line.strip(), file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if FAIL_MARK in output:
|
||||
print("FAIL: the image reported failing checks.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if PASS_MARK not in output:
|
||||
print(
|
||||
"FAIL: no result line found. The image neither passed nor "
|
||||
"reported failure, so it did not reach its checks.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
|
||||
print("PASS")
|
||||
return 0
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--elf", required=True, help="image to run")
|
||||
parser.add_argument("--fvp", default="FVP_BaseR_AEMv8R", help="model binary")
|
||||
parser.add_argument(
|
||||
"--timeout", type=int, default=180, help="seconds before declaring a hang"
|
||||
)
|
||||
arguments = parser.parse_args()
|
||||
|
||||
return run(arguments.elf, arguments.fvp, arguments.timeout)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,174 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License which is available at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*
|
||||
* AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
|
||||
* The AI-generated portions may be considered public domain (CC0-1.0)
|
||||
* and not subject to the project's licence. The human contributor has
|
||||
* reviewed and verified that the code is correct.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT and CC0-1.0
|
||||
**************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* BOARD SUPPORT RELEASE */
|
||||
/* */
|
||||
/* timer.c Cortex-R52/GNU */
|
||||
/* 6.5.2 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Frédéric Desbiens, Eclipse Foundation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* Arm generic timer tick for Cortex-R52 on the Armv8-R AEM FVP. */
|
||||
/* */
|
||||
/* Two model behaviours make this longer than a bare timer setup, both */
|
||||
/* confirmed by reading the hardware rather than assumed: */
|
||||
/* */
|
||||
/* 1. The system counter is STOPPED at reset (CNTCR = 0, CNTCV = 0). */
|
||||
/* The model documents that firmware is expected to start it, so */
|
||||
/* the counter control frame is enabled here. Without this the */
|
||||
/* timer never counts and no tick is ever delivered. */
|
||||
/* 2. CNTFRQ resets to ZERO. It is writable only at the highest */
|
||||
/* implemented exception level, so entry.S programs it at EL2; */
|
||||
/* this file only reads it. Deriving the tick interval from an */
|
||||
/* unprogrammed CNTFRQ would divide by zero. */
|
||||
/* */
|
||||
/* EL1 access to the physical timer and counter also depends on */
|
||||
/* CNTHCTL.PL1PCEN/PL1PCTEN, which reset disabled and are set by */
|
||||
/* entry.S at EL2; otherwise these accesses would trap to EL2. */
|
||||
/* */
|
||||
/* MISRA C:2012 deviations (justified) */
|
||||
/* */
|
||||
/* Directive 4.3 -- the generic timer is only reachable through CP15 */
|
||||
/* registers; every such access is encapsulated in an accessor below.*/
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "platform.h"
|
||||
#include "timer.h"
|
||||
|
||||
/* Counter control frame (CNTControlBase). */
|
||||
|
||||
#define CNTCR 0x0000U
|
||||
#define CNTCR_EN (1UL << 0)
|
||||
#define CNTSR 0x0004U
|
||||
|
||||
/* CNTP_CTL bits. */
|
||||
|
||||
#define CNTP_CTL_ENABLE (1UL << 0)
|
||||
#define CNTP_CTL_IMASK (1UL << 1)
|
||||
|
||||
static unsigned long tick_interval;
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* Generic timer accessors (AArch32 CP15). */
|
||||
/**************************************************************************/
|
||||
|
||||
static unsigned long read_cntfrq(void)
|
||||
{
|
||||
unsigned long value;
|
||||
__asm__ volatile("mrc p15, 0, %0, c14, c0, 0" : "=r"(value));
|
||||
return value;
|
||||
}
|
||||
|
||||
static void write_cntp_tval(unsigned long value)
|
||||
{
|
||||
__asm__ volatile("mcr p15, 0, %0, c14, c2, 0" : : "r"(value) : "memory");
|
||||
}
|
||||
|
||||
static void write_cntp_ctl(unsigned long value)
|
||||
{
|
||||
__asm__ volatile("mcr p15, 0, %0, c14, c2, 1" : : "r"(value) : "memory");
|
||||
}
|
||||
|
||||
static unsigned long long read_cntpct(void)
|
||||
{
|
||||
unsigned long low;
|
||||
unsigned long high;
|
||||
|
||||
__asm__ volatile("mrrc p15, 0, %0, %1, c14" : "=r"(low), "=r"(high));
|
||||
|
||||
return ((unsigned long long) high << 32) | (unsigned long long) low;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* timer_frequency */
|
||||
/**************************************************************************/
|
||||
|
||||
unsigned long timer_frequency(void)
|
||||
{
|
||||
return read_cntfrq();
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* timer_counter */
|
||||
/**************************************************************************/
|
||||
|
||||
unsigned long long timer_counter(void)
|
||||
{
|
||||
return read_cntpct();
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* timer_counter_enabled */
|
||||
/**************************************************************************/
|
||||
|
||||
unsigned int timer_counter_enabled(void)
|
||||
{
|
||||
return ((REG32(CNT_CONTROL_BASE + CNTCR) & CNTCR_EN) != 0UL) ? 1U : 0U;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* timer_reload */
|
||||
/**************************************************************************/
|
||||
|
||||
void timer_reload(void)
|
||||
{
|
||||
/* Writing CNTP_TVAL restarts the down-count, which also deasserts the
|
||||
level-sensitive timer output. */
|
||||
|
||||
write_cntp_tval(tick_interval);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* timer_init */
|
||||
/**************************************************************************/
|
||||
|
||||
void timer_init(void)
|
||||
{
|
||||
unsigned long frequency;
|
||||
|
||||
/* Start the system counter -- it is stopped at reset on this model. */
|
||||
|
||||
REG32(CNT_CONTROL_BASE + CNTCR) |= CNTCR_EN;
|
||||
|
||||
/* Derive the tick interval. CNTFRQ was programmed at EL2; fall back to
|
||||
the known counter frequency rather than dividing by zero should that
|
||||
ever not have happened. */
|
||||
|
||||
frequency = read_cntfrq();
|
||||
if (frequency == 0UL)
|
||||
{
|
||||
frequency = (unsigned long) SYSTEM_COUNTER_HZ;
|
||||
}
|
||||
|
||||
tick_interval = frequency / TX_TIMER_TICKS_PER_SECOND;
|
||||
|
||||
/* Enable the timer, unmasked, and arm the first interval. */
|
||||
|
||||
write_cntp_tval(tick_interval);
|
||||
write_cntp_ctl(CNTP_CTL_ENABLE);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License which is available at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*
|
||||
* AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
|
||||
* The AI-generated portions may be considered public domain (CC0-1.0)
|
||||
* and not subject to the project's licence. The human contributor has
|
||||
* reviewed and verified that the code is correct.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT and CC0-1.0
|
||||
**************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* BOARD SUPPORT RELEASE */
|
||||
/* */
|
||||
/* timer.h Cortex-R52/GNU */
|
||||
/* 6.5.2 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Frédéric Desbiens, Eclipse Foundation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* Arm generic timer tick for Cortex-R52. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef TIMER_H
|
||||
#define TIMER_H
|
||||
|
||||
/* PPI driven by the EL1 physical timer.
|
||||
*
|
||||
* This was not assumed. Bring-up enabled the entire PPI range 25-31 and
|
||||
* recorded whichever INTID came back from ICC_IAR1; the model drove 30, which
|
||||
* matches the architectural assignment for the EL1 physical timer. Only that
|
||||
* line is enabled now, and irq_dispatch.c still records any other INTID so a
|
||||
* different platform assignment would be reported rather than silently
|
||||
* mishandled. Re-verify when moving to S32Z2 silicon. */
|
||||
|
||||
#define TIMER_PPI_INTID 30U
|
||||
|
||||
/* Enable the system counter, then start the periodic tick at
|
||||
TX_TIMER_TICKS_PER_SECOND. gicv3_init() must have run first. */
|
||||
|
||||
void timer_init(void);
|
||||
|
||||
/* Re-arm the timer for the next tick. Called from the interrupt path. */
|
||||
|
||||
void timer_reload(void);
|
||||
|
||||
/* CNTFRQ as programmed by entry.S at EL2. */
|
||||
|
||||
unsigned long timer_frequency(void);
|
||||
|
||||
/* Current 64-bit physical counter value, for verifying the counter runs. */
|
||||
|
||||
unsigned long long timer_counter(void);
|
||||
|
||||
/* True once the counter control frame reports the counter enabled. */
|
||||
|
||||
unsigned int timer_counter_enabled(void);
|
||||
|
||||
#endif /* TIMER_H */
|
||||
@@ -0,0 +1,102 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License which is available at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*
|
||||
* AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
|
||||
* The AI-generated portions may be considered public domain (CC0-1.0)
|
||||
* and not subject to the project's licence. The human contributor has
|
||||
* reviewed and verified that the code is correct.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT and CC0-1.0
|
||||
**************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Initialize */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
.arch armv8-r
|
||||
.syntax unified
|
||||
.arm
|
||||
|
||||
.global _tx_thread_system_stack_ptr
|
||||
.global _tx_initialize_unused_memory
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_initialize_low_level Cortex-R52/GNU */
|
||||
/* 6.5.2 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Frédéric Desbiens, Eclipse Foundation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* Low-level initialization for Cortex-R52 on the Armv8-R AEM FVP. */
|
||||
/* Called by _tx_initialize_kernel_enter with the processor already in */
|
||||
/* Supervisor mode at EL1. */
|
||||
/* */
|
||||
/* This is deliberately shorter than the A-profile reference ports: */
|
||||
/* entry.S has already given every AArch32 mode its own stack from */
|
||||
/* dedicated linker-script regions, so there is no stack carving to do */
|
||||
/* here and no run-time stack-overlap check to perform -- the linker */
|
||||
/* guarantees the regions do not overlap. */
|
||||
/* */
|
||||
/* When built with TX_R52_USE_THREADX_IRQ, board_init() brings up GICv3*/
|
||||
/* and the generic timer tick here. That is safe this early because */
|
||||
/* interrupts stay masked until _tx_thread_schedule enables them, so no*/
|
||||
/* tick can be delivered before the kernel is ready to take one. */
|
||||
/* Without that symbol (the M2 cooperative demo) no tick is created, */
|
||||
/* which keeps M2 free of any interrupt dependency. */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_initialize_kernel_enter ThreadX entry function */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
.global _tx_initialize_low_level
|
||||
.type _tx_initialize_low_level, %function
|
||||
_tx_initialize_low_level:
|
||||
|
||||
/* Record the system stack. The interrupt path uses it when an
|
||||
exception arrives while no thread is running. */
|
||||
|
||||
ldr r0, =__sys_stack_top
|
||||
ldr r1, =_tx_thread_system_stack_ptr
|
||||
str r0, [r1]
|
||||
|
||||
/* Publish the first free memory address for tx_application_define.
|
||||
_end sits above the image, .bss and every per-mode stack. Round up
|
||||
to an 8-byte boundary so pool control blocks are aligned. */
|
||||
|
||||
ldr r0, =_end
|
||||
add r0, r0, #7
|
||||
bic r0, r0, #7
|
||||
ldr r1, =_tx_initialize_unused_memory
|
||||
str r0, [r1]
|
||||
|
||||
#ifdef TX_R52_USE_THREADX_IRQ
|
||||
|
||||
/* Bring up the interrupt controller and the periodic tick. */
|
||||
|
||||
push {lr}
|
||||
bl board_init
|
||||
pop {lr}
|
||||
|
||||
#endif
|
||||
|
||||
bx lr
|
||||
@@ -0,0 +1,127 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License which is available at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*
|
||||
* AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
|
||||
* The AI-generated portions may be considered public domain (CC0-1.0)
|
||||
* and not subject to the project's licence. The human contributor has
|
||||
* reviewed and verified that the code is correct.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT and CC0-1.0
|
||||
**************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* BOARD SUPPORT RELEASE */
|
||||
/* */
|
||||
/* uart_pl011.c Cortex-R52/GNU */
|
||||
/* 6.5.2 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Frédéric Desbiens, Eclipse Foundation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* PL011 UART output for the Armv8-R AEM FVP, used as the console when */
|
||||
/* the image is built with TX_R52_CONSOLE_PL011. */
|
||||
/* */
|
||||
/* Semihosting remains the default because it needs no peripheral at */
|
||||
/* all, which keeps early bring-up independent of the memory map. The */
|
||||
/* UART matters because it is what real silicon will use: exercising it*/
|
||||
/* here means the S32Z280 console differs only in its base address and */
|
||||
/* clocking, not in structure. */
|
||||
/* */
|
||||
/* The model leaves UART0 disabled at reset */
|
||||
/* (bp.pl011_uart0.uart_enable=0), so the control register must be */
|
||||
/* written before the first character. Baud rate is left alone: the */
|
||||
/* model does not emulate serial timing, and inventing a divisor here */
|
||||
/* would only be misleading. */
|
||||
/* */
|
||||
/* MISRA C:2012 deviations (justified) */
|
||||
/* */
|
||||
/* Rule 11.4/11.6 -- casting integer addresses to volatile pointers is */
|
||||
/* inherent to memory-mapped device access; confined to REG32. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "platform.h"
|
||||
#include "uart_pl011.h"
|
||||
|
||||
/* PL011 register offsets. */
|
||||
|
||||
#define UART_DR 0x000U /* data */
|
||||
#define UART_FR 0x018U /* flags */
|
||||
#define UART_LCR_H 0x02CU /* line control */
|
||||
#define UART_CR 0x030U /* control */
|
||||
|
||||
#define UART_FR_TXFF (1UL << 5) /* transmit FIFO full */
|
||||
|
||||
#define UART_LCR_H_WLEN_8 (3UL << 5) /* 8 data bits */
|
||||
#define UART_LCR_H_FEN (1UL << 4) /* enable FIFOs */
|
||||
|
||||
#define UART_CR_UARTEN (1UL << 0) /* UART enable */
|
||||
#define UART_CR_TXE (1UL << 8) /* transmit enable */
|
||||
#define UART_CR_RXE (1UL << 9) /* receive enable */
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* pl011_init */
|
||||
/**************************************************************************/
|
||||
|
||||
void pl011_init(void)
|
||||
{
|
||||
/* Disable while reconfiguring, as the programming model requires. */
|
||||
|
||||
REG32(PL011_UART0_BASE + UART_CR) = 0UL;
|
||||
|
||||
REG32(PL011_UART0_BASE + UART_LCR_H) = UART_LCR_H_WLEN_8 | UART_LCR_H_FEN;
|
||||
|
||||
REG32(PL011_UART0_BASE + UART_CR) =
|
||||
UART_CR_UARTEN | UART_CR_TXE | UART_CR_RXE;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* pl011_putc */
|
||||
/**************************************************************************/
|
||||
|
||||
void pl011_putc(char character)
|
||||
{
|
||||
/* Expand newlines so the host console shows discrete lines. */
|
||||
|
||||
if (character == '\n')
|
||||
{
|
||||
pl011_putc('\r');
|
||||
}
|
||||
|
||||
while ((REG32(PL011_UART0_BASE + UART_FR) & UART_FR_TXFF) != 0UL)
|
||||
{
|
||||
/* Wait for room in the transmit FIFO. */
|
||||
}
|
||||
|
||||
REG32(PL011_UART0_BASE + UART_DR) = (unsigned long) (unsigned char) character;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* pl011_puts */
|
||||
/**************************************************************************/
|
||||
|
||||
void pl011_puts(const char *string_ptr)
|
||||
{
|
||||
const char *cursor = string_ptr;
|
||||
|
||||
if (cursor == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (*cursor != '\0')
|
||||
{
|
||||
pl011_putc(*cursor);
|
||||
cursor++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License which is available at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*
|
||||
* AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
|
||||
* The AI-generated portions may be considered public domain (CC0-1.0)
|
||||
* and not subject to the project's licence. The human contributor has
|
||||
* reviewed and verified that the code is correct.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT and CC0-1.0
|
||||
**************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* BOARD SUPPORT RELEASE */
|
||||
/* */
|
||||
/* uart_pl011.h Cortex-R52/GNU */
|
||||
/* 6.5.2 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Frédéric Desbiens, Eclipse Foundation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* PL011 UART console backend for the Armv8-R AEM FVP. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef UART_PL011_H
|
||||
#define UART_PL011_H
|
||||
|
||||
/* Configure and enable UART0. The model leaves it disabled at reset. */
|
||||
|
||||
void pl011_init(void);
|
||||
|
||||
/* Send one character, expanding a newline into CR LF. */
|
||||
|
||||
void pl011_putc(char character);
|
||||
|
||||
/* Send a NUL-terminated string. */
|
||||
|
||||
void pl011_puts(const char *string_ptr);
|
||||
|
||||
#endif /* UART_PL011_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,172 @@
|
||||
Eclipse ThreadX for Cortex-R52
|
||||
Using GNU Tools
|
||||
|
||||
|
||||
1. Building the ThreadX run-time Library
|
||||
|
||||
The port is built with CMake and Ninja. From the repository root:
|
||||
|
||||
cmake -B build_r52 -G Ninja \
|
||||
-DCMAKE_TOOLCHAIN_FILE=cmake/cortex_r52.cmake .
|
||||
ninja -C build_r52
|
||||
|
||||
This produces libthreadx.a for Cortex-R52 in AArch32 state. The toolchain
|
||||
file pins the reference cross compiler by absolute path so that the build
|
||||
does not depend on PATH ordering; override it with
|
||||
|
||||
-DARM_TOOLCHAIN_PATH=<directory containing arm-none-eabi-gcc>
|
||||
|
||||
Note this is 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 previously be built this way.
|
||||
|
||||
|
||||
2. Build options
|
||||
|
||||
-DTX_R52_FLOAT_ABI=soft|hard floating-point ABI, default soft
|
||||
-DTX_R52_ENABLE_VFP=ON lazy VFP context save and restore
|
||||
-DTX_R52_ENABLE_FIQ=ON FIQ support
|
||||
-DTX_R52_ENABLE_IRQ_NESTING=ON nested IRQ support
|
||||
-DTX_R52_ENABLE_FIQ_NESTING=ON nested FIQ support (requires the above)
|
||||
-DTX_R52_BUILD_FVP_EXAMPLE=ON build the Armv8-R AEM FVP examples
|
||||
-DTX_R52_ENABLE_MPU=ON PMSAv8-R protection and caches
|
||||
-DTX_R52_CONSOLE_PL011=ON console on the PL011 UART, not semihosting
|
||||
|
||||
TX_R52_ENABLE_VFP is PUBLIC: it changes which registers the context switch
|
||||
saves, so the library and the application must agree. Pair it with
|
||||
TX_R52_FLOAT_ABI=hard, otherwise the compiler emits no floating-point
|
||||
instructions and the VFP path is never exercised.
|
||||
|
||||
Cortex-R52 always implements at least a single-precision FPU. GCC rejects
|
||||
"-mcpu=cortex-r52+nofp" and offers only "+nofp.dp", so the soft-float
|
||||
baseline selects the soft ABI rather than removing the FPU.
|
||||
|
||||
|
||||
3. Example builds and tests
|
||||
|
||||
cmake -B build_r52 -G Ninja \
|
||||
-DCMAKE_TOOLCHAIN_FILE=cmake/cortex_r52.cmake \
|
||||
-DTX_R52_BUILD_FVP_EXAMPLE=ON .
|
||||
ninja -C build_r52 boot_check.elf demo_m2.elf demo_m3.elf \
|
||||
demo_threadx.elf demo_mpu.elf
|
||||
ctest --test-dir build_r52
|
||||
|
||||
The images target the free Armv8-R AEM FVP (FVP_BaseR_AEMv8R):
|
||||
|
||||
boot_check.elf EL2 configuration, the drop to EL1 and the EL2 seam
|
||||
demo_m2.elf cooperative context switching, no interrupts
|
||||
demo_m3.elf generic timer tick, GICv3 and preemption
|
||||
demo_threadx.elf the standard eight-thread demo plus verification
|
||||
demo_mpu.elf PMSAv8-R protection and cache enable
|
||||
demo_m5.elf lazy VFP context save (needs TX_R52_ENABLE_VFP)
|
||||
|
||||
Each image reports its own result and terminates the model through the
|
||||
semihosting SYS_EXIT call, so no host-side timeout is needed. The test
|
||||
runner treats a missing result line as failure, so a hang cannot pass.
|
||||
|
||||
|
||||
4. System Initialization
|
||||
|
||||
The entry point is _start in the example build's entry.S. Cortex-R52
|
||||
always implements EL2 and resets into it, so the reset path configures EL2
|
||||
first, installs both the EL2 and EL1 vector tables, and only then drops to
|
||||
EL1 (Supervisor mode) to run the kernel. Define TX_R52_BOOT_AT_EL1 to skip
|
||||
the EL2 stage where an earlier boot stage or a vendor EL2 monitor has
|
||||
already dropped privilege.
|
||||
|
||||
Work that must happen at EL2, because the registers are inaccessible or
|
||||
read-only later:
|
||||
|
||||
CNTFRQ the model resets it to zero and it is writable
|
||||
only at the highest implemented exception level
|
||||
CNTHCTL.PL1PCTEN/PL1PCEN otherwise every EL1 access to CNTPCT or CNTP_*
|
||||
traps to EL2
|
||||
ICC_HSRE.SRE/Enable lets EL1 reach the GICv3 CPU interface through
|
||||
its system registers
|
||||
HCR.HCD cleared enables HVC, which the EL2 seam depends on
|
||||
HCPTR.TCP10/TCP11 cleared lets EL1 use the FPU
|
||||
|
||||
_tx_initialize_low_level records the system stack and publishes the first
|
||||
free memory address. It is shorter than the A-profile equivalents because
|
||||
entry.S has already given every AArch32 mode its own stack from dedicated
|
||||
linker-script regions, so there is no stack carving and no run-time overlap
|
||||
check to perform. With TX_R52_USE_THREADX_IRQ it also calls board_init to
|
||||
bring up GICv3 and the periodic tick; that is safe this early because
|
||||
interrupts stay masked until _tx_thread_schedule enables them.
|
||||
|
||||
|
||||
5. Interrupt Handling
|
||||
|
||||
The EL1 IRQ vector branches directly into _tx_thread_context_save, which
|
||||
returns to __tx_irq_processing_return. A C dispatcher acknowledges the
|
||||
interrupt, re-arms the timer, calls _tx_timer_interrupt and finishes with
|
||||
_tx_thread_context_restore. The branch must be a plain B: context save
|
||||
adjusts lr itself to locate the point of interrupt.
|
||||
|
||||
Exceptions routed to EL2 from EL1 or EL0 all arrive at the Hyp Trap Entry,
|
||||
vector offset 0x14, not at 0x08. Offsets 0x04 to 0x10 are exceptions taken
|
||||
from Hyp mode itself, and 0x08 is specifically SVC from Hyp. The handler
|
||||
therefore decodes HSR.EC and dispatches; it services HVC (EC 0x12) and
|
||||
reports anything else. That single funnel is the seam that partitioning
|
||||
work extends.
|
||||
|
||||
Every unhandled vector identifies itself over the console. The FVP exposes
|
||||
only an Iris server and no GDB stub, which makes a self-identifying fault
|
||||
the primary debugging tool for this port.
|
||||
|
||||
|
||||
6. Floating Point
|
||||
|
||||
Floating-point context is saved lazily: only threads that call
|
||||
tx_thread_vfp_enable() pay for it. Note that function sets a per-thread
|
||||
software flag for the context switch; it does not enable the FPU. Enabling
|
||||
the hardware is the board support package's responsibility -- CPACR grants
|
||||
CP10/CP11 access and FPEXC.EN enables execution, both of which reset
|
||||
disabled. The example build does this in entry.S under __ARM_FP.
|
||||
|
||||
The flag lives in TX_THREAD_EXTENSION_2 and is reached from assembly by the
|
||||
hard-coded offset 144. It is defined unconditionally rather than under
|
||||
TX_ENABLE_VFP_SUPPORT so that the structure layout does not change with the
|
||||
floating-point build options. tx_port_offset_check.c asserts that offset,
|
||||
and the thread stack pointer and run counter offsets, at compile time: a
|
||||
layout change becomes a build failure instead of silent corruption.
|
||||
|
||||
|
||||
7. Memory Protection
|
||||
|
||||
PMSAv8-R regions are described by a table rather than a sequence of
|
||||
register writes, so that a region set can be swapped wholesale. The
|
||||
example programs three regions -- code read-only and executable, all
|
||||
writable memory non-executable, peripherals as Device -- and explicitly
|
||||
disables the regions it does not use.
|
||||
|
||||
Two cautions for anyone reusing this code on silicon:
|
||||
|
||||
- The PRBAR.AP encoding used here was calibrated against the hardware.
|
||||
The low bit is read-only and the high bit grants EL0 access, which is
|
||||
the reverse of the widely-published Armv8-R AArch64 macro set. Getting
|
||||
it wrong produces regions that report as read-only and accept writes,
|
||||
because region coverage is still enforced: an unmapped address faults
|
||||
while a "read-only" region does not. Re-calibrate before trusting
|
||||
these values on a different implementation.
|
||||
|
||||
- The code and data regions must not share a 64-byte granule. The
|
||||
linker script separates them with ".data ALIGN(64) :" on the output
|
||||
section. An assignment to the location counter between sections does
|
||||
not advance a MEMORY region's allocation pointer, and an ALIGN at the
|
||||
end of the preceding section does not extend it when no data follows,
|
||||
so both of those leave writable data inside the read-only region.
|
||||
|
||||
|
||||
8. Validation
|
||||
|
||||
Functional validation is performed on the Armv8-R AEM FVP through the
|
||||
images listed in section 3. Structural coverage is not claimed from this
|
||||
port: the platform-agnostic regression suite runs on the host, which is
|
||||
where the coverage instrumentation and the certification evidence live.
|
||||
|
||||
The FVP is an architecture envelope model, not a Cortex-R52
|
||||
implementation -- it reports MIDR 0x410FD0F0, part number 0xD0F. It
|
||||
validates architecture; implementation details such as MPU region count,
|
||||
TCM, lockstep and RAS must be validated on silicon. Nothing in this port
|
||||
is gated on MIDR.
|
||||
@@ -0,0 +1,86 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License which is available at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*
|
||||
* AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
|
||||
* The AI-generated portions may be considered public domain (CC0-1.0)
|
||||
* and not subject to the project's licence. The human contributor has
|
||||
* reviewed and verified that the code is correct.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT and CC0-1.0
|
||||
**************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Port Specific */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* PORT SPECIFIC C INFORMATION RELEASE */
|
||||
/* */
|
||||
/* tx_port_offset_check.c Cortex-R52/GNU */
|
||||
/* 6.5.2 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Frédéric Desbiens, Eclipse Foundation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* Compile-time verification of the TX_THREAD structure offsets that */
|
||||
/* this port's assembly reaches by hard-coded displacement. The file */
|
||||
/* emits no code; it exists purely so that a layout change becomes a */
|
||||
/* build failure. */
|
||||
/* */
|
||||
/* Why this is needed: tx_thread_schedule.S, */
|
||||
/* tx_thread_system_return.S and tx_thread_context_restore.S read and */
|
||||
/* write the per-thread VFP enable flag as [thread, #144]. Nothing in */
|
||||
/* the toolchain connects that literal to the C structure, so adding a */
|
||||
/* member, enabling an option that adds one, or reordering the port */
|
||||
/* extensions would silently retarget those accesses at an unrelated */
|
||||
/* field -- corrupting thread state in a way that is extremely hard to */
|
||||
/* diagnose from the symptom. The offset was measured at 144 for the */
|
||||
/* default build and is asserted here. */
|
||||
/* */
|
||||
/* A negative array dimension is used rather than _Static_assert */
|
||||
/* because this project targets C99, where _Static_assert does not */
|
||||
/* exist. If an assertion below fails, the compiler reports a negative*/
|
||||
/* or zero-sized array for the named typedef. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "tx_api.h"
|
||||
#include <stddef.h>
|
||||
|
||||
/* Offset of the VFP enable flag as encoded in this port's assembly.
|
||||
Overridable only so that the assertion itself can be tested. */
|
||||
|
||||
#ifndef TX_PORT_VFP_ENABLE_OFFSET
|
||||
#define TX_PORT_VFP_ENABLE_OFFSET 144
|
||||
#endif
|
||||
|
||||
typedef char
|
||||
tx_port_assert_vfp_enable_offset_is_144[
|
||||
(offsetof(TX_THREAD, tx_thread_vfp_enable) == TX_PORT_VFP_ENABLE_OFFSET)
|
||||
? 1 : -1];
|
||||
|
||||
/* The stack pointer is read as [thread, #8] by tx_thread_schedule.S and
|
||||
written by tx_thread_system_return.S, and the run counter as
|
||||
[thread, #4]. Assert those too, since they are on the context-switch
|
||||
critical path. */
|
||||
|
||||
typedef char
|
||||
tx_port_assert_stack_ptr_offset_is_8[
|
||||
(offsetof(TX_THREAD, tx_thread_stack_ptr) == 8) ? 1 : -1];
|
||||
|
||||
typedef char
|
||||
tx_port_assert_run_count_offset_is_4[
|
||||
(offsetof(TX_THREAD, tx_thread_run_count) == 4) ? 1 : -1];
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,193 @@
|
||||
@/***************************************************************************
|
||||
@ * Copyright (c) 2024 Microsoft Corporation
|
||||
@ * Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
@ *
|
||||
@ * This program and the accompanying materials are made available under the
|
||||
@ * terms of the MIT License which is available at
|
||||
@ * https://opensource.org/licenses/MIT.
|
||||
@ *
|
||||
@ * SPDX-License-Identifier: MIT
|
||||
@ **************************************************************************/
|
||||
@ Some portions generated by Claude Code (Opus 5).
|
||||
@
|
||||
@
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@/** */
|
||||
@/** ThreadX Component */
|
||||
@/** */
|
||||
@/** Thread */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
#ifdef TX_INCLUDE_USER_DEFINE_FILE
|
||||
#include "tx_user.h"
|
||||
#endif
|
||||
|
||||
.global _tx_thread_system_state
|
||||
.global _tx_thread_current_ptr
|
||||
.global _tx_irq_processing_return
|
||||
.global _tx_execution_isr_enter
|
||||
@
|
||||
@
|
||||
@/* No 16-bit Thumb mode veneer code is needed for _tx_thread_context_save
|
||||
@ since it will never be called 16-bit mode. */
|
||||
@
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_context_save Cortex-R52/GNU */
|
||||
@/* 6.5.2 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* Frédéric Desbiens, Eclipse Foundation */
|
||||
@/* */
|
||||
@/* Derived from the Cortex-R5/GNU port originally written by */
|
||||
@/* William E. Lamie, Microsoft Corporation. */
|
||||
@/* */
|
||||
@/* DESCRIPTION */
|
||||
@/* */
|
||||
@/* This function saves the context of an executing thread in the */
|
||||
@/* beginning of interrupt processing. The function also ensures that */
|
||||
@/* the system stack is used upon return to the calling ISR. */
|
||||
@/* */
|
||||
@/* INPUT */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* OUTPUT */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* CALLS */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* CALLED BY */
|
||||
@/* */
|
||||
@/* ISRs */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@VOID _tx_thread_context_save(VOID)
|
||||
@{
|
||||
.global _tx_thread_context_save
|
||||
.type _tx_thread_context_save,function
|
||||
_tx_thread_context_save:
|
||||
@
|
||||
@ /* Upon entry to this routine, it is assumed that IRQ interrupts are locked
|
||||
@ out, we are in IRQ mode, and all registers are intact. */
|
||||
@
|
||||
@ /* Check for a nested interrupt condition. */
|
||||
@ if (_tx_thread_system_state++)
|
||||
@ {
|
||||
@
|
||||
STMDB sp!, {r0-r3} @ Save some working registers
|
||||
#ifdef TX_ENABLE_FIQ_SUPPORT
|
||||
CPSID if @ Disable FIQ interrupts
|
||||
#endif
|
||||
LDR r3, =_tx_thread_system_state @ Pickup address of system state variable
|
||||
LDR r2, [r3] @ Pickup system state
|
||||
CMP r2, #0 @ Is this the first interrupt?
|
||||
BEQ __tx_thread_not_nested_save @ Yes, not a nested context save
|
||||
@
|
||||
@ /* Nested interrupt condition. */
|
||||
@
|
||||
ADD r2, r2, #1 @ Increment the interrupt counter
|
||||
STR r2, [r3] @ Store it back in the variable
|
||||
@
|
||||
@ /* Save the rest of the scratch registers on the stack and return to the
|
||||
@ calling ISR. */
|
||||
@
|
||||
MRS r0, SPSR @ Pickup saved SPSR
|
||||
SUB lr, lr, #4 @ Adjust point of interrupt
|
||||
STMDB sp!, {r0, r10, r12, lr} @ Store other registers
|
||||
@
|
||||
@ /* Return to the ISR. */
|
||||
@
|
||||
MOV r10, #0 @ Clear stack limit
|
||||
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
@
|
||||
@ /* Call the ISR enter function to indicate an ISR is executing. */
|
||||
@
|
||||
PUSH {lr} @ Save ISR lr
|
||||
BL _tx_execution_isr_enter @ Call the ISR enter function
|
||||
POP {lr} @ Recover ISR lr
|
||||
#endif
|
||||
|
||||
B __tx_irq_processing_return @ Continue IRQ processing
|
||||
@
|
||||
__tx_thread_not_nested_save:
|
||||
@ }
|
||||
@
|
||||
@ /* Otherwise, not nested, check to see if a thread was running. */
|
||||
@ else if (_tx_thread_current_ptr)
|
||||
@ {
|
||||
@
|
||||
ADD r2, r2, #1 @ Increment the interrupt counter
|
||||
STR r2, [r3] @ Store it back in the variable
|
||||
LDR r1, =_tx_thread_current_ptr @ Pickup address of current thread ptr
|
||||
LDR r0, [r1] @ Pickup current thread pointer
|
||||
CMP r0, #0 @ Is it NULL?
|
||||
BEQ __tx_thread_idle_system_save @ If so, interrupt occurred in
|
||||
@ scheduling loop - nothing needs saving!
|
||||
@
|
||||
@ /* Save minimal context of interrupted thread. */
|
||||
@
|
||||
MRS r2, SPSR @ Pickup saved SPSR
|
||||
SUB lr, lr, #4 @ Adjust point of interrupt
|
||||
STMDB sp!, {r2, r10, r12, lr} @ Store other registers
|
||||
@
|
||||
@ /* Save the current stack pointer in the thread's control block. */
|
||||
@ _tx_thread_current_ptr -> tx_thread_stack_ptr = sp;
|
||||
@
|
||||
@ /* Switch to the system stack. */
|
||||
@ sp = _tx_thread_system_stack_ptr@
|
||||
@
|
||||
MOV r10, #0 @ Clear stack limit
|
||||
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
@
|
||||
@ /* Call the ISR enter function to indicate an ISR is executing. */
|
||||
@
|
||||
PUSH {lr} @ Save ISR lr
|
||||
BL _tx_execution_isr_enter @ Call the ISR enter function
|
||||
POP {lr} @ Recover ISR lr
|
||||
#endif
|
||||
|
||||
B __tx_irq_processing_return @ Continue IRQ processing
|
||||
@
|
||||
@ }
|
||||
@ else
|
||||
@ {
|
||||
@
|
||||
__tx_thread_idle_system_save:
|
||||
@
|
||||
@ /* Interrupt occurred in the scheduling loop. */
|
||||
@
|
||||
@ /* Not much to do here, just adjust the stack pointer, and return to IRQ
|
||||
@ processing. */
|
||||
@
|
||||
MOV r10, #0 @ Clear stack limit
|
||||
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
@
|
||||
@ /* Call the ISR enter function to indicate an ISR is executing. */
|
||||
@
|
||||
PUSH {lr} @ Save ISR lr
|
||||
BL _tx_execution_isr_enter @ Call the ISR enter function
|
||||
POP {lr} @ Recover ISR lr
|
||||
#endif
|
||||
|
||||
ADD sp, sp, #16 @ Recover saved registers
|
||||
B __tx_irq_processing_return @ Continue IRQ processing
|
||||
@
|
||||
@ }
|
||||
@}
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,195 @@
|
||||
@/***************************************************************************
|
||||
@ * Copyright (c) 2024 Microsoft Corporation
|
||||
@ * Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
@ *
|
||||
@ * This program and the accompanying materials are made available under the
|
||||
@ * terms of the MIT License which is available at
|
||||
@ * https://opensource.org/licenses/MIT.
|
||||
@ *
|
||||
@ * SPDX-License-Identifier: MIT
|
||||
@ **************************************************************************/
|
||||
@ Some portions generated by Claude Code (Opus 5).
|
||||
@
|
||||
@
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@/** */
|
||||
@/** ThreadX Component */
|
||||
@/** */
|
||||
@/** Thread */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
#ifdef TX_INCLUDE_USER_DEFINE_FILE
|
||||
#include "tx_user.h"
|
||||
#endif
|
||||
|
||||
.global _tx_thread_system_state
|
||||
.global _tx_thread_current_ptr
|
||||
.global __tx_fiq_processing_return
|
||||
.global _tx_execution_isr_enter
|
||||
@
|
||||
@
|
||||
@/* No 16-bit Thumb mode veneer code is needed for _tx_thread_fiq_context_save
|
||||
@ since it will never be called 16-bit mode. */
|
||||
@
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_fiq_context_save Cortex-R52/GNU */
|
||||
@/* 6.5.2 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* Frédéric Desbiens, Eclipse Foundation */
|
||||
@/* */
|
||||
@/* Derived from the Cortex-R5/GNU port originally written by */
|
||||
@/* William E. Lamie, Microsoft Corporation. */
|
||||
@/* */
|
||||
@/* DESCRIPTION */
|
||||
@/* */
|
||||
@/* This function saves the context of an executing thread in the */
|
||||
@/* beginning of interrupt processing. The function also ensures that */
|
||||
@/* the system stack is used upon return to the calling ISR. */
|
||||
@/* */
|
||||
@/* INPUT */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* OUTPUT */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* CALLS */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* CALLED BY */
|
||||
@/* */
|
||||
@/* ISRs */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@ VOID _tx_thread_fiq_context_save(VOID)
|
||||
@{
|
||||
.global _tx_thread_fiq_context_save
|
||||
.type _tx_thread_fiq_context_save,function
|
||||
_tx_thread_fiq_context_save:
|
||||
@
|
||||
@ /* Upon entry to this routine, it is assumed that IRQ interrupts are locked
|
||||
@ out, we are in IRQ mode, and all registers are intact. */
|
||||
@
|
||||
@ /* Check for a nested interrupt condition. */
|
||||
@ if (_tx_thread_system_state++)
|
||||
@ {
|
||||
@
|
||||
STMDB sp!, {r0-r3} @ Save some working registers
|
||||
LDR r3, =_tx_thread_system_state @ Pickup address of system state variable
|
||||
LDR r2, [r3] @ Pickup system state
|
||||
CMP r2, #0 @ Is this the first interrupt?
|
||||
BEQ __tx_thread_fiq_not_nested_save @ Yes, not a nested context save
|
||||
@
|
||||
@ /* Nested interrupt condition. */
|
||||
@
|
||||
ADD r2, r2, #1 @ Increment the interrupt counter
|
||||
STR r2, [r3] @ Store it back in the variable
|
||||
@
|
||||
@ /* Save the rest of the scratch registers on the stack and return to the
|
||||
@ calling ISR. */
|
||||
@
|
||||
MRS r0, SPSR @ Pickup saved SPSR
|
||||
SUB lr, lr, #4 @ Adjust point of interrupt
|
||||
STMDB sp!, {r0, r10, r12, lr} @ Store other registers
|
||||
@
|
||||
@ /* Return to the ISR. */
|
||||
@
|
||||
MOV r10, #0 @ Clear stack limit
|
||||
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
@
|
||||
@ /* Call the ISR enter function to indicate an ISR is executing. */
|
||||
@
|
||||
PUSH {lr} @ Save ISR lr
|
||||
BL _tx_execution_isr_enter @ Call the ISR enter function
|
||||
POP {lr} @ Recover ISR lr
|
||||
#endif
|
||||
|
||||
B __tx_fiq_processing_return @ Continue FIQ processing
|
||||
@
|
||||
__tx_thread_fiq_not_nested_save:
|
||||
@ }
|
||||
@
|
||||
@ /* Otherwise, not nested, check to see if a thread was running. */
|
||||
@ else if (_tx_thread_current_ptr)
|
||||
@ {
|
||||
@
|
||||
ADD r2, r2, #1 @ Increment the interrupt counter
|
||||
STR r2, [r3] @ Store it back in the variable
|
||||
LDR r1, =_tx_thread_current_ptr @ Pickup address of current thread ptr
|
||||
LDR r0, [r1] @ Pickup current thread pointer
|
||||
CMP r0, #0 @ Is it NULL?
|
||||
BEQ __tx_thread_fiq_idle_system_save @ If so, interrupt occurred in
|
||||
@ @ scheduling loop - nothing needs saving!
|
||||
@
|
||||
@ /* Save minimal context of interrupted thread. */
|
||||
@
|
||||
MRS r2, SPSR @ Pickup saved SPSR
|
||||
SUB lr, lr, #4 @ Adjust point of interrupt
|
||||
STMDB sp!, {r2, lr} @ Store other registers, Note that we don't
|
||||
@ @ need to save sl and ip since FIQ has
|
||||
@ @ copies of these registers. Nested
|
||||
@ @ interrupt processing does need to save
|
||||
@ @ these registers.
|
||||
@
|
||||
@ /* Save the current stack pointer in the thread's control block. */
|
||||
@ _tx_thread_current_ptr -> tx_thread_stack_ptr = sp;
|
||||
@
|
||||
@ /* Switch to the system stack. */
|
||||
@ sp = _tx_thread_system_stack_ptr;
|
||||
@
|
||||
MOV r10, #0 @ Clear stack limit
|
||||
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
@
|
||||
@ /* Call the ISR enter function to indicate an ISR is executing. */
|
||||
@
|
||||
PUSH {lr} @ Save ISR lr
|
||||
BL _tx_execution_isr_enter @ Call the ISR enter function
|
||||
POP {lr} @ Recover ISR lr
|
||||
#endif
|
||||
|
||||
B __tx_fiq_processing_return @ Continue FIQ processing
|
||||
@
|
||||
@ }
|
||||
@ else
|
||||
@ {
|
||||
@
|
||||
__tx_thread_fiq_idle_system_save:
|
||||
@
|
||||
@ /* Interrupt occurred in the scheduling loop. */
|
||||
@
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
@
|
||||
@ /* Call the ISR enter function to indicate an ISR is executing. */
|
||||
@
|
||||
PUSH {lr} @ Save ISR lr
|
||||
BL _tx_execution_isr_enter @ Call the ISR enter function
|
||||
POP {lr} @ Recover ISR lr
|
||||
#endif
|
||||
@
|
||||
@ /* Not much to do here, save the current SPSR and LR for possible
|
||||
@ use in IRQ interrupted in idle system conditions, and return to
|
||||
@ FIQ interrupt processing. */
|
||||
@
|
||||
MRS r0, SPSR @ Pickup saved SPSR
|
||||
SUB lr, lr, #4 @ Adjust point of interrupt
|
||||
STMDB sp!, {r0, lr} @ Store other registers that will get used
|
||||
@ @ or stripped off the stack in context
|
||||
@ @ restore
|
||||
B __tx_fiq_processing_return @ Continue FIQ processing
|
||||
@
|
||||
@ }
|
||||
@}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
@/***************************************************************************
|
||||
@ * Copyright (c) 2024 Microsoft Corporation
|
||||
@ * Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
@ *
|
||||
@ * This program and the accompanying materials are made available under the
|
||||
@ * terms of the MIT License which is available at
|
||||
@ * https://opensource.org/licenses/MIT.
|
||||
@ *
|
||||
@ * SPDX-License-Identifier: MIT
|
||||
@ **************************************************************************/
|
||||
@ Some portions generated by Claude Code (Opus 5).
|
||||
@
|
||||
@
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@/** */
|
||||
@/** ThreadX Component */
|
||||
@/** */
|
||||
@/** Thread */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
#ifdef TX_INCLUDE_USER_DEFINE_FILE
|
||||
#include "tx_user.h"
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_FIQ_SUPPORT
|
||||
DISABLE_INTS = 0xC0 @ Disable IRQ/FIQ interrupts
|
||||
#else
|
||||
DISABLE_INTS = 0x80 @ Disable IRQ interrupts
|
||||
#endif
|
||||
MODE_MASK = 0x1F @ Mode mask
|
||||
FIQ_MODE_BITS = 0x11 @ FIQ mode bits
|
||||
@
|
||||
@
|
||||
@/* No 16-bit Thumb mode veneer code is needed for _tx_thread_fiq_nesting_end
|
||||
@ since it will never be called 16-bit mode. */
|
||||
@
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_fiq_nesting_end Cortex-R52/GNU */
|
||||
@/* 6.5.2 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* Frédéric Desbiens, Eclipse Foundation */
|
||||
@/* */
|
||||
@/* Derived from the Cortex-R5/GNU port originally written by */
|
||||
@/* William E. Lamie, Microsoft Corporation. */
|
||||
@/* */
|
||||
@/* DESCRIPTION */
|
||||
@/* */
|
||||
@/* This function is called by the application from FIQ mode after */
|
||||
@/* _tx_thread_fiq_nesting_start has been called and switches the FIQ */
|
||||
@/* processing from system mode back to FIQ mode prior to the ISR */
|
||||
@/* calling _tx_thread_fiq_context_restore. Note that this function */
|
||||
@/* assumes the system stack pointer is in the same position after */
|
||||
@/* nesting start function was called. */
|
||||
@/* */
|
||||
@/* This function assumes that the system mode stack pointer was setup */
|
||||
@/* during low-level initialization (tx_initialize_low_level.s). */
|
||||
@/* */
|
||||
@/* This function returns with FIQ interrupts disabled. */
|
||||
@/* */
|
||||
@/* INPUT */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* OUTPUT */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* CALLS */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* CALLED BY */
|
||||
@/* */
|
||||
@/* ISRs */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@VOID _tx_thread_fiq_nesting_end(VOID)
|
||||
@{
|
||||
.global _tx_thread_fiq_nesting_end
|
||||
.type _tx_thread_fiq_nesting_end,function
|
||||
_tx_thread_fiq_nesting_end:
|
||||
MOV r3,lr @ Save ISR return address
|
||||
MRS r0, CPSR @ Pickup the CPSR
|
||||
ORR r0, r0, #DISABLE_INTS @ Build disable interrupt value
|
||||
MSR CPSR_c, r0 @ Disable interrupts
|
||||
LDMIA sp!, {r1, lr} @ Pickup saved lr (and r1 throw-away for
|
||||
@ 8-byte alignment logic)
|
||||
BIC r0, r0, #MODE_MASK @ Clear mode bits
|
||||
ORR r0, r0, #FIQ_MODE_BITS @ Build IRQ mode CPSR
|
||||
MSR CPSR_c, r0 @ Reenter IRQ mode
|
||||
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX r3 @ Return to caller
|
||||
#else
|
||||
MOV pc, r3 @ Return to caller
|
||||
#endif
|
||||
@}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
@/***************************************************************************
|
||||
@ * Copyright (c) 2024 Microsoft Corporation
|
||||
@ * Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
@ *
|
||||
@ * This program and the accompanying materials are made available under the
|
||||
@ * terms of the MIT License which is available at
|
||||
@ * https://opensource.org/licenses/MIT.
|
||||
@ *
|
||||
@ * SPDX-License-Identifier: MIT
|
||||
@ **************************************************************************/
|
||||
@ Some portions generated by Claude Code (Opus 5).
|
||||
@
|
||||
@
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@/** */
|
||||
@/** ThreadX Component */
|
||||
@/** */
|
||||
@/** Thread */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
#ifdef TX_INCLUDE_USER_DEFINE_FILE
|
||||
#include "tx_user.h"
|
||||
#endif
|
||||
|
||||
FIQ_DISABLE = 0x40 @ FIQ disable bit
|
||||
MODE_MASK = 0x1F @ Mode mask
|
||||
SYS_MODE_BITS = 0x1F @ System mode bits
|
||||
@
|
||||
@
|
||||
@/* No 16-bit Thumb mode veneer code is needed for _tx_thread_fiq_nesting_start
|
||||
@ since it will never be called 16-bit mode. */
|
||||
@
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_fiq_nesting_start Cortex-R52/GNU */
|
||||
@/* 6.5.2 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* Frédéric Desbiens, Eclipse Foundation */
|
||||
@/* */
|
||||
@/* Derived from the Cortex-R5/GNU port originally written by */
|
||||
@/* William E. Lamie, Microsoft Corporation. */
|
||||
@/* */
|
||||
@/* DESCRIPTION */
|
||||
@/* */
|
||||
@/* This function is called by the application from FIQ mode after */
|
||||
@/* _tx_thread_fiq_context_save has been called and switches the FIQ */
|
||||
@/* processing to the system mode so nested FIQ interrupt processing */
|
||||
@/* is possible (system mode has its own "lr" register). Note that */
|
||||
@/* this function assumes that the system mode stack pointer was setup */
|
||||
@/* during low-level initialization (tx_initialize_low_level.s). */
|
||||
@/* */
|
||||
@/* This function returns with FIQ interrupts enabled. */
|
||||
@/* */
|
||||
@/* INPUT */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* OUTPUT */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* CALLS */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* CALLED BY */
|
||||
@/* */
|
||||
@/* ISRs */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@VOID _tx_thread_fiq_nesting_start(VOID)
|
||||
@{
|
||||
.global _tx_thread_fiq_nesting_start
|
||||
.type _tx_thread_fiq_nesting_start,function
|
||||
_tx_thread_fiq_nesting_start:
|
||||
MOV r3,lr @ Save ISR return address
|
||||
MRS r0, CPSR @ Pickup the CPSR
|
||||
BIC r0, r0, #MODE_MASK @ Clear the mode bits
|
||||
ORR r0, r0, #SYS_MODE_BITS @ Build system mode CPSR
|
||||
MSR CPSR_c, r0 @ Enter system mode
|
||||
STMDB sp!, {r1, lr} @ Push the system mode lr on the system mode stack
|
||||
@ and push r1 just to keep 8-byte alignment
|
||||
BIC r0, r0, #FIQ_DISABLE @ Build enable FIQ CPSR
|
||||
MSR CPSR_c, r0 @ Enter system mode
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX r3 @ Return to caller
|
||||
#else
|
||||
MOV pc, r3 @ Return to caller
|
||||
#endif
|
||||
@}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
@/***************************************************************************
|
||||
@ * Copyright (c) 2024 Microsoft Corporation
|
||||
@ * Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
@ *
|
||||
@ * This program and the accompanying materials are made available under the
|
||||
@ * terms of the MIT License which is available at
|
||||
@ * https://opensource.org/licenses/MIT.
|
||||
@ *
|
||||
@ * SPDX-License-Identifier: MIT
|
||||
@ **************************************************************************/
|
||||
@ Some portions generated by Claude Code (Opus 5).
|
||||
@
|
||||
@
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@/** */
|
||||
@/** ThreadX Component */
|
||||
@/** */
|
||||
@/** Thread */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
#ifdef TX_INCLUDE_USER_DEFINE_FILE
|
||||
#include "tx_user.h"
|
||||
#endif
|
||||
|
||||
|
||||
INT_MASK = 0x03F
|
||||
|
||||
@
|
||||
@/* Define the 16-bit Thumb mode veneer for _tx_thread_interrupt_control for
|
||||
@ applications calling this function from to 16-bit Thumb mode. */
|
||||
@
|
||||
.text
|
||||
.align 2
|
||||
.global $_tx_thread_interrupt_control
|
||||
$_tx_thread_interrupt_control:
|
||||
.thumb
|
||||
BX pc @ Switch to 32-bit mode
|
||||
NOP @
|
||||
.arm
|
||||
STMFD sp!, {lr} @ Save return address
|
||||
BL _tx_thread_interrupt_control @ Call _tx_thread_interrupt_control function
|
||||
LDMFD sp!, {lr} @ Recover saved return address
|
||||
BX lr @ Return to 16-bit caller
|
||||
@
|
||||
@
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_interrupt_control Cortex-R52/GNU */
|
||||
@/* 6.5.2 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* Frédéric Desbiens, Eclipse Foundation */
|
||||
@/* */
|
||||
@/* Derived from the Cortex-R5/GNU port originally written by */
|
||||
@/* William E. Lamie, Microsoft Corporation. */
|
||||
@/* */
|
||||
@/* DESCRIPTION */
|
||||
@/* */
|
||||
@/* This function is responsible for changing the interrupt lockout */
|
||||
@/* posture of the system. */
|
||||
@/* */
|
||||
@/* INPUT */
|
||||
@/* */
|
||||
@/* new_posture New interrupt lockout posture */
|
||||
@/* */
|
||||
@/* OUTPUT */
|
||||
@/* */
|
||||
@/* old_posture Old interrupt lockout posture */
|
||||
@/* */
|
||||
@/* CALLS */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* CALLED BY */
|
||||
@/* */
|
||||
@/* Application Code */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@UINT _tx_thread_interrupt_control(UINT new_posture)
|
||||
@{
|
||||
.global _tx_thread_interrupt_control
|
||||
.type _tx_thread_interrupt_control,function
|
||||
_tx_thread_interrupt_control:
|
||||
@
|
||||
@ /* Pickup current interrupt lockout posture. */
|
||||
@
|
||||
MRS r3, CPSR @ Pickup current CPSR
|
||||
MOV r2, #INT_MASK @ Build interrupt mask
|
||||
AND r1, r3, r2 @ Clear interrupt lockout bits
|
||||
ORR r1, r1, r0 @ Or-in new interrupt lockout bits
|
||||
@
|
||||
@ /* Apply the new interrupt posture. */
|
||||
@
|
||||
MSR CPSR_c, r1 @ Setup new CPSR
|
||||
BIC r0, r3, r2 @ Return previous interrupt mask
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX lr @ Return to caller
|
||||
#else
|
||||
MOV pc, lr @ Return to caller
|
||||
#endif
|
||||
@}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
@/***************************************************************************
|
||||
@ * Copyright (c) 2024 Microsoft Corporation
|
||||
@ * Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
@ *
|
||||
@ * This program and the accompanying materials are made available under the
|
||||
@ * terms of the MIT License which is available at
|
||||
@ * https://opensource.org/licenses/MIT.
|
||||
@ *
|
||||
@ * SPDX-License-Identifier: MIT
|
||||
@ **************************************************************************/
|
||||
@ Some portions generated by Claude Code (Opus 5).
|
||||
@
|
||||
@
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@/** */
|
||||
@/** ThreadX Component */
|
||||
@/** */
|
||||
@/** Thread */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
#ifdef TX_INCLUDE_USER_DEFINE_FILE
|
||||
#include "tx_user.h"
|
||||
#endif
|
||||
|
||||
@/* Define the 16-bit Thumb mode veneer for _tx_thread_interrupt_disable for
|
||||
@ applications calling this function from to 16-bit Thumb mode. */
|
||||
@
|
||||
.text
|
||||
.align 2
|
||||
.global $_tx_thread_interrupt_disable
|
||||
$_tx_thread_interrupt_disable:
|
||||
.thumb
|
||||
BX pc @ Switch to 32-bit mode
|
||||
NOP @
|
||||
.arm
|
||||
STMFD sp!, {lr} @ Save return address
|
||||
BL _tx_thread_interrupt_disable @ Call _tx_thread_interrupt_disable function
|
||||
LDMFD sp!, {lr} @ Recover saved return address
|
||||
BX lr @ Return to 16-bit caller
|
||||
@
|
||||
@
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_interrupt_disable Cortex-R52/GNU */
|
||||
@/* 6.5.2 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* Frédéric Desbiens, Eclipse Foundation */
|
||||
@/* */
|
||||
@/* Derived from the Cortex-R5/GNU port originally written by */
|
||||
@/* William E. Lamie, Microsoft Corporation. */
|
||||
@/* */
|
||||
@/* DESCRIPTION */
|
||||
@/* */
|
||||
@/* This function is responsible for disabling interrupts */
|
||||
@/* */
|
||||
@/* INPUT */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* OUTPUT */
|
||||
@/* */
|
||||
@/* old_posture Old interrupt lockout posture */
|
||||
@/* */
|
||||
@/* CALLS */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* CALLED BY */
|
||||
@/* */
|
||||
@/* Application Code */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@UINT _tx_thread_interrupt_disable(void)
|
||||
@{
|
||||
.global _tx_thread_interrupt_disable
|
||||
.type _tx_thread_interrupt_disable,function
|
||||
_tx_thread_interrupt_disable:
|
||||
@
|
||||
@ /* Pickup current interrupt lockout posture. */
|
||||
@
|
||||
MRS r0, CPSR @ Pickup current CPSR
|
||||
@
|
||||
@ /* Mask interrupts. */
|
||||
@
|
||||
#ifdef TX_ENABLE_FIQ_SUPPORT
|
||||
CPSID if @ Disable IRQ and FIQ
|
||||
#else
|
||||
CPSID i @ Disable IRQ
|
||||
#endif
|
||||
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX lr @ Return to caller
|
||||
#else
|
||||
MOV pc, lr @ Return to caller
|
||||
#endif
|
||||
@}
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
@/***************************************************************************
|
||||
@ * Copyright (c) 2024 Microsoft Corporation
|
||||
@ * Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
@ *
|
||||
@ * This program and the accompanying materials are made available under the
|
||||
@ * terms of the MIT License which is available at
|
||||
@ * https://opensource.org/licenses/MIT.
|
||||
@ *
|
||||
@ * SPDX-License-Identifier: MIT
|
||||
@ **************************************************************************/
|
||||
@ Some portions generated by Claude Code (Opus 5).
|
||||
@
|
||||
@
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@/** */
|
||||
@/** ThreadX Component */
|
||||
@/** */
|
||||
@/** Thread */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
#ifdef TX_INCLUDE_USER_DEFINE_FILE
|
||||
#include "tx_user.h"
|
||||
#endif
|
||||
|
||||
@/* Define the 16-bit Thumb mode veneer for _tx_thread_interrupt_restore for
|
||||
@ applications calling this function from to 16-bit Thumb mode. */
|
||||
@
|
||||
.text
|
||||
.align 2
|
||||
.global $_tx_thread_interrupt_restore
|
||||
$_tx_thread_interrupt_restore:
|
||||
.thumb
|
||||
BX pc @ Switch to 32-bit mode
|
||||
NOP @
|
||||
.arm
|
||||
STMFD sp!, {lr} @ Save return address
|
||||
BL _tx_thread_interrupt_restore @ Call _tx_thread_interrupt_restore function
|
||||
LDMFD sp!, {lr} @ Recover saved return address
|
||||
BX lr @ Return to 16-bit caller
|
||||
@
|
||||
@
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_interrupt_restore Cortex-R52/GNU */
|
||||
@/* 6.5.2 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* Frédéric Desbiens, Eclipse Foundation */
|
||||
@/* */
|
||||
@/* Derived from the Cortex-R5/GNU port originally written by */
|
||||
@/* William E. Lamie, Microsoft Corporation. */
|
||||
@/* */
|
||||
@/* DESCRIPTION */
|
||||
@/* */
|
||||
@/* This function is responsible for restoring interrupts to the state */
|
||||
@/* returned by a previous _tx_thread_interrupt_disable call. */
|
||||
@/* */
|
||||
@/* INPUT */
|
||||
@/* */
|
||||
@/* old_posture Old interrupt lockout posture */
|
||||
@/* */
|
||||
@/* OUTPUT */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* CALLS */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* CALLED BY */
|
||||
@/* */
|
||||
@/* Application Code */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@UINT _tx_thread_interrupt_restore(UINT old_posture)
|
||||
@{
|
||||
.global _tx_thread_interrupt_restore
|
||||
.type _tx_thread_interrupt_restore,function
|
||||
_tx_thread_interrupt_restore:
|
||||
@
|
||||
@ /* Apply the new interrupt posture. */
|
||||
@
|
||||
MSR CPSR_c, r0 @ Setup new CPSR
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX lr @ Return to caller
|
||||
#else
|
||||
MOV pc, lr @ Return to caller
|
||||
#endif
|
||||
@}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
@/***************************************************************************
|
||||
@ * Copyright (c) 2024 Microsoft Corporation
|
||||
@ * Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
@ *
|
||||
@ * This program and the accompanying materials are made available under the
|
||||
@ * terms of the MIT License which is available at
|
||||
@ * https://opensource.org/licenses/MIT.
|
||||
@ *
|
||||
@ * SPDX-License-Identifier: MIT
|
||||
@ **************************************************************************/
|
||||
@ Some portions generated by Claude Code (Opus 5).
|
||||
@
|
||||
@
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@/** */
|
||||
@/** ThreadX Component */
|
||||
@/** */
|
||||
@/** Thread */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
#ifdef TX_INCLUDE_USER_DEFINE_FILE
|
||||
#include "tx_user.h"
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_FIQ_SUPPORT
|
||||
DISABLE_INTS = 0xC0 @ Disable IRQ/FIQ interrupts
|
||||
#else
|
||||
DISABLE_INTS = 0x80 @ Disable IRQ interrupts
|
||||
#endif
|
||||
MODE_MASK = 0x1F @ Mode mask
|
||||
IRQ_MODE_BITS = 0x12 @ IRQ mode bits
|
||||
@
|
||||
@
|
||||
@/* No 16-bit Thumb mode veneer code is needed for _tx_thread_irq_nesting_end
|
||||
@ since it will never be called 16-bit mode. */
|
||||
@
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_irq_nesting_end Cortex-R52/GNU */
|
||||
@/* 6.5.2 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* Frédéric Desbiens, Eclipse Foundation */
|
||||
@/* */
|
||||
@/* Derived from the Cortex-R5/GNU port originally written by */
|
||||
@/* William E. Lamie, Microsoft Corporation. */
|
||||
@/* */
|
||||
@/* DESCRIPTION */
|
||||
@/* */
|
||||
@/* This function is called by the application from IRQ mode after */
|
||||
@/* _tx_thread_irq_nesting_start has been called and switches the IRQ */
|
||||
@/* processing from system mode back to IRQ mode prior to the ISR */
|
||||
@/* calling _tx_thread_context_restore. Note that this function */
|
||||
@/* assumes the system stack pointer is in the same position after */
|
||||
@/* nesting start function was called. */
|
||||
@/* */
|
||||
@/* This function assumes that the system mode stack pointer was setup */
|
||||
@/* during low-level initialization (tx_initialize_low_level.s). */
|
||||
@/* */
|
||||
@/* This function returns with IRQ interrupts disabled. */
|
||||
@/* */
|
||||
@/* INPUT */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* OUTPUT */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* CALLS */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* CALLED BY */
|
||||
@/* */
|
||||
@/* ISRs */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@VOID _tx_thread_irq_nesting_end(VOID)
|
||||
@{
|
||||
.global _tx_thread_irq_nesting_end
|
||||
.type _tx_thread_irq_nesting_end,function
|
||||
_tx_thread_irq_nesting_end:
|
||||
MOV r3,lr @ Save ISR return address
|
||||
MRS r0, CPSR @ Pickup the CPSR
|
||||
ORR r0, r0, #DISABLE_INTS @ Build disable interrupt value
|
||||
MSR CPSR_c, r0 @ Disable interrupts
|
||||
LDMIA sp!, {r1, lr} @ Pickup saved lr (and r1 throw-away for
|
||||
@ 8-byte alignment logic)
|
||||
BIC r0, r0, #MODE_MASK @ Clear mode bits
|
||||
ORR r0, r0, #IRQ_MODE_BITS @ Build IRQ mode CPSR
|
||||
MSR CPSR_c, r0 @ Reenter IRQ mode
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX r3 @ Return to caller
|
||||
#else
|
||||
MOV pc, r3 @ Return to caller
|
||||
#endif
|
||||
@}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
@/***************************************************************************
|
||||
@ * Copyright (c) 2024 Microsoft Corporation
|
||||
@ * Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
@ *
|
||||
@ * This program and the accompanying materials are made available under the
|
||||
@ * terms of the MIT License which is available at
|
||||
@ * https://opensource.org/licenses/MIT.
|
||||
@ *
|
||||
@ * SPDX-License-Identifier: MIT
|
||||
@ **************************************************************************/
|
||||
@ Some portions generated by Claude Code (Opus 5).
|
||||
@
|
||||
@
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@/** */
|
||||
@/** ThreadX Component */
|
||||
@/** */
|
||||
@/** Thread */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
#ifdef TX_INCLUDE_USER_DEFINE_FILE
|
||||
#include "tx_user.h"
|
||||
#endif
|
||||
|
||||
IRQ_DISABLE = 0x80 @ IRQ disable bit
|
||||
MODE_MASK = 0x1F @ Mode mask
|
||||
SYS_MODE_BITS = 0x1F @ System mode bits
|
||||
@
|
||||
@
|
||||
@/* No 16-bit Thumb mode veneer code is needed for _tx_thread_irq_nesting_start
|
||||
@ since it will never be called 16-bit mode. */
|
||||
@
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_irq_nesting_start Cortex-R52/GNU */
|
||||
@/* 6.5.2 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* Frédéric Desbiens, Eclipse Foundation */
|
||||
@/* */
|
||||
@/* Derived from the Cortex-R5/GNU port originally written by */
|
||||
@/* William E. Lamie, Microsoft Corporation. */
|
||||
@/* */
|
||||
@/* DESCRIPTION */
|
||||
@/* */
|
||||
@/* This function is called by the application from IRQ mode after */
|
||||
@/* _tx_thread_context_save has been called and switches the IRQ */
|
||||
@/* processing to the system mode so nested IRQ interrupt processing */
|
||||
@/* is possible (system mode has its own "lr" register). Note that */
|
||||
@/* this function assumes that the system mode stack pointer was setup */
|
||||
@/* during low-level initialization (tx_initialize_low_level.s). */
|
||||
@/* */
|
||||
@/* This function returns with IRQ interrupts enabled. */
|
||||
@/* */
|
||||
@/* INPUT */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* OUTPUT */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* CALLS */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* CALLED BY */
|
||||
@/* */
|
||||
@/* ISRs */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@VOID _tx_thread_irq_nesting_start(VOID)
|
||||
@{
|
||||
.global _tx_thread_irq_nesting_start
|
||||
.type _tx_thread_irq_nesting_start,function
|
||||
_tx_thread_irq_nesting_start:
|
||||
MOV r3,lr @ Save ISR return address
|
||||
MRS r0, CPSR @ Pickup the CPSR
|
||||
BIC r0, r0, #MODE_MASK @ Clear the mode bits
|
||||
ORR r0, r0, #SYS_MODE_BITS @ Build system mode CPSR
|
||||
MSR CPSR_c, r0 @ Enter system mode
|
||||
STMDB sp!, {r1, lr} @ Push the system mode lr on the system mode stack
|
||||
@ and push r1 just to keep 8-byte alignment
|
||||
BIC r0, r0, #IRQ_DISABLE @ Build enable IRQ CPSR
|
||||
MSR CPSR_c, r0 @ Enter system mode
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX r3 @ Return to caller
|
||||
#else
|
||||
MOV pc, r3 @ Return to caller
|
||||
#endif
|
||||
@}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,170 @@
|
||||
@/***************************************************************************
|
||||
@ * Copyright (c) 2024 Microsoft Corporation
|
||||
@ * Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
@ *
|
||||
@ * This program and the accompanying materials are made available under the
|
||||
@ * terms of the MIT License which is available at
|
||||
@ * https://opensource.org/licenses/MIT.
|
||||
@ *
|
||||
@ * SPDX-License-Identifier: MIT
|
||||
@ **************************************************************************/
|
||||
@ Some portions generated by Claude Code (Opus 5).
|
||||
@
|
||||
@
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@/** */
|
||||
@/** ThreadX Component */
|
||||
@/** */
|
||||
@/** Thread */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
#ifdef TX_INCLUDE_USER_DEFINE_FILE
|
||||
#include "tx_user.h"
|
||||
#endif
|
||||
|
||||
.arm
|
||||
|
||||
SVC_MODE = 0x13 @ SVC mode
|
||||
#ifdef TX_ENABLE_FIQ_SUPPORT
|
||||
CPSR_MASK = 0xDF @ Mask initial CPSR, IRQ & FIQ interrupts enabled
|
||||
#else
|
||||
CPSR_MASK = 0x9F @ Mask initial CPSR, IRQ interrupts enabled
|
||||
#endif
|
||||
@
|
||||
@
|
||||
@/* Define the 16-bit Thumb mode veneer for _tx_thread_stack_build for
|
||||
@ applications calling this function from to 16-bit Thumb mode. */
|
||||
@
|
||||
.text
|
||||
.align 2
|
||||
.thumb
|
||||
.global $_tx_thread_stack_build
|
||||
.type $_tx_thread_stack_build,function
|
||||
$_tx_thread_stack_build:
|
||||
BX pc @ Switch to 32-bit mode
|
||||
NOP @
|
||||
.arm
|
||||
STMFD sp!, {lr} @ Save return address
|
||||
BL _tx_thread_stack_build @ Call _tx_thread_stack_build function
|
||||
LDMFD sp!, {lr} @ Recover saved return address
|
||||
BX lr @ Return to 16-bit caller
|
||||
@
|
||||
@
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_stack_build Cortex-R52/GNU */
|
||||
@/* 6.5.2 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* Frédéric Desbiens, Eclipse Foundation */
|
||||
@/* */
|
||||
@/* Derived from the Cortex-R5/GNU port originally written by */
|
||||
@/* William E. Lamie, Microsoft Corporation. */
|
||||
@/* */
|
||||
@/* DESCRIPTION */
|
||||
@/* */
|
||||
@/* This function builds a stack frame on the supplied thread's stack. */
|
||||
@/* The stack frame results in a fake interrupt return to the supplied */
|
||||
@/* function pointer. */
|
||||
@/* */
|
||||
@/* INPUT */
|
||||
@/* */
|
||||
@/* thread_ptr Pointer to thread control blk */
|
||||
@/* function_ptr Pointer to return function */
|
||||
@/* */
|
||||
@/* OUTPUT */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* CALLS */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* CALLED BY */
|
||||
@/* */
|
||||
@/* _tx_thread_create Create thread service */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID))
|
||||
@{
|
||||
.global _tx_thread_stack_build
|
||||
.type _tx_thread_stack_build,function
|
||||
_tx_thread_stack_build:
|
||||
@
|
||||
@
|
||||
@ /* Build a fake interrupt frame. The form of the fake interrupt stack
|
||||
@ on the ARM9 should look like the following after it is built:
|
||||
@
|
||||
@ Stack Top: 1 Interrupt stack frame type
|
||||
@ CPSR Initial value for CPSR
|
||||
@ a1 (r0) Initial value for a1
|
||||
@ a2 (r1) Initial value for a2
|
||||
@ a3 (r2) Initial value for a3
|
||||
@ a4 (r3) Initial value for a4
|
||||
@ v1 (r4) Initial value for v1
|
||||
@ v2 (r5) Initial value for v2
|
||||
@ v3 (r6) Initial value for v3
|
||||
@ v4 (r7) Initial value for v4
|
||||
@ v5 (r8) Initial value for v5
|
||||
@ sb (r9) Initial value for sb
|
||||
@ sl (r10) Initial value for sl
|
||||
@ fp (r11) Initial value for fp
|
||||
@ ip (r12) Initial value for ip
|
||||
@ lr (r14) Initial value for lr
|
||||
@ pc (r15) Initial value for pc
|
||||
@ 0 For stack backtracing
|
||||
@
|
||||
@ Stack Bottom: (higher memory address) */
|
||||
@
|
||||
LDR r2, [r0, #16] @ Pickup end of stack area
|
||||
BIC r2, r2, #7 @ Ensure 8-byte alignment
|
||||
SUB r2, r2, #76 @ Allocate space for the stack frame
|
||||
@
|
||||
@ /* Actually build the stack frame. */
|
||||
@
|
||||
MOV r3, #1 @ Build interrupt stack type
|
||||
STR r3, [r2, #0] @ Store stack type
|
||||
MOV r3, #0 @ Build initial register value
|
||||
STR r3, [r2, #8] @ Store initial r0
|
||||
STR r3, [r2, #12] @ Store initial r1
|
||||
STR r3, [r2, #16] @ Store initial r2
|
||||
STR r3, [r2, #20] @ Store initial r3
|
||||
STR r3, [r2, #24] @ Store initial r4
|
||||
STR r3, [r2, #28] @ Store initial r5
|
||||
STR r3, [r2, #32] @ Store initial r6
|
||||
STR r3, [r2, #36] @ Store initial r7
|
||||
STR r3, [r2, #40] @ Store initial r8
|
||||
STR r3, [r2, #44] @ Store initial r9
|
||||
LDR r3, [r0, #12] @ Pickup stack starting address
|
||||
STR r3, [r2, #48] @ Store initial r10 (sl)
|
||||
LDR r3,=_tx_thread_schedule @ Pickup address of _tx_thread_schedule for GDB backtrace
|
||||
STR r3, [r2, #60] @ Store initial r14 (lr)
|
||||
MOV r3, #0 @ Build initial register value
|
||||
STR r3, [r2, #52] @ Store initial r11
|
||||
STR r3, [r2, #56] @ Store initial r12
|
||||
STR r1, [r2, #64] @ Store initial pc
|
||||
STR r3, [r2, #68] @ 0 for back-trace
|
||||
MRS r1, CPSR @ Pickup CPSR
|
||||
BIC r1, r1, #CPSR_MASK @ Mask mode bits of CPSR
|
||||
ORR r3, r1, #SVC_MODE @ Build CPSR, SVC mode, interrupts enabled
|
||||
STR r3, [r2, #4] @ Store initial CPSR
|
||||
@
|
||||
@ /* Setup stack pointer. */
|
||||
@ thread_ptr -> tx_thread_stack_ptr = r2;
|
||||
@
|
||||
STR r2, [r0, #8] @ Save stack pointer in thread's
|
||||
@ control block
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX lr @ Return to caller
|
||||
#else
|
||||
MOV pc, lr @ Return to caller
|
||||
#endif
|
||||
@}
|
||||
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
@/***************************************************************************
|
||||
@ * Copyright (c) 2024 Microsoft Corporation
|
||||
@ * Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
@ *
|
||||
@ * This program and the accompanying materials are made available under the
|
||||
@ * terms of the MIT License which is available at
|
||||
@ * https://opensource.org/licenses/MIT.
|
||||
@ *
|
||||
@ * SPDX-License-Identifier: MIT
|
||||
@ **************************************************************************/
|
||||
@ Some portions generated by Claude Code (Opus 5).
|
||||
@
|
||||
@
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@/** */
|
||||
@/** ThreadX Component */
|
||||
@/** */
|
||||
@/** Thread */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
#ifdef TX_INCLUDE_USER_DEFINE_FILE
|
||||
#include "tx_user.h"
|
||||
#endif
|
||||
|
||||
.arm
|
||||
@
|
||||
@
|
||||
.global _tx_thread_current_ptr
|
||||
.global _tx_timer_time_slice
|
||||
.global _tx_thread_schedule
|
||||
.global _tx_execution_thread_exit
|
||||
@
|
||||
@
|
||||
@
|
||||
@/* Define the 16-bit Thumb mode veneer for _tx_thread_system_return for
|
||||
@ applications calling this function from to 16-bit Thumb mode. */
|
||||
@
|
||||
.text
|
||||
.align 2
|
||||
.global $_tx_thread_system_return
|
||||
.type $_tx_thread_system_return,function
|
||||
$_tx_thread_system_return:
|
||||
.thumb
|
||||
BX pc @ Switch to 32-bit mode
|
||||
NOP @
|
||||
.arm
|
||||
STMFD sp!, {lr} @ Save return address
|
||||
BL _tx_thread_system_return @ Call _tx_thread_system_return function
|
||||
LDMFD sp!, {lr} @ Recover saved return address
|
||||
BX lr @ Return to 16-bit caller
|
||||
@
|
||||
@
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_system_return Cortex-R52/GNU */
|
||||
@/* 6.5.2 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* Frédéric Desbiens, Eclipse Foundation */
|
||||
@/* */
|
||||
@/* Derived from the Cortex-R5/GNU port originally written by */
|
||||
@/* William E. Lamie, Microsoft Corporation. */
|
||||
@/* */
|
||||
@/* DESCRIPTION */
|
||||
@/* */
|
||||
@/* This function is target processor specific. It is used to transfer */
|
||||
@/* control from a thread back to the ThreadX system. Only a */
|
||||
@/* minimal context is saved since the compiler assumes temp registers */
|
||||
@/* are going to get slicked by a function call anyway. */
|
||||
@/* */
|
||||
@/* INPUT */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* OUTPUT */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* CALLS */
|
||||
@/* */
|
||||
@/* _tx_thread_schedule Thread scheduling loop */
|
||||
@/* */
|
||||
@/* CALLED BY */
|
||||
@/* */
|
||||
@/* ThreadX components */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@VOID _tx_thread_system_return(VOID)
|
||||
@{
|
||||
.global _tx_thread_system_return
|
||||
.type _tx_thread_system_return,function
|
||||
_tx_thread_system_return:
|
||||
@
|
||||
@ /* Lockout interrupts. */
|
||||
@
|
||||
MRS r1, CPSR @ Pickup the CPSR
|
||||
#ifdef TX_ENABLE_FIQ_SUPPORT
|
||||
CPSID if @ Disable IRQ and FIQ interrupts
|
||||
#else
|
||||
CPSID i @ Disable IRQ interrupts
|
||||
#endif
|
||||
@ /* Save minimal context on the stack. */
|
||||
@
|
||||
STMDB sp!, {r4-r11, lr} @ Save minimal context
|
||||
LDR r5, =_tx_thread_current_ptr @ Pickup address of current ptr
|
||||
LDR r6, [r5, #0] @ Pickup current thread pointer
|
||||
@
|
||||
#ifdef TX_ENABLE_VFP_SUPPORT
|
||||
LDR r0, [r6, #144] @ Pickup the VFP enabled flag
|
||||
CMP r0, #0 @ Is the VFP enabled?
|
||||
BEQ _tx_skip_solicited_vfp_save @ No, skip VFP solicited save
|
||||
VMRS r4, FPSCR @ Pickup the FPSCR
|
||||
STR r4, [sp, #-4]! @ Save FPSCR
|
||||
VSTMDB sp!, {D8-D15} @ Save D8-D15
|
||||
_tx_skip_solicited_vfp_save:
|
||||
#endif
|
||||
@
|
||||
MOV r0, #0 @ Build a solicited stack type
|
||||
STMDB sp!, {r0-r1} @ Save type and CPSR
|
||||
@
|
||||
@
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
@
|
||||
@ /* Call the thread exit function to indicate the thread is no longer executing. */
|
||||
@
|
||||
BL _tx_execution_thread_exit @ Call the thread exit function
|
||||
#endif
|
||||
@
|
||||
LDR r2, =_tx_timer_time_slice @ Pickup address of time slice
|
||||
LDR r1, [r2, #0] @ Pickup current time slice
|
||||
@
|
||||
@ /* Save current stack and switch to system stack. */
|
||||
@ _tx_thread_current_ptr -> tx_thread_stack_ptr = sp;
|
||||
@ sp = _tx_thread_system_stack_ptr;
|
||||
@
|
||||
STR sp, [r6, #8] @ Save thread stack pointer
|
||||
@
|
||||
@ /* Determine if the time-slice is active. */
|
||||
@ if (_tx_timer_time_slice)
|
||||
@ {
|
||||
@
|
||||
MOV r4, #0 @ Build clear value
|
||||
CMP r1, #0 @ Is a time-slice active?
|
||||
BEQ __tx_thread_dont_save_ts @ No, don't save the time-slice
|
||||
@
|
||||
@ /* Save time-slice for the thread and clear the current time-slice. */
|
||||
@ _tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice;
|
||||
@ _tx_timer_time_slice = 0;
|
||||
@
|
||||
STR r4, [r2, #0] @ Clear time-slice
|
||||
STR r1, [r6, #24] @ Save current time-slice
|
||||
@
|
||||
@ }
|
||||
__tx_thread_dont_save_ts:
|
||||
@
|
||||
@ /* Clear the current thread pointer. */
|
||||
@ _tx_thread_current_ptr = TX_NULL;
|
||||
@
|
||||
STR r4, [r5, #0] @ Clear current thread pointer
|
||||
B _tx_thread_schedule @ Jump to scheduler!
|
||||
@
|
||||
@}
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
@/***************************************************************************
|
||||
@ * Copyright (c) 2024 Microsoft Corporation
|
||||
@ * Copyright (c) 2026 Eclipse ThreadX contributors
|
||||
@ *
|
||||
@ * This program and the accompanying materials are made available under the
|
||||
@ * terms of the MIT License which is available at
|
||||
@ * https://opensource.org/licenses/MIT.
|
||||
@ *
|
||||
@ * SPDX-License-Identifier: MIT
|
||||
@ **************************************************************************/
|
||||
@ Some portions generated by Claude Code (Opus 5).
|
||||
@
|
||||
@
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@/** */
|
||||
@/** ThreadX Component */
|
||||
@/** */
|
||||
@/** Thread */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
#ifdef TX_INCLUDE_USER_DEFINE_FILE
|
||||
#include "tx_user.h"
|
||||
#endif
|
||||
|
||||
.global _tx_thread_system_state
|
||||
.global _tx_thread_current_ptr
|
||||
.global _tx_execution_isr_enter
|
||||
@
|
||||
@
|
||||
@
|
||||
@/* No 16-bit Thumb mode veneer code is needed for _tx_thread_vectored_context_save
|
||||
@ since it will never be called 16-bit mode. */
|
||||
@
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_vectored_context_save Cortex-R52/GNU */
|
||||
@/* 6.5.2 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* Frédéric Desbiens, Eclipse Foundation */
|
||||
@/* */
|
||||
@/* Derived from the Cortex-R5/GNU port originally written by */
|
||||
@/* William E. Lamie, Microsoft Corporation. */
|
||||
@/* */
|
||||
@/* DESCRIPTION */
|
||||
@/* */
|
||||
@/* This function saves the context of an executing thread in the */
|
||||
@/* beginning of interrupt processing. The function also ensures that */
|
||||
@/* the system stack is used upon return to the calling ISR. */
|
||||
@/* */
|
||||
@/* INPUT */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* OUTPUT */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* CALLS */
|
||||
@/* */
|
||||
@/* None */
|
||||
@/* */
|
||||
@/* CALLED BY */
|
||||
@/* */
|
||||
@/* ISRs */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@VOID _tx_thread_vectored_context_save(VOID)
|
||||
@{
|
||||
.global _tx_thread_vectored_context_save
|
||||
.type _tx_thread_vectored_context_save,function
|
||||
_tx_thread_vectored_context_save:
|
||||
@
|
||||
@ /* Upon entry to this routine, it is assumed that IRQ interrupts are locked
|
||||
@ out, we are in IRQ mode, and all registers are intact. */
|
||||
@
|
||||
@ /* Check for a nested interrupt condition. */
|
||||
@ if (_tx_thread_system_state++)
|
||||
@ {
|
||||
@
|
||||
#ifdef TX_ENABLE_FIQ_SUPPORT
|
||||
CPSID if @ Disable IRQ and FIQ interrupts
|
||||
#endif
|
||||
LDR r3, =_tx_thread_system_state @ Pickup address of system state variable
|
||||
LDR r2, [r3, #0] @ Pickup system state
|
||||
CMP r2, #0 @ Is this the first interrupt?
|
||||
BEQ __tx_thread_not_nested_save @ Yes, not a nested context save
|
||||
@
|
||||
@ /* Nested interrupt condition. */
|
||||
@
|
||||
ADD r2, r2, #1 @ Increment the interrupt counter
|
||||
STR r2, [r3, #0] @ Store it back in the variable
|
||||
@
|
||||
@ /* Note: Minimal context of interrupted thread is already saved. */
|
||||
@
|
||||
@ /* Return to the ISR. */
|
||||
@
|
||||
MOV r10, #0 @ Clear stack limit
|
||||
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
@
|
||||
@ /* Call the ISR enter function to indicate an ISR is executing. */
|
||||
@
|
||||
PUSH {lr} @ Save ISR lr
|
||||
BL _tx_execution_isr_enter @ Call the ISR enter function
|
||||
POP {lr} @ Recover ISR lr
|
||||
#endif
|
||||
|
||||
MOV pc, lr @ Return to caller
|
||||
@
|
||||
__tx_thread_not_nested_save:
|
||||
@ }
|
||||
@
|
||||
@ /* Otherwise, not nested, check to see if a thread was running. */
|
||||
@ else if (_tx_thread_current_ptr)
|
||||
@ {
|
||||
@
|
||||
ADD r2, r2, #1 @ Increment the interrupt counter
|
||||
STR r2, [r3, #0] @ Store it back in the variable
|
||||
LDR r1, =_tx_thread_current_ptr @ Pickup address of current thread ptr
|
||||
LDR r0, [r1, #0] @ Pickup current thread pointer
|
||||
CMP r0, #0 @ Is it NULL?
|
||||
BEQ __tx_thread_idle_system_save @ If so, interrupt occurred in
|
||||
@ scheduling loop - nothing needs saving!
|
||||
@
|
||||
@ /* Note: Minimal context of interrupted thread is already saved. */
|
||||
@
|
||||
@ /* Save the current stack pointer in the thread's control block. */
|
||||
@ _tx_thread_current_ptr -> tx_thread_stack_ptr = sp;
|
||||
@
|
||||
@ /* Switch to the system stack. */
|
||||
@ sp = _tx_thread_system_stack_ptr;
|
||||
@
|
||||
MOV r10, #0 @ Clear stack limit
|
||||
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
@
|
||||
@ /* Call the ISR enter function to indicate an ISR is executing. */
|
||||
@
|
||||
PUSH {lr} @ Save ISR lr
|
||||
BL _tx_execution_isr_enter @ Call the ISR enter function
|
||||
POP {lr} @ Recover ISR lr
|
||||
#endif
|
||||
|
||||
MOV pc, lr @ Return to caller
|
||||
@
|
||||
@ }
|
||||
@ else
|
||||
@ {
|
||||
@
|
||||
__tx_thread_idle_system_save:
|
||||
@
|
||||
@ /* Interrupt occurred in the scheduling loop. */
|
||||
@
|
||||
@ /* Not much to do here, just adjust the stack pointer, and return to IRQ
|
||||
@ processing. */
|
||||
@
|
||||
MOV r10, #0 @ Clear stack limit
|
||||
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
@
|
||||
@ /* Call the ISR enter function to indicate an ISR is executing. */
|
||||
@
|
||||
PUSH {lr} @ Save ISR lr
|
||||
BL _tx_execution_isr_enter @ Call the ISR enter function
|
||||
POP {lr} @ Recover ISR lr
|
||||
#endif
|
||||
|
||||
ADD sp, sp, #32 @ Recover saved registers
|
||||
MOV pc, lr @ Return to caller
|
||||
@
|
||||
@ }
|
||||
@}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user