Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
6 changes: 3 additions & 3 deletions Documentation/applications/examples/nxflatxip/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ Building the module
===================

The module is built from ``module/xipmod.c`` at build time, exactly the way
:doc:`../nxflat/index` builds its test programs, so it needs the same two
host tools from the NuttX toolchain, ``mknxflat`` and ``ldnxflat``, and the
board's ``Make.defs`` must name them.
:doc:`../nxflat/index` builds its test programs, so it needs the same host
tools: ``mknxflat``, which NuttX builds itself, and ``ldnxflat``, which has
to come from the buildroot toolchain. See :doc:`/components/nxflat`.

The module has no static data and no string constants, and reports through a
callback into the firmware rather than formatting its own output. The comment
Expand Down
406 changes: 406 additions & 0 deletions Documentation/components/fdpic.rst

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions Documentation/components/filesystem/nxflat.rst
Original file line number Diff line number Diff line change
Expand Up @@ -160,14 +160,14 @@ indeed, a solution to the above NXFLAT problem in newer
compilers. You simply need to modify the board Make.defs
file like:

1. ARCHPICFLAGS = -fpic -msingle-pic-base -mpic-register=r10
1. ARCHPICFLAGS = -fpic -msingle-pic-base -mpic-register=r9

.. code-block:: bash
+ARCHPICFLAGS = -fpic -msingle-pic-base -mpic-register=r10 -mno-pic-data-is-text-relative
+ARCHPICFLAGS = -fpic -msingle-pic-base -mpic-register=r9 -mno-pic-data-is-text-relative
NOTE the minor difference from the post: NuttX uses ``r10`` as
the PIC base register by default in all configurations.
NuttX uses ``r9`` as the PIC base register in all configurations,
which matches the register named in the post above.

See this `thread <https://groups.google.com/forum/>`_ for additional information.

Expand Down
1 change: 1 addition & 0 deletions Documentation/components/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ case, you can head to the :doc:`reference <../reference/index>`.
binfmt.rst
concurrency/index.rst
drivers/index.rst
fdpic.rst
nxflat.rst
nxgraphics/index.rst
paging.rst
Expand Down
141 changes: 87 additions & 54 deletions Documentation/components/nxflat.rst
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ Limitations
- **Read-Only Data in RAM**:
With older GCC compilers (at least up to 4.3.3), read-only data must
reside in RAM. In code generated by GCC, all data references are
indexed by the PIC2 base register (that is usually R10 or sl for the
ARM processors). The includes read-only data (.rodata). Embedded
indexed by the PIC2 base register (r9 for the ARM processors).
The includes read-only data (.rodata). Embedded
firmware developers normally like to keep .rodata in FLASH with
the code sections. But because all data is referenced with the
PIC base register, all of that data must lie in RAM. A NXFLAT
Expand Down Expand Up @@ -136,57 +136,61 @@ such, NXFLAT is currently in an early alpha phase.
NXFLAT Toolchain
================

Building the NXFLAT Toolchain
-----------------------------

In order to use NXFLAT, you must use special NXFLAT tools to create the
binary module in FLASH. To do this, you will need to download the
buildroot package and build it on your Linux or Cygwin machine. The
buildroot can be downloaded from
`Bitbucket.org <https://bitbucket.org/nuttx/buildroot/downloads>`__. You
will need version 0.1.7 or later.

Here are some general build instructions:

- You must have already configured NuttX in ``<some-dir>/nuttx``
- Download the buildroot package ``buildroot-0.x.y`` into
``<some-dir>``
- Unpack ``<some-dir>/buildroot-0.x.y.tar.gz`` using a command like ``tar zxf buildroot-0.x.y``.
This will result in a new directory like ``<some-dir>/buildroot-0.x.y``
- Move this into position:
``mv <some-dir>/buildroot-0.x.y``\ <some-dir>/buildroot
- ``cd``\ <some-dir>/buildroot
Getting the NXFLAT Tools
------------------------

Building an NXFLAT module takes two tools beyond an ordinary GCC toolchain:
``mknxflat``, which generates the module's *thunk* file, and ``ldnxflat``,
which links the module into the NXFLAT binary format.

``mknxflat`` is part of NuttX, in ``tools/nxflat``. The build produces it as
``tools/mknxflat`` whenever ``CONFIG_NXFLAT`` is selected, so there is
nothing to install.

``ldnxflat`` is not part of NuttX and has to be built from the buildroot
package, which can be downloaded from
`Bitbucket.org <https://bitbucket.org/nuttx/buildroot/downloads>`__. You
will need version 0.1.7 or later:

- Unpack the package and ``cd`` into the resulting directory.
- Copy a configuration file into the top buildroot directory:
``cp boards/abc-defconfig-x.y.z .config``.
- Enable building of the NXFLAT tools by ``make menuconfig``. Select to
build the NXFLAT toolchain with GCC (you can also select omit
building GCC with and only build the NXFLAT toolchain for use with
your own GCC toolchain).
- Make the toolchain: ``make``. When the make completes, the tool
binaries will be available under
``<some-dir>/buildroot/build_abc/staging_dir/bin``
- Run ``make menuconfig`` and select the NXFLAT toolchain. Building GCC
can be omitted if you already have a toolchain of your own.
- Run ``make``. The tool binaries are left under
``build_abc/staging_dir/bin``; put that directory on your ``PATH``.

On ARM, ``arch/arm/src/common/Toolchain.defs`` provides both ``MKNXFLAT``
(with the ``-a`` option following ``CONFIG_ARM_THUMB``) and ``LDNXFLAT``, so
a board only has to assign them if it needs something different.

mknxflat
--------

``mknxflat`` is used to build a *thunk* file. See below
for usage::

Usage: mknxflat [options] <bfd-filename>
Usage: mknxflat [options] <elf-filename>

Where options are one or more of the following. Note
that a space is always required between the option and
any following arguments.
that a space is always required between the
option and any following arguments.

-a <arch>
Instruction set of the module: arm or thumb2
[thumb2]
-d Use dynamic symbol table. [symtab]
-f <cmd-filename>
Take next commands from <cmd-filename> [cmd-line]
-o <out-filename>
Output to [stdout]
Output to <out-filename> [stdout]
-v Verbose output [no output]
-w Import weakly declared functions, i.e., weakly
declared functions are expected to be provided at
load-time [not imported]
declared functions are expected to be
provided at load-time [not imported]

A module calls an imported function through one of these thunks, which
reaches the import table using the module's PIC base register. The thunks
are emitted as assembly, so ``-a`` must match the instruction set the module
was compiled for.

ldnxflat
--------
Expand Down Expand Up @@ -263,7 +267,7 @@ example).
.. code-block:: makefile

hello-thunk.S: hello.r1
mknxflat -o $@ $^
$(MKNXFLAT) -o $@ $^

* Target 3:

Expand All @@ -277,7 +281,7 @@ example).
.. code-block:: makefile

hello: hello.r2
ldnxflat -e main -s 2048 -o $@ $^
$(LDNXFLAT) -e main -s 2048 -o $@ $^

**Target 1**. This target links all of the module's object files
together into one relocatable object. Two relocatable objects will be
Expand All @@ -290,7 +294,7 @@ CFLAGS must be provided. First, the option ``-fpic`` is required to tell
the compiler to generate position independent code (other GCC options,
like ``-fno-jump-tables`` might also be desirable). For ARM compilers,
two additional compilation options are required: ``-msingle-pic-base``
and ``-mpic-register=r10``. On ARM these are supplied centrally rather
and ``-mpic-register=r9``. On ARM these are supplied centrally rather
than per board; see `Where the ARM PIC flags come from`_ below.

**Target 2**. Given the ``hello.r1`` relocatable object, this target
Expand Down Expand Up @@ -331,32 +335,61 @@ object to create the final, NXFLAT module ``hello`` by executing
**binfmt Registration** NXFLAT calls :c:func:`register_binfmt` to
incorporate itself into the system.

Module ABI marker
-----------------

The NXFLAT header carries no version field -- ``h_magic`` is written by
``ldnxflat``, which lives outside this repository and cannot be changed in
step with the loader -- so the module ABI is declared through the import
table instead. Every module built by ``mknxflat`` imports the symbol
``__nxflat_abi_v2``, the base firmware defines it, and the loader refuses a
module whose import table does not name it. The generation is bumped
whenever the module ABI changes; v2 is the move of the PIC base register to
r9, and a v1 module's thunks would add r10 and branch to a wild address on
the first call into the base firmware.

A module built before the marker therefore fails ``exec()`` with
``ENOEXEC``, and with binfmt debug output enabled the loader reports::

ERROR: Module does not declare __nxflat_abi_v2: it was built by a
toolchain predating the r9 PIC base register. Rebuild it.

Rebuilding the module with the current ``mknxflat`` is the entire fix;
nothing in the module source has to change. A module built against a newer
ABI than the firmware fails the other way, with ``Exported symbol
"__nxflat_abi_vN" not found`` and ``ENOENT``.

The marker resolves like any other import, so the exported symbol table
passed to ``exec()`` has to contain it. A table generated from the modules'
thunk files, the way ``apps/tools/mksymtab.sh`` generates one, picks it up
automatically; a hand-written table has to list it.

Where the ARM PIC flags come from
---------------------------------

On ARM the compilation flags described under **Target 1** are supplied by
``arch/arm/src/common/Toolchain.defs``, not by each board. A board only has
to say something when it differs from the default::

ARCHPICFLAGS ?= -fpic -msingle-pic-base -mpic-register=r10
ARCHPICFLAGS ?= -fpic -msingle-pic-base -mpic-register=r9

CPICFLAGS = $(ARCHPICFLAGS) $(filter-out --fixed-r10,$(CFLAGS))
CXXPICFLAGS = $(ARCHPICFLAGS) $(filter-out --fixed-r10,$(CXXFLAGS))
CPICFLAGS = $(ARCHPICFLAGS) $(filter-out --fixed-r9,$(CFLAGS))
CXXPICFLAGS = $(ARCHPICFLAGS) $(filter-out --fixed-r9,$(CXXFLAGS))

``ARCHPICFLAGS`` uses ``?=``, and the two derived variables use deferred
``=``, so a board that includes this file may still override
``ARCHPICFLAGS`` afterwards or append to it, and ``CFLAGS`` is whatever the
board finally set it to. A few boards do differ: one adds ``-ffixed-r10``
and one conditionally adds ``-mno-pic-data-is-text-relative``.
board finally set it to. One board does differ: lm3s6965-ek conditionally
appends ``-mno-pic-data-is-text-relative``.

Reserving r10 in the base firmware
----------------------------------
Reserving r9 in the base firmware
---------------------------------

A module reaches its data through r10, and the base firmware has to leave
A module reaches its data through r9, and the base firmware has to leave
that register alone -- otherwise a call *back* from the firmware into module
code arrives with the wrong data base. ``qsort()`` with a comparison
function inside the module is the usual way to meet this. Under
``CONFIG_PIC`` the firmware is therefore built with ``--fixed-r10``.
``CONFIG_PIC`` the firmware is therefore built with ``--fixed-r9``.

That flag goes into ``ARCHCFLAGS`` rather than ``CFLAGS``, because nearly
every board ``Make.defs`` includes ``Toolchain.defs`` and then assigns::
Expand All @@ -369,8 +402,8 @@ remote from the cause: everything builds, and only a callback into module
code misbehaves.

The two sides of that contract cannot both appear on one command line. A
module gets r10 through ``-mpic-register=r10``, and GCC rejects it alongside
``--fixed-r10`` with *"unable to use 'r10' for PIC register"*. Since
module gets r9 through ``-mpic-register=r9``, and GCC rejects it alongside
``--fixed-r9`` with *"unable to use 'r9' for PIC register"*. Since
``CPICFLAGS``, ``CXXPICFLAGS``, ``CELFFLAGS`` and ``CXXELFFLAGS`` all derive
from ``CFLAGS``, the flag is filtered back out where they are defined,
rather than in every board that builds modules.
Expand All @@ -387,7 +420,7 @@ without PIC:
.. code-block:: asm

ldr r1, .L0 /* Fetch the offset to 'x' */
ldr r0, [r10, r1] /* Load the value of 'x' with PIC offset */
ldr r0, [r9, r1] /* Load the value of 'x' with PIC offset */
/* ... */
.L0: .word x /* Offset to 'x' */

Expand All @@ -397,7 +430,7 @@ generate code like this:
.. code-block:: asm

ldr r1, .L0 /* Fetch the offset to the GOT entry */
ldr r1, [r10, r1] /* Fetch the (relocated) address of 'x' from the GOT */
ldr r1, [r9, r1] /* Fetch the (relocated) address of 'x' from the GOT */
ldr r0, [r1, #0] /* Fetch the value of 'x' */
/* ... */
.L1 .word x(GOT) /* Offset to entry in the GOT */
Expand Down Expand Up @@ -429,7 +462,7 @@ contiguous (virtual) address space like::
.data
.bss

It assumes that the PIC base register (usually r10 for ARM) points to
It assumes that the PIC base register (r9 for ARM) points to
the base of ``.text`` so that any address in ``.text``, ``.got``,
``.data``, ``.bss`` can be found with an offset from the same base
address. But that is not the memory arrangement that we need in the XIP
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -641,7 +641,7 @@ Appendix : out-of-tree code
+
+ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)$(LDSCRIPT)
+
+ARCHPICFLAGS = -fpic -msingle-pic-base -mpic-register=r10
+ARCHPICFLAGS = -fpic -msingle-pic-base -mpic-register=r9
+
+CFLAGS := $(ARCHCFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe
+CPICFLAGS = $(ARCHPICFLAGS) $(CFLAGS)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,24 @@ xipfs
XIPFS mounted on the on-board flash, with the ``xipfs`` command and the
XIPFS test suite.

xipfs-fdpic
-----------

Same as ``xipfs``, plus the FDPIC module loader and the
``fdpicxip`` demo, so the ``fdpic`` and ``reject`` sections of the XIPFS
test suite have something to run. The demo carries its modules as
committed byte arrays, so nothing beyond the ordinary ARM toolchain is
needed to build it; rebuilding those from source needs
``arm-uclinuxfdpiceabi`` binutils. See :doc:`/components/fdpic`.

``CONFIG_ELF_STACKSIZE`` is 4096 here rather than the 2048 the rest of
the board's tasks use. A module that calls into the firmware's printf
family overflows 2048, and with no MPU that is a lockup rather than a
diagnostic.

xipfs-nxflat
------------

Same as ``xipfs``, plus the NXFLAT execute-in-place demo. Building this
configuration requires the NXFLAT tools (``mknxflat`` and ``ldnxflat``),
which are not part of a standard toolchain installation.
configuration requires ``ldnxflat``, which is not part of a standard
toolchain installation; see :doc:`/components/nxflat`.
10 changes: 6 additions & 4 deletions arch/arm/include/arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,14 @@

#ifdef CONFIG_PIC

/* This identifies the register the is used by the processor as the PIC base
* register. It is usually r9 or r10
/* 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 r10
#define PIC_REG_STRING "r10"
#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
Expand Down
6 changes: 3 additions & 3 deletions arch/arm/include/arm/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,11 @@
#define REG_LR REG_R14
#define REG_PC REG_R15

/* The PIC register is usually R10. It can be R9 is stack checking is enabled
* or if the user changes it with -mpic-register on the GCC command line.
/* The PIC base register is R9, the AAPCS platform register. See PIC_REG
* in arch/arm/include/arch.h; every PIC binary format uses the same one.
*/

#define REG_PIC REG_R10
#define REG_PIC REG_R9

/****************************************************************************
* Public Types
Expand Down
6 changes: 3 additions & 3 deletions arch/arm/include/armv6-m/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,11 @@
#define REG_LR REG_R14
#define REG_PC REG_R15

/* The PIC register is usually R10. It can be R9 is stack checking is enabled
* or if the user changes it with -mpic-register on the GCC command line.
/* The PIC base register is R9, the AAPCS platform register. See PIC_REG
* in arch/arm/include/arch.h; every PIC binary format uses the same one.
*/

#define REG_PIC REG_R10
#define REG_PIC REG_R9

/* CONTROL register */

Expand Down
6 changes: 3 additions & 3 deletions arch/arm/include/armv7-a/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,11 @@
#define REG_LR REG_R14
#define REG_PC REG_R15

/* The PIC register is usually R10. It can be R9 is stack checking is enabled
* or if the user changes it with -mpic-register on the GCC command line.
/* The PIC base register is R9, the AAPCS platform register. See PIC_REG
* in arch/arm/include/arch.h; every PIC binary format uses the same one.
*/

#define REG_PIC REG_R10
#define REG_PIC REG_R9

/* Multiprocessor Affinity Register (MPIDR): CRn=c0, opc1=0, CRm=c0, opc2=5 */

Expand Down
6 changes: 3 additions & 3 deletions arch/arm/include/armv7-m/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,11 @@
#define REG_LR REG_R14
#define REG_PC REG_R15

/* The PIC register is usually R10. It can be R9 is stack checking is enabled
* or if the user changes it with -mpic-register on the GCC command line.
/* The PIC base register is R9, the AAPCS platform register. See PIC_REG
* in arch/arm/include/arch.h; every PIC binary format uses the same one.
*/

#define REG_PIC REG_R10
#define REG_PIC REG_R9

/* CONTROL register */

Expand Down
Loading
Loading