Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,63 @@ After successfully built and flashed, run on the boards's terminal::

The corresponding output should show related debug information.

kernel_n8r2
-----------

A KERNEL build for a module with 2 MB of PSRAM, such as the
ESP32-S3-WROOM-1-N8R2. The flash is quad and runs in DIO mode.

The page pool is smaller than in ``kernel_oct``, and each of the text, data
and heap regions of a process is 2 pages of 64 KiB. A process therefore takes
384 KiB, and a ``fork()`` needs 768 KiB while the parent and the child both
exist.

This is tight on purpose. ``ostest`` has 115 KiB of text against a 128 KiB
text region. A larger program needs a module with more PSRAM, not a larger
page pool.

kernel_oct
----------

A KERNEL build for a module with octal flash and 8 MB of PSRAM, such as the
ESP32-S3-WROOM-2-N32R8V.

A KERNEL build gives each process its own address environment. This is the
only build mode in which ``fork()`` is available on this chip: the child
receives its own copy of the memory of the parent, at the same virtual
addresses. ``vfork()`` is available in every build mode.

The page pool holds the pages of every process. It is carved out of the
PSRAM, and it is not kept mapped into the kernel address space. The kernel
reaches a page of the pool through a small scratch region, mapped for one
operation and invalidated afterwards.

Build the kernel first, then the applications, then the boot ROMFS, and then
link the kernel again. The ROMFS is linked into the kernel image, so a change
to an application needs the whole chain::

make -j
make export
cd ../apps
./tools/mkimport.sh -z -x ../nuttx/nuttx-export-*.tar.gz
make import -j
./tools/mkromfsimg.sh ../nuttx/arch/xtensa/src/board/board/romfs_boot.c
cd ../nuttx
make -j

Confirm that the ROMFS is in the image. ``romfs_img`` must be a strong symbol
of a few hundred kilobytes::

xtensa-esp32s3-elf-nm -S nuttx | grep " romfs_img$"

A one byte symbol means that the linker took the stub. Delete
``boards/xtensa/esp32s3/esp32s3-devkit/src/romfs_stub.o`` and ``libboard.a``,
then link again.

The shell needs the full path of a program in this build mode::

nsh> /system/bin/ostest

knsh
----

Expand Down
25 changes: 15 additions & 10 deletions arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ config ARCH_XTENSA
bool "Xtensa"
select ARCH_HAVE_BACKTRACE
select ARCH_HAVE_VFORK
select ARCH_HAVE_FORK if BUILD_KERNEL && ARCH_ADDRENV
select ARCH_HAVE_CPUINFO
select ARCH_HAVE_INTERRUPTSTACK
select ARCH_HAVE_STACKCHECK
Expand Down Expand Up @@ -1029,8 +1030,6 @@ config ARCH_PGPOOL_MAPPING
Otherwise, a temporary mapping will have to be established each time
it is necessary to modify the contents of a page.

if ARCH_PGPOOL_MAPPING

config ARCH_PGPOOL_PBASE
hex "Page pool physical address"
default 0x0
Expand All @@ -1040,14 +1039,9 @@ config ARCH_PGPOOL_PBASE
but is required again in order to modularize the common address
environment logic.

config ARCH_PGPOOL_VBASE
hex "Page pool virtual address"
default 0x0
---help---
The virtual address of the start of the page pool memory. This
setting is probably equivalent to other platform specific definitions
but is required again in order to modularize the common address
environment logic.
This applies whether or not the pool is statically mapped: the page
allocator hands out physical addresses either way. Only
ARCH_PGPOOL_VBASE depends on ARCH_PGPOOL_MAPPING.

config ARCH_PGPOOL_SIZE
int "Page pool size (bytes)"
Expand All @@ -1057,6 +1051,17 @@ config ARCH_PGPOOL_SIZE
equivalent to other platform specific definitions but is required again
in order to modularize the common address environment logic.

if ARCH_PGPOOL_MAPPING

config ARCH_PGPOOL_VBASE
hex "Page pool virtual address"
default 0x0
---help---
The virtual address of the start of the page pool memory. This
setting is probably equivalent to other platform specific definitions
but is required again in order to modularize the common address
environment logic.

endif # ARCH_PGPOOL_MAPPING
endif # ARCH_ADDRENV && ARCH_NEED_ADDRENV_MAPPING

Expand Down
4 changes: 4 additions & 0 deletions arch/xtensa/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ config ARCH_CHIP_ESP32S3
select ARCH_HAVE_DEBUG
select ARCH_HAVE_FPU
select ARCH_HAVE_MPU
select ARCH_HAVE_MMU
select ARCH_HAVE_ADDRENV
select ARCH_NEED_ADDRENV_MAPPING
select ARCH_HAVE_ELF_EXECUTABLE
select ARCH_HAVE_MULTICPU
select ARCH_HAVE_RESET
select ARCH_HAVE_TEXT_HEAP
Expand Down
50 changes: 50 additions & 0 deletions arch/xtensa/include/arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,56 @@
* Public Types
****************************************************************************/

#ifdef CONFIG_ARCH_ADDRENV
#ifndef __ASSEMBLY__

/* The ESP32-S3 has no general paging MMU and no per-process page-table root.
* External memory (PSRAM) is reached through a single global cache-MMU remap
* table with separate instruction-bus (.text) and data-bus (.data/.bss/heap)
* address windows, at 64 KB page granularity. An address environment is
* therefore described not by a page-table root (no satp/TTBR equivalent) but
* by the set of physical PSRAM pages that back the process plus the fixed
* virtual window bases. up_addrenv_select() makes an environment active by
* reprogramming the cache-MMU window entries to point at these pages,
* invalidating the cache, and reprogramming the PMS split lines that gate
* WORLD1 (user) access -- with a fast path when the incoming environment is
* already the active one (thread<->thread, ISR, syscall).
*/

struct arch_addrenv_s
{
/* Virtual bases and heap size. Returned by up_addrenv_vtext/vdata/vheap
* and up_addrenv_heapsize. .text maps through the instruction-bus window,
* .data/.bss and the heap through the data-bus window.
*/

uintptr_t textvbase;
uintptr_t datavbase;
uintptr_t heapvbase;
size_t heapsize;

/* Physical PSRAM page addresses backing each region -- one 64 KB page per
* entry, allocated from the PSRAM page pool by up_addrenv_create().
* Index i of a region backs virtual page i counted from that region's
* vbase.
*/

uintptr_t textpages[CONFIG_ARCH_TEXT_NPAGES];
uintptr_t datapages[CONFIG_ARCH_DATA_NPAGES];
uintptr_t heappages[CONFIG_ARCH_HEAP_NPAGES];

/* Number of pages actually allocated in each region */

uint16_t ntext;
uint16_t ndata;
uint16_t nheap;
};

typedef struct arch_addrenv_s arch_addrenv_t;

#endif /* __ASSEMBLY__ */
#endif /* CONFIG_ARCH_ADDRENV */

/****************************************************************************
* Public Data
****************************************************************************/
Expand Down
50 changes: 49 additions & 1 deletion arch/xtensa/src/esp32s3/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,26 @@ config ESP32S3_RUN_IRAM
This loads all of NuttX inside IRAM. Used to test somewhat small
images that can fit entirely in IRAM.

config ESP32S3_PGPOOL_SCRATCH
bool
default y
depends on BUILD_KERNEL && ARCH_ADDRENV && MM_PGALLOC
select ARCH_KVMA_MAPPING
---help---
The page pool is deliberately not kept mapped into the kernel
address space: it is carved out of the PSRAM the user processes
themselves run from, and the external memory permissions are indexed
by physical address, so a kernel window onto the pool is a window
onto every process's memory that no permission setting can close.

The kernel reaches a pool page through a small scratch region
instead, mapped for the duration of one operation and invalidated
afterwards. ARCH_KMAP_VBASE and ARCH_KMAP_NPAGES describe it.

The pool itself is described by ARCH_PGPOOL_PBASE and
ARCH_PGPOOL_SIZE as usual. Only ARCH_PGPOOL_VBASE does not apply,
because there is no permanent virtual mapping to name.

menu "ESP32-S3 Peripheral Selection"

source "arch/xtensa/src/common/espressif/Kconfig"
Expand Down Expand Up @@ -923,7 +943,35 @@ config ESP32S3_WCL
bool "World Controller"
default n
select ARCH_USE_MPU
select XTENSA_HAVE_GENERAL_EXCEPTION_HOOKS if BUILD_PROTECTED
select XTENSA_HAVE_GENERAL_EXCEPTION_HOOKS if !BUILD_FLAT

config ESP32S3_PAGEFAULT
bool "Recoverable PMS permission faults"
default n
depends on !BUILD_FLAT
---help---
Route the precise Load/Store/InstrFetch Prohibited exceptions raised
by PMS (memory-protection) permission violations through a
recoverable-fault dispatcher instead of panicking unconditionally.
This is the foundation for guard pages, lazy stack/heap growth and,
ultimately, demand paging / copy-on-write on the ESP32-S3.

if ESP32S3_PAGEFAULT

config ESP32S3_PAGEFAULT_SELFTEST
bool "Recoverable-fault self-test"
default n
---help---
Prove the recoverable-fault primitive on silicon. A load from
0x80000000 raises a precise LoadProhibited (EXCCAUSE 28, "cache
attribute does not allow load"); the fault dispatcher lets the RFE
re-execute the identical faulting instruction several times (proving
a faulted precise access restarts cleanly) before stepping past it,
reporting the result over the console. Trigger it from a user task,
e.g. with examples/pffault: nsh> pffault r 0x80000000
For bring-up and evaluation only.

endif # ESP32S3_PAGEFAULT

config ESP32S3_LCD
bool "LCD"
Expand Down
19 changes: 19 additions & 0 deletions arch/xtensa/src/esp32s3/Make.defs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,25 @@ ifeq ($(CONFIG_BUILD_PROTECTED),y)
CHIP_CSRCS += esp32s3_userspace.c
endif

# The MMU/PMS/WCL primitives back both the protected user split and the
# BUILD_KERNEL address-environment remap.

ifneq ($(filter y,$(CONFIG_BUILD_PROTECTED) $(CONFIG_ARCH_ADDRENV)),)
CHIP_CSRCS += esp32s3_mmu.c esp32s3_pms.c esp32s3_wcl.c
endif

ifeq ($(CONFIG_ESP32S3_PAGEFAULT),y)
CHIP_CSRCS += esp32s3_pagefault.c
endif

ifeq ($(CONFIG_ARCH_ADDRENV),y)
CHIP_CSRCS += esp32s3_addrenv.c esp32s3_addrenv_utils.c
endif

ifeq ($(CONFIG_MM_PGALLOC),y)
CHIP_CSRCS += esp32s3_pgalloc.c
endif

ifeq ($(CONFIG_SMP),y)
CHIP_CSRCS += esp32s3_cpuidlestack.c esp32s3_cpustart.c esp32s3_intercpu_interrupt.c
endif
Expand Down
4 changes: 2 additions & 2 deletions arch/xtensa/src/esp32s3/chip_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
#endif
#endif

#if defined(CONFIG_ESP32S3_WCL) && defined(CONFIG_BUILD_PROTECTED)
#if defined(CONFIG_ESP32S3_WCL) && !defined(CONFIG_BUILD_FLAT)
#include "hardware/esp32s3_wcl_core.h"
#endif

Expand All @@ -47,7 +47,7 @@

#define HANDLER_SECTION .iram1

#if defined(CONFIG_ESP32S3_WCL) && defined(CONFIG_BUILD_PROTECTED)
#if defined(CONFIG_ESP32S3_WCL) && !defined(CONFIG_BUILD_FLAT)

/* Definitions for the Worlds reserved for Kernel and Userspace */

Expand Down
Loading
Loading