中文字幕理论片,69视频免费在线观看,亚洲成人app,国产1级毛片,刘涛最大尺度戏视频,欧美亚洲美女视频,2021韩国美女仙女屋vip视频

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
ARMv7-A 處理器窺探
userphoto

2022.11.02 上海

關注
ARM 官方針對 ARMv7-A 處理器的描述再:

ARMv7-A_and_R_Architecture_Reference_Manual

1、處理器模式

1.1、特權等級

ARMv7架構支持安全擴展,如果使能了安全擴展,ARMv7-A架構分為安全模式(Secure State)和非安全模式(Non-secure State)兩個世界。
在非安全模式下,存在三種運行特權 PL0,PL1和 PL2(Privilege level)。(這里僅僅討論非安全 State)

特權等級描述
PL0PL0運行在用戶模式(User),用于運行應用程序。該模式程序受限訪問系統(tǒng)資源。對應Linux用戶態(tài)。
PL1PL1運行非用戶模式和Hyp模式外的所有模式。Linux內核運行在PL1。包含了ARMv6架構中的System,SVC,FIQ,IRQ,UNDEF及Abort模式。此外,安全模式中的Montior也運行在PL1等級,管理安全模式和非安全模式的切換。
PL2PL2用于虛擬化。虛擬化超級管理程序(Hypervisor)運行在 PL2。

這里的 PL0~PL2 指的是特權等級,不同的特權等級,訪問資源的權限不一樣,操作系統(tǒng)運行再 PL1 的特權等級下,具有較高的訪問權限,用戶態(tài)運行再 PL0 的特權等級下(也叫非特權等級),只有最最基本的訪問權限;

 

1.2、處理器模式

上面說的是處理器的特權等級,那么處理器真正的運行的模式有幾種呢?如下所示:

可以看到,ARMv7-A 的處理器模式有 User、FIQ、IRQ、Supervisor、Monitor、Abort、Hyp、Undefined、System 模式:

User:用戶模式,運行再 PL0 這個特權等級上,也就是沒有特權等級,他是OS上運行應用程序時候的等級,他不可以訪問系統(tǒng)資源(諸如 MMU 等),在這個模式下,無法主動切換模式,除非遇到中斷或者異常(諸如 SWI 觸發(fā)系統(tǒng)調用);

FIQ:快中斷模式,發(fā)生 FIQ 快中斷的時候處理器模式;

IRQ:中斷模式,發(fā)生 IRQ 快中斷的時候處理器模式;

Supervisor:管理員模式,復位后的默認模式,運行再 PL1 特權等級,可以通過 SWI(SVC) 系統(tǒng)調用呼叫產(chǎn)生 Supervisor Call 異常,進入 Supervisor 模式,操作系統(tǒng)常用的模式;

Monitor:監(jiān)視模式,針對 Security 擴展,不詳細討論;

Abort:停止模式,當發(fā)生 Data Abort exception 或者 Prefetch Abort exception 異常時候進入這個模式;

Hyp:當支持虛擬化擴展的時候模式,不詳細討論;

Undefined:這是執(zhí)行和指令相關的模式,當企圖執(zhí)行 UNDEFINED 指令的時候進入這個模式;

System:系統(tǒng)模式,也是 PL1 特權等級,和 Supervisor 的區(qū)別是,System 模式具有和 User 模式一樣的寄存器,目前大多數(shù)系統(tǒng)未使用;

2、寄存器組織

2.1、通用寄存器

ARMv7-A 處理器有 16 個通用寄存器:R0~R15,其中:

R13:通常用做堆棧指針 SP;

R14:通常用作鏈接寄存器 LR;

R15:通常用作程序計數(shù)器 PC;

前面說了處理器有特權等級,每種特權等級訪問系統(tǒng)資源的權限不一樣,而處理器又有幾種模式,每種模式對應的特權等級有一定區(qū)別;

每一種處理器模式對應的寄存器也有一定區(qū)別:

從上圖可以看出:

1、R0~R7,PC是所有模式下共享的;

2、FIQ 模式下,R8~R12、SP、LR 都是有專門的寄存器,有的材料上,稱之為“影子寄存器”,什么意思呢?這個模式下,有他專用的 R8~R12、SP、LR;

3、同樣道理,Supervisor、Abort、Undefined、IRQ 等,都有他們自己模式下專用的 SP 和 LR,也就是說,從其他模式進來的時候,不需要針對這兩個寄存器進行恢復現(xiàn)場;

4、FIQ 之所以稱之為 FIQ,從軟件上也看得出來,他專用的寄存器要多于 IRQ 的,所以也的確是要 Fast 一些;

從這里,我們也可以看出,exception 發(fā)生的時候,我們其實是有必要手動保存一些現(xiàn)場的;

2.2、特殊寄存器

ARMv7-A 還有一個特殊寄存器叫:程序狀態(tài)寄存器 CPSR(Current Program Status Register),再進入異常之前,當前的 CPSR 被保存到 SPSR (Saved Program Status Register)中;

當然 CPRS 再用戶層叫做 APSR,APSR 只是 CPSR 寄存器中被截取的一部分,因為在用戶層,并不是所有的 CPSR 的位都可以訪問;

CPSR 的組成如下所示:

Field作用
NALU返回運算結果是否為負數(shù)
ZALU返回運算結果是否為0
CALU運算是否發(fā)生進位
VALU運算是否發(fā)生溢出
Qcumulative saturation
JARM是否處于 Jazelle 狀態(tài)
E控制 load/store 字節(jié)序,E=1表示大端模式,E=0表示小端模式;
Adisables asynchronous aborts,User模式不能操作
I使能/禁能 IRQ,User模式不能操作,I=1表示禁止 IRQ,I=0表示使能 IRQ;
F使能/禁能 FIQ,User模式不能操作,F(xiàn)=1表示禁止 FIQ,I=0表示使能 FIQ;
TARM和Thumb狀態(tài)標志位
GE用于某些SIMD(Single Instruction, Multiple Data)指令
M[4:0]處理器模式:FIQ,IRQ,ABT,SVC,UND,MON,HYP。User模式不能操作
IT[7:0]IT[7:2](bit15:10):和IT[1:0](bit26:25)一起組成IT[7:0],表示IF-THEN指令的執(zhí)行狀態(tài);

這里的 M[4:0] 就是直接對應到了前面講到的模式,還記得在前面那個處理器模式的列表中,每一個模式都對應了一個 Encoding 嗎?這個 Encoding 就是這個 M 位的值;

3、指令集

ARMv7-A 支持 32bit ARM 指令集的同時,還支持 16bit 的 Thumb 指令集,它具有更好的代碼密度,處理器可以在這兩種指令集之間切換;

所有的Cortex-A系列處理器實現(xiàn)了Thumb-2技術,它擴展了Thumb指令集。混合使用32位和16位指令,以Thumb指令集的代碼密度和接近ARM指令集的性能。自從所有的Cortex-A系列處理器支持這一擴展,針對它們的軟件常被編譯成Thumb指令集;

ARM 處理是加載/存儲體系結構的典型的RISC處理器,對存儲器的訪問只能使用加載和存儲指令實現(xiàn)。ARM 的加載/存儲指令是可以實現(xiàn)字、半字、無符/有符字節(jié)操作;批量加載/存儲指令可實現(xiàn)一條指令加載/存儲多個寄存器的內容,大大提高效率;

3.1、指令集格式

基本格式為:

<opcode>{<cond>}{S} <Rd>,<Rn>{,<opcode2>}

<>內的項是必須的,{}內的項是可選的,如<opcode>是指令助記符,是必須的,而{<cond>}為指令執(zhí)行條件,是可選的,如果不寫則使用默認條件AL(無條件執(zhí)行)

opcode:指令助記符,如 LDR,STR 等

cond:執(zhí)行條件,如EQ,NE 等

S:是否影響CPSR 寄存器的值,書寫時影響CPSR,否則不影響

Rd :目標寄存器

Rn:第一個操作數(shù)的寄存器

operand2:第二個操作數(shù)

3.2、常用指令集

3.2.1、LDR/STR

LDR指令用于從內存中讀取數(shù)據(jù)放入寄存器中;STR 指令用于將寄存器中的數(shù)據(jù)保存到內存。指令格式如下:

LDR{cond}{T} Rd,<地址>;      加載指定地址上的數(shù)據(jù)(字),放入Rd中

STR{cond}{T} Rd,<地址>;      存儲數(shù)據(jù)(字)到指定地址的存儲單元,要存儲的數(shù)據(jù)在Rd中

LDR/STR 指令尋址是非常靈活的,由兩部分組成,一部分為一個基址寄存器,可以為任一個通用寄存器,另一部分為一個地址偏移量。地址偏移量有以下3種格式:

(1) 立即數(shù)。立即數(shù)可以是一個無符號數(shù)值,這個數(shù)據(jù)可以加到基址寄存器,也可以從基址寄存器中減去這個數(shù)值。指令舉例如下:

  1. LDR R0,=0X123     ; 將0X123存入r0中
  2. LDR R0,=label    ; 將label_1所指向的地址值存入r0中

  3. LDR R1,[R0] ; 將 R0 地址處的數(shù)據(jù)讀出,保存到R1中 (R0 的值不變)
  4. LDR R1,[R0,#0x12] ; 將 R0+0x12 地址處的數(shù)據(jù)讀出,保存到R1中 (R0 的值不變)
  5. LDR R1,[R0,#-0x12]; 將 R0-0x12 地址處的數(shù)據(jù)讀出,保存到R1中 (R0 的值不變)

(2)寄存器。寄存器中的數(shù)值可以加到基址寄存器,也可以從基址寄存器中減去這個數(shù)值。指令舉例值。指令舉例如下:

  1. LDR R1,[R0,R2] ; 將R0+R2 地址的數(shù)據(jù)計讀出,保存到R1中(R0 的值不變)
  2. LDR R1,[R0,-R2] ; 將R0-R2 地址的數(shù)據(jù)計讀出,保存到R1中(R0 的值不變)

(3)寄存器及移位常數(shù)。寄存器移位后的值可以加到基址寄存器,也可以從基址寄存器中減去這個數(shù)值。指令舉例如下:

  1. LDR R1,[R0,R2,LSL #2] ;將R0+R2*4地址處的數(shù)據(jù)讀出,保存到R1中(R0,R2的值不變)
  2. LDR R1,[R0,-R2,LSL #2];將R0-R2*4地址處的數(shù)據(jù)計讀出,保存到R1中(R0,R2的值不變)

一組代碼示例:

  1. NumCount EQU 0x40003000 ;定義變量NumCount
  2. LDR R0,=NumCount ;使用LDR 偽指令裝載NumCount的地址到R0
  3. LDR R1,[R0] ;取出變量值
  4. ADD R1,R1,#1 ;NumCount=NumCount+1
  5. STR R1,[R0] ;保存變量值
  6. GPIO 設置
  7. GPIO-BASE EQU 0Xe0028000 ;定義GPIO 寄存器的基地址
  8. LDR R0,=GPIO-BASE
  9. LDR R1,=0x00FFFF00 ;裝載32 位立即數(shù),即設置值
  10. STR R1,[R0,#0x0C] ;IODIR=0x00FFFF00, IODIR 的地址為0xE002800C
  11. MOV R1,#0x00F00000
  12. STR R1,[R0,#0x04] ;IOSET=0x00F00000,IOSET 的地址為0xE0028004

 

3.2.2、LDM/STM

批量加載/存儲指令可以實現(xiàn)在一組寄存器和一塊連續(xù)的內存單元之間傳輸數(shù)據(jù)。LDM 為加載多個寄存器,STM 為存儲多個寄存器。允許一條指令傳送16 個寄存器的任何子集或所有寄存器。指令格式如下:

LDM{cond}<模式> Rn{!},reglist{^}

STM{cond}<模式> Rn{!},reglist{^}

LDM /STM 的主要用途是現(xiàn)場保護、數(shù)據(jù)復制、參數(shù)傳送等。其模式有8種,如下所列:(前面4 種用于數(shù)據(jù)塊的傳輸,后面4 種是堆棧操作)。

(1) IA:每次傳送后地址加4
(2) IB:每次傳送前地址加4
(3) DA:每次傳送后地址減4
(4) DB:每次傳送前地址減4
(5) FD:滿遞減堆棧
(6) ED:空遞增堆棧
(7) FA:滿遞增堆棧
(8) EA:空遞增堆棧

其中,寄存器Rn 為基址寄存器,裝有傳送數(shù)據(jù)的初始地址,Rn 不允許為R15;后綴“!”表示最后的地址寫回到Rn中;寄存器列表reglist 可包含多于一個寄存器或寄存器范圍,使用“,”分開,如{R1,R2,R6-R9},寄存器排列由小到大排列;“^”后綴不允許在用戶模式呈系統(tǒng)模式下使用,若在LDM 指令用寄存器列表中包含有PC 時使用,那么除了正常的多寄存器傳送外,將SPSR 拷貝到CPSR 中,這可用于異常處理返回;使用“^”后綴進行數(shù)據(jù)傳送且寄存器列表不包含PC時,加載/存儲的是用戶模式的寄存器,而不是當前模式的寄存器。
地址對準――這些指令忽略地址的位[1:0]。
批量加載/存儲指令舉例如下:

LDMIA R0!,{R3-R9} ;加載R0 指向的地址上的多字數(shù)據(jù),保存到R3~R9中,R0 值更新
STMIA R1!,{R3-R9} ;將R3~R9 的數(shù)據(jù)存儲到R1 指向的地址上,R1值更新
STMFD SP!,{R0-R7,LR} ;現(xiàn)場保存,將R0~R7、LR入棧
LDMFD SP!,{R0-R7,PC}^;恢復現(xiàn)場,異常處理返回

在進行數(shù)據(jù)復制時,先設置好源數(shù)據(jù)指針,然后使用塊拷貝尋址指令LDMIA/STMIA、LDMIB/STMIB、LDMDA/STMDA、LDMDB/STMDB 進行讀取和存儲。而進行堆棧操作時,則要先設置堆棧指針,一般使用SP 然后使用堆棧尋址指令STMFD/LDMFD、STMED。LDMED、STMFA/LDMFA、STMEA/LDMEA實現(xiàn)堆棧操作。
使用LDM/STM 進行數(shù)據(jù)復制例程如下:

  1. LDR R0,=SrcData ;設置源數(shù)據(jù)地址
  2. LDR R1,=DstData ;設置目標地址
  3. LDMIA R0,{R2-R9} ;加載8 字數(shù)據(jù)到寄存器R2~R9
  4. STMIA R1,{R2-R9} ;存儲寄存器R2~R9 到目標地址

  5. 使用LDM/STM 進行現(xiàn)場寄存器保護,常在子程序中或異常處理使用:
  6. SENDBYTE
  7. STMFD SP!,{R0-R7,LR} ;寄存器入堆
  8. BL DELAY ;調用DELAY 子程序
  9. LDMFD SP!,{R0-R7,PC} ;恢復寄存器,并返回

值得注意的是一些諸如原子操作的指令:STREX/LDREX;

 

3.2.3、MRS/MSR

特殊寄存器 CPSR 通過 MRS 和 MSR 指令進行讀寫操作:

MRS:讀狀態(tài)寄存器指令。在ARM 處理器中,只有 MRS 指令可以狀態(tài)寄存器CPSR或SPSR讀出到通用寄存器中。

MRS{cond} Rd ,psr

Rd 目標寄存器。Rd 不允許為R15

舉例:

  1. MRS R1,CPSR ;將CPSR狀態(tài)寄存器讀取,保存到R1 中
  2. MRS R2,SPSR ;將SPSR狀態(tài)寄存器讀取,保存到R2 中

 

MRS 指令讀取CPSR,可用來判斷ALU 的狀態(tài)標志,或IRQ、FIQ中斷是否允許等;在異常處理程序中,讀SPSR 可知道進行異常前的處理器狀態(tài)等。MRS 與MSR 配合使用,實現(xiàn)CPSR 或SPSR 寄存器的讀—修改---寫操作,可用來進行處理器模式切換(),允許/禁止IRQ/FIQ中斷等設置。另外,進程切換或允許異常中斷嵌套時,也需要使用MRS 指令讀取SPSR 狀態(tài)值。保存起來

舉例:

  1. 使能IRQ 中斷例程:
  2. ENABLE_IRQ
  3. MRS R0,CPSR
  4. BIC R0,R0,#0x80
  5. MSR CPSR_c,R0
  6. MOV PC,LR

  7. 禁能IRQ 中斷例程:
  8. DISABLE_IRQ
  9. MRS R0,CPSR
  10. ORR R0,R0,#0x80
  11. MSR CPSR_c,R0
  12. MOV PC,LR

MSR:寫狀態(tài)寄存器指令。在ARM 處理器中。只有MSR 指令可以直接設置狀態(tài)寄存器CPSR或SPSR。指令格式如下:

MSR{cond} psr_fields,#immed_8r

MSR{cond} psr_fields,Rm

psr CPSR 或 SPSR,

fields 指定傳送的區(qū)域。Fields 可以是以下的一種或多種(字母必須為小寫):

c 控制域屏蔽字節(jié)(psr[7…0])
x 擴展域屏蔽字節(jié)(psr[15…8])
s 狀態(tài)域屏蔽字節(jié)(psr[23。…16])
f 標志域屏蔽字節(jié)(psr[31…24])
immed_8r 要傳送到狀態(tài)寄存器指定域的立即數(shù),8 位。
Rm 要傳送到狀態(tài)寄存器指定域的數(shù)據(jù)的源寄存器。

MSR 指令舉例如下:

  1. MSR CPSR_c,#0xD3 ;CPSR[7…0]=0xD3,即切換到管理模式。
  2. MSR CPSR_cxsf,R3 ;CPSR=R3

注意:只有在特權模式下才能修改狀態(tài)寄存器!

程序中不能通過MSR 指令直接修改CPSR 中的 T 控制位來實現(xiàn)ARM 狀態(tài)/Thumb狀態(tài)的切換,必須使用 BX 指令完成處理器狀態(tài)的切換(因為BX 指令屬轉移指令,它會打斷流水線狀態(tài),實現(xiàn)處理器狀態(tài)切換)。MRS 與MSR 配合使用,實現(xiàn)CPSR或SPSR 寄存器的讀-修改-寫操作,可用來進行處理器模式切換、允許/禁止IRQ/FIQ 中斷等設置。

  1. 堆棧指令實始化例程:
  2. INITSTACK
  3. MOV R0,LR ;保存返回地址
  4. ;設置管理模式堆棧
  5. MSR CPSR_c,#0xD3
  6. LDR SP,StackSvc
  7. ;設置中斷模式堆棧
  8. MSR CPSR_c,#0xD2
  9. LDR SP,StackIrq

更多指令集 相關的詳細內容,參考 ARM 官方文檔,或者:

https://blog.csdn.net/u014069939/article/details/81107340

更多關于協(xié)處理器 Cp15 以及 Cache 和 MMU 相關的,在下一章介紹;


1、ARMv7-A 協(xié)處理器

ARMv7-A 處理器除了標準的 R0~R15,CPSR,SPSR 以外,由于引入了 MMU、TLB、Cache 等內容,ARMv7-A 使用協(xié)處理器來對這些擴展來進行管理,ARMv7-A 支持 16 個協(xié)處理器,編號從 CP0~CP15,其中的 CP15 協(xié)處理器稱之為系統(tǒng)控制協(xié)處理器,CP15 協(xié)處理器下的寄存器包含了 MMU、TLB、Cache等關鍵組件,其余的 CP0~CP14 有的控制Debug功能,有的控制 SIMD,有的控制浮點,咱們暫時只關注關鍵的 CP15;

2、CP15 協(xié)處理器

2.1、組成

CP15 協(xié)處理器由16個子寄存器組成,分別為 c0~c15,所以 CP15 的層次關系為:

這里的 c0~c15 不是寄存器的含義,而是主(Primary Register)寄存器的意思,也就是每個 c0~c15 中,包含很多寄存器組:

比較常用的 c0~c15 的寄存器組織如下

registerphysical register描述
c0MIDR主ID寄存器,用于記錄廠商版本信息
MPIDR多核處理器情況下,配置 Affinity
c1SCTLR系統(tǒng)控制寄存器
ACTLR輔助控制寄存器
CPACR協(xié)處理器訪問控制寄存器,控制訪問除了CP14和CP15的協(xié)處理器
SCR安全配置寄存器
c2 c3TTBR0一級轉換頁表基址寄存器0
TTBR1一級轉換頁表基址寄存器1
TTBCR頁表轉換控制寄存器
c5 c6DFSR數(shù)據(jù)異常(Data Fault)狀態(tài)寄存器
IFSR指令異常(Instruction Fault)狀態(tài)寄存器
DFAR數(shù)據(jù)異常(Data Fault)地址寄存器
IFAR指令異常(Instruction Fault)地址寄存器
c7predictorcache及分支預測
barrier數(shù)據(jù)及指令屏障
c8TLBTLB操作
c9performance monitors性能監(jiān)視器
c12VBAR非安全模式異常基址寄存器
MVBAR安全模式異?;芳拇嫫?/td>
c13ASID上下文ID寄存器,軟件線程ID寄存器
c15CBAR配置基址寄存器,用于GIC(Generic Interrupt Controller)和定時器類型外設

所以,針對 CP15 協(xié)處理器相關的層次結構總結下來為(這里以c0為例,c1~c15同樣有很多寄存器,每個寄存器都是 32bits 的):

2.2、訪問指令

與 CPSR 類似,協(xié)處理器的訪問是通過指定的匯編指令進行訪問;常用的有 MCR/MRC 兩條:

MRC: 將 CP15 協(xié)處理器中的寄存器數(shù)據(jù)讀到 ARM 寄存器中。

MCR: 將 ARM 寄存器的數(shù)據(jù)寫入到 CP15 協(xié)處理器寄存器中。

使用這兩條指令,外加一些標準的指令,就可以實現(xiàn)讀改寫;

2.2.1、MCR

MCR 指令的格式如下:

MCR<c> <coproc>, <opc1>, <Rt>, <CRn>, <CRm>{, <opc2>}

其中:

coproc:訪問協(xié)處理器的名字,取值范圍從 p0~p15;

opc1:協(xié)處理器要執(zhí)行的操作碼,取值范圍從 0~7;

Rt:ARM 的寄存器(比如 R0),要寫入到指定協(xié)處理器寄存器的數(shù)據(jù)就保存在此寄存器中;

CRn:指定協(xié)處理器的目標寄存器;

CRm:協(xié)處理器中附加的目標寄存器或者源操作數(shù)寄存器,如果不需要附加信息就將 CRm 設置為 C0,否則結果不可預測;

opc2:可選的協(xié)處理器特定操作碼,取值范圍從 0~7,當不需要的時候要設置為 0;

2.2.2、MRC

MRC 指令的格式如下:

MRC<c> <coproc>, <opc1>, <Rt>, <CRn>, <CRm>{, <opc2>}

其中:

coproc:訪問協(xié)處理器的名字,取值范圍從 p0~p15;

opc1:協(xié)處理器要執(zhí)行的操作碼,取值范圍從 0~7;

Rt:ARM 的寄存器(比如 R0),將指定協(xié)處理器寄存器的數(shù)據(jù)讀在此 ARM Core 寄存器中;

CRn:指定協(xié)處理器的目標寄存器;

CRm:協(xié)處理器中附加的目標寄存器或者源操作數(shù)寄存器,如果不需要附加信息就將 CRm 設置為 C0,否則結果不可預測;

opc2:可選的協(xié)處理器特定操作碼,取值范圍從 0~7,當不需要的時候要設置為 0;

訪問協(xié)處理器寄存器的指令已經(jīng)寫得很清楚,接下來就是如何來填這指令中的變量,這涉及到具體的協(xié)處理器的寄存器組織,我們使用最常用的 CP15 為例進行講述;

2.3、Cp15 協(xié)處理器寄存器組成

不管是 MCR/MRC 指令,如果針對到具體的 Cp15 協(xié)處理器,coproc 字段填 p15,Rt 字段可以隨便指定,暫時不管,那么就剩下 4 個變量:

{opc1、CRn、CRm、opc2};

Cp15 協(xié)處理器的所有寄存器訪問,都要依賴這幾個值的組合達到訪問的目的,前面說過整個 Cp15 的寄存器,分為 c0~c15,一個 16 個 Primary Regiser,再在每個 Primary Regiser 下面,又細分了很多具體的每個長度為 32bits 的寄存器,他們的整體組織結構為:

可以看到,Cp15 協(xié)處理器的 CRn 編號從 c0~c15,每個 Primary Regiser 都標記得有訪問權限;后面的 opc1、CRm、opc2 的取值訪問也都標記得清清楚楚;

那么下面將 c0~c16 每個展開看一下便可以清清楚楚看到他們怎么組織起來的,這樣就可以知道如何使用匯編進行編碼配置;

2.3.0、Cp15-c0 寄存器組成

c0 的寄存器組成如下:

訪問每個寄存器的 {opc1、CRn、CRm、opc2} 寫的清清楚楚;

主要是和 ID 相關的內容;

2.3.1、Cp15-c1 寄存器組成

c1 的寄存器組成如下:

主要是和系統(tǒng)控制相關的配置;

2.3.2、Cp15-c2&c3 寄存器組成

c2&c3 的寄存器組成如下:

主要是內存保護和控制相關的(MMU);

2.3.3、Cp15-c4 寄存器組成

Cp15 協(xié)處理器的 c4 寄存器為 Not used;

2.3.4、Cp15-c5&c6 寄存器組成

c5&c6 的寄存器組成如下:

主要是和 memory fault 相關的;

2.3.5、Cp15-c7 寄存器組成

c7 的寄存器組成如下:

主要是和 Cache 相關的部分;

2.3.6、Cp15-c8 寄存器組成

c8 的寄存器組成如下:

主要是和 TLB 相關的;

2.3.7、Cp15-c9 寄存器組成

c9 的寄存器是為 cache 和 TCM 預留的;

2.3.8、Cp15-c10 寄存器組成

c10 的寄存器是為內存重映射和 TLB 控制:

2.3.9、Cp15-c11 寄存器組成

c11 的寄存器是為 TCM DMA 預留:

2.3.10、Cp15-c12 寄存器組成

c12 的寄存器是為安全擴展的:

2.3.11、Cp15-c13 寄存器組成

c13 的寄存器是為進程,上下文和線程 ID 的:

2.3.12、Cp15-c14 寄存器組成

c14 的寄存器是為通用 Timer 預留的:

2.3.13、Cp15-c15 寄存器組成

c15 的寄存器是 IMPLEMENTATION DEFINED 的,不管他:

參考文獻:
ARM體系架構—ARMv7-A協(xié)處理器_liyuewuwunaile的博客-CSDN博客

ARM體系架構—ARMv7-A指令集:協(xié)處理器指令_liyuewuwunaile的博客-CSDN博客

ARMv7 CP15協(xié)處理器詳解_Deep_l_zh的博客-CSDN博客_cp15協(xié)處理器


Memory Model

本文參考:

ARMv7-A_and_R_Architecture_Reference_Manual》 中的 {A3.5 Memory types and attributes and the memory order model}

1、Memory Type

ARMv7-A 處理器中,將 Memory定義為幾種類型(Memory Type):

1、Strongly-ordered;

2、Normal;

3、Device;

它的定義如下所示:

注意:這里的 Memory 指的不是內存,可以翻譯成儲存器,是地址空間的概念;

普通的內存(RAM),只讀的內存(ROM),這些都屬于 Normal Type 的范疇;

外設和I/O,這些屬于 Device 和 Strongly-ordered 范疇;

2、Memory Attributes

對于地址空間來說,每種地址空間,ARMv7-A 使用 attribute 來描述這個存儲器地址的屬性,總的屬性分為兩種:

1、shareability;共享屬性

2、cacheability;緩存屬性

它們描述了存儲器是否可以共享,或者是否可以過cache;

2.1、Shareability Attributes

Shareability 共享屬性用于描述存儲器地址空間是否可以共享;只對 Normal Type 類型和 Device 類型有效;

2.1.1、Normal memory with Shareability

Normal Type 是比較常見的存儲器模型,它可以支持讀/寫或只讀,它可以被配置成為 Shareable 或者 Non-Shareable;

在訪問 Normal 存儲器的時候(比如 DDR),一定要小心內存一致性的問題,因為系統(tǒng)中,常常會開啟 cache,并在多核系統(tǒng)中,存在多 CPU 核心訪問內存,內存屏障能夠起到訪問的保序作用,原子操作指令,可以起到訪問互斥(LDREX/STREX);

對于 Normal Type 的內存屬性描述如下:

當被配置成為 Non-Shareable 的時候,意味著在多核系統(tǒng)中,它只能被一個核心訪問;

當配置為 Inner-Shareable 的時候,意味著只能夠被單個 CPU cluster 集群訪問;

當配置為 Outer-Shareable 的時候,意味著只能夠被多個 CPU clusters 集群訪問;

2.1.2、Device memory with Shareability

Device 類型存儲器地址空間,可以配置為 Shareable(比如多核 CPU 中,UART 外設地址空間是對所有 CPU 共享的);當然,也可以配置為 Non-Shareable;

但是具體實際的設計實現(xiàn)中,不管是配置為 Non-Shareable,還是 Inner-Shareable,還是 Outer-Shareable,都一概視為 Outer-Shareable(畢竟是外設);

2.2、Cacheability Attributes

2.2.1、Normal memory with cacheable

Normal 類型的存儲器(比如 DDR)除了有 Shareable 的屬性以外,還可以攜帶 cacheable 的屬性:

Write-Through Cacheable:寫透型 Cache 屬性;

Write-Back Cacheable:回寫型 Cache 屬性;

Non-cacheable:不帶 Cache 屬性;

Non-Cacheable 很好理解,就是不帶 Cache,直接與存儲器交互,這樣不會帶來內存一致性問題,但是效率不高;

其余兩種都是帶 Cache 的訪問,不過 Cache 的策略略有區(qū)別;寫透也可以在一定程度上保證內存一致性問題,但要發(fā)起內存訪問時序,降低性能;回寫只是將數(shù)據(jù)寫到了 Cache 中,并通過 Dirty 標記等方式來記錄數(shù)據(jù)的有效性,從而避免直接的內存訪問,可以提高性能;

2.2.2、Device memory with cacheable

Device 和 Strongly-ordered 類型的存儲器(可以理解為外設)區(qū)域,都是 Non-cacheable 的,即,不緩存的;這個很好理解,寫過驅動的朋友應該都能夠知道,對外設的訪問和對普通內存的訪問是完全不一樣的兩個概念;

所以,最后總結起來就是:

3、Device VS Strongly-ordered

ARMv7-A 中,Device 類型的存儲器和 Strongly-ordered 類型存儲器,都是不可 Cacheable 的,并且他們的訪問是不可被優(yōu)化的,他們的唯一區(qū)別是在 Shareability 屬性:

1、對 Strongly-ordered 存儲器的寫入,只有在寫訪問到外設或者存儲器組件的時候,才算完成;

2、對 Device 存儲器的寫入,允許在寫訪問到達外設之前就完成;

上面這個說法是官方的意思,我理解一下,應該是 Strongly-ordered 不惜犧牲性能,去做保序的要求,一定要實際訪問到外設,而 Device 類型的訪問指令,可能還在路上(流水線中);

而且,Strongly-ordered 和 Device 類型要求,對他們的訪問必須是對齊訪問;

4、Access rights

存儲器模型除了有各種屬性以外,還需要支持訪問權限(這個是必須的,否則訪問非法空間,那還得了);

ARMv7-A 定義了擴展的存儲器區(qū)域訪問屬性,也就是這個權限訪問;訪問權限分為兩部分:

1、基于特權等級的限制數(shù)據(jù)的訪問;

2、基于特權等級的指令訪問;

PL0 的時候,也就是 User 模式,相當于非特權等級下,禁止訪問結構體系下的某些特性,它不能更改許多配置設置。 在PL0上執(zhí)行的軟件只允許非特權內存訪問;

當在 PL1 上執(zhí)行的軟件(通常操作系統(tǒng)都執(zhí)行在 PL1 特權模式下)可以訪問體系結構的所有特性,并且可以更改這些特性的配置設置;

值得注意的是,fa權限的配置以及更改,只能夠在 PL1 模式下進行

4.1、Privilege level access controls for data accesses

針對數(shù)據(jù)的訪問來說,在 PL1 模式下,可以定義某存儲器區(qū)域的訪問權限為:

1、不可訪問;

2、只有 PL1 特權才能訪問;

3、特權和非特權模式都可以訪問;

如果處理器嘗試訪問權限不允許的數(shù)據(jù)訪問,則會生成數(shù)據(jù)中止異常(Data Abort)。 例如,如果處理器位于 PL0,并且試圖訪問被標記為僅特權模式可訪問的內存區(qū)域,則會生成數(shù)據(jù)中止異常 Data Abort;

4.2、Privilege level access controls for instruction accesses

針對指令的執(zhí)行來說,PL1 模式下,以定義某存儲器區(qū)域的執(zhí)行權限為:

1、不允許執(zhí)行;

2、在處理器實現(xiàn)了 Large Physical Address Extension 情況下,PL1 不允許執(zhí)行;

3、只能在 PL1 執(zhí)行;

4、特權和非特權模式都可以執(zhí)行;

訪問權限的配置,在 CP15 的 MMU 相關的寄存器,他們的層次結構為:


Cache

0、Preview

一些 Cache 基本的內容,比如 “為什么需要 Cache”,“Cache 的組織形式”,“Cache 的映射形式”等,我已經(jīng)在之前的文章《Cache 原理淺析》中敘述得比較清楚了,這里不再贅述,有興趣的同學可以跳轉觀看一下,這里主要是補充一些 ARMv7-A 上的一些細節(jié);

1、ARMv7-A Cache Architecture

Cache 原理淺析》可以知道,Cache Line 是 Cache 的最小單位,為了尋找特定 Cache,在 Cache 結構中,ARM 將地址分為了幾段,比如 32bits 的地址總線,ARM 將其分為了 3 段:

最高的一段叫做 Tag,中間的叫 Index,最后叫 Offset;

在一個多路組相關的 Cache 結構中,它的結構如下:

針對這個圖,可以做如下理解:

1、這里的 Line,指的是一個 Cache Line,最小的緩存單位,可能很多字節(jié)(比如,64 Bytes);

2、可以看到,一個 Way,包含了 N 條 Cache Line(這里包含了 4 條),圖中有 4 個 Way,也就是 4-Way associate 的含義;

3、每一個 Way 的同樣位置的 4 條 Cache Line 組成一個 Set,具體分為了多少個 Set,這個要看 Cache 總共有多大,這里畫了 4 個 Set;

4、因為 Cache 進行數(shù)據(jù)緩存,并不是按照 一個地址+一個數(shù)據(jù)(32bits 地址+數(shù)據(jù)),如果按照這樣的結構來緩存,因為這樣效率太低;實際上,它緩存的方式是一組一組來緩存,每一組用一個 Tag 進行表征;所以,每個 Cache Line 就有一個 Tag;

5、Index 用于表征一個 Way 中

5、每個 Way 中,都對 Cache Line 進行編號,有 Index=1,2,3..n(Index=1表示 Cache Line 的編號即 line1,index=2表示 line2), 我們將在不同 way 中,Index 相同的叫成 set。

 

上面的結構如果用 C 語言來表示的話:

Way = Cache[tag];

Cache Line = Way[Index];

Data = Cache Line[Offset]

舉個真實的例子:

假如我們有一個 Cache Line = 32Bytes,4路 Way 的 組織方式,Cache=32KBytes。

Per Way = (32KBytes 32KBytes) 4 Way= 256 Cache Line/Way;

前面說過,一個 Way 中的 Cache Line 是 Index 來索引的,256 個 Cache Line/Way 的話,就要 5 個 bits 來表示;

一個 Cache Line 是 32Bytes,那么就是 8 個 Word,使用 3 個 bits 表示即可;

剩余的高位,作為 Tag 的形式存在:

既然以地址來進行查找 Cache 的,那么我們到底是用虛擬地址還是物理地址呢?三種方式:

1、早期的 ARM 處理器,如 ARM720T 或 ARM926EJ-S 處理器使用虛擬地址提供 Index 和 Tag。 這有一個優(yōu)點,即 CPU 不需要虛擬到物理地址轉換就可以進行緩存查找。 缺點是,每當進行進程切換(虛擬地址映射表發(fā)生改變),Cache 中的虛擬地址就不能再用了,導致性能下降,現(xiàn)在這種方式已經(jīng)淘汰。

2、使用物理地址來查找 Cache(我們叫它 PIPT),那么這么做很明顯解決了第一種的缺點(因為是以物理地址進行 Cache 的,不管映射表怎么變,物理地址不會變)。但是由引入了一個缺點:每次進行查表的時候,都需要到MMU去進行地址轉換,這樣增加了查找cache需要的時間,效率明顯沒有采用虛擬地址的高。注:這種方法,依賴MMU,即MMU關閉,Cache 就必須關閉;

3、是第 1 種和第 2 種的折中處理,將這個查找過程分為兩步,Tag 用物理地址表示,Index 用虛擬地址的,我們叫它 VIPT(Virtually Indexed, Physically Tagged)。那么怎么實現(xiàn)呢?首先,由于 Cache 控制器和 MMU 是兩個獨立模塊,因此通過 MMU 去查找 Tag 和通過 Index 去 Cache 查找 Way 是相互獨立的即可以同時運行。即當用 Index 去 Cache 查找 Set(上面有解釋,即 Index 相同,但處于不同 Way 的一組集合)的同時也在用虛擬地址去 MMU 找物理地址的 Tag,當從cache找到一組set(line[way])的時候(因為只提供了index,因此cache control不知道到底是哪個way,所以返回每個包含index的way),此時MMU中也查到了物理tag,然后再用該物理tag去匹配返回的set,最后獲取到對應的 cache line。常用CPU情況如下。

可能到這里有人會問了,混合使用物理地址和虛擬地址不會有問題嗎?畢竟虛擬地址在進程發(fā)生變動的時候是會不斷變化的。不不不,理論上是不會有問題的,為什么呢?我們知道我們的虛擬映射表了,我們的映射表一般是以4K為一個page,即4k對齊,不管虛擬地址怎么發(fā)生變化,一個page內的偏移是不變的。要尋址一個4k大小我們需要[11:0]共12個bit來提供支持,即在MMU當中,虛擬地址的低12位和物理地址的低12位是相同的。假如我們用的是一個16kb大小,含有4個way,每個line 32bytes的cache,那么通過計算[4:0]用于cache的offset定位,[11:5]則用于cache的index定位。如上所說,虛擬地址和物理地址的[11:0]是相同的,因此index用虛擬地址就不會有影響。但是話又說回來,如果我們的cache大小超過了16k,加入為32kb呢?那么我們以32KB,含有4個way,每個line 32bytes的cache來說,[4:0]用于offset定位,[12:0]用于index定位,那么問題來了,由于虛擬地址和物理地址僅僅是[11:0]相同,那么第13位在發(fā)生切換后,就可能會出現(xiàn)0/1兩個值,意味著一個物理地址可能會同時占用2個cache line,即兩個副本, 這樣就會容易引發(fā)cache一致性的問題。針對于這種cache alias問題,目前的方案是由操作系統(tǒng)來保證,對于同一物理地址在不同進程空間的虛擬地址,他們的虛擬地址的差一定是cache way大小的整數(shù)倍,也就是說他們的第13位一定是相同的。同時已經(jīng)有些cpu廠商在開發(fā)監(jiān)視模塊,試圖在硬件層面解決類似的同步問題。同理對于64kb的cache也采用同樣的方法。

2、ARMv7-A Cache policies

在 Cache 操作策略中可以做出許多不同的選擇。

2.1、Allocation Policy

第一種,CPU讀數(shù)據(jù)時。只有當讀取的時候,發(fā)現(xiàn)cache miss,才從cache中申請一個line去緩存該數(shù)據(jù)。寫的時候,不申請,直接寫入下一級。

第二種,寫和讀時。只要訪問時,不管讀或者寫,發(fā)生了cache miss都去申請一個cache line。

2.2、Replacement Policy

當 Cache miss 的時候,Cache 替換策略:

第一種,Round-robin 或者循環(huán)替換策略;

第二種,Random 替換,Cache 存滿并且出現(xiàn) Cache miss,如果來了一條新的,則隨機找一個 Cache Line 被替換;

第三種,LRU(Least Recently Used) 算法替換,方法如名字,當 Cache 存滿了后,如果來了一條新的,則選擇最近最少使用的被替換;

2.3、Write Policy

第一種,Write-Back 模式:寫數(shù)據(jù)時,只向 Cache寫入數(shù)據(jù),并標記 Cache 為 Dirty,然后在合適的時機將數(shù)據(jù)更新到主存;

第二種,Write-Through 模式:寫數(shù)據(jù)時,Cache 和主存都要寫一份;

3、ARMv7-A Cache Registers

和 Cache 相關的寄存器控制,首先就是 CP15 的 SCTLR 系統(tǒng)控制寄存器:

bit[2] 是控制 Cache enable 的

bit[12] 是控制指令 Cache enable 的

獲取 Cache 的 Type,刷 Cache 等操作寄存器,等在分析 Linux Kernel 的時候,在對著代碼解讀;

這里需要注意的是,訪問 CP15 協(xié)處理器的寄存器,通過 MRC/MCR 特殊指令;

參考:

linux系統(tǒng)之a(chǎn)rm架構的CPU與Cache_eleven_xiy的博客-CSDN博客

關于L1 L2 Cache_憂郁天蝎-CSDN博客


MMU/TLB

之前寫過 MMU 的一些入門和基礎的分析《初探 MMU》和《ARMv7-A 的 MMU 淺析》,有基于概念掌握和基本入門的一些理解,這里打算在針對 ARMv7-A 的處理器再次稍微深入一點研究一下他的 MMU 和 TLB;

這一版同樣基于 ARM 官方文檔:

ARMv7-A_and_R_Architecture_Reference_Manual

DEN0013D_cortex_a_series_PG

的一個是完整版的 ARMv7-A 的處理器架構文檔,第二個是 Cortex-A 系列的 Programmer Guide;

由于有前面的兩篇文章墊底(《初探 MMU》和《ARMv7-A 的 MMU 淺析》),這里就不再介紹一些基礎的內容了,直接單刀直入;

0、回顧

前面知道,MMU 用作虛擬地址和物理地址的相互轉換,是為了能夠給 OS 提供統(tǒng)一視角的虛擬地址空間;

TLB 的作用是作為 MMU 的 Cache,以提高 MMU 的性能,他們之間的關系如下:

1、ARM 處理器發(fā)出地址訪問(虛擬地址),首先過 MMU 地址翻譯單元的 TLB,如果 TLB 命中,那么直接返回真實的物理地址;

2、如果 TLB Miss,那么就要靠 Table Walk 單元去主存中查找表,以獲取物理地址,然后通過 Cache,去訪問;

3、Cache 如果命中,那么直接返回實際物理地址的數(shù)據(jù),否則,也就是最糟糕的情況,會去訪問主存的數(shù)據(jù);

上面的過程呢,軟件要做的,只有配置并放好這個 Transliation Tables,其他的過程,全部是硬件行為;下面馬上仔細的過這部分的細節(jié);

使能 MMU 的參考代碼(因為是 CP15 的系統(tǒng)控制寄存器,所以使用 MRC/MCR 指令):

  1. MRC p15, 0, R1, c1, C0, 0 ;Read control register
  2. ORR R1, #0x1 ;Set M bit
  3. MCR p15, 0,R1,C1, C0,0 ;Write control register and enable MMU

這里要注意的一點是,可能要用到內存屏障指令,因為這里就開啟了 MMU,即將進入虛擬內存的世界,要確保在這之前,流水線干凈,所以執(zhí)行已經(jīng)完畢;

1、TLB

TLB 的全稱是:Translation Lookaside Buffer;從第一節(jié)的那個圖可以看出來,MMU 做 Table Walk 的這個 Transliation Tables 是放到主存中,主存訪問速度很慢(加 Cache 的根本原因),所以,這里每次都去再主存中做 Table Walk,顯然效率非常低,所以,這里就為這個 Table Walk 定制了一個屬于他的 “Cache”,稱之為 TLB;

但是與 真是的 Cache 不一樣(詳見《ARMv7-A 處理器窺探(4) —— Cache》),這個 TLB 是專門緩存 Transliation Tables 的,典型的情況,他的組成如下:

由 VA、ASID、PA、Attributes 組成,即:

VA:虛擬地址;

PA:物理地址;

ASID:Address Space ID;

Attributes:屬性;

1.1、TLB coherency

TLB 既然扮演的 Transliation Tables Cache 的角色,那么也會有一致性問題,最典型的就是再 OS 中,上下文切換的時候,上一個進程的虛擬地址對應的物理地址表,肯定是和另一個不一樣,導致 TLB 一致性問題;此刻,OS 必須處理這種情況,使得上一個進程的 TLB 對下一個失效,也可以直接通過 CP15 控制寄存器,來 flush 掉 TLB(代價太大);

2、MMU

這里,拋開大物理地址擴展和 section 和 supersection 的分析,暫時就看最最常用的兩段查找;兩段頁表查找,我們稱第一級頁表為 L1,第二級為 L2;

2.1、TTBR0、TTBR1、TTBCR

前面知道,軟件需要負責構建這個虛擬地址到物理地址的轉換表:Transliation Tables,當軟件構件完畢這個表后,只需要告訴硬件,這個 Transliation Tables 放到了那個首地址即可,這個配置通過寫 ARM 的 TTBR 寄存器實現(xiàn)(Translation Table Base Address );這里其實有兩個 TTRB 寄存器,分別叫 TTBR0 和 TTBR1,為啥兩個,后面解釋;

2.1.1、TTBCR

和這個 TTBR0、TTBR1 勾肩搭背的,還有一個 TTBCR 寄存器,他們直接什么關系呢,看寄存器說明:

TTBCR:

PD0 和 PD1 是和 Security Extensions 相關的,不管他;

EAE 是和 Large Physical Address Extension  相關的,不管他;

主要關注這里的 N[2:0],指示TTBR0頁表基址寄存器基址位寬,同時指示使用 TTBR0 還是 TTBR1 作為頁表基址寄存器,以及 TTBR0 頁表尺寸:

如果 N = 0 的話,則在做 Table Walk 的時候使用 TTBR0 指定的基地址作為 Transliation Tables 入口的地址;

如果 N > 0 的話:指示TTBR0頁表基址寄存器基址位寬,同時指示使用 TTBR0 還是 TTBR1 作為頁表基址寄存器,以及 TTBR0 頁表尺寸;

  • N==0,使用 TTBR0。
  • N>0,如果虛擬地址[31:32-N]為0,則使用 TTBR0;其他情況使用TTRB1。這種情況下,N 指示了TTBR1的頁表地址,也指示了 TTBR0 的頁表大小。
  • TTRB0的頁表大小由TTBCR.N控制,TTRB1的頁表大小為16KB。

我換句話來說,當 N>0 的時候,比如 N=1,那么按照這種說法,VA [31:31] 也就是 VA 的 bit[31] 為 0 的時候,使用 TTBR0 否則使用 TTRB1,按照地址空間來劃分,即,32bits 地址,當最高位為 0,即虛擬地址為 0x0000_0000 ~ 0x7FFF_FFFF  這個區(qū)間的時候,使用 TTBR0 作為 Transliation Tables 入口的地址,從 0x8000_000 ~ 0xFFFF_FFFF 的虛擬地址空間,使用 TTBR1;

ARM 官方舉了個例子,當 TTBCR.N=3'b111 的時候,VA [31:25] 全部為 0 的時候,使用 TTBR0,按照地址空間來劃分就是,虛擬地址為:0x0000_0000 ~ 0x01FF_FFFF 這段區(qū)間使用 TTBR0 作為 Transliation Tables 入口的地址;

0x0200_0000 ~ 0xFFFF_FFFF 的虛擬地址空間,使用 TTBR1;

OK,現(xiàn)在可以理解為,配置 TTBCR.N 這個值,可以實現(xiàn)將虛擬地址切割成為兩部分,一部分使用 TTBR0 指定的 Transliation Tables 進行 Table Walk,另一部分使用 TTBR1 指定的 Transliation Tables 進行 Table Walk,這個有什么好處呢?比如,內核的頁表,是不會改變的,而進程上下文的頁表是會改變的,有了這個的話,就可以考慮用一個 TTBR 來專門為內核服務,另一個 TTBR 為進程服務,這樣避免進程和內核使用同一個頁表,每次都要進行內核頁表的拷貝;

由于 TTBCR 是 CP15 的寄存器,訪問 TTBCR 的指令為:

  1. MRC p15, 0, <Rt>, c2, c0, 2 ; Read TTBCR into Rt
  2. MCR p15, 0, <Rt>, c2, c0, 2 ; Write RT to TTBCR

2.1.2、TTBR0、TTBR1

上面說了 TTBCR,下面來看 TTRB0、TTRB1 寄存器描述:

TTBR0

在帶有多核處理器擴展的情況下 TTBR0 由一個可變的長度構成 Transliation Tables Base Address,這個 x 就是上面的 (14 - (TTBCR.N));

Bits[31:x]:x=(14-(TTBCR.N))。一級頁表地址;

Bits[x-1:7]:Reserved;

NOS:Not Outer Shareable bit,指示了做 Table walk 的那個內存的屬性,是 Outer Shareable 還是 Inner Shareable.

  • 0  Outer Shareable.
  • 1  Inner Shareable.

TTBR0.S == 0 時,該bit無效;

S:Shareable bit. 指示內存共享屬性與頁表轉換的關系;

  • 0  Non-shareable.
  • 1  Shareable.

RNG:Region bits,指示 Outer Cache 屬性與頁表轉換的關系;

  • 0b00 Normal memory, Outer Non-cacheable.
  • 0b01 Normal memory, Outer Write-Back Write-Allocate Cacheable.
  • 0b10 Normal memory, Outer Write-Through Cacheable.
  • 0b11 Normal memory, Outer Write-Back no Write-Allocate Cacheable.

IRGN[6,0]:Inner region bits,指示 Inner Cache 屬性與頁表轉換的關系;

  • 0b00 Normal memory, Inner Non-cacheable.
  • 0b01 Normal memory, Inner Write-Back Write-Allocate Cacheable.
  • 0b10 Normal memory, Inner Write-Through Cacheable.
  • 0b11 Normal memory, Inner Write-Back no Write-Allocate Cacheable.

訪問 TTBR0 的指令為:

  1. MRC p15, 0, <Rt>, c2, c0, 0 ; Read 32-bit TTBR0 into Rt
  2. MCR p15, 0, <Rt>, c2, c0, 0 ; Write Rt to 32-bit TTBR0

TTBR1

它的位域和 TTBR0 幾乎一樣,唯一不一樣的地方在于,配置的地址區(qū)間在于 bit[31:14],這意味著,配置進 TTBR1 的 Transliation Tables Base Address 的物理地址,必須 16KB 對齊;

訪問 TTBR1 的指令為:

  1. MRC p15, 0, <Rt>, c2, c0, 1 ; Read 32-bit TTBR1 into Rt
  2. MCR p15, 0, <Rt>, c2, c0, 1 ; Write Rt to 32-bit TTBR1

2.2、Translation Table

現(xiàn)在我們知道了合理的配置 TTBCR/TTBR0/TTBR1 可以分配并指定 Transliation Tables,而這個 Transliation Tables 位于內存中,用作 MMU 來做 Table Walk;那么接下來我們需要知道頁表的結構,這樣我們才能夠在內存中創(chuàng)建頁表,并將頁表配置給 TTBR 寄存器,完成 MMU 的配置;

不考慮大地址擴展和 SuperSection 以及 Section 的情況下,針對 Transliation Tables,ARMv7-A 的手冊給出了如下的圖解

圖中,我們暫時只考慮 Page Table 的情況,即紅色部分(其余的可以照著推);

藍色的部分,可以理解為之前寄存器里面配置的那個 N 值;這里為了說明情況,我們暫時將 N 定為 0;

2.2.1、L1 Address Translation

我們先暫時不管使用 TTBR0 還是 TTBR1,其實過程是一樣的;此刻當 N = 0 的時候,一級頁表以虛擬地址(后面簡稱 VA,即 Virtual Address)VA[31:20] 作為 L1 Index,一共 12bits,最大能夠表征 4K 的 Index:

每個入口是 4 Bytes 也就是一個 Word,32bits 的入口,L1 Index 從 0~4095,一共 4K,在內存上,每個入口 4Bytes,那么 L1 頁表占用內存 4K x 4 Bytes = 16KB;

每一個入口是什么樣子的呢,我們放大來看:

可以看到,這個入口,根據(jù)不同的配置,內容有所區(qū)別,一共有 4 種類型,這 4 種類型,通過 32bits 的尾部 2 bits 來區(qū)分,即,綠色部分(Section 和 SuperSection 的區(qū)分,還靠 bit[18]);

這里我們暫時不關心 Section 和 SuperSection,關注于紅色部分和那個 Fault;

Level 2 Descriptor Base Address:指向的是 L2 頁表的物理地址的基地址;可以看到他是 bit[31:10],是 1KB 邊界對齊的;

這個 Domain 指的是 ARM 支持將內存標記為最多 16 個 domain,并以 Domain ID 作為區(qū)分,每個 Domain 可以支持配置成為不同的訪問權限(通過配置 CP15 的 C3 的 Domain Access Control Register (DACR) 寄存器):

配置指令為:

  1. MRC p15, 0, <Rt>, c3, c0, 0 ; Read DACR into Rt
  2. MCR p15, 0, <Rt>, c3, c0, 0 ; Write Rt to DACR

針對這個 DACR 寄存器,ARM 官方建議配置成為 Client;

The use of domains is deprecated in the ARMv7 architecture, and will eventually be removed,
but in order for access permissions to be enforced, it is still necessary to assign a domain number
to a section and to ensure that the permission bits for that domain are set to client. Typically, you
would set all domain ID fields to 0 and set all fields in the DACR to 'Client’.

2.2.2、L2 Address Translation

介紹完 L1 Address Translation 后,下面是二級頁表!與 L1 頁表不一樣,二級頁表不和 N 值掛鉤,它直接采用 VA[19:12]  作為 L2 Index 索引,一共 8 bits,最大能夠表征 256 的 L2 Index;

加入 L2 頁表后結合 L1,通過一個給定的 VA 進行索引的第二步為(圖中表示的 N 值為 0):

這樣,一個 VA 通過高地址部分[31:20] 索引到了 L1,再從 L1 指向的 L2 加上 VA[19:12] 作為 L2 Index,索引到 L2 表的固定位置;

L2 也是每條由 4 Bytes 構成,即一個 32bits 的數(shù),那么一個 L2 表大小為 256 x 4 Bytes = 1024 Bytes = 1KB;一共有 4096 個這樣的 L2,那么 L2 表總的大小為:4096 x 1KB = 4MB;

我們放大每一條 L2 的入口:

我們只關心紅色部分!可以看到,這個 Small Page Base Address 有 bit[31:12] 也就是 4KB 邊界對齊!接下來我們看剩余幾個位的含義:

AP/APX:Access Permission 即訪問權限,每個內存區(qū)域 都有自己的權限,不符合訪問權限的 內存訪問都會引發(fā) 異常。如果是 數(shù)據(jù)訪問 則引發(fā) 數(shù)據(jù)異常。如果是 指令訪問,且該指令在執(zhí)行前沒有被 flush,將引發(fā) 預取指異常。引發(fā)的 異常原因將會被設置在 CP15 的 the fault address and fault status registers;

內存區(qū)域類型 可以通過 TEX字段、C字段 和 B字段 來進行設置:

XN:指的是 Execute Never,不允許執(zhí)行,如果往這里取地址執(zhí)行,那么會導致異常發(fā)生;通常,Device memory 類型的區(qū)域會配置成為 XN;

S:指的是是否具有 Shareable 屬性;

nG:non-Global,這個標記告訴 MMU,這個頁表是否是一個全局的,什么意思呢?看下面:

當 nG 為 0 的時候,說明此區(qū)域是全局可見的,換句話來說,就是任何時候都生效;

當 nG 為 1 的時候,說明此區(qū)域不是全局的,要聯(lián)合這個 ASID 來確認;

每一個 nG=1 的區(qū)域,都會和 ASID 來關聯(lián),ASID (Address Space Identifier),這代表,TLB 可以存在多個不同進程的頁表緩存,后面說 ASID 的時候會仔細說;

自此,L1/L2 分析完畢,那么整個 Table Walk 的流程為:

VA 的 4K 頁內偏移,直接對應到 PA 的 4KB 頁內偏移;

3、OS Usage Of Translation Tables

通常情況下,在使用 Cortex-A 系列處理器的時候,典型場景是跑多任務 OS;每一個任務(或者成為應用),都有它獨立的虛擬地址空間,以及他的獨立的 Translation Table;但是對于 OS 來說,Kernel 的 Translation Tables 其實是固定的,只是進程之間的 Translation Tables 不一樣而已;

當一個進程啟動的時候,OS 負責為他 code 和 data 段建立映射表(Translation Tables);當進程調用諸如 malloc 之類分配內存的行為,OS 負責修改 Translation Tables(Linux 中,實際訪問分配的內存的時候,才去修改頁表),進程生命周期消亡,OS 負責回收它的資源和頁表,并可以為下一個新的進程提供資源;每一個進程都有自己的獨立的頁表,這便可以保證進程之間不會相互干擾;

3.1、Address Space ID(ASID)

在操作系統(tǒng)中,多進程是一種常態(tài)。那么多進程 的情況下,每次切換進程都需要進行 TLB 清理。這樣會導致切換的效率變低。為了解決問題,TLB 引入了 ASID(Address Space ID) 。ASID 的范圍是 0-255。ASID 由操作系統(tǒng)分配,當前進程的ASID值 被寫在 ASID 寄存器 (使用CP15 c3訪問)。TLB 在更新頁表項時也會將 ASID 寫入 TLB。

如果設置了如果 當前進程的ASID,那么 MMU 在查找 TLB 時, 只會查找 TLB 中具有 相同ASID值 的 TLB行。且在切換進程是,TLB 中被設置了 ASID 的 TLB行 不會被清理掉,當下次切換回來的時候還在。所以ASID 的出現(xiàn)使得切換進程時不需要清理 TLB 中的所有數(shù)據(jù),可以大大減少切換開銷。

有了這個 ASID + nG 的機制,那么 TLB 中就可以緩存不同進程的頁表,不用每次都去 flush TLB,導致性能的損失:

3.2、TTBR0、TTBR1

前面我們說了 TTBR0、TTBR1 是根據(jù) TTBCR.N 來進行劃分的,典型場景下 OS 跑多任務,如果處理器只能夠支持一個 TTBR 的話,也就意味著用戶空間和內核空間使用同一個 TTBR,由于內核空間的 code 和 data 幾乎是不變的,但是多任務的用戶空間都是不一樣的,這樣就會存在兩個問題:

1、多個任務的頁表里面,都有同樣一部分內核映射的拷貝副本;

2、要修改內核映射的時候,所有任務的頁表都要修改;

加入兩個 TTBR 的原因,是因為希望內核和用戶空間使用兩套 TTBR,這樣就可以避免上面的尷尬;內核空間固定使用一組,用戶空間不斷的切換(比如,配合 TTBR0 + ASID 進行性能的提升)

參考文獻:

https://www.jianshu.com/p/ef1e93e9d65b

https://www.cs.rutgers.edu/~pxk/416/notes/10-paging.html

https://blog.csdn.net/liyuewuwunaile/article/details/106773630?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-0&spm=1001.2101.3001.4242

本站僅提供存儲服務,所有內容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
關于ARM9協(xié)處理器CP15及MCR和MRC指令
ARM協(xié)處理器CP15寄存器詳解
ARM CP15協(xié)處理器
ARM的存儲管理單元MMU
s3c2440硬件學習筆記----內存管理單元MMU
x86-64安全虛擬機構架
更多類似文章 >>
生活服務
熱點新聞
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服