paging.rst 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. .. _ondemandpaging:
  2. ================
  3. On-Demand Paging
  4. ================
  5. Introduction
  6. ============
  7. Overview
  8. --------
  9. This document summarizes the design of NuttX on-demand paging. This
  10. feature permits embedded MCUs with some limited RAM space to execute
  11. large programs from some non-random access media.
  12. What kind of platforms can support NuttX on-demang paging?
  13. #. The MCU should have some large, probably low-cost non-volatile
  14. storage such as serial FLASH or an SD card. This storage probably
  15. does not support non-random access (otherwise, why not just execute
  16. the program directly on the storage media). SD and serial FLASH are
  17. inexpensive and do not require very many pins and SPI support is
  18. prevalent in just about all MCUs. This large serial FLASH would
  19. contain a big program. Perhaps a program of several megabytes in
  20. size.
  21. #. The MCU must have a (relatively) small block of fast SRAM from which
  22. it can execute code. A size of, say 256K (or 192K as in the NXP
  23. LPC3131) would be sufficient for many applications.
  24. #. The MCU has an MMU (again like the NXP LPC3131).
  25. If the platform meets these requirement, then NuttX can provide
  26. on-demand paging: It can copy .text from the large program in
  27. non-volatile media into RAM as needed to execute a huge program from the
  28. small RAM.
  29. Terminology
  30. -----------
  31. ``g_waitingforfill``:
  32. An OS list that is used to hold the TCBs of tasks that are waiting
  33. for a page fill.
  34. ``g_pftcb``:
  35. A variable that holds a reference to the TCB of the thread that is
  36. currently be re-filled.
  37. ``g_pgworker``:
  38. The *process* ID of the thread that will perform the page fills.
  39. ``pg_callback()``:
  40. The callback function that is invoked from a driver when the fill is
  41. complete.
  42. ``pg_miss()``:
  43. The function that is called from architecture-specific code to handle
  44. a page fault.
  45. ``TCB``:
  46. Task Control Block
  47. NuttX Common Logic Design Description
  48. =====================================
  49. Initialization
  50. --------------
  51. The following declarations will be added.
  52. - ``g_waitingforfill``. A doubly linked list that will be used to
  53. implement a prioritized list of the TCBs of tasks that are waiting
  54. for a page fill.
  55. - ``g_pgworker``. The *process* ID of the thread that will perform
  56. the page fills
  57. During OS initialization in ``sched/init/nx_start.c``, the following
  58. steps will be performed:
  59. - The ``g_waitingforfill`` queue will be initialized.
  60. - The special, page fill worker thread, will be started. The ``pid`` of
  61. the page will worker thread will be saved in ``g_pgworker``. Note
  62. that we need a special worker thread to perform fills; we cannot use
  63. the "generic" worker thread facility because we cannot be assured
  64. that all actions called by that worker thread will always be resident
  65. in memory.
  66. Declarations for ``g_waitingforfill``, ``g_pgworker``, and other
  67. internal, private definitions will be provided in
  68. ``sched/paging/paging.h``. All public definitions that should be used by
  69. the architecture-specific code will be available in
  70. ``include/nuttx/page.h``. Most architecture-specific functions are
  71. declared in ``include/nuttx/arch.h``, but for the case of this paging
  72. logic, those architecture specific functions are instead declared in
  73. ``include/nuttx/page.h``.
  74. Page Faults
  75. -----------
  76. **Page fault exception handling**. Page fault handling is performed by
  77. the function ``pg_miss()``. This function is called from
  78. architecture-specific memory segmentation fault handling logic. This
  79. function will perform the following operations:
  80. #. **Sanity checking**. This function will ASSERT if the currently
  81. executing task is the page fill worker thread. The page fill worker
  82. thread is how the page fault is resolved and all logic associated
  83. with the page fill worker must be "`locked <#MemoryOrg>`__" and
  84. always present in memory.
  85. #. **Block the currently executing task**. This function will call
  86. ``up_block_task()`` to block the task at the head of the ready-to-run
  87. list. This should cause an interrupt level context switch to the next
  88. highest priority task. The blocked task will be marked with state
  89. ``TSTATE_WAIT_PAGEFILL`` and will be retained in the
  90. ``g_waitingforfill`` prioritized task list.
  91. #. **Boost the page fill worker thread priority**. Check the priority of
  92. the task at the head of the ``g_waitingforfill`` list. If the
  93. priority of that task is higher than the current priority of the page
  94. fill worker thread, then boost the priority of the page fill worker
  95. thread to that priority. Thus, the page fill worker thread will
  96. always run at the priority of the highest priority task that is
  97. waiting for a fill.
  98. #. **Signal the page fill worker thread**. Is there a page already being
  99. filled? If not then signal the page fill worker thread to start
  100. working on the queued page fill requests.
  101. When signaled from ``pg_miss()``, the page fill worker thread will be
  102. awakenend and will initiate the fill operation.
  103. **Input Parameters.** None -- The head of the ready-to-run list is
  104. assumed to be that task that caused the exception. The current task
  105. context should already be saved in the TCB of that task. No additional
  106. inputs are required.
  107. **Assumptions**.
  108. - It is assumed that this function is called from the level of an
  109. exception handler and that all interrupts are disabled.
  110. - The ``pg_miss()`` must be "`locked <#MemoryOrg>`__" in memory.
  111. Calling ``pg_miss()`` cannot cause a nested page fault.
  112. - It is assumed that currently executing task (the one at the head of
  113. the ready-to-run list) is the one that cause the fault. This will
  114. always be true unless the page fault occurred in an interrupt
  115. handler. Interrupt handling logic must always be available and
  116. "`locked <#MemoryOrg>`__" into memory so that page faults never come
  117. from interrupt handling.
  118. - The architecture-specific page fault exception handling has already
  119. verified that the exception did not occur from interrupt/exception
  120. handling logic.
  121. - As mentioned above, the task causing the page fault must not be the
  122. page fill worker thread because that is the only way to complete the
  123. page fill.
  124. Fill Initiation
  125. ---------------
  126. The page fill worker thread will be awakened on one of three conditions:
  127. - When signaled by ``pg_miss()``, the page fill worker thread will be
  128. awakenend (see above),
  129. - From ``pg_callback()`` after completing last fill (when
  130. ``CONFIG_PAGING_BLOCKINGFILL`` is defined... see below), or
  131. - A configurable timeout expires with no activity. This timeout can be
  132. used to detect failure conditions such things as fills that never
  133. complete.
  134. The page fill worker thread will maintain a static variable called
  135. ``struct tcb_s *g_pftcb``. If no fill is in progress, ``g_pftcb`` will
  136. be NULL. Otherwise, it will point to the TCB of the task which is
  137. receiving the fill that is in progress.
  138. When awakened from ``pg_miss()``, no fill will be in progress and
  139. ``g_pftcb`` will be NULL. In this case, the page fill worker thread will
  140. call ``pg_startfill()``. That function will perform the following
  141. operations:
  142. - Call the architecture-specific function ``up_checkmapping()`` to see
  143. if the page fill still needs to be performed. In certain conditions,
  144. the page fault may occur on several threads and be queued multiple
  145. times. In this corner case, the blocked task will simply be restarted
  146. (see the logic below for the case of normal completion of the fill
  147. operation).
  148. - Call ``up_allocpage(tcb, &vpage)``. This architecture-specific
  149. function will set aside page in memory and map to virtual address
  150. (vpage). If all available pages are in-use (the typical case), this
  151. function will select a page in-use, un-map it, and make it available.
  152. - Call the architecture-specific function ``up_fillpage()``. Two
  153. versions of the up_fillpage function are supported -- a blocking and
  154. a non-blocking version based upon the configuration setting
  155. ``CONFIG_PAGING_BLOCKINGFILL``.
  156. - If ``CONFIG_PAGING_BLOCKINGFILL`` is defined, then up_fillpage is
  157. blocking call. In this case, ``up_fillpage()`` will accept only
  158. (1) a reference to the TCB that requires the fill.
  159. Architecture-specific context information within the TCB will be
  160. sufficient to perform the fill. And (2) the (virtual) address of
  161. the allocated page to be filled. The resulting status of the fill
  162. will be provided by return value from ``up_fillpage()``.
  163. - If ``CONFIG_PAGING_BLOCKINGFILL`` is defined, then up_fillpage is
  164. non-blocking call. In this case ``up_fillpage()`` will accept an
  165. additional argument: The page fill worker thread will provide a
  166. callback function, ``pg_callback``. This function is non-blocking,
  167. it will start an asynchronous page fill. After calling the
  168. non-blocking ``up_fillpage()``, the page fill worker thread will
  169. wait to be signaled for the next event -- the fill completion
  170. event. The callback function will be called when the page fill is
  171. finished (or an error occurs). The resulting status of the fill
  172. will be providing as an argument to the callback functions. This
  173. callback will probably occur from interrupt level.
  174. In any case, while the fill is in progress, other tasks may execute. If
  175. another page fault occurs during this time, the faulting task will be
  176. blocked, its TCB will be added (in priority order) to
  177. ``g_waitingforfill``, and the priority of the page worker task may be
  178. boosted. But no action will be taken until the current page fill
  179. completes. NOTE: The IDLE task must also be fully
  180. `locked <#MemoryOrg>`__ in memory. The IDLE task cannot be blocked. It
  181. the case where all tasks are blocked waiting for a page fill, the IDLE
  182. task must still be available to run.
  183. The architecture-specific functions, ``up_checkmapping()``,
  184. ``up_allocpage(tcb, &vpage)`` and ``up_fillpage(page, pg_callback)``
  185. will be prototyped in ``include/nuttx/arch.h``
  186. Fill Complete
  187. -------------
  188. For the blocking ``up_fillpage()``, the result of the fill will be
  189. returned directly from the call to ``up_fillpage``.
  190. For the non-blocking ``up_fillpage()``, the architecture-specific driver
  191. call the ``pg_callback()`` that was provided to ``up_fillpage()`` when
  192. the fill completes. In this case, the ``pg_callback()`` will probably be
  193. called from driver interrupt-level logic. The driver will provide the
  194. result of the fill as an argument to the callback function. NOTE:
  195. ``pg_callback()`` must also be `locked <#MemoryOrg>`__ in memory.
  196. In this non-blocking case, the callback ``pg_callback()`` will perform
  197. the following operations when it is notified that the fill has
  198. completed:
  199. - Verify that ``g_pftcb`` is non-NULL.
  200. - Find the higher priority between the task waiting for the fill to
  201. complete in ``g_pftcb`` and the task waiting at the head of the
  202. ``g_waitingforfill`` list. That will be the priority of he highest
  203. priority task waiting for a fill.
  204. - If this higher priority is higher than current page fill worker
  205. thread, then boost worker thread's priority to that level. Thus, the
  206. page fill worker thread will always run at the priority of the
  207. highest priority task that is waiting for a fill.
  208. - Save the result of the fill operation.
  209. - Signal the page fill worker thread.
  210. Task Resumption
  211. ---------------
  212. For the non-blocking ``up_fillpage()``, the page fill worker thread will
  213. detect that the page fill is complete when it is awakened with
  214. ``g_pftcb`` non-NULL and fill completion status from ``pg_callback``. In
  215. the non-blocking case, the page fill worker thread will know that the
  216. page fill is complete when ``up_fillpage()`` returns.
  217. In this either, the page fill worker thread will:
  218. - Verify consistency of state information and ``g_pftcb``.
  219. - Verify that the page fill completed successfully, and if so,
  220. - Call ``up_unblocktask(g_pftcb)`` to make the task that just received
  221. the fill ready-to-run.
  222. - Check if the ``g_waitingforfill`` list is empty. If not:
  223. - Remove the highest priority task waiting for a page fill from
  224. ``g_waitingforfill``,
  225. - Save the task's TCB in ``g_pftcb``,
  226. - If the priority of the thread in ``g_pftcb``, is higher in
  227. priority than the default priority of the page fill worker thread,
  228. then set the priority of the page fill worker thread to that
  229. priority.
  230. - Call ``pg_startfill()`` which will start the next fill (as
  231. described above).
  232. - Otherwise,
  233. - Set ``g_pftcb`` to NULL.
  234. - Restore the default priority of the page fill worker thread.
  235. - Wait for the next fill related event (a new page fault).
  236. Architecture-Specific Support Requirements
  237. ==========================================
  238. Memory Organization
  239. -------------------
  240. **Memory Regions**. Chip specific logic will map the virtual and
  241. physical address spaces into three general regions:
  242. #. A .text region containing "`locked-in-memory <#MemoryOrg>`__" code
  243. that is always available and will never cause a page fault. This
  244. locked memory is loaded at boot time and remains resident for all
  245. time. This memory regions must include:
  246. - All logic for all interrupt paths. All interrupt logic must be
  247. locked in memory because the design present here will not support
  248. page faults from interrupt handlers. This includes the page fault
  249. handling logic and ```pg_miss()`` <#PageFaults>`__ that is called
  250. from the page fault handler. It also includes the
  251. ```pg_callback()`` <#FillComplete>`__ function that wakes up the
  252. page fill worker thread and whatever architecture-specific logic
  253. that calls ``pg_callback()``.
  254. - All logic for the IDLE thread. The IDLE thread must always be
  255. ready to run and cannot be blocked for any reason.
  256. - All of the page fill worker thread must be locked in memory. This
  257. thread must execute in order to unblock any thread waiting for a
  258. fill. It this thread were to block, there would be no way to
  259. complete the fills!
  260. #. A .text region containing pages that can be assigned allocated,
  261. mapped to various virtual addresses, and filled from some mass
  262. storage medium.
  263. #. And a fixed RAM space for .bss, .text, and .heap.
  264. This memory organization is illustrated in the following table. Notice
  265. that:
  266. - There is a one-to-one relationship between pages in the virtual
  267. address space and between pages of .text in the non-volatile mass
  268. storage device.
  269. - There are, however, far fewer physical pages available than virtual
  270. pages. Only a subset of physical pages will be mapped to virtual
  271. pages at any given time. This mapping will be performed on-demand as
  272. needed for program execution.
  273. ============================= ============================ ====================
  274. SRAM Virtual Address Space Non-Volatile Storage
  275. ============================= ============================ ====================
  276. . DATA .
  277. . Virtual Page *n* (*n* > *m*) Stored Page *n*
  278. . Virtual Page *n-1* Stored Page *n-1*
  279. DATA ... ...
  280. Physical Page *m* (*m* < *n*) ... ...
  281. Physical Page *m-1* ... ...
  282. ... ... ...
  283. Physical Page *1* Virtual Page *1* Stored Page *1*
  284. Locked Memory Locked Memory Memory Resident
  285. ============================= ============================ ====================
  286. **Example**. As an example, suppose that the size of the SRAM is 192K
  287. (as in the NXP LPC3131). And suppose further that:
  288. - The size of the locked, memory resident .text area is 32K, and
  289. - The size of the DATA area is 64K.
  290. - The size of one, managed page is 1K.
  291. - The size of the whole .text image on the non-volatile, mass storage
  292. device is 1024K.
  293. Then, the size of the locked, memory resident code is 32K (*m*\ =32
  294. pages). The size of the physical page region is 96K (96 pages), and the
  295. size of the data region is 64 pages. And the size of the virtual paged
  296. region must then be greater than or equal to (1024-32) or 992 pages
  297. (*n*).
  298. **Building the Locked, In-Memory Image**. One way to accomplish this
  299. would be a two phase link:
  300. - In the first phase, create a partially linked objected containing all
  301. interrupt/exception handling logic, the page fill worker thread plus
  302. all parts of the IDLE thread (which must always be available for
  303. execution).
  304. - All of the ``.text`` and ``.rodata`` sections of this partial link
  305. should be collected into a single section.
  306. - The second link would link the partially linked object along with the
  307. remaining object to produce the final binary. The linker script
  308. should position the "special" section so that it lies in a reserved,
  309. "non-swappable" region.
  310. Architecture-Specific Functions
  311. -------------------------------
  312. Most standard, architecture-specific functions are declared in
  313. ``include/nuttx/arch.h``. However, for the case of this paging logic,
  314. the architecture specific functions are declared in
  315. ``include/nuttx/page.h``. Standard, architecture-specific functions that
  316. should already be provided in the architecture port are :c:func:`up_block_task`
  317. and :c:func:`up_unblock_task`. New, additional functions that must be
  318. implemented just for on-demand paging support are:
  319. .. c:function:: int up_checkmapping(FAR struct tcb_s *tcb)
  320. The function ``up_checkmapping()`` returns an indication if the page
  321. fill still needs to performed or not. In certain conditions, the page
  322. fault may occur on several threads and be queued multiple times. This
  323. function will prevent the same page from be filled multiple times.
  324. .. c:function:: int up_allocpage(FAR struct tcb_s *tcb, FAR void *vpage)
  325. This architecture-specific function will set aside page in memory and
  326. map to its correct virtual address. Architecture-specific context
  327. information saved within the TCB will provide the function with the
  328. information needed to identify the virtual miss address. This function
  329. will return the allocated physical page address in ``vpage``. The size
  330. of the underlying physical page is determined by the configuration
  331. setting ``CONFIG_PAGING_PAGESIZE``. NOTE: This function must *always*
  332. return a page allocation. If all available pages are in-use (the typical
  333. case), then this function will select a page in-use, un-map it, and make
  334. it available.
  335. .. c:function:: int up_fillpage(FAR struct tcb_s *tcb, FAR const void *vpage, void (*pg_callback)(FAR struct tcb_s *tcb, int result))
  336. The actual filling of the page with data from the non-volatile, must be
  337. performed by a separate call to the architecture-specific function,
  338. ``up_fillpage()``. This will start asynchronous page fill. The common
  339. paging logic will provide a callback function, ``pg_callback``, that
  340. will be called when the page fill is finished (or an error occurs). This
  341. callback is assumed to occur from an interrupt level when the device
  342. driver completes the fill operation.