微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > arm linux kernel 从入口到start_kernel 的代码分析

arm linux kernel 从入口到start_kernel 的代码分析

时间:11-09 来源:互联网 点击:

1. 确定 processor type

arch/arm/kernel/head.S中:
75: mrc p15, 0, r9, c0, c0 @ get processor id
76: bl __lookup_processor_type @ r5=procinfo r9=cpuid
77: movs r10, r5 @ invalid processor (r5=0)?
78: beq __error_p @ yes, error p
75行: 通过cp15协处理器的c0寄存器来获得processor id的指令. 关于cp15的详细内容可参考相关的arm手册
76行: 跳转到__lookup_processor_type.在__lookup_processor_type中,会把processor type 存储在r5中
77,78行: 判断r5中的processor type是否是0,如果是0,说明是无效的processor type,跳转到__error_p(出错)
__lookup_processor_type 函数主要是根据从cpu中获得的processor id和系统中的proc_info进行匹配,将匹配到的proc_info_list的基地址存到r5中, 0表示没有找到对应的processor type.
下面我们分析__lookup_processor_type函数
arch/arm/kernel/head-common.S中:
00145: .type __lookup_processor_type, %function
00146: __lookup_processor_type:
00147: adr r3, 3f
00148: ldmda r3, {r5 - r7}
00149: sub r3, r3, r7 @ get offset between virt&phys
00150: add r5, r5, r3 @ convert virt addresses to
00151: add r6, r6, r3 @ physical address space
00152: 1: ldmia r5, {r3, r4} @ value, mask
00153: and r4, r4, r9 @ mask wanted bits
00154: teq r3, r4
00155: beq 2f
00156: add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list)
00157: cmp r5, r6
00158: blo 1b
00159: mov r5, #0 @ unknown processor
00160: 2: mov pc, lr
00161:
00162: /*
00163: * This provides a C-API version of the above function.
00164: */
00165: ENTRY(lookup_processor_type)
00166: stmfd sp!, {r4 - r7, r9, lr}
00167: mov r9, r0
00168: bl __lookup_processor_type
00169: mov r0, r5
00170: ldmfd sp!, {r4 - r7, r9, pc}
00171:
00172: /*
00173: * Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for
00174: * more information about the __proc_info and __arch_info structures.
00175: */
00176: .long __proc_info_begin
00177: .long __proc_info_end
00178: 3: .long .
00179: .long __arch_info_begin
00180: .long __arch_info_end
145, 146行是函数定义
147行: 取地址指令,这里的3f是向前symbol名称是3的位置,即第178行,将该地址存入r3.
这里需要注意的是,adr指令取址,获得的是基于pc的一个地址,要格外注意,这个地址是3f处的"运行时地址", 由于此时MMU还没有打开,也可以理解成物理地址(实地址).(详细内容可参考arm指令手册)
148行: 因为r3中的地址是178行的位置的地址,因而执行完后: (ldmda表示栈指针递减,即r3递减,内存的地址编号较大的对应寄存器编号较大的)
r5存的是176行符号 __proc_info_begin的地址;
r6存的是177行符号 __proc_info_end的地址;
r7存的是3f处的地址.
这里需要注意链接地址和运行时地址的区别. r3存储的是运行时地址(物理地址),而r7中存储的是链接地址(虚拟地址).
__proc_info_begin和__proc_info_end是在arch/arm/kernel/vmlinux.lds.S中:
31: __proc_info_begin = .;
32: *(.proc.info.init)
33: __proc_info_end = .;
这里是声明了两个变量:__proc_info_begin 和 __proc_info_end,其中等号后面的"."是location counter(详细内容请参考ld.info)
这三行的意思是: __proc_info_begin 的位置上,放置所有文件中的 ".proc.info.init" 段的内容,然后紧接着是 __proc_info_end 的位置.
kernel 使用struct proc_info_list来描述processor type.
在 include/asm-arm/procinfo.h 中:
29: struct proc_info_list {
30: unsigned int cpu_val;
31: unsigned int cpu_mask;
32: unsigned long __cpu_mm_mmu_flags; /* used by head.S */
33: unsigned long __cpu_io_mmu_flags; /* used by head.S */
34: unsigned long __cpu_flush; /* used by head.S */
35: const char *arch_name;
36: const char *elf_name;
37: unsigned int elf_hwcap;
38: const char *cpu_name;
39: struct processor *proc;
40: struct cpu_tlb_fns *tlb;
41: struct cpu_user_fns *user;
42: struct cpu_cache_fns *cache;
43: };
我们当前以at91为例,其processor是926的.
在arch/arm/mm/proc-arm926.S 中:
00464: .section ".proc.info.init", #alloc, #execinstr
00465:
00466: .type __arm926_proc_info,#object
00467: __arm926_proc_info:
00468: .long 0x41069260 @ ARM926EJ-S (v5TEJ)
00469: .long 0xff0ffff0
00470: .long PMD_TYPE_SECT \
00471: PMD_SECT_BUFFERABLE \
00472: PMD_SECT_CACHEABLE \
00473: PMD_BIT4 \
00474: PMD_SECT_AP_WRITE \
00475: PMD_SECT_AP_READ
00476: .long PMD_TYPE_SECT \
00477: PMD_BIT4 \
00478: PMD_SECT_AP_WRITE \
00479: PMD_SECT_AP_READ
00480: b __arm926_setup
00481: .long cpu_arch_name
00482: .long cpu_elf_name
00483: .long HWCAP_SWPHWCAP_HALFHWCAP_THUMBHWCAP_FAST_MULTHWCAP_VFPHWCAP_E

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top