加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Linux > 正文

linux内核启动汇编部分详解

发布时间:2020-12-13 22:33:01 所属栏目:Linux 来源:网络整理
导读:参考文档: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

参考文档: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部分

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读