This is an automated email from the ASF dual-hosted git repository.
xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 6d0ae23c93a libs/libc/machine/arm64: Add the ucontext functions.
6d0ae23c93a is described below
commit 6d0ae23c93a2c129f13d010bf3e87336ee3fcf69
Author: Marco Casaroli <[email protected]>
AuthorDate: Mon Oct 12 00:54:30 2026 +0200
libs/libc/machine/arm64: Add the ucontext functions.
Programs that switch between their own stacks, such as coroutine
libraries, use the ucontext functions, and NuttX had none.
Add include/ucontext.h with ucontext_t, and an implementation for arm64,
which selects the new ARCH_HAVE_UCONTEXT. A context holds the
callee-saved registers, the stack pointer, the program counter, the
arguments of makecontext(), the callee-saved FP registers when there is
an FPU, and the signal mask. A context made by makecontext() continues
with uc_link when its function returns, or the task exits if uc_link is
NULL. mcontext_t is in arch/arm64/include/irq.h, next to
struct xcptcontext.
Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <[email protected]>
---
Kconfig | 7 ++
arch/Kconfig | 1 +
arch/arm64/include/irq.h | 15 ++++
include/ucontext.h | 77 ++++++++++++++++
libs/libc/machine/arm64/CMakeLists.txt | 4 +
libs/libc/machine/arm64/Make.defs | 5 ++
libs/libc/machine/arm64/arch_makecontext.c | 127 ++++++++++++++++++++++++++
libs/libc/machine/arm64/arch_ucontext.S | 138 +++++++++++++++++++++++++++++
8 files changed, 374 insertions(+)
diff --git a/Kconfig b/Kconfig
index a97f50658bf..e8c72ecfc64 100644
--- a/Kconfig
+++ b/Kconfig
@@ -674,6 +674,13 @@ config ARCH_SETJMP_H
ARCH_SETJMP_H=y and providing. If ARCH_SETJMP_H, is not
defined, then
the setjmp.h header file will stay out-of-the-way in
include/nuttx/.
+config ARCH_HAVE_UCONTEXT
+ bool
+ default n
+ ---help---
+ The architecture provides getcontext(), setcontext(),
makecontext()
+ and swapcontext() in libc.
+
choice
prompt "debug.h selection"
default ARCH_NONE_DEBUG_H
diff --git a/arch/Kconfig b/arch/Kconfig
index fdc48c09f50..28cbfcf1b46 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -35,6 +35,7 @@ config ARCH_ARM64
select ARCH_HAVE_CUSTOMOPT
select ARCH_HAVE_STDARG_H
select ARCH_HAVE_SETJMP
+ select ARCH_HAVE_UCONTEXT
select ARCH_HAVE_SYSCALL_HOOKS
select ARCH_HAVE_RDWR_MEM_CPU_RUN
select ARCH_HAVE_TCBINFO
diff --git a/arch/arm64/include/irq.h b/arch/arm64/include/irq.h
index 6dd9a4e2821..e38d46c5bd8 100644
--- a/arch/arm64/include/irq.h
+++ b/arch/arm64/include/irq.h
@@ -340,6 +340,21 @@ struct xcptcontext
#endif
};
+/* The machine context of getcontext() and makecontext(). The assembly code
+ * in libs/libc/machine/arm64/arch_ucontext.S knows this layout.
+ */
+
+typedef struct mcontext_s
+{
+ uint64_t args[8]; /* x0-x7, the arguments of makecontext() */
+ uint64_t regs[12]; /* x19-x30, the callee-saved registers */
+ uint64_t sp;
+ uint64_t pc;
+#ifdef CONFIG_ARCH_FPU
+ uint64_t fpregs[8]; /* d8-d15, the callee-saved FP registers */
+#endif
+} mcontext_t;
+
/* Name: up_irq_save, up_irq_restore, and friends.
*
* NOTE: This function should never be called from application code and,
diff --git a/include/ucontext.h b/include/ucontext.h
new file mode 100644
index 00000000000..ce03da2df30
--- /dev/null
+++ b/include/ucontext.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+ * include/ucontext.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_UCONTEXT_H
+#define __INCLUDE_UCONTEXT_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <signal.h>
+
+#ifdef CONFIG_ARCH_HAVE_UCONTEXT
+# include <nuttx/irq.h>
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* uc_mcontext comes first: the architecture code uses it at offset 0 */
+
+typedef struct ucontext_s
+{
+ mcontext_t uc_mcontext; /* Machine context */
+ FAR struct ucontext_s *uc_link; /* Context to resume when this one
+ * returns */
+ sigset_t uc_sigmask; /* Signals blocked in the context */
+ stack_t uc_stack; /* Stack of the context */
+} ucontext_t;
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+int getcontext(FAR ucontext_t *ucp);
+int setcontext(FAR const ucontext_t *ucp);
+void makecontext(FAR ucontext_t *ucp, CODE void (*func)(void), int argc,
+ ...);
+int swapcontext(FAR ucontext_t *oucp, FAR const ucontext_t *ucp);
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* CONFIG_ARCH_HAVE_UCONTEXT */
+#endif /* __INCLUDE_UCONTEXT_H */
diff --git a/libs/libc/machine/arm64/CMakeLists.txt
b/libs/libc/machine/arm64/CMakeLists.txt
index ae2c50f8562..544b13db972 100644
--- a/libs/libc/machine/arm64/CMakeLists.txt
+++ b/libs/libc/machine/arm64/CMakeLists.txt
@@ -82,6 +82,10 @@ if(CONFIG_ARCH_SETJMP_H)
list(APPEND SRCS arch_setjmp.S)
endif()
+if(CONFIG_ARCH_HAVE_UCONTEXT)
+ list(APPEND SRCS arch_ucontext.S arch_makecontext.c)
+endif()
+
if(NOT CONFIG_PROFILE_NONE)
list(APPEND SRCS arch_mcount.c)
endif()
diff --git a/libs/libc/machine/arm64/Make.defs
b/libs/libc/machine/arm64/Make.defs
index aca2a54554b..acf9c52dac1 100644
--- a/libs/libc/machine/arm64/Make.defs
+++ b/libs/libc/machine/arm64/Make.defs
@@ -80,6 +80,11 @@ ifeq ($(CONFIG_ARCH_SETJMP_H),y)
ASRCS += arch_setjmp.S
endif
+ifeq ($(CONFIG_ARCH_HAVE_UCONTEXT),y)
+ASRCS += arch_ucontext.S
+CSRCS += arch_makecontext.c
+endif
+
ifeq ($(CONFIG_PROFILE_NONE),)
CSRCS += arch_mcount.c
endif
diff --git a/libs/libc/machine/arm64/arch_makecontext.c
b/libs/libc/machine/arm64/arch_makecontext.c
new file mode 100644
index 00000000000..242490d64d7
--- /dev/null
+++ b/libs/libc/machine/arm64/arch_makecontext.c
@@ -0,0 +1,127 @@
+/****************************************************************************
+ * libs/libc/machine/arm64/arch_makecontext.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <signal.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <ucontext.h>
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/* In arch_ucontext.S, and called from there */
+
+void arm64_ucontext_start(void);
+int arm64_ucontext_getmask(ucontext_t *ucp);
+void arm64_ucontext_setmask(const ucontext_t *ucp);
+void arm64_ucontext_swapmask(ucontext_t *oucp,
+ const ucontext_t *ucp);
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm64_ucontext_getmask, arm64_ucontext_setmask and
+ * arm64_ucontext_swapmask
+ *
+ * Description:
+ * Save and restore the signal mask of a context, for getcontext(),
+ * setcontext() and swapcontext().
+ *
+ ****************************************************************************/
+
+int arm64_ucontext_getmask(ucontext_t *ucp)
+{
+ return sigprocmask(SIG_BLOCK, NULL, &ucp->uc_sigmask);
+}
+
+void arm64_ucontext_setmask(const ucontext_t *ucp)
+{
+ sigprocmask(SIG_SETMASK, &ucp->uc_sigmask, NULL);
+}
+
+void arm64_ucontext_swapmask(ucontext_t *oucp,
+ const ucontext_t *ucp)
+{
+ sigprocmask(SIG_SETMASK, &ucp->uc_sigmask, &oucp->uc_sigmask);
+}
+
+/****************************************************************************
+ * Name: makecontext
+ *
+ * Description:
+ * Make ucp run func(argc integer arguments) on ucp->uc_stack. When func
+ * returns, the context continues with ucp->uc_link, or the task exits if
+ * it is NULL.
+ *
+ ****************************************************************************/
+
+void makecontext(ucontext_t *ucp, CODE void (*func)(void), int argc,
+ ...)
+{
+ uint64_t *stack;
+ uintptr_t sp;
+ va_list ap;
+ int i;
+
+ sp = (uintptr_t)ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size;
+ sp &= ~(STACKFRAME_ALIGN - 1);
+
+ /* The first eight arguments go in x0-x7, the others on the stack */
+
+ if (argc > 8)
+ {
+ sp -= (argc - 8) * sizeof(uint64_t);
+ sp &= ~(STACKFRAME_ALIGN - 1);
+ }
+
+ stack = (uint64_t *)sp;
+
+ va_start(ap, argc);
+ for (i = 0; i < argc; i++)
+ {
+ if (i < 8)
+ {
+ ucp->uc_mcontext.args[i] = va_arg(ap, int64_t);
+ }
+ else
+ {
+ stack[i - 8] = va_arg(ap, int64_t);
+ }
+ }
+
+ va_end(ap);
+
+ ucp->uc_mcontext.regs[0] = (uintptr_t)ucp->uc_link; /* x19 */
+ ucp->uc_mcontext.regs[10] = 0; /* x29 */
+ ucp->uc_mcontext.regs[11] = (uintptr_t)arm64_ucontext_start; /* x30 */
+ ucp->uc_mcontext.sp = sp;
+ ucp->uc_mcontext.pc = (uintptr_t)func;
+}
diff --git a/libs/libc/machine/arm64/arch_ucontext.S
b/libs/libc/machine/arm64/arch_ucontext.S
new file mode 100644
index 00000000000..6eb8db6d0e8
--- /dev/null
+++ b/libs/libc/machine/arm64/arch_ucontext.S
@@ -0,0 +1,138 @@
+/****************************************************************************
+ * libs/libc/machine/arm64/arch_ucontext.S
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Offsets in mcontext_t (arch/arm64/include/irq.h), which is at the start
+ * of ucontext_t.
+ */
+
+#define UC_X0 0
+#define UC_X19 (8 * 8)
+#define UC_SP (20 * 8)
+#define UC_PC (21 * 8)
+#define UC_D8 (22 * 8)
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+ .text
+
+/* Save the callee-saved registers of the caller in the context at \base:
+ * the context resumes at the return address with x0 = 0.
+ */
+
+ .macro save_context base
+ stp x19, x20, [\base, #UC_X19]
+ stp x21, x22, [\base, #UC_X19 + 16]
+ stp x23, x24, [\base, #UC_X19 + 32]
+ stp x25, x26, [\base, #UC_X19 + 48]
+ stp x27, x28, [\base, #UC_X19 + 64]
+ stp x29, x30, [\base, #UC_X19 + 80]
+ str xzr, [\base, #UC_X0]
+ mov x9, sp
+ stp x9, x30, [\base, #UC_SP]
+#ifdef CONFIG_ARCH_FPU
+ stp d8, d9, [\base, #UC_D8]
+ stp d10, d11, [\base, #UC_D8 + 16]
+ stp d12, d13, [\base, #UC_D8 + 32]
+ stp d14, d15, [\base, #UC_D8 + 48]
+#endif
+ .endm
+
+/* int getcontext(ucontext_t *ucp) */
+
+ .global getcontext
+ .type getcontext, %function
+getcontext:
+ save_context x0
+ b arm64_ucontext_getmask
+ .size getcontext, . - getcontext
+
+/* int setcontext(const ucontext_t *ucp) */
+
+ .global setcontext
+ .type setcontext, %function
+setcontext:
+ mov x19, x0
+ bl arm64_ucontext_setmask
+ mov x16, x19
+
+/* Load the context at x16 and jump to its pc */
+
+arm64_ucontext_load:
+#ifdef CONFIG_ARCH_FPU
+ ldp d8, d9, [x16, #UC_D8]
+ ldp d10, d11, [x16, #UC_D8 + 16]
+ ldp d12, d13, [x16, #UC_D8 + 32]
+ ldp d14, d15, [x16, #UC_D8 + 48]
+#endif
+ ldp x19, x20, [x16, #UC_X19]
+ ldp x21, x22, [x16, #UC_X19 + 16]
+ ldp x23, x24, [x16, #UC_X19 + 32]
+ ldp x25, x26, [x16, #UC_X19 + 48]
+ ldp x27, x28, [x16, #UC_X19 + 64]
+ ldp x29, x30, [x16, #UC_X19 + 80]
+ ldp x2, x3, [x16, #UC_X0 + 16]
+ ldp x4, x5, [x16, #UC_X0 + 32]
+ ldp x6, x7, [x16, #UC_X0 + 48]
+ ldp x17, x1, [x16, #UC_SP]
+ mov sp, x17
+ mov x17, x1
+ ldp x0, x1, [x16, #UC_X0]
+ br x17
+ .size setcontext, . - setcontext
+
+/* int swapcontext(ucontext_t *oucp, const ucontext_t *ucp) */
+
+ .global swapcontext
+ .type swapcontext, %function
+swapcontext:
+ save_context x0
+ mov x19, x0
+ mov x20, x1
+ bl arm64_ucontext_swapmask
+ mov x16, x20
+ b arm64_ucontext_load
+ .size swapcontext, . - swapcontext
+
+/* A context made by makecontext() returns here: x19 holds its uc_link */
+
+ .global arm64_ucontext_start
+ .type arm64_ucontext_start, %function
+arm64_ucontext_start:
+ mov x0, x19
+ cbz x0, 1f
+ bl setcontext
+1:
+ mov x0, #0
+ bl exit
+ .size arm64_ucontext_start, . - arm64_ucontext_start