|
@@ -28,6 +28,7 @@
|
|
|
#include <linux/io.h>
|
|
|
|
|
|
#include <asm/cputype.h>
|
|
|
+#include <asm/fixmap.h>
|
|
|
#include <asm/sections.h>
|
|
|
#include <asm/setup.h>
|
|
|
#include <asm/sizes.h>
|
|
@@ -463,3 +464,96 @@ void vmemmap_free(unsigned long start, unsigned long end)
|
|
|
{
|
|
|
}
|
|
|
#endif /* CONFIG_SPARSEMEM_VMEMMAP */
|
|
|
+
|
|
|
+static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss;
|
|
|
+#if CONFIG_ARM64_PGTABLE_LEVELS > 2
|
|
|
+static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss;
|
|
|
+#endif
|
|
|
+#if CONFIG_ARM64_PGTABLE_LEVELS > 3
|
|
|
+static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss;
|
|
|
+#endif
|
|
|
+
|
|
|
+static inline pud_t * fixmap_pud(unsigned long addr)
|
|
|
+{
|
|
|
+ pgd_t *pgd = pgd_offset_k(addr);
|
|
|
+
|
|
|
+ BUG_ON(pgd_none(*pgd) || pgd_bad(*pgd));
|
|
|
+
|
|
|
+ return pud_offset(pgd, addr);
|
|
|
+}
|
|
|
+
|
|
|
+static inline pmd_t * fixmap_pmd(unsigned long addr)
|
|
|
+{
|
|
|
+ pud_t *pud = fixmap_pud(addr);
|
|
|
+
|
|
|
+ BUG_ON(pud_none(*pud) || pud_bad(*pud));
|
|
|
+
|
|
|
+ return pmd_offset(pud, addr);
|
|
|
+}
|
|
|
+
|
|
|
+static inline pte_t * fixmap_pte(unsigned long addr)
|
|
|
+{
|
|
|
+ pmd_t *pmd = fixmap_pmd(addr);
|
|
|
+
|
|
|
+ BUG_ON(pmd_none(*pmd) || pmd_bad(*pmd));
|
|
|
+
|
|
|
+ return pte_offset_kernel(pmd, addr);
|
|
|
+}
|
|
|
+
|
|
|
+void __init early_fixmap_init(void)
|
|
|
+{
|
|
|
+ pgd_t *pgd;
|
|
|
+ pud_t *pud;
|
|
|
+ pmd_t *pmd;
|
|
|
+ unsigned long addr = FIXADDR_START;
|
|
|
+
|
|
|
+ pgd = pgd_offset_k(addr);
|
|
|
+ pgd_populate(&init_mm, pgd, bm_pud);
|
|
|
+ pud = pud_offset(pgd, addr);
|
|
|
+ pud_populate(&init_mm, pud, bm_pmd);
|
|
|
+ pmd = pmd_offset(pud, addr);
|
|
|
+ pmd_populate_kernel(&init_mm, pmd, bm_pte);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The boot-ioremap range spans multiple pmds, for which
|
|
|
+ * we are not preparted:
|
|
|
+ */
|
|
|
+ BUILD_BUG_ON((__fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT)
|
|
|
+ != (__fix_to_virt(FIX_BTMAP_END) >> PMD_SHIFT));
|
|
|
+
|
|
|
+ if ((pmd != fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)))
|
|
|
+ || pmd != fixmap_pmd(fix_to_virt(FIX_BTMAP_END))) {
|
|
|
+ WARN_ON(1);
|
|
|
+ pr_warn("pmd %p != %p, %p\n",
|
|
|
+ pmd, fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)),
|
|
|
+ fixmap_pmd(fix_to_virt(FIX_BTMAP_END)));
|
|
|
+ pr_warn("fix_to_virt(FIX_BTMAP_BEGIN): %08lx\n",
|
|
|
+ fix_to_virt(FIX_BTMAP_BEGIN));
|
|
|
+ pr_warn("fix_to_virt(FIX_BTMAP_END): %08lx\n",
|
|
|
+ fix_to_virt(FIX_BTMAP_END));
|
|
|
+
|
|
|
+ pr_warn("FIX_BTMAP_END: %d\n", FIX_BTMAP_END);
|
|
|
+ pr_warn("FIX_BTMAP_BEGIN: %d\n", FIX_BTMAP_BEGIN);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void __set_fixmap(enum fixed_addresses idx,
|
|
|
+ phys_addr_t phys, pgprot_t flags)
|
|
|
+{
|
|
|
+ unsigned long addr = __fix_to_virt(idx);
|
|
|
+ pte_t *pte;
|
|
|
+
|
|
|
+ if (idx >= __end_of_fixed_addresses) {
|
|
|
+ BUG();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ pte = fixmap_pte(addr);
|
|
|
+
|
|
|
+ if (pgprot_val(flags)) {
|
|
|
+ set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, flags));
|
|
|
+ } else {
|
|
|
+ pte_clear(&init_mm, addr, pte);
|
|
|
+ flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
|
|
|
+ }
|
|
|
+}
|