1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3 * Describes operations that can be performed on software-defined page table
4 * leaf entries. These are abstracted from the hardware page table entries
5 * themselves by the softleaf_t type, see mm_types.h.
6 */
7 #ifndef _LINUX_LEAFOPS_H
8 #define _LINUX_LEAFOPS_H
9
10 #include <linux/mm_types.h>
11 #include <linux/swapops.h>
12 #include <linux/swap.h>
13
14 #ifdef CONFIG_MMU
15
16 /* Temporary until swp_entry_t eliminated. */
17 #define LEAF_TYPE_SHIFT SWP_TYPE_SHIFT
18
19 enum softleaf_type {
20 /* Fundamental types. */
21 SOFTLEAF_NONE,
22 SOFTLEAF_SWAP,
23 /* Migration types. */
24 SOFTLEAF_MIGRATION_READ,
25 SOFTLEAF_MIGRATION_READ_EXCLUSIVE,
26 SOFTLEAF_MIGRATION_WRITE,
27 /* Device types. */
28 SOFTLEAF_DEVICE_PRIVATE_READ,
29 SOFTLEAF_DEVICE_PRIVATE_WRITE,
30 SOFTLEAF_DEVICE_EXCLUSIVE,
31 /* H/W posion types. */
32 SOFTLEAF_HWPOISON,
33 /* Marker types. */
34 SOFTLEAF_MARKER,
35 };
36
37 /**
38 * softleaf_mk_none() - Create an empty ('none') leaf entry.
39 * Returns: empty leaf entry.
40 */
softleaf_mk_none(void)41 static inline softleaf_t softleaf_mk_none(void)
42 {
43 return ((softleaf_t) { 0 });
44 }
45
46 /**
47 * softleaf_from_pte() - Obtain a leaf entry from a PTE entry.
48 * @pte: PTE entry.
49 *
50 * If @pte is present (therefore not a leaf entry) the function returns an empty
51 * leaf entry. Otherwise, it returns a leaf entry.
52 *
53 * Returns: Leaf entry.
54 */
softleaf_from_pte(pte_t pte)55 static inline softleaf_t softleaf_from_pte(pte_t pte)
56 {
57 softleaf_t arch_entry;
58
59 if (pte_present(pte) || pte_none(pte))
60 return softleaf_mk_none();
61
62 pte = pte_swp_clear_flags(pte);
63 arch_entry = __pte_to_swp_entry(pte);
64
65 /* Temporary until swp_entry_t eliminated. */
66 return swp_entry(__swp_type(arch_entry), __swp_offset(arch_entry));
67 }
68
69 /**
70 * softleaf_to_pte() - Obtain a PTE entry from a leaf entry.
71 * @entry: Leaf entry.
72 *
73 * This generates an architecture-specific PTE entry that can be utilised to
74 * encode the metadata the leaf entry encodes.
75 *
76 * Returns: Architecture-specific PTE entry encoding leaf entry.
77 */
softleaf_to_pte(softleaf_t entry)78 static inline pte_t softleaf_to_pte(softleaf_t entry)
79 {
80 /* Temporary until swp_entry_t eliminated. */
81 return swp_entry_to_pte(entry);
82 }
83
84 #ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
85 /**
86 * softleaf_from_pmd() - Obtain a leaf entry from a PMD entry.
87 * @pmd: PMD entry.
88 *
89 * If @pmd is present (therefore not a leaf entry) the function returns an empty
90 * leaf entry. Otherwise, it returns a leaf entry.
91 *
92 * Returns: Leaf entry.
93 */
softleaf_from_pmd(pmd_t pmd)94 static inline softleaf_t softleaf_from_pmd(pmd_t pmd)
95 {
96 softleaf_t arch_entry;
97
98 if (pmd_present(pmd) || pmd_none(pmd))
99 return softleaf_mk_none();
100
101 if (pmd_swp_soft_dirty(pmd))
102 pmd = pmd_swp_clear_soft_dirty(pmd);
103 if (pmd_swp_uffd_wp(pmd))
104 pmd = pmd_swp_clear_uffd_wp(pmd);
105 arch_entry = __pmd_to_swp_entry(pmd);
106
107 /* Temporary until swp_entry_t eliminated. */
108 return swp_entry(__swp_type(arch_entry), __swp_offset(arch_entry));
109 }
110
111 #else
112
softleaf_from_pmd(pmd_t pmd)113 static inline softleaf_t softleaf_from_pmd(pmd_t pmd)
114 {
115 return softleaf_mk_none();
116 }
117
118 #endif
119
120 /**
121 * softleaf_is_none() - Is the leaf entry empty?
122 * @entry: Leaf entry.
123 *
124 * Empty entries are typically the result of a 'none' page table leaf entry
125 * being converted to a leaf entry.
126 *
127 * Returns: true if the entry is empty, false otherwise.
128 */
softleaf_is_none(softleaf_t entry)129 static inline bool softleaf_is_none(softleaf_t entry)
130 {
131 return entry.val == 0;
132 }
133
134 /**
135 * softleaf_type() - Identify the type of leaf entry.
136 * @entry: Leaf entry.
137 *
138 * Returns: the leaf entry type associated with @entry.
139 */
softleaf_type(softleaf_t entry)140 static inline enum softleaf_type softleaf_type(softleaf_t entry)
141 {
142 unsigned int type_num;
143
144 if (softleaf_is_none(entry))
145 return SOFTLEAF_NONE;
146
147 type_num = entry.val >> LEAF_TYPE_SHIFT;
148
149 if (type_num < MAX_SWAPFILES)
150 return SOFTLEAF_SWAP;
151
152 switch (type_num) {
153 #ifdef CONFIG_MIGRATION
154 case SWP_MIGRATION_READ:
155 return SOFTLEAF_MIGRATION_READ;
156 case SWP_MIGRATION_READ_EXCLUSIVE:
157 return SOFTLEAF_MIGRATION_READ_EXCLUSIVE;
158 case SWP_MIGRATION_WRITE:
159 return SOFTLEAF_MIGRATION_WRITE;
160 #endif
161 #ifdef CONFIG_DEVICE_PRIVATE
162 case SWP_DEVICE_WRITE:
163 return SOFTLEAF_DEVICE_PRIVATE_WRITE;
164 case SWP_DEVICE_READ:
165 return SOFTLEAF_DEVICE_PRIVATE_READ;
166 case SWP_DEVICE_EXCLUSIVE:
167 return SOFTLEAF_DEVICE_EXCLUSIVE;
168 #endif
169 #ifdef CONFIG_MEMORY_FAILURE
170 case SWP_HWPOISON:
171 return SOFTLEAF_HWPOISON;
172 #endif
173 case SWP_PTE_MARKER:
174 return SOFTLEAF_MARKER;
175 }
176
177 /* Unknown entry type. */
178 VM_WARN_ON_ONCE(1);
179 return SOFTLEAF_NONE;
180 }
181
182 /**
183 * softleaf_is_swap() - Is this leaf entry a swap entry?
184 * @entry: Leaf entry.
185 *
186 * Returns: true if the leaf entry is a swap entry, otherwise false.
187 */
softleaf_is_swap(softleaf_t entry)188 static inline bool softleaf_is_swap(softleaf_t entry)
189 {
190 return softleaf_type(entry) == SOFTLEAF_SWAP;
191 }
192
193 /**
194 * softleaf_is_migration_write() - Is this leaf entry a writable migration entry?
195 * @entry: Leaf entry.
196 *
197 * Returns: true if the leaf entry is a writable migration entry, otherwise
198 * false.
199 */
softleaf_is_migration_write(softleaf_t entry)200 static inline bool softleaf_is_migration_write(softleaf_t entry)
201 {
202 return softleaf_type(entry) == SOFTLEAF_MIGRATION_WRITE;
203 }
204
205 /**
206 * softleaf_is_migration_read() - Is this leaf entry a readable migration entry?
207 * @entry: Leaf entry.
208 *
209 * Returns: true if the leaf entry is a readable migration entry, otherwise
210 * false.
211 */
softleaf_is_migration_read(softleaf_t entry)212 static inline bool softleaf_is_migration_read(softleaf_t entry)
213 {
214 return softleaf_type(entry) == SOFTLEAF_MIGRATION_READ;
215 }
216
217 /**
218 * softleaf_is_migration_read_exclusive() - Is this leaf entry an exclusive
219 * readable migration entry?
220 * @entry: Leaf entry.
221 *
222 * Returns: true if the leaf entry is an exclusive readable migration entry,
223 * otherwise false.
224 */
softleaf_is_migration_read_exclusive(softleaf_t entry)225 static inline bool softleaf_is_migration_read_exclusive(softleaf_t entry)
226 {
227 return softleaf_type(entry) == SOFTLEAF_MIGRATION_READ_EXCLUSIVE;
228 }
229
230 /**
231 * softleaf_is_migration() - Is this leaf entry a migration entry?
232 * @entry: Leaf entry.
233 *
234 * Returns: true if the leaf entry is a migration entry, otherwise false.
235 */
softleaf_is_migration(softleaf_t entry)236 static inline bool softleaf_is_migration(softleaf_t entry)
237 {
238 switch (softleaf_type(entry)) {
239 case SOFTLEAF_MIGRATION_READ:
240 case SOFTLEAF_MIGRATION_READ_EXCLUSIVE:
241 case SOFTLEAF_MIGRATION_WRITE:
242 return true;
243 default:
244 return false;
245 }
246 }
247
248 /**
249 * softleaf_is_device_private_write() - Is this leaf entry a device private
250 * writable entry?
251 * @entry: Leaf entry.
252 *
253 * Returns: true if the leaf entry is a device private writable entry, otherwise
254 * false.
255 */
softleaf_is_device_private_write(softleaf_t entry)256 static inline bool softleaf_is_device_private_write(softleaf_t entry)
257 {
258 return softleaf_type(entry) == SOFTLEAF_DEVICE_PRIVATE_WRITE;
259 }
260
261 /**
262 * softleaf_is_device_private() - Is this leaf entry a device private entry?
263 * @entry: Leaf entry.
264 *
265 * Returns: true if the leaf entry is a device private entry, otherwise false.
266 */
softleaf_is_device_private(softleaf_t entry)267 static inline bool softleaf_is_device_private(softleaf_t entry)
268 {
269 switch (softleaf_type(entry)) {
270 case SOFTLEAF_DEVICE_PRIVATE_WRITE:
271 case SOFTLEAF_DEVICE_PRIVATE_READ:
272 return true;
273 default:
274 return false;
275 }
276 }
277
278 /**
279 * softleaf_is_device_exclusive() - Is this leaf entry a device-exclusive entry?
280 * @entry: Leaf entry.
281 *
282 * Returns: true if the leaf entry is a device-exclusive entry, otherwise false.
283 */
softleaf_is_device_exclusive(softleaf_t entry)284 static inline bool softleaf_is_device_exclusive(softleaf_t entry)
285 {
286 return softleaf_type(entry) == SOFTLEAF_DEVICE_EXCLUSIVE;
287 }
288
289 /**
290 * softleaf_is_hwpoison() - Is this leaf entry a hardware poison entry?
291 * @entry: Leaf entry.
292 *
293 * Returns: true if the leaf entry is a hardware poison entry, otherwise false.
294 */
softleaf_is_hwpoison(softleaf_t entry)295 static inline bool softleaf_is_hwpoison(softleaf_t entry)
296 {
297 return softleaf_type(entry) == SOFTLEAF_HWPOISON;
298 }
299
300 /**
301 * softleaf_is_marker() - Is this leaf entry a marker?
302 * @entry: Leaf entry.
303 *
304 * Returns: true if the leaf entry is a marker entry, otherwise false.
305 */
softleaf_is_marker(softleaf_t entry)306 static inline bool softleaf_is_marker(softleaf_t entry)
307 {
308 return softleaf_type(entry) == SOFTLEAF_MARKER;
309 }
310
311 /**
312 * softleaf_to_marker() - Obtain marker associated with leaf entry.
313 * @entry: Leaf entry, softleaf_is_marker(@entry) must return true.
314 *
315 * Returns: Marker associated with the leaf entry.
316 */
softleaf_to_marker(softleaf_t entry)317 static inline pte_marker softleaf_to_marker(softleaf_t entry)
318 {
319 VM_WARN_ON_ONCE(!softleaf_is_marker(entry));
320
321 return swp_offset(entry) & PTE_MARKER_MASK;
322 }
323
324 /**
325 * softleaf_has_pfn() - Does this leaf entry encode a valid PFN number?
326 * @entry: Leaf entry.
327 *
328 * A pfn swap entry is a special type of swap entry that always has a pfn stored
329 * in the swap offset. They can either be used to represent unaddressable device
330 * memory, to restrict access to a page undergoing migration or to represent a
331 * pfn which has been hwpoisoned and unmapped.
332 *
333 * Returns: true if the leaf entry encodes a PFN, otherwise false.
334 */
softleaf_has_pfn(softleaf_t entry)335 static inline bool softleaf_has_pfn(softleaf_t entry)
336 {
337 /* Make sure the swp offset can always store the needed fields. */
338 BUILD_BUG_ON(SWP_TYPE_SHIFT < SWP_PFN_BITS);
339
340 if (softleaf_is_migration(entry))
341 return true;
342 if (softleaf_is_device_private(entry))
343 return true;
344 if (softleaf_is_device_exclusive(entry))
345 return true;
346 if (softleaf_is_hwpoison(entry))
347 return true;
348
349 return false;
350 }
351
352 /**
353 * softleaf_to_pfn() - Obtain PFN encoded within leaf entry.
354 * @entry: Leaf entry, softleaf_has_pfn(@entry) must return true.
355 *
356 * Returns: The PFN associated with the leaf entry.
357 */
softleaf_to_pfn(softleaf_t entry)358 static inline unsigned long softleaf_to_pfn(softleaf_t entry)
359 {
360 VM_WARN_ON_ONCE(!softleaf_has_pfn(entry));
361
362 /* Temporary until swp_entry_t eliminated. */
363 return swp_offset(entry) & SWP_PFN_MASK;
364 }
365
softleaf_migration_sync(softleaf_t entry,struct folio * folio)366 static inline void softleaf_migration_sync(softleaf_t entry,
367 struct folio *folio)
368 {
369 /*
370 * Ensure we do not race with split, which might alter tail pages into new
371 * folios and thus result in observing an unlocked folio.
372 * This matches the write barrier in __split_folio_to_order().
373 */
374 smp_rmb();
375
376 /*
377 * Any use of migration entries may only occur while the
378 * corresponding page is locked
379 */
380 VM_WARN_ON_ONCE(!folio_test_locked(folio));
381 }
382
383 /**
384 * softleaf_to_page() - Obtains struct page for PFN encoded within leaf entry.
385 * @entry: Leaf entry, softleaf_has_pfn(@entry) must return true.
386 *
387 * Returns: Pointer to the struct page associated with the leaf entry's PFN.
388 */
softleaf_to_page(softleaf_t entry)389 static inline struct page *softleaf_to_page(softleaf_t entry)
390 {
391 struct page *page = pfn_to_page(softleaf_to_pfn(entry));
392
393 VM_WARN_ON_ONCE(!softleaf_has_pfn(entry));
394 if (softleaf_is_migration(entry))
395 softleaf_migration_sync(entry, page_folio(page));
396
397 return page;
398 }
399
400 /**
401 * softleaf_to_folio() - Obtains struct folio for PFN encoded within leaf entry.
402 * @entry: Leaf entry, softleaf_has_pfn(@entry) must return true.
403 *
404 * Returns: Pointer to the struct folio associated with the leaf entry's PFN.
405 */
softleaf_to_folio(softleaf_t entry)406 static inline struct folio *softleaf_to_folio(softleaf_t entry)
407 {
408 struct folio *folio = pfn_folio(softleaf_to_pfn(entry));
409
410 VM_WARN_ON_ONCE(!softleaf_has_pfn(entry));
411 if (softleaf_is_migration(entry))
412 softleaf_migration_sync(entry, folio);
413
414 return folio;
415 }
416
417 /**
418 * softleaf_is_poison_marker() - Is this leaf entry a poison marker?
419 * @entry: Leaf entry.
420 *
421 * The poison marker is set via UFFDIO_POISON. Userfaultfd-specific.
422 *
423 * Returns: true if the leaf entry is a poison marker, otherwise false.
424 */
softleaf_is_poison_marker(softleaf_t entry)425 static inline bool softleaf_is_poison_marker(softleaf_t entry)
426 {
427 if (!softleaf_is_marker(entry))
428 return false;
429
430 return softleaf_to_marker(entry) & PTE_MARKER_POISONED;
431 }
432
433 /**
434 * softleaf_is_guard_marker() - Is this leaf entry a guard region marker?
435 * @entry: Leaf entry.
436 *
437 * Returns: true if the leaf entry is a guard marker, otherwise false.
438 */
softleaf_is_guard_marker(softleaf_t entry)439 static inline bool softleaf_is_guard_marker(softleaf_t entry)
440 {
441 if (!softleaf_is_marker(entry))
442 return false;
443
444 return softleaf_to_marker(entry) & PTE_MARKER_GUARD;
445 }
446
447 /**
448 * softleaf_is_uffd_wp_marker() - Is this leaf entry a userfautlfd write protect
449 * marker?
450 * @entry: Leaf entry.
451 *
452 * Userfaultfd-specific.
453 *
454 * Returns: true if the leaf entry is a UFFD WP marker, otherwise false.
455 */
softleaf_is_uffd_wp_marker(softleaf_t entry)456 static inline bool softleaf_is_uffd_wp_marker(softleaf_t entry)
457 {
458 if (!softleaf_is_marker(entry))
459 return false;
460
461 return softleaf_to_marker(entry) & PTE_MARKER_UFFD_WP;
462 }
463
464 #ifdef CONFIG_MIGRATION
465
466 /**
467 * softleaf_is_migration_young() - Does this migration entry contain an accessed
468 * bit?
469 * @entry: Leaf entry.
470 *
471 * If the architecture can support storing A/D bits in migration entries, this
472 * determines whether the accessed (or 'young') bit was set on the migrated page
473 * table entry.
474 *
475 * Returns: true if the entry contains an accessed bit, otherwise false.
476 */
softleaf_is_migration_young(softleaf_t entry)477 static inline bool softleaf_is_migration_young(softleaf_t entry)
478 {
479 VM_WARN_ON_ONCE(!softleaf_is_migration(entry));
480
481 if (migration_entry_supports_ad())
482 return swp_offset(entry) & SWP_MIG_YOUNG;
483 /* Keep the old behavior of aging page after migration */
484 return false;
485 }
486
487 /**
488 * softleaf_is_migration_dirty() - Does this migration entry contain a dirty bit?
489 * @entry: Leaf entry.
490 *
491 * If the architecture can support storing A/D bits in migration entries, this
492 * determines whether the dirty bit was set on the migrated page table entry.
493 *
494 * Returns: true if the entry contains a dirty bit, otherwise false.
495 */
softleaf_is_migration_dirty(softleaf_t entry)496 static inline bool softleaf_is_migration_dirty(softleaf_t entry)
497 {
498 VM_WARN_ON_ONCE(!softleaf_is_migration(entry));
499
500 if (migration_entry_supports_ad())
501 return swp_offset(entry) & SWP_MIG_DIRTY;
502 /* Keep the old behavior of clean page after migration */
503 return false;
504 }
505
506 #else /* CONFIG_MIGRATION */
507
softleaf_is_migration_young(softleaf_t entry)508 static inline bool softleaf_is_migration_young(softleaf_t entry)
509 {
510 return false;
511 }
512
softleaf_is_migration_dirty(softleaf_t entry)513 static inline bool softleaf_is_migration_dirty(softleaf_t entry)
514 {
515 return false;
516 }
517 #endif /* CONFIG_MIGRATION */
518
519 /**
520 * pte_is_marker() - Does the PTE entry encode a marker leaf entry?
521 * @pte: PTE entry.
522 *
523 * Returns: true if this PTE is a marker leaf entry, otherwise false.
524 */
pte_is_marker(pte_t pte)525 static inline bool pte_is_marker(pte_t pte)
526 {
527 return softleaf_is_marker(softleaf_from_pte(pte));
528 }
529
530 /**
531 * pte_is_uffd_wp_marker() - Does this PTE entry encode a userfaultfd write
532 * protect marker leaf entry?
533 * @pte: PTE entry.
534 *
535 * Returns: true if this PTE is a UFFD WP marker leaf entry, otherwise false.
536 */
pte_is_uffd_wp_marker(pte_t pte)537 static inline bool pte_is_uffd_wp_marker(pte_t pte)
538 {
539 const softleaf_t entry = softleaf_from_pte(pte);
540
541 return softleaf_is_uffd_wp_marker(entry);
542 }
543
544 /**
545 * pte_is_uffd_marker() - Does this PTE entry encode a userfault-specific marker
546 * leaf entry?
547 * @pte: PTE entry.
548 *
549 * It's useful to be able to determine which leaf entries encode UFFD-specific
550 * markers so we can handle these correctly.
551 *
552 * Returns: true if this PTE entry is a UFFD-specific marker, otherwise false.
553 */
pte_is_uffd_marker(pte_t pte)554 static inline bool pte_is_uffd_marker(pte_t pte)
555 {
556 const softleaf_t entry = softleaf_from_pte(pte);
557
558 if (!softleaf_is_marker(entry))
559 return false;
560
561 /* UFFD WP, poisoned swap entries are UFFD-handled. */
562 if (softleaf_is_uffd_wp_marker(entry))
563 return true;
564 if (softleaf_is_poison_marker(entry))
565 return true;
566
567 return false;
568 }
569
570 #if defined(CONFIG_ZONE_DEVICE) && defined(CONFIG_ARCH_ENABLE_THP_MIGRATION)
571
572 /**
573 * pmd_is_device_private_entry() - Check if PMD contains a device private swap
574 * entry.
575 * @pmd: The PMD to check.
576 *
577 * Returns true if the PMD contains a swap entry that represents a device private
578 * page mapping. This is used for zone device private pages that have been
579 * swapped out but still need special handling during various memory management
580 * operations.
581 *
582 * Return: true if PMD contains device private entry, false otherwise
583 */
pmd_is_device_private_entry(pmd_t pmd)584 static inline bool pmd_is_device_private_entry(pmd_t pmd)
585 {
586 return softleaf_is_device_private(softleaf_from_pmd(pmd));
587 }
588
589 #else /* CONFIG_ZONE_DEVICE && CONFIG_ARCH_ENABLE_THP_MIGRATION */
590
pmd_is_device_private_entry(pmd_t pmd)591 static inline bool pmd_is_device_private_entry(pmd_t pmd)
592 {
593 return false;
594 }
595
596 #endif /* CONFIG_ZONE_DEVICE && CONFIG_ARCH_ENABLE_THP_MIGRATION */
597
598 /**
599 * pmd_is_migration_entry() - Does this PMD entry encode a migration entry?
600 * @pmd: PMD entry.
601 *
602 * Returns: true if the PMD encodes a migration entry, otherwise false.
603 */
pmd_is_migration_entry(pmd_t pmd)604 static inline bool pmd_is_migration_entry(pmd_t pmd)
605 {
606 return softleaf_is_migration(softleaf_from_pmd(pmd));
607 }
608
609 /**
610 * pmd_is_valid_softleaf() - Is this PMD entry a valid leaf entry?
611 * @pmd: PMD entry.
612 *
613 * PMD leaf entries are valid only if they are device private or migration
614 * entries. This function asserts that a PMD leaf entry is valid in this
615 * respect.
616 *
617 * Returns: true if the PMD entry is a valid leaf entry, otherwise false.
618 */
pmd_is_valid_softleaf(pmd_t pmd)619 static inline bool pmd_is_valid_softleaf(pmd_t pmd)
620 {
621 const softleaf_t entry = softleaf_from_pmd(pmd);
622
623 /* Only device private, migration entries valid for PMD. */
624 return softleaf_is_device_private(entry) ||
625 softleaf_is_migration(entry);
626 }
627
628 #endif /* CONFIG_MMU */
629 #endif /* _LINUX_LEAFOPS_H */
630