Skip to content

Commit 3294dd3

Browse files
committed
Started a ThreadX module port for the Cortex-R52, headers first
No GNU module port exists for any R-profile core, so there is no close template to copy. This adds the two headers a module port needs and records the design decisions the rest of it will rest on. Seeded from cortex_m33 rather than cortex_r4, which is the important choice here. The R4 port is the other R-profile one, but it is PMSAv7: power-of-two region sizes, and 541 lines of register setup mostly spent juggling them plus an alignment adjustment pass to match. PMSAv8-R uses base and limit pairs with a 64-byte granule, which is the Armv8-M model, so the M33 port's structure transfers and that whole class of complexity does not arise. The attribute encodings are bit-identical: shareability in PRBAR[4:3], access permission in PRBAR[2:1], execute-never in PRBAR[0], attribute index in PRLAR[3:1], region enable in PRLAR[0]. What differs from the M33, and is handled: Region budget. MPUIR on the S32Z280 reports 20 EL1 regions where an M33 has 8, and that changes the design rather than the numbers. On an M33 the kernel and a module compete for the same eight; here the kernel keeps its own and the manager owns a separate block from TXM_MODULE_MPU_FIRST_REGION upward, so a module switch reprograms only the module's regions and never rebuilds the kernel's. Granule. 64 bytes, not 32. This one is silent when wrong: the low bits of PRBAR and PRLAR hold attributes, so an under-aligned base does not fault, it changes the region's shareability and permissions instead. Fault reporting. Armv8-M reports a memory fault through SHCSR, CFSR, MMFAR and BFAR. This core splits it by access type, so the fault info structure carries DFSR and DFAR for data aborts and IFSR and IFAR for prefetch aborts. Both pairs are needed: a module can fault either by writing outside its data region or by branching outside its code region. SPSR replaces xPSR, because the mode the faulting code was in is what says whether it was the module in user mode or the kernel. No secure-stack extension. Those calls are the Armv8-M security extension, which this core does not have; privilege here is EL1 against EL0 and there is no secure world to allocate a second stack in. tx_thread_vfp_enable is kept at the front of TX_THREAD_EXTENSION_2, ahead of the module fields. The base port holds the floating-point lazy-enable flag there, and dropping it while adding the module fields would leave VFP threads with nowhere to record that they have used the unit -- which would surface as corrupted floating-point state inside a module, a long way from its cause. Also recorded, from the measurement in #637: a region switch on this part costs 562 to 604 cycles against a context switch of about 1400, and most of that is the dsb and isb rather than the register writes. A module switch programming several regions should therefore issue one barrier pair at the end rather than one per region, and the header says so where the register info structure is defined. Still to come: the module manager sources. Its own copies of the port assembly so the region switch happens in the scheduler, the PMSAv8-R region setup, a memory fault handler, user-mode entry, the port dispatch, and a sample module with its build. Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
1 parent ca62edd commit 3294dd3

2 files changed

Lines changed: 756 additions & 0 deletions

File tree

Lines changed: 368 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,368 @@
1+
/***************************************************************************
2+
* Copyright (c) 2024 Microsoft Corporation
3+
* Copyright (c) 2026 Eclipse ThreadX contributors
4+
*
5+
* This program and the accompanying materials are made available under the
6+
* terms of the MIT License which is available at
7+
* https://opensource.org/licenses/MIT.
8+
*
9+
* SPDX-License-Identifier: MIT
10+
**************************************************************************/
11+
// Some portions generated by Claude Code (Opus 5).
12+
13+
14+
/**************************************************************************/
15+
/**************************************************************************/
16+
/** */
17+
/** ThreadX Component */
18+
/** */
19+
/** Port Specific */
20+
/** */
21+
/**************************************************************************/
22+
/**************************************************************************/
23+
24+
25+
/**************************************************************************/
26+
/* */
27+
/* PORT SPECIFIC C INFORMATION RELEASE */
28+
/* */
29+
/* tx_port.h Cortex-R52/GNU */
30+
/* 6.5.2 */
31+
/* */
32+
/* AUTHOR */
33+
/* */
34+
/* Frédéric Desbiens, Eclipse Foundation */
35+
/* */
36+
/* Derived from the Cortex-R5/GNU port originally written by */
37+
/* William E. Lamie, Microsoft Corporation. */
38+
/* */
39+
/* DESCRIPTION */
40+
/* */
41+
/* This file contains data type definitions that make the ThreadX */
42+
/* real-time kernel function identically on a variety of different */
43+
/* processor architectures. For example, the size or number of bits */
44+
/* in an "int" data type vary between microprocessor architectures and */
45+
/* even C compilers for the same microprocessor. ThreadX does not */
46+
/* directly use native C data types. Instead, ThreadX creates its */
47+
/* own special types that can be mapped to actual data types by this */
48+
/* file to guarantee consistency in the interface and functionality. */
49+
/* */
50+
/**************************************************************************/
51+
52+
#ifndef TX_PORT_H
53+
#define TX_PORT_H
54+
55+
56+
/* Determine if the optional ThreadX user define file should be used. */
57+
58+
#ifdef TX_INCLUDE_USER_DEFINE_FILE
59+
60+
61+
/* Yes, include the user defines in tx_user.h. The defines in this file may
62+
alternately be defined on the command line. */
63+
64+
#include "tx_user.h"
65+
#endif
66+
67+
68+
/* Define compiler library include files. */
69+
70+
#include <stdlib.h>
71+
#include <string.h>
72+
73+
74+
/* Define ThreadX basic types for this port. */
75+
76+
#define VOID void
77+
typedef char CHAR;
78+
typedef unsigned char UCHAR;
79+
typedef int INT;
80+
typedef unsigned int UINT;
81+
typedef long LONG;
82+
typedef unsigned long ULONG;
83+
typedef short SHORT;
84+
typedef unsigned short USHORT;
85+
86+
87+
/* Define the priority levels for ThreadX. Legal values range
88+
from 32 to 1024 and MUST be evenly divisible by 32. */
89+
90+
#ifndef TX_MAX_PRIORITIES
91+
#define TX_MAX_PRIORITIES 32
92+
#endif
93+
94+
95+
/* Define the minimum stack for a ThreadX thread on this processor. If the size supplied during
96+
thread creation is less than this value, the thread create call will return an error. */
97+
98+
#ifndef TX_MINIMUM_STACK
99+
#define TX_MINIMUM_STACK 200 /* Minimum stack size for this port */
100+
#endif
101+
102+
103+
/* Define the system timer thread's default stack size and priority. These are only applicable
104+
if TX_TIMER_PROCESS_IN_ISR is not defined. */
105+
106+
#ifndef TX_TIMER_THREAD_STACK_SIZE
107+
#define TX_TIMER_THREAD_STACK_SIZE 1024 /* Default timer thread stack size */
108+
#endif
109+
110+
#ifndef TX_TIMER_THREAD_PRIORITY
111+
#define TX_TIMER_THREAD_PRIORITY 0 /* Default timer thread priority */
112+
#endif
113+
114+
115+
/* Define various constants for the ThreadX ARM port. */
116+
117+
#ifdef TX_ENABLE_FIQ_SUPPORT
118+
#define TX_INT_DISABLE 0xC0 /* Disable IRQ & FIQ interrupts */
119+
#else
120+
#define TX_INT_DISABLE 0x80 /* Disable IRQ interrupts */
121+
#endif
122+
#define TX_INT_ENABLE 0x00 /* Enable IRQ interrupts */
123+
124+
125+
/* Define the clock source for trace event entry time stamp. The following two item are port specific.
126+
For example, if the time source is at the address 0x0a800024 and is 16-bits in size, the clock
127+
source constants would be:
128+
129+
#define TX_TRACE_TIME_SOURCE *((ULONG *) 0x0a800024)
130+
#define TX_TRACE_TIME_MASK 0x0000FFFFUL
131+
132+
*/
133+
134+
#ifndef TX_TRACE_TIME_SOURCE
135+
#define TX_TRACE_TIME_SOURCE ++_tx_trace_simulated_time
136+
#endif
137+
#ifndef TX_TRACE_TIME_MASK
138+
#define TX_TRACE_TIME_MASK 0xFFFFFFFFUL
139+
#endif
140+
141+
142+
/* Define the port specific options for the _tx_build_options variable. This variable indicates
143+
how the ThreadX library was built. */
144+
145+
#ifdef TX_ENABLE_FIQ_SUPPORT
146+
#define TX_FIQ_ENABLED 1
147+
#else
148+
#define TX_FIQ_ENABLED 0
149+
#endif
150+
151+
#ifdef TX_ENABLE_IRQ_NESTING
152+
#define TX_IRQ_NESTING_ENABLED 2
153+
#else
154+
#define TX_IRQ_NESTING_ENABLED 0
155+
#endif
156+
157+
#ifdef TX_ENABLE_FIQ_NESTING
158+
#define TX_FIQ_NESTING_ENABLED 4
159+
#else
160+
#define TX_FIQ_NESTING_ENABLED 0
161+
#endif
162+
163+
#define TX_PORT_SPECIFIC_BUILD_OPTIONS TX_FIQ_ENABLED | TX_IRQ_NESTING_ENABLED | TX_FIQ_NESTING_ENABLED
164+
165+
166+
/* Define the in-line initialization constant so that modules with in-line
167+
initialization capabilities can prevent their initialization from being
168+
a function call. */
169+
170+
#define TX_INLINE_INITIALIZATION
171+
172+
173+
/* Determine whether or not stack checking is enabled. By default, ThreadX stack checking is
174+
disabled. When the following is defined, ThreadX thread stack checking is enabled. If stack
175+
checking is enabled (TX_ENABLE_STACK_CHECKING is defined), the TX_DISABLE_STACK_FILLING
176+
define is negated, thereby forcing the stack fill which is necessary for the stack checking
177+
logic. */
178+
179+
#ifdef TX_ENABLE_STACK_CHECKING
180+
#undef TX_DISABLE_STACK_FILLING
181+
#endif
182+
183+
184+
/* Define the TX_THREAD control block extensions for this port. The main reason
185+
for the multiple macros is so that backward compatibility can be maintained with
186+
existing ThreadX kernel awareness modules. */
187+
188+
/* TX_THREAD_EXTENSION_2 carries the per-thread VFP enable flag used by the
189+
lazy floating-point save and restore in tx_thread_schedule.S,
190+
tx_thread_system_return.S and tx_thread_context_restore.S.
191+
192+
It is defined UNCONDITIONALLY, not under TX_ENABLE_VFP_SUPPORT, and that is
193+
deliberate: the assembly reaches this field through a hard-coded structure
194+
offset, so making the field conditional would move every following member
195+
between build configurations and leave the offset correct in only one of
196+
them. Keeping it always present makes the layout independent of the
197+
floating-point build options. The offset is checked at compile time in
198+
tx_port_offset_check.c, which turns a wrong offset into a build failure
199+
instead of silent corruption of an unrelated thread field. */
200+
201+
#define TX_THREAD_EXTENSION_0
202+
#define TX_THREAD_EXTENSION_1
203+
/* The module thread extension. A thread that belongs to a module carries a
204+
pointer to its module instance, its entry information, the user-mode state to
205+
restore when it is scheduled, and two stacks: the module's own stack for user
206+
mode and a kernel stack for the privileged side of a system call.
207+
208+
Two stacks rather than one is not an implementation detail that can be
209+
simplified away. A module thread runs in user mode on memory the module owns;
210+
the moment it enters the kernel through a system call, the kernel must not be
211+
writing its own state onto memory the module can also write, or the module
212+
could corrupt the kernel by scribbling on its own stack. */
213+
214+
/* tx_thread_vfp_enable comes first and is not optional here. The Cortex-R52
215+
port keeps the floating-point lazy-enable flag in this extension, and dropping
216+
it while adding the module fields would leave VFP threads with nowhere to
217+
record that they have used the unit -- the kind of breakage that shows up as
218+
corrupted floating-point state in a module, a long way from its cause. */
219+
220+
#define TX_THREAD_EXTENSION_2 ULONG tx_thread_vfp_enable; \
221+
VOID *tx_thread_module_instance_ptr; \
222+
VOID *tx_thread_module_entry_info_ptr; \
223+
ULONG tx_thread_module_current_user_mode; \
224+
ULONG tx_thread_module_user_mode; \
225+
ULONG tx_thread_module_saved_lr; \
226+
VOID *tx_thread_module_kernel_stack_start; \
227+
VOID *tx_thread_module_kernel_stack_end; \
228+
ULONG tx_thread_module_kernel_stack_size; \
229+
VOID *tx_thread_module_stack_ptr; \
230+
VOID *tx_thread_module_stack_start; \
231+
VOID *tx_thread_module_stack_end; \
232+
ULONG tx_thread_module_stack_size; \
233+
VOID *tx_thread_module_reserved;
234+
#define TX_THREAD_EXTENSION_3
235+
236+
237+
/* Define the port extensions of the remaining ThreadX objects. */
238+
239+
#define TX_BLOCK_POOL_EXTENSION
240+
#define TX_BYTE_POOL_EXTENSION
241+
#define TX_EVENT_FLAGS_GROUP_EXTENSION
242+
#define TX_MUTEX_EXTENSION
243+
#define TX_QUEUE_EXTENSION
244+
#define TX_SEMAPHORE_EXTENSION
245+
#define TX_TIMER_EXTENSION
246+
247+
248+
/* Define the user extension field of the thread control block. Nothing
249+
additional is needed for this port so it is defined as white space. */
250+
251+
#ifndef TX_THREAD_USER_EXTENSION
252+
#define TX_THREAD_USER_EXTENSION
253+
#endif
254+
255+
256+
/* Define the macros for processing extensions in tx_thread_create, tx_thread_delete,
257+
tx_thread_shell_entry, and tx_thread_terminate. */
258+
259+
260+
#define TX_THREAD_CREATE_EXTENSION(thread_ptr)
261+
#define TX_THREAD_DELETE_EXTENSION(thread_ptr)
262+
#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr)
263+
#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr)
264+
265+
266+
/* Define the ThreadX object creation extensions for remaining objects. */
267+
268+
#define TX_BLOCK_POOL_CREATE_EXTENSION(pool_ptr)
269+
#define TX_BYTE_POOL_CREATE_EXTENSION(pool_ptr)
270+
#define TX_EVENT_FLAGS_GROUP_CREATE_EXTENSION(group_ptr)
271+
#define TX_MUTEX_CREATE_EXTENSION(mutex_ptr)
272+
#define TX_QUEUE_CREATE_EXTENSION(queue_ptr)
273+
#define TX_SEMAPHORE_CREATE_EXTENSION(semaphore_ptr)
274+
#define TX_TIMER_CREATE_EXTENSION(timer_ptr)
275+
276+
277+
/* Define the ThreadX object deletion extensions for remaining objects. */
278+
279+
#define TX_BLOCK_POOL_DELETE_EXTENSION(pool_ptr)
280+
#define TX_BYTE_POOL_DELETE_EXTENSION(pool_ptr)
281+
#define TX_EVENT_FLAGS_GROUP_DELETE_EXTENSION(group_ptr)
282+
#define TX_MUTEX_DELETE_EXTENSION(mutex_ptr)
283+
#define TX_QUEUE_DELETE_EXTENSION(queue_ptr)
284+
#define TX_SEMAPHORE_DELETE_EXTENSION(semaphore_ptr)
285+
#define TX_TIMER_DELETE_EXTENSION(timer_ptr)
286+
287+
288+
/* Determine if the ARM architecture has the CLZ instruction. This is available on
289+
architectures v5 and above. If available, redefine the macro for calculating the
290+
lowest bit set. */
291+
292+
#if __TARGET_ARCH_ARM > 4
293+
294+
#ifndef __thumb__
295+
296+
#define TX_LOWEST_SET_BIT_CALCULATE(m, b) m = m & ((ULONG) (-((LONG) m))); \
297+
asm volatile (" CLZ %0,%1 ": "=r" (b) : "r" (m) ); \
298+
b = 31 - b;
299+
#endif
300+
#endif
301+
302+
303+
/* Define ThreadX interrupt lockout and restore macros for protection on
304+
access of critical kernel information. The restore interrupt macro must
305+
restore the interrupt posture of the running thread prior to the value
306+
present prior to the disable macro. In most cases, the save area macro
307+
is used to define a local function save area for the disable and restore
308+
macros. */
309+
310+
/* Per-thread floating-point control. Implemented in tx_thread_schedule.S and
311+
available only when the library is built with TX_ENABLE_VFP_SUPPORT. A
312+
thread's floating-point context is saved and restored lazily: only threads
313+
that have called tx_thread_vfp_enable() pay for it. */
314+
315+
#ifdef TX_ENABLE_VFP_SUPPORT
316+
void tx_thread_vfp_enable(void);
317+
void tx_thread_vfp_disable(void);
318+
#endif
319+
320+
321+
#ifdef __thumb__
322+
323+
unsigned int _tx_thread_interrupt_disable(void);
324+
unsigned int _tx_thread_interrupt_restore(UINT old_posture);
325+
326+
327+
#define TX_INTERRUPT_SAVE_AREA UINT interrupt_save;
328+
329+
#define TX_DISABLE interrupt_save = _tx_thread_interrupt_disable();
330+
#define TX_RESTORE _tx_thread_interrupt_restore(interrupt_save);
331+
332+
#else
333+
334+
#define TX_INTERRUPT_SAVE_AREA UINT interrupt_save;
335+
336+
#ifdef TX_ENABLE_FIQ_SUPPORT
337+
#define TX_DISABLE asm volatile (" MRS %0,CPSR; CPSID if ": "=r" (interrupt_save) );
338+
#else
339+
#define TX_DISABLE asm volatile (" MRS %0,CPSR; CPSID i ": "=r" (interrupt_save) );
340+
#endif
341+
342+
#define TX_RESTORE asm volatile (" MSR CPSR_c,%0 "::"r" (interrupt_save) );
343+
344+
#endif
345+
346+
347+
/* Define the interrupt lockout macros for each ThreadX object. */
348+
349+
#define TX_BLOCK_POOL_DISABLE TX_DISABLE
350+
#define TX_BYTE_POOL_DISABLE TX_DISABLE
351+
#define TX_EVENT_FLAGS_GROUP_DISABLE TX_DISABLE
352+
#define TX_MUTEX_DISABLE TX_DISABLE
353+
#define TX_QUEUE_DISABLE TX_DISABLE
354+
#define TX_SEMAPHORE_DISABLE TX_DISABLE
355+
356+
357+
/* Define the version ID of ThreadX. This may be used by the application.*/
358+
359+
#ifdef TX_THREAD_INIT
360+
CHAR _tx_version_id[] =
361+
"(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * ThreadXCortex-R52/GNU Version 6.5.1.202602a *";
362+
#else
363+
extern CHAR _tx_version_id[];
364+
#endif
365+
366+
367+
#endif
368+

0 commit comments

Comments
 (0)