From: ard.biesheuvel@linaro.org (Ard Biesheuvel)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v3 07/11] arm64: fixmap: allow init before linear mapping is set up
Date: Fri, 10 Apr 2015 15:53:51 +0200 [thread overview]
Message-ID: <1428674035-26603-8-git-send-email-ard.biesheuvel@linaro.org> (raw)
In-Reply-To: <1428674035-26603-1-git-send-email-ard.biesheuvel@linaro.org>
This reworks early_ioremap_init() so it populates the various levels
of translation tables while taking the following into account:
- be prepared for any of the levels to have been populated already, as
this may be the case once we move the kernel text mapping out of the
linear mapping;
- don't rely on __va() to translate the physical address in a page table
entry to a virtual address, since this produces linear mapping addresses;
instead, use the fact that at any level, we know exactly which page in
swapper_pg_dir an entry could be pointing to if it points anywhere.
This allows us to defer the initialization of the linear mapping until
after we have figured out where our RAM resides in the physical address
space.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/include/asm/compiler.h | 2 +
arch/arm64/kernel/vmlinux.lds.S | 14 +++--
arch/arm64/mm/mmu.c | 117 +++++++++++++++++++++++++-------------
3 files changed, 90 insertions(+), 43 deletions(-)
diff --git a/arch/arm64/include/asm/compiler.h b/arch/arm64/include/asm/compiler.h
index ee35fd0f2236..dd342af63673 100644
--- a/arch/arm64/include/asm/compiler.h
+++ b/arch/arm64/include/asm/compiler.h
@@ -27,4 +27,6 @@
*/
#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t"
+#define __pgdir __attribute__((section(".pgdir"),aligned(PAGE_SIZE)))
+
#endif /* __ASM_COMPILER_H */
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 98073332e2d0..604f285d3832 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -160,11 +160,15 @@ SECTIONS
BSS_SECTION(0, 0, 0)
- . = ALIGN(PAGE_SIZE);
- idmap_pg_dir = .;
- . += IDMAP_DIR_SIZE;
- swapper_pg_dir = .;
- . += SWAPPER_DIR_SIZE;
+ .pgdir (NOLOAD) : {
+ . = ALIGN(PAGE_SIZE);
+ idmap_pg_dir = .;
+ . += IDMAP_DIR_SIZE;
+ swapper_pg_dir = .;
+ __swapper_bs_region = . + PAGE_SIZE;
+ . += SWAPPER_DIR_SIZE;
+ *(.pgdir)
+ }
_end = .;
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 60be58a160a2..c0427b5c90c7 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -341,6 +341,70 @@ static void __init __map_memblock(phys_addr_t start, phys_addr_t end)
}
#endif
+struct mem_bootstrap_region {
+#if CONFIG_ARM64_PGTABLE_LEVELS > 3
+ pud_t pud[PTRS_PER_PUD];
+#endif
+#if CONFIG_ARM64_PGTABLE_LEVELS > 2
+ pmd_t pmd[PTRS_PER_PMD];
+#endif
+ pte_t pte[PTRS_PER_PTE];
+};
+
+static void __init bootstrap_mem_region(unsigned long addr,
+ struct mem_bootstrap_region *reg,
+ pmd_t **ppmd, pte_t **ppte)
+{
+ /*
+ * Avoid using the linear phys-to-virt translation __va() so that we
+ * can use this code before the linear mapping is set up. Note that
+ * any populated entries at any level can only point into swapper_pg_dir
+ * since no other translation table pages have been allocated yet.
+ * So at each level, we either need to populate it, or it has already
+ * been populated by a swapper_pg_dir table at the same level, in which
+ * case we can figure out its virtual address without applying __va()
+ * on the contents of the entry, using the following struct.
+ */
+ extern struct mem_bootstrap_region __swapper_bs_region;
+
+ pgd_t *pgd = pgd_offset_k(addr);
+ pud_t *pud = (pud_t *)pgd;
+ pmd_t *pmd = (pmd_t *)pud;
+
+#if CONFIG_ARM64_PGTABLE_LEVELS > 3
+ if (pgd_none(*pgd)) {
+ clear_page(reg->pud);
+ pgd_populate(&init_mm, pgd, reg->pud);
+ pud = reg->pud;
+ } else {
+ pud = __swapper_bs_region.pud;
+ }
+ pud += pud_index(addr);
+#endif
+
+#if CONFIG_ARM64_PGTABLE_LEVELS > 2
+ if (pud_none(*pud)) {
+ clear_page(reg->pmd);
+ pud_populate(&init_mm, pud, reg->pmd);
+ *ppmd = reg->pmd;
+ } else {
+ *ppmd = __swapper_bs_region.pmd;
+ }
+ pmd = *ppmd + pmd_index(addr);
+#endif
+
+ if (!ppte)
+ return;
+
+ if (pmd_none(*pmd)) {
+ clear_page(reg->pte);
+ pmd_populate_kernel(&init_mm, pmd, reg->pte);
+ *ppte = reg->pte;
+ } else {
+ *ppte = __swapper_bs_region.pte;
+ }
+}
+
static void __init map_mem(void)
{
struct memblock_region *reg;
@@ -554,58 +618,35 @@ 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 pmd_t *fixmap_pmd_dir __initdata = (pmd_t *)swapper_pg_dir;
+static pte_t *fixmap_pte_dir;
-static inline pmd_t * fixmap_pmd(unsigned long addr)
+static __always_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);
+#if CONFIG_ARM64_PGTABLE_LEVELS > 2
+ return fixmap_pmd_dir + pmd_index(addr);
+#else
+ return fixmap_pmd_dir + pgd_index(addr);
+#endif
}
-static inline pte_t * fixmap_pte(unsigned long 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);
+ return fixmap_pte_dir + pte_index(addr);
}
void __init early_fixmap_init(void)
{
- pgd_t *pgd;
- pud_t *pud;
+ static struct mem_bootstrap_region fixmap_bs_region __pgdir;
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);
+ bootstrap_mem_region(FIXADDR_START, &fixmap_bs_region, &fixmap_pmd_dir,
+ &fixmap_pte_dir);
+ pmd = fixmap_pmd(FIXADDR_START);
/*
* The boot-ioremap range spans multiple pmds, for which
- * we are not preparted:
+ * we are not prepared:
*/
BUILD_BUG_ON((__fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT)
!= (__fix_to_virt(FIX_BTMAP_END) >> PMD_SHIFT));
--
1.8.3.2
next prev parent reply other threads:[~2015-04-10 13:53 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-04-10 13:53 [PATCH v3 00/11] arm64: update/clarify/relax Image and FDT placement rules Ard Biesheuvel
2015-04-10 13:53 ` [PATCH v3 01/11] arm64: reduce ID map to a single page Ard Biesheuvel
2015-04-13 12:53 ` Mark Rutland
2015-04-13 12:56 ` Ard Biesheuvel
2015-04-10 13:53 ` [PATCH v3 02/11] arm64: drop sleep_idmap_phys and clean up cpu_resume() Ard Biesheuvel
2015-04-10 13:53 ` [PATCH v3 03/11] of/fdt: split off FDT self reservation from memreserve processing Ard Biesheuvel
2015-04-10 13:53 ` [PATCH v3 04/11] arm64: use fixmap region for permanent FDT mapping Ard Biesheuvel
2015-04-13 15:02 ` Mark Rutland
2015-04-13 15:15 ` Ard Biesheuvel
2015-04-13 15:26 ` Mark Rutland
2015-04-13 15:45 ` Ard Biesheuvel
2015-04-13 16:26 ` Mark Rutland
2015-04-14 7:44 ` Ard Biesheuvel
2015-04-14 8:57 ` Mark Rutland
2015-04-10 13:53 ` [PATCH v3 05/11] arm64/efi: adapt to relaxed FDT placement requirements Ard Biesheuvel
2015-04-13 16:20 ` Mark Rutland
2015-04-13 16:25 ` Ard Biesheuvel
2015-04-13 16:35 ` Mark Rutland
2015-04-13 16:36 ` Ard Biesheuvel
2015-04-10 13:53 ` [PATCH v3 06/11] arm64: implement our own early_init_dt_add_memory_arch() Ard Biesheuvel
2015-04-10 13:53 ` Ard Biesheuvel [this message]
2015-04-14 10:47 ` [PATCH v3 07/11] arm64: fixmap: allow init before linear mapping is set up Mark Rutland
2015-04-14 11:02 ` Ard Biesheuvel
2015-04-14 13:41 ` Mark Rutland
2015-04-10 13:53 ` [PATCH v3 08/11] arm64: mm: explicitly bootstrap the linear mapping Ard Biesheuvel
2015-04-10 13:53 ` [PATCH v3 09/11] arm64: move kernel mapping out of linear region Ard Biesheuvel
2015-04-10 13:53 ` [PATCH v3 10/11] arm64: allow kernel Image to be loaded anywhere in physical memory Ard Biesheuvel
2015-04-14 14:36 ` Mark Rutland
2015-04-10 13:53 ` [PATCH v3 11/11] arm64/efi: adapt to relaxed kernel Image placement requirements Ard Biesheuvel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1428674035-26603-8-git-send-email-ard.biesheuvel@linaro.org \
--to=ard.biesheuvel@linaro.org \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).