WinCE6.0学习之EBoot源码分析----startup.s(四)

简介:
                ldr                    r5, =0x1FF00000 
                and                    r2, r2, r5                                        ; VA needs 512MB, 1MB aligned.
    原来 R2 中存储的是虚拟地址值(如 0x80000000 ),通过上面的代码,将 R2 中数据的 [29-21] 位置为 1 ,前面已经说过将空间划分成了多个 1MB 的段,那么就必须以 1MB 对齐,而且 WinCE 最多只能支持 512MB 的物理内存,所以虚拟地址的合法区间是 0x80000000~0x9FFFFFFF ,正好是 512MB 的大小(这段是带缓冲的虚拟地址,相应的不带缓冲的虚拟地址是 0xA0000000~0xBFFFFFFF )。 R2 中的数据正是虚拟地址对应的页表相对于页表首地址的偏移地址,也就是 R2 用来计算该虚拟地址对应的页表的存储地址,从下面的代码会看出这点。
                ldr                    r5, =0xFFF00000 
                and                    r3, r3, r5                                        ; PA needs 4GB, 1MB aligned.
          原来 R3 中存储的是物理地址的地址值,页表项的内容由两部分组成:物理地址的高 12 位(高 12 位) + 缓冲读写属性(低 12 位),这里的代码正是保留了物理地址的高 12 位,清空低 20 位,正是为了形成页表项内容进行准备。
                add                    r2, r10, r2, LSR #18 
                add                    r0, r0, r3                                        ; (r0) = PTE for next physical page
    这两条代码正是在前面计算得基础上,用 R2 中虚拟地址的高 14 位的偏移量 +R10 中存储的页表的基地址,从而将该虚拟地址对应的页表要存储的地址计算出来,并赋值给 R2 。而 R0 存储的数据是关于页表对应的虚拟页的缓冲读写属性,再加上 R3 中存储的物理地址的高 12 位,从而形成了相应页表项的内容,并赋值给 R0
35 
                str                    r0, [r2], #4 
                add                    r0, r0, #0x00100000         ; (r0) = PTE for next physical page 
                sub                    r4, r4, #1                             ; Decrement number of MB left 
                cmp                    r4, #0 
                bne                    %B35                                        ; Map next MB
         上面的第一条代码,通过 str 指令将 R0 中存储的页表项内容,写入 R2 指向的地址中,同时 R2 指向下一个地址。接下来将页表项的内容增加 1MB 的大小,从 oemaddrtab_cfg.inc 的映射表可以看出,最后一个参数表示的分配存储空间的大小,是以 MB 为单位,所以 R0 指向的是下一个物理地址页(单位 1M )的页表项的内容。之后将 R4 中空间大小的值减 1 ,表示剩余要构造的页表数目,如果不为 0 ,则跳转到标号 35 处,继续构造页表,知道这一个页表条目完成为止(或者说这一段存储空间全部映射完成为止)。
                bic                    r0, r0, #0xF0000000         ; Clear Section Base Address Field 
                bic                    r0, r0, #0x0FF00000         ; Clear Section Base Address Field 
                b                    %B30                                        ; Get next element
    这部分代码简单的说就是清空 R0 中的高 12 位,即清空上一个物理地址的高 12 位,因为要用来存储下一个物理地址的高 12 位,同时保留低 20 位中的缓冲读写属性,完成后跳转到标号 30 处,继续读取全局内存映射表的内容,构造地址映射的页表。其中 %B30 表示向前寻找标号为 30 的地址( B=Before )。
40 
                tst                    r0, #8 
                bic                    r0, r0, #0x0C                             ; clear cachable & bufferable bits in PTE 
                add                    r10, r10, #0x0800                    ; (r10) = ptr to 1st PTE for "unmapped uncached space" 
                bne                    %B25                                        ; go setup PTEs for uncached space 
                sub                    r10, r10, #0x3000                    ; (r10) = restore address of 1st level page table
一般 WinCE 会根据全局内存映射表进行两份虚实映射,一份带缓冲的虚拟地址和不带缓冲的虚拟地址。到这里的时候,说明 0x80000000~0x9FFFFFFF 这段 512M 的虚拟地址的页表已经构造完成了,这段地址是带缓冲的,下面需要对不带缓冲的虚拟地址构造页表。
第一条 tst 语句表示判断 R0 的位 [7] 的值是否为 1 ,从而影响 bne 跳转语句的结果。 R0 的第 7 位在页表项内容中表示的是缓冲的属性,如果为 1 ,表明还没有开始构造不带缓冲的虚拟地址对应的页表,如果不为 0 ,说明不带缓冲的虚拟地址对应的页表也已经构造完成了(是不是有点晕啊,呵呵,因为当第二次循环运行这条语句的时候,已经就完成了不带缓冲的页表的构造,不行你自己走一遍代码就知道了)。第二条 bic 的语句很简单,就是为了将高速缓冲和写缓冲的属性值去掉。第三条语句有点意思,其实就是为了将 R10 指向存储不带缓冲的虚拟地址对应的页表的存储地址( 0xA0000000 ),但是采用的方法是计算偏移量,当前 R10 中存储的是带缓冲的虚拟地址对应的页表的存储地址( 0x80000000 ),而 0xA0000000 0x8000000 相差 0x20000000 ,那么把 0x20000000>>18 得到的结果就是 0x0800 ,所以在 R10 的基础加上 0x0800 就是页表应该存储的地址(其实就是依据虚拟地址高 14 位代表的是相对于页表首地址的偏移量,所以也可以直接用 0xA0000000>>18 位来计算页表的存储地址,不信你试试,结果是一样的)。第四条语句就简单了,向前跳转到标号 25 处,像缓冲虚拟地址的页表构造的方法对不带缓冲虚拟地址的页表进行构造。第五条语句为下面的代码做准备,将 R10 指向的地址重新指向页表基地址,即 PT_1ST_BASE ,网上有人说这句有问题,其实没有问题,不过这一句确实没什么用处,因为下面对 R10 进行了重新赋值,即将 PT_1ST_BASE 重新赋给了 R10 。不过为了理解明白,本人还是解释一下这句是怎么计算出来的?首先在最开始 R10 增加了 0x2000 ,上这里有两次增加了 0x0800 (为什么是两次呢?好好看代码,上面的第三条语句会被执行两次),加起来正好是 0x3000 ,所以减去这个值得到的正是页表的基地址。
        ;---------------------------------------------- 
        ; Setup mmu to map (VA == 0) to (PA == 0x30000000). 

                ; cached area 
                ldr                    r0, =PT_1ST_BASE                             ; PTE entry for VA = 0 
                ldr                    r1, =PT_1ST_ENTRY_CNB         ; Cache/Unbuffer/RW 
                str                    r1, [r0]
    上面是将 0x0 的带缓冲的虚拟地址映射到 0x30000000 的物理地址处,  0x0 的虚拟地址对应的页表的存储地址就在 PT_1ST_BASE 处( 0x0>>18 得到的是偏移量,说明就在页表基地址处)。第二条语句是设置页表项的内容:物理地址的高 12 + 缓冲读写属性。第三条语句 str 将页表项的内容写入到对应的页表存储地址处。
                ; uncached area. 
                add                    r0, r0, #0x0800                             ; PTE entry for VA = 0x02000000 
                ldr                    r1, =PT_1ST_ENTRY_NCNB         ; Uncache/Unbuffer/RW 
                str                    r1, [r0]
    这部分用来映射不带缓冲的虚拟地址 0x20000000 (后面的注释不对)到物理地址 0x30000000 ,上之前分析的一样,采用计算偏移量的方法,第二条和第三条语句和上一部分的一样,这里不再赘述。


本文转自jazka 51CTO博客,原文链接:http://blog.51cto.com/jazka/572626,如需转载请自行联系原作者
相关文章
|
3月前
|
存储 调度 芯片
RT-Thread快速入门-内核移植
RT-Thread快速入门-内核移植
33 0
|
存储 编译器 C语言
STM32第二章-启动过程详解
STM32 的启动过程,启动过程是指从 CPU 上电复位执行第 1 条指令开始(汇编文件)到进入 C 程序 main()函数入口之间的部分。启动过程相对来说还是比较重要的,虽然难但必须了解掌握。
216 0
STM32第二章-启动过程详解
|
监控 Linux Shell
erlang无图形界面的linux下如何使用observer:start(). --- ★firecat推荐★
erlang无图形界面的linux下如何使用observer:start(). --- ★firecat推荐★
218 0
erlang无图形界面的linux下如何使用observer:start(). --- ★firecat推荐★