Skip to contentSkip to conversation

Miscellaneous nommu fixes

PATCH Superseded Will Deacon 3 participants 11 messages Mar 6, 2012

Subsystems (3)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover Miscellaneous nommu fixes

Hello,

This set of patches is a series of fixes for kernels built without CONFIG_MMU selected. It seems that this isn't a particularly popular choice amongst users of mainline kernels, but I was feeling brave and gave it a go.

The first patch is already in the patch system as 7337/1 but is unlikely to be merged unless it can be shown to work correctly. I tried the latest Codesourcery / Mentor uclinux GDB but that doesn't appear to issue the relevant ptrace requests:

http://lists.infradead.org/pipermail/linux-arm-kernel/2012-February/086219.html

If anybody has a working uclinux environment, it would *make my day* if they could take GDB for a spin.

The second patch has been picked up by Andrew Morton from the kexec list.

The remaining patches are largely straightforward with the exception of the CPU suspend changes. I actually managed to test this with a rather weird and wonderful configuration, although this was using software models which tend to hide some of the issues you may experience with real hardware.

All feedback welcome.

Will

Jonathan Austin (1):
ARM: nommu: Use VECTORS_BASE for vector copying with !MMU

Will Deacon (5):
ARM: ptrace: fix ptrace_read_user for !CONFIG_MMU platforms
kexec: crash: don't save swapper_pg_dir for !CONFIG_MMU
configurations
ARM: nommu: fix typo in mm/Kconfig
ARM: suspend: fix CPU suspend code for !CONFIG_MMU configurations
ARM: mm: truncate memory banks to fit in 4GB space for classic MMU

 arch/arm/kernel/ptrace.c  |    4 ++-
 arch/arm/kernel/setup.c   |   11 ++++++++-
 arch/arm/kernel/suspend.c |   52 ++++++++++++++++++++++++++-------------------
 arch/arm/kernel/traps.c   |    2 +-
 arch/arm/mm/Kconfig       |    2 +-
 arch/arm/mm/proc-v6.S     |    6 ++++-
 arch/arm/mm/proc-v7.S     |   14 +++++++----
 kernel/kexec.c            |    2 +
 8 files changed, 61 insertions(+), 32 deletions(-)
Signature · 1 line
1.7.4.1
#1 lore raw

PATCH 1/6 ARM: ptrace: fix ptrace_read_user for !CONFIG_MMU platforms

Commit 68b7f715 ("nommu: ptrace support") added definitions for PT_TEXT_ADDR and friends, as well as adding ptrace support for reading from these magic offsets.

Unfortunately, this has probably never worked, since ptrace_read_user predicates reading on off < sizeof(struct user), returning -EIO otherwise.

This patch moves the offset size check until after we have tried to match it against either a magic value or an offset into pt_regs.

---
 arch/arm/kernel/ptrace.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)
arch/arm/kernel/ptrace.c +3 -1
index ede6443..4fe2d598 100644
@@ -257,7 +257,7 @@ static int ptrace_read_user(struct task_struct *tsk, unsigned long off,
 {
 	unsigned long tmp;
 
-	if (off & 3 || off >= sizeof(struct user))
+	if (off & 3)
 		return -EIO;
 
 	tmp = 0;
@@ -269,6 +269,8 @@ static int ptrace_read_user(struct task_struct *tsk, unsigned long off,
 		tmp = tsk->mm->end_code;
 	else if (off < sizeof(struct pt_regs))
 		tmp = get_user_reg(tsk, off >> 2);
+	else if (off >= sizeof(struct user))
+		return -EIO;
 
 	return put_user(tmp, ret);
 }
Signature · 1 line
1.7.4.1
#2 lore raw

PATCH 2/6 kexec: crash: don't save swapper_pg_dir for !CONFIG_MMU configurations

In reply to Will Deacon

nommu platforms don't have very interesting swapper_pg_dir pointers and usually just #define them to NULL, meaning that we can't include them in the vmcoreinfo on the kexec crash path.

This patch only saves the swapper_pg_dir if we have an MMU.

---
 kernel/kexec.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
kernel/kexec.c +2 -0
index 7b08867..cb5d13c 100644
@@ -1462,7 +1462,9 @@ static int __init crash_save_vmcoreinfo_init(void)
 
 	VMCOREINFO_SYMBOL(init_uts_ns);
 	VMCOREINFO_SYMBOL(node_online_map);
+#ifdef CONFIG_MMU
 	VMCOREINFO_SYMBOL(swapper_pg_dir);
+#endif
 	VMCOREINFO_SYMBOL(_stext);
 	VMCOREINFO_SYMBOL(vmlist);
 
Signature · 1 line
1.7.4.1
#3 lore raw

PATCH 3/6 ARM: nommu: fix typo in mm/Kconfig

In reply to Will Deacon

The description for the CPU_HIGH_VECTOR Kconfig option for nommu builds doesn't make any sense.

This patch fixes up the trivial grammatical error.

---
 arch/arm/mm/Kconfig |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
arch/arm/mm/Kconfig +1 -1
index 7edef91..7c8a7d8 100644
@@ -723,7 +723,7 @@ config CPU_HIGH_VECTOR
 	bool "Select the High exception vector"
 	help
 	  Say Y here to select high exception vector(0xFFFF0000~).
-	  The exception vector can be vary depending on the platform
+	  The exception vector can vary depending on the platform
 	  design in nommu mode. If your platform needs to select
 	  high exception vector, say Y.
 	  Otherwise or if you are unsure, say N, and the low exception
Signature · 1 line
1.7.4.1
#4 lore raw

PATCH 4/6 ARM: suspend: fix CPU suspend code for !CONFIG_MMU configurations

In reply to Will Deacon

The ARM CPU suspend code can be selected even for a !CONFIG_MMU configuration. The resulting kernel will not compile and, even if it did, would access undefined co-processor registers when executing.

This patch fixes the v6 and v7 CPU suspend code for the nommu case.

---
 arch/arm/kernel/suspend.c |   52 ++++++++++++++++++++++++++-------------------
 arch/arm/mm/proc-v6.S     |    6 ++++-
 arch/arm/mm/proc-v7.S     |   14 +++++++----
 3 files changed, 44 insertions(+), 28 deletions(-)
arch/arm/kernel/suspend.c +30 -22
index 1794cc3..073601e 100644
@@ -10,28 +10,7 @@
 extern int __cpu_suspend(unsigned long, int (*)(unsigned long));
 extern void cpu_resume_mmu(void);
 
-/*
- * This is called by __cpu_suspend() to save the state, and do whatever
- * flushing is required to ensure that when the CPU goes to sleep we have
- * the necessary data available when the caches are not searched.
- */
-void __cpu_suspend_save(u32 *ptr, u32 ptrsz, u32 sp, u32 *save_ptr)
-{
-	*save_ptr = virt_to_phys(ptr);
-
-	/* This must correspond to the LDM in cpu_resume() assembly */
-	*ptr++ = virt_to_phys(idmap_pgd);
-	*ptr++ = sp;
-	*ptr++ = virt_to_phys(cpu_do_resume);
-
-	cpu_do_suspend(ptr);
-
-	flush_cache_all();
-	outer_clean_range(*save_ptr, *save_ptr + ptrsz);
-	outer_clean_range(virt_to_phys(save_ptr),
-			  virt_to_phys(save_ptr) + sizeof(*save_ptr));
-}
-
+#ifdef CONFIG_MMU
 /*
  * Hide the first two arguments to __cpu_suspend - these are an implementation
  * detail which platform code shouldn't have to know about.
@@ -58,3 +37,32 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
 
 	return ret;
 }
+#else
+int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
+{
+	return __cpu_suspend(arg, fn);
+}
+#define	idmap_pgd	NULL
+#endif
+
+/*
+ * This is called by __cpu_suspend() to save the state, and do whatever
+ * flushing is required to ensure that when the CPU goes to sleep we have
+ * the necessary data available when the caches are not searched.
+ */
+void __cpu_suspend_save(u32 *ptr, u32 ptrsz, u32 sp, u32 *save_ptr)
+{
+	*save_ptr = virt_to_phys(ptr);
+
+	/* This must correspond to the LDM in cpu_resume() assembly */
+	*ptr++ = virt_to_phys(idmap_pgd);
+	*ptr++ = sp;
+	*ptr++ = virt_to_phys(cpu_do_resume);
+
+	cpu_do_suspend(ptr);
+
+	flush_cache_all();
+	outer_clean_range(*save_ptr, *save_ptr + ptrsz);
+	outer_clean_range(virt_to_phys(save_ptr),
+			  virt_to_phys(save_ptr) + sizeof(*save_ptr));
+}
arch/arm/mm/proc-v6.S +5 -1
index 5900cd5..2f702fd 100644
@@ -136,8 +136,10 @@ ENTRY(cpu_v6_set_pte_ext)
 ENTRY(cpu_v6_do_suspend)
 	stmfd	sp!, {r4 - r9, lr}
 	mrc	p15, 0, r4, c13, c0, 0	@ FCSE/PID
+#ifdef CONFIG_MMU
 	mrc	p15, 0, r5, c3, c0, 0	@ Domain ID
 	mrc	p15, 0, r6, c2, c0, 1	@ Translation table base 1
+#endif
 	mrc	p15, 0, r7, c1, c0, 1	@ auxiliary control register
 	mrc	p15, 0, r8, c1, c0, 2	@ co-processor access control
 	mrc	p15, 0, r9, c1, c0, 0	@ control register
@@ -154,14 +156,16 @@ ENTRY(cpu_v6_do_resume)
 	mcr	p15, 0, ip, c13, c0, 1	@ set reserved context ID
 	ldmia	r0, {r4 - r9}
 	mcr	p15, 0, r4, c13, c0, 0	@ FCSE/PID
+#ifdef CONFIG_MMU
 	mcr	p15, 0, r5, c3, c0, 0	@ Domain ID
 	ALT_SMP(orr	r1, r1, #TTB_FLAGS_SMP)
 	ALT_UP(orr	r1, r1, #TTB_FLAGS_UP)
 	mcr	p15, 0, r1, c2, c0, 0	@ Translation table base 0
 	mcr	p15, 0, r6, c2, c0, 1	@ Translation table base 1
+	mcr	p15, 0, ip, c2, c0, 2	@ TTB control register
+#endif
 	mcr	p15, 0, r7, c1, c0, 1	@ auxiliary control register
 	mcr	p15, 0, r8, c1, c0, 2	@ co-processor access control
-	mcr	p15, 0, ip, c2, c0, 2	@ TTB control register
 	mcr	p15, 0, ip, c7, c5, 4	@ ISB
 	mov	r0, r9			@ control register
 	b	cpu_resume_mmu
arch/arm/mm/proc-v7.S +9 -5
index 0404ccb..5903ceb 100644
@@ -98,9 +98,11 @@ ENTRY(cpu_v7_do_suspend)
 	mrc	p15, 0, r4, c13, c0, 0	@ FCSE/PID
 	mrc	p15, 0, r5, c13, c0, 3	@ User r/o thread ID
 	stmia	r0!, {r4 - r5}
+#ifdef CONFIG_MMU
 	mrc	p15, 0, r6, c3, c0, 0	@ Domain ID
 	mrc	p15, 0, r7, c2, c0, 1	@ TTB 1
 	mrc	p15, 0, r11, c2, c0, 2	@ TTB control register
+#endif
 	mrc	p15, 0, r8, c1, c0, 0	@ Control register
 	mrc	p15, 0, r9, c1, c0, 1	@ Auxiliary control register
 	mrc	p15, 0, r10, c1, c0, 2	@ Co-processor access control
@@ -110,13 +112,14 @@ ENDPROC(cpu_v7_do_suspend)
 
 ENTRY(cpu_v7_do_resume)
 	mov	ip, #0
-	mcr	p15, 0, ip, c8, c7, 0	@ invalidate TLBs
 	mcr	p15, 0, ip, c7, c5, 0	@ invalidate I cache
 	mcr	p15, 0, ip, c13, c0, 1	@ set reserved context ID
 	ldmia	r0!, {r4 - r5}
 	mcr	p15, 0, r4, c13, c0, 0	@ FCSE/PID
 	mcr	p15, 0, r5, c13, c0, 3	@ User r/o thread ID
 	ldmia	r0, {r6 - r11}
+#ifdef CONFIG_MMU
+	mcr	p15, 0, ip, c8, c7, 0	@ invalidate TLBs
 	mcr	p15, 0, r6, c3, c0, 0	@ Domain ID
 #ifndef CONFIG_ARM_LPAE
 	ALT_SMP(orr	r1, r1, #TTB_FLAGS_SMP)
@@ -125,14 +128,15 @@ ENTRY(cpu_v7_do_resume)
 	mcr	p15, 0, r1, c2, c0, 0	@ TTB 0
 	mcr	p15, 0, r7, c2, c0, 1	@ TTB 1
 	mcr	p15, 0, r11, c2, c0, 2	@ TTB control register
-	mrc	p15, 0, r4, c1, c0, 1	@ Read Auxiliary control register
-	teq	r4, r9			@ Is it already set?
-	mcrne	p15, 0, r9, c1, c0, 1	@ No, so write it
-	mcr	p15, 0, r10, c1, c0, 2	@ Co-processor access control
 	ldr	r4, =PRRR		@ PRRR
 	ldr	r5, =NMRR		@ NMRR
 	mcr	p15, 0, r4, c10, c2, 0	@ write PRRR
 	mcr	p15, 0, r5, c10, c2, 1	@ write NMRR
+#endif	/* CONFIG_MMU */
+	mrc	p15, 0, r4, c1, c0, 1	@ Read Auxiliary control register
+	teq	r4, r9			@ Is it already set?
+	mcrne	p15, 0, r9, c1, c0, 1	@ No, so write it
+	mcr	p15, 0, r10, c1, c0, 2	@ Co-processor access control
 	isb
 	dsb
 	mov	r0, r8			@ control register
Signature · 1 line
1.7.4.1
#5 lore raw

PATCH 5/6 ARM: nommu: Use VECTORS_BASE for vector copying with !MMU

In reply to Will Deacon

From: Jonathan Austin <[email protected]>

When compiling with !CONFIG_MMU the vectors_page pointer does not get initialised. In the high vectors case, this results in copying to the wrong address (0x0) and hence a failure to boot.

This patch instead uses CONFIG_VECTORS_BASE as the destination address when !CONFIG_MMU.

---
 arch/arm/kernel/traps.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
arch/arm/kernel/traps.c +1 -1
index f84dfe6..f1ab393 100644
@@ -786,7 +786,7 @@ static void __init kuser_get_tls_init(unsigned long vectors)
 
 void __init early_trap_init(void)
 {
-#if defined(CONFIG_CPU_USE_DOMAINS)
+#if defined(CONFIG_CPU_USE_DOMAINS) || !defined(CONFIG_MMU)
 	unsigned long vectors = CONFIG_VECTORS_BASE;
 #else
 	unsigned long vectors = (unsigned long)vectors_page;
Signature · 1 line
1.7.4.1
#6 lore raw

PATCH 6/6 ARM: mm: truncate memory banks to fit in 4GB space for classic MMU

In reply to Will Deacon

If a bank of memory spanning the 4GB boundary is added on a !CONFIG_LPAE kernel then we will hang early during boot since the memory bank will have wrapped around to zero.

This patch truncates memory banks for !LPAE configurations when the end address is not representable in 32 bits.

---
 arch/arm/kernel/setup.c |   11 ++++++++++-
 1 files changed, 10 insertions(+), 1 deletions(-)
arch/arm/kernel/setup.c +10 -1
index a255c39..aeaa048 100644
@@ -521,7 +521,16 @@ int __init arm_add_memory(phys_addr_t start, unsigned long size)
 	 */
 	size -= start & ~PAGE_MASK;
 	bank->start = PAGE_ALIGN(start);
-	bank->size  = size & PAGE_MASK;
+
+#ifndef CONFIG_LPAE
+	if (bank->start + size < bank->start) {
+		printk(KERN_CRIT "Truncating memory at 0x%08llx to fit in "
+			"32-bit physical address space\n", (long long)start);
+		size = ULONG_MAX - bank->start;
+	}
+#endif
+
+	bank->size = size & PAGE_MASK;
 
 	/*
 	 * Check whether this memory region has non-zero size or
Signature · 1 line
1.7.4.1
#7 lore raw

PATCH 6/6 ARM: mm: truncate memory banks to fit in 4GB space for classic MMU

Hello.

Quoted 17 lines · Will Deacon

If a bank of memory spanning the 4GB boundary is added on a !CONFIG_LPAE kernel then we will hang early during boot since the memory bank will have wrapped around to zero.

This patch truncates memory banks for !LPAE configurations when the end address is not representable in 32 bits.

---
  arch/arm/kernel/setup.c |   11 ++++++++++-
  1 files changed, 10 insertions(+), 1 deletions(-)
arch/arm/kernel/setup.c +0 -0
index a255c39..aeaa048 100644

arch/arm/kernel/setup.c int __init arm_add_memory(phys_addr_t start, unsigned long size) · line 529

Quoted 10 lines
arch/arm/kernel/setup.c +6 -1
@@ -521,7 +521,16 @@ int __init arm_add_memory(phys_addr_t start, unsigned long size)
  	 */
  	size -= start&  ~PAGE_MASK;
  	bank->start = PAGE_ALIGN(start);
-	bank->size  = size&  PAGE_MASK;
+
+#ifndef CONFIG_LPAE
+	if (bank->start + size<  bank->start) {
+		printk(KERN_CRIT "Truncating memory at 0x%08llx to fit in "
+			"32-bit physical address space\n", (long long)start);
+		size = ULONG_MAX - bank->start;

I think you forgot to add one here.

WBR, Sergei

#8 lore raw

PATCH 6/6 ARM: mm: truncate memory banks to fit in 4GB space for classic MMU

Quoted 1 line · Sergei Shtylyov

Hello.

Hi Sergei,

Quoted 23 lines · Will Deacon
Quoted 22 lines

If a bank of memory spanning the 4GB boundary is added on a !CONFIG_LPAE kernel then we will hang early during boot since the memory bank will have wrapped around to zero.

This patch truncates memory banks for !LPAE configurations when the end address is not representable in 32 bits.

---
  arch/arm/kernel/setup.c |   11 ++++++++++-
  1 files changed, 10 insertions(+), 1 deletions(-)
arch/arm/kernel/setup.c +0 -1
index a255c39..aeaa048 100644
@@ -521,7 +521,16 @@ int __init arm_add_memory(phys_addr_t start, unsigned long size)
  	 */
  	size -= start&  ~PAGE_MASK;
  	bank->start = PAGE_ALIGN(start);
-	bank->size  = size&  PAGE_MASK;
Quoted 8 lines

arch/arm/kernel/setup.c int __init arm_add_memory(phys_addr_t start, unsigned long size) · line 529

Quoted 6 lines
arch/arm/kernel/setup.c +6 -0
+
+#ifndef CONFIG_LPAE
+	if (bank->start + size<  bank->start) {
+		printk(KERN_CRIT "Truncating memory at 0x%08llx to fit in "
+			"32-bit physical address space\n", (long long)start);
+		size = ULONG_MAX - bank->start;

I think you forgot to add one here.

No, I deliberately omit the last page because otherwise we end up with the end address of the bank being calculated as 0, which leads to boot failure.

Will

#9 lore raw

PATCH 6/6 ARM: mm: truncate memory banks to fit in 4GB space for classic MMU

Quoted 37 lines · Will Deacon
Quoted 1 line · Sergei Shtylyov

Hello.

Hi Sergei,

Quoted 23 lines · Will Deacon
Quoted 22 lines

If a bank of memory spanning the 4GB boundary is added on a !CONFIG_LPAE kernel then we will hang early during boot since the memory bank will have wrapped around to zero.

This patch truncates memory banks for !LPAE configurations when the end address is not representable in 32 bits.

---
  arch/arm/kernel/setup.c |   11 ++++++++++-
  1 files changed, 10 insertions(+), 1 deletions(-)
arch/arm/kernel/setup.c +0 -1
index a255c39..aeaa048 100644
@@ -521,7 +521,16 @@ int __init arm_add_memory(phys_addr_t start, unsigned long size)
  	 */
  	size -= start&  ~PAGE_MASK;
  	bank->start = PAGE_ALIGN(start);
-	bank->size  = size&  PAGE_MASK;
Quoted 8 lines

arch/arm/kernel/setup.c int __init arm_add_memory(phys_addr_t start, unsigned long size) · line 529

Quoted 6 lines
arch/arm/kernel/setup.c +6 -0
+
+#ifndef CONFIG_LPAE
+	if (bank->start + size<  bank->start) {
+		printk(KERN_CRIT "Truncating memory at 0x%08llx to fit in "
+			"32-bit physical address space\n", (long long)start);
+		size = ULONG_MAX - bank->start;

I think you forgot to add one here.

Quoted 2 lines

No, I deliberately omit the last page because otherwise we end up with the end address of the bank being calculated as 0, which leads to boot failure.

What this mentioned in the code, or at least in the patch log?

Nicolas

#10 lore raw

PATCH 6/6 ARM: mm: truncate memory banks to fit in 4GB space for classic MMU

Hi Nicolas,

Quoted 12 lines · Nicolas Pitre
Quoted 11 lines · Will Deacon
Quoted 9 lines · Sergei Shtylyov

arch/arm/kernel/setup.c int __init arm_add_memory(phys_addr_t start, unsigned long size) · line 529

Quoted 5 lines · Will Deacon
arch/arm/kernel/setup.c +5 -0
+#ifndef CONFIG_LPAE
+	if (bank->start + size<  bank->start) {
+		printk(KERN_CRIT "Truncating memory at 0x%08llx to fit in "
+			"32-bit physical address space\n", (long long)start);
+		size = ULONG_MAX - bank->start;

I think you forgot to add one here.

Quoted 4 lines
Quoted 2 lines

No, I deliberately omit the last page because otherwise we end up with the end address of the bank being calculated as 0, which leads to boot failure.

What this mentioned in the code, or at least in the patch log?

Good idea - I'll add a comment to the code when we assign size.

Will