Linux汇编启动relocate重定向分析

relocaterelocate重定向,就是在开启mmu。开启mmu的操作就是将一级页表的地址以及权限写到satp寄存器中,这就算开启mmu了。
#ifdef config_mmu la a0, early_pg_dir //跳转到relocate前,先把第一级页表early_pg_dir的地址存入a0 call relocate //跳转到relocate,开启mmu#endifrelocate有两次开启mmu的操作,第一次开启mmu使用的是setup_vm()建立的trampoline_gd_dir页表,这页表保存的是kernel的前2m内存。第二次开启mmu使用的是early_pg_dir页表,这个页表映射了整个kernel内存以及dtb的4m空间。
如果trampoline_pg_dir或者early_pg_dir这两个页表的映射没弄好的话,开启mmu的时候就会失败,所以页表的建立十分关键。页表创建后续再深究,下面分析relocate汇编代码。
计算返回地址
返回地址就是ra加上虚拟地址和物理地址之间的偏移量,这个是固定偏移量。page_offset是kernel入口地址对应的虚拟地址,_start就是kernel入口地址的虚拟地址,page_offset - _start就得到它们之间的偏移,然后再和ra相加,就是返回地址。/* relocate return address */ li a1, page_offset la a2, _start sub a1, a1, a2 add ra, ra, a1将异常入口1f的虚拟地址写入stvec寄存器
因为一旦开启mmu,地址都变成了虚拟地址,原来访问的都是物理地址,开启mmu时,地址发生了改变,va != pa,从而进入异常,所以要先设置异常入口地址,此时的异常入口为1f。/* point stvec to virtual address of intruction after satp write */ la a2, 1f add a2, a2, a1 csrw csr_tvec, a2提前计算切换到early_pg_dir页表要写入satp的值再进入relocate之前,就已经把early_pg_dir赋值给a0了,所以a0是early_pg_dir。srl是逻辑右移,mmu使用的是sv39,虚拟地址39位,物理地址56位:
低12位是偏移量,所以page_shift等于12,将early_pg_dir地址右移12位存到a2。根据satp寄存器定义:
mode等于0x8代表使用sv39 mmu,0x0代表不进行地址翻译,即不开启mmu。这里stap_mode为sv39,即0x8。将early_pg_dir地址和satp_mode进行或运算后,即可得到写入satp寄存器的值,最后保存到a2。
/* compute satp for kernel page tables, but don't load it yet */ srl a2, a0, page_shift li a1, satp_mode //sv39 mmu or a2, a2, a1第一次开启mmu,使用trampoline_pg_dir页表satp值的计算和上述是一样的。开启mmu之前,通过sfence.vma命令先刷新tlb。此时开启mmu,就会进入下面的标号为1的汇编段
la a0, trampoline_pg_dir srl a0, a0, page_shift or a0, a0, a1 sfence.vma csrw csr_satp, a0进入异常1f段,重新设置异常入口为.lsecondary_park,然后切换到early_pg_dir页表,相当于第二次开启mmu。此时,如果之前建立的early_pg_dir页表不对,则会就进入.lsecondary_park。.lsecondary_park里面是个wfi指令,是个死循环。
完整relocate汇编代码:
relocate: /* relocate return address */ li a1, page_offset la a2, _start sub a1, a1, a2 add ra, ra, a1 /* point stvec to virtual address of intruction after satp write */ la a2, 1f add a2, a2, a1 csrw csr_tvec, a2 /* compute satp for kernel page tables, but don't load it yet */ srl a2, a0, page_shift li a1, satp_mode or a2, a2, a1 /* * load trampoline page directory, which will cause us to trap to * stvec if va != pa, or simply fall through if va == pa. we need a * full fence here because setup_vm() just wrote these ptes and we need * to ensure the new translations are in use. */ la a0, trampoline_pg_dir srl a0, a0, page_shift or a0, a0, a1 sfence.vma csrw csr_satp, a0.align 21: /* set trap vector to spin forever to help debug */ la a0, .lsecondary_park csrw csr_tvec, a0 /* reload the global pointer */.option push.option norelax la gp, __global_pointer$.option pop /* * switch to kernel page tables. a full fence is necessary in order to * avoid using the trampoline translations, which are only correct for * the first superpage. fetching the fence is guarnteed to work * because that first superpage is translated the same way. */ csrw csr_satp, a2 sfence.vma ret

什么是电气互锁?工作原理
IC Insights:半导体资本年支出将首次超过千亿美元,存储占比53%
某水下机器人供电系统干扰改善方案浅析
浅析液压伺服系统工作原理及电气故障诊断
液晶显示器色彩数
Linux汇编启动relocate重定向分析
LCD驱动芯片VK1056B/C概述及特点
异步电机的改进型电压模型磁链观测器介绍
小米6最新消息:小米6价格被曝光:这次真的不是1999元,雷军很烦恼!
彩电维修口诀
VXI总线测试设计
关于单分散聚糖分子形貌的实空间观测
比特率,波特率,比特和波特的关系是什么?
桁架机器人容易操纵吗?
TCL推出平板Plus 10主打移动化体验,并支持三种工作模式
模态计算精度影响因素分析
撒花!武汉森木磊石科技有限公司新版官方网站上线啦!
STM32裸机编程的基础知识(2)
诺基亚8最新消息:诺基亚8无边框+骁龙835,配置、性能、拍照全方位升级
循环工作定时控制器电路设计