Skip to contentSkip to conversation

arm64: Use contiguous PTE bit for the kernel linear mapping

PATCH Superseded Jeremy Linton 2 participants 15 messages Oct 2, 2015 – Oct 6, 2015

Subsystems (2)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

v2 cover arm64: Use contiguous PTE bit for the kernel linear mapping

Changes from V1:

This version is similar to the previous versions with the addition of contpte/nocontpte kernel parameters for enabling/disabling the functionality. I defaulted it to contpte, but will change it to nocontpte if someone feels strongly about that. I considered making the default a kconfig option, but decided against it to avoid adding clutter for what should eventually be a fairly normal piece of functionality. I also used the early_param_on_off() macro, which is a small and concise piece of code, but varies a little from the more common parameter=value kernel parameters.

Also, continuing thanks to Steve Capper who has been religiously testing these patch sets, and found a bug in the previous implementation.

Finally, I removed the formatting change per Catalin.

Original Description:

When running 64k pages it became apparent that it was possible that the kernel could create more TLB pressure in certain circumstances when compared to the 4k page kernel. This is due to the fact that large portions of the 4k kernel can be mapped with 2M blocks. While the larger block size for 64k pages is 512M, it frequently won't be used for assorted reasons.

ARMv8 has a contiguous PTE bit that allows the TLBs to map a range larger than a single PTE if the range is physically contiguous. So its a good idea to use this where appropriate for the kernel mapping.

This patch adds the definitions for the contiguous bit, updates the kernel page range dump to understand them (and block translations), and updates the code in mmu.c to use the contiguous bit where appropriate for the kernel linear mapping.

Jeremy Linton (7):
arm64: Add contiguous page flag shifts and constants
arm64: PTE/PMD contiguous bit definition
arm64: Macros to check/set/unset the contiguous bit
arm64: Default kernel pages should be contiguous
arm64: Make the kernel page dump utility aware of the CONT bit
arm64: Mark kernel page ranges contiguous
Document the use of the arm64 contpte/nonconpte flags.

 Documentation/kernel-parameters.txt    |  4 ++
 arch/arm64/include/asm/page.h          |  8 +++-
 arch/arm64/include/asm/pgtable-hwdef.h |  9 ++++
 arch/arm64/include/asm/pgtable.h       | 13 ++++++
 arch/arm64/mm/dump.c                   | 18 +++++++-
 arch/arm64/mm/mmu.c                    | 81 ++++++++++++++++++++++++++++++----
 6 files changed, 122 insertions(+), 11 deletions(-)
Signature · 1 line
2.4.3
#1 lore raw

PATCH v2 1/7 arm64: Add contiguous page flag shifts and constants

Add the number of pages required to form a contigious range, as well as some supporting constants.

---
 arch/arm64/include/asm/page.h | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
arch/arm64/include/asm/page.h +7 -1
index 7d9c7e4..33892ef 100644
@@ -20,14 +20,20 @@
 #define __ASM_PAGE_H
 
 /* PAGE_SHIFT determines the page size */
+/* CONT_SHIFT determines the number of pages which can be tracked together  */
 #ifdef CONFIG_ARM64_64K_PAGES
 #define PAGE_SHIFT		16
+#define CONT_SHIFT		5
 #else
 #define PAGE_SHIFT		12
+#define CONT_SHIFT		4
 #endif
-#define PAGE_SIZE		(_AC(1,UL) << PAGE_SHIFT)
+#define PAGE_SIZE		(_AC(1, UL) << PAGE_SHIFT)
 #define PAGE_MASK		(~(PAGE_SIZE-1))
 
+#define CONT_SIZE		(_AC(1, UL) << (CONT_SHIFT + PAGE_SHIFT))
+#define CONT_MASK		(~(CONT_SIZE-1))
+
 /*
  * The idmap and swapper page tables need some space reserved in the kernel
  * image. Both require pgd, pud (4 levels only) and pmd tables to (section)
Signature · 1 line
2.4.3
#2 lore raw

PATCH v2 2/7 arm64: PTE/PMD contiguous bit definition

In reply to Jeremy Linton

Define the bit positions in the PTE and PMD for the contiguous bit.

---
 arch/arm64/include/asm/pgtable-hwdef.h | 9 +++++++++
 1 file changed, 9 insertions(+)
arch/arm64/include/asm/pgtable-hwdef.h +9 -0
index 24154b0..361352d 100644
@@ -55,6 +55,13 @@
 #define SECTION_MASK		(~(SECTION_SIZE-1))
 
 /*
+ * Contiguous page definitions.
+ */
+#define CONT_RANGE		(_AC(1, UL) << CONT_SHIFT)
+#define CONT_RANGE_MASK		((CONT_RANGE-1) << PAGE_SHIFT)
+#define CONT_RANGE_OFFSET(addr) (((addr)>>PAGE_SHIFT)&(CONT_RANGE-1))
+
+/*
  * Hardware page table definitions.
  *
  * Level 1 descriptor (PUD).
@@ -83,6 +90,7 @@
 #define PMD_SECT_S		(_AT(pmdval_t, 3) << 8)
 #define PMD_SECT_AF		(_AT(pmdval_t, 1) << 10)
 #define PMD_SECT_NG		(_AT(pmdval_t, 1) << 11)
+#define PMD_SECT_CONT		(_AT(pmdval_t, 1) << 52)
 #define PMD_SECT_PXN		(_AT(pmdval_t, 1) << 53)
 #define PMD_SECT_UXN		(_AT(pmdval_t, 1) << 54)
 
@@ -105,6 +113,7 @@
 #define PTE_AF			(_AT(pteval_t, 1) << 10)	/* Access Flag */
 #define PTE_NG			(_AT(pteval_t, 1) << 11)	/* nG */
 #define PTE_DBM			(_AT(pteval_t, 1) << 51)	/* Dirty Bit Management */
+#define PTE_CONT		(_AT(pteval_t, 1) << 52)	/* Contiguous range */
 #define PTE_PXN			(_AT(pteval_t, 1) << 53)	/* Privileged XN */
 #define PTE_UXN			(_AT(pteval_t, 1) << 54)	/* User XN */
 
Signature · 1 line
2.4.3
maintainer
#3 lore raw

PATCH v2 2/7 arm64: PTE/PMD contiguous bit definition

Quoted 13 lines · Jeremy Linton

Define the bit positions in the PTE and PMD for the contiguous bit.

---
 arch/arm64/include/asm/pgtable-hwdef.h | 9 +++++++++
 1 file changed, 9 insertions(+)
arch/arm64/include/asm/pgtable-hwdef.h +0 -0
index 24154b0..361352d 100644

arch/arm64/include/asm/pgtable-hwdef.h line 62

Quoted 8 lines
arch/arm64/include/asm/pgtable-hwdef.h +5 -0
@@ -55,6 +55,13 @@
 #define SECTION_MASK		(~(SECTION_SIZE-1))
 
 /*
+ * Contiguous page definitions.
+ */
+#define CONT_RANGE		(_AC(1, UL) << CONT_SHIFT)
+#define CONT_RANGE_MASK		((CONT_RANGE-1) << PAGE_SHIFT)
+#define CONT_RANGE_OFFSET(addr) (((addr)>>PAGE_SHIFT)&(CONT_RANGE-1))

This still looks confusing to me: CONT_RANGE refers to the number of contiguous ptes while CONT_RANGE_MASK refers to actual addresses. I'd rather have CONT_PTES (since we only use this for ptes currently) and CONT_MASK used instead of CONT_RANGE_MASK. This is for consistency with SECTION_MASK which we already use.

Signature · 1 line
Catalin
#4 lore raw

PATCH v2 3/7 arm64: Macros to check/set/unset the contiguous bit

In reply to Jeremy Linton

Add the supporting macros to check if the contiguous bit is set, set the bit, or clear it in a PTE entry.

---
 arch/arm64/include/asm/pgtable.h | 11 +++++++++++
 1 file changed, 11 insertions(+)
arch/arm64/include/asm/pgtable.h +11 -0
index 6900b2d9..d43e1d1 100644
@@ -144,6 +144,7 @@ extern struct page *empty_zero_page;
 #define pte_special(pte)	(!!(pte_val(pte) & PTE_SPECIAL))
 #define pte_write(pte)		(!!(pte_val(pte) & PTE_WRITE))
 #define pte_exec(pte)		(!(pte_val(pte) & PTE_UXN))
+#define pte_cont(pte)		(!!(pte_val(pte) & PTE_CONT))
 
 #ifdef CONFIG_ARM64_HW_AFDBM
 #define pte_hw_dirty(pte)	(!(pte_val(pte) & PTE_RDONLY))
@@ -206,6 +207,16 @@ static inline pte_t pte_mkspecial(pte_t pte)
 	return set_pte_bit(pte, __pgprot(PTE_SPECIAL));
 }
 
+static inline pte_t pte_mkcont(pte_t pte)
+{
+	return set_pte_bit(pte, __pgprot(PTE_CONT));
+}
+
+static inline pte_t pte_mknoncont(pte_t pte)
+{
+	return clear_pte_bit(pte, __pgprot(PTE_CONT));
+}
+
 static inline void set_pte(pte_t *ptep, pte_t pte)
 {
 	*ptep = pte;
Signature · 1 line
2.4.3
#5 lore raw

PATCH v2 4/7 arm64: Default kernel pages should be contiguous

In reply to Jeremy Linton

The default page attributes for a PMD being broken should have the CONT bit set. Create a new definition for an early boot range of PTE's that are contiguous.

---
 arch/arm64/include/asm/pgtable.h | 2 ++
 1 file changed, 2 insertions(+)
arch/arm64/include/asm/pgtable.h +2 -0
index d43e1d1..252499e 100644
@@ -76,6 +76,8 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
 
 #define PAGE_KERNEL		__pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE)
 #define PAGE_KERNEL_EXEC	__pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE)
+#define PAGE_KERNEL_EXEC_CONT	__pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | \
+					 PTE_WRITE | PTE_CONT)
 
 #define PAGE_HYP		__pgprot(_PAGE_DEFAULT | PTE_HYP)
 #define PAGE_HYP_DEVICE		__pgprot(PROT_DEVICE_nGnRE | PTE_HYP)
Signature · 1 line
2.4.3
#6 lore raw

PATCH v2 5/7 arm64: Make the kernel page dump utility aware of the CONT bit

In reply to Jeremy Linton

The kernel page dump utility needs to be aware of the CONT bit before it will break up pages ranges for display.

---
 arch/arm64/mm/dump.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)
arch/arm64/mm/dump.c +17 -1
index f3d6221..5a22a11 100644
@@ -67,6 +67,12 @@ static struct addr_marker address_markers[] = {
 	{ -1,			NULL },
 };
 
+/*
+ * The page dumper groups page table entries of the same type into a single
+ * description. It uses pg_state to track the range information while
+ * iterating over the pte entries. When the continuity is broken it then
+ * dumps out a description of the range.
+ */
 struct pg_state {
 	struct seq_file *seq;
 	const struct addr_marker *marker;
@@ -114,6 +120,16 @@ static const struct prot_bits pte_bits[] = {
 		.set	= "NG",
 		.clear	= "  ",
 	}, {
+		.mask	= PTE_CONT,
+		.val	= PTE_CONT,
+		.set	= "CON",
+		.clear	= "   ",
+	}, {
+		.mask	= PTE_TABLE_BIT,
+		.val	= PTE_TABLE_BIT,
+		.set	= "   ",
+		.clear	= "BLK",
+	}, {
 		.mask	= PTE_UXN,
 		.val	= PTE_UXN,
 		.set	= "UXN",
@@ -198,7 +214,7 @@ static void note_page(struct pg_state *st, unsigned long addr, unsigned level,
 		unsigned long delta;
 
 		if (st->current_prot) {
-			seq_printf(st->seq, "0x%16lx-0x%16lx   ",
+			seq_printf(st->seq, "0x%016lx-0x%016lx   ",
 				   st->start_address, addr);
 
 			delta = (addr - st->start_address) >> 10;
Signature · 1 line
2.4.3
#7 lore raw

PATCH v2 6/7 arm64: Mark kernel page ranges contiguous

In reply to Jeremy Linton

With 64k pages, the next larger segment size is 512M. The linux kernel also uses different protection flags to cover its code and data. Because of this requirement, the vast majority of the kernel code and data structures end up being mapped with 64k pages instead of the larger pages common with a 4k page kernel.

Recent ARM processors support a contiguous bit in the page tables which allows the a TLB to cover a range larger than a single PTE if that range is mapped into physically contiguous ram.

So, for the kernel its a good idea to set this flag. Some basic micro benchmarks show it can significantly reduce the number of L1 dTLB refills.

Add boot option to enable/disable CONT marking, as well as fix a bug found by Steve Capper.

---
 arch/arm64/mm/mmu.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 70 insertions(+), 9 deletions(-)
arch/arm64/mm/mmu.c +70 -9
index 9211b85..4949f1d 100644
@@ -69,6 +69,8 @@ static void __init *early_alloc(unsigned long sz)
 	return ptr;
 }
 
+early_param_on_off("contpte", "nocontpte", cont_linear_ptes, 1);
+
 /*
  * remap a PMD into pages
  */
@@ -80,19 +82,58 @@ static void split_pmd(pmd_t *pmd, pte_t *pte)
 	do {
 		/*
 		 * Need to have the least restrictive permissions available
-		 * permissions will be fixed up later
+		 * permissions will be fixed up later. Default the new page
+		 * range as contiguous ptes.
 		 */
-		set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));
+		if (cont_linear_ptes)
+			set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC_CONT));
+		else
+			set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));
 		pfn++;
 	} while (pte++, i++, i < PTRS_PER_PTE);
 }
 
+/*
+ * Given a PTE with the CONT bit set, determine where the CONT range
+ * starts, and clear the entire range of PTE CONT bits.
+ */
+static void clear_cont_pte_range(pte_t *pte, unsigned long addr)
+{
+	int i;
+
+	pte -= CONT_RANGE_OFFSET(addr);
+	for (i = 0; i < CONT_RANGE; i++) {
+		set_pte(pte, pte_mknoncont(*pte));
+		pte++;
+	}
+	flush_tlb_all();
+}
+
+/*
+ * Given a range of PTEs set the pfn and provided page protection flags
+ */
+static void __populate_init_pte(pte_t *pte, unsigned long addr,
+				unsigned long end, phys_addr_t phys,
+				pgprot_t prot)
+{
+	unsigned long pfn = __phys_to_pfn(phys);
+
+	do {
+		/* clear all the bits except the pfn, then apply the prot */
+		set_pte(pte, pfn_pte(pfn, prot));
+		pte++;
+		pfn++;
+		addr += PAGE_SIZE;
+	} while (addr != end);
+}
+
 static void alloc_init_pte(pmd_t *pmd, unsigned long addr,
-				  unsigned long end, unsigned long pfn,
+				  unsigned long end, phys_addr_t phys,
 				  pgprot_t prot,
 				  void *(*alloc)(unsigned long size))
 {
 	pte_t *pte;
+	unsigned long next;
 
 	if (pmd_none(*pmd) || pmd_sect(*pmd)) {
 		pte = alloc(PTRS_PER_PTE * sizeof(pte_t));
@@ -104,10 +145,31 @@ static void alloc_init_pte(pmd_t *pmd, unsigned long addr,
 	BUG_ON(pmd_bad(*pmd));
 
 	pte = pte_offset_kernel(pmd, addr);
-	do {
-		set_pte(pte, pfn_pte(pfn, prot));
-		pfn++;
-	} while (pte++, addr += PAGE_SIZE, addr != end);
+	if (!cont_linear_ptes)
+		__populate_init_pte(pte, addr, end, phys, prot);
+	else
+	    do {
+		next = min(end, (addr + CONT_SIZE) & CONT_MASK);
+		if (((addr | next | phys) & CONT_RANGE_MASK) == 0) {
+			/* a block of CONT_RANGE_SIZE PTEs */
+			__populate_init_pte(pte, addr, next, phys,
+					    prot | __pgprot(PTE_CONT));
+		} else {
+			/*
+			 * If the range being split is already inside of a
+			 * contiguous range but this PTE isn't going to be
+			 * contiguous, then we want to unmark the adjacent
+			 * ranges, then update the portion of the range we
+			 * are interrested in.
+			 */
+			 clear_cont_pte_range(pte, addr);
+			 __populate_init_pte(pte, addr, next, phys, prot);
+		}
+
+		pte += (next - addr) >> PAGE_SHIFT;
+		phys += next - addr;
+		addr = next;
+	} while (addr != end);
 }
 
 void split_pud(pud_t *old_pud, pmd_t *pmd)
@@ -168,8 +230,7 @@ static void alloc_init_pmd(struct mm_struct *mm, pud_t *pud,
 				}
 			}
 		} else {
-			alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys),
-				       prot, alloc);
+			alloc_init_pte(pmd, addr, next, phys, prot, alloc);
 		}
 		phys += next - addr;
 	} while (pmd++, addr = next, addr != end);
Signature · 1 line
2.4.3
maintainer
#8 lore raw

PATCH v2 6/7 arm64: Mark kernel page ranges contiguous

Quoted 15 lines · Jeremy Linton

static void alloc_init_pte(pmd_t *pmd, unsigned long addr,

arch/arm64/mm/mmu.c +2 -1
-				  unsigned long end, unsigned long pfn,
+				  unsigned long end, phys_addr_t phys,
 				  pgprot_t prot,
 				  void *(*alloc)(unsigned long size))
 {
 	pte_t *pte;
+	unsigned long next;
 
 	if (pmd_none(*pmd) || pmd_sect(*pmd)) {
 		pte = alloc(PTRS_PER_PTE * sizeof(pte_t));
@@ -104,10 +145,31 @@ static void alloc_init_pte(pmd_t *pmd, unsigned long addr,
 	BUG_ON(pmd_bad(*pmd));
 
 	pte = pte_offset_kernel(pmd, addr);

arch/arm64/mm/mmu.c static void alloc_init_pte(pmd_t *pmd, unsigned long addr, · line 153

Quoted 10 lines
arch/arm64/mm/mmu.c +6 -4
-	do {
-		set_pte(pte, pfn_pte(pfn, prot));
-		pfn++;
-	} while (pte++, addr += PAGE_SIZE, addr != end);
+	if (!cont_linear_ptes)
+		__populate_init_pte(pte, addr, end, phys, prot);
+	else
+	    do {
+		next = min(end, (addr + CONT_SIZE) & CONT_MASK);
+		if (((addr | next | phys) & CONT_RANGE_MASK) == 0) {

~CONT_MASK directly here? We don't expect addr/next/phys to not be page aligned (and if they are, the condition fails anyway).

arch/arm64/mm/mmu.c static void alloc_init_pte(pmd_t *pmd, unsigned long addr, · line 154

Quoted 1 line
arch/arm64/mm/mmu.c +1 -0
+			/* a block of CONT_RANGE_SIZE PTEs */

We don't have a CONT_RANGE_SIZE macro, I guess that's CONT_RANGE (or CONT_PTES if you rename it).

Quoted 19 lines
arch/arm64/mm/mmu.c +18 -0
+			__populate_init_pte(pte, addr, next, phys,
+					    prot | __pgprot(PTE_CONT));
+		} else {
+			/*
+			 * If the range being split is already inside of a
+			 * contiguous range but this PTE isn't going to be
+			 * contiguous, then we want to unmark the adjacent
+			 * ranges, then update the portion of the range we
+			 * are interrested in.
+			 */
+			 clear_cont_pte_range(pte, addr);
+			 __populate_init_pte(pte, addr, next, phys, prot);
+		}
+
+		pte += (next - addr) >> PAGE_SHIFT;
+		phys += next - addr;
+		addr = next;
+	} while (addr != end);
 }
Signature · 1 line
Catalin
#9 lore raw

PATCH v2 7/7 Document the use of the arm64 contpte/nonconpte flags.

In reply to Jeremy Linton

These flags allow the user to enable/disable the contiguous PTE detection and marking on the kernel command line for debugging purposes.

---
 Documentation/kernel-parameters.txt | 4 ++++
 1 file changed, 4 insertions(+)
Documentation/kernel-parameters.txt +4 -0
index 22a4b68..2766290 100644
@@ -744,6 +744,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 			seconds. Defaults to 10*60 = 10mins. A value of 0
 			disables the blank timer.
 
+	contpte		[ARM64] Enable contiguous PTE marking for the kernel
+			linear range. This may be disabled with nocontpte.
+			Default: Enabled
+
 	coredump_filter=
 			[KNL] Change the default value for
 			/proc/<pid>/coredump_filter.
Signature · 1 line
2.4.3
maintainer
#10 lore raw

PATCH v2 7/7 Document the use of the arm64 contpte/nonconpte flags.

Quoted 14 lines · Jeremy Linton

These flags allow the user to enable/disable the contiguous PTE detection and marking on the kernel command line for debugging purposes.

---
 Documentation/kernel-parameters.txt | 4 ++++
 1 file changed, 4 insertions(+)
Documentation/kernel-parameters.txt +0 -0
index 22a4b68..2766290 100644

Documentation/kernel-parameters.txt bytes respectively. Such letter suffixes can also be entirely omitted. · line 749

Quoted 6 lines
Documentation/kernel-parameters.txt +3 -0
@@ -744,6 +744,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 			seconds. Defaults to 10*60 = 10mins. A value of 0
 			disables the blank timer.
 
+	contpte		[ARM64] Enable contiguous PTE marking for the kernel
+			linear range. This may be disabled with nocontpte.
+			Default: Enabled

I recall you asked the question but I didn't have the time to reply. I don't think we need a command line option for this. In the "unlikely" event that something is broken in hardware (or software) and we want to disable the contiguous bit, I would rather have a Kconfig option.

Signature · 1 line
Catalin
#11 lore raw

PATCH v2 7/7 Document the use of the arm64 contpte/nonconpte flags.

Quoted 4 lines · Catalin Marinas

I recall you asked the question but I didn't have the time to reply. I don't think we need a command line option for this. In the "unlikely" event that something is broken in hardware (or software) and we want to disable the contiguous bit, I would rather have a Kconfig option.

How about both? Other users of early_param_on_off() set the default
state using kconfig. Is that an acceptable choice, or should I remove the command line parameter all together? I sort of expect that in a few years time, the whole option goes away once it been in use for a while and there are a number of V8 implementations widely available.

maintainer
#12 lore raw

PATCH v2 7/7 Document the use of the arm64 contpte/nonconpte flags.

Quoted 11 lines · Jeremy Linton
Quoted 4 lines · Catalin Marinas

I recall you asked the question but I didn't have the time to reply. I don't think we need a command line option for this. In the "unlikely" event that something is broken in hardware (or software) and we want to disable the contiguous bit, I would rather have a Kconfig option.

How about both? Other users of early_param_on_off() set the default state
using kconfig. Is that an acceptable choice, or should I remove the command line parameter all together? I sort of expect that in a few years time, the whole option goes away once it been in use for a while and there are a number of V8 implementations widely available.

If for debugging purposes we could get away with just changing PAGE_KERNEL_EXEC_CONT, I think we can avoid both command line and Kconfig option. Otherwise only a Kconfig option, I don't see much point in a command line option (maybe benchmarking).

Signature · 1 line
Catalin
maintainer
#13 lore raw

v2 cover arm64: Use contiguous PTE bit for the kernel linear mapping

In reply to Jeremy Linton
Quoted 3 lines · Jeremy Linton

Also, continuing thanks to Steve Capper who has been religiously testing these patch sets, and found a bug in the previous implementation.

Quick question: has this series been tested with CONFIG_DEBUG_RODATA enabled?

Signature · 1 line
Catalin
#14 lore raw

v2 cover arm64: Use contiguous PTE bit for the kernel linear mapping

Quoted 7 lines · Catalin Marinas
Quoted 3 lines · Jeremy Linton

Also, continuing thanks to Steve Capper who has been religiously testing these patch sets, and found a bug in the previous implementation.

Quick question: has this series been tested with CONFIG_DEBUG_RODATA enabled?

In my case, yes. Longer answer, my testing was pretty basic. I flipped it on and checked to see if the machine booted and if the kernel mappings looked correct.