xref: /linux/include/linux/leafops.h (revision ed3b875bea55a3ec4837113356df2ead11115af9)
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  */
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  */
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  */
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_HAS_PMD_SOFTLEAVES
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  */
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(pmd))
104 		pmd = pmd_swp_clear_uffd(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 /**
112  * softleaf_to_pmd() - Obtain a PMD entry from a leaf entry.
113  * @entry: Leaf entry.
114  *
115  * This generates an architecture-specific PMD entry that can be utilised to
116  * encode the metadata the leaf entry encodes.
117  *
118  * Returns: Architecture-specific PMD entry encoding leaf entry.
119  */
120 static inline pmd_t softleaf_to_pmd(softleaf_t entry)
121 {
122 	/* Temporary until swp_entry_t eliminated. */
123 	return swp_entry_to_pmd(entry);
124 }
125 
126 #else
127 
128 static inline softleaf_t softleaf_from_pmd(pmd_t pmd)
129 {
130 	return softleaf_mk_none();
131 }
132 
133 static inline pmd_t softleaf_to_pmd(softleaf_t entry)
134 {
135 	return __pmd(0);
136 }
137 
138 #endif
139 
140 /**
141  * softleaf_is_none() - Is the leaf entry empty?
142  * @entry: Leaf entry.
143  *
144  * Empty entries are typically the result of a 'none' page table leaf entry
145  * being converted to a leaf entry.
146  *
147  * Returns: true if the entry is empty, false otherwise.
148  */
149 static inline bool softleaf_is_none(softleaf_t entry)
150 {
151 	return entry.val == 0;
152 }
153 
154 /**
155  * softleaf_type() - Identify the type of leaf entry.
156  * @entry: Leaf entry.
157  *
158  * Returns: the leaf entry type associated with @entry.
159  */
160 static inline enum softleaf_type softleaf_type(softleaf_t entry)
161 {
162 	unsigned int type_num;
163 
164 	if (softleaf_is_none(entry))
165 		return SOFTLEAF_NONE;
166 
167 	type_num = entry.val >> LEAF_TYPE_SHIFT;
168 
169 	if (type_num < MAX_SWAPFILES)
170 		return SOFTLEAF_SWAP;
171 
172 	switch (type_num) {
173 #ifdef CONFIG_MIGRATION
174 	case SWP_MIGRATION_READ:
175 		return SOFTLEAF_MIGRATION_READ;
176 	case SWP_MIGRATION_READ_EXCLUSIVE:
177 		return SOFTLEAF_MIGRATION_READ_EXCLUSIVE;
178 	case SWP_MIGRATION_WRITE:
179 		return SOFTLEAF_MIGRATION_WRITE;
180 #endif
181 #ifdef CONFIG_DEVICE_PRIVATE
182 	case SWP_DEVICE_WRITE:
183 		return SOFTLEAF_DEVICE_PRIVATE_WRITE;
184 	case SWP_DEVICE_READ:
185 		return SOFTLEAF_DEVICE_PRIVATE_READ;
186 	case SWP_DEVICE_EXCLUSIVE:
187 		return SOFTLEAF_DEVICE_EXCLUSIVE;
188 #endif
189 #ifdef CONFIG_MEMORY_FAILURE
190 	case SWP_HWPOISON:
191 		return SOFTLEAF_HWPOISON;
192 #endif
193 	case SWP_PTE_MARKER:
194 		return SOFTLEAF_MARKER;
195 	}
196 
197 	/* Unknown entry type. */
198 	VM_WARN_ON_ONCE(1);
199 	return SOFTLEAF_NONE;
200 }
201 
202 /**
203  * softleaf_is_swap() - Is this leaf entry a swap entry?
204  * @entry: Leaf entry.
205  *
206  * Returns: true if the leaf entry is a swap entry, otherwise false.
207  */
208 static inline bool softleaf_is_swap(softleaf_t entry)
209 {
210 	return softleaf_type(entry) == SOFTLEAF_SWAP;
211 }
212 
213 /**
214  * softleaf_is_migration_write() - Is this leaf entry a writable migration entry?
215  * @entry: Leaf entry.
216  *
217  * Returns: true if the leaf entry is a writable migration entry, otherwise
218  * false.
219  */
220 static inline bool softleaf_is_migration_write(softleaf_t entry)
221 {
222 	return softleaf_type(entry) == SOFTLEAF_MIGRATION_WRITE;
223 }
224 
225 /**
226  * softleaf_is_migration_read() - Is this leaf entry a readable migration entry?
227  * @entry: Leaf entry.
228  *
229  * Returns: true if the leaf entry is a readable migration entry, otherwise
230  * false.
231  */
232 static inline bool softleaf_is_migration_read(softleaf_t entry)
233 {
234 	return softleaf_type(entry) == SOFTLEAF_MIGRATION_READ;
235 }
236 
237 /**
238  * softleaf_is_migration_read_exclusive() - Is this leaf entry an exclusive
239  * readable migration entry?
240  * @entry: Leaf entry.
241  *
242  * Returns: true if the leaf entry is an exclusive readable migration entry,
243  * otherwise false.
244  */
245 static inline bool softleaf_is_migration_read_exclusive(softleaf_t entry)
246 {
247 	return softleaf_type(entry) == SOFTLEAF_MIGRATION_READ_EXCLUSIVE;
248 }
249 
250 /**
251  * softleaf_is_migration() - Is this leaf entry a migration entry?
252  * @entry: Leaf entry.
253  *
254  * Returns: true if the leaf entry is a migration entry, otherwise false.
255  */
256 static inline bool softleaf_is_migration(softleaf_t entry)
257 {
258 	switch (softleaf_type(entry)) {
259 	case SOFTLEAF_MIGRATION_READ:
260 	case SOFTLEAF_MIGRATION_READ_EXCLUSIVE:
261 	case SOFTLEAF_MIGRATION_WRITE:
262 		return true;
263 	default:
264 		return false;
265 	}
266 }
267 
268 /**
269  * softleaf_is_device_private_write() - Is this leaf entry a device private
270  * writable entry?
271  * @entry: Leaf entry.
272  *
273  * Returns: true if the leaf entry is a device private writable entry, otherwise
274  * false.
275  */
276 static inline bool softleaf_is_device_private_write(softleaf_t entry)
277 {
278 	return softleaf_type(entry) == SOFTLEAF_DEVICE_PRIVATE_WRITE;
279 }
280 
281 /**
282  * softleaf_is_device_private() - Is this leaf entry a device private entry?
283  * @entry: Leaf entry.
284  *
285  * Returns: true if the leaf entry is a device private entry, otherwise false.
286  */
287 static inline bool softleaf_is_device_private(softleaf_t entry)
288 {
289 	switch (softleaf_type(entry)) {
290 	case SOFTLEAF_DEVICE_PRIVATE_WRITE:
291 	case SOFTLEAF_DEVICE_PRIVATE_READ:
292 		return true;
293 	default:
294 		return false;
295 	}
296 }
297 
298 /**
299  * softleaf_is_device_exclusive() - Is this leaf entry a device-exclusive entry?
300  * @entry: Leaf entry.
301  *
302  * Returns: true if the leaf entry is a device-exclusive entry, otherwise false.
303  */
304 static inline bool softleaf_is_device_exclusive(softleaf_t entry)
305 {
306 	return softleaf_type(entry) == SOFTLEAF_DEVICE_EXCLUSIVE;
307 }
308 
309 /**
310  * softleaf_is_hwpoison() - Is this leaf entry a hardware poison entry?
311  * @entry: Leaf entry.
312  *
313  * Returns: true if the leaf entry is a hardware poison entry, otherwise false.
314  */
315 static inline bool softleaf_is_hwpoison(softleaf_t entry)
316 {
317 	return softleaf_type(entry) == SOFTLEAF_HWPOISON;
318 }
319 
320 /**
321  * softleaf_is_marker() - Is this leaf entry a marker?
322  * @entry: Leaf entry.
323  *
324  * Returns: true if the leaf entry is a marker entry, otherwise false.
325  */
326 static inline bool softleaf_is_marker(softleaf_t entry)
327 {
328 	return softleaf_type(entry) == SOFTLEAF_MARKER;
329 }
330 
331 /**
332  * softleaf_to_marker() - Obtain marker associated with leaf entry.
333  * @entry: Leaf entry, softleaf_is_marker(@entry) must return true.
334  *
335  * Returns: Marker associated with the leaf entry.
336  */
337 static inline pte_marker softleaf_to_marker(softleaf_t entry)
338 {
339 	VM_WARN_ON_ONCE(!softleaf_is_marker(entry));
340 
341 	return swp_offset(entry) & PTE_MARKER_MASK;
342 }
343 
344 /**
345  * softleaf_has_pfn() - Does this leaf entry encode a valid PFN number?
346  * @entry: Leaf entry.
347  *
348  * A pfn swap entry is a special type of swap entry that always has a pfn stored
349  * in the swap offset. They can either be used to represent unaddressable device
350  * memory, to restrict access to a page undergoing migration or to represent a
351  * pfn which has been hwpoisoned and unmapped.
352  *
353  * Returns: true if the leaf entry encodes a PFN, otherwise false.
354  */
355 static inline bool softleaf_has_pfn(softleaf_t entry)
356 {
357 	/* Make sure the swp offset can always store the needed fields. */
358 	BUILD_BUG_ON(SWP_TYPE_SHIFT < SWP_PFN_BITS);
359 
360 	if (softleaf_is_migration(entry))
361 		return true;
362 	if (softleaf_is_device_private(entry))
363 		return true;
364 	if (softleaf_is_device_exclusive(entry))
365 		return true;
366 	if (softleaf_is_hwpoison(entry))
367 		return true;
368 
369 	return false;
370 }
371 
372 /**
373  * softleaf_to_pfn() - Obtain PFN encoded within leaf entry.
374  * @entry: Leaf entry, softleaf_has_pfn(@entry) must return true.
375  *
376  * Returns: The PFN associated with the leaf entry.
377  */
378 static inline unsigned long softleaf_to_pfn(softleaf_t entry)
379 {
380 	VM_WARN_ON_ONCE(!softleaf_has_pfn(entry));
381 
382 	/* Temporary until swp_entry_t eliminated. */
383 	return swp_offset(entry) & SWP_PFN_MASK;
384 }
385 
386 static inline void softleaf_migration_sync(softleaf_t entry,
387 		struct folio *folio)
388 {
389 	/*
390 	 * Ensure we do not race with split, which might alter tail pages into new
391 	 * folios and thus result in observing an unlocked folio.
392 	 * This matches the write barrier in __split_folio_to_order().
393 	 */
394 	smp_rmb();
395 
396 	/*
397 	 * Any use of migration entries may only occur while the
398 	 * corresponding page is locked
399 	 */
400 	VM_WARN_ON_ONCE(!folio_test_locked(folio));
401 }
402 
403 /**
404  * softleaf_to_page() - Obtains struct page for PFN encoded within leaf entry.
405  * @entry: Leaf entry, softleaf_has_pfn(@entry) must return true.
406  *
407  * Returns: Pointer to the struct page associated with the leaf entry's PFN.
408  */
409 static inline struct page *softleaf_to_page(softleaf_t entry)
410 {
411 	struct page *page = pfn_to_page(softleaf_to_pfn(entry));
412 
413 	VM_WARN_ON_ONCE(!softleaf_has_pfn(entry));
414 	if (softleaf_is_migration(entry))
415 		softleaf_migration_sync(entry, page_folio(page));
416 
417 	return page;
418 }
419 
420 /**
421  * softleaf_to_folio() - Obtains struct folio for PFN encoded within leaf entry.
422  * @entry: Leaf entry, softleaf_has_pfn(@entry) must return true.
423  *
424  * Returns: Pointer to the struct folio associated with the leaf entry's PFN.
425  */
426 static inline struct folio *softleaf_to_folio(softleaf_t entry)
427 {
428 	struct folio *folio = pfn_folio(softleaf_to_pfn(entry));
429 
430 	VM_WARN_ON_ONCE(!softleaf_has_pfn(entry));
431 	if (softleaf_is_migration(entry))
432 		softleaf_migration_sync(entry, folio);
433 
434 	return folio;
435 }
436 
437 /**
438  * softleaf_is_poison_marker() - Is this leaf entry a poison marker?
439  * @entry: Leaf entry.
440  *
441  * The poison marker is set via UFFDIO_POISON. Userfaultfd-specific.
442  *
443  * Returns: true if the leaf entry is a poison marker, otherwise false.
444  */
445 static inline bool softleaf_is_poison_marker(softleaf_t entry)
446 {
447 	if (!softleaf_is_marker(entry))
448 		return false;
449 
450 	return softleaf_to_marker(entry) & PTE_MARKER_POISONED;
451 }
452 
453 /**
454  * softleaf_is_guard_marker() - Is this leaf entry a guard region marker?
455  * @entry: Leaf entry.
456  *
457  * Returns: true if the leaf entry is a guard marker, otherwise false.
458  */
459 static inline bool softleaf_is_guard_marker(softleaf_t entry)
460 {
461 	if (!softleaf_is_marker(entry))
462 		return false;
463 
464 	return softleaf_to_marker(entry) & PTE_MARKER_GUARD;
465 }
466 
467 /**
468  * softleaf_is_uffd_wp_marker() - Is this leaf entry a userfautlfd write protect
469  * marker?
470  * @entry: Leaf entry.
471  *
472  * Userfaultfd-specific.
473  *
474  * Returns: true if the leaf entry is a UFFD WP marker, otherwise false.
475  */
476 static inline bool softleaf_is_uffd_wp_marker(softleaf_t entry)
477 {
478 	if (!softleaf_is_marker(entry))
479 		return false;
480 
481 	return softleaf_to_marker(entry) & PTE_MARKER_UFFD_WP;
482 }
483 
484 #ifdef CONFIG_MIGRATION
485 
486 /**
487  * softleaf_is_migration_young() - Does this migration entry contain an accessed
488  * bit?
489  * @entry: Leaf entry.
490  *
491  * If the architecture can support storing A/D bits in migration entries, this
492  * determines whether the accessed (or 'young') bit was set on the migrated page
493  * table entry.
494  *
495  * Returns: true if the entry contains an accessed bit, otherwise false.
496  */
497 static inline bool softleaf_is_migration_young(softleaf_t entry)
498 {
499 	VM_WARN_ON_ONCE(!softleaf_is_migration(entry));
500 
501 	if (migration_entry_supports_ad())
502 		return swp_offset(entry) & SWP_MIG_YOUNG;
503 	/* Keep the old behavior of aging page after migration */
504 	return false;
505 }
506 
507 /**
508  * softleaf_is_migration_dirty() - Does this migration entry contain a dirty bit?
509  * @entry: Leaf entry.
510  *
511  * If the architecture can support storing A/D bits in migration entries, this
512  * determines whether the dirty bit was set on the migrated page table entry.
513  *
514  * Returns: true if the entry contains a dirty bit, otherwise false.
515  */
516 static inline bool softleaf_is_migration_dirty(softleaf_t entry)
517 {
518 	VM_WARN_ON_ONCE(!softleaf_is_migration(entry));
519 
520 	if (migration_entry_supports_ad())
521 		return swp_offset(entry) & SWP_MIG_DIRTY;
522 	/* Keep the old behavior of clean page after migration */
523 	return false;
524 }
525 
526 #else /* CONFIG_MIGRATION */
527 
528 static inline bool softleaf_is_migration_young(softleaf_t entry)
529 {
530 	return false;
531 }
532 
533 static inline bool softleaf_is_migration_dirty(softleaf_t entry)
534 {
535 	return false;
536 }
537 #endif /* CONFIG_MIGRATION */
538 
539 /**
540  * pte_is_marker() - Does the PTE entry encode a marker leaf entry?
541  * @pte: PTE entry.
542  *
543  * Returns: true if this PTE is a marker leaf entry, otherwise false.
544  */
545 static inline bool pte_is_marker(pte_t pte)
546 {
547 	return softleaf_is_marker(softleaf_from_pte(pte));
548 }
549 
550 /**
551  * pte_is_uffd_wp_marker() - Does this PTE entry encode a userfaultfd write
552  * protect marker leaf entry?
553  * @pte: PTE entry.
554  *
555  * Returns: true if this PTE is a UFFD WP marker leaf entry, otherwise false.
556  */
557 static inline bool pte_is_uffd_wp_marker(pte_t pte)
558 {
559 	const softleaf_t entry = softleaf_from_pte(pte);
560 
561 	return softleaf_is_uffd_wp_marker(entry);
562 }
563 
564 /**
565  * pte_is_uffd_marker() - Does this PTE entry encode a userfault-specific marker
566  * leaf entry?
567  * @pte: PTE entry.
568  *
569  * It's useful to be able to determine which leaf entries encode UFFD-specific
570  * markers so we can handle these correctly.
571  *
572  * Returns: true if this PTE entry is a UFFD-specific marker, otherwise false.
573  */
574 static inline bool pte_is_uffd_marker(pte_t pte)
575 {
576 	const softleaf_t entry = softleaf_from_pte(pte);
577 
578 	if (!softleaf_is_marker(entry))
579 		return false;
580 
581 	/* UFFD WP, poisoned swap entries are UFFD-handled. */
582 	if (softleaf_is_uffd_wp_marker(entry))
583 		return true;
584 	if (softleaf_is_poison_marker(entry))
585 		return true;
586 
587 	return false;
588 }
589 
590 #if defined(CONFIG_ZONE_DEVICE) && defined(CONFIG_ARCH_HAS_PMD_SOFTLEAVES)
591 
592 /**
593  * pmd_is_device_private_entry() - Check if PMD contains a device private swap
594  * entry.
595  * @pmd: The PMD to check.
596  *
597  * Returns true if the PMD contains a swap entry that represents a device private
598  * page mapping. This is used for zone device private pages that have been
599  * swapped out but still need special handling during various memory management
600  * operations.
601  *
602  * Return: true if PMD contains device private entry, false otherwise
603  */
604 static inline bool pmd_is_device_private_entry(pmd_t pmd)
605 {
606 	return softleaf_is_device_private(softleaf_from_pmd(pmd));
607 }
608 
609 #else  /* CONFIG_ZONE_DEVICE && CONFIG_ARCH_HAS_PMD_SOFTLEAVES */
610 
611 static inline bool pmd_is_device_private_entry(pmd_t pmd)
612 {
613 	return false;
614 }
615 
616 #endif /* CONFIG_ZONE_DEVICE && CONFIG_ARCH_HAS_PMD_SOFTLEAVES */
617 
618 /**
619  * pmd_is_migration_entry() - Does this PMD entry encode a migration entry?
620  * @pmd: PMD entry.
621  *
622  * Returns: true if the PMD encodes a migration entry, otherwise false.
623  */
624 static inline bool pmd_is_migration_entry(pmd_t pmd)
625 {
626 	return softleaf_is_migration(softleaf_from_pmd(pmd));
627 }
628 
629 /**
630  * softleaf_is_valid_pmd_entry() - Is the specified softleaf entry obtained from
631  * a PMD one that we support at PMD level?
632  * @entry: Entry to check.
633  * Returns: true if the softleaf entry is valid at PMD, otherwise false.
634  */
635 static inline bool softleaf_is_valid_pmd_entry(softleaf_t entry)
636 {
637 	/* Only device private, migration entries valid for PMD. */
638 	return softleaf_is_device_private(entry) ||
639 		softleaf_is_migration(entry);
640 }
641 
642 /**
643  * pmd_is_valid_softleaf() - Is this PMD entry a valid softleaf entry?
644  * @pmd: PMD entry.
645  *
646  * PMD leaf entries are valid only if they are device private or migration
647  * entries. This function asserts that a PMD leaf entry is valid in this
648  * respect.
649  *
650  * Returns: true if the PMD entry is a valid leaf entry, otherwise false.
651  */
652 static inline bool pmd_is_valid_softleaf(pmd_t pmd)
653 {
654 	const softleaf_t entry = softleaf_from_pmd(pmd);
655 
656 	return softleaf_is_valid_pmd_entry(entry);
657 }
658 
659 /**
660  * pmd_to_softleaf_folio() - Convert the PMD entry to a folio.
661  * @pmd: PMD entry.
662  *
663  * The PMD entry is expected to be a valid PMD softleaf entry.
664  *
665  * Returns: the folio the softleaf entry references if this is a valid softleaf
666  * entry, otherwise NULL.
667  */
668 static inline struct folio *pmd_to_softleaf_folio(pmd_t pmd)
669 {
670 	const softleaf_t entry = softleaf_from_pmd(pmd);
671 
672 	if (!softleaf_is_valid_pmd_entry(entry)) {
673 		VM_WARN_ON_ONCE(true);
674 		return NULL;
675 	}
676 	return softleaf_to_folio(entry);
677 }
678 
679 #endif  /* CONFIG_MMU */
680 #endif  /* _LINUX_LEAFOPS_H */
681