MMU与cache(ARM920)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012142460/article/details/83721588

1、虚拟地址与物理地址

        CPU通过地址来访问内存中的单元,地址有虚拟地址和物理地址之分,如果CPU没有MMU(Memory Management Unit,内存管理单元),或者有MMU但没有启用,CPU核在取指令或访问内存时发出的地址将直接传到CPU芯片的外部地址引脚上,直接被内存芯片(以下称为物理内存,以便与虚拟内存区分)接收,这称为物理地址(Physical Address,以下简称PA),如下图所示。

                                                               

        如果CPU启用了MMU,CPU核发出的地址将被MMU截获,从CPU到MMU的地址称为虚拟地址(Virtual Address,以下简称VA),而MMU将这个地址翻译成另一个地址发到CPU芯片的外部地址引脚上,也就是将虚拟地址映射成物理地址,如下图所示

       

                                                        

        MMU将虚拟地址映射到物理地址是以页(Page)为单位的,对于32位CPU通常一页为4K。例如,虚拟地址0xb700 1000~0xb700 1fff是一个页,可能被MMU映射到物理地址0x2000~0x2fff,物理内存中的一个物理页面也称为一个页框(Page Frame)。

2 ARM920T的CP15协处理器

        ARM920T的MMU和Cache都集成在CP15协处理器中,MMU和Cache的联系非常密切,我们来看看协处理器CP15的具体细节。

CP15定义了16个寄存器,寄存器的映射图如下:

 注:寄存器位置0可以访问两个寄存器,通过opcode_2的值来确定。

访问CP15协处理器的格式为

MCR/MRC{cond} P15,opcode_1,Rd,CRn,CRm,opcode_2

        对于MCR/MRC这两条指令,其实很好记忆,M代表MOVE,R为主处理器寄存器,C代表是协处理器,方向是从右向左。MCR表示数据从寄存器到协处理器,MRC代表的是数据从协处理器到寄存器。

  1. P15 为固定值
  2. Rd为主寄存器编号
  3. CRn表示协处理器寄存器编号
  4. op_code1,op_code2,CRm与其他参数配合使用

ARM920T存在3个地址。

        MVA(Modified Virtual Address)这个概念,这属于ARM的快速上下文切换(Fast Context Switch)机制,适用于一些小型的RTOS,每个进程的地址空间不超过32M,Linux并没有利用快速上下文切换机制,因此在我们的讨论当中,VA 和MVA不加区分,认为是相同的。

我们来详细看看协处理器的这几个寄存器

register0  ID code

命令格式:

MRC p15,0,Rd,c0,c0,0

寄存器的详细格式如下

register0  Cache type

命令格式:

MRC p15,0,Rd,c0,c0,1

该寄存器的格式如下:

Isize和Dsize的域是一致的

寄存器的详细描述如下

Register1,control register 控制寄存器

这个寄存器包含了ARM920T的控制位。

MRC p15,0,Rd,c1,c0,0 ;read control register

MCR p15,0,Rd,c1,c0,0;write control register

寄存器详细格式如下:0bit是cache的使能位,bit2是dcache使能位,bit12是icache使能位

Register 2,translation table base(TTB)register,页表基址寄存器。具体作用后面讲

指令格式

MRC p15,0,Rd,c2,c0,0;         read TTB register 

MCR p15,0,Rd,c2,c0,0;         write TTB register

Register 3,domain access control register读写域访问控制寄存器。

详细解释下文会介绍

命令格式:

MRC p15,0,Rd,c3,c0,0;         read domain 15:0 access permissions

MCR p15,0,Rd,c3,c0,0;         write domain 15:0 access permissions

Register 4,reserved

Register 5,fault status registers

Register 6,fault address registers

Register 7,cache operations register

这是cp15中最常用的寄存器

例如,在读内存时,确保数据从内存读取而不仅仅是从cache中读,首先使dcache无效invalid

MCR p15 ,0,rd,c7,c6,1               rd寄存器中是要invalid的虚拟内存地址。

写内存时,确保数据不仅仅写入到cache中,也要写入到内存中,首先要clean dcache

MCR p15 ,0,rd,c7,c10,1                   rd寄存器中是要clean的虚拟内存地址。

 

Register 8,TLB operations register

用来管理Translation Lookaside Buffers(TLBs),指令TLB和数据TLB

Register 9,cache lockdown register

opcode_2=0x0 访问的是Dcache

opcode_2=0x1 访问的是 Icache

Regiter 10,TLB lockdown register

opcode_2=0x0 访问的是D TLB

opcode_2=0x1 访问的是 I TLB

Register 11,12,and 14,reserved

Register 13,FCSE PID register

是快速上下文切换扩展寄存器。

MRC p15,0,Rd,c13,c0,0;read FCSE_PID

MCR p15,0,Rd,c13,c0,0; write FCSE_PID

3 MMU与CHACHE相关知识

        在第一章节中,我们知道了虚拟地址与物理地址的相关概念。那么虚拟地址是如何映射成实际的物理地址的呢?这实际上是一个查表的过程。

        虚拟地址VA被分成了三段,[31:20],[19:12],[11:0]。三段都是在一个偏移值,不同的是[31:20],[19:12]用来做两次查表索引,[11:0]用来做页内的偏移。一页的大小通常为4K。(这是其中一种情况,其他情况下面还会有介绍)

 

  1.  在协处理器的寄存器中,C2寄存器保存的时TTB的值,TTB的意思时Translation Table Base,也就是页表的基地址。这个基地址是实际的物理地址。通过它就可以找到页表。我们称这个页表是一级页表
  2. VA[31:20]字段就是表示的是在一级页表内的偏移,一级页表内共4096个表项,每个表项代表的是二级页表的物理地址。
  3. 通过第二步我们找到了二级页表的基地址,如图中的coarse page table(还有其他类型的二级页表,待会儿我们将看到),VA[19:12]字段表示的是在二级页表内的偏移,二级页表共256个表项,每个表项中保存的是某一页的物理地址。
  4. 通过第三步,我们找到了某一页的物理地址,如图中的small page,VA[11:0]字段表示的是相对于页的基地址的偏移,也就是实际的物理地址了。

        我们再来详细看看一级页表中的内容,一级页表中每一项成为一级页表描述符,一个表项占4个字节。页表描述符的内容如下

最低两bit表示的cache的格式

bit1-bit0:00 fault格式,此处的VA没有映射到PA

bit1-bit0:10 Section格式 ,没有二级页表,直接映射到物理页面。一个section是1M大页面,[31:20]是这个1M页面的基地址,[19:0]为0.Domain 和AP控制访问权限,B,C两bit控制缓存模式。下面有详细介绍。

bit1-bit0:01 coarse格式,[31:10]为二级页表的基地址,再用VA[19:12]作为二级页表的索引偏移找到二级页表,二级页表共计256项

bit1-bit0:11 fine格式,[31:12]为二级页表的基地址,再用VA[19:10]作为二级页表的索引偏移找到二级页表。

找到二级页表之后,我们会根据二级页表的内容找到页的基地址,二级页表的内容如下:

bit1-bit0:00 fault格式

bit1-bit0:01 large page,large page一页是64k,bit[31:16]就是页的基地址。

bit1-bit0:10 small page,small page一页是4k,bit[31:12]就是页的基地址

bit1-bit0:11 tiny page,tiny page的页大小是1k,bit[31:10]就是页的基地址

ap代表权限位,每2个bit为一组,tiny page只有一组,small page 和 large page 各有四组权限位,这样可以为每1/4个物理页面分别设置不同的权限,也就是说,Large Page可以为每16K设置不同的权限,Small Page可以为每1K设置不同的权限。

arm920提供了多种页表和页面规格,linux系统使用其中的一种,一级页表采用coarse page table,二级页表采用small page,也就是一页大小为4k。

再来看一下使用这种方式的详细过程

从上到下依次解释如下:

    1 VA被划分为三段用于地址映射过程,各段的长度取决于页描述符的格式

    2 TTB寄存器中只有[31:14]位有效,低14位全为0,因此一级页表的基地址对齐到16K地址边界,而一级页表的大小也是16K。

    3 一级页表的基地址加上VA[31:20]左移两位组装成一个物理地址。想一想为什么VA[31:20]要左移两位占据[13:2]的位置,而空出[1:0]两位呢?类型?,4字节对齐

   4 用这个组装的物理地址从物理内存中读取一级页描述符,这是一个Coarse Page Table格式的描述符。

   5 通过Domain权限检查后,Coarse Page Table的基地址再加上VA[19:12]左移两位组装成一个物理地址。同样是因为要四字节对齐的原因。

   6 用这个组装的物理地址从物理内存中读取二级页描述符,这是一个Small Page格式的描述符。

   7 通过AP权限检查后,Small Page的基地址再加上VA[11:0]就是最终的物理地址。想一想为什么这次不左移两位了呢?这里要查找的就是实际的地址了,并不要求四字节对齐。

 下面解释一下Domain和AP位。CP15的Domain访问控制寄存器(见表 1 “CP15协处理器的寄存器列表”寄存器3)表示了16个域(Domain),每两位表示一个Domain的访问权限,以下是该寄存器的格式:

 每个Domain的两个位可以取值为00、01、10或11

00/10:该domain不可访问

01:需要进一步检查AP位

11:改domain可以直接访问

快速上下文切换、Domain和多种规格的页表是ARM特有的机制,是针对嵌入式系统软件的特点而设计的,其它处理器不一定有类似的机制,例如也许没有Domain和快速上下文切换的概念,也许只有一种规格的页表。为了能够在多种不同的平台上移植,Linux内核代码不会利用ARM特有的这些机制。除了这些特例之外,我们在这里介绍的其它机制都具有普遍性,读者应重点把握具有普遍意义的基本原理和基本概念

 CP15的控制寄存器(见 “CP15协处理器的寄存器列表”寄存器1)中的S和R位与页描述符的AP位合在一起决定访问权限,如下所示:

  可见,同样的AP、S、R位对用户模式和特权模式来说具有不同的意义,特权模式的权限都不低于用户模式的权限。最后将各种由内存访问产生的异常总结如下:

    Alignment Fault——以Word为单位的数据访问指令地址未对齐到4字节边界,或者以Half Word为单位的数据访问指令地址未对齐到2字节边界。

    Translation Fault——页描述符的[1:0]为00,属于Fault格式,无效表项。

    Domain Fault——一级页描述符或Section所属Domain的权限位为00或10。

   Permission Fault——根据AP位和CP15寄存器1的S、R位检查访问权限,若所属Domain的权限位为11则跳过这一步检查。

    External Abort——总线异常,例如此物理地址上没有挂RAM芯片,或者其它硬件故障。

实例

我们来看一个简单的例子,使用最简单的mmu功能:1M的大页映射(只有一级页表),简单地址平板映射(0地址---0地址,1M地址---1M地址,也就是虚拟地址和物理地址实际上是一致的)

.equ PG_BASE,		0xF00000    /* Page table'offset is at 15MB */
.equ PG_DIR_SIZE,    0x4000

.equ MAX_PHY_SIZE,   0x10000000

.equ CACHE_DLINESIZE, 32

基本信息设置,页表起始地址为15M,页表大小为16k,内存最大地址为256M

 

__create_sect_pt:
    mov     r0, #0
    ldr     r1, =PG_BASE
    ldr     r2, =PG_DIR_SIZE
init:
    str     r0, [r1, #0]
    add     r1, r1, #4
    subs    r2, r2, #4
    bne     init
    ldr     r1, =PG_BASE
    ldr     r2, =MAX_PHY_SIZE
    lsr     r2, r2, #20      

开始创建页表,首先对16k页表初始化清零,最后两行是对256M内存以1M为单位进行处理,处理过程继续向下看

 

ddr_config:
    mov     r3, #0xc00
    orr     r3, r3, r0, lsl #20
    orr     r3, r3, #0x1e
    str     r3,[r1, r0, lsl #2]
    add     r0, r0, #1
    subs    r2, r2, #1
    bne     ddr_config

    mov     r0, #0x010
    mov     r2, #0xc00
    orr     r2, r2, r0, lsl #20
    orr     r2, r2, #0x12 /* Non-Cache Non-Buffer */
    str     r2, [r1, r0, lsl #2]

        对于每个1M的空间都或上0xc12标志,表示read/write都具有cache,write buffer模式。共执行256次,每1M空间都映射到了本身的地址。对于一些特殊地址,如果我们不想使用cache,比如映射到外设的地址空间,或者是专为DMA分配的内存空间,我们可以设置不适用cache,例如上面的下半部分,设置16M处的空间,不使用cache,不使用write buffer。

然后,我们就可以使能mmu和cache

__enable_caches:
     push    {r4}
     mrc     p15, 0, r4, c1, c0, 0
     orr     r4, r4, #(0x4)                      /* Enable DCache */
     orr     r4, r4, #(0x1000)           /* Enable ICache */
     mcr     p15, 0, r4, c1, c0, 0
 
     mrc     p15, 0, r4, c0, c0, 0       /* Read id reg */
     mov     r4, r4
     mov     r4, r4
 
     pop     {r4}
     bx      lr
__mmu_enable:
    ldr     r4, =PG_BASE
    mcr     p15, 0, r4, c2, c0, 0 /* Tell the MMU where to find the page table */

    orr     r0, r0, #(0x1)
    mcr     p15, 0, r0, c1, c0, 0

    mrc     p15, 0, r3, c0, c0, 0 /* Read id reg */
    mov     r3, r3
    mov     r3, r3

使能icache,dcache,并页表的起始地址赋值给协处理器c15的c2寄存器,然后将mmu使能

 

 

 

 

猜你喜欢

转载自blog.csdn.net/u012142460/article/details/83721588
920