下面将详细叙述MMU的设置,也是本人花费时间最多的一部分内容,无论是2410、6410甚至是Cortex-A8核的ARM,MMU的设置基本都一样,所以移植时这部分可以直接搬过来,只需要更改全局内存映射表的映射关系即可。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
先说说为什么在EBoot要设置MMU?其实有大牛们讨论过这个话题,在系统启动时会对页表进行重新映射,包括二级页表的设置,而在EBoot中只进行了一级页表的设置,最后也没有给出明确的答案,有的说是WinCE规定的,这里先不追究了,等以后研究了系统启动后的代码,再来讨论这个问题。OAL作为WinCE的开始需要启用虚拟内存,需要为MMU设置正确的页表进行地址映射,另外WinCE编译系统产生的二进制文件.bib使用的内存地址都是虚拟地址,这些虚拟地址是编译系统对二进制代码进行地址重定位的重要依据,所以在Eboot中对MMU进行设置,定义内存映射表的依据是全局内存映射表,在PLATFORM\SMDK6410\SRC\INC\oemaddrtab_cfg.inc文件中定义,内容如下:
g_oalAddressTable

; mDDR 128 MB
                ;DCD         0x80000000, 0x50000000,    64         ; 64 MB DRAM
                [ SMDK6410_X5D
                DCD         0x80000000, 0x60000000,     64         ; 64 MB DRAM
                |
                DCD         0x80000000, 0x50000000,    128         ; 128 MB DRAM
                ]

DCD         0x90000000, 0x70000000,    4            ; SROM SFR
                DCD         0x00000000, 0x00000000,    0            ; end of table

    它是以g_oalAddressTable宏开始的,DCD用来分配一片连续的字存储单元,第一个参数是虚拟地址值,第二个参数是对应的物理地址值,第三个参数指明分配的大小,在映射表的最后,将三个参数的值均设为0,表示是映射表的结束。下面看startup.s文件中的源码。
;------------------------------------
;         Initialize MMU Table
;------------------------------------

;----------------------------
        ; Compute physical address of the OEMAddressTable.

20
                add                    r11, pc, #g_oalAddressTable -(. + 8)
                ldr                    r10, =PT_1ST_BASE                                        ; (r10) = 1st level page table

   上面的代码将R11赋值为内存映射表的地址,R10赋值为页表存储的地址,PT_1ST_BASE在最开始处已经进行了定义,是页表基地址0x50010000,解释一下R11的赋值语句。ARM处理器是流水线结构,允许指令预取,所以PC一般等于当前执行指令下面的第2条指令的地址,即PC=当前指令地址值+8字节,而“.”代表的是当前指令的地址值,PC=(. + 8),这样R11获得的是g_oalAddressTable的地址。那为什么不直接mov  r11  #g_oalAddressTable进行赋值呢?确实不能这样,这样可以编译通过,但是执行不通过,只能采用和PC的相对值来换算。
add                    r10, r10, #0x2000                    ; (r10) = ptr to 1st PTE for "unmapped space"
    这一条代码,将R10的值增加了0x2000,因为第1级MMU的入口是地址值的高14为(过滤掉低18位),g_oalAddressTable中看出,DRAM的起始虚拟地址为0x80000000,而0x80000000>>18=0x2000,正好是0x80000000地址对应的第1级MMU入口的偏移值,也就是说R10现在存储的是0x80000000虚拟地址对应的页表的存储地址。那么为什么要右移18位?第1级页表将4GB的地址空间划分为多个1MB的段,对应的就有4096个页表项,而ARM地址映射时,虚拟地址被分为两部分:高位+低位,高位用来表示虚拟地址对应的页表针对页表首地址的偏移值,而低位表示在页表1MB地址空间中的偏移量,页表中的一个页表项可以描述4字节的虚拟页(因为ARM是32位的,每次都是读取4字节的数据),那么1MB的空间就需要256KB个这样的页表项才可以描述(256K*4=1M),而要表示256KB的大小,需要虚拟地址的低18位,剩下的高14位就可以用来计算虚拟地址对应页表相对于页表首地址的偏移量了。
mov                    r0, #0x0E                             ; (r0) = PTE for 0: 1MB cachable bufferable
                orr                    r0, r0, #0x400                    ; set kernel r/w permission
    上面的两条代码用来设置页表项的高速缓冲、写缓冲以及读写属性,具体的设置请参看CP15协处理器C1寄存器的功能,以后有时间会整理一篇关于CP15协处理器的说明。其实读者如果仔细看会发现,设置后R0=0x40E,和文件开始声明的PT_1ST_ENTRY_CNB变量的值是一样的,所以也可以用mov  r0  PT_1ST_ENTRY_CNB来代替两条语句,但是本人觉得用两条语句更能表明设置了什么,语义更明确。
25
                mov                    r1, r11                                        ; (r1) = ptr to MemoryMap array

30
                ldr                    r2, [r1], #4                             ; (r2) = virtual address to map Bank at
                ldr                    r3, [r1], #4                             ; (r3) = physical address to map from
                ldr                    r4, [r1], #4                             ; (r4) = num MB to map

    首先将R11也就是g_oalAddressTable指向的全局内存映射表的地址赋给R1(这就是高手的代码书写习惯,不会直接操作R11),然后依次将R1指向的地址处的数据赋值给R2、R3和R4寄存器,“#4”是表示每次操作完后,R1的地址值增加4字节,指向下一个数据,其实对照oemaddrtab_cfg.inc的映射表,很容易发现,R2获得的是虚拟地址的值,R3获得的是对应物理地址的值,R4则是这段存储空间的大小。
cmp                    r4, #0                                        ; End of table?
                beq                    %F40
    上面两条代码用来判断是否到了oemaddrtab_cfg.in中映射表的结尾,上面已经介绍过,映射表的最后一条的三个参数全部都为0,标识映射表的结束。beq是一条跳转语句,表示如果相等,则跳转,%F40表明向后寻找名称为40的标号(F=After)。

转载于:https://blog.51cto.com/jazka/572644

WinCE6.0学习之EBoot源码分析----startup.s(三)相关推荐

  1. sheng的学习笔记-Vector源码分析

    概述 Vector底层也是数组,跟ArrayList很像(先看下ArrayList,再看Vector会很轻松),ArrayList可参考下文,并且由于效率低,已经被淘汰了,大概瞅瞅得了 sheng的学 ...

  2. [导入]SunriseUpload.0.9.1的源码分析(七)

    接着分析了几个小时的SunriseUpload.0.9.1的源码. 终于明白了作者的整体思路.在此就做一个总结. 首先,要想能上传很大的文件,我们就必须编写一个HttpModule来自己处理用户上传的 ...

  3. Java设计模式学习以及底层源码分析

    源码在分支master 工厂模式 把具体创建产品的细节封装起来,你要什么产品,我给你什么产品即可. 简单工厂模式 工厂方法模式 缓存层:抽象类 抽象工厂模式 缓存层是:接口 原型模式 问题: 原型模式 ...

  4. Netty学习十七:源码分析之HashWheelTimer

    一.常见定时任务实现 定时器的使用场景包括:成月统计报表.财务对账.会员积分结算.邮件推送等,它一般有三种表现形式:按固定周期定时执行.延迟一定时间后执行.指定某个时刻执行. 定时器的本质是设计一种数 ...

  5. Licode入门学习:MediaStream源码分析(二)

    Licode服务与启动过程分析 MediaStream源码分析(一) MediaStream源码分析(二) MediaStream源码分析(三) WebRtcConnection源码分析(一) Web ...

  6. Licode入门学习:MediaStream源码分析(三)

    Licode服务与启动过程分析 MediaStream源码分析(一) MediaStream源码分析(二) MediaStream源码分析(三) WebRtcConnection源码分析(一) Web ...

  7. Licode入门学习:WebRtcConnection源码分析(一)

    Licode服务与启动过程分析 WebRtcConnection源码分析(一) WebRtcConnection源码分析(二) WebRtcConnection源码分析(三) MediaStream源 ...

  8. Licode入门学习:MediaStream源码分析(一)

    Licode服务与启动过程分析 MediaStream源码分析(一) MediaStream源码分析(二) MediaStream源码分析(三) WebRtcConnection源码分析(一) Web ...

  9. Licode入门学习:WebRtcConnection源码分析(二)

    Licode服务与启动过程分析 WebRtcConnection源码分析(一) WebRtcConnection源码分析(二) WebRtcConnection源码分析(三) MediaStream源 ...

最新文章

  1. 学生教育云平台登录入口_湖南省教育云平台登录入口
  2. R可视化包ggplot2设置透明背景实战
  3. 深圳美景品牌策划机构:美景、BOBDOG传媒合作论坛广州举行
  4. oracle数据库实例,数据库的理解
  5. ca开头的车是什么牌子_微电调研 | 把高速车摘了牌子当低速车卖还很普遍
  6. DockerCompose构建Springboot项目
  7. EF中报错:附加类型“xxxx”的实体失败,因为相同类型的其他实体已具有相同的主键值。
  8. Android Service与Thread的区别
  9. mysql 事务sql_mysql存储过程之事务篇
  10. em在聊天中是什么意思_被神化的EM菌,该怎样正确使用?
  11. C# 读取XML 写入XML 读写XML
  12. hadoop集群的搭建与配置(2)
  13. SATI 国产文献题录信息统计分析工具:简介
  14. c4d流体插件_C4D流体模拟插件 NextLimit RealFlow 2.6.5.0095 Win已注册版
  15. Java 参数类型后面三个点,可变参数列表
  16. 大数据时代的“小数据”
  17. 亚马逊云科技荣获2021中国公有云平台用户满意度第一
  18. 南方电网两栖机器人_南方电网首个作业级水下机器人落户海南 为海底电缆“护驾”...
  19. lumen 项目根目录_Lumen 初体验(二)
  20. 2020复工后刷脸支付将迎来高潮

热门文章

  1. Dockerfile构建容器镜像 - 运维笔记
  2. 软件工程进度条-第十五周
  3. mysql索引结构原理、性能分析与优化
  4. 网站出现403 Forbidden
  5. 夜深了,发点无聊的东西
  6. Python中抓网页的小陷阱
  7. WAP开发笔记(1)-.net移动页面中html控件不能直接显示的解决
  8. 说说大型高并发高负载网站的系统架构(ZT)
  9. javaScript第五天(2)
  10. Kubernetes学习之路(四)之Node节点二进制部署