nuttx/arch/arm/include/arch.h
Marco Casaroli 9f1107862b 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) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-09-08 16:31:16 -03:00

231 lines
7.2 KiB
C

/****************************************************************************
* arch/arm/include/arch.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.
*
****************************************************************************/
/* This file should never be included directly but, rather,
* only indirectly through nuttx/arch.h
*/
#ifndef __ARCH_ARM_INCLUDE_ARCH_H
#define __ARCH_ARM_INCLUDE_ARCH_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#ifndef __ASSEMBLY__
# include <stdint.h>
# include <nuttx/pgalloc.h>
#endif
#include <arch/barriers.h>
/****************************************************************************
* Pre-processor Prototypes
****************************************************************************/
#ifdef CONFIG_PIC
/* This identifies the register that is used by the processor as the PIC base
* register. r9 is the AAPCS platform register (the "static base"), which is
* also what GCC picks for -msingle-pic-base on an EABI target, so the whole
* of PIC uses it: NXFLAT, ELF PIC, and CONFIG_BUILD_PIC alike.
*/
#define PIC_REG r9
#define PIC_REG_STRING "r9"
/* Macros to get and set the PIC base register. picbase is assumed to be
* of type (void*) and that it will fit into a uint32_t. These must be
* inline so that they will be compatible with the ABIs rules for
* preserving the PIC register
*/
#define up_getpicbase(ppicbase) \
do { \
uint32_t picbase; \
__asm__ \
( \
"\tmov %0, " PIC_REG_STRING "\n\t" \
: "=r"(picbase) \
); \
*(uint32_t *)ppicbase = picbase; \
} while (0)
#define up_setpicbase(picbase) \
do { \
uint32_t _picbase = (uint32_t)picbase; \
__asm__ \
( \
"\tmov " PIC_REG_STRING ", %0\n\t" \
: : "r"(_picbase) : PIC_REG_STRING \
); \
} 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
#if CONFIG_MM_PGSIZE != 4096
# error Only pages sizes of 4096 are currently supported (CONFIG_ARCH_ADDRENV)
#endif
/* Convert 4KiB pages to 1MiB sections */
# define __PG2SECT_SHIFT (20 - MM_PGSHIFT)
# define __PG2SECT_MASK ((1 << __PG2SECT_SHIFT) - 1)
# define ARCH_PG2SECT(p) (((p) + __PG2SECT_MASK) >> __PG2SECT_SHIFT)
# define ARCH_SECT2PG(s) ((s) << __PG2SECT_SHIFT)
# define ARCH_TEXT_NSECTS ARCH_PG2SECT(CONFIG_ARCH_TEXT_NPAGES)
# define ARCH_DATA_NSECTS ARCH_PG2SECT(CONFIG_ARCH_DATA_NPAGES)
# define ARCH_HEAP_NSECTS ARCH_PG2SECT(CONFIG_ARCH_HEAP_NPAGES)
# ifdef CONFIG_ARCH_VMA_MAPPING
# define ARCH_SHM_NSECTS ARCH_PG2SECT((CONFIG_ARCH_SHM_NPAGES * CONFIG_ARCH_SHM_MAXREGIONS))
# endif
# ifdef CONFIG_ARCH_STACK_DYNAMIC
# define ARCH_STACK_NSECTS ARCH_PG2SECT(CONFIG_ARCH_STACK_NPAGES)
# endif
#endif /* CONFIG_ARCH_ADDRENV */
/* Redefine the linker symbols as armlink style */
#ifdef CONFIG_ARM_TOOLCHAIN_ARMCLANG
# define _sinit Image$$init_section$$Base
# define _einit Image$$init_section$$Limit
#endif
#ifdef CONFIG_ARM_HAVE_WFE_SEV
# define UP_WFE() __asm__ __volatile__ ("wfe" : : : "memory")
# define UP_SEV() __asm__ __volatile__ ("sev" : : : "memory")
#endif
/****************************************************************************
* Inline functions
****************************************************************************/
/****************************************************************************
* Public Types
****************************************************************************/
#ifdef CONFIG_ARCH_ADDRENV
/* The task group resources are retained in a single structure, task_group_s
* that is defined in the header file nuttx/include/nuttx/sched.h. The type
* arch_addrenv_t must be defined by platform specific logic in
* nuttx/arch/<architecture>/include/arch.h.
*
* These tables would hold the physical address of the level 2 page tables.
* All would be initially NULL and would not be backed up with physical
* memory until mappings in the level 2 page table are required.
*/
struct arch_addrenv_s
{
/* Alloc whole l1table to make better context switch performance */
uintptr_t *l1table;
/* The text, data, heap bases and heap size here */
uintptr_t textvbase;
uintptr_t datavbase;
uintptr_t heapvbase;
/* Initial heap allocation (in bytes). This exists only provide an
* indirect path for passing the size of the initial heap to the heap
* initialization logic. These operations are separated in time and
* architecture. REVISIT: I would like a better way to do this.
*/
size_t heapsize;
#ifdef CONFIG_ARCH_VMA_MAPPING
uintptr_t shmvbase;
#endif
};
typedef struct arch_addrenv_s arch_addrenv_t;
#endif
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* __ARCH_ARM_INCLUDE_ARCH_H */