免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1868 | 回复: 0
打印 上一主题 下一主题

非操作系统模式下页表的管理及页错异常的处理--mmu [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-03-03 21:02 |只看该作者 |倒序浏览
    在非操作系统下使用mmu,需要手动建立和管理页表。最近一段时间在师兄的带领下实现了arm926ej的mmu的开启,页表的手动创建和管理。确定虚实地址的对应关系是痛苦的,为此我用mfc编写了一个页表转换的小程序,通过输入虚拟地址和物理地址、基址寄存器、2级页表基地址等信息得到1级页表和2级页表的地址和描述符,代码比较简单,在此就不献丑了。
    代码运行在linux下的arm处理器模型facsim上,地址空间由0x00000000-0x001fffff,一共2M,为了实现在页错异常中管理页表,把abort模式的堆栈指针指向0x1ffffc,并把从0x1ff000开始的页的虚拟地址映射到同物理地址的页帧,即这个页的物理地址与虚拟地址相同,作为abort模式下的堆栈。这样在页错异常后,开关mmu不影响abort堆栈的访问。
    本试验中,将发生第一次页表错误的页帧放到spm中,虚拟地址不变,通过改变页表将虚拟地址映射到spm中。
   
下面介绍一下页表的创建过程:
1.首先建立好各个模式下的堆栈指针,注意把abort模式下的堆栈指针指向0x1ffffc!
AREA BOOT, CODE, READONLY
ENTRY
    ldr sp, =0x301ffefc ;init sp_svc

    mov R4, #0xD2 ;chmod to irq and init sp_irq
    msr cpsr_cf, R4
    ldr sp, =0x301ffdfc

    mov R4, #0XD1 ;chomod to fiq and init sp_fiq
    msr cpsr_cf, R4
    ldr sp, =0x301ffcfc

    mov R4, #0XD7 ;chomod to abt and init sp_ABT
    msr cpsr_cf, R4
    ldr sp, =0x1ffffc

    mov R4, #0XDB ;chomod to undf and init sp_UNDF
    msr cpsr_cf, R4
    ldr sp, =0x301ffafc
   
                                ;chomod to abt and init sp_sys
    mov R4, #0xDF ;all interrupts disabled
    msr cpsr_cxsf, R4 ;SYSTEM mode, @32-bit code mode
    ldr sp, =0x301ff0fc
   
    mov R4, #0XD3 ;chmod to svc modle, CPSR IRQ bit is disable
    msr cpsr_c, R4
2.关闭I/DCache,挤干write buffer,关闭mmu
mov r0,#0
mcr p15,0,r0,c7,c7,0 ; 失效I/DCache
mcr p15,0,r0,c7,c10,4 ; 挤干WB
mcr p15,0,r0,c8,c7,0 ; 失效I/D TLBs
mrc p15,0,r0,c1,c0,0 ; 加载控制寄存器C1到R0
bic r0,r0,#0x000f ; 将R0的W(WB)C(Cache)A(Align)M(MMU)位清零
bic r0,r0,#0x1100 ; 将R0的I(ICache)S(System Protection)位清零
mcr p15,0,r0,c1,c0,0 ; 将R0写到控制寄存器C1
3.将页表区域清零,页表的基地址是0x4000,结束地址是0x7ffc
    ldr        r4,=0x4000     ; 页表的开始地址
    mov        r0,r4          ; 保存页表开始地址到R0,为后面循坏递增准备
    ldr        r3, =0x0            
    ldr r6,=0x7ffc            ; 调用循环将0x4000~0x8000清零,准备写页表
1    str        r3, [r0], #4                    
    teq        r0, r6
    bne        %b1
4.写入1级页表。代码从0x30008000开始执行,对应的1级页表地址为0x4c00,0x30100000对应1级页表地址为0x4c04,一共2M地址空间,所以只用到两个1级页表项。
ldr        r4,=0x4c00            ; R0寄存器加载第一个段的1级页表项
    mov        r0,r4                ;
    ldr        r3,=0x6011            ; 1级页表描述符,意义:粗页表,IMP=100,Domain=0,粗页表基址=
    str        r3, [r0], #4        ;
    ldr        r3,=0x6431            ; 1级页表描述符,负责映射VA0x3010,0000到0x0010,0000
    str        r3, [r0]        
5.写入2级页表项。2级页表基地址是0x6000,2级页表项最后两位是01,所以对应的是4k大页。
写入2级页表
    ldr        r4,=0x6000            ; 2级页表开始位置
    mov        r0,r4                ;
    ldr        r3, =0xffe            ; 准备2级页表项,意义:4KB页,CB位打开AP位全部置位
    add        r6, r0, #0x800        ; 将2级页表结束地址保存到r6中
1    str        r3, [r0], #4        ; 循环装载2级页表
    add        r3, r3, #0x1000        ; 每次加0x1000,为了页号每次自加(偏移)1页
    teq        r0, r6                ; 和0x6800对比,等于则意味着完成虚地址0x3000,0000~0x3020,0000共2MB的映射
    bne        %b1                    
6.为了产生页错异常,将数据段的2级页表项的最后两位设成00,这样mmu取到2级页表项的时候将发生数据异常,在异常处理函数中我们就可以重新修改页表了。注意代码中的红色部分!
ldr        r4,=0x60c0            ; 2级页表(数据段)的开始位置
    mov        r0,r4                ;
    ldr        r3, =0x30ffc        ;
    add        r6, r0, #0x740        ;
1    str        r3, [r0], #4        ;
    add        r3, r3, #0x1000
    teq        r0, r6
    bne        %b1
7.创建一些特殊的页表。注意前面部分我们的1级页表项是从0x4c00开始放的,我们在0x4000处放置0x0000开始的页帧和0x8000开始的页帧的一级页表项,将这两个页帧的虚实地址映射为相等,2级页表放在0x4400和0x4420处。同理,为了实现abort异常的堆栈虚实地址相等,我们也需要单独设置这个页帧的页表。改页帧的1级页表放在0x4004,2级页表放在0x47fe。地址的映射关系在此就不详述了。
    ldr r4,=0x4000                ; 1级页表
    ldr r5,=0x4471                ; 1级页表项,意义:二级页表的基址应该是0x4400,IMP=b100,Domain=b0011
    str r5,[r4]
    ldr r4,=0x4400                ; 为映射0页的2即页表地址
    ldr r5,=0xffe                ; 0页的2级页表项
    str r5,[r4]
    ldr r4,=0x4420                ; 0x8000地址对应页2级页表地址
    ldr r5,=0x8FFE                ; 0x8000地址对应页2级页表项
    str r5,[r4]
    ldr r4,=0x4c08                ;
;--------------------映射0x1ff000 到 0x1ff000
     ldr r4,=0x4004                ; 1级页表
    ldr r5,=0x4471                ; 1级页表项,意义:二级页表的基址应该是0x4400,IMP=b100,Domain=b0011
    str r5,[r4]
    ldr r4,=0x47fe                ; 0x1ff000地址对应页2级页表地址
    ldr r5,=0x1ffffe                ; 0x1ff000地址对应页2级页表项
    str r5,[r4]
8.开启mmu。初始化过程结束。
    ldr r0, =0x0
    ldr r1, =0x40000055            ; 准备填写Domain域,由于上面用到0和3两个域,所以需要给0x55,最前面的4问题不大
    mcr p15,0,r1,c3,c0,0        ; 写入Domain域
    ldr r1, =0x4005147D            ; 准备填写C1控制寄存器
    IMPORT __main                ; 准备打开MMU后跳向的地址
    ldr r5,=__main
    mcr p15,0,r1,c1,c0,0        ; 打开MMU和Cache等
    add pc,r5,#0                ; 跳PC到刚才准备的__main的虚地址地址继续执行
    mov r0,r0                    ; 填充流水线
    mov r0,r0
    mov r0,r0
    mov r0,r0
    mov r0,r0
    END
9.下面开始讨论abort异常处理程序
ABORT_DATA_DO
;-----------------------数据中止异常------------------------
;-----------------------压栈--------------------------------==
    subs     lr, lr, #8            ;获得数据中止时pc值
    stmfd     sp!,{r0-r11, lr}     ;压榨
;----------------------------end---------------------------==
10.关闭mmu
;------------------------关闭mmu---------------------------++
    mrc    p15,0,r9,c6,c0,0      ; 从错误地址寄存器中拿到FAR,放入R9保存

    mov r0,#0
    mcr    p15,0,r0,c7,c7,0      ; 失效I/DCaches
    mcr    p15,0,r0,c7,c10,4     ; 挤干WB
    mcr    p15,0,r0,c8,c7,0      ; 失效I/D TLBs
    mrc    p15,0,r0,c1,c0,0      ; 加载控制寄存器C1到R0
    bic    r0,r0,#0x000f         ; 将R0的W(WB)C(Cache)A(Align)M(MMU)位清零
    bic    r0,r0,#0x1100         ; 将R0的I(ICache)S(System Protection)位清零
    mcr    p15,0,r0,c1,c0,0      ; 将R0写到控制寄存器C1
;-----------------------------end---------------------------++
11.修改页表。先将所有的数据段的2级页表项置为01,然后将发生页错异常的段的物理地址映射到spm中,地址为0x04000000,最后从sdram中搬运数据到spm,这样下次访问该页帧时就可以从spm中访问数据了,而不需要到sdram中。
;---------------修改页的2级页表描述符(测试)--------------------##
    ldr        r4,=0x60c0            ; 2级页表(数据段)的开始位置
    mov        r0,r4                ;
    ldr        r3, =0x30ffe        ;
    add        r6, r0, #0x740        ;
1    str        r3, [r0], #4        ;
    add        r3, r3, #0x1000
    teq        r0, r6
    bne        %b1
;-------------------------end--------------------------------##
;-----------------------修改页表映射---------------------------**   
    ; 查找该页原来的页表
    mov r1, r9                    ; 加载保留了FAR寄存器中错误地址的R9寄存器的值到R1
    mov r8, r1                    ; 将R1中的错误地址保存到R8
    mrc p15,0,r0,c2,c0,0        ; 加载页表基址寄存器C2到R0,准备软件找页表
    orr r0,r0,r1,LSR #18        ; 使用错误地址产生1级页表,由R0保存
    and r0,r0,#0xFFFFFFFC        ;
    ldr r2,[r0]                    ; 加载1级页表描述符到r2
    ;and r2,r2,#0xfffff800        ; ++++++++新增,取2级页表基地址?
    and r1,r1,#0x000ff000        ; 得到2级页表索引r1
    orr r2,r2,r1,LSR #10        ; --------得到2级页表地址r2,问什么用orr??
    ;add r2,r2,r1,LSR #10        ; ++++++++得到2级页表地址
    and r2,r2,#0xfffffffc        ; 清除低2位数据
; Generate the pagetable entry for linear mapping
    ldr r3,[r2]                    ;R3中是二级页表描述符
    and r3,r3,#0xff0            ;修改2级页表
    orr r3,r3,#0x04000000        ;修改2级页表大页地址为0x0400
    orr r3,r3,#0xe                ;2级页表改为小页
; str r3,[r2]                    ;保存新页表
; Copy data from sdram to spm
    ldr r6,=0xFFFFF000
    and r1,r3,r6                ;小页地址保存到R1
    and r2,r8,r6                ;页错地址得到1级索引和2级索引
     add    r6,r1,#0x1000
1 ldr r3,[r2]   
    str r3,[r1],#4
    teq r1,r6
    add r2,r2,#4
    bne %b1
;endof 1 page SPM in total
;-------------------------end--------------------------------**


12.开mmu。

;-------------------------开mmu -----------------------------&&
    ldr r1, =0x4005147D
    mcr p15,0,r1,c1,c0,0
    mov r0,#0x0
;--------------------------end-------------------------------&&
13.出栈。
;--------------------------出栈------------------------------[[
    ldmfd     sp!,{r0-r11, pc}^
;--------------------------end------------------------------[[

总结:先写到这,任务尚未完成。


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/84450/showart_1850301.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP