date: 2017-8-28linux
2011年,ARM推出了第8代架构ARMv8(ARMv4以前的架构已经被废弃),ARMv8架构是迄今为止ARM历史上变革最大的架构。编程
若是知道了架构的历史背景,以及设计者的设计理念,那么理解架构的行为方式便很容易了。为了方便后续的研究,咱们先来回顾下ARMv8的历史背景(具体可参考ARMv8白皮书,连接地址为:http://www.arm.com/zh/files/downloads/ARMv8_white_paper_v5.pdf,感兴趣的同窗能够自行阅读)。缓存
ARM为低功耗而生,过去20年,基于RISC指令集的ARM芯片在各个领域得到普遍的成功。除了移动设备领域,ARM芯片也已经悄悄渗透到PC领域(基于ARM的平板能够给用户带来PC级的体验,尤为是win10宣布支持ARM)、企业与服务器领域(这些领域一直是intel的天下)。为了更精准的响应市场的需求,从ARMv7开始,ARM将其架构分为三个品类,分别是:安全
2011年10月,ARM推出了Cortex-A7以及大小核架构,再一次振奋了业界,在延迟电池寿命的同时,为用户提供优秀智能手机的体验。Cortex系列迅速成为ARM新业务中的王牌。服务器
ARM芯片的性能上去了,那些包含复杂运算的大致量程序能够开心的跑起来了。但问题来了,这些大致量的程序须要更多的地址空间(好比超过4G的地址空间),因而AMR在AMRv7中增长了LAPE(Large Physical Address Extensions),使用48位虚拟地址,并将虚拟内存映射到40位物理内存地址上(支持高达1024G的物理内存)。网络
利用LAPE,内存空间的问题算是暂时解决了,但这只能是补救方案。若是你想继续搞企业级产品,想接着玩服务器,不搞64位操做系统行吗?不搞虚拟化行吗?所以ARM在设计v8架构时,它面临下面几个“刚需”:架构
因为基于32位ARMv7架构的Cortex系列大受欢迎,并且已经创建起完善的开发者生态。所以新架构(指ARMv8)不能推倒重来另起炉灶,必须兼容ARMv7架构中的主要特性。app
为了兼容32位程序,新架构将运行状态分红AArch64和AArch32两种状态,这两种状态的具体情形见下表:dom
AArch64: | 64bit的运行状态。地址存储在64bit的寄存器中,使用A64指令集,可使用64bit寄存器 |
提供31个64位的通用寄存器(命名为X0-X30,能够经过W0~W30来访问低32位。X30通常用做程序连接寄存器); | |
一个64位的程序计数器(PC); | |
64位的堆栈指针SP(每一个异常等级一个); | |
以及64位的异常连接寄存器ELR(每一个异常等级一个),存储了从中断返回的地址 | |
提供32个128位的NEON浮点寄存器(命令为V0-V31),支持SIMD的向量运算以及标量浮点的运算 | |
使用A64指令集,A64指令集使用固定长度的指令,指令使用32位编码 | |
从新定义了异常模型,该模型定义了4个异常等级EL0-EL3,异常等级提供了执行权限的等级制度,层级越高,权限越大。 | |
支持64位的虚拟地址空间 | |
定义了一组Process state寄存器PSTATE(NZCV/DAIF/CurrentEL/SPSel等),用于保存PE当前的状态信息,A64指令集提供专门的指令来访问这些PSTATE | |
每一个系统寄存器(System register)名称后面都带有一个后缀,该后缀表示能够访问该寄存器的最低EL级别 | |
AArch32: | 32bit的运行状态。地址存储在32bit的寄存器中,可使用T32或者A32指令,使用32bit的寄存器 |
提供13个32位的通用寄存器(R0-R12); | |
一个32位的程序计数器PC; | |
一个32位的堆栈指针寄存器SP; | |
一个32位的程序连接寄存器LR,LR不只做为程序连接器也用做异常连接寄存器ELR | |
提供一个ELR,用来保存Hyp模式下异常返回的地址,Hyp模式与虚拟化有关。 | |
提供32个64位的浮点寄存器,支持Advanced SIMD的向量计算以及标量浮点运算 | |
使用A32(使用固定长度指令,指令32位编码)或者T32(使用变长指令,指令编码能够是16位的也能够是32位的)指令集 | |
支持ARMv7架构中基于PE模式(FIQ/IRQ/Abort/Undefined/Svc)的异常模型。本质上是将PE模式映射到ARMv8架构中基于异常等级的异常模型中来。 | |
支持32位的虚拟地址空间 | |
定义了一组Process state寄存器PSTATE(NZCV/DAIF/CurrentEL/SPSel等),用于保存PE当前的状态信息,A32/T32指令集提供专门的指令来访问这些PSTATE。指令能够经过APSR(Application Program Status Register)或者CPSR(Current Program Status Register)来访问PSTATE,就像在ARMv7架构中作的那样。 |
表1:AArch64与AArch32的对比ide
ARMv7及以前的架构,为PE定义了不少种模式:System/User/FIQ/Svc/Abort/IRQ/Undefined,每种模式都有本身的R13(用做SP)与R14(用做LR),FIQ模式还有本身的R8-R12。应用程序大部分时间跑在User模式下。这种设计,一方面是权限隔离,不一样的模式有不一样的资源访问权限;另外一方面,FIQ/Abort/IRQ/Undefined这几种模式与异常或者中断关联,处理相应的异常时迅速切换到对应的模式提升了处理效率。
到了ARMv8,ARM摒弃了这种多模式的设计,从新定义了一套异常或者说等级模型:
异常等级也能够理解为特权级别(Privilege Level)。特权级别划分出来了,那么在每一个级别,均可以干那些事?ARM对这4个等级的设想能够描述以下:
图1:四个异常等级的实施例
在实现架构时(ARM只是出设计,具体的芯片由厂商实现),并非全部的EL都要实现,其中EL0-EL1是必需要实现的,EL2主要是为了支持虚拟化,能够不用实现,EL3用来支持Security,也能够不实现。
AArch32运行状态兼容ARMv7中的多模式PE,是经过将不一样的PE模式映射到不一样的EL来实现的。
若是换作你,如何在ARMv8架构的等级模型上构建Linux操做系统呢?Linux操做系统只用到两个特权级别:用户空间程序与操做系统内核,用户空间的程序通常运行在非特权级别,操做系统内核运行在特权级别,用户空间发起的系统调用,以及触发的异常与中断,都须要交给“具备特权”的内核空间来处理。所以,针对ARMv8架构,用户空间能够落实到EL0层,内核空间能够落实到EL1层。
为了向下兼容,ARM v8a将运行状态分红AArch64和AArch32两种状态。AArch64就是64位指令集的运行态,而AArch32是兼容Arm-v7a的状态,全部Arm-v7a以及更早的软件均可以在这个状态上正常运行。对于应用程序来讲,因为EL0没有权限进行AArch64和AArch32状态切换的,所以只能一条道走到黑地用一种态。这也是AArch64与AArch32使用各自独立指令集的缘由,两种状态下的指令集保持着井水不犯河水的“克制”。但两者在同一个系统中能够共生,不免眉来眼去:
图2:AArch32状态的下用到的寄存器是用AArch64中的寄存器来模拟的
地址映射就是把PE发出的虚拟地址映射为内存的物理地址的过程。将虚拟地址映射为物理地址,显然这是一件须要“特权”才能干的事(出于安全考虑,不能在非特权级去执行,否则,那些坏人想攻破你的系统不要太容易),须要与特权等级也就是异常等级联系起来:
异常等级及其支持的地址映射以下图所示:
图3:stage1/stage2地址映射与异常等级的关系
安全与非安全是一种“物理隔离”。当PE运行在安全模式下,它能够访问那些标记为安全的内存(表示这些内存只能在安全模式下访问),也能够访问那些标记为非安全的内存。当PE运行在非安全模式,它只能访问那些标记为非安全的内存,而没法访问那些标记为安全的物理内存,从而实现物理隔离。
只有在非安全状态下,从EL1/EL0提高至EL2等级时,Stage2的地址映射才会开启。若是Stage2没有开启,那么Stage1从虚拟地址VA转换后获得的地址就是物理地址PA。而若是Stage2开启,那么Stage1从虚拟地址VA转换后获得的地址被称为“中间态”物理地址IPA,Stage2再将IPA转换为物理地址PA。
地址映射就是将虚拟地址映射为物理地址,Stage1就够了,为什在EL2层又加上Stage2呢?咱们能够这样理解:
在后面的讨论中,咱们认为只进行stage 1的地址映射。
64位系统能够支持更多的虚拟地址空间了,那么须要将虚拟地址直接提升到64位吗?一方面,虚拟地址空间越大,一次地址映射(TTW,translation table walk)就须要更多级(Level)的查找。好比在32位系统中,若是page的尺寸为4K,可能经过两级查找(目录表查找/页表查找)就能将一个32位的虚拟地址映射为对应的物理地址;若是虚拟地址提升到64位,则须要超过4级的查找才能完成一次地址映射,致使地址映射的开销增长。另外一方面,当前也没有那么大的物理内存,用40位的物理地址就能覆盖1024G的物理内存了,已经足能够应付当前及将来很长一段时间的需求了。
所以,ARMv8的地址映射基于ARMv7的LAPE机制,LAPE的设计之初是要解决在如何在32位系统给程序提供超过4G内存空间的问题。LAPE使用48位虚拟地址,而且能够将虚拟内存映射到40位物理内存地址上。每一个TTBR(地址映射表基址寄存器)最多可支持48位的虚拟地址空间,具体的位数在运行时设定。在一次TTW过程当中,有多少个级别的查找,取决于使用多少位的虚拟地址。
若是地址映射只支持一个VA区间(TCR_ELx 中若是只有T0SZ域有效,说明地址映射只支持一个虚拟地址空间),则TTBR_ELx指向转换表的基址,且L0(第一级)查找必须使用该转换表。VA区间的虚拟地址位数=64-TTBR_ELx.T0SZE。
若是地址映射支持两个虚拟地址区间(TCR_ELx 中T0SZ域与T1SZ域都有效),则每一个虚拟地址区间对应一个TTBR_ELx寄存器,其中TTBR0_ELx指向第一VA区域(起始地址为0x0000000000000000)的转换表的基址,第一VA区域的虚拟地址位数=64-TCR_ELx.T0SZ;TTBR1_ELx指向第二个VA区域(截止地址为0xFFFFFFFFFFFFFFFF)的转换表的基址,第二个VA区域的虚拟地址位数=64-TCR_ELx.T1SZ。
下图展现了EL1/EL0 Stage1的地址映射,该转换支持两个VA区域,虚拟地址位数为48,各个VA区域的地址空间范围如图中所示:
图4:当地址映射支持两个VA区域时每一个VA区域的分布状况
虚拟地址的位数肯定了为48位,那么咱们要为48位的虚拟地址从新建立一种数据类型吗?彻底不必,咱们用现成的64位整数来存储地址,只是在进行地址映射时,从64位中取出“有效地址位”即低48位做为虚拟地址。高16位彻底能够拿来“变废为宝”,记录一些额外的信息。
虚拟地址的位数定下来了,那么地址映射过程当中要通过几级查找,才能把虚拟地址对应的物理地址找到呢?这与地址映射粒度有关。转换粒度由两个含义:一是page的大小,二是查找表的大小即表中包含多少个表项。page大小与查找表之间有什么关联呢?为了提升效率,通常将查找表的尺寸与page对齐,这样一个page就能容纳一张查找表了。查找表的尺寸肯定了,表中每一项的尺寸是固定的(为64位),那么整个查找表的大小就能够肯定了。
ARMv8架构支持3种地址映射粒度,以下表:
4KB granule |
16KB granule |
64KB granule |
|
查找表的大小(最多能够容纳的条目数) |
512 |
2048 |
8192 |
每级查找消耗虚拟地址中的位数 |
9-bit |
11-bit |
13-bit |
页内偏移offset |
VA[11,0] |
VA[13,0] |
VA[15,0] |
支持几级查找 |
4级 |
4级 |
3级 |
TCR_ELx.TG0域(共2bit)的取值 |
00b |
10b |
01b |
表2:3种转换粒度对比表
咱们以4KB的粒度来讲明上表中各项的含义。
如无特殊声明,后文中咱们讨论的地址映射是以4KB为粒度的。4KB转换粒度下的4级查找,以下图所示:
图5:查找粒度为4K时4级查找过程
咱们历经4级查找,最终目的是为了找到容纳目标物理内存的物理页的起始地址。物理内存是以页为单位组织起来的,所以,要找物理内存,先找到它所在的页。这种内存管理方式被称做页式内存管理。
如今咱们思考一个问题,为何要建立这种层级查找结构,为何不干脆搞一张超大的页表,表里的每一项指向一个页面的基址。这样只须要查一次表就能够完成地址映射了,整个结构更扁平了,以下图示意。
图6:一种设想的只须要一级查找的地址映射过程
这种架构至少存在下面几个问题:
首先,Page Table的大小问题。为了完成一次就能找到的目标,Page Table确定是个线性表(不能玩hash表那一套),用索引作下标直接能够找到对应的项,而咱们又是拿虚拟地址去索引这张表,所以虚拟地址覆盖多少个Page,Page Table中就应该有多少项。所以在32位系统中就有 4G/4K=1M个Page。因此Page Table中要有1048576个表项,每一个表项4byte,则Page Table就要消耗掉4M的空间。若是实际的物理内存只有512M,那Page Table中的不少项就会白白浪费。而在4级查找中,经过4个层级的查找表,咱们创建起了一个查找树(或者目录树),整棵查找树是动态造成的。一个进程不可能用光全部的虚存空间,虚存空间中确定有不一样大小级别的空洞,在树形结构中,对于空洞咱们能够不建立对应的查找表从而节省空间。下图展现了AArch64的4级查找表构成的查找树。L0 Table中的一个表项领衔512G的地址空间,若是进程用不到这块地址空间,那么以该表项为根,衍生的1个L1 Table以及512个L2 Table,以及由512个L2 Table衍生的512*512个L3 Table都不会被建立。一样,L1 Table的一个表项领衔1G的地址空间,若是该1G空间不会被用到,那么由该表项衍生的全部查找表都不会被建立。
图7:4个层级组成的查找树
其次咱们要考虑cache命中率的问题。因为那张Page Table太大了,cache每次只能装载其中的一部分。因为地址的跳跃,致使Page Table的索引跳跃,致使以前加载到cache中内容失效,须要从新装载cache。而在4级查找结构中,每一个查找表的size与Page size对齐,提升了cache的命中率。
综合这两点,咱们获得结论:页式内存管理是综合考虑空间与效率的结果。
经过前面的介绍,咱们已经看到了,4KB的转换粒度须要4个级别的查找(因此才用translation table walk来描述地址映射过程,转换过程就像在一条分叉众多的路上行走同样,每到一个路口,就须要拿出你的指南针,去找到前进的方向),这条路径并不短。有没有能够提早结束查找的方法呢?
ARM在内存页以外,提出内存block,一个block包含多个连续的页,一个块能够覆盖的空间更大。若是咱们咱们知道物理内存在某个块中,并且知道了相对于块基址的偏移,那么咱们只须要找到这个块的基址,再加上块内偏移,即可以获得物理内存的地址,从而提早就是查找过程。所以查找表中,可能存在在两种表项:
4KB转换粒度下的4级查找能够进化到这种样子:
图8:考虑内存block后,4KB转换粒度下的4级查找
在上图中咱们也看到,在4KB的转换粒度下的4级查找中,只有L1 Table以及L2 Table中能够出现block描述符。L1 Table中的一个block描述符领衔1GB的地址空间(由于剩下的位段为IA[29:0]共30bit,能够覆盖1G的空间),T2 Table中的block描述符领衔2MB的地址空间(由于剩下的位段为IA[20:0]共21bit,能够覆盖2MB的空间)。block描述符与转换粒度的关系见下表:
转换粒度 |
block描述符 |
4KB |
L0 不支持block描述符 L1 支持block描述符,一个block领衔1GB的地址空间 L2 支持block描述符,一个block领衔2MB的地址空间 |
16KB |
L0/L1不支持block描述符 L2 支持block描述符,一个block领衔32MB的地址空间 |
64KB |
不支持L0级别的查找(只有三级查找:L1-L3) 若是ARMv8.2-LPA功能没开启的话,L1不支持BLOCK L2支持block描述符,一个block领衔512MB的地址空间 |
表3:3种转换粒度下block描述符对比
请你们思考下,当转换粒度为4K时,为何L0不支持block呢?
由于L0若是支持block的话,一个block领衔512G空间。一方面当前Android手机的内存最大才12G,上哪去找一块连续的大小为512G的物理内存呢?另外一方面block太大,也缺乏一些必要的灵活性。
上表中并无说L4是否支持block,要不要支持呢?答案是不须要支持。L4中维护的已是页表了,在L4这个级别,即便支持block,block的尺寸已经与page一致了,固然就不必画蛇添足再支持block了。
L0-L3查找表中的描述符格式:
前文说过,L0-L3的转换表中的描述符可能存在两种状况:table描述符与block描述符。下图列出转换粒度为4KB时,L0-L3的描述符格式:
图9:4KB转换粒度下的L0-L2对应的描述符格式
咱们拿64位的整数来表示地址,前文提到过,有效的虚拟地址只有48位,所以其余的位段能够挪做他用。因为转换表的尺寸与page对齐,转换表的基址与4K对齐,因此48位的基址中低12位确定为0,这低12位也可拿来作文章。这里用bit[1:0]来指示该描述符的类型,以下表:
Bit[1:0]取值 |
描述符类型 |
‘x0’ |
无效描述符 |
‘01’ |
block描述符,output address指向一个block的基址 |
‘11’ |
Table描述符,next-level table address指向下一级转换表的基址 |
表4:L0-L2描述符类型
在block描述符中,bit[63:52]与bit[11:2]这两个位段用来描述block属性(后文讨论这些属性)。
在table描述符中,bit[63:59]用来表示与table有关的属性,详细以下表:
标志位 |
描述 |
NSTable |
NS表示Non-Secure,该table描述符指向的下一级的转换表是否存储在secure memory之中。 为0表示存储在Secutre PA中,不然表示存储在Non-secure PA中。 当在non-secure状态下进行地址映射时,该标志别忽略 |
APTable |
AP表示Access Permission,这两个标志为指明了下一级转换表的访问权限,有以下4中状况: ‘00’——不作限制 ‘01’——EL0没有权限访问 ‘10’——任何异常等级都不能写(修改转换表) ‘11’——任何异常等级都不能写(修改转换表);并且EL0不能读 |
UXNTable /XNTable |
当地址映射支持两个VA区域时,名称为UXNTable,当地址映射只支持一个VA区域时,名称为XNTable。 UXN 的含义是“Unprivileged Execute Never”,XN的含义是“Execute Never”。它们用来表示内存的执行权限。好比咱们在加载动态库时,动态库的代码段所在的地址就具备执行(x)权限。若是标志位为0表示具备执行权限,不然没有执行权限。 |
PXNTable |
该标志只有当地址映射支持两个VA区域时有效。PXN表示Privileged Execute Never,表示内存是否具备“特权执行”权限,好比内核的代码便具备“特权执行”的权限。 |
表5:Table描述符中的标志位
L3页描述符格式:
L3查找表即页表,4KB转换粒度下,页表的描述符格式以下:
图10:4KB转换粒度下的L3页描述符格式
页描述符与block描述符中的属性字段:
从前文可知,block描述符与page描述符都有两个属性位段,主要的属性字段以下:
图11:block描述符与table描述符中的属性位段
这些属性的含义以下表:
属性位段 |
描述 |
|||||||||||||||
Contiguous |
该表项是否为连续表项中的一项。即转换表在该表项先后是连续的,没有空洞。这样,这些连续的表项便有可能一次性加载到cache中(好比由一个TLB entry缓存) |
|||||||||||||||
nG |
not Global 若是该表项缓存在TLB中,该标志位指示TLB entry是全局有效仍是仅仅对当前进程有效 |
|||||||||||||||
AF |
Access Flag 当该标志为0,标明对应的内存区域(一个block或者一个page)是第一次访问 |
|||||||||||||||
SH |
Shareability Field 参考后文 |
|||||||||||||||
AP[2:1] |
Access Permission. control the stage 1 data access permissions, and: AP[2] Selects between read-only and read/write access. AP[1] Selects between Application level (EL0) control and the higher Exception level control. This provides four permission settings for data accesses: • Read-only at all levels. • Read/write at all levels. • Read-only at the higher Exception level, no access by software executing at EL0. • Read/write at the higher Exception level, no access by software executing at EL0. the following talbe shows the meaning of the AP[2:1] field for stage 1 of a translation regime that applies to both EL0 and a higher Exception level. In this table, an entry of None indicates that any access from that Exception level faults.
|
|||||||||||||||
NS |
Non-secure 当从Secure状态访问内存时,该标志指示转换后的地址在Secure区域仍是在Non-Secure区域 |
|||||||||||||||
AttrIndx |
指向内存区域的类型以及可缓存性。 参考后文 |
表6:block描述符与table描述符中的属性字段的含义
ARMv8中定义了以下两种内存类型(在ARM手册中,类型是从内存模型的角度来描述,这里摘自网络定义)
类型 |
特性 |
Normal (普通) |
。读写通过Cache 。支持乱序,内存访问顺序同编程顺序可能不一致 。支持预读取 。支持内存非对齐访问 |
Device (设备) |
。读写不通过Cache 。不支持乱序内存访问 。不支持预读取 。不支持内存非对齐访问 Device类型的内存还有三个属性,分别用G/R/E来表示,它们的定义是:
|
表7:内存类型分为normal与device
除了类型外,ARM还定义了其余内存特性,它们的含义以下:
Shareability (可共享性) |
指当前内存页表项的数据是否能够同步到其它CPU上,多核CPU调用带有该属性页表项的数据,一旦某个CPU修改了数据,那么系统将自动更新到其它CPU的数据拷贝,实现内存数据一致性. 对于Normal类型的内存,有3种状况: • Inner Shareable, meaning it applies across the Inner Shareable shareability domain. • Outer Shareable, meaning it applies across both the Inner Shareable and the Outer Shareable shareability domains. • Non-shareable. |
Cacheability (可缓存性) |
指当前内存页表项对于的数据是否能够加载到Cache当中 对于Normal类型的内存,有3种状况: • Write-Through Cacheable. • Write-Back Cacheable. • Non-cacheable. |
表8:内存的可共享性与可缓存性
本文首先介绍了ARMv8的历史背景,了解了ARMv8主要的发力点:一是为了支持更大的地址空间,ARMv8被设计成64为的架构,而且从新设计的指令集T64;二是为了应对企业级(服务器)的市场,提供对虚拟化的支持;三是对安全的加强。
为了兼容旧的架构,ARMv8定义了两种运行状态:AARch64与AArch32,在AArch64状态下运行64位指令,在AArch32状态下运行32位的ARM指令或者16位的Thumb指令。
ARMv7及以前的架构为处理器设置了7种模式(mode),并在此基础上搭建了ARM的异常处理架构。ARMv8摒弃了这种设计, 它定义了4个异常等级(简称EL),异常等级构成了一个特权的等级制度,ARMv8在此基础上构建新的异常处理架构。CPU厂家在实现本身的CPU时,只有EL0与EL1是必选项,EL2(主要用来支持虚拟化)与EL3(主要用来支持安全)是可选项。
当EL2存在时,ARM能够提供两个stage的地址映射。不过EL2主要用做虚拟化,手机上的CPU能够不实现。这个时候只须要通过一个stage的地址映射,就能将虚拟地址(VA)转换成物理地址(PA)。一个stage 的地址映射能够支持两个VA区域,好比第一VA区域(起始地址为0x0000000000000000)给用户空间使用,第二个VA区域(截止地址为0xFFFFFFFFFFFFFFFF)给内核使用。
ARMv8虚拟内存架构发展自ARMv7的LAPE机制,支持48位虚拟地址。不过最终虚拟地址的宽度能够经过TCR_ELx的T0SZ域或者T1SZ域(对于支持两个VA区域的地址映射来讲)来指定。虚拟地址的宽度定好后,虚拟地址的空间大小便肯定下来了。
ARMv8支持3种转换粒度(经过TCR_ELx寄存器的TG0域来指定):4KB、16KB与64KB。转换粒度不只定义了page的size,也定义了查找表的尺寸。当转换粒度为4KB时,一个stage的地址映射支持4个level的查找(这与linux的4级内存管理暗合),这四个level分别记做L0~L3。这样,一个虚拟地址便被分红了5部分:L0 Index、L1 Index、L2 Index、L3 Index与offset。在查找时,拿Lx Index在Lx Table中查表(就是将Lx Index做为索引,拿Lx Table的基址 + Lx Index),获得下一级查找表的基址。L0 Table的基址存储在寄存器TTBR中。L3 Table是一个页表PT,页表中每一个表项指向一个物理page的起始地址,当经过4级查找以后,就能够找到虚拟地址对应的物理地址。
为了加快地址映射过程,当转换粒度为4KB时,能够在L1 Table或者L2 Table中插入一些block描述符,block表示匹配到一块连续的物理内存。在地址映射过程当中,若是虚拟地址与一个内存块匹配,则能够提早结束查找过程,从而提升地址映射效率。所以,在L0~L2 的Table中,存在两种描述符:block描述符与table描述符。
咱们拿64位的整数来表示地址,L0~L3 Table中的描述符也是64位的,而有效的虚拟地址只有48位,所以描述符中的其余的位段能够挪做他用,好比用做标记或者用来指示转换表以及内存的相关属性。