首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

linux内核vmlinux启动过程中是如何调用到__arm920_setup函数的

linux内核vmlinux启动过程中是如何调用到__arm920_setup函数的

一、前言
看完韦老师第一期视频中的内核分析第一阶段后,感觉自己对内核不再那么恐惧了。韦老师在视频中对内核的分析,一句句将我们载入内核这个神秘而又美丽的世界。首先说一下内核的任务。
正如韦东山老师在所说的那样,我们辛辛苦苦移植U-BOOT,干了这么多工作,其实我们的主要目的就是能够运行内核。如果你们对UBOOT的启动过程还不清楚,那就强烈建议你们看看韦东山老师的第一期视频课程,里面对UBOOT所做的分析堪称完美中的经典之作。UBOOT移植好后,就要启动内核,别忘记UBOOT启动内核之前传给内核两个参数:1、机器ID;2、在UBOOT中专门跳出一块内存,在这块内存中设置了打算传递给内核的一些参数。UBOOT 将这块内存的地址传递给内核。
那么理所当然,内核就要处理UBOOT 传递过来的参数吧。大体就是这样子的,不明白的话,还是那句话转进去看看韦东山老师的视频教程,那里面有详细的分析。
下面就是我在学习韦东山老师教程中时遇到的一点迷惑,在此记录了下来!希望也能帮助你们解决疑惑!
二、linux内核vmlinux启动过程中是如何调用到__arm920_setup函数的(对应arch/arm/kernal/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      1
               @ mmu has been enabled                     2
adr lr, __enable_mmu @ return (PIC) address   
add pc, r10, #PROCINFO_INITFUNC                             3
前面的调用过程暂且不分析,网上的资料有很多,从红色部分开始分析:
1中将__switcn_data标号地址放入到寄存器r13中(即SP中),2中将__enable_mmu标号地址放入lr中,重点是第3句,
首先得知道PROCINFO_INITFUNC它代表的是什么含义:在Source Insight中搜索PROCINFO_INITFUNC得到结果如下:
file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ksohtml\wps163.tmp.png
进入第一个,发现有如下定义:
  DEFINE(PROCINFO_INITFUNC, offsetof(struct proc_info_list, __cpu_flush));
这句话可以理解为将PROCINFO_INITFUNC定义为结构体成员__cpu_flush在结构体proc_info_list中的偏移量。
接下来:先搞明白结构体都有哪些成员变量
点击proc_info_list进入结构体proc_info_list的C语言定义如下:
struct proc_info_list {
unsigned int cpu_val;
unsigned int cpu_mask;这两个不就是__lookup_processor_type函数中用到的VAL与mask么!!
unsigned long __cpu_mm_mmu_flags; /* used by head.S */
unsigned long __cpu_io_mmu_flags; /* used by head.S */
unsigned long __cpu_flush; /* used by head.S */
const char *arch_name;
const char *elf_name;
unsigned int elf_hwcap;
const char *cpu_name;
struct processor *proc;
struct cpu_tlb_fns *tlb;
struct cpu_user_fns *user;
struct cpu_cache_fns *cache;
};
这时咱们得弄明白proc_info_list这个结构体中每个成员的含义了,其实这个结构体就是__lookup_processor_type函数中搜索的基本单位,每一种处理器都对应这么一个结构体,对应连接脚本中的
               __proc_info_begin = .;
                *(.proc.info.init)
                __proc_info_end = .;
那么咱们得找到咱们自己板子对应处理器型号(我的是ARM920T)的这个结构体在哪里填充的呢???
在Source Insight中搜索.proc.info.init,进入下面这个条目:proc-arm920.S (arch\arm\mm):448: .section ".proc.info.init", #alloc, #execinstr(因为我的处理器是arm920的,如果你的是别的类的,找到对应的项进入即可),得到结构体proc_info_list汇编语言定义如下:
.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
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
.long cpu_arm920_name
.long arm920_processor_functions
.long v4wbi_tlb_fns
.long v4wb_user_fns
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
.long arm920_cache_fns
#else
.long v4wt_cache_fns
#endif
.size __arm920_proc_info, . - __arm920_proc_info
可以理解为上述汇编代码对应的每一项在编译连接时就被填充到对应的C语言定义的结构体成员中,最后以这种结构体为单位把每一种型号所对应的结构体都放到连接脚本
                 __proc_info_begin = .;
                  *(.proc.info.init)
                   __proc_info_end = .;
所定义的地方。
好了,分析到这里想必大家都能明白过来PROCINFO_INITFUNC这个东西代表的什么含义了,它就是结构体proc_info_list 中第五个成员变量,对应汇编代码,那就是b __arm920_setup这句话。
第2句话add pc, r10, #PROCINFO_INITFUNC中r10中存放的是__lookup_processor_type函数找到对应的处理器型号后返回的在段
__proc_info_begin = .;
*(.proc.info.init)
__proc_info_end = .;
中的地址。其实返回的就是上述分析总舵处理器型号对应的结构体信息中的的一个结构体的地址。
对应JZ2440也就是我这个开发板的处理器型号arm920所对应的结构体在段中的位置。
add pc, r10,#PROCINFO_INITFUNC
进而这句话就是调用b __arm920_setup了。
进入到标号__arm920_setup处。
__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
__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
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
继承事业,薪火相传
返回列表