mirror of
https://github.com/apache/nuttx.git
synced 2026-05-28 03:45:50 +08:00
documentation: implement on-demand paging for RISC-V devices
It documents how the on-demand paging was implemented for RISC-V devices and how it can be extended to other architectures.
This commit is contained in:
committed by
Xiang Xiao
parent
c67502d9b4
commit
e287ed9090
@@ -4,17 +4,78 @@
|
|||||||
On-Demand Paging
|
On-Demand Paging
|
||||||
================
|
================
|
||||||
|
|
||||||
Introduction
|
Kernel Build Implementation
|
||||||
============
|
===========================
|
||||||
|
|
||||||
Overview
|
On-demand paging and lazy loading are techniques used to manage physical
|
||||||
--------
|
memory. The basic idea is to allow a program to execute even though the
|
||||||
|
entire program is not resident in memory. The program is loaded into
|
||||||
|
memory on demand. This is a technique that is used in many operating
|
||||||
|
systems to allow large programs to execute on small memory systems.
|
||||||
|
Commonly, a Memory Management Unit (MMU) is used to map virtual memory
|
||||||
|
into physical memory. Applications are then loaded into virtual memory
|
||||||
|
address spaces and access to physical memory is managed by the MMU. If
|
||||||
|
the virtual memory is not resident in physical memory, then a page fault
|
||||||
|
occurs. The operating system then loads the missing page into memory and
|
||||||
|
resumes execution.
|
||||||
|
|
||||||
This document summarizes the design of NuttX on-demand paging. This
|
Requirements and Assumptions
|
||||||
feature permits embedded MCUs with some limited RAM space to execute
|
----------------------------
|
||||||
large programs from some non-random access media.
|
|
||||||
|
|
||||||
What kind of platforms can support NuttX on-demang paging?
|
On-demand paging requires *Kernel Build* (``CONFIG_BUILD_KERNEL=y``) mode.
|
||||||
|
In this mode, no applications are built within the NuttX kernel. Instead,
|
||||||
|
the applications are built as separate programs that are loaded into memory
|
||||||
|
(``CONFIG_ELF=y`` and ``CONFIG_BINFMT_LOADABLE=y``). In this mode, each
|
||||||
|
process has its own address environment (``CONFIG_ARCH_ADDRENV=y``).
|
||||||
|
|
||||||
|
Logic Design Description
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
When an application is being loaded ``up_addrenv_create`` is called to create
|
||||||
|
the process's address environment. This includes mapping the commonly used
|
||||||
|
``text``, ``data`` and ``heap`` sections withing the virtual memory space.
|
||||||
|
Without on-demand paging, the physical memory is then allocated and mapped
|
||||||
|
accordingly, before the process is started. When on-demand paging is enabled,
|
||||||
|
usually only one single page for each section is allocated and mapped.
|
||||||
|
|
||||||
|
The process starts executing within its address environment, accessing the
|
||||||
|
virtual memory. Whenever it tries to access a virtual memory address that is
|
||||||
|
not mapped in the MMU, a page fault occurs. The MMU then triggers an
|
||||||
|
exception that is handled by the kernel. The kernel then checks if there are
|
||||||
|
enough free physical pages available and maps the virtual memory address to
|
||||||
|
it. Finally, execution is resumed from the same point where the page fault
|
||||||
|
first occurred.
|
||||||
|
|
||||||
|
Example: RISC-V
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
RISC-V's ``up_addrenv_create`` calls ``create_region`` (both defined in
|
||||||
|
``arch/risc-v/src/common/riscv_addrenv.c``). ``create_region`` maps a single
|
||||||
|
region to MMU by allocating physical memory for the page tables. When
|
||||||
|
``CONFIG_PAGING=y`` is not selected, all the physical page tables are
|
||||||
|
allocated from the physical memory space and then mapped to the virtual
|
||||||
|
memory space. When ``CONFIG_PAGING=y`` is selected, only the first page of
|
||||||
|
each section is mapped to the virtual memory space. The rest of the pages are
|
||||||
|
mapped to the virtual memory space only when a page fault occurs.
|
||||||
|
|
||||||
|
The page fault is handled by the ``riscv_fillpage`` function in the exception
|
||||||
|
handler (defined in ``arch/risc-v/src/common/riscv_exception.c``). Whenever
|
||||||
|
a page fault occurs, the ``riscv_fillpage`` function is called. This function
|
||||||
|
allocates a physical page and maps it to the virtual memory space that
|
||||||
|
triggered the page fault exception and then resumes execution from the same
|
||||||
|
point where the page fault first occurred.
|
||||||
|
|
||||||
|
:ref:`knsh32_paging` simulates a device with 4MiB physical memory with 8MiB
|
||||||
|
of virtual heap memory allocated for each process. This is possible by
|
||||||
|
enabling on-demand paging.
|
||||||
|
|
||||||
|
Legacy Implementation
|
||||||
|
=====================
|
||||||
|
|
||||||
|
This legacy implementation runs on *Flat Build* (*Kernel Build* did not
|
||||||
|
even exist at that time).
|
||||||
|
|
||||||
|
What kind of platforms can support NuttX legacy on-demand paging?
|
||||||
|
|
||||||
#. The MCU should have some large, probably low-cost non-volatile
|
#. The MCU should have some large, probably low-cost non-volatile
|
||||||
storage such as serial FLASH or an SD card. This storage probably
|
storage such as serial FLASH or an SD card. This storage probably
|
||||||
@@ -29,7 +90,7 @@ What kind of platforms can support NuttX on-demang paging?
|
|||||||
LPC3131) would be sufficient for many applications.
|
LPC3131) would be sufficient for many applications.
|
||||||
#. The MCU has an MMU (again like the NXP LPC3131).
|
#. The MCU has an MMU (again like the NXP LPC3131).
|
||||||
|
|
||||||
If the platform meets these requirement, then NuttX can provide
|
If the platform meets these requirements, then NuttX can provide
|
||||||
on-demand paging: It can copy .text from the large program in
|
on-demand paging: It can copy .text from the large program in
|
||||||
non-volatile media into RAM as needed to execute a huge program from the
|
non-volatile media into RAM as needed to execute a huge program from the
|
||||||
small RAM.
|
small RAM.
|
||||||
@@ -55,10 +116,10 @@ Terminology
|
|||||||
Task Control Block
|
Task Control Block
|
||||||
|
|
||||||
NuttX Common Logic Design Description
|
NuttX Common Logic Design Description
|
||||||
=====================================
|
-------------------------------------
|
||||||
|
|
||||||
Initialization
|
Initialization
|
||||||
--------------
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
The following declarations will be added.
|
The following declarations will be added.
|
||||||
|
|
||||||
@@ -89,7 +150,7 @@ logic, those architecture specific functions are instead declared in
|
|||||||
``include/nuttx/page.h``.
|
``include/nuttx/page.h``.
|
||||||
|
|
||||||
Page Faults
|
Page Faults
|
||||||
-----------
|
^^^^^^^^^^^
|
||||||
|
|
||||||
**Page fault exception handling**. Page fault handling is performed by
|
**Page fault exception handling**. Page fault handling is performed by
|
||||||
the function ``pg_miss()``. This function is called from
|
the function ``pg_miss()``. This function is called from
|
||||||
@@ -146,7 +207,7 @@ inputs are required.
|
|||||||
page fill.
|
page fill.
|
||||||
|
|
||||||
Fill Initiation
|
Fill Initiation
|
||||||
---------------
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
The page fill worker thread will be awakened on one of three conditions:
|
The page fill worker thread will be awakened on one of three conditions:
|
||||||
|
|
||||||
@@ -217,7 +278,7 @@ The architecture-specific functions, ``up_checkmapping()``,
|
|||||||
will be prototyped in ``include/nuttx/arch.h``
|
will be prototyped in ``include/nuttx/arch.h``
|
||||||
|
|
||||||
Fill Complete
|
Fill Complete
|
||||||
-------------
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
For the blocking ``up_fillpage()``, the result of the fill will be
|
For the blocking ``up_fillpage()``, the result of the fill will be
|
||||||
returned directly from the call to ``up_fillpage``.
|
returned directly from the call to ``up_fillpage``.
|
||||||
@@ -246,7 +307,7 @@ completed:
|
|||||||
- Signal the page fill worker thread.
|
- Signal the page fill worker thread.
|
||||||
|
|
||||||
Task Resumption
|
Task Resumption
|
||||||
---------------
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
For the non-blocking ``up_fillpage()``, the page fill worker thread will
|
For the non-blocking ``up_fillpage()``, the page fill worker thread will
|
||||||
detect that the page fill is complete when it is awakened with
|
detect that the page fill is complete when it is awakened with
|
||||||
@@ -279,10 +340,10 @@ In this either, the page fill worker thread will:
|
|||||||
- Wait for the next fill related event (a new page fault).
|
- Wait for the next fill related event (a new page fault).
|
||||||
|
|
||||||
Architecture-Specific Support Requirements
|
Architecture-Specific Support Requirements
|
||||||
==========================================
|
------------------------------------------
|
||||||
|
|
||||||
Memory Organization
|
Memory Organization
|
||||||
-------------------
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
**Memory Regions**. Chip specific logic will map the virtual and
|
**Memory Regions**. Chip specific logic will map the virtual and
|
||||||
physical address spaces into three general regions:
|
physical address spaces into three general regions:
|
||||||
@@ -367,7 +428,7 @@ would be a two phase link:
|
|||||||
"non-swappable" region.
|
"non-swappable" region.
|
||||||
|
|
||||||
Architecture-Specific Functions
|
Architecture-Specific Functions
|
||||||
-------------------------------
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Most standard, architecture-specific functions are declared in
|
Most standard, architecture-specific functions are declared in
|
||||||
``include/nuttx/arch.h``. However, for the case of this paging logic,
|
``include/nuttx/arch.h``. However, for the case of this paging logic,
|
||||||
@@ -406,4 +467,3 @@ implemented just for on-demand paging support are:
|
|||||||
will be called when the page fill is finished (or an error occurs). This
|
will be called when the page fill is finished (or an error occurs). This
|
||||||
callback is assumed to occur from an interrupt level when the device
|
callback is assumed to occur from an interrupt level when the device
|
||||||
driver completes the fill operation.
|
driver completes the fill operation.
|
||||||
|
|
||||||
|
|||||||
@@ -154,6 +154,22 @@ In `nsh`, applications can be run from the `/system/bin` directory::
|
|||||||
|
|
||||||
nsh> /system/bin/hello
|
nsh> /system/bin/hello
|
||||||
|
|
||||||
|
.. _knsh32_paging:
|
||||||
|
|
||||||
|
knsh32_paging
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Similar to ``knsh32_romfs``, but enabling on-demand paging: this
|
||||||
|
configuration simulates a 4MiB device (using QEMU), but sets the number of
|
||||||
|
heap pages equal to ``CONFIG_ARCH_HEAP_NPAGES=2048``. This means that each
|
||||||
|
process's heap is 8MiB, whereas ``CONFIG_POSIX_SPAWN_DEFAULT_STACKSIZE`` is
|
||||||
|
``1048576`` (1MiB) represents the stack size of the processes (which is
|
||||||
|
allocated from the process's heap). This configuration is used for 32-bit
|
||||||
|
RISC-V which implements the Sv32 MMU specification and enables processes
|
||||||
|
to have their own address space larger than the available physical memory.
|
||||||
|
This is particularly useful for implementing a set of programming language
|
||||||
|
interpreters.
|
||||||
|
|
||||||
knsh32_romfs
|
knsh32_romfs
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user