[RFC v2 1/4] ARM: mm: add early page table attribute modification ability

Bill Mills wmills at ti.com
Sun Jun 5 20:20:26 PDT 2016


Allow early-init to specify modifications to be made to the boot time page
table. Any modifications specified will be done with MMU off at the same
time that any Phy<->Virt fixup is done.

This ability is enabled with ARM_PV_FIXUP.

It is currently only implemented for LPAE mode.

Signed-off-by: Bill Mills <wmills at ti.com>
---
 arch/arm/include/asm/pgtable-hwdef.h | 21 +++++++++
 arch/arm/mm/mmu.c                    | 36 ++++++++++++---
 arch/arm/mm/pv-fixup-asm.S           | 86 ++++++++++++++++++++++++++++++++++--
 3 files changed, 135 insertions(+), 8 deletions(-)

diff --git a/arch/arm/include/asm/pgtable-hwdef.h b/arch/arm/include/asm/pgtable-hwdef.h
index 8426229..c35d71f 100644
--- a/arch/arm/include/asm/pgtable-hwdef.h
+++ b/arch/arm/include/asm/pgtable-hwdef.h
@@ -16,4 +16,25 @@
 #include <asm/pgtable-2level-hwdef.h>
 #endif
 
+#ifdef CONFIG_ARM_PV_FIXUP
+
+#define MAX_ATTR_MOD_ENTRIES	64
+
+#ifndef __ASSEMBLY__
+
+struct attr_mod_entry {
+	pmdval_t	test_mask;
+	pmdval_t	test_value;
+	pmdval_t	clear_mask;
+	pmdval_t	set_mask;
+};
+
+bool attr_mod_add(struct attr_mod_entry *pmod);
+
+extern int num_attr_mods;
+extern struct attr_mod_entry attr_mod_table[MAX_ATTR_MOD_ENTRIES];
+
+#endif	/* __ASSEMBLY__ */
+#endif	/* CONFIG_ARM_PV_FIXUP */
+
 #endif
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 62f4d01..a608980 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -1496,23 +1496,41 @@ extern unsigned long __atags_pointer;
 typedef void pgtables_remap(long long offset, unsigned long pgd, void *bdata);
 pgtables_remap lpae_pgtables_remap_asm;
 
+int num_attr_mods;
+
+/* add an entry to the early page table attribute modification list */
+bool __init attr_mod_add(struct attr_mod_entry *pmod)
+{
+	if (num_attr_mods >= MAX_ATTR_MOD_ENTRIES) {
+		pr_crit("Out of room for (or late use of) early page table attribute modifications.\n");
+		return false;
+	}
+
+	attr_mod_table[num_attr_mods++] = *pmod;
+	return true;
+}
+
 /*
  * early_paging_init() recreates boot time page table setup, allowing machines
  * to switch over to a high (>4G) address space on LPAE systems
+ *
+ * This function also applies any attribute modifications specified in
+ * attr_mod_table.  These may have been added before we got here (early_param)
+ * or from within mdesc->pv_fixup called by this function
  */
 void __init early_paging_init(const struct machine_desc *mdesc)
 {
 	pgtables_remap *lpae_pgtables_remap;
 	unsigned long pa_pgd;
 	unsigned int cr, ttbcr;
-	long long offset;
+	long long offset = 0;
 	void *boot_data;
+	unsigned long pmd;
 
-	if (!mdesc->pv_fixup)
-		return;
+	if (mdesc->pv_fixup)
+		offset = mdesc->pv_fixup();
 
-	offset = mdesc->pv_fixup();
-	if (offset == 0)
+	if (offset == 0 && num_attr_mods == 0)
 		return;
 
 	/*
@@ -1564,6 +1582,14 @@ void __init early_paging_init(const struct machine_desc *mdesc)
 	/* Re-enable the caches and cacheable TLB walks */
 	asm volatile("mcr p15, 0, %0, c2, c0, 2" : : "r" (ttbcr));
 	set_cr(cr);
+
+	/* disable any further use of attribute fixup */
+	num_attr_mods = MAX_ATTR_MOD_ENTRIES + 1;
+
+	/* record the new "initial" pmd and cachepolicy */
+	pmd = pmd_val(*pmd_off_k((unsigned long)_data));
+	pmd &= ~PMD_MASK;
+	init_default_cache_policy(pmd);
 }
 
 #else
diff --git a/arch/arm/mm/pv-fixup-asm.S b/arch/arm/mm/pv-fixup-asm.S
index 1867f3e4..ad8edc2 100644
--- a/arch/arm/mm/pv-fixup-asm.S
+++ b/arch/arm/mm/pv-fixup-asm.S
@@ -19,8 +19,44 @@
 #define L1_ORDER 3
 #define L2_ORDER 3
 
+/*
+ *	attr_mod_table:
+ *		describe transforms to be made to the early boot pgtable
+ *		This is poked by early init code
+ *	mod descriptor list:
+ *		64 bit test mask
+ *		64 bit test value
+ *		64 bit clear mask
+ *		64 bit set mask
+ *      	next descriptor
+ *		...
+ *		0x0000_00000 0x0000_0000 end of list
+ */
+/* TODO: what segment?, test w/ XIP kernel? */
+	 .globl attr_mod_table
+attr_mod_table:
+	.zero   8*MAX_ATTR_MOD_ENTRIES*4 + 1
+
+/*
+ *	lpae_pgtables_remap_asm(long long offset, unsigned long pg,
+ *		void* boot_data)
+ *
+ *	Rewrite initial boot page tables with new physical addresses and or
+ *	attributes.
+ *	This function starts in identity mapped VA -> low PA
+ *	The body runs in low PA with MMU off
+ * 	The function ends in "identity mapped" VA -> high PA
+ *	The function returns to kernel VA space -> high PA
+ *
+ *	- r0    PA delta low
+ *	- r1	PA delta high
+ *	- r2    address of top level table
+ *	- r3    address of dtb (or atags))
+ *
+ *	uses null terminated list of attribute modifications in attr_mod_table
+ */
 ENTRY(lpae_pgtables_remap_asm)
-	stmfd	sp!, {r4-r8, lr}
+	stmfd	sp!, {r4-r11, lr}
 
 	mrc	p15, 0, r8, c1, c0, 0		@ read control reg
 	bic	ip, r8, #CR_M			@ disable caches and MMU
@@ -63,6 +99,7 @@ ENTRY(lpae_pgtables_remap_asm)
 	subs	r6, r6, #1
 	bne	2b
 
+	/* Update HW page table regs with new PA */
 	mrrc	p15, 0, r4, r5, c2		@ read TTBR0
 	adds	r4, r4, r0			@ update physical address
 	adc	r5, r5, r1
@@ -74,15 +111,58 @@ ENTRY(lpae_pgtables_remap_asm)
 
 	dsb
 
+	/* Update attributes of all level 2 entries in 1GB space */
+	/* TODO: fix/test BE8 THUMB2 kernel */
+	adrl	r3, attr_mod_table
+	add	r7, r2, #0x1000
+	add	r6, r7, #0x4000
+	bl	3f				@ NOT C ABI
+
+	/* Update attributes of the 4 level 1 entries */
+	/* TODO: delete this or allow mod entries to match only L1 */
+	mov	r7, r2
+	add	r6, r7, #32
+	bl	3f				@ NOT C ABI
+	b	7f
+
+3:	ldrd	r4, [r7]
+	orrs	r11, r4, r5
+	beq	6f				@ skip unused entries
+	mov 	r10, r3
+4:	ldrd	r8, [r10]
+	orrs	r11, r8, r9
+	beq	6f				@ end of mod table?
+	and	r0, r4, r8			@ no, load test mask
+	and	r1, r5, r9
+	ldrd	r8, [r10, #8]			@ load test bits
+	cmp	r0, r8
+	cmpeq	r1, r9
+	bne	5f				@ does entry match desc?
+	ldrd	r8, [r10, #16]			@ yes, load mod clear mask
+	bic	r4, r4, r8
+	bic	r5, r5, r9
+	ldrd	r8, [r10, #24]			@ load mod set mask
+	orr	r4, r4, r8
+	orr	r5, r5, r9
+5:	add     r10, r10, #32			@ try next mod desc
+	b	4b
+6:	strd	r4, [r7], #1 << L2_ORDER
+	cmp	r7, r6
+	bls	3b
+	bx 	lr
+
+7:
 	mov	ip, #0
 	mcr	p15, 0, ip, c7, c5, 0		@ I+BTB cache invalidate
 	mcr	p15, 0, ip, c8, c7, 0		@ local_flush_tlb_all()
 	dsb
 	isb
 
-	mcr	p15, 0, r8, c1, c0, 0		@ re-enable MMU
+	mrc	p15, 0, r8, c1, c0, 0		@ re-enable MMU
+	orr	r8, r8, #CR_M
+	mcr	p15, 0, r8, c1, c0, 0
 	dsb
 	isb
 
-	ldmfd	sp!, {r4-r8, pc}
+	ldmfd	sp!, {r4-r11, pc}
 ENDPROC(lpae_pgtables_remap_asm)
-- 
1.9.1




More information about the linux-arm-kernel mailing list