程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)

Mini2440裸机开发之MMU

一、linux中的内存管理

1.1 虚拟内存的引出

我们都知道linux是一个多进程的操作系统,既然是多进程操作系统,那就会存在一个问题。

假设我们有两个进程A和B、并且A和B都是直接访问的物理地址,如果程序A使用了物理地址0x40000,B程序并不知道程序A使用了物理地址0x40000,B程序修改了这个地址的内容,将会影响到A程序的运行,很显然这样是行不通。

在32位操作系统下,我们期望的是每一个进程都有4GB的内存空间,而且在对自己的内存空间进行读写时,并不会影响其他进程的内存空间。

然而,32位操作系统下,我们的物理内存实际上只有4GB,linux操作系统解决这个问题的方法就是有一个虚拟内存的概念,每一个进程都有一个独立的4GB虚拟内存。虚拟地址通过MMU转换成真正的物理地址。

1.2 物理地址和虚拟地址等术语

在linux内存管理中,我们经常听到线性地址、逻辑地址、物理地址和虚拟地址,咋一看很容易混淆,让人云里雾里。

线性地址和逻辑地址都是x86的概念,主要用于内存分段机制,而在ARM平台上,没有分段机制,线性地址/逻辑地址和虚拟地址都是同一个概念,都统称为虚拟地址。

  • 物理地址:Physical addresses are those used by the actual hardware system,是硬件真实使用的地址;
  • 虚拟地址: Virtual addresses are those used by you, and the compiler and linker, when placing code in;

1.3 内存管理方式

在多任务操作系统中,内存管理方式一般可以分为:

  • 页式存储结构:将全部物理内存划分为同样大小的页面,每一个页面都有一个页号,有一片存储区域存储"页表"数据结构,页表记录了页面和索引号之间的关系。内存线性地址的前几位的含义变成了“页表索引号“,CPU通过它在“页表”中查到页号,再加上地址后几位的偏移量,得到物理地址的值;
  • 段式存储结构:段氏存储和页式存储类似,只是将内存划分的基本单位由页变成了段;

二、MMU

2.1 什么是MMU

我们之前提到过将虚拟地址转换成物理地址是通过MMU完成的。那MMU到底是什么呢?

MMU全称是memory management unit,中文叫做内存管理单元。在ARM的体系结构中,MMU可以使用内存中保存的页表来进行虚拟地址到物理地址的转换,此外MMU还可以控制cache的策略,内存的属性以及访问权限的设置。

ARM920T架构MMU单元具有以下特征:

  • 映射大小为1MB(段)、64KB(大页)、4KB(小页)和1KB(极小页);
  • 段访问权限;
  • 页访问权限;
  • 域访问权限;
  • TLB(Translation lookaside buffers),又叫快表;
  • 清除TLB,当内存中页表的内容改变或者使用新的页表时TLB中的内容需要清空,使用CP15寄存器C8完成该功能;
  • 锁定TLB,可以将一个页表项锁定在TLB中,以加快访问速度,使用CP15寄存器C10完成此功能;
  • 指令MMU和数据MMU;

2.2 协处理器

CP15,即通常所说的系统控制协处理器(System Control Coprocesssor)。它负责完成大部分的存储系统管理。

CP15包含16个32位寄存器,其编号为0~15。实际上对于某些编号的寄存器可能对应多个物理寄存器,在指令中指定特定的标志位来区分这些物理寄存器。这种机制有些类似于ARM中的寄存器,当处于不同的处理器模式时,某些相同编号的寄存器对应于不同的物理寄存器。

这里我直接截图了,内容太多,自己看吧。

2.3 域访问权限

所有段都有一个关联的域,域是内存区域的访问控制机制。ARM共有16个域,每一个域都可以设定不同的权限,将段分配到某个域,就使得这个段的权限和设定的域的权限一样。

每一个域的访问控制权限定义在CP15域访问控制寄存器C3中:

31:30 29:28 27:26 25:24 23:22 21:20 19:18 17:16 15:14 13:12 11:10 9:8 7:6 5:4 3:2 1:0
D15 D14 D13 D12 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0

每个域都有一个 2 位字段来定义对其的访问权限:

  • 00:不可访问,任何访问都会产生domain fault;
  • 01:client、访问时需要检查访问权限;
  • 10:保留;
  • 11:manager、访问时不检查访问权限;

一级转换描述符的AP位和CP15控制寄存器C1的位8(S)和位9(R)决定了如何对某块内存进行检查:

AP SR R 特权模式 用户模式
00 0 0 不可访问 不可访问
00 1 0 只读 不可访问
00 0 1 只读 只读
00 1 1 - -
01 x x 读写 不可访问
10 x x 读写 只读
11 x x 读写 读写
xx 1 1 - -

2.4 快表

由于页表是存放在内存中的,假设我们使用的是段式存储结构,这使得CPU在每存储一个数据时,都需要两次访问内存。

第一次是访问内存中的转换表(Translation table),从中找到指定段的物理段号,再将段号与段内偏移进行拼接,形成物理地址。

第二次访问内存时,才是从第一次所得地址中获得所需数据。因此采用这种方式会使的计算机的处理速度降低1/2.,可见,以此高昂的代价来换取存储器空间利用率的提高,是得不偿失的。

根据程序访问的局限性,可以使用一个高速容量较小的存储器来存储近期用到的页表条目,避免每次地址转换都到内存中查找,这样就可以大幅度提高性能,而这个高速存储器在这里被被称作快表。

2.5 VA、MVA、PA

上图为ARM920T架构的结构图,从图中我们可以看到指令/数据地址的转换过程:

  • IVA->IMVA->IPA;
  • DVA->DMVA->DPA;

ARM CPU地址转换涉及三种地址:

  • 虚拟地址(VA Virtual address);
  • 变换后的虚拟地址(MVA,Modified virtual address);
  • 物理地址:(PA, Pyhsical address);

没有开启MMU时,CPU核心、cache、MMU、外设所有部件使用的都是PA。

启动MMU之后,CPU核心对外发出VA,VA转换成MVA供cache、MMU使用,在这里MVA被转换成PA,最后使用PA读取实际数据:

  • CPU核心看到和用到的都是VA,至于VA如何去找对应的物理地址PA,CPU核心不关心;
  • cache和MMU看不到VA,它们利用MVA转换得到PA;
  • 实际设备看不到VA、MVA,读取它们使用的都是物理地址;

VA和MVA的变换关系:

如果VA<32M,需要使用进程标识号PID(通过读CP15寄存器C13获取)来转换为MVA;

if(VA<32M) then
    MVA = VA | (PID << 25)
else 
   MVA = VA

使用MVA而不使用VA的目的,当有若干个进程的时候,并且进程的链接地址都相同时,转换为MVA地址时将不会重叠。

此外每一个进程都是拥有自己的页表的,如果保证每一个进程页表映射到到的物理内存页不冲突呢?操作系统在创建进程的时候,会利用某种分配算法,进行内存分配和回收。具体可以参考操作系统内存动态分区分配算法(Java实现)

2.6 cache

ARM处理器一般内置 I cache、D cache、writer buffer。

利用程序访问的局部性,在主存和CPU之间建立高速缓存,把正在执行的指令地址附近的一部分指令或数据从主存加载到缓存中。

缓存的写回方式有两种:

  • 写穿式(write through):一旦更新cache、立即写回主存、保持cache和主存数据的始终一致;
  • 回写式(write back):数据只写到cache、并且dirty位作为标识,一旦数据被强迫换出时,检查该标识位,判断是否要写回主存;

cache有以下两个操作:

  • 清空:把cache和write buffer中已经脏(修改过的、但未写回主存)数据写回主存;
  • 使无效:使之不能再使用,并不将脏的数据写入主存;

I cache:系统刚上电,关闭的,CP15寄存器C1位12 I;

D cache:系统刚上电,关闭的,CP15寄存器C1位2 D;

write buffer和D cache是密切相连,必须在MMU开启后才能被使用。

三、MMU地址转换(MVA->PA)

下面这张图是从ARM920T手册截取到的,这张图描述了如何将一个MVA转换成物理地址的过程。

3.1 TTB base(Translation Tbale Base Register)

TTB寄存器指向内存中转换表的基地址,TTB寄存器在读取的时候低14位被设置成0。转换表最多有4096个项,每一项长度为32位,并且每一项描述1MB的虚拟内存,从而最多可以描述4GB的虚拟内存。

注意:这里我称作转换表,是直接英语翻译过来的,实际上叫法应该是一级页表。

3.2 Level  one fetch

 

通过MVA[31:20],我们首先得到Table index,然后根据Table index查找转换表中对应的项,转换表中的每一项又叫做转换描述符。

这个转换描述符就是一个存储在内存中的32位数据。通过这个描述符最后两位,可以判断是什么转换:

  • 如果是段转换,就按照段转换的格式去转换物理地址(最后两位为10);
  • 如果是页转换,就去找第二级的页表,然后再按照二级页表的格式去转换物理地址(最后两位为01:粗页,11:细页);

3.3 一级转换描述符

其中:

  • Domain字段用于指定当前段/页的权限和哪一个域的权限一致;
  • 最后两位用来指定物理地址的转换方式;

CB作用:

如果一级描述符的后两位为10,那么就是进行的段转换,一级转换描述符的[31:20]存储的就是段转换后的物段理基地址,然后加上MVA的段内地址(位[19:0])就可以得到真实的物理地址。

如果一级描述符的后两位配置为11,那么就是进行细页转换,一级转换描述符的[31:12]以及MVA的[19:10]被用来确定二级页表的位置。对应上图的Fine table page。

3.4 二级转换描述符

二级页表包含1024项,每一项的长度为32位;

亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。

日期姓名金额
2023-09-06*源19
2023-09-11*朝科88
2023-09-21*号5
2023-09-16*真60
2023-10-26*通9.9
2023-11-04*慎0.66
2023-11-24*恩0.01
2023-12-30I*B1
2024-01-28*兴20
2024-02-01QYing20
2024-02-11*督6
2024-02-18一*x1
2024-02-20c*l18.88
2024-01-01*I5
2024-04-08*程150
2024-04-18*超20
2024-04-26.*V30
2024-05-08D*W5
2024-05-29*辉20
2024-05-30*雄10
2024-06-08*:10
2024-06-23小狮子666
2024-06-28*s6.66
2024-06-29*炼1
2024-06-30*!1
2024-07-08*方20
2024-07-18A*16.66
2024-07-31*北12
2024-08-13*基1
2024-08-23n*s2
2024-09-02*源50
2024-09-04*J2
2024-09-06*强8.8
2024-09-09*波1
2024-09-10*口1
2024-09-10*波1
2024-09-12*波10
2024-09-18*明1.68
2024-09-26B*h10
2024-09-3010
2024-10-02M*i1
2024-10-14*朋10
2024-10-22*海10
2024-10-23*南10
2024-10-26*节6.66
2024-10-27*o5
2024-10-28W*F6.66
2024-10-29R*n6.66
2024-11-02*球6
2024-11-021*鑫6.66
2024-11-25*沙5
2024-11-29C*n2.88
posted @   大奥特曼打小怪兽  阅读(445)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
如果有任何技术小问题,欢迎大家交流沟通,共同进步

公告 & 打赏

>>

欢迎打赏支持我 ^_^

最新公告

程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)。

了解更多

点击右上角即可分享
微信分享提示