Line data Source code
1 0 : /* 2 : * Copyright (c) 2020 Intel Corporation 3 : * 4 : * SPDX-License-Identifier: Apache-2.0 5 : */ 6 : 7 : #ifndef ZEPHYR_INCLUDE_KERNEL_MM_DEMAND_PAGING_H 8 : #define ZEPHYR_INCLUDE_KERNEL_MM_DEMAND_PAGING_H 9 : 10 : #include <zephyr/kernel/mm.h> 11 : 12 : #include <zephyr/sys/util.h> 13 : #include <zephyr/toolchain.h> 14 : 15 : /** 16 : * @defgroup demand_paging Demand Paging 17 : * @ingroup kernel_memory_management 18 : */ 19 : 20 : /** 21 : * @defgroup mem-demand-paging Demand Paging APIs 22 : * @ingroup demand_paging 23 : * @{ 24 : */ 25 : 26 : #ifndef _ASMLANGUAGE 27 : #include <stdint.h> 28 : #include <stddef.h> 29 : #include <inttypes.h> 30 : #include <zephyr/sys/__assert.h> 31 : 32 : struct k_mem_page_frame; 33 : 34 : /** 35 : * Paging Statistics. 36 : */ 37 1 : struct k_mem_paging_stats_t { 38 : #if defined(CONFIG_DEMAND_PAGING_STATS) || defined(__DOXYGEN__) 39 : struct { 40 : /** Number of page faults */ 41 1 : unsigned long cnt; 42 : 43 : /** Number of page faults with IRQ locked */ 44 1 : unsigned long irq_locked; 45 : 46 : /** Number of page faults with IRQ unlocked */ 47 1 : unsigned long irq_unlocked; 48 : 49 : #if !defined(CONFIG_DEMAND_PAGING_ALLOW_IRQ) || defined(__DOXYGEN__) 50 : /** Number of page faults while in ISR */ 51 1 : unsigned long in_isr; 52 : #endif /* !CONFIG_DEMAND_PAGING_ALLOW_IRQ */ 53 0 : } pagefaults; 54 : 55 : struct { 56 : /** Number of clean pages selected for eviction */ 57 1 : unsigned long clean; 58 : 59 : /** Number of dirty pages selected for eviction */ 60 1 : unsigned long dirty; 61 0 : } eviction; 62 : #endif /* CONFIG_DEMAND_PAGING_STATS */ 63 : }; 64 : 65 : /** 66 : * Paging Statistics Histograms. 67 : */ 68 1 : struct k_mem_paging_histogram_t { 69 : #if defined(CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM) || defined(__DOXYGEN__) 70 : /* Counts for each bin in timing histogram */ 71 0 : unsigned long counts[CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM_NUM_BINS]; 72 : 73 : /* Bounds for the bins in timing histogram, 74 : * excluding the first and last (hence, NUM_SLOTS - 1). 75 : */ 76 0 : unsigned long bounds[CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM_NUM_BINS]; 77 : #endif /* CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM */ 78 : }; 79 : 80 : #ifdef __cplusplus 81 : extern "C" { 82 : #endif 83 : 84 : /** 85 : * Evict a page-aligned virtual memory region to the backing store 86 : * 87 : * Useful if it is known that a memory region will not be used for some time. 88 : * All the data pages within the specified region will be evicted to the 89 : * backing store if they weren't already, with their associated page frames 90 : * marked as available for mappings or page-ins. 91 : * 92 : * None of the associated page frames mapped to the provided region should 93 : * be pinned. 94 : * 95 : * Note that there are no guarantees how long these pages will be evicted, 96 : * they could take page faults immediately. 97 : * 98 : * If CONFIG_DEMAND_PAGING_ALLOW_IRQ is enabled, this function may not be 99 : * called by ISRs as the backing store may be in-use. 100 : * 101 : * @param addr Base page-aligned virtual address 102 : * @param size Page-aligned data region size 103 : * @retval 0 Success 104 : * @retval -ENOMEM Insufficient space in backing store to satisfy request. 105 : * The region may be partially paged out. 106 : */ 107 1 : int k_mem_page_out(void *addr, size_t size); 108 : 109 : /** 110 : * Load a virtual data region into memory 111 : * 112 : * After the function completes, all the page frames associated with this 113 : * function will be paged in. However, they are not guaranteed to stay there. 114 : * This is useful if the region is known to be used soon. 115 : * 116 : * If CONFIG_DEMAND_PAGING_ALLOW_IRQ is enabled, this function may not be 117 : * called by ISRs as the backing store may be in-use. 118 : * 119 : * @param addr Base page-aligned virtual address 120 : * @param size Page-aligned data region size 121 : */ 122 1 : void k_mem_page_in(void *addr, size_t size); 123 : 124 : /** 125 : * Pin an aligned virtual data region, paging in as necessary 126 : * 127 : * After the function completes, all the page frames associated with this 128 : * region will be resident in memory and pinned such that they stay that way. 129 : * This is a stronger version of z_mem_page_in(). 130 : * 131 : * If CONFIG_DEMAND_PAGING_ALLOW_IRQ is enabled, this function may not be 132 : * called by ISRs as the backing store may be in-use. 133 : * 134 : * @param addr Base page-aligned virtual address 135 : * @param size Page-aligned data region size 136 : */ 137 1 : void k_mem_pin(void *addr, size_t size); 138 : 139 : /** 140 : * Un-pin an aligned virtual data region 141 : * 142 : * After the function completes, all the page frames associated with this 143 : * region will be no longer marked as pinned. This does not evict the region, 144 : * follow this with z_mem_page_out() if you need that. 145 : * 146 : * @param addr Base page-aligned virtual address 147 : * @param size Page-aligned data region size 148 : */ 149 1 : void k_mem_unpin(void *addr, size_t size); 150 : 151 : /** 152 : * Get the paging statistics since system startup 153 : * 154 : * This populates the paging statistics struct being passed in 155 : * as argument. 156 : * 157 : * @param[in,out] stats Paging statistics struct to be filled. 158 : */ 159 1 : __syscall void k_mem_paging_stats_get(struct k_mem_paging_stats_t *stats); 160 : 161 : struct k_thread; 162 : /** 163 : * Get the paging statistics since system startup for a thread 164 : * 165 : * This populates the paging statistics struct being passed in 166 : * as argument for a particular thread. 167 : * 168 : * @param[in] thread Thread 169 : * @param[in,out] stats Paging statistics struct to be filled. 170 : */ 171 : __syscall 172 1 : void k_mem_paging_thread_stats_get(struct k_thread *thread, 173 : struct k_mem_paging_stats_t *stats); 174 : 175 : /** 176 : * Get the eviction timing histogram 177 : * 178 : * This populates the timing histogram struct being passed in 179 : * as argument. 180 : * 181 : * @param[in,out] hist Timing histogram struct to be filled. 182 : */ 183 1 : __syscall void k_mem_paging_histogram_eviction_get( 184 : struct k_mem_paging_histogram_t *hist); 185 : 186 : /** 187 : * Get the backing store page-in timing histogram 188 : * 189 : * This populates the timing histogram struct being passed in 190 : * as argument. 191 : * 192 : * @param[in,out] hist Timing histogram struct to be filled. 193 : */ 194 1 : __syscall void k_mem_paging_histogram_backing_store_page_in_get( 195 : struct k_mem_paging_histogram_t *hist); 196 : 197 : /** 198 : * Get the backing store page-out timing histogram 199 : * 200 : * This populates the timing histogram struct being passed in 201 : * as argument. 202 : * 203 : * @param[in,out] hist Timing histogram struct to be filled. 204 : */ 205 1 : __syscall void k_mem_paging_histogram_backing_store_page_out_get( 206 : struct k_mem_paging_histogram_t *hist); 207 : 208 : #include <zephyr/syscalls/demand_paging.h> 209 : 210 : /** @} */ 211 : 212 : /** 213 : * Eviction algorithm APIs 214 : * 215 : * @defgroup mem-demand-paging-eviction Eviction Algorithm APIs 216 : * @ingroup demand_paging 217 : * @{ 218 : */ 219 : 220 : #if defined(CONFIG_EVICTION_TRACKING) || defined(__DOXYGEN__) 221 : 222 : /** 223 : * Submit a page frame for eviction candidate tracking 224 : * 225 : * The kernel will invoke this to tell the eviction algorithm the provided 226 : * page frame may be considered as a potential eviction candidate. 227 : * 228 : * This function will never be called before the initial 229 : * k_mem_paging_eviction_init(). 230 : * 231 : * This function is invoked with interrupts locked. 232 : * 233 : * @param [in] pf The page frame to add 234 : */ 235 1 : void k_mem_paging_eviction_add(struct k_mem_page_frame *pf); 236 : 237 : /** 238 : * Remove a page frame from potential eviction candidates 239 : * 240 : * The kernel will invoke this to tell the eviction algorithm the provided 241 : * page frame may no longer be considered as a potential eviction candidate. 242 : * 243 : * This function will only be called with page frames that were submitted 244 : * using k_mem_paging_eviction_add() beforehand. 245 : * 246 : * This function is invoked with interrupts locked. 247 : * 248 : * @param [in] pf The page frame to remove 249 : */ 250 1 : void k_mem_paging_eviction_remove(struct k_mem_page_frame *pf); 251 : 252 : /** 253 : * Process a page frame as being newly accessed 254 : * 255 : * The architecture-specific memory fault handler will invoke this to tell the 256 : * eviction algorithm the provided physical address belongs to a page frame 257 : * being accessed and such page frame should become unlikely to be 258 : * considered as the next eviction candidate. 259 : * 260 : * This function is invoked with interrupts locked. 261 : * 262 : * @param [in] phys The physical address being accessed 263 : */ 264 1 : void k_mem_paging_eviction_accessed(uintptr_t phys); 265 : 266 : #else /* CONFIG_EVICTION_TRACKING || __DOXYGEN__ */ 267 : 268 : static inline void k_mem_paging_eviction_add(struct k_mem_page_frame *pf) 269 : { 270 : ARG_UNUSED(pf); 271 : } 272 : 273 : static inline void k_mem_paging_eviction_remove(struct k_mem_page_frame *pf) 274 : { 275 : ARG_UNUSED(pf); 276 : } 277 : 278 : static inline void k_mem_paging_eviction_accessed(uintptr_t phys) 279 : { 280 : ARG_UNUSED(phys); 281 : } 282 : 283 : #endif /* CONFIG_EVICTION_TRACKING || __DOXYGEN__ */ 284 : 285 : /** 286 : * Select a page frame for eviction 287 : * 288 : * The kernel will invoke this to choose a page frame to evict if there 289 : * are no free page frames. It is not guaranteed that the returned page 290 : * frame will actually be evicted. If it is then the kernel will call 291 : * k_mem_paging_eviction_remove() with it. 292 : * 293 : * This function will never be called before the initial 294 : * k_mem_paging_eviction_init(). 295 : * 296 : * This function is invoked with interrupts locked. 297 : * 298 : * @param [out] dirty Whether the page to evict is dirty 299 : * @return The page frame to evict 300 : */ 301 1 : struct k_mem_page_frame *k_mem_paging_eviction_select(bool *dirty); 302 : 303 : /** 304 : * Initialization function 305 : * 306 : * Called at POST_KERNEL to perform any necessary initialization tasks for the 307 : * eviction algorithm. k_mem_paging_eviction_select() is guaranteed to never be 308 : * called until this has returned, and this will only be called once. 309 : */ 310 1 : void k_mem_paging_eviction_init(void); 311 : 312 : /** @} */ 313 : 314 : /** 315 : * Backing store APIs 316 : * 317 : * @defgroup mem-demand-paging-backing-store Backing Store APIs 318 : * @ingroup demand_paging 319 : * @{ 320 : */ 321 : 322 : /** 323 : * Reserve or fetch a storage location for a data page loaded into a page frame 324 : * 325 : * The returned location token must be unique to the mapped virtual address. 326 : * This location will be used in the backing store to page out data page 327 : * contents for later retrieval. The location value must be page-aligned. 328 : * 329 : * This function may be called multiple times on the same data page. If its 330 : * page frame has its K_MEM_PAGE_FRAME_BACKED bit set, it is expected to return 331 : * the previous backing store location for the data page containing a cached 332 : * clean copy. This clean copy may be updated on page-out, or used to 333 : * discard clean pages without needing to write out their contents. 334 : * 335 : * If the backing store is full, some other backing store location which caches 336 : * a loaded data page may be selected, in which case its associated page frame 337 : * will have the K_MEM_PAGE_FRAME_BACKED bit cleared (as it is no longer cached). 338 : * 339 : * k_mem_page_frame_to_virt(pf) will indicate the virtual address the page is 340 : * currently mapped to. Large, sparse backing stores which can contain the 341 : * entire address space may simply generate location tokens purely as a 342 : * function of that virtual address with no other management necessary. 343 : * 344 : * This function distinguishes whether it was called on behalf of a page 345 : * fault. A free backing store location must always be reserved in order for 346 : * page faults to succeed. If the page_fault parameter is not set, this 347 : * function should return -ENOMEM even if one location is available. 348 : * 349 : * This function is invoked with interrupts locked. 350 : * 351 : * @param pf Virtual address to obtain a storage location 352 : * @param [out] location storage location token 353 : * @param page_fault Whether this request was for a page fault 354 : * @return 0 Success 355 : * @return -ENOMEM Backing store is full 356 : */ 357 1 : int k_mem_paging_backing_store_location_get(struct k_mem_page_frame *pf, 358 : uintptr_t *location, 359 : bool page_fault); 360 : 361 : /** 362 : * Free a backing store location 363 : * 364 : * Any stored data may be discarded, and the location token associated with 365 : * this address may be re-used for some other data page. 366 : * 367 : * This function is invoked with interrupts locked. 368 : * 369 : * @param location Location token to free 370 : */ 371 1 : void k_mem_paging_backing_store_location_free(uintptr_t location); 372 : 373 : /** 374 : * Obtain persistent location token for on-demand content 375 : * 376 : * Unlike k_mem_paging_backing_store_location_get() this does not allocate 377 : * any backing store space. Instead, it returns a location token corresponding 378 : * to some fixed storage content to be paged in on demand. This is expected 379 : * to be used in conjonction with CONFIG_LINKER_USE_ONDEMAND_SECTION and the 380 : * K_MEM_MAP_UNPAGED flag to create demand mappings at boot time. This may 381 : * also be used e.g. to implement file-based mmap(). 382 : * 383 : * @param addr Virtual address to obtain a location token for 384 : * @param [out] location storage location token 385 : * @return 0 for success or negative error code 386 : */ 387 1 : int k_mem_paging_backing_store_location_query(void *addr, uintptr_t *location); 388 : 389 : /** 390 : * Copy a data page from K_MEM_SCRATCH_PAGE to the specified location 391 : * 392 : * Immediately before this is called, K_MEM_SCRATCH_PAGE will be mapped read-write 393 : * to the intended source page frame for the calling context. 394 : * 395 : * Calls to this and k_mem_paging_backing_store_page_in() will always be 396 : * serialized, but interrupts may be enabled. 397 : * 398 : * @param location Location token for the data page, for later retrieval 399 : */ 400 1 : void k_mem_paging_backing_store_page_out(uintptr_t location); 401 : 402 : /** 403 : * Copy a data page from the provided location to K_MEM_SCRATCH_PAGE. 404 : * 405 : * Immediately before this is called, K_MEM_SCRATCH_PAGE will be mapped read-write 406 : * to the intended destination page frame for the calling context. 407 : * 408 : * Calls to this and k_mem_paging_backing_store_page_out() will always be 409 : * serialized, but interrupts may be enabled. 410 : * 411 : * @param location Location token for the data page 412 : */ 413 1 : void k_mem_paging_backing_store_page_in(uintptr_t location); 414 : 415 : /** 416 : * Update internal accounting after a page-in 417 : * 418 : * This is invoked after k_mem_paging_backing_store_page_in() and interrupts 419 : * have been* re-locked, making it safe to access the k_mem_page_frame data. 420 : * The location value will be the same passed to 421 : * k_mem_paging_backing_store_page_in(). 422 : * 423 : * The primary use-case for this is to update custom fields for the backing 424 : * store in the page frame, to reflect where the data should be evicted to 425 : * if it is paged out again. This may be a no-op in some implementations. 426 : * 427 : * If the backing store caches paged-in data pages, this is the appropriate 428 : * time to set the K_MEM_PAGE_FRAME_BACKED bit. The kernel only skips paging 429 : * out clean data pages if they are noted as clean in the page tables and the 430 : * K_MEM_PAGE_FRAME_BACKED bit is set in their associated page frame. 431 : * 432 : * @param pf Page frame that was loaded in 433 : * @param location Location of where the loaded data page was retrieved 434 : */ 435 1 : void k_mem_paging_backing_store_page_finalize(struct k_mem_page_frame *pf, 436 : uintptr_t location); 437 : 438 : /** 439 : * Backing store initialization function. 440 : * 441 : * The implementation may expect to receive page in/out calls as soon as this 442 : * returns, but not before that. Called at POST_KERNEL. 443 : * 444 : * This function is expected to do two things: 445 : * - Initialize any internal data structures and accounting for the backing 446 : * store. 447 : * - If the backing store already contains all or some loaded kernel data pages 448 : * at boot time, K_MEM_PAGE_FRAME_BACKED should be appropriately set for their 449 : * associated page frames, and any internal accounting set up appropriately. 450 : */ 451 1 : void k_mem_paging_backing_store_init(void); 452 : 453 : /** @} */ 454 : 455 : #ifdef __cplusplus 456 : } 457 : #endif 458 : 459 : #endif /* !_ASMLANGUAGE */ 460 : #endif /* ZEPHYR_INCLUDE_KERNEL_MM_DEMAND_PAGING_H */