参考资料:
1: 关于ARM地址映射的理解.
2:uboot中的 MMU代码分析.
3: 协处理器CP15介绍—MCR/MRC指令(6).
4.朱老师的课程uboot的2.5.10-2.5.12节
【uboot的虚拟地址映射学习】虚拟地址映射
把虚拟地址映射到物理地址 。
怎么映射
两者之间的进行转换的话会有一个转换关系,这个转换关系对应的是虚拟地址映射表 。
uboot是在进行完BL2的重定位之后,开始虚拟地址映射,然后后面都使用的虚拟地址了 。
重定位之后进入段
具体思路可以看注释,并且要结合用到的参考资料,知道一个个转换关系到底是怎样结合起来的 。
还有,这里只是一级映射,用了段模式,算是最简单的一种映射方法 。
after_copy:#if defined(CONFIG_ENABLE_MMU)enable_mmu:/* enable domain access */ldr r5, =0x0000ffffmcr p15, 0, r5, c3, c0, 0@load domain access register //mcr 把arm处理器的数据传输到协处理器里面 即把r5的值写到c3里面//c3是协处理器cp15的一个寄存器,控制了ARM处理器16个域的访问权限//ffff即16个1对应16个域的权限 。/* Set the TTB register */ldr r0, _mmu_table_base//获取mmu_table(转换表)的基地址ldr r1, =CFG_PHY_UBOOT_BASE //根据注释算得是0x33e000000ldr r2, =0xfff00000//取bit[31:20]位,也就是高12位bic r0, r0, r2//取把这个值的高12位清零orr r1, r0, r1//把物理地址和这个经过处理的转换表进行位或运算,组合成一个段地址+条目描述符mcr p15, 0, r1, c2, c0, 0 //把这个得到的转换关系写到c2寄存器,也就是TTB 转换表里面/* Enable the MMU *///设置完之后就启动mmummu_on:mrc p15, 0, r0, c1, c0, 0orr r0, r0, #1mcr p15, 0, r0, c1, c0, 0nopnopnopnop#endif
下面这段代码是在里面,作用就是建立转换表
/* form a first-level section entry *///ap是设置权限在 cp15 c2寄存器 bit[10-11]//d是domain域 cp15 c2寄存器 bit[5-8]不管是段模式还是页模式,系统都把4GB空间分为16个域,每个域有相同的权限检查//c bit 3b bit 2C/B位是控制位,与本条目(描述符)所在域的Cache和Buffer有关(是否允许本域开启Cache和Buffer)//最后的1<<1设置bit1为1,其实bit[0:1]是设置模式描述符,0b10是段模式的描述符标识.macro FL_SECTION_ENTRY base,ap,d,c,b//.macro 声明一个宏一个宏名,接受5个参数.word (\base << 20) | (\ap << 10) | \(\d << 5) | (1<<4) | (\c << 3) | (\b << 2) | (1<<1).endm//.end macro 应该是完成的宏定义标志.section .mmudata, "a"//.section.mmudata 这里是链接脚本的mmudata段,后面的"a"不懂.align 14// the following alignment creates the mmu table at address 0x4000. 这句注释感觉不对,不止是不是没改还是我理解不对.globl mmu_tablemmu_table:.set __base,0//base是<<20位,20-31是段基址的地方,也就设置段基址位0// Access for iRAM.rept 0x100//.rept repeat 伪指令 循环0x100次 转成十进制 256次FL_SECTION_ENTRY __base,3,0,0,0//每一次循环,段基地址都加1一段1MB 共256MB.set __base,__base+1.endr//.endr end repeat 构成一个for循环// Not Allowed.rept 0x200 - 0x100//又循环256次但是每次循环里面都置零.word 0x00000000.endr.set __base,0x200//设置段基址位0x200 ap权限还是3 也就是11 cb控制为控制cache和buffer开吧// should be accessed.rept 0x600 - 0x200//循环1024次FL_SECTION_ENTRY __base,3,0,1,1.set __base,__base+1//每次段基址+1 一段1M 1024段就1024M 1G.endr.rept 0x800 - 0x600// 循环512次但是都是置0.word 0x00000000.endr.set __base,0x800//设置段基址0x800// should be accessed.rept 0xb00 - 0x800// 0x300 256*3次 一次段+1 768MBFL_SECTION_ENTRY __base,3,0,0,0.set __base,__base+1.endr/* .rept 0xc00 - 0xb00.word 0x00000000.endr */.set __base,0xB00//设置段基址 B00.rept 0xc00 - 0xb00//0x100 256次256MBFL_SECTION_ENTRY __base,3,0,0,0.set __base,__base+1.endr// 0xC000_0000映射到0x3000_0000.set __base,0x300//设置段基址0x300//.set __base,0x200// 256MB for SDRAM with cacheable.rept 0xD00 - 0xC00//从0xc00开始到0xd00一共256次,一次1MB,共256MBFL_SECTION_ENTRY __base,3,0,1,1.set __base,__base+1.endr// access is not allowed.@.rept 0xD00 - 0xC80//从c80到d00又不给用@.word 0x00000000@.endr.set __base,0xD00//d00到 10000 循环0x300次 768次 即768M// 1:1 mapping for debugging with non-cacheable.rept 0x1000 - 0xD00FL_SECTION_ENTRY __base,3,0,0,0.set __base,__base+1.endr
抽取前面两端进行分析讲解,如图所示 。
文章插图
跟着代码一步步分析最终算出了的长度加起来刚刚好是4G的长度,也就是全映射了 。
细心点会发现,到也是设置为不可用的 。
结果就完成了转换表的建立 。
回顾
DRAM有效范围:
DMC0: -
DMC1:
结论:虚拟地址映射只是把虚拟地址的开头的256MB映射到了DMC0的开头的256MB物理内存上去了 。其他的虚拟地址空间根本没动,还是原样映射的 。
思考:为什么配置时将链接地址设置为,因为这个地址将来会被映射到这个物理地址 。
之前在主里面的设置为,经过映射后就到了的位置 。
- [亲测可用]申请虚拟VISA卡ONEKEY保姆级教程/开通GPT-Plus
- 华帝蒸汽清洗好还是自动洗好_如何获得更好的蒸汽价格警报
- [Linux+OpenCV]创建自己的第一个文件
- 【操作系统】虚拟内存相关分段分页页面置换算法
- 空间想象力强的人适合学计算机吗,据说空间想象力强的人都是学霸!
- 入手评测 Pico Neo 3 256G先锋版和128G基础版的区别
- 亚马逊和速卖通店铺要如何规划?4个观念成为人气爆棚的店铺
- 基于Cocos2d-x3.2的虚拟摇杆实现及操控角色移动
- 在ssm的基础上 spring boot快速了解
- 一 安卓逆向:基础入门