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 */
|