今天在看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(出错)。

先看这么多,其余的上班后再看吧,睡觉

Logo

更多推荐