Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions components/libc/compilers/common/clocale.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2026, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Kernel-mode musl is linked with native RT-Thread threads, not musl's Linux
* pthread runtime. A few musl locale functions reach the Linux pthread
* locale object through the architecture thread pointer. Supply the fixed
* UTF-8/C-locale subset used by kernel applications until a complete musl
* pthread locale runtime is available.
*/

#include <rtthread.h>

#if defined(RT_USING_MUSLLIBC) && !defined(RT_USING_SMART)

#include <langinfo.h>
#include <stdio.h>
#include <wchar.h>

char *nl_langinfo(nl_item item)
{
static char empty[] = "";

if (item == CODESET)
{
return (char *)"UTF-8";
}

return empty;
}

wint_t btowc(int character)
{
if (character == EOF)
{
return WEOF;
}

/* A single UTF-8 byte is a character only in the ASCII range. */
if ((unsigned int)character > 0x7f)
{
return WEOF;
}

return (wint_t)character;
}

#endif /* RT_USING_MUSLLIBC && !RT_USING_SMART */
15 changes: 13 additions & 2 deletions libcpu/aarch64/common/mp/context_gcc.S
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@
#endif /* ARCH_USING_HW_THREAD_SELF */
.endm

.macro update_tls, srcx
#ifdef RT_USING_CPLUSPLUS
mov x0, \srcx
bl rt_hw_thread_tls_base
msr tpidr_el0, x0
#endif /* RT_USING_CPLUSPLUS */
.endm

/*
* void rt_hw_context_switch_to(rt_uint3 to, struct rt_thread *to_thread);
* X0 --> to (thread stack)
Expand All @@ -41,10 +49,11 @@
rt_hw_context_switch_to:
ldr x0, [x0]
mov sp, x0
update_tidr x1

/* reserved to_thread */
mov x19, x1
update_tidr x19
update_tls x19

mov x0, x19
bl rt_cpus_lock_status_restore
Expand All @@ -69,10 +78,11 @@ rt_hw_context_switch:
str x3, [x0] // store sp in preempted tasks TCB
ldr x0, [x1] // get new task stack pointer
mov sp, x0
update_tidr x2

/* backup thread self */
mov x19, x2
update_tidr x19
update_tls x19

mov x0, x19
bl rt_cpus_lock_status_restore
Expand Down Expand Up @@ -128,6 +138,7 @@ rt_hw_context_switch_interrupt:
ldr x0, [TO_SPP]
mov sp, x0
update_tidr TO_TCB
update_tls TO_TCB

mov x0, TO_TCB
bl rt_cpus_lock_status_restore
Expand Down
40 changes: 40 additions & 0 deletions libcpu/aarch64/common/stack.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,40 @@

#define INITIAL_SPSR_EL1 (PSTATE_EL1 | SP_ELx)

#ifdef RT_USING_CPLUSPLUS
extern char __tdata_start, __tdata_end;
extern char __tbss_start, __tbss_end;

static rt_size_t rt_hw_thread_tls_size(void)
{
/* Preserve any linker-inserted alignment gap between .tdata and .tbss. */
rt_size_t size = &__tbss_end - &__tdata_start;

return RT_ALIGN(size, 16);
}

static void rt_hw_thread_tls_init(void *tls)
{
rt_size_t tdata_size = &__tdata_end - &__tdata_start;
rt_size_t tls_size = rt_hw_thread_tls_size();

rt_memcpy(tls, &__tdata_start, tdata_size);
rt_memset((rt_uint8_t *)tls + tdata_size, 0, tls_size - tdata_size);
}

/*
* rt_hw_stack_init() reserves TLS below the initial stack pointer. Derive
* the same aligned address from the TCB for every subsequent context switch.
*/
void *rt_hw_thread_tls_base(struct rt_thread *thread)
{
rt_ubase_t top = (rt_ubase_t)thread->stack_addr + thread->stack_size -
sizeof(rt_ubase_t);

return (void *)RT_ALIGN_DOWN(top - rt_hw_thread_tls_size(), 16);
}
#endif /* RT_USING_CPLUSPLUS */

/**
* This function will initialize thread stack
*
Expand All @@ -31,6 +65,12 @@ rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter,
{
rt_ubase_t *stk;

#ifdef RT_USING_CPLUSPLUS
stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN(
(rt_ubase_t)stack_addr - rt_hw_thread_tls_size(), 16);
rt_hw_thread_tls_init(stack_addr);
#endif

/* The AAPCS64 requires 128-bit (16 byte) stack alignment */
stk = (rt_ubase_t*)RT_ALIGN_DOWN((rt_ubase_t)stack_addr, 16);

Expand Down
24 changes: 24 additions & 0 deletions libcpu/aarch64/link.lds.S
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,30 @@ SECTIONS
*(.rel.local)
} :data

#ifdef RT_USING_CPLUSPLUS
/*
* Keep the static TLS image so the kernel can instantiate it for each
* RT-Thread thread. Musl and Qt both use TPIDR_EL0 on AArch64.
*/
. = ALIGN(16);
.tdata :
{
PROVIDE(__tdata_start = .);
*(.tdata)
*(.tdata.*)
PROVIDE(__tdata_end = .);
} :data

. = ALIGN(16);
.tbss :
{
PROVIDE(__tbss_start = .);
*(.tbss)
*(.tbss.*)
PROVIDE(__tbss_end = .);
}
#endif /* RT_USING_CPLUSPLUS */

. = ALIGN(8);
.ctors :
{
Expand Down
35 changes: 34 additions & 1 deletion libcpu/risc-v/common/stack.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,30 @@
#include <mmu.h>
#endif

#if defined(RT_USING_CPLUSPLUS) && defined(ARCH_MM_MMU) && !defined(ARCH_RISCV_M_MODE)
extern char __tdata_start, __tdata_end;
extern char __tbss_start, __tbss_end;

static rt_size_t riscv_thread_tls_size(void)
{
/* .tbss can have stricter alignment than .tdata. Its linker-inserted
* gap is part of the ABI-visible TLS layout and must be retained. */
rt_size_t size = &__tbss_end - &__tdata_start;

return RT_ALIGN(size, 16);
}

static void riscv_thread_tls_init(void *tls)
{
rt_size_t tdata_size = &__tdata_end - &__tdata_start;
rt_size_t tls_size = riscv_thread_tls_size();

rt_memcpy(tls, &__tdata_start, tdata_size);
rt_memset((rt_uint8_t *)tls + tdata_size, 0, tls_size - tdata_size);
}

#endif /* RT_USING_CPLUSPLUS && ARCH_MM_MMU && !ARCH_RISCV_M_MODE */

/**
* This function will initialize thread stack, we assuming
* when scheduler restore this new thread, context will restore
Expand All @@ -41,6 +65,12 @@ rt_uint8_t *rt_hw_stack_init(void *tentry,
{
rt_ubase_t *sp;
rt_hw_switch_frame_t frame;
#if defined(RT_USING_CPLUSPLUS) && defined(ARCH_MM_MMU) && !defined(ARCH_RISCV_M_MODE)
void *tls = (void *)RT_ALIGN_DOWN((rt_ubase_t)stack_addr - riscv_thread_tls_size(), 16);

riscv_thread_tls_init(tls);
stack_addr = tls;
#endif

/* We use a strict alignment requirement for Q extension */
sp = (rt_ubase_t *)RT_ALIGN_DOWN((rt_ubase_t)stack_addr, 16);
Expand All @@ -56,7 +86,10 @@ rt_uint8_t *rt_hw_stack_init(void *tentry,

frame->regs[RT_HW_SWITCH_CONTEXT_RA] = (rt_ubase_t)_thread_start;
frame->regs[RT_HW_SWITCH_CONTEXT_XSTATUS] = K_XSTATUS_DEFAULT;
/* Bare SMP keeps the current hart's tp across context switches. */
#if defined(RT_USING_CPLUSPLUS) && defined(ARCH_MM_MMU) && !defined(ARCH_RISCV_M_MODE)
frame->regs[RT_HW_SWITCH_CONTEXT_TP] = (rt_ubase_t)tls;
#endif
/* Non-MMU and M-mode configurations keep their existing tp policy. */

return (void *)frame;
}
29 changes: 29 additions & 0 deletions libcpu/risc-v/link.lds.S
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,35 @@ SECTIONS
*(.rel.local)
} :data

#if defined(RT_USING_CPLUSPLUS) && defined(ARCH_MM_MMU) && !defined(ARCH_RISCV_M_MODE)
/*
* Keep the static TLS image in the kernel image. On RISC-V, tp points
* at the beginning of the current thread's TLS block. stack.c makes a
* private copy for every RT-Thread thread before its initial context is
* built.
*
* Only S-mode MMU configurations opt in. Other RISC-V libcpu targets
* retain their existing tp policy.
*/
. = ALIGN(16);
.tdata :
{
PROVIDE(__tdata_start = .);
*(.tdata)
*(.tdata.*)
PROVIDE(__tdata_end = .);
} :data

. = ALIGN(16);
.tbss (NOLOAD) :
{
PROVIDE(__tbss_start = .);
*(.tbss)
*(.tbss.*)
PROVIDE(__tbss_end = .);
}
#endif /* RT_USING_CPLUSPLUS && ARCH_MM_MMU && !ARCH_RISCV_M_MODE */

. = ALIGN(RISCV_SZPTR);
.ctors :
{
Expand Down
Loading