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

Reply via email to