^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/mm_types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/pgtable.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <asm/cputype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <asm/idmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <asm/hwcap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <asm/pgalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <asm/sections.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <asm/system_info.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * Note: accesses outside of the kernel image and the identity map area
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * are not supported on any CPU using the idmap tables as its current
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * page tables.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) pgd_t *idmap_pgd __ro_after_init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) long long arch_phys_to_idmap_offset __ro_after_init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #ifdef CONFIG_ARM_LPAE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) static void idmap_add_pmd(pud_t *pud, unsigned long addr, unsigned long end,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) unsigned long prot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) pmd_t *pmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) unsigned long next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) if (pud_none_or_clear_bad(pud) || (pud_val(*pud) & L_PGD_SWAPPER)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) pmd = pmd_alloc_one(&init_mm, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) if (!pmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) pr_warn("Failed to allocate identity pmd.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * Copy the original PMD to ensure that the PMD entries for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * the kernel image are preserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) if (!pud_none(*pud))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) memcpy(pmd, pmd_offset(pud, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) PTRS_PER_PMD * sizeof(pmd_t));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) pud_populate(&init_mm, pud, pmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) pmd += pmd_index(addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) pmd = pmd_offset(pud, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) next = pmd_addr_end(addr, end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) *pmd = __pmd((addr & PMD_MASK) | prot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) flush_pmd_entry(pmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) } while (pmd++, addr = next, addr != end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #else /* !CONFIG_ARM_LPAE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static void idmap_add_pmd(pud_t *pud, unsigned long addr, unsigned long end,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) unsigned long prot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) pmd_t *pmd = pmd_offset(pud, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) addr = (addr & PMD_MASK) | prot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) pmd[0] = __pmd(addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) addr += SECTION_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) pmd[1] = __pmd(addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) flush_pmd_entry(pmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #endif /* CONFIG_ARM_LPAE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static void idmap_add_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) unsigned long prot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) p4d_t *p4d = p4d_offset(pgd, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) pud_t *pud = pud_offset(p4d, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) unsigned long next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) next = pud_addr_end(addr, end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) idmap_add_pmd(pud, addr, next, prot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) } while (pud++, addr = next, addr != end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static void identity_mapping_add(pgd_t *pgd, const char *text_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) const char *text_end, unsigned long prot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) unsigned long addr, end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) unsigned long next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) addr = virt_to_idmap(text_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) end = virt_to_idmap(text_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) pr_info("Setting up static identity map for 0x%lx - 0x%lx\n", addr, end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) prot |= PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale_family())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) prot |= PMD_BIT4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) pgd += pgd_index(addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) next = pgd_addr_end(addr, end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) idmap_add_pud(pgd, addr, next, prot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) } while (pgd++, addr = next, addr != end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) extern char __idmap_text_start[], __idmap_text_end[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) static int __init init_static_idmap(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) idmap_pgd = pgd_alloc(&init_mm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (!idmap_pgd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) identity_mapping_add(idmap_pgd, __idmap_text_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) __idmap_text_end, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) /* Flush L1 for the hardware to see this page table content */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (!(elf_hwcap & HWCAP_LPAE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) flush_cache_louis();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) early_initcall(init_static_idmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) * In order to soft-boot, we need to switch to a 1:1 mapping for the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) * cpu_reset functions. This will then ensure that we have predictable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) * results when turning off the mmu.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) void setup_mm_for_reboot(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) /* Switch to the identity mapping. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) cpu_switch_mm(idmap_pgd, &init_mm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) local_flush_bp_all();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) #ifdef CONFIG_CPU_HAS_ASID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * We don't have a clean ASID for the identity mapping, which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) * may clash with virtual addresses of the previous page tables
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * and therefore potentially in the TLB.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) local_flush_tlb_all();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }