1.如果内核镜像是压缩的,需要解压缩,引导的第一步是从解压缩开始:arch\arm\boot\compressed\head.S
2.解压缩之后,内核镜像已经存在于ARM中了,下面开始运行,内核开始运行是从/arch/arm/kernel/head.S开始的,入口代码为:
1
2
3
4
5
6
7
8
|
.arm
__HEAD
ENTRY(stext)
THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered
in
ARM.
THUMB( bx r9 ) @ If this is a Thumb-2 kernel,
THUMB( .thumb ) @ switch to Thumb now.
THUMB(1: )
|
这是由/arch/arm/kernel/vmlinux.lds.S决定的。告诉我们入口点为stext.
1
2
|
OUTPUT_ARCH(arm)
ENTRY(stext)
|
3.顺序执行head.S的代码。
1
2
3
4
5
6
7
8
|
ldr r13, =__switch_data @ address to jump to after
@ mmu has been enabled
adr lr, BSYM(1f) @
return
(PIC) address
mov r8, r4 @ set TTBR1 to swapper_pg_dir
ARM( add pc, r10, #PROCINFO_INITFUNC )
THUMB( add r12, r10, #PROCINFO_INITFUNC )
THUMB( mov pc, r12 )
1: b __enable_mmu
|
代码line1将__switch_data的地址赋给r13,在__enable_mmu(代码line8)执行成功后跳转到__switch_data执行。
因为是.arm环境,所以执行代码ARM( add pc, r10, #PROCINFO_INITFUNC ),即跳转到__cpu_flush执行。
1
2
3
4
|
/arch/arm/kernel/head.S
mrc p15, 0, r9, c0, c0 @ get processor id
bl __lookup_processor_type @ r5=procinfo r9=cpuid
movs r10, r5 @ invalid processor (r5=0)?
|
r10中保存的是proc_info结构体的start address.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
arch\arm\include\asm\Procinfo.h
struct
proc_info_list {
unsigned
int
cpu_val;
unsigned
int
cpu_mask;
unsigned
long
__cpu_mm_mmu_flags;
/* used by head.S */
unsigned
long
__cpu_io_mmu_flags;
/* used by head.S */
unsigned
long
__cpu_flush;
/* used by head.S */
const
char
*arch_name;
const
char
*elf_name;
unsigned
int
elf_hwcap;
const
char
*cpu_name;
struct
processor *proc;
struct
cpu_tlb_fns *tlb;
struct
cpu_user_fns *user;
struct
cpu_cache_fns *cache;
};
|
1
2
|
include/generated/asm-offsets.h
#define PROCINFO_INITFUNC 16
|
4.__cpu_flush
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
arch/arm/mm/proc-v7.S
__v7_ca9mp_proc_info:
.
long
0x410fc090
.
long
0xff0ffff0
__v7_proc __v7_ca9mp_setup
.macro __v7_proc initfunc, mm_mmuflags = 0, io_mmuflags = 0, hwcaps = 0
ALT_SMP(.
long
PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \
PMD_SECT_AF | PMD_FLAGS_SMP | \mm_mmuflags)
ALT_UP(.
long
PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \
PMD_SECT_AF | PMD_FLAGS_UP | \mm_mmuflags)
.
long
PMD_TYPE_SECT | PMD_SECT_AP_WRITE | \
PMD_SECT_AP_READ | PMD_SECT_AF | \io_mmuflags
W(b) \initfunc
__v7_ca5mp_setup:
__v7_ca9mp_setup:
mov r10, #(1 << 0) @ TLB ops broadcasting
b 1f
__v7_ca7mp_setup:
__v7_ca15mp_setup:
mov r10, #0
|
不同架构的CPU,针对的文件不同,对于ARMV7架构的cpu而言,对应的为proc-v7.S。从code中可以看出,其对应俄proc_info为__v7_ca9mp_proc_info,所以偏移16后,就是执行跳转代码 b 1f。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
__CPUINIT
/*
* __v7_setup
*
* Initialise TLB, Caches, and MMU state ready to switch the MMU
* on. Return in r0 the new CP15 C1 control register setting.
*
* This should be able to cover all ARMv7 cores.
*
* It is assumed that:
* - cache type register is implemented
*/
__v7_ca5mp_setup:
__v7_ca9mp_setup:
mov r10, #(1 << 0) @ TLB ops broadcasting
b 1f
__v7_ca7mp_setup:
__v7_ca15mp_setup:
mov r10, #0
1:
#ifdef CONFIG_SMP
ALT_SMP(mrc p15, 0, r0, c1, c0, 1)
ALT_UP(mov r0, #(1 << 6)) @ fake it
for
UP
tst r0, #(1 << 6) @ SMP/nAMP mode enabled?
orreq r0, r0, #(1 << 6) @ Enable SMP/nAMP mode
orreq r0, r0, r10 @ Enable CPU-specific SMP bits
mcreq p15, 0, r0, c1, c0, 1
#endif
__v7_setup:
|
5.__v7_setup->__enable_mmu->__turn_mmu_on
1
2
3
4
5
6
7
8
|
__turn_mmu_on:
mov r0, r0
mcr p15, 0, r0, c1, c0, 0 @ write control reg
mrc p15, 0, r3, c0, c0, 0 @ read id reg
mov r3, r3
mov r3, r3
mov pc, r13
ENDPROC(__turn_mmu_on)
|
r13保存的是__switch_data的地址,mov pc,r13跳转到__switch_data.
6.__mmap_switched
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
.type __switch_data, %object
__switch_data:
.
long
__mmap_switched
.
long
__data_loc @ r4
.
long
_data @ r5
.
long
__bss_start @ r6
.
long
_end @ r7
.
long
processor_id @ r4
.
long
__machine_arch_type @ r5
.
long
__atags_pointer @ r6
.
long
cr_alignment @ r7
.
long
init_thread_union + THREAD_START_SP @ sp
/*
* The following fragment of code is executed with the MMU on in MMU mode,
* and uses absolute addresses; this is not position independent.
*
* r0 = cp#15 control register
* r1 = machine ID
* r2 = atags pointer
* r9 = processor ID
*/
__mmap_switched:
adr r3, __switch_data + 4
ldmia r3!, {r4, r5, r6, r7}
cmp r4, r5 @ Copy data segment
if
needed
1: cmpne r5, r6
ldrne fp, [r4], #4
strne fp, [r5], #4
bne 1b
mov fp, #0 @ Clear BSS (and zero fp)
1: cmp r6, r7
strcc fp, [r6],#4
bcc 1b
ldmia r3, {r4, r5, r6, r7, sp}
str r9, [r4] @ Save processor ID
str r1, [r5] @ Save machine type
str r2, [r6] @ Save atags pointer
bic r4, r0, #CR_A @ Clear
'A'
bit
stmia r7, {r0, r4} @ Save control
register
values
b start_kernel
ENDPROC(__mmap_switched)
|
7. start_kernel, 第一个C语言函数。
原文地址:http://hi.baidu.com/wesley2012/item/dcf2cfc1b9deec14b67a24d9