参考文档:https://blog.csdn.net/haoge921026/article/details/46785995
找到入口ENTRY(stext)开始分析
setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE,r9 @ ensure svc mode @ and irqs Disabled
设置cpu为svc模式,禁止中断
mrc p15,r9,c0,c0 @ get processor ID
读取ARM协处理器cp15的c0寄存器获得cpu ID,存放在r9
cpu ID格式如下:
---------------------------------------------------------------------
厂商编号 | 产品子编号 | ARM 体系版本号 | 产品主编号 |处理器版本号 |
---------------------------------------------------------------------
查手册: cotex_a8_r3p2_trm.pdf 3.2.2节可以获得如下信息
厂商编号 [31:24] : 0x41 表示ARM公司
产品子编号 [23:20] : 0x3
ARM体系版本号 [19:16] : 0x1->ARMv4,...,0xF ->ARMv7
产品主编号 [15: 4] : 0xc08->CortexA8
处理器版本号 [ 3: 0] : 0x2
r9 : cpuID(0x413fc082) r1:机器码 r2:atag指针
bl __lookup_processor_type @ r5=procinfo r9=cpuID
linux内核支持多个cpu,每个cpu对应一个procinfo结构体,这句指令是去查找procinfo结构体中查找是否有这个cpu
查看代码:
__lookup_processor_type:
adr r3,3f //将procinfo结构体集的链接首地址的运行指针赋给r3
ldmia r3,{r5 - r7}
r3 -> 局部标号3运行地址
r5 -> __proc_info_begin [虚拟地址] 链接地址
r6 -> __proc_info_end [虚拟地址] 链接地址
r7 -> 局部标号4的链接地址[虚拟地址:0xcxxx,xxxx]
add r3,r3,#8
sub r3,r7 @ get offset between virt&phys
r3 -> 运行地址与链接地址的偏移
add r5,r5,r3 @ convert virt addresses to
add r6,r6,r3 @ physical address space
r5 -> __proc_info_begin 运行地址
r6 -> __proc_info_end 运行地址
1: ldmia r5,{r3,r4} @ value,mask
and r4,r4,r9 @ mask wanted bits
teq r3,r4
beq 2f //cpuID的value相等就跳转
add r5,#PROC_INFO_SZ @ sizeof(proc_info_List) //跳到下一个procinfo的地址
cmp r5,r6 // 已经查完最后一个procinto了
blo 1b
mov r5,#0 @ unkNown processor //匹配失败r5=0
2: mov pc,lr //返回
ENDPROC(__lookup_processor_type)
查看代码:
.align 2
3: .long __proc_info_begin
.long __proc_info_end
4: .long .
r5=procinfo r9=cpuID r1:机器码 r2:atag指针
movs r10,r5 @ invalID processor (r5=0)?
beq __error_p @ yes,error ‘p‘
r5返回0则去"nError:
unrecognized/unrecognized processor variant(0x<cpuID>).\n",然后进入死循环 。
r9=cpuID r10=procinfo r1:机器码 r2:atag指针
bl __lookup_machine_type @ r5=machinfo
movs r8,r5 @ invalID machine (r5=0)?
beq __error_a @ yes,error ‘a‘
linux内核支持多个开发板,每个开发板对应多个machinfo结构体,去查找这个结构体集看看是否存在与r1传进来的机器码匹配
存在则返回r5=machinfo,不存在(r5=0)打印Error: unrecognized/unsupported machine ID (r1 = 0x<machine_ID>")然后进入死循环
r9=cpuID r10=procinfo r1:机器码 r8=machinfo r2:atag指针
bl __vet_aTags
检查atag格式是否正确,不正确会r2=0
bl __create_page_tables
在0x30004000-0x30008000之间创建16k的页表,将内核代码范围的地址映射到0x30000000
ldr r13,__switch_data @ address to jump to after
@ mmu has been enabled
adr lr,BSYM(__enable_mmu) @ return (PIC) address
ARM( add pc,r10,#PROCINFO_INITFUNC )
r10为主机procinfo结构体首地址,跳转__v7_setup 主要干的事情有:
清除cahe,设置控制MMU的协处理器寄存器的值,将r4寄存器的值写入了cp15的c2寄存器。
最终在找页表所在基地址的时候, MMU会自动从cp15的c2寄存器中读取。我们在lr寄存器中保存了
__enable_mmu,所以__v7_setup函数返回的时候,就去执行__enable_mmu了。在__enable_mmu中设置些参数打开mmu
跳转__switch_data
__switch_data中主要请bss,设置栈,保存cpuID,机器码,aTags指针
最后用b start_kernel 跳转内核启动c部分
总结以上是内存溢出为你收集整理的linux内核启动汇编部分详解全部内容,希望文章能够帮你解决linux内核启动汇编部分详解所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)