summary refs log tree commit diff
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2008-08-07 22:36:59 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2008-08-07 22:36:59 +0100
commit058ddee5625ade9e9e011b9ae155ac3b8d4eda3a (patch)
tree2821d666c06733da81f606624bf2a16bdf86ce73 /arch/arm/kernel
parentafd2fc02ab7bae6062671c5ca80dd34c34a63fb7 (diff)
downloadlinux-058ddee5625ade9e9e011b9ae155ac3b8d4eda3a.tar.gz
[ARM] Fix SMP booting with non-zero PHYS_OFFSET
The existing code tries to get the pmd for the temporary page table
by doing:

        pgd = pgd_alloc(&init_mm);
        pmd = pmd_offset(pgd, PHYS_OFFSET);

Since we have a two level page table, pmd_offset() is a no-op, so
this just has a casting effect from a pgd to a pmd - the address
argument is unused.  So this can't work.

Normally, we'd do:

	pgd = pgd_offset(&init_mm, PHYS_OFFSET);
	...
	pmd = pmd_offset(pgd, PHYS_OFFSET);

to get the pmd you want.  However, pgd_offset() takes the mm_struct,
not the (unattached) pgd we just allocated.  So, instead use:

        pgd = pgd_alloc(&init_mm);
        pmd = pmd_offset(pgd + pgd_index(PHYS_OFFSET), PHYS_OFFSET);

Reported-by: Antti P Miettinen <ananaza@iki.fi>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/smp.c4
1 files changed, 2 insertions, 2 deletions
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 5a7c09564d13..e9842f6767f9 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -100,7 +100,7 @@ int __cpuinit __cpu_up(unsigned int cpu)
 	 * a 1:1 mapping for the physical address of the kernel.
 	 */
 	pgd = pgd_alloc(&init_mm);
-	pmd = pmd_offset(pgd, PHYS_OFFSET);
+	pmd = pmd_offset(pgd + pgd_index(PHYS_OFFSET), PHYS_OFFSET);
 	*pmd = __pmd((PHYS_OFFSET & PGDIR_MASK) |
 		     PMD_TYPE_SECT | PMD_SECT_AP_WRITE);
 
@@ -139,7 +139,7 @@ int __cpuinit __cpu_up(unsigned int cpu)
 	secondary_data.stack = NULL;
 	secondary_data.pgdir = 0;
 
-	*pmd_offset(pgd, PHYS_OFFSET) = __pmd(0);
+	*pmd = __pmd(0);
 	pgd_free(&init_mm, pgd);
 
 	if (ret) {