/**************************************************************************** * include/nuttx/page.h * * SPDX-License-Identifier: Apache-2.0 * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ #ifndef __INCLUDE_NUTTX_PAGE_H #define __INCLUDE_NUTTX_PAGE_H /**************************************************************************** * Included Files ****************************************************************************/ #include #ifndef __ASSEMBLY__ # include # include #endif #ifdef CONFIG_LEGACY_PAGING /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ /* Configuration ************************************************************/ /* CONFIG_PAGING_PAGESIZE - The size of one managed page. This must be a * value supported by the processor's memory management unit. The * following may need to be extended to support additional page sizes at * some point. */ #if CONFIG_PAGING_PAGESIZE == 1024 # define PAGESHIFT 10 #elif CONFIG_PAGING_PAGESIZE == 4096 # define PAGESHIFT 12 #else # error "Need extended definitions for CONFIG_PAGING_PAGESIZE" #endif /* Common page macros */ # define PAGESIZE (1 << PAGESHIFT) # define PAGEMASK (PAGESIZE - 1) /* Alignment macros */ #define PG_ALIGNDOWN(addr) ((addr) & ~PAGEMASK) #define PG_ALIGNUP(addr) (((addr) + PAGEMASK) & ~PAGEMASK) /* CONFIG_PAGING_NLOCKED - This is the number of locked pages in the memory * map. The size of locked address region will then be given by * PG_LOCKED_SIZE. These values applies to both physical and virtual memory * regions. */ #define PG_LOCKED_SIZE (CONFIG_PAGING_NLOCKED << PAGESHIFT) /* CONFIG_PAGING_LOCKED_P/VBASE - May be defined to determine the base * address of the locked page regions (lowest in memory). If neither * are defined, then this logic will be set the bases to CONFIG_RAM_START * and CONFIG_RAM_VSTART (i.e., it assumes that the base address of the * locked region is at the beginning of RAM). * * NOTE: In some architectures, it may be necessary to take some memory * from the beginning of this region for vectors or for a page table. * In such cases, either (1) CONFIG_PAGING_LOCKED_P/VBASE might take that * into consideration to prevent overlapping the locked memory region * and the system data at the beginning of SRAM, (2) you extend * CONFIG_PAGING_NLOCKED include these pages at the beginning * of memory and map let them be mapped read-only. */ #if defined(CONFIG_PAGING_LOCKED_PBASE) && defined(CONFIG_PAGING_LOCKED_VBASE) # define PG_LOCKED_PBASE CONFIG_PAGING_LOCKED_PBASE # define PG_LOCKED_VBASE CONFIG_PAGING_LOCKED_VBASE #else # define PG_LOCKED_PBASE CONFIG_RAM_START # define PG_LOCKED_VBASE CONFIG_RAM_VSTART #endif #define PG_LOCKED_PEND (PG_LOCKED_PBASE + PG_LOCKED_SIZE) #define PG_LOCKED_VEND (PG_LOCKED_VBASE + PG_LOCKED_SIZE) #if (PG_LOCKED_PBASE & PAGEMASK) != 0 || (PG_LOCKED_VBASE & PAGEMASK) != 0 # error "Base address of the locked region is not page aligned" #endif /* CONFIG_PAGING_NPPAGED - This is the number of physical pages available to * support the paged text region. * CONFIG_PAGING_NVPAGED - This actual size of the virtual paged text region * (in pages). This is also the number of virtual pages required to span * the entire paged region. The on-demand paging feature is intended to * support only the case where the virtual paged text area is much larger * the available physical pages. Otherwise, why would you enable on-demand * paging? */ #if CONFIG_PAGING_NPPAGED >= CONFIG_PAGING_NVPAGED # error "CONFIG_PAGING_NPPAGED must be less than CONFIG_PAGING_NVPAGED" #endif /* The size of physical and virtual paged address regions will then be: */ #define PG_PAGED_PSIZE (CONFIG_PAGING_NPPAGED << PAGESHIFT) #define PG_PAGED_VSIZE (CONFIG_PAGING_NVPAGED << PAGESHIFT) /* This positions the paging Read-Only text region. If the configuration * did not override the default, the paged region will immediately follow * the locked region. */ #if defined(CONFIG_PAGING_LOCKED_PBASE) && defined(CONFIG_PAGING_LOCKED_VBASE) # define PG_PAGED_PBASE CONFIG_PAGING_LOCKED_PBASE # define PG_PAGED_VBASE CONFIG_PAGING_LOCKED_VBASE #else # define PG_PAGED_PBASE PG_LOCKED_PEND # define PG_PAGED_VBASE PG_LOCKED_VEND #endif #define PG_PAGED_PEND (PG_PAGED_PBASE + PG_PAGED_PSIZE) #define PG_PAGED_VEND (PG_PAGED_VBASE + PG_PAGED_VSIZE) /* Size and description of the overall text section. The number of * pages in the text section is the sum of the number of pages in * both the locked and paged regions. The base of the text section * is the base of the locked region. */ #define PG_TEXT_NPPAGES (CONFIG_PAGING_NLOCKED + CONFIG_PAGING_NPPAGED) #define PG_TEXT_NVPAGES (CONFIG_PAGING_NLOCKED + CONFIG_PAGING_NVPAGED) #define PG_TEXT_PSIZE (PG_TEXT_NPPAGES << PAGESHIFT) #define PG_TEXT_VSIZE (PG_TEXT_NVPAGES << PAGESHIFT) #define PG_TEXT_PBASE PG_LOCKED_PBASE #define PG_TEXT_VBASE PG_LOCKED_VBASE /* CONFIG_PAGING_NDATA - This is the number of data pages in the memory * map. The data region will extend to the end of RAM unless overridden * by a setting in the configuration file. * * NOTE: In some architectures, it may be necessary to take some memory * from the end of RAM for page tables or other system usage. The * configuration settings and linker directives must be cognizant of that: * CONFIG_PAGING_NDATA should be defined to prevent the data region from * extending all the way to the end of memory. */ #define PG_RAM_PAGES (CONFIG_RAM_SIZE >> PAGESHIFT) #ifdef CONFIG_PAGING_NDATA # define PG_DATA_NPAGES CONFIG_PAGING_NDATA #elif PG_RAM_PAGES > PG_TEXT_NPPAGES # define PG_DATA_NPAGES (PG_RAM_PAGES - PG_TEXT_NPAGES) #else # error "Not enough memory for this page layout" #endif #define PG_DATA_SIZE (PG_DATA_NPAGES << PAGESHIFT) /* This positions the Read/Write data region. If the configuration * did not override the default, the paged region will immediately follow * the paged region and will extend to the end of memory. */ #if defined(CONFIG_PAGING_DATA_PBASE) && defined(CONFIG_PAGING_DATA_VBASE) # define PG_DATA_PBASE CONFIG_PAGING_DATA_PBASE # define PG_DATA_VBASE CONFIG_PAGING_DATA_VBASE #else # define PG_DATA_PBASE PG_LOCKED_PEND # define PG_DATA_VBASE PG_LOCKED_VEND #endif /* CONFIG_PAGING_DEFPRIO - The default, minimum priority of the page fill * worker thread. The priority of the page fill work thread will be * boosted boosted dynamically so that it matches the priority of the * task on behalf of which it performs the fill. This defines the * minimum priority that will be used. Default: 50. * CONFIG_PAGING_STACKSIZE - Defines the size of the allocated stack * for the page fill worker thread. Default: 1024. * CONFIG_PAGING_BLOCKINGFILL - The architecture specific up_fillpage() * function may be blocking or non-blocking. If defined, this setting * indicates that the up_fillpage() implementation will block until * the transfer is completed. Default: Undefined (non-blocking). * CONFIG_PAGING_WORKPERIOD - The page fill worker thread will wake * periodically even if there is no mapping to do. This selection controls * that wake-up period (in microseconds). This wake-up a failsafe that * will handle any cases where a single is lost (that would really be a bug * and shouldn't happen!) and also supports timeouts for case of * non-blocking, asynchronous fills (see CONFIG_PAGING_TIMEOUT_TICKS). * CONFIG_PAGING_TIMEOUT_TICKS - If defined, the implementation will monitor * the (asynchronous) page fill logic. If the fill takes longer than this * number if microseconds, then a fatal error will be declared. * Default: No timeouts monitored. */ /**************************************************************************** * Public Data ****************************************************************************/ #ifndef __ASSEMBLY__ #undef EXTERN #if defined(__cplusplus) #define EXTERN extern "C" extern "C" { #else #define EXTERN extern #endif /**************************************************************************** * Public Functions -- Provided by common paging logic to architecture- * specific logic. ****************************************************************************/ /**************************************************************************** * Name: pg_miss * * Description: * This function is called from architecture-specific memory segmentation * fault handling logic. This function will perform the following * operations: * * 1) Sanity checking. * - ASSERT if the currently executing task is the page fill worker * thread. The page fill worker thread is how the page fault * is resolved and all logic associated with the page fill worker * must be "locked" and always present in memory. * 2) Block the currently executing task. * - Call up_switch_context() 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 TSTATE_WAIT_PAGEFILL * and will be retained in the g_waitingforfill prioritized task * list. * 3) Boost the page fill worker thread priority. * - Check the priority of the task at the head of the g_waitingforfill * 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. * 4) Signal the page fill worker thread. * - Is there a page fill pending? If not then signal the worker * thread to start working on the queued page fill requests. * * Input Parameters: * None - The head of the ready-to-run list is assumed to be task that * caused the exception. * * Returned Value: * None - Either this function function succeeds or an assertion occurs. * * Assumptions: * - It is assumed that this function is called from the level of an * exception handler and that all interrupts are disabled. * - 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 present and "locked" into * memory. * - The chip-specific page fault exception handler has already verified * that the exception did not occur from interrupt/exception handling * logic. * - 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. * * NOTES: * 1. One way to accomplish this would be a two pass link phase: * - 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). * - All of the .text and .rodata sections of this partial link should * be collected into a single section. * - 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. * ****************************************************************************/ void pg_miss(void); /**************************************************************************** * Public Functions -- Provided by architecture-specific logic to common * paging logic. ****************************************************************************/ /**************************************************************************** * Name: up_checkmapping() * * Description: * The function up_checkmapping() 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. * * Input Parameters: * tcb - A reference to the task control block of the task that we believe * needs to have a page fill. Architecture-specific logic can * retrieve page fault information from the architecture-specific * context information in this TCB and can consult processor * resources (page tables or TLBs or ???) to determine if the fill * still needs to be performed or not. * * Returned Value: * This function will return true if the mapping is in place and false * if the mapping is still needed. Errors encountered should be * interpreted as fatal. * * Assumptions: * - This function is called from the normal tasking context (but with * interrupts disabled). The implementation must take whatever actions * are necessary to assure that the operation is safe within this * context. * ****************************************************************************/ bool up_checkmapping(FAR struct tcb_s *tcb); /**************************************************************************** * Name: up_allocpage() * * Description: * This architecture-specific function will set aside page in memory and map * the page 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 vpage. * The size of the underlying physical page is determined by the * configuration setting CONFIG_PAGING_PAGESIZE. * * NOTE 1: This function must always 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. * * NOTE 2: If an in-use page is un-mapped, it may be necessary to flush the * instruction cache in some architectures. * * NOTE 3: Allocating and filling a page is a two step process. * up_allocpage() allocates the page, and up_fillpage() fills it with data * from some non- volatile storage device. This distinction is made because * up_allocpage() can probably be implemented in board-independent logic * whereas up_fillpage() probably must be implemented as board-specific * logic. * * NOTE 4: The initial mapping of vpage should be read-able and write- * able (but not cached). No special actions will be required of * up_fillpage() in order to write into this allocated page. * * Input Parameters: * tcb - A reference to the task control block of the task that needs to * have a page fill. Architecture-specific logic can retrieve page * fault information from the architecture-specific context * information in this TCB to perform the mapping. * * Returned Value: * This function will return zero (OK) if the allocation was successful. * A negated errno value may be returned if an error occurs. All errors, * however, are fatal. * * Assumptions: * - This function is called from the normal tasking context (but with * interrupts disabled). The implementation must take whatever actions * are necessary to assure that the operation is safe within this * context. * ****************************************************************************/ int up_allocpage(FAR struct tcb_s *tcb, FAR void **vpage); /**************************************************************************** * Name: up_fillpage() * * Description: * After a page is allocated and mapped by up_allocpage(), the actual * filling of the page with data from the non-volatile, must be performed * by a separate call to the architecture-specific function, up_fillpage(). * This function is non-blocking, it will start an asynchronous page fill. * The common paging logic will provide a callback function, pg_callback, * 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. * * NOTE 1: Allocating and filling a page is a two step process. * up_allocpage() allocates the page, and up_fillpage() fills it with data * from some non- volatile storage device. This distinction is made because * up_allocpage() can probably be implemented in board-independent logic * whereas up_fillpage() probably must be implemented as board-specific * logic. * * NOTE 2: The initial mapping of vpage will be read-able, write-able, * but non-cacheable. No special actions will be required of * up_fillpage() in order to write into this allocated page. If the * virtual address maps to a text region, however, this function should * remap the region so that is is read/execute only. It should be made * cache-able in any case. * * Input Parameters: * tcb - A reference to the task control block of the task that needs to * have a page fill. Architecture-specific logic can retrieve page * fault information from the architecture-specific context * information in this TCB to perform the fill. * pg_callbck - The function to be called when the page fill is complete. * * Returned Value: * This function will return zero (OK) if the page fill was successfully * started (the result of the page fill is passed to the callback function * as the result argument). A negated errno value may be returned if an * error occurs. All errors, however, are fatal. * * NOTE: -EBUSY has a special meaning. It is used internally to mean that * the callback function has not executed. Therefore, -EBUSY should * never be provided in the result argument of pg_callback. * * Assumptions: * - This function is called from the normal tasking context (but * interrupts siabled). The implementation must take whatever actions * are necessary to assure that the operation is safe within this * context. * - Upon return, the caller will sleep waiting for the page fill callback * to occur. The callback function will perform the wakeup. * ****************************************************************************/ #ifdef CONFIG_PAGING_BLOCKINGFILL int up_fillpage(FAR struct tcb_s *tcb, FAR void *vpage); #else typedef CODE void (*up_pgcallback_t)(FAR struct tcb_s *tcb, int result); int up_fillpage(FAR struct tcb_s *tcb, FAR void *vpage, up_pgcallback_t pg_callback); #endif #undef EXTERN #if defined(__cplusplus) } #endif #endif /* __ASSEMBLY__ */ #endif /* CONFIG_LEGACY_PAGING */ #endif /* __INCLUDE_NUTTX_PAGE_H */