分类: LINUX
2011-02-22 21:32:24
ARM linux 内核启动分析(2) [原创 2007-06-11 10:50:25]
Author: jimmy.li
Date:
2007-06-08
--------------------------------------
分支1:__lookup_processor_type函数分析
内核中使用了一个结构struct proc_info_list,用来记录处理器相关的信息,该结构定义在kernel/include/asm-arm/procinfo.h头文件中。
/* arch/arm/kernel/head-armv.S
*/ /* * Note! struct processor is always defined if we're * using MULTI_CPU, otherwise this entry is unused, * but still exists. * * NOTE! The following structure is defined by assembly * language, NOT C code. For more information, check: * arch/arm/mm/proc-*.S and arch/arm/kernel/head-armv.S */ struct proc_info_list { unsigned int cpu_val; unsigned int cpu_mask; unsigned long __cpu_mmu_flags; /* used by head-armv.S */ unsigned long __cpu_flush; /* used by head-armv.S */ const char *arch_name; const char *elf_name; unsigned int elf_hwcap; struct proc_info_item *info; struct processor *proc; }; |
/* arch/arm/mm/proc-xscale.S
*/ 1027 .section ".proc.info", #alloc,
#execinstr 1028 1029 .type
__80200_proc_info,#object 1030 __80200_proc_info: //每一个__xxx_proc_info就对应于proc_info_list 1031 .long 0x69052000 //cpu_val 1032 .long 0xfffffff0
//cpu_mask 1033 #if
CACHE_WRITE_THROUGH 1034 .long 0x 1035 #else 1036 .long 0x 1037 #endif 1038 b __xscale_setup //__cpu_flush 1039 .long cpu_arch_name //arch_name 1040 .long cpu_elf_name //elf_name 1041 .long
HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT| 1042 .long cpu_80200_info // info 1043 .long xscale_processor_functions //proc 1044 .size __80200_proc_info, . -
__80200_proc_info 1045 ….
1096 1097 .type
__bva0_proc_info,#object 1098 __bva0_proc_info: //pxa270 的proc_info_list 1099 .long
0x69054110 @ Bulverde A0:
0x69054110, A1 : 0x69054111. 1100 .long
0xfffffff0 @ and this is
the CPU id mask. 1101 #if
CACHE_WRITE_THROUGH 1102 .long
0x 1103 #else 1104 .long
0x 1105 #endif 1106 b
__xscale_setup 1107 .long
cpu_arch_name 1108 .long
cpu_elf_name 1109 .long
HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT| 1110 .long
cpu_bva0_info 1111 .long
xscale_processor_functions 1112 .size
__bva0_proc_info, . -
__bva0_proc_info |
在上述code中,由于定义了section,因此__bva0_proc_info等在编译时会放入.proc.info section中。根据vmlinux-armv.lds,__arch_info_begin与__arch_info_end就分别指向.proc.info section的起始和结束,换句话说,在__arrch_info_begin与__arch_info_end所指向的区域,包含着若干个proc_info_list结构的数据。这个会在__lookup_processor_type中用到,下面来看一下__lookup_processor_type这个分支代码。
/* arch/arm/kernel/head-armv.S
*/
477 __lookup_processor_type:
478 adr r5, 479 ldmia r5, {r7, r9, r10} //r7 =
__proc_info_end // r9 = __proc_info_begin //
r10 = 标号2(行498)的地址
480 sub r5, r5, r10 @ convert
addresses
481 add r7, r7, r5 @ to our address
space
482 add r10, r9, r5
483 mrc p15, 0, r9, c0, c0 @ get processor
id
484 1: ldmia r10,
{r5, r6, r8} @ value, mask,
mmuflags
485 and r6, r6, r9 @ mask wanted
bits
486 teq r5, r6
487 moveq pc, lr
488 add r10, r10, #36 @
sizeof(proc_info_list)
489 cmp r10, r7
490 blt 1b
491 mov r10, #0 @ unknown
processor 492 mov pc, lr 493 494 /* 495
* Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch]
for 496
* more information about the __proc_info and __arch_info
structures. 497
*/ 498 2: .long __proc_info_end 499 .long __proc_info_begin 500 .long 2b 501 .long __arch_info_begin 502 .long __arch_info_end |
Line478:将line498的地址放到寄存器r5中,adr是小范围的地址读取伪指令。
Line479:将r5所指向的数据区的数据读出到r7,r9,r10。结果就是r7= __proc_info_end,r9 = __proc_info_begin, r10 = 标号2(line498)的地址。
Line480~482:r10 = __proc_info_begin。
Line483:mrc是一个协处理器寄存器到ARM寄存器的数据传送指令,它的指令格式是:MRC coproc, opcode1, Rd, CRn {, opcode2} 对于读取Processor ID来说,coproc 为15,opcode1为0, CRn=0, opcode2=0。Line483读取processor ID,并放入r9寄存器中。
Line484~490,是一个循环处理过程,由于r10一开始是指向__proc_info_begin的,前面提到__proc_info_begin指向.proc.info section的首地址,所以整个循环就是遍历.proc.info section,也就是遍历proc_info_list结构数组,比较(proc_info_list[i]->cpu_val == processor ID & proc_info_list[i]->cpu_mask)是否与当前运行的processor ID一致,如果有条件满足的则函数在line487返回(跳转到line189),此时r10是不为零的(因为函数返回后,要根据r10是否为0,来判断processor未知与否);如果遍历完整个.proc.info section都不满足的,则进入line491。
Line491~492:置r10=0用来表示processor 未知,然后函数返回(跳转到line189)。