Linux 启动之__lookup_processor_type介绍
今天在看Linux的启动代码,前面看的还好理解,可是在看到arch/arm/kernel/head.S汇编文件中的__lookup_processor_type函数时出现了疑问,上网看了n多资料,大概有一些了解,此处记下来以后好方便查看,1、内核中使用了一个结构struct proc_info_list,用来记录处理器相关的信息,该结构定义在kernel/include/asm-arm/p
今天在看Linux的启动代码,前面看的还好理解,可是在看到arch/arm/kernel/head.S汇编文件中的__lookup_processor_type函数时出现了疑问,上网看了n多资料,大概有一些了解,此处记下来以后好方便查看,
1、内核中使用了一个结构struct proc_info_list,用来记录处理器相关的信息,该结构定义在kernel/include/asm-arm/procinfo.h头文件中定义。
20 /*
21 * Note! struct processor is always defined if we're
22 * using MULTI_CPU, otherwise this entry is unused,
23 * but still exists.
24 *
25 * NOTE! The following structure is defined by assembly
26 * language, NOT C code. For more information, check:
27 * arch/arm/mm/proc-*.S and arch/arm/kernel/head.S
28 */
29 struct proc_info_list {
30 unsigned int cpu_val;
31 unsigned int cpu_mask;
32 unsigned long __cpu_mmu_flags; /* used by head.S */
33 unsigned long __cpu_flush; /* used by head.S */
34 const char *arch_name;
35 const char *elf_name;
36 unsigned int elf_hwcap;
37 const char *cpu_name;
38 struct processor *proc;
39 struct cpu_tlb_fns *tlb;
40 struct cpu_user_fns *user;
41 struct cpu_cache_fns *cache;
42 };
2、在arch/arm/mm/proc-arm720.S文件中定义了所有和arm720T有关的proc_info_list,我们使用的arm720T定义如下:
221 /*
222 * See linux/include/asm-arm/procinfo.h for a definition of this structure.
223 */
224
225 .section ".proc.info.init", #alloc, #execinstr
226
227 .type __arm710_proc_info, #object
228 __arm710_proc_info:
229 .long 0x41807100 @ cpu_val
230 .long 0xffffff00 @ cpu_mask
231 .long PMD_TYPE_SECT | \
232 PMD_SECT_BUFFERABLE | \
233 PMD_SECT_CACHEABLE | \
234 PMD_BIT4 | \
235 PMD_SECT_AP_WRITE | \
236 PMD_SECT_AP_READ
237 b __arm710_setup @ cpu_flush
238 .long cpu_arch_name @ arch_name
239 .long cpu_elf_name @ elf_name
240 .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB @ elf_hwcap
241 .long cpu_arm710_name @ name
242 .long arm720_processor_functions
243 .long v4_tlb_fns
244 .long v4wt_user_fns
245 .long v4_cache_fns
246 .size __arm710_proc_info, . - __arm710_proc_info
247
248 .type __arm720_proc_info, #object
249 __arm720_proc_info:
250 .long 0x41807200 @ cpu_val
251 .long 0xffffff00 @ cpu_mask
252 .long PMD_TYPE_SECT | \
253 PMD_SECT_BUFFERABLE | \
254 PMD_SECT_CACHEABLE | \
255 PMD_BIT4 | \
256 PMD_SECT_AP_WRITE | \
257 PMD_SECT_AP_READ
258 b __arm720_setup @ cpu_flush
259 .long cpu_arch_name @ arch_name
260 .long cpu_elf_name @ elf_name
261 .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB @ elf_hwcap
262 .long cpu_arm720_name @ name
263 .long arm720_processor_functions
264 .long v4_tlb_fns
265 .long v4wt_user_fns
266 .long v4_cache_fns
267 .size __arm720_proc_info, . - __arm720_proc_info
3、由于.section指示符,上面定义的__arm720_proc_info信息在编译的时候被放到了.proc.info段中,这是由linux的链接脚本文件arch/arm/kernel/vmlinux.lds(还是vmlinux.lds.S,待确定)指定的,参考如下:
616 OUTPUT_ARCH(arm)
617 ENTRY(stext)
618 jiffies = jiffies_64;
619 SECTIONS
620 {
621 . = (0xc0000000) + 0x00008000;
622 .init : { /* Init code and data */
623 _stext = .;
624 _sinittext = .;
625 *(.init.text)
626 _einittext = .;
627 __proc_info_begin = .;
628 *(.proc.info.init)
629 __proc_info_end = .;
630 __arch_info_begin = .;
631 *(.arch.info.init)
632 __arch_info_end = .;
这里是声明了两个变量:__proc_info_begin 和 __proc_info_end,其中等号后面的"."是location counter(详细内容请参考ld.info,待了解)
这三行的意思是: __proc_info_begin 的位置上,放置所有文件中的 ".proc.info.init" 段的内容,然后紧接着是 __proc_info_end 的位置。
4、下面我们来分析 __lookup_processor_type函数,在 arch/arm/kernel/head.S文件中:
459 __lookup_processor_type:
460 adr r3, 3f
461 ldmda r3, {r5, r6, r9}
462 sub r3, r3, r9 @ get offset between virt&phys
463 add r5, r5, r3 @ convert virt addresses to
464 add r6, r6, r3 @ physical address space
465 mrc p15, 0, r9, c0, c0 @ get processor id
466 1: ldmia r5, {r3, r4} @ value, mask
467 and r4, r4, r9 @ mask wanted bits
468 teq r3, r4
469 beq 2f
470 add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list)
471 cmp r5, r6
472 blo 1b
473 mov r5, #0 @ unknown processor
474 2: mov pc, lr
475
476 /*
477 * This provides a C-API version of the above function.
478 */
479 ENTRY(lookup_processor_type)
480 stmfd sp!, {r4 - r6, r9, lr}
481 bl __lookup_processor_type
482 mov r0, r5
483 ldmfd sp!, {r4 - r6, r9, pc}
484
485 /*
486 * Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for
487 * more information about the __proc_info and __arch_info structures.
488 */
489 .long __proc_info_begin
490 .long __proc_info_end
491 3: .long .
492 .long __arch_info_begin
493 .long __arch_info_end
494
下面逐行来进行分析:
460:将491行的地址放到寄存器 r3 中,adr是小范围的地址读取伪指令。
461:将489~491行符号的地址分别存放在 r5,r6,r9寄存器, 这里需要注意链接地址和运行时地址的区别. r3存储的是运行时地址(物理地址),而r9中存储的是链接地址(虚拟地址). 这边还需继续理解
462:计算出虚实地址的偏移。
463:
464:根据偏移,从虚拟地址计算出实际的物理地址。
465:读取cpu的id,这是一个协处理器指令,将processor ID存储在r9中。
466:对照struct proc_info_list,可以得知,这句是将当前proc_info的cpu_val和cpu_mask分别存r3, r4中。(注意r5寄存器是info_begin,此处,取最前面两个变量)。
467:r9中存储了processor id(arch/arm/kernel/head.S中的465行),与r4的cpu_mask进行逻辑与操作,得到我们需要的值。
468:将467行中得到的值与r3中的cpu_val进行比较.。
469:如果相等,说明我们找到了对应的processor type,跳到474行,返回。
470:(如果不相等) , 将r5指向下一个proc_info,即增加偏移量为sizeof(proc_info_list)。
471:和r6比较,检查是否到了__proc_info_end。
472:如果没有到__proc_info_end,表明还有proc_info配置,返回466行继续查找.
473:执行到这里,说明所有的proc_info都匹配过了,但是没有找到匹配的,将r5设置成0(unknown processor)。
474:返回。
5、大概说一下调用__lookup_processor_type 的目的,在arch/arm/kernel/head.S文件中::
80 __INIT
81 .type stext, %function
82 ENTRY(stext)
83 msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | MODE_SVC @ ensure svc mode
84 @ and irqs disabled
85 bl __lookup_processor_type @ r5=procinfo r9=cpuid
86 movs r10, r5 @ invalid processor (r5=0)?
87 beq __error_p @ yes, error 'p'
85:执行完后r5保存处理器的ID, r9保存bootloader传进来的ID.
86:
87:判断r5中的processor type是否是0,如果是0,说明是无效的processor type,跳转到__error_p(出错)。
先看这么多,其余的上班后再看吧,睡觉
更多推荐
所有评论(0)