hotplug and init section
Russell King - ARM Linux
linux at arm.linux.org.uk
Wed Aug 4 13:56:11 EDT 2010
On Tue, Aug 03, 2010 at 05:51:34PM -0700, Jeff Ohlstein wrote:
> This doesn't boot for me, I will look into it further. I am using a
> 2.6.32 kernel, but I think commit
> a1c29fa34b6be6b7c1d9075f4057c3995c993e8c or "ARM: convert to use __HEAD
> and HEAD_TEXT macros" should be sufficient.
Hmm. Well, what seems to be happening is that the assembler is being
utterly stupid (we've had this kind of problem before.) Take this:
.text
nop
nop
nop
adr r0, sym
nop
nop
.data
.long 1
sym: .long 0
.long 2
As the assembler to build this (which it does successfully), and look at
the resulting object:
$ arm-linux-objdump -dr t.o
t.o: file format elf32-littlearm
Disassembly of section .text:
00000000 <.text>:
0: e1a00000 nop (mov r0,r0)
4: e1a00000 nop (mov r0,r0)
8: e1a00000 nop (mov r0,r0)
c: e24f0004 sub r0, pc, #4 ; 0x4
10: e1a00000 nop (mov r0,r0)
14: e1a00000 nop (mov r0,r0)
So, it succesfully built the object, and somehow thinks that 'sym' can
be referenced by the ADR pseudo-instruction by a PC-relative reference
even though it's in a different section an unknown distance away.
Clearly it's not just my toolchain which accepts this, but whatever
toolchain you're using as well - I'd go so far as to suggest that almost
every recent toolchain has this broken behaviour.
This is why the patch I sent you passes build testing, but doesn't
actually work - what's coming out of the assembler is utter garbage.
Here's a slightly fixed-up and refined version - but it still won't
completely fix your problem. __enable_mmu ends up still being in
the head text section, which is placed on the start of the kernel
image along with stuff to be freed. Moving this to the __cpuinit.text
section results in the function being moved outside of the 1:1 mapped
region, causing the system to crash when it tries to turn the MMU on.
I haven't worked out how to sanely sort this out yet - that in itself
is quite a horrible problem to resolve. I'm toying with the idea of
putting an assembly function before and after the __enable_mmu code
which returns the address that each of these functions is located -
and using that to ensure that we have 1:1 mappings. This just feels
like a really insane way to fix it - though I don't think changing the
layout of the cpuinit sections etc is really on either.
We could just add more 1:1 mappings and just hope that we cover the
code - but that's not going to work for really big kernels.
diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S
index b9505aa..706a6c1 100644
--- a/arch/arm/kernel/head-common.S
+++ b/arch/arm/kernel/head-common.S
@@ -143,56 +143,7 @@ __error:
b 1b
ENDPROC(__error)
-
-/*
- * Read processor ID register (CP#15, CR0), and look up in the linker-built
- * supported processor list. Note that we can't use the absolute addresses
- * for the __proc_info lists since we aren't running with the MMU on
- * (and therefore, we are not in the correct address space). We have to
- * calculate the offset.
- *
- * r9 = cpuid
- * Returns:
- * r3, r4, r6 corrupted
- * r5 = proc_info pointer in physical address space
- * r9 = cpuid (preserved)
- */
-__lookup_processor_type:
- adr r3, 3f
- ldmia r3, {r5 - r7}
- add r3, r3, #8
- sub r3, r3, r7 @ get offset between virt&phys
- add r5, r5, r3 @ convert virt addresses to
- add r6, r6, r3 @ physical address space
-1: ldmia r5, {r3, r4} @ value, mask
- and r4, r4, r9 @ mask wanted bits
- teq r3, r4
- beq 2f
- add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list)
- cmp r5, r6
- blo 1b
- mov r5, #0 @ unknown processor
-2: mov pc, lr
-ENDPROC(__lookup_processor_type)
-
-/*
- * This provides a C-API version of the above function.
- */
-ENTRY(lookup_processor_type)
- stmfd sp!, {r4 - r7, r9, lr}
- mov r9, r0
- bl __lookup_processor_type
- mov r0, r5
- ldmfd sp!, {r4 - r7, r9, pc}
-ENDPROC(lookup_processor_type)
-
-/*
- * Look in <asm/procinfo.h> and arch/arm/kernel/arch.[ch] for
- * more information about the __proc_info and __arch_info structures.
- */
.align 2
-3: .long __proc_info_begin
- .long __proc_info_end
4: .long .
.long __arch_info_begin
.long __arch_info_end
@@ -265,3 +216,54 @@ __vet_atags:
1: mov r2, #0
mov pc, lr
ENDPROC(__vet_atags)
+
+ __CPUINIT
+
+/*
+ * Read processor ID register (CP#15, CR0), and look up in the linker-built
+ * supported processor list. Note that we can't use the absolute addresses
+ * for the __proc_info lists since we aren't running with the MMU on
+ * (and therefore, we are not in the correct address space). We have to
+ * calculate the offset.
+ *
+ * r9 = cpuid
+ * Returns:
+ * r3, r4, r6 corrupted
+ * r5 = proc_info pointer in physical address space
+ * r9 = cpuid (preserved)
+ */
+__lookup_processor_type:
+ adr r3, 3f
+ ldmia r3, {r4 - r6}
+ sub r3, r3, r4 @ get offset between virt&phys
+ add r5, r5, r3 @ convert virt addresses to
+ add r6, r6, r3 @ physical address space
+1: ldmia r5, {r3, r4} @ value, mask
+ and r4, r4, r9 @ mask wanted bits
+ teq r3, r4
+ beq 2f
+ add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list)
+ cmp r5, r6
+ blo 1b
+ mov r5, #0 @ unknown processor
+2: mov pc, lr
+ENDPROC(__lookup_processor_type)
+
+/*
+ * Look in <asm/procinfo.h> more information about the __proc_info structure.
+ */
+ .align 2
+3: .long .
+ .long __proc_info_begin
+ .long __proc_info_end
+
+/*
+ * This provides a C-API version of the above function.
+ */
+ENTRY(lookup_processor_type)
+ stmfd sp!, {r4 - r6, r9, lr}
+ mov r9, r0
+ bl __lookup_processor_type
+ mov r0, r5
+ ldmfd sp!, {r4 - r6, r9, pc}
+ENDPROC(lookup_processor_type)
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index eb62bf9..c8ab09d 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -104,6 +104,7 @@ ENTRY(stext)
ENDPROC(stext)
#if defined(CONFIG_SMP)
+ __CPUINIT
ENTRY(secondary_startup)
/*
* Common entry point for secondary CPUs.
@@ -126,12 +127,13 @@ ENTRY(secondary_startup)
ldmia r4, {r5, r7, r12} @ address to jump to after
sub r4, r4, r5 @ mmu has been enabled
ldr r4, [r7, r4] @ get secondary_data.pgdir
- adr lr, BSYM(__enable_mmu) @ return address
+ adr lr, BSYM(1f) @ return address
mov r13, r12 @ __secondary_switched address
ARM( add pc, r10, #PROCINFO_INITFUNC ) @ initialise processor
@ (return control reg)
THUMB( add r12, r10, #PROCINFO_INITFUNC )
THUMB( mov pc, r12 )
+1: b __enable_mmu
ENDPROC(secondary_startup)
/*
@@ -148,6 +150,8 @@ __secondary_data:
.long .
.long secondary_data
.long __secondary_switched
+
+ __HEAD
#endif /* defined(CONFIG_SMP) */
More information about the linux-arm-kernel
mailing list