ident_map.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Helper routines for building identity mapping page tables. This is
  4. * included by both the compressed kernel and the regular kernel.
  5. */
  6. static void ident_pmd_init(struct x86_mapping_info *info, pmd_t *pmd_page,
  7. unsigned long addr, unsigned long end)
  8. {
  9. addr &= PMD_MASK;
  10. for (; addr < end; addr += PMD_SIZE) {
  11. pmd_t *pmd = pmd_page + pmd_index(addr);
  12. if (pmd_present(*pmd))
  13. continue;
  14. set_pmd(pmd, __pmd((addr - info->offset) | info->page_flag));
  15. }
  16. }
  17. static int ident_pud_init(struct x86_mapping_info *info, pud_t *pud_page,
  18. unsigned long addr, unsigned long end)
  19. {
  20. unsigned long next;
  21. for (; addr < end; addr = next) {
  22. pud_t *pud = pud_page + pud_index(addr);
  23. pmd_t *pmd;
  24. next = (addr & PUD_MASK) + PUD_SIZE;
  25. if (next > end)
  26. next = end;
  27. if (info->direct_gbpages) {
  28. pud_t pudval;
  29. if (pud_present(*pud))
  30. continue;
  31. addr &= PUD_MASK;
  32. pudval = __pud((addr - info->offset) | info->page_flag);
  33. set_pud(pud, pudval);
  34. continue;
  35. }
  36. if (pud_present(*pud)) {
  37. pmd = pmd_offset(pud, 0);
  38. ident_pmd_init(info, pmd, addr, next);
  39. continue;
  40. }
  41. pmd = (pmd_t *)info->alloc_pgt_page(info->context);
  42. if (!pmd)
  43. return -ENOMEM;
  44. ident_pmd_init(info, pmd, addr, next);
  45. set_pud(pud, __pud(__pa(pmd) | info->kernpg_flag));
  46. }
  47. return 0;
  48. }
  49. static int ident_p4d_init(struct x86_mapping_info *info, p4d_t *p4d_page,
  50. unsigned long addr, unsigned long end)
  51. {
  52. unsigned long next;
  53. int result;
  54. for (; addr < end; addr = next) {
  55. p4d_t *p4d = p4d_page + p4d_index(addr);
  56. pud_t *pud;
  57. next = (addr & P4D_MASK) + P4D_SIZE;
  58. if (next > end)
  59. next = end;
  60. if (p4d_present(*p4d)) {
  61. pud = pud_offset(p4d, 0);
  62. result = ident_pud_init(info, pud, addr, next);
  63. if (result)
  64. return result;
  65. continue;
  66. }
  67. pud = (pud_t *)info->alloc_pgt_page(info->context);
  68. if (!pud)
  69. return -ENOMEM;
  70. result = ident_pud_init(info, pud, addr, next);
  71. if (result)
  72. return result;
  73. set_p4d(p4d, __p4d(__pa(pud) | info->kernpg_flag));
  74. }
  75. return 0;
  76. }
  77. int kernel_ident_mapping_init(struct x86_mapping_info *info, pgd_t *pgd_page,
  78. unsigned long pstart, unsigned long pend)
  79. {
  80. unsigned long addr = pstart + info->offset;
  81. unsigned long end = pend + info->offset;
  82. unsigned long next;
  83. int result;
  84. /* Set the default pagetable flags if not supplied */
  85. if (!info->kernpg_flag)
  86. info->kernpg_flag = _KERNPG_TABLE;
  87. /* Filter out unsupported __PAGE_KERNEL_* bits: */
  88. info->kernpg_flag &= __default_kernel_pte_mask;
  89. for (; addr < end; addr = next) {
  90. pgd_t *pgd = pgd_page + pgd_index(addr);
  91. p4d_t *p4d;
  92. next = (addr & PGDIR_MASK) + PGDIR_SIZE;
  93. if (next > end)
  94. next = end;
  95. if (pgd_present(*pgd)) {
  96. p4d = p4d_offset(pgd, 0);
  97. result = ident_p4d_init(info, p4d, addr, next);
  98. if (result)
  99. return result;
  100. continue;
  101. }
  102. p4d = (p4d_t *)info->alloc_pgt_page(info->context);
  103. if (!p4d)
  104. return -ENOMEM;
  105. result = ident_p4d_init(info, p4d, addr, next);
  106. if (result)
  107. return result;
  108. if (pgtable_l5_enabled()) {
  109. set_pgd(pgd, __pgd(__pa(p4d) | info->kernpg_flag));
  110. } else {
  111. /*
  112. * With p4d folded, pgd is equal to p4d.
  113. * The pgd entry has to point to the pud page table in this case.
  114. */
  115. pud_t *pud = pud_offset(p4d, 0);
  116. set_pgd(pgd, __pgd(__pa(pud) | info->kernpg_flag));
  117. }
  118. }
  119. return 0;
  120. }