Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/acpi: Replace manual page table initialization with kernel_ident_mapping_init()

The init_transition_pgtable() functions maps the page with
asm_acpi_mp_play_dead() into an identity mapping.

Replace open-coded manual page table initialization with
kernel_ident_mapping_init() to avoid code duplication.

Use x86_mapping_info::offset to get the page mapped at the
correct location.

Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Kai Huang <kai.huang@intel.com>
Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Link: https://lore.kernel.org/r/20241016111458.846228-3-kirill.shutemov@linux.intel.com

authored by

Kirill A. Shutemov and committed by
Ingo Molnar
775d37d8 634ab761

+15 -58
+15 -58
arch/x86/kernel/acpi/madt_wakeup.c
··· 70 70 return memblock_free(pgt, PAGE_SIZE); 71 71 } 72 72 73 - /* 74 - * Make sure asm_acpi_mp_play_dead() is present in the identity mapping at 75 - * the same place as in the kernel page tables. asm_acpi_mp_play_dead() switches 76 - * to the identity mapping and the function has be present at the same spot in 77 - * the virtual address space before and after switching page tables. 78 - */ 79 - static int __init init_transition_pgtable(pgd_t *pgd) 80 - { 81 - pgprot_t prot = PAGE_KERNEL_EXEC_NOENC; 82 - unsigned long vaddr, paddr; 83 - p4d_t *p4d; 84 - pud_t *pud; 85 - pmd_t *pmd; 86 - pte_t *pte; 87 - 88 - vaddr = (unsigned long)asm_acpi_mp_play_dead; 89 - pgd += pgd_index(vaddr); 90 - if (!pgd_present(*pgd)) { 91 - p4d = (p4d_t *)alloc_pgt_page(NULL); 92 - if (!p4d) 93 - return -ENOMEM; 94 - set_pgd(pgd, __pgd(__pa(p4d) | _KERNPG_TABLE)); 95 - } 96 - p4d = p4d_offset(pgd, vaddr); 97 - if (!p4d_present(*p4d)) { 98 - pud = (pud_t *)alloc_pgt_page(NULL); 99 - if (!pud) 100 - return -ENOMEM; 101 - set_p4d(p4d, __p4d(__pa(pud) | _KERNPG_TABLE)); 102 - } 103 - pud = pud_offset(p4d, vaddr); 104 - if (!pud_present(*pud)) { 105 - pmd = (pmd_t *)alloc_pgt_page(NULL); 106 - if (!pmd) 107 - return -ENOMEM; 108 - set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE)); 109 - } 110 - pmd = pmd_offset(pud, vaddr); 111 - if (!pmd_present(*pmd)) { 112 - pte = (pte_t *)alloc_pgt_page(NULL); 113 - if (!pte) 114 - return -ENOMEM; 115 - set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE)); 116 - } 117 - pte = pte_offset_kernel(pmd, vaddr); 118 - 119 - paddr = __pa(vaddr); 120 - set_pte(pte, pfn_pte(paddr >> PAGE_SHIFT, prot)); 121 - 122 - return 0; 123 - } 124 - 125 73 static int __init acpi_mp_setup_reset(u64 reset_vector) 126 74 { 127 75 struct x86_mapping_info info = { ··· 78 130 .page_flag = __PAGE_KERNEL_LARGE_EXEC, 79 131 .kernpg_flag = _KERNPG_TABLE_NOENC, 80 132 }; 133 + unsigned long mstart, mend; 81 134 pgd_t *pgd; 82 135 83 136 pgd = alloc_pgt_page(NULL); ··· 86 137 return -ENOMEM; 87 138 88 139 for (int i = 0; i < nr_pfn_mapped; i++) { 89 - unsigned long mstart, mend; 90 - 91 140 mstart = pfn_mapped[i].start << PAGE_SHIFT; 92 141 mend = pfn_mapped[i].end << PAGE_SHIFT; 93 142 if (kernel_ident_mapping_init(&info, pgd, mstart, mend)) { ··· 94 147 } 95 148 } 96 149 97 - if (kernel_ident_mapping_init(&info, pgd, 98 - PAGE_ALIGN_DOWN(reset_vector), 99 - PAGE_ALIGN(reset_vector + 1))) { 150 + mstart = PAGE_ALIGN_DOWN(reset_vector); 151 + mend = mstart + PAGE_SIZE; 152 + if (kernel_ident_mapping_init(&info, pgd, mstart, mend)) { 100 153 kernel_ident_mapping_free(&info, pgd); 101 154 return -ENOMEM; 102 155 } 103 156 104 - if (init_transition_pgtable(pgd)) { 157 + /* 158 + * Make sure asm_acpi_mp_play_dead() is present in the identity mapping 159 + * at the same place as in the kernel page tables. 160 + * asm_acpi_mp_play_dead() switches to the identity mapping and the 161 + * function must be present at the same spot in the virtual address space 162 + * before and after switching page tables. 163 + */ 164 + info.offset = __START_KERNEL_map - phys_base; 165 + mstart = PAGE_ALIGN_DOWN(__pa(asm_acpi_mp_play_dead)); 166 + mend = mstart + PAGE_SIZE; 167 + if (kernel_ident_mapping_init(&info, pgd, mstart, mend)) { 105 168 kernel_ident_mapping_free(&info, pgd); 106 169 return -ENOMEM; 107 170 }