This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 9f1107862b9d32be74736aa21b0d515c74036173
Author: Marco Casaroli <[email protected]>
AuthorDate: Sun Aug 23 23:31:37 2026 +0200

    binfmt, arch/arm: Add the CONFIG_FDPIC option and the ABI header.
    
    The commits that follow teach the ELF loader to load an FDPIC object.  This
    puts the option they hang off and the definitions they share in one place
    first, so each of them builds on its own.
    
    CONFIG_FDPIC depends on ARCH_HAVE_ELF_FDPIC, which an architecture selects
    when it has a PIC base register and the FDPIC relocations.  Only armv7-m
    and armv8-m select it today, and it defaults off, so nothing changes for
    anyone who does not ask for it.
    
    include/nuttx/fdpic.h holds what both sides of the loader need: the two
    word function descriptor an FDPIC module passes instead of a code address,
    the test for whether the caller is such a module, and the call sequence
    that enters one with its own data base.  All of it is behind CONFIG_FDPIC,
    thus the header is empty without it and a file may include it
    unconditionally.
    
    The call sequence itself is architecture specific, so 
arch/arm/include/arch.h
    supplies it as up_fdpic_invoke(), beside the other PIC base register macros.
    up_setpicbase() cannot serve here: the register has to hold the module's
    base for exactly one call and then go back, and nothing in C tells the
    compiler the register is live across that call, so the save, the install,
    the branch and the restore have to be one sequence.
    
    Built for mps3-an547:bl and mps3-an547:picostest, with CONFIG_FDPIC off,
    which is every configuration in the tree.
    
    Assisted-by: Claude Opus 5 (1M context) <[email protected]>
    Signed-off-by: Marco Casaroli <[email protected]>
---
 arch/Kconfig            |   7 +++
 arch/arm/Kconfig        |   2 +
 arch/arm/include/arch.h |  39 +++++++++++++++
 binfmt/Kconfig          |  32 ++++++++++++
 include/nuttx/fdpic.h   | 129 ++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 209 insertions(+)

diff --git a/arch/Kconfig b/arch/Kconfig
index 3de2bd2caf4..b40bab2a0f0 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -710,6 +710,13 @@ config ARCH_HAVE_ELF_EXECUTABLE
        bool
        default n
 
+config ARCH_HAVE_ELF_FDPIC
+       bool
+       default n
+       ---help---
+               The architecture has a PIC base register and the ELF relocations
+               that an FDPIC object uses.
+
 config ARCH_HAVE_TRUSTZONE
        bool
        default n
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 6a96c672816..9bbf8540d5d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1052,6 +1052,7 @@ config ARCH_ARMV7M
        default n
        select ARCH_HAVE_CPUINFO
        select ARCH_HAVE_DEBUG
+       select ARCH_HAVE_ELF_FDPIC
        select ARCH_HAVE_PERF_EVENTS
 
 config ARCH_CORTEXM3
@@ -1190,6 +1191,7 @@ config ARCH_ARMV8M
        default n
        select ARCH_HAVE_CPUINFO
        select ARCH_HAVE_DEBUG
+       select ARCH_HAVE_ELF_FDPIC
        select ARCH_HAVE_PERF_EVENTS
 
 config ARCH_CORTEXM23
diff --git a/arch/arm/include/arch.h b/arch/arm/include/arch.h
index a91136c4662..da8429bfb59 100644
--- a/arch/arm/include/arch.h
+++ b/arch/arm/include/arch.h
@@ -81,6 +81,45 @@ do { \
   ); \
 } while (0)
 
+#ifdef CONFIG_FDPIC
+
+/****************************************************************************
+ * Name: up_fdpic_invoke
+ *
+ * Description:
+ *   Call a module entry point with the module data base in the PIC base
+ *   register.  Put the caller data base back after the call.
+ *
+ * Input Parameters:
+ *   arg   - The one word argument, passed in r0.
+ *   entry - The code address to enter.
+ *   got   - The module data base to install.
+ *
+ ****************************************************************************/
+
+static inline void up_fdpic_invoke(uintptr_t arg, uintptr_t entry,
+                                   uintptr_t got)
+{
+  register uintptr_t r0v __asm__ ("r0") = arg;
+
+  /* arg is already in r0.  r4 goes on the stack with the PIC register to
+   * keep the push aligned to 8 bytes.
+   */
+
+  __asm__ __volatile__
+  (
+    "push {r4, " PIC_REG_STRING "}\n"   /* Save the caller's base       */
+    "mov " PIC_REG_STRING ", %[got]\n"  /* Install the module's base    */
+    "blx %[entry]\n"                    /* Enter the module             */
+    "pop {r4, " PIC_REG_STRING "}\n"    /* Restore the caller's base    */
+    : "+r" (r0v)
+    : [entry] "r" (entry), [got] "r" (got)
+    : "r1", "r2", "r3", "r12", "lr", "cc", "memory"
+  );
+}
+
+#endif /* CONFIG_FDPIC */
+
 #endif /* CONFIG_PIC */
 
 #ifdef CONFIG_ARCH_ADDRENV
diff --git a/binfmt/Kconfig b/binfmt/Kconfig
index 93844898da0..dd0678af577 100644
--- a/binfmt/Kconfig
+++ b/binfmt/Kconfig
@@ -60,6 +60,38 @@ config ELF_STACKSIZE
        default DEFAULT_TASK_STACKSIZE
        ---help---
                This is the default stack size that will be used when starting 
ELF binaries.
+
+config FDPIC
+       bool "FDPIC modules"
+       default n
+       select PIC
+       depends on ARCH_HAVE_ELF_FDPIC
+       ---help---
+               Load ELF modules built for the FDPIC ABI.
+
+               An FDPIC module places its read-only and writable segments
+               independently, so its text can be executed directly out of flash
+               while only the writable segment is copied to RAM, once per 
running
+               instance.  A filesystem that can show its media, such as XIPFS 
or
+               ROMFS, gives that result.  On any other filesystem the loader 
copies
+               the text to RAM, and the module runs but shares nothing.
+
+               Building a module needs an arm-uclinuxfdpiceabi linker.  The 
stock
+               arm-none-eabi compiler emits correct FDPIC objects for both C 
and
+               C++, so only the link needs it.
+
+               What this adds over the position independent ELF support already
+               present is a function pointer that carries its own data base, 
as a
+               two word descriptor rather than a bare code address.  That is 
what
+               lets a module be called back on a thread it did not create, 
such as
+               the work queue worker that runs a SIGEV_THREAD notification.
+
+               Selecting this makes ten libc and sched entry points that can
+               accept a callback from a module resolve such a descriptor before
+               storing or branching to it.  Each costs a register read and a
+               branch on a path that is not hot.
+
+               This implementation covers ARM Thumb-2.
 endif
 endif
 
diff --git a/include/nuttx/fdpic.h b/include/nuttx/fdpic.h
new file mode 100644
index 00000000000..27b997f7f90
--- /dev/null
+++ b/include/nuttx/fdpic.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+ * include/nuttx/fdpic.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_NUTTX_FDPIC_H
+#define __INCLUDE_NUTTX_FDPIC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/compiler.h>
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* A function descriptor: what a function pointer is under FDPIC.  The
+ * firmware branches to a code address; a module passes one of these.
+ */
+
+struct fdpic_desc_s
+{
+  uintptr_t entry;      /* Address of the code */
+  uintptr_t got;        /* Data base to install before branching */
+};
+
+/****************************************************************************
+ * Inline Functions
+ ****************************************************************************/
+
+#ifdef CONFIG_FDPIC
+
+/****************************************************************************
+ * Name: fdpic_base
+ *
+ * Description:
+ *   The data base of the calling context, from the PIC base register.
+ *   Non-zero means the caller is an FDPIC module, zero means firmware.
+ *
+ ****************************************************************************/
+
+static inline uintptr_t fdpic_base(void)
+{
+  uintptr_t base;
+
+  up_getpicbase(&base);
+  return base;
+}
+
+/****************************************************************************
+ * Name: fdpic_callback
+ *
+ * Description:
+ *   Resolve a function pointer from a caller that may be an FDPIC module.
+ *   Only the entry point is taken: the data base is already in the register.
+ *
+ * Input Parameters:
+ *   fn - The pointer as it was received.
+ *
+ * Returned Value:
+ *   An address that can be branched to directly.
+ *
+ ****************************************************************************/
+
+static inline FAR void *fdpic_callback(FAR void *fn)
+{
+  if (fn != NULL && fdpic_base() != 0)
+    {
+      return (FAR void *)((FAR struct fdpic_desc_s *)fn)->entry;
+    }
+
+  return fn;
+}
+
+/****************************************************************************
+ * Name: fdpic_invoke
+ *
+ * Description:
+ *   Call a resolved module entry point with the module data base in the PIC
+ *   base register.  For a callback that runs on a shared thread, which
+ *   carries no module base.  Elsewhere fdpic_callback() is enough.
+ *
+ * Input Parameters:
+ *   arg   - The one word argument.
+ *   entry - The code address to enter, already resolved from the descriptor.
+ *   got   - The module data base to install.
+ *
+ ****************************************************************************/
+
+static inline void fdpic_invoke(uintptr_t arg, uintptr_t entry,
+                                uintptr_t got)
+{
+  up_fdpic_invoke(arg, entry, got);
+}
+
+#else
+
+#  define fdpic_base()       (0)
+#  define fdpic_callback(fn) (fn)
+#  define fdpic_invoke(arg, entry, got) \
+          ((void)(got), (((CODE void (*)(uintptr_t))(uintptr_t)(entry))(arg)))
+
+#endif /* CONFIG_FDPIC */
+
+#endif /* __INCLUDE_NUTTX_FDPIC_H */

Reply via email to