分类:
2008-03-26 17:37:06
ARM LINUX启动代码笔记―――启动
Kernel
S
内核的入口为stext
位置在文件/arch/arm/kernel/head.S
...
.section
".text.head", "ax"
.type stext, %function
ENTRY(stext)
....
vmlinux.lds.S把ENTRY值为stext
/arch/arm/kernel/vmlinux.lds.S
.....
OUTPUT_ARCH(arm)
ENTRY(stext)
.....
下面看文件/arch/arm/kernel/head.S
....
.section
".text.head", "ax"
.type stext, %function
ENTRY(stext)
msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @
ensure svc mode
@
and irqs disabled
mrc p15, 0, r9, c0, c0 @ get processor id
bl __lookup_processor_type @ r5=procinfo r9=cpuid
movs r10, r5 @
invalid processor (r5=0)?
beq __error_p @
yes, error 'p'
bl __lookup_machine_type @ r5=machinfo
movs r8, r5 @
invalid machine (r5=0)?
beq __error_a @
yes, error 'a'
bl __create_page_tables
/*
* The following calls CPU specific code in a
position independent
* manner.
See arch/arm/mm/proc-*.S for details.
r10 = base of
* xxx_proc_info structure selected by __lookup_machine_type(注释错误)
* above.
On return, the CPU will be ready for the MMU to be
* turned on, and r0 will hold the CPU control
register value.
*/
ldr r13, __switch_data @ address to jump to after
@
mmu has been enabled
adr lr, __enable_mmu @ return (PIC) address
add pc, r10, #PROCINFO_INITFUNC
...
stext代码主要进行如下操作
1.禁止中断
2.获取CPU型号
3.获取machine类型
4.创建页表
5.Enable MMU
6.程序跳到r10+PROCINFO_INITFUNC
认真看了代码,比较有趣
2.获取CPU型号
文件/arch/arm/kernel/head-common.S
.type __lookup_processor_type, %function
__lookup_processor_type:
adr r3,
ldmda r3, {r5 - r7}
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
add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list)
cmp r5, r6
blo 1b
mov r5, #0 @
unknown processor
2: mov pc, lr
一句句来看
adr r3,
/arch/arm/kernel/head-common.S
….
* Look in
include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for
* more information about the __proc_info and
__arch_info structures.
*/
.long __proc_info_begin
.long __proc_info_end
3: .long .
.long __arch_info_begin
.long __arch_info_end
…
r3就指到
3: .long .
接下来
ldmda r3, {r5 - r7}
sub r3, r3, r7 @
get offset between virt&phys
add r5, r5, r3 @
convert virt addresses to
add r6, r6, r3 @
physical address space
r7 = [r3]
r6 = [r3-4] 即为__proc_info_end
r5 = [r3-8] 即为__proc_info_begin
接着VA转化为PA
sub r3, r3, r7 @
get offset between virt&phys
add r5, r5, r3 @
convert virt addresses to
add r6, r6, r3 @
physical address space
在__proc_info_begin查找与r9相符合的CPU,r5指向该PROC_INFO,然后返回
movs r10, r5 @
invalid processor (r5=0)?
把r5保存到r10中
3.获取machine类型
bl __lookup_machine_type @ r5=machinfo
与__lookup_processor_type类似
4.创建页表
以后分析
5.Enable
MMU
ldr r13, __switch_data @ address to jump to after
@
mmu has been enabled
adr lr, __enable_mmu @ return (PIC) address
a. r13指向__switch_data,即指向 .long __mmap_switched
__switch_data在/arch/arm/kernel/head-common.S
...
.type __switch_data, %object
__switch_data:
.long __mmap_switched
.long __data_loc @ r4
.long __data_start @ r5
.long __bss_start @ r6
.long _end @
r7
.long processor_id @ r4
.long __machine_arch_type @ r5
.long cr_alignment @ r6
.long init_thread_union + THREAD_START_SP @ sp
...
b.lr 指向__enable_mmu
6.程序跳到r10+PROCINFO_INITFUNC
/arch/arm/mm/proc-arm920.S
….
.section
".proc.info.init", #alloc, #execinstr
.type __arm920_proc_info,#object
__arm920_proc_info:
.long 0x41009200
.long 0xff00fff0
.long PMD_TYPE_SECT | \
PMD_SECT_BUFFERABLE
| \
PMD_SECT_CACHEABLE
| \
PMD_BIT4
| \
PMD_SECT_AP_WRITE
| \
PMD_SECT_AP_READ
.long PMD_TYPE_SECT | \
PMD_BIT4
| \
PMD_SECT_AP_WRITE
| \
PMD_SECT_AP_READ
b __arm920_setup
…
/arch/arm/kernel/head.S中
add pc, r10, #PROCINFO_INITFUNC
即把PC指到b __arm920_setup
7.执行__arm920_setup
/arch/arm/mm/proc-arm920.S
…
.type __arm920_setup, #function
__arm920_setup:
mov r0, #0
mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
#endif
adr r5, arm920_crval
ldmia r5, {r5, r6}
mrc p15, 0, r0, c1, c0 @ get control register v4
bic r0, r0, r5
orr r0, r0, r6
mov pc, lr
…
做一些设置后,把lr赋给pc.
lr指向 adr lr, __enable_mmu @ return (PIC) address
8.执行__enable_mmu
/arch/arm/kernel/head.S中
…
.type __enable_mmu, %function
__enable_mmu:
#ifdef CONFIG_ALIGNMENT_TRAP
orr r0, r0, #CR_A
#else
bic r0, r0, #CR_A
#endif
#ifdef CONFIG_CPU_DCACHE_DISABLE
bic r0, r0, #CR_C
#endif
#ifdef CONFIG_CPU_BPREDICT_DISABLE
bic r0, r0, #CR_Z
#endif
#ifdef CONFIG_CPU_ICACHE_DISABLE
bic r0, r0, #CR_I
#endif
mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) |
\
domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER)
| \
domain_val(DOMAIN_TABLE, DOMAIN_MANAGER)
| \
domain_val(DOMAIN_IO, DOMAIN_CLIENT))
mcr p15, 0, r5, c3, c0, 0 @ load domain access register
mcr p15, 0, r4, c2, c0, 0 @ load page table pointer
b __turn_mmu_on
…
设置一下MMU,跳转到 b __turn_mmu_on
9.执行__turn_mmu_on
中
…
.type __turn_mmu_on, %function
__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
…
最好pc指向r13,即指向 ldr r13, __switch_data @ address to jump to after
最终执行__mmap_switched
10.执行__mmap_switched
/arch/arm/kernel/head-common.S中
.type __mmap_switched, %function
__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, sp}
str r9, [r4] @
Save processor ID
str r1, [r5] @
Save machine type
bic r4, r0, #CR_A @
Clear 'A' bit
stmia r6, {r0, r4} @ Save control register values
b start_kernel
最后调用start_kernel