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