diff --git a/ChangeLog b/ChangeLog index 614381c900ad8d367eebbcf144cbd70227348009..107a426d6f296f0224e271cfd8fc57855f13f7eb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -816,7 +816,7 @@ and (2) it requires symbol table arguments. * lib/: Add fileno() * examples/ostest: Several of the tests used a big, hard-coded stack size - when creating test threads (16Kb stacksize). The stack size should + when creating test threads (16K stacksize). The stack size should be controlled by the .config file or the OSTest won't work on platforms with memory constraints. * netutils/thttpd: An initial port of Jeff Poskanzer's THTTPD HTTP server. @@ -1369,10 +1369,10 @@ out instead. This improves behavior, for example, on the first GET request from a browser. * arch/arm/src/lpc17xx/lpc17_emacram.h and lpc17_allocateheap.c: The Ethernet - logic was using all of AHB SRAM Bank0 for Ethernet packet buffers (16Kb). An + logic was using all of AHB SRAM Bank0 for Ethernet packet buffers (16K). An option was added to limit the amount of SRAM used for packet buffering and to re-use any extra Bank0 memory for heap. configs/olimex-lpc1766stk/nettest - now uses only 8Kb at the beginning of Bank0; the 8Kb at the end of Bank0 is + now uses only 8K at the beginning of Bank0; the 8K at the end of Bank0 is included in the heap * arch/arm/src/lpc17xx/lpc17_ssp.c: Fix compilation errors when SSP1 is selected. @@ -1785,7 +1785,7 @@ that support 16-bit addressability have smaller overhead than devices that support 32-bit addressability. However, there are many MCUs that support 32-bit addressability *but* have internal SRAM of size - less than or equal to 64Kb. In this case, CONFIG_MM_SMALL can be + less than or equal to 64K. In this case, CONFIG_MM_SMALL can be defined so that those MCUs will also benefit from the smaller, 16- bit-based allocation overhead. * lib/string/lib_strndup.c: Add standard strndup() library function. @@ -1846,7 +1846,7 @@ * arch/sim/src/up_romgetc.c: Used to test the basic logic to access strings without directly de-referencing a string pointer. * arch/avr/src/avr/up_romget.c: Used to access strings that lie in the first - 64Kb of FLASH (But I still haven't figured out how to get strings to reside in + 64K of FLASH (But I still haven't figured out how to get strings to reside in FLASH without using the PROGMEM attribute). * configs/teensy/src/up_spi.c: Correct reading of SD CD and WP pins (was reading the wrong register. AVR SPI now appears to be functional. diff --git a/Documentation/NuttShell.html b/Documentation/NuttShell.html index a92cbadd8e62e86955a56857f3935935df109ebc..ca7e82627966b5679d4f303d16b2e4283d596969 100644 --- a/Documentation/NuttShell.html +++ b/Documentation/NuttShell.html @@ -8,7 +8,7 @@ <tr align="center" bgcolor="#e4e4e4"> <td> <h1><big><font color="#3c34ec"><i>NuttShell (NSH)</i></font></big></h1> - <p>Last Updated: August 3, 2012</p> + <p>Last Updated: August 7, 2012</p> </td> </tr> </table> @@ -1210,7 +1210,7 @@ losetup [-o <offset>] [-r] <dev-path> <file-path> <p> <b>Synopsis</b>. Setup the loop device at <dev-path> to access the file at <file-path> as a block device. - In the following example a 256Kb file is created (<code>dd</code>) and <code>losetup</code> is + In the following example a 256K file is created (<code>dd</code>) and <code>losetup</code> is used to make the file accessible as a block device. A FAT file system is created (<code>mkfatfs</code>) and mounted (<code>mount</code>). Files can then be managed on the loop-mounted file. @@ -3148,7 +3148,7 @@ endef </p> <li> <p> - The make file then defines the application name (<code>hello</code>), the task priority (default), and the stack size that will be allocated in the task runs (2Kb). + The make file then defines the application name (<code>hello</code>), the task priority (default), and the stack size that will be allocated in the task runs (2K). </p> <ul><pre> APPNAME = hello @@ -3160,7 +3160,7 @@ STACKSIZE = 2048 <p> And finally, the <code>Makefile</code> invokes the <code>REGISTER</code> macro to added the <code>hello_main()</code> named application. Then, when the system build completes, the <code>hello</code> command can be executed from the NSH command line. - When the <code>hello</code> command is executed, it will start the task with entry point <code>hello_main()</code> with the default priority and with a stack size of 2Kb. + When the <code>hello</code> command is executed, it will start the task with entry point <code>hello_main()</code> with the default priority and with a stack size of 2K. </p> <ul><pre> .context: diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html index ed994d69b9c0ba0cea00d695dcd112de014889a6..b7026f89651d494a415802051d0e42b1a4523b5e 100644 --- a/Documentation/NuttX.html +++ b/Documentation/NuttX.html @@ -858,9 +858,9 @@ <p> Using a variety of technologies, NuttX can scale from the very tiny to the moderate-size system. I have executed NuttX with some simple applications - in as little as 32Kb <i>total</i> memory (code and data). - On the other hand, typical, richly featured NuttX builds require more like 64Kb - (and if all of the features are used, this can push 100Kb). + in as little as 32K <i>total</i> memory (code and data). + On the other hand, typical, richly featured NuttX builds require more like 64K + (and if all of the features are used, this can push 100K). </p> </td> </tr> @@ -2028,8 +2028,8 @@ <b>Micropendous 3 AT9USB64x</b> and <b>AT9USB6128x</b>. This port of NuttX to the Opendous Micropendous 3 board. The Micropendous3 is may be populated with an AT90USB646, 647, 1286, or 1287. I have only the AT90USB647 - version for testing. This version have very limited memory resources: 64Kb of - FLASH and 4Kb of SRAM. + version for testing. This version have very limited memory resources: 64K of + FLASH and 4K of SRAM. </p> <ul> <p> @@ -2085,7 +2085,7 @@ </p> <p> Most NuttX test applications are console-oriented with lots of strings used for printf and debug output. - These strings are all stored in SRAM now due to these data accessing issues and even the smallest console-oriented applications can quickly fill a 4-8Kb memory. + These strings are all stored in SRAM now due to these data accessing issues and even the smallest console-oriented applications can quickly fill a 4-8K memory. So, in order for the AVR port to be useful, one of two things would need to be done: </p> <ol> @@ -2917,7 +2917,7 @@ if [ -x "$WINELOADER" ]; then exec "$WINELOADER" "$appname" "$@"; fi </pre> <p><b>87C52</b> A reduced functionality OS test for the 8052 target requires only - about 18-19Kb: + about 18-19K: </p> <pre> Stack starts at: 0x21 (sp set to 0x20) with 223 bytes available. diff --git a/Documentation/NuttXDemandPaging.html b/Documentation/NuttXDemandPaging.html index 3246e070d0f418f46f98c9ff19dbd50a343f35e1..c238161a8257242a6184d44a4c2008cecffe6d0a 100644 --- a/Documentation/NuttXDemandPaging.html +++ b/Documentation/NuttXDemandPaging.html @@ -1,675 +1,675 @@ -<html> -<head> -<title>On-Demand Paging</title> -</head> -<body background="backgd.gif"> -<hr><hr> -<table width ="100%"> - <tr align="center" bgcolor="#e4e4e4"> - <td> - <h1><big><font color="#3c34ec"><i>On-Demand Paging</i></font></big></h1> - <h2><font color="#dc143c">>>> Under Construction <<<</font></h2> - <p>Last Updated: August 12, 2010</p> - </td> - </tr> -</table> -<hr><hr> - -<table width ="100%"> - <tr bgcolor="#e4e4e4"> - <td> - <h1>Table of Contents</h1> - </td> - </tr> -</table> - -<center><table width ="80%"> -<tr> - <td> - <table> - <tr> - <td valign="top" width="22"><img height="20" width="20" src="favicon.ico"></td> - <td> - <a href="#Introduction">Introduction</a> - </td> - </tr> - <tr> - <td> </td> - <td> - <a href="#Overview">Overview</a> - </td> - </tr> - <tr> - <td> </td> - <td> - <a href="#Terminology">Terminology</a> - </td> - </tr> - </table> - </td> -</tr> -<tr> - <td> - <table> - <tr> - <td valign="top" width="22"><img height="20" width="20" src="favicon.ico"></td> - <td> - <a href="#NuttXDesign">NuttX Common Logic Design Description</a> - </td> - </tr> - <tr> - <td> </td> - <td> - <a href="#Initialization">Initialization</a> - </td> - </tr> - <tr> - <td> </td> - <td> - <a href="#PageFaults">Page Faults</a> - </td> - </tr> - <tr> - <td> </td> - <td> - <a href="#FillInitiation">Fill Initiation</a> - </td> - </tr> - <tr> - <td> </td> - <td> - <a href="#FillComplete">Fill Complete</a> - </td> - </tr> - <tr> - <td> </td> - <td> - <a href="#TaskResumption">Task Resumption</a> - </td> - </tr> - </table> - </td> -</tr> -<tr> - <td> - <table> - <tr> - <td valign="top" width="22"><img height="20" width="20" src="favicon.ico"></td> - <td> - <a href="#ArchSupport">Architecture-Specific Support Requirements</a> - </td> - </tr> - <tr> - <td> </td> - <td> - <a href="#MemoryOrg">Memory Organization</a> - </td> - </tr> - <tr> - <td> </td> - <td> - <a href="#ArchFuncs">Architecture-Specific Functions</a> - </td> - </tr> - </table> - </td> -</tr> - -</table></center> - -<table width ="100%"> - <tr bgcolor="#e4e4e4"> - <td> - <a name="Introduction"><h1>Introduction</h1></a> - </td> - </tr> -</table> -<a name="Overview"><h2>Overview</h2></a> - -<p> - This document summarizes the design of NuttX on-demand paging. - This feature permits embedded MCUs with some limited RAM space to execute large programs from some non-random access media. - This feature was first discussed in this email thread: - <a href="http://tech.groups.yahoo.com/group/nuttx/message/213">http://tech.groups.yahoo.com/group/nuttx/message/213</a>. -</p> -<p> - What kind of platforms can support NuttX on-demang paging? - <ol> - <li> - The MCU should have some large, probably low-cost non-volatile storage such as serial FLASH or an SD card. - This storage probably does not support non-random access (otherwise, why not just execute the program directly on the storage media). - SD and serial FLASH are inexpensive and do not require very many pins and SPI support is prevalent in just about all MCUs. - This large serial FLASH would contain a big program. Perhaps a program of several megabytes in size. - </li> - <li> - The MCU must have a (relatively) small block of fast SRAM from which it can execute code. - A size of, say 256Kb (or 192Kb as in the NXP LPC3131) would be sufficient for many applications. - </li> - <li> - The MCU has an MMU (again like the NXP LPC3131). - </li> - </ol> -</p> -<p> - If the platform meets these requirement, then NuttX can provide 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 small RAM. -</p> - -<a name="Terminology"><h2>Terminology</h2></a> - -<dl> - <dt><code>g_waitingforfill</code></dt> - <dd>An OS list that is used to hold the TCBs of tasks that are waiting for a page fill.</dd> - <dt><code>g_pftcb</code></dt> - <dd>A variable that holds a reference to the TCB of the thread that is currently be re-filled.</dd> - <dt><code>g_pgworker</code></dt> - <dd>The <i>process</i> ID of of the thread that will perform the page fills.</dd> - <dt><code>pg_callback()</code></dt> - <dd>The callback function that is invoked from a driver when the fill is complete.</dd> - <dt><code>pg_miss()</code></dt> - <dd>The function that is called from architecture-specific code to handle a page fault.</dd> - <dt><code>TCB</code></dt> - <dd>Task Control Block</dd> -</dl> - -<table width ="100%"> - <tr bgcolor="#e4e4e4"> - <td> - <a name="NuttXDesign"><h1>NuttX Common Logic Design Description</h1></a> - </td> - </tr> -</table> - - -<a name="Initialization"><h2>Initialization</h2></a> - -<p> - The following declarations will be added. - <ul> - <li> - <b><code>g_waitingforfill</code></b>. - A doubly linked list that will be used to implement a prioritized list of the TCBs of tasks that are waiting for a page fill. - </li> - <li> - <b><code>g_pgworker</code></b>. - The <i>process</i> ID of of the thread that will perform the page fills - </li> - </ul> -</p> -<p> - During OS initialization in <code>sched/os_start.c</code>, the following steps - will be performed: - <ul> - <li> - The <code>g_waitingforfill</code> queue will be initialized. - </li> - <li> - The special, page fill worker thread, will be started. - The <code>pid</code> of the page will worker thread will be saved in <code>g_pgworker</code>. - Note that we need a special worker thread to perform fills; - we cannot use the "generic" worker thread facility because we cannot be - assured that all actions called by that worker thread will always be resident in memory. - </li> - </ul> - </p> - <p> - Declarations for <code>g_waitingforfill</code>, <code>g_pgworker</code>, and other - internal, private definitions will be provided in <code>sched/pg_internal.h</code>. - All public definitions that should be used by the architecture-specific code will be available - in <code>include/nuttx/page.h</code>. - Most architecture-specific functions are declared in <code>include/nuttx/arch.h</code>, - but for the case of this paging logic, those architecture specific functions are instead declared in <code>include/nuttx/page.h</code>. - </p> - -<a name="PageFaults"><h2>Page Faults</h2></a> - -<p> - <b>Page fault exception handling</b>. - Page fault handling is performed by the function <code>pg_miss()</code>. - This function is called from architecture-specific memory segmentation - fault handling logic. This function will perform the following - operations: - <ol> - <li> - <b>Sanity checking</b>. - This function will ASSERT if the currently executing task is the page fill worker thread. - The page fill worker thread is how the the page fault is resolved and all logic associated with the page fill worker - must be "<a href="#MemoryOrg">locked</a>" and always present in memory. - </li> - <li> - <b>Block the currently executing task</b>. - This function will call <code>up_block_task()</code> to block the task at the head of the ready-to-run list. - This should cause an interrupt level context switch to the next highest priority task. - The blocked task will be marked with state <code>TSTATE_WAIT_PAGEFILL</code> and will be retained in the <code>g_waitingforfill</code> prioritized task list. - </li> - <li> - <b>Boost the page fill worker thread priority</b>. - Check the priority of the task at the head of the <code>g_waitingforfill</code> list. - If the priority of that task is higher than the current priority of the page fill worker thread, then boost the priority of the page fill worker thread to that priority. - Thus, the page fill worker thread will always run at the priority of the highest priority task that is waiting for a fill. - </li> - <li> - <b>Signal the page fill worker thread</b>. - Is there a page already being filled? - If not then signal the page fill worker thread to start working on the queued page fill requests. - </li> - </ol> -</p> -<p> - When signaled from <code>pg_miss()</code>, the page fill worker thread will be awakenend and will initiate the fill operation. -</p> -<p> - <b>Input Parameters.</b> - None -- The head of the ready-to-run list is assumed to be that task that caused the exception. - The current task context should already be saved in the TCB of that task. - No additional inputs are required. -</p> -<p> - <b>Assumptions</b>. - <ul> - <li> - It is assumed that this function is called from the level of an exception handler and that all interrupts are disabled. - </li> - <li> - The <code>pg_miss()</code> must be "<a href="#MemoryOrg">locked</a>" in memory. - Calling <code>pg_miss()</code> cannot cause a nested page fault. - </li> - <li> - It is assumed that currently executing task (the one at the head of the ready-to-run list) is the one that cause the fault. - This will always be true unless the page fault occurred in an interrupt handler. - Interrupt handling logic must always be available and "<a href="#MemoryOrg">locked</a>" into memory so that page faults never come from interrupt handling. - </li> - <li> - The architecture-specific page fault exception handling has already verified that the exception did not occur from interrupt/exception handling logic. - </li> - <li> - As mentioned above, the task causing the page fault must not be the page fill worker thread because that is the only way to complete the page fill. - </li> - </ul> -</p> - -<a name="FillInitiation"><h2>Fill Initiation</h2></a> - -<p> - The page fill worker thread will be awakened on one of three conditions: - <ul> - <li> - When signaled by <code>pg_miss()</code>, the page fill worker thread will be awakenend (see above), - </li> - <li> - From <code>pg_callback()</code> after completing last fill (when <code>CONFIG_PAGING_BLOCKINGFILL</code> is defined... see below), or - </li> - <li> - A configurable timeout expires with no activity. - This timeout can be used to detect failure conditions such things as fills that never complete. - </li> - </ul> -</p> - -<p> - The page fill worker thread will maintain a static variable called <code>_TCB *g_pftcb</code>. - If no fill is in progress, <code>g_pftcb</code> will be NULL. - Otherwise, it will point to the TCB of the task which is receiving the fill that is in progess. -</p> -<ul><small> - <b>NOTE</b>: - I think that this is the only state in which a TCB does not reside in some list. - Here is it in limbo, outside of the normally queuing while the page file is in progress. - While here, it will be marked with TSTATE_TASK_INVALID. -</small></ul> - -<p> - When awakened from <code>pg_miss()</code>, no fill will be in progress and <code>g_pftcb</code> will be NULL. - In this case, the page fill worker thread will call <code>pg_startfill()</code>. - That function will perform the following operations: - <ul> - <li> - Call the architecture-specific function <code>up_checkmapping()</code> to see if the page fill - still needs to be performed. - In certain conditions, the page fault may occur on several threads and be queued multiple times. - In this corner case, the blocked task will simply be restarted (see the logic below for the - case of normal completion of the fill operation). - </li> - <li> - Call <code>up_allocpage(tcb, &vpage)</code>. - This architecture-specific function will set aside page in memory and map to virtual address (vpage). - If all available pages are in-use (the typical case), - this function will select a page in-use, un-map it, and make it available. - </li> - <li> - Call the architecture-specific function <code>up_fillpage()</code>. - Two versions of the up_fillpage function are supported -- a blocking and a non-blocking version based upon the configuratin setting <code>CONFIG_PAGING_BLOCKINGFILL</code>. - <ul> - <li> - If <code>CONFIG_PAGING_BLOCKINGFILL</code> is defined, then up_fillpage is blocking call. - In this case, <code>up_fillpage()</code> will accept only (1) a reference to the TCB that requires the fill. - Architecture-specific context information within the TCB will be sufficient to perform the fill. - And (2) the (virtual) address of the allocated page to be filled. - The resulting status of the fill will be provided by return value from <code>up_fillpage()</code>. - </li> - <li> - If <code>CONFIG_PAGING_BLOCKINGFILL</code> is defined, then up_fillpage is non-blocking call. - In this case <code>up_fillpage()</code> will accept an additional argument: - The page fill worker thread will provide a callback function, <code>pg_callback</code>. - This function is non-blocking, it will start an asynchronous page fill. - After calling the non-blocking <code>up_fillpage()</code>, the page fill worker thread will wait to be signaled for the next event -- the fill completion event. - The callback function will be called when the page fill is finished (or an error occurs). - The resulting status of the fill will be providing as an argument to the callback functions. - This callback will probably occur from interrupt level. - </ul> - </li> - </ul> -</p> -<p> - In any case, while the fill is in progress, other tasks may execute. - If another page fault occurs during this time, the faulting task will be blocked, its TCB will be added (in priority order) to <code>g_waitingforfill</code>, and the priority of the page worker task may be boosted. - But no action will be taken until the current page fill completes. - NOTE: The IDLE task must also be fully <a href="#MemoryOrg">locked</a> in memory. - The IDLE task cannot be blocked. - It the case where all tasks are blocked waiting for a page fill, the IDLE task must still be available to run. -<p> - The architecture-specific functions, <code>up_checkmapping()</code>, <code>up_allocpage(tcb, &vpage)</code> and <code>up_fillpage(page, pg_callback)</code> - will be prototyped in <code>include/nuttx/arch.h</code> -</p> - -<a name="FillComplete"><h2>Fill Complete</h2></a> - -<p> - For the blocking <code>up_fillpage()</code>, the result of the fill will be returned directly from the call to <code>up_fillpage</code>. -</p> -<p> - For the non-blocking <code>up_fillpage()</code>, the architecture-specific driver call the <code>pg_callback()</code> that was provided to <code>up_fillpage()</code> when the fill completes. - In this case, the <code>pg_callback()</code> will probably be called from driver interrupt-level logic. - The driver will provide the result of the fill as an argument to the callback function. - NOTE: <code>pg_callback()</code> must also be <a href="#MemoryOrg">locked</a> in memory. -</p> -<p> - In this non-blocking case, the callback <code>pg_callback()</code> will perform the following operations when it is notified that the fill has completed: - <ul> - <li> - Verify that <code>g_pftcb</code> is non-NULL. - </li> - <li> - Find the higher priority between the task waiting for the fill to complete in <code>g_pftcb</code> and the task waiting at the head of the <code>g_waitingforfill</code> list. - That will be the priority of he highest priority task waiting for a fill. - </li> - <li> - If this higher priority is higher than current page fill worker thread, then boost worker thread's priority to that level. - Thus, the page fill worker thread will always run at the priority of the highest priority task that is waiting for a fill. - </li> - <li> - Save the result of the fill operation. - </li> - <li> - Signal the page fill worker thread. - </li> - </ul> -</p> - -<a name="TaskResumption"><h2>Task Resumption</h2></a> - -<p> - For the non-blocking <code>up_fillpage()</code>, the page fill worker thread will detect that the page fill is complete when it is awakened with <code>g_pftcb</code> non-NULL and fill completion status from <code>pg_callback</code>. - In the non-blocking case, the page fill worker thread will know that the page fill is complete when <code>up_fillpage()</code> returns. -</p> -<p> - In this either, the page fill worker thread will: - <ul> - <li> - Verify consistency of state information and <code>g_pftcb</code>. - </li> - <li> - Verify that the page fill completed successfully, and if so, - </li> - <li> - Call <code>up_unblocktask(g_pftcb)</code> to make the task that just received the fill ready-to-run. - </li> - <li> - Check if the <code>g_waitingforfill</code> list is empty. - If not: - <ul> - <li> - Remove the highest priority task waiting for a page fill from <code>g_waitingforfill</code>, - </li> - <li> - Save the task's TCB in <code>g_pftcb</code>, - </li> - <li> - If the priority of the thread in <code>g_pftcb</code>, is higher in priority than the default priority of the page fill worker thread, then set the priority of the page fill worker thread to that priority. - </li> - <li> - Call <code>pg_startfill()</code> which will start the next fill (as described above). - </li> - </ul> - </li> - <li> - Otherwise, - <ul> - <li> - Set <code>g_pftcb</code> to NULL. - </li> - <li> - Restore the default priority of the page fill worker thread. - </li> - <li> - Wait for the next fill related event (a new page fault). - </li> - </ul> - </li> - </ul> -</p> - -<table width ="100%"> - <tr bgcolor="#e4e4e4"> - <td> - <a name="ArchSupport"><h1>Architecture-Specific Support Requirements</h1></a> - </td> - </tr> -</table> - -<a name="MemoryOrg"><h2>Memory Organization</h2></a> - -<p> - <b>Memory Regions</b>. - Chip specific logic will map the virtual and physical address spaces into three general regions: - <ol> - <li> - A .text region containing "<a href="#MemoryOrg">locked-in-memory</a>" code that is always avaialable and will never cause a page fault. - This locked memory is loaded at boot time and remains resident for all time. - This memory regions must include: - <ul> - <li> - All logic for all interrupt pathes. - All interrupt logic must be locked in memory because the design present here will not support page faults from interrupt handlers. - This includes the page fault handling logic and <a href="#PageFaults"><code>pg_miss()</code></a> that is called from the page fault handler. - It also includes the <a href="#FillComplete"><code>pg_callback()</code></a> function that wakes up the page fill worker thread - and whatever architecture-specific logic that calls <code>pg_callback()</code>. - </li> - <li> - All logic for the IDLE thread. - The IDLE thread must always be ready to run and cannot be blocked for any reason. - </li> - <li> - All of the page fill worker thread must be locked in memory. - This thread must execute in order to unblock any thread waiting for a fill. - It this thread were to block, there would be no way to complete the fills! - </ul> - </li> - <li> - A .text region containing pages that can be assigned allocated, mapped to various virtual addresses, and filled from some mass storage medium. - </li> - <li> - And a fixed RAM space for .bss, .text, and .heap. - </li> - </ol> -</p> -<p> - This memory organization is illustrated in the following table. - Notice that: - <ul> - <li> - There is a one-to-one relationship between pages in the virtual address space and between pages of .text in the non-volatile mass storage device. - </li> - <li> - There are, however, far fewer physical pages available than virtual pages. - Only a subset of physical pages will be mapped to virtual pages at any given time. - This mapping will be performed on-demand as needed for program execution. - </ul> -</p> - -<center><table width="80%"> -<tr> - <th width="33%">SRAM</th> - <th width="33%">Virtual Address Space</th> - <th width="34%">Non-Volatile Storage</th> -</tr> -<tr> - <td> </td> - <td bgcolor="lightslategray">DATA</td> - <td> </td> -</tr> -<tr> - <td> </td> - <td bgcolor="lightskyblue">Virtual Page <i>n</i> (<i>n</i> > <i>m</i>)</td> - <td bgcolor="lightskyblue">Stored Page <i>n</i></td> -</tr> -<tr> - <td> </td> - <td bgcolor="lightskyblue">Virtual Page <i>n-1</i></td> - <td bgcolor="lightskyblue">Stored Page <i>n-1</i></td> -</tr> -<tr> - <td bgcolor="lightslategray">DATA</td> - <td bgcolor="lightskyblue">...</td> - <td bgcolor="lightskyblue">...</td> -</tr> -<tr> - <td bgcolor="lightskyblue">Physical Page <i>m</i> (<i>m</i> < <i>n</i>)</td> - <td bgcolor="lightskyblue">...</td> - <td bgcolor="lightskyblue">...</td> -</tr> -<tr> - <td bgcolor="lightskyblue">Physical Page <i>m-1</i></td> - <td bgcolor="lightskyblue">...</td> - <td bgcolor="lightskyblue">...</td> -</tr> -<tr> - <td bgcolor="lightskyblue">...</td> - <td bgcolor="lightskyblue">...</td> - <td bgcolor="lightskyblue">...</td> -</tr> -<tr> - <td bgcolor="lightskyblue">Physical Page <i>1</i></td> - <td bgcolor="lightskyblue">Virtual Page <i>1</i></td> - <td bgcolor="lightskyblue">Stored Page <i>1</i></td> -</tr> -<tr> - <td bgcolor="slategray">Locked Memory</td> - <td bgcolor="slategray">Locked Memory</td> - <td bgcolor="slategray">Memory Resident</td> -</tr> -</table></center> - -<p> - <b>Example</b>. - As an example, suppose that the size of the SRAM is 192Kb (as in the NXP LPC3131). And suppose further that: - <ul> - <li> - The size of the locked, memory resident .text area is 32Kb, and - </li> - <li> - The size of the DATA area is 64Kb. - </li> - <li> - The size of one, managed page is 1Kb. - </li> - <li> - The size of the whole .text image on the non-volatile, mass storage device is 1024Kb. - </li> - </ul> -<p> - Then, the size of the locked, memory resident code is 32Kb (<i>m</i>=32 pages). - The size of the physical page region is 96Kb (96 pages), and the - size of the data region is 64 pages. - And the size of the virtual paged region must then be greater than or equal to (1024-32) or 992 pages (<i>n</i>). -</p> - -<p> - <b>Building the Locked, In-Memory Image</b>. - One way to accomplish this would be a two phase link: - <ul> - <li> - In the first phase, create a partially linked objected containing all interrupt/exception handling logic, the page fill worker thread plus all parts of the IDLE thread (which must always be available for execution). - </li> - <li> - All of the <code>.text</code> and <code>.rodata</code> sections of this partial link should be collected into a single section. - </li> - <li> - The second link would link the partially linked object along with the remaining object to produce the final binary. - The linker script should position the "special" section so that it lies in a reserved, "non-swappable" region. - </ul> -</p> - -<a name="ArchFuncs"><h2>Architecture-Specific Functions</h2></a> - -<p> - Most standard, architecture-specific functions are declared in <code>include/nuttx/arch.h</code>. - However, for the case of this paging logic, the architecture specific functions are declared in <code>include/nuttx/page.h</code>. - Standard, architecture-specific functions that should already be provided in the architecture port. - The following are used by the common paging logic: -</p> -<ul><dl> - <dt> - <code>void up_block_task(FAR _TCB *tcb, tstate_t task_state);</code> - </dt> - <dd> - The currently executing task at the head of the ready to run list must be stopped. - Save its context and move it to the inactive list specified by task_state. - This function is called by the on-demand paging logic in order to block the task that requires the - page fill, and to - </dd> - <dt> - <code>void up_unblock_task(FAR _TCB *tcb);</code> - </dt> - <dd> - A task is currently in an inactive task list but has been prepped to execute. - Move the TCB to the ready-to-run list, restore its context, and start execution. - This function will be called - </dd> -</dl></ul> - -<p> - New, additional functions that must be implemented just for on-demand paging support: -</p> - -<ul><dl> - <dt> - <code>int up_checkmapping(FAR _TCB *tcb);</code> - </dt> - <dd> - The function <code>up_checkmapping()</code> returns an indication if the page fill still needs to performed or not. - In certain conditions, the page fault may occur on several threads and be queued multiple times. - This function will prevent the same page from be filled multiple times. - </dd> - <dt> - <code>int up_allocpage(FAR _TCB *tcb, FAR void *vpage);</code> - </dt> - <dd> - This architecture-specific function will set aside page in memory and map to its correct virtual address. - Architecture-specific context information saved within the TCB will provide the function with the information needed to identify the virtual miss address. - This function will return the allocated physical page address in <code>vpage</code>. - The size of the underlying physical page is determined by the configuration setting <code>CONFIG_PAGING_PAGESIZE</code>. - NOTE: This function must <i>always</i> return a page allocation. - If all available pages are in-use (the typical case), then this function will select a page in-use, un-map it, and make it available. - </dd> - <dt><code>int up_fillpage(FAR _TCB *tcb, FAR const void *vpage, void (*pg_callback)(FAR _TCB *tcb, int result));</code> - </dt> - The actual filling of the page with data from the non-volatile, must be performed by a separate call to the architecture-specific function, <code>up_fillpage()</code>. - This will start asynchronous page fill. - The common paging logic will provide a callback function, <code>pg_callback</code>, that 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 driver completes the fill operation. - </dt> -</dl></ul> -</body> -</html> - +<html> +<head> +<title>On-Demand Paging</title> +</head> +<body background="backgd.gif"> +<hr><hr> +<table width ="100%"> + <tr align="center" bgcolor="#e4e4e4"> + <td> + <h1><big><font color="#3c34ec"><i>On-Demand Paging</i></font></big></h1> + <h2><font color="#dc143c">>>> Under Construction <<<</font></h2> + <p>Last Updated: August 12, 2010</p> + </td> + </tr> +</table> +<hr><hr> + +<table width ="100%"> + <tr bgcolor="#e4e4e4"> + <td> + <h1>Table of Contents</h1> + </td> + </tr> +</table> + +<center><table width ="80%"> +<tr> + <td> + <table> + <tr> + <td valign="top" width="22"><img height="20" width="20" src="favicon.ico"></td> + <td> + <a href="#Introduction">Introduction</a> + </td> + </tr> + <tr> + <td> </td> + <td> + <a href="#Overview">Overview</a> + </td> + </tr> + <tr> + <td> </td> + <td> + <a href="#Terminology">Terminology</a> + </td> + </tr> + </table> + </td> +</tr> +<tr> + <td> + <table> + <tr> + <td valign="top" width="22"><img height="20" width="20" src="favicon.ico"></td> + <td> + <a href="#NuttXDesign">NuttX Common Logic Design Description</a> + </td> + </tr> + <tr> + <td> </td> + <td> + <a href="#Initialization">Initialization</a> + </td> + </tr> + <tr> + <td> </td> + <td> + <a href="#PageFaults">Page Faults</a> + </td> + </tr> + <tr> + <td> </td> + <td> + <a href="#FillInitiation">Fill Initiation</a> + </td> + </tr> + <tr> + <td> </td> + <td> + <a href="#FillComplete">Fill Complete</a> + </td> + </tr> + <tr> + <td> </td> + <td> + <a href="#TaskResumption">Task Resumption</a> + </td> + </tr> + </table> + </td> +</tr> +<tr> + <td> + <table> + <tr> + <td valign="top" width="22"><img height="20" width="20" src="favicon.ico"></td> + <td> + <a href="#ArchSupport">Architecture-Specific Support Requirements</a> + </td> + </tr> + <tr> + <td> </td> + <td> + <a href="#MemoryOrg">Memory Organization</a> + </td> + </tr> + <tr> + <td> </td> + <td> + <a href="#ArchFuncs">Architecture-Specific Functions</a> + </td> + </tr> + </table> + </td> +</tr> + +</table></center> + +<table width ="100%"> + <tr bgcolor="#e4e4e4"> + <td> + <a name="Introduction"><h1>Introduction</h1></a> + </td> + </tr> +</table> +<a name="Overview"><h2>Overview</h2></a> + +<p> + This document summarizes the design of NuttX on-demand paging. + This feature permits embedded MCUs with some limited RAM space to execute large programs from some non-random access media. + This feature was first discussed in this email thread: + <a href="http://tech.groups.yahoo.com/group/nuttx/message/213">http://tech.groups.yahoo.com/group/nuttx/message/213</a>. +</p> +<p> + What kind of platforms can support NuttX on-demang paging? + <ol> + <li> + The MCU should have some large, probably low-cost non-volatile storage such as serial FLASH or an SD card. + This storage probably does not support non-random access (otherwise, why not just execute the program directly on the storage media). + SD and serial FLASH are inexpensive and do not require very many pins and SPI support is prevalent in just about all MCUs. + This large serial FLASH would contain a big program. Perhaps a program of several megabytes in size. + </li> + <li> + The MCU must have a (relatively) small block of fast SRAM from which it can execute code. + A size of, say 256K (or 192K as in the NXP LPC3131) would be sufficient for many applications. + </li> + <li> + The MCU has an MMU (again like the NXP LPC3131). + </li> + </ol> +</p> +<p> + If the platform meets these requirement, then NuttX can provide 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 small RAM. +</p> + +<a name="Terminology"><h2>Terminology</h2></a> + +<dl> + <dt><code>g_waitingforfill</code></dt> + <dd>An OS list that is used to hold the TCBs of tasks that are waiting for a page fill.</dd> + <dt><code>g_pftcb</code></dt> + <dd>A variable that holds a reference to the TCB of the thread that is currently be re-filled.</dd> + <dt><code>g_pgworker</code></dt> + <dd>The <i>process</i> ID of of the thread that will perform the page fills.</dd> + <dt><code>pg_callback()</code></dt> + <dd>The callback function that is invoked from a driver when the fill is complete.</dd> + <dt><code>pg_miss()</code></dt> + <dd>The function that is called from architecture-specific code to handle a page fault.</dd> + <dt><code>TCB</code></dt> + <dd>Task Control Block</dd> +</dl> + +<table width ="100%"> + <tr bgcolor="#e4e4e4"> + <td> + <a name="NuttXDesign"><h1>NuttX Common Logic Design Description</h1></a> + </td> + </tr> +</table> + + +<a name="Initialization"><h2>Initialization</h2></a> + +<p> + The following declarations will be added. + <ul> + <li> + <b><code>g_waitingforfill</code></b>. + A doubly linked list that will be used to implement a prioritized list of the TCBs of tasks that are waiting for a page fill. + </li> + <li> + <b><code>g_pgworker</code></b>. + The <i>process</i> ID of of the thread that will perform the page fills + </li> + </ul> +</p> +<p> + During OS initialization in <code>sched/os_start.c</code>, the following steps + will be performed: + <ul> + <li> + The <code>g_waitingforfill</code> queue will be initialized. + </li> + <li> + The special, page fill worker thread, will be started. + The <code>pid</code> of the page will worker thread will be saved in <code>g_pgworker</code>. + Note that we need a special worker thread to perform fills; + we cannot use the "generic" worker thread facility because we cannot be + assured that all actions called by that worker thread will always be resident in memory. + </li> + </ul> + </p> + <p> + Declarations for <code>g_waitingforfill</code>, <code>g_pgworker</code>, and other + internal, private definitions will be provided in <code>sched/pg_internal.h</code>. + All public definitions that should be used by the architecture-specific code will be available + in <code>include/nuttx/page.h</code>. + Most architecture-specific functions are declared in <code>include/nuttx/arch.h</code>, + but for the case of this paging logic, those architecture specific functions are instead declared in <code>include/nuttx/page.h</code>. + </p> + +<a name="PageFaults"><h2>Page Faults</h2></a> + +<p> + <b>Page fault exception handling</b>. + Page fault handling is performed by the function <code>pg_miss()</code>. + This function is called from architecture-specific memory segmentation + fault handling logic. This function will perform the following + operations: + <ol> + <li> + <b>Sanity checking</b>. + This function will ASSERT if the currently executing task is the page fill worker thread. + The page fill worker thread is how the the page fault is resolved and all logic associated with the page fill worker + must be "<a href="#MemoryOrg">locked</a>" and always present in memory. + </li> + <li> + <b>Block the currently executing task</b>. + This function will call <code>up_block_task()</code> to block the task at the head of the ready-to-run list. + This should cause an interrupt level context switch to the next highest priority task. + The blocked task will be marked with state <code>TSTATE_WAIT_PAGEFILL</code> and will be retained in the <code>g_waitingforfill</code> prioritized task list. + </li> + <li> + <b>Boost the page fill worker thread priority</b>. + Check the priority of the task at the head of the <code>g_waitingforfill</code> list. + If the priority of that task is higher than the current priority of the page fill worker thread, then boost the priority of the page fill worker thread to that priority. + Thus, the page fill worker thread will always run at the priority of the highest priority task that is waiting for a fill. + </li> + <li> + <b>Signal the page fill worker thread</b>. + Is there a page already being filled? + If not then signal the page fill worker thread to start working on the queued page fill requests. + </li> + </ol> +</p> +<p> + When signaled from <code>pg_miss()</code>, the page fill worker thread will be awakenend and will initiate the fill operation. +</p> +<p> + <b>Input Parameters.</b> + None -- The head of the ready-to-run list is assumed to be that task that caused the exception. + The current task context should already be saved in the TCB of that task. + No additional inputs are required. +</p> +<p> + <b>Assumptions</b>. + <ul> + <li> + It is assumed that this function is called from the level of an exception handler and that all interrupts are disabled. + </li> + <li> + The <code>pg_miss()</code> must be "<a href="#MemoryOrg">locked</a>" in memory. + Calling <code>pg_miss()</code> cannot cause a nested page fault. + </li> + <li> + It is assumed that currently executing task (the one at the head of the ready-to-run list) is the one that cause the fault. + This will always be true unless the page fault occurred in an interrupt handler. + Interrupt handling logic must always be available and "<a href="#MemoryOrg">locked</a>" into memory so that page faults never come from interrupt handling. + </li> + <li> + The architecture-specific page fault exception handling has already verified that the exception did not occur from interrupt/exception handling logic. + </li> + <li> + As mentioned above, the task causing the page fault must not be the page fill worker thread because that is the only way to complete the page fill. + </li> + </ul> +</p> + +<a name="FillInitiation"><h2>Fill Initiation</h2></a> + +<p> + The page fill worker thread will be awakened on one of three conditions: + <ul> + <li> + When signaled by <code>pg_miss()</code>, the page fill worker thread will be awakenend (see above), + </li> + <li> + From <code>pg_callback()</code> after completing last fill (when <code>CONFIG_PAGING_BLOCKINGFILL</code> is defined... see below), or + </li> + <li> + A configurable timeout expires with no activity. + This timeout can be used to detect failure conditions such things as fills that never complete. + </li> + </ul> +</p> + +<p> + The page fill worker thread will maintain a static variable called <code>_TCB *g_pftcb</code>. + If no fill is in progress, <code>g_pftcb</code> will be NULL. + Otherwise, it will point to the TCB of the task which is receiving the fill that is in progess. +</p> +<ul><small> + <b>NOTE</b>: + I think that this is the only state in which a TCB does not reside in some list. + Here is it in limbo, outside of the normally queuing while the page file is in progress. + While here, it will be marked with TSTATE_TASK_INVALID. +</small></ul> + +<p> + When awakened from <code>pg_miss()</code>, no fill will be in progress and <code>g_pftcb</code> will be NULL. + In this case, the page fill worker thread will call <code>pg_startfill()</code>. + That function will perform the following operations: + <ul> + <li> + Call the architecture-specific function <code>up_checkmapping()</code> to see if the page fill + still needs to be performed. + In certain conditions, the page fault may occur on several threads and be queued multiple times. + In this corner case, the blocked task will simply be restarted (see the logic below for the + case of normal completion of the fill operation). + </li> + <li> + Call <code>up_allocpage(tcb, &vpage)</code>. + This architecture-specific function will set aside page in memory and map to virtual address (vpage). + If all available pages are in-use (the typical case), + this function will select a page in-use, un-map it, and make it available. + </li> + <li> + Call the architecture-specific function <code>up_fillpage()</code>. + Two versions of the up_fillpage function are supported -- a blocking and a non-blocking version based upon the configuratin setting <code>CONFIG_PAGING_BLOCKINGFILL</code>. + <ul> + <li> + If <code>CONFIG_PAGING_BLOCKINGFILL</code> is defined, then up_fillpage is blocking call. + In this case, <code>up_fillpage()</code> will accept only (1) a reference to the TCB that requires the fill. + Architecture-specific context information within the TCB will be sufficient to perform the fill. + And (2) the (virtual) address of the allocated page to be filled. + The resulting status of the fill will be provided by return value from <code>up_fillpage()</code>. + </li> + <li> + If <code>CONFIG_PAGING_BLOCKINGFILL</code> is defined, then up_fillpage is non-blocking call. + In this case <code>up_fillpage()</code> will accept an additional argument: + The page fill worker thread will provide a callback function, <code>pg_callback</code>. + This function is non-blocking, it will start an asynchronous page fill. + After calling the non-blocking <code>up_fillpage()</code>, the page fill worker thread will wait to be signaled for the next event -- the fill completion event. + The callback function will be called when the page fill is finished (or an error occurs). + The resulting status of the fill will be providing as an argument to the callback functions. + This callback will probably occur from interrupt level. + </ul> + </li> + </ul> +</p> +<p> + In any case, while the fill is in progress, other tasks may execute. + If another page fault occurs during this time, the faulting task will be blocked, its TCB will be added (in priority order) to <code>g_waitingforfill</code>, and the priority of the page worker task may be boosted. + But no action will be taken until the current page fill completes. + NOTE: The IDLE task must also be fully <a href="#MemoryOrg">locked</a> in memory. + The IDLE task cannot be blocked. + It the case where all tasks are blocked waiting for a page fill, the IDLE task must still be available to run. +<p> + The architecture-specific functions, <code>up_checkmapping()</code>, <code>up_allocpage(tcb, &vpage)</code> and <code>up_fillpage(page, pg_callback)</code> + will be prototyped in <code>include/nuttx/arch.h</code> +</p> + +<a name="FillComplete"><h2>Fill Complete</h2></a> + +<p> + For the blocking <code>up_fillpage()</code>, the result of the fill will be returned directly from the call to <code>up_fillpage</code>. +</p> +<p> + For the non-blocking <code>up_fillpage()</code>, the architecture-specific driver call the <code>pg_callback()</code> that was provided to <code>up_fillpage()</code> when the fill completes. + In this case, the <code>pg_callback()</code> will probably be called from driver interrupt-level logic. + The driver will provide the result of the fill as an argument to the callback function. + NOTE: <code>pg_callback()</code> must also be <a href="#MemoryOrg">locked</a> in memory. +</p> +<p> + In this non-blocking case, the callback <code>pg_callback()</code> will perform the following operations when it is notified that the fill has completed: + <ul> + <li> + Verify that <code>g_pftcb</code> is non-NULL. + </li> + <li> + Find the higher priority between the task waiting for the fill to complete in <code>g_pftcb</code> and the task waiting at the head of the <code>g_waitingforfill</code> list. + That will be the priority of he highest priority task waiting for a fill. + </li> + <li> + If this higher priority is higher than current page fill worker thread, then boost worker thread's priority to that level. + Thus, the page fill worker thread will always run at the priority of the highest priority task that is waiting for a fill. + </li> + <li> + Save the result of the fill operation. + </li> + <li> + Signal the page fill worker thread. + </li> + </ul> +</p> + +<a name="TaskResumption"><h2>Task Resumption</h2></a> + +<p> + For the non-blocking <code>up_fillpage()</code>, the page fill worker thread will detect that the page fill is complete when it is awakened with <code>g_pftcb</code> non-NULL and fill completion status from <code>pg_callback</code>. + In the non-blocking case, the page fill worker thread will know that the page fill is complete when <code>up_fillpage()</code> returns. +</p> +<p> + In this either, the page fill worker thread will: + <ul> + <li> + Verify consistency of state information and <code>g_pftcb</code>. + </li> + <li> + Verify that the page fill completed successfully, and if so, + </li> + <li> + Call <code>up_unblocktask(g_pftcb)</code> to make the task that just received the fill ready-to-run. + </li> + <li> + Check if the <code>g_waitingforfill</code> list is empty. + If not: + <ul> + <li> + Remove the highest priority task waiting for a page fill from <code>g_waitingforfill</code>, + </li> + <li> + Save the task's TCB in <code>g_pftcb</code>, + </li> + <li> + If the priority of the thread in <code>g_pftcb</code>, is higher in priority than the default priority of the page fill worker thread, then set the priority of the page fill worker thread to that priority. + </li> + <li> + Call <code>pg_startfill()</code> which will start the next fill (as described above). + </li> + </ul> + </li> + <li> + Otherwise, + <ul> + <li> + Set <code>g_pftcb</code> to NULL. + </li> + <li> + Restore the default priority of the page fill worker thread. + </li> + <li> + Wait for the next fill related event (a new page fault). + </li> + </ul> + </li> + </ul> +</p> + +<table width ="100%"> + <tr bgcolor="#e4e4e4"> + <td> + <a name="ArchSupport"><h1>Architecture-Specific Support Requirements</h1></a> + </td> + </tr> +</table> + +<a name="MemoryOrg"><h2>Memory Organization</h2></a> + +<p> + <b>Memory Regions</b>. + Chip specific logic will map the virtual and physical address spaces into three general regions: + <ol> + <li> + A .text region containing "<a href="#MemoryOrg">locked-in-memory</a>" code that is always avaialable and will never cause a page fault. + This locked memory is loaded at boot time and remains resident for all time. + This memory regions must include: + <ul> + <li> + All logic for all interrupt paths. + All interrupt logic must be locked in memory because the design present here will not support page faults from interrupt handlers. + This includes the page fault handling logic and <a href="#PageFaults"><code>pg_miss()</code></a> that is called from the page fault handler. + It also includes the <a href="#FillComplete"><code>pg_callback()</code></a> function that wakes up the page fill worker thread + and whatever architecture-specific logic that calls <code>pg_callback()</code>. + </li> + <li> + All logic for the IDLE thread. + The IDLE thread must always be ready to run and cannot be blocked for any reason. + </li> + <li> + All of the page fill worker thread must be locked in memory. + This thread must execute in order to unblock any thread waiting for a fill. + It this thread were to block, there would be no way to complete the fills! + </ul> + </li> + <li> + A .text region containing pages that can be assigned allocated, mapped to various virtual addresses, and filled from some mass storage medium. + </li> + <li> + And a fixed RAM space for .bss, .text, and .heap. + </li> + </ol> +</p> +<p> + This memory organization is illustrated in the following table. + Notice that: + <ul> + <li> + There is a one-to-one relationship between pages in the virtual address space and between pages of .text in the non-volatile mass storage device. + </li> + <li> + There are, however, far fewer physical pages available than virtual pages. + Only a subset of physical pages will be mapped to virtual pages at any given time. + This mapping will be performed on-demand as needed for program execution. + </ul> +</p> + +<center><table width="80%"> +<tr> + <th width="33%">SRAM</th> + <th width="33%">Virtual Address Space</th> + <th width="34%">Non-Volatile Storage</th> +</tr> +<tr> + <td> </td> + <td bgcolor="lightslategray">DATA</td> + <td> </td> +</tr> +<tr> + <td> </td> + <td bgcolor="lightskyblue">Virtual Page <i>n</i> (<i>n</i> > <i>m</i>)</td> + <td bgcolor="lightskyblue">Stored Page <i>n</i></td> +</tr> +<tr> + <td> </td> + <td bgcolor="lightskyblue">Virtual Page <i>n-1</i></td> + <td bgcolor="lightskyblue">Stored Page <i>n-1</i></td> +</tr> +<tr> + <td bgcolor="lightslategray">DATA</td> + <td bgcolor="lightskyblue">...</td> + <td bgcolor="lightskyblue">...</td> +</tr> +<tr> + <td bgcolor="lightskyblue">Physical Page <i>m</i> (<i>m</i> < <i>n</i>)</td> + <td bgcolor="lightskyblue">...</td> + <td bgcolor="lightskyblue">...</td> +</tr> +<tr> + <td bgcolor="lightskyblue">Physical Page <i>m-1</i></td> + <td bgcolor="lightskyblue">...</td> + <td bgcolor="lightskyblue">...</td> +</tr> +<tr> + <td bgcolor="lightskyblue">...</td> + <td bgcolor="lightskyblue">...</td> + <td bgcolor="lightskyblue">...</td> +</tr> +<tr> + <td bgcolor="lightskyblue">Physical Page <i>1</i></td> + <td bgcolor="lightskyblue">Virtual Page <i>1</i></td> + <td bgcolor="lightskyblue">Stored Page <i>1</i></td> +</tr> +<tr> + <td bgcolor="slategray">Locked Memory</td> + <td bgcolor="slategray">Locked Memory</td> + <td bgcolor="slategray">Memory Resident</td> +</tr> +</table></center> + +<p> + <b>Example</b>. + As an example, suppose that the size of the SRAM is 192K (as in the NXP LPC3131). And suppose further that: + <ul> + <li> + The size of the locked, memory resident .text area is 32K, and + </li> + <li> + The size of the DATA area is 64K. + </li> + <li> + The size of one, managed page is 1K. + </li> + <li> + The size of the whole .text image on the non-volatile, mass storage device is 1024K. + </li> + </ul> +<p> + Then, the size of the locked, memory resident code is 32K (<i>m</i>=32 pages). + The size of the physical page region is 96K (96 pages), and the + size of the data region is 64 pages. + And the size of the virtual paged region must then be greater than or equal to (1024-32) or 992 pages (<i>n</i>). +</p> + +<p> + <b>Building the Locked, In-Memory Image</b>. + One way to accomplish this would be a two phase link: + <ul> + <li> + In the first phase, create a partially linked objected containing all interrupt/exception handling logic, the page fill worker thread plus all parts of the IDLE thread (which must always be available for execution). + </li> + <li> + All of the <code>.text</code> and <code>.rodata</code> sections of this partial link should be collected into a single section. + </li> + <li> + The second link would link the partially linked object along with the remaining object to produce the final binary. + The linker script should position the "special" section so that it lies in a reserved, "non-swappable" region. + </ul> +</p> + +<a name="ArchFuncs"><h2>Architecture-Specific Functions</h2></a> + +<p> + Most standard, architecture-specific functions are declared in <code>include/nuttx/arch.h</code>. + However, for the case of this paging logic, the architecture specific functions are declared in <code>include/nuttx/page.h</code>. + Standard, architecture-specific functions that should already be provided in the architecture port. + The following are used by the common paging logic: +</p> +<ul><dl> + <dt> + <code>void up_block_task(FAR _TCB *tcb, tstate_t task_state);</code> + </dt> + <dd> + The currently executing task at the head of the ready to run list must be stopped. + Save its context and move it to the inactive list specified by task_state. + This function is called by the on-demand paging logic in order to block the task that requires the + page fill, and to + </dd> + <dt> + <code>void up_unblock_task(FAR _TCB *tcb);</code> + </dt> + <dd> + A task is currently in an inactive task list but has been prepped to execute. + Move the TCB to the ready-to-run list, restore its context, and start execution. + This function will be called + </dd> +</dl></ul> + +<p> + New, additional functions that must be implemented just for on-demand paging support: +</p> + +<ul><dl> + <dt> + <code>int up_checkmapping(FAR _TCB *tcb);</code> + </dt> + <dd> + The function <code>up_checkmapping()</code> returns an indication if the page fill still needs to performed or not. + In certain conditions, the page fault may occur on several threads and be queued multiple times. + This function will prevent the same page from be filled multiple times. + </dd> + <dt> + <code>int up_allocpage(FAR _TCB *tcb, FAR void *vpage);</code> + </dt> + <dd> + This architecture-specific function will set aside page in memory and map to its correct virtual address. + Architecture-specific context information saved within the TCB will provide the function with the information needed to identify the virtual miss address. + This function will return the allocated physical page address in <code>vpage</code>. + The size of the underlying physical page is determined by the configuration setting <code>CONFIG_PAGING_PAGESIZE</code>. + NOTE: This function must <i>always</i> return a page allocation. + If all available pages are in-use (the typical case), then this function will select a page in-use, un-map it, and make it available. + </dd> + <dt><code>int up_fillpage(FAR _TCB *tcb, FAR const void *vpage, void (*pg_callback)(FAR _TCB *tcb, int result));</code> + </dt> + The actual filling of the page with data from the non-volatile, must be performed by a separate call to the architecture-specific function, <code>up_fillpage()</code>. + This will start asynchronous page fill. + The common paging logic will provide a callback function, <code>pg_callback</code>, that 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 driver completes the fill operation. + </dt> +</dl></ul> +</body> +</html> + diff --git a/Documentation/NuttxPortingGuide.html b/Documentation/NuttxPortingGuide.html index e605dd109d5cba8b636654ef37c8b9b38fdbfb25..a339b3a99023e0c3c0589e0203d046140bf10a02 100644 --- a/Documentation/NuttxPortingGuide.html +++ b/Documentation/NuttxPortingGuide.html @@ -3935,7 +3935,7 @@ build 16-bit addressability have smaller overhead than devices that support 32-bit addressability. However, there are many MCUs that support 32-bit addressability <i>but</i> have internal SRAM - of size less than or equal to 64Kb. In this case, CONFIG_MM_SMALL + of size less than or equal to 64K. In this case, CONFIG_MM_SMALL can be defined so that those MCUs will also benefit from the smaller, 16-bit-based allocation overhead. </li> @@ -4740,7 +4740,7 @@ build <li> <code>CONFIG_P14201_FRAMEBUFFER</code>: If defined, accesses will be performed using an in-memory copy of the OLEDs GDDRAM. - This cost of this buffer is 128 * 96 / 2 = 6Kb. + This cost of this buffer is 128 * 96 / 2 = 6K. If this is defined, then the driver will be fully functional. If not, then it will have the following limitations: <ul> diff --git a/Documentation/NxWidgets.html b/Documentation/NxWidgets.html index cef99d494335baa97d274c1fa24f1addce1f34ed..1678d9ebe7fa2e5cc1eddc3ef5bc058ed0a60a1f 100755 --- a/Documentation/NxWidgets.html +++ b/Documentation/NxWidgets.html @@ -33,7 +33,7 @@ <li><b>Small Footprint</b>. NXWidgets is tailored for use MCUs in embedded applications. It is ideally suited for mid- and upper-range of most MCU families. - A complete NXWidgets is possible in as little as 40Kb of FLASH and maybe 4Kb of SRAM. + A complete NXWidgets is possible in as little as 40K of FLASH and maybe 4K of SRAM. </li> <li><b>Output Devices</b>. NXWidgets will work on the high-end frame buffer devices as well as on LCDs connected via serial or parallel ports to a small MCU. diff --git a/ReleaseNotes b/ReleaseNotes index 8c6ae0ccb87325200300183b5cd306adda4dee82..26af0e38d4c71af8d7be15030756be23719dcf38 100644 --- a/ReleaseNotes +++ b/ReleaseNotes @@ -1668,7 +1668,7 @@ Important bugfixes included: And feature enhancements: * The LPC176x Ethernet driver was using all of AHB SRAM Bank0 for - Ethernet packet buffers (16Kb). An option was added to limit + Ethernet packet buffers (16K). An option was added to limit the amount of SRAM used for packet buffering and to re-use any extra Bank0 memory for heap. @@ -2022,7 +2022,7 @@ and is available for download from the SourceForge website. The * A PCI-based E1000 Ethernet driver (contributed by Yu Qiang) * New C library functions: inet_addr() (contributed by Yu Qiang), strndup(), asprintf() - * Reduced memory allocation overhead for MCUs with small heaps (<64Kb). + * Reduced memory allocation overhead for MCUs with small heaps (<64K). * fdopen() now works with socket descriptors allowing standard buffered C functions to be used for network communications. * The NSH ifconfig command can now be used to set or change the @@ -2062,7 +2062,7 @@ they are, ordered from the least to the most complete: This port of NuttX to the Amber Web Server from SoC Robotics (http://www.soc-robotics.com/index.htm). Is only partially in place. The Amber Web Server is based on an Atmel ATMega128 - (128Kb FLASH but only 4Kb of SRAM). + (128K FLASH but only 4K of SRAM). STATUS: Work on this port has stalled due to toolchain issues. It is complete, but untested. @@ -2073,7 +2073,7 @@ they are, ordered from the least to the most complete: Micropendous3 may be populated with an AT90USB646, 647, 1286, or 1287. See http://code.google.com/p/opendous/. I have only the AT90USB647 version for testing. This version has very - limited memory resources: 64Kb of FLASH and 4Kb of SRAM. + limited memory resources: 64K of FLASH and 4K of SRAM. STATUS: The basic port was released in NuttX-6.5. This basic port consists only of a "Hello, World!!" example that demonstrates @@ -2085,8 +2085,8 @@ they are, ordered from the least to the most complete: This is a port of NuttX to the PJRC Teensy++ 2.0 board. This board was developed by PJRC (http://pjrc.com/teensy/). The - Teensy++ 2.0 is based on an Atmel AT90USB1286 MCU with 128Kb - of FLASH and 8Kb of SRAM; a little more room to move than the + Teensy++ 2.0 is based on an Atmel AT90USB1286 MCU with 128K + of FLASH and 8K of SRAM; a little more room to move than the AT90USB647. STATUS: The basic port was released in NuttX-6.5. This basic @@ -2109,7 +2109,7 @@ integrated into the normal, general purpose OS. Most NuttX test applications are console-oriented with lots of strings used for printf and debug output. These strings are all stored in SRAM now due to these data accessing issues and even the -smallest console-oriented applications can quickly fill a 4-8Kb +smallest console-oriented applications can quickly fill a 4-8K memory. So, in order for the AVR port to be useful, one of two things would need to be done: diff --git a/TODO b/TODO index 7ffcb9ca807f3b570bc3c4911bd1b6e191a58b64..f9fc558eabca20ae5e6e9a15a7be177493aec91b 100644 --- a/TODO +++ b/TODO @@ -1819,7 +1819,7 @@ o mc68hc1x (arch/hc) Description: There is no script for building in banked mode (more correctly, there is a script, but logic inside the script has not yet been implemented). It would be necessary to implement banked mode to able to access more - the 48Kb of FLASH. + the 48K of FLASH. Status: Open. Priority: Medium/Low diff --git a/arch/arm/src/lpc43xx/lpc43_usb0dev.c b/arch/arm/src/lpc43xx/lpc43_usb0dev.c index 40233ec0f69c99e8e650bba3f67ac5037940a39a..2ce19a32504e7ae856e3b68954dd7d6835c05bc6 100644 --- a/arch/arm/src/lpc43xx/lpc43_usb0dev.c +++ b/arch/arm/src/lpc43xx/lpc43_usb0dev.c @@ -69,9 +69,7 @@ #include "up_arch.h" #include "up_internal.h" -#include "lpc43_usbotg.h" -#include "lpc43_evntrtr.h" -#include "lpc43_syscreg.h" +#include "lpc43_usb0dev.h" /******************************************************************************* * Definitions diff --git a/arch/arm/src/lpc43xx/lpc43_usb0dev.h b/arch/arm/src/lpc43xx/lpc43_usb0dev.h new file mode 100644 index 0000000000000000000000000000000000000000..97076cd802f51e2988bd91a200adbb205c18a484 --- /dev/null +++ b/arch/arm/src/lpc43xx/lpc43_usb0dev.h @@ -0,0 +1,98 @@ +/************************************************************************************ + * arch/arm/src/lpc43xx/lpc43_usbdev.h + * + * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************************/ + +#ifndef __ARCH_ARM_SRC_LPC43XX_LPC32_USB0DEV_H +#define __ARCH_ARM_SRC_LPC43XX_LPC32_USB0DEV_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include <nuttx/config.h> +#include <nuttx/usb/usbdev.h> +#include <stdint.h> + +#include "chip.h" +#include "chip/lpc43_usb0.h" + +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/************************************************************************************ + * Name: lpc43_usbpullup + * + * Description: + * If USB is supported and the board supports a pullup via GPIO (for USB software + * connect and disconnect), then the board software must provide lpc43_pullup. + * See include/nuttx/usb/usbdev.h for additional description of this method. + * Alternatively, if no pull-up GPIO the following EXTERN can be redefined to be + * NULL. + * + ************************************************************************************/ + +EXTERN int lpc43_usbpullup(FAR struct usbdev_s *dev, bool enable); + +/************************************************************************************ + * Name: lpc43_usbsuspend + * + * Description: + * Board logic must provide the lpc43_usbsuspend logic if the USBDEV driver is + * used. This function is called whenever the USB enters or leaves suspend mode. + * This is an opportunity for the board logic to shutdown clocks, power, etc. + * while the USB is suspended. + * + ************************************************************************************/ + +EXTERN void lpc43_usbsuspend(FAR struct usbdev_s *dev, bool resume); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_LPC43XX_LPC32_USB0DEV_H */ +