本篇很重要,對CP15
協處理所有16
個寄存器一一介紹,可能是全網介紹CP15
最全面的一篇,鴻蒙內核的匯編部分(尤其開機啟動)中會使用,熟練掌握后看匯編代碼將如虎添翼。
協處理器
協處理器?(co-processor) 顧名思義是協助主處理器完成工作,例如浮點、圖像、音頻處理這一類外圍工作。角色相當于老板的助理/秘書,咱皇上身邊的人,專干些咱皇上又不好出面的臟活累活,您可別小看了這個角色,權利不大但能力大,是能通天的人,而且老板越大,身邊這樣的人還不止一個。
在?arm
?的協處理器設計中,最多可以支持?16
?個協處理器,通常被命名為?cp0
~cp15
,本篇主要說第16
號協處理器?cp15
CP15
關于?cp15
詳細介紹見于?<< ARM體系架構參考手冊(ARMv7-A/R).pdf >>?的?B3.17。
cp15
?一共有?16
個32
位的寄存器,其編號為C0 ~ C15
?,用來控制cache
、TCM
和存儲器管理。cp15
?寄存器都是復合功能寄存器,不同功能對應不同的內存實體,全由訪問指令的參數來決定,對于?armv7
?架構而言,A
?系列和?R
?系列是統一設計的,A
?系列帶有?MMU
?相關的控制,而?R
?系列帶有?MPU
?相關控制,針對不同的功能需要做區分,同時又因為協處理器?cp15
?只支持?16
?個寄存器,而需要支持的功能較多,所以通過同一寄存器不同功能的方式來滿足需求。
mcr | mrc 指令
armv7 中對于協處理器的訪問,CP15
的寄存器只能被MRC
和MCR
(Move to Coprocessor from ARM Register )指令訪問。MCR
表示將?arm
?核心寄存器中的值的寫到?cp15
?寄存器中,MRC
?從?cp15
?寄存器中讀到?arm
?核心寄存器中,大部分指令都需要在?PL1
?以及更高的特權級下才能正常執行,這是因為?cp15
?協處理器大多都涉及到系統和內存的設置,user
?模式沒有操作權限,user
?模式僅能訪問?cp15
?中有限的幾個寄存器比如:ISB、DSB、DMB、TPIDRURW、TPIDRURO 寄存器。
從 `cp**` 寄存器中讀到 `arm` 核心寄存器中
MRC<cond> <coproc>, <opc1>, <Rt>, <CRn>, <CRm>{, <opc2>}
- cond?: 指令后綴,表示條件執行,關于條件執行可以參考 arm狀態寄存器
- coproc?:協處理器的名稱,cp0~cp15 分別對應名稱 p0~p15
- opc1?:對于 cp15 而言,這一個參數一般為0。
- Rt?:arm 的通用寄存器
- CRn?:與 arm 核心寄存器交換數據的核心寄存器名,c0~c15
- CRm?:需要額外操作的協處理器的寄存器名,c0~c15,針對多種功能的 cp15 寄存器,需要使用 CRm 和 opc2 來確定 CRn 對應哪個寄存器實體。
- opc2?:可選,與 CRm搭配使用,同樣是決定多功能寄存器中指定實體。
啥玩意,太抽象沒看懂,后面直接上內核代碼就懂了,先看16個寄存器的功能介紹表
c0 寄存器
c0?寄存器提供處理器和特征識別 ,內核宏定義為,可參考圖理解
/*!* Identification registers (c0) | c0 - 身份寄存器*/
#define MIDR CP15_REG(c0, 0, c0, 0) /*! Main ID Register | 主ID寄存器 */
#define MPIDR CP15_REG(c0, 0, c0, 5) /*! Multiprocessor Affinity Register | 多處理器關聯寄存器給每個CPU制定一個邏輯地址*/
#define CCSIDR CP15_REG(c0, 1, c0, 0) /*! Cache Size ID Registers | 緩存大小ID寄存器*/
#define CLIDR CP15_REG(c0, 1, c0, 1) /*! Cache Level ID Register | 緩存登記ID寄存器*/
#define VPIDR CP15_REG(c0, 4, c0, 0) /*! Virtualization Processor ID Register | 虛擬化處理器ID寄存器*/
#define VMPIDR CP15_REG(c0, 4, c0, 5) /*! Virtualization Multiprocessor ID Register | 虛擬化多處理器ID寄存器*/
c1 寄存器
c1?為系統控制寄存器
/*!* System control registers (c1) | c1 - 系統控制寄存器 各種控制位(可讀寫)*/
#define SCTLR CP15_REG(c1, 0, c0, 0) /*! System Control Register | 系統控制寄存器*/
#define ACTLR CP15_REG(c1, 0, c0, 1) /*! Auxiliary Control Register | 輔助控制寄存器*/
#define CPACR CP15_REG(c1, 0, c0, 2) /*! Coprocessor Access Control Register | 協處理器訪問控制寄存器*/
/// 讀取CP15的系統控制寄存器到 R0寄存器
STATIC INLINE UINT32 OsArmReadSctlr(VOID)
{UINT32 val;__asm__ volatile("mrc p15, 0, %0, c1,c0,0" : "=r"(val));return val;
}
/// R0寄存器寫入CP15的系統控制寄存器
STATIC INLINE VOID OsArmWriteSctlr(UINT32 val)
{__asm__ volatile("mcr p15, 0, %0, c1,c0,0" ::"r"(val));__asm__ volatile("isb" ::: "memory");
}
解讀
- 從圖中找到?
c1-0-c0-0
行,后邊的備注是?SCTLR, System Control Register?系統控制寄存器,其操作模式是支持?Read/Write %0
表示?r0?寄存器,注意這個寄存器是CPU
的寄存器,: “=r”(val)?意思向編譯器聲明,會修改R0
寄存器的值,改之前提前打好招呼,都是紳士文明人。其實編譯器的功能是非常強大的,不僅僅是大家普遍認為的只是編譯代碼的工具而已。OsArmReadSctlr
的含義就是讀取CP15的系統控制寄存器到R0寄存器。volatile
的意思還告訴編譯器,不要去優化這段代碼,原封不動的生成目標指令。- “isb” ::: “memory” 還是告訴編譯器內存的內容要被更改了,需要無效所有
Cache
,并訪問實際的內容,而不是Cache!
- CRn?|?CRm?|?opc2?是一套組合拳,
c7-0-c10-4
?c7-0-c10-5
?都表示不同的功能含義
c2、c3 寄存器
/*!* Memory protection and control registers (c2 & c3) | c2 - 傳說中的TTB寄存器,主要是給MMU使用 c3 - 域訪問控制位*/
#define TTBR0 CP15_REG(c2, 0, c0, 0) /*! Translation Table Base Register 0 | 轉換表基地址寄存器0*/
#define TTBR1 CP15_REG(c2, 0, c0, 1) /*! Translation Table Base Register 1 | 轉換表基地址寄存器1*/
#define TTBCR CP15_REG(c2, 0, c0, 2) /*! Translation Table Base Control Register | 轉換表基地址控制寄存器*/
#define DACR CP15_REG(c3, 0, c0, 0) /*! Domain Access Control Register | 域訪問控制寄存器*/
看段代碼
STATIC INLINE UINT32 OsArmReadTtbr0(VOID)
{UINT32 val;__asm__ volatile("mrc p15, 0, %0, c2,c0,0" : "=r"(val));return val;
}
STATIC INLINE VOID OsArmWriteTtbr0(UINT32 val)
{__asm__ volatile("mcr p15, 0, %0, c2,c0,0" ::"r"(val));__asm__ volatile("isb" ::: "memory");
}
STATIC INLINE UINT32 OsArmReadTtbr1(VOID)
{UINT32 val;__asm__ volatile("mrc p15, 0, %0, c2,c0,1" : "=r"(val));return val;
}
STATIC INLINE VOID OsArmWriteTtbr1(UINT32 val)
{__asm__ volatile("mcr p15, 0, %0, c2,c0,1" ::"r"(val));__asm__ volatile("isb" ::: "memory");
}
c2
寄存器負責存頁表的基地址,即一級映射描述符表的基地址。還記得嗎?每個進程的頁表都是獨立的!c2
值一變,當前使用的頁表就發生了變化,頁表變化意味著虛擬地址和物理地址的映射關系發生了變化。那么什么情況下會修改里面的值呢?很容易想到只有在進程切換時發生的mmu
上下文切換,直接看代碼吧!
/// mmu 上下文切換
VOID LOS_ArchMmuContextSwitch(LosArchMmu *archMmu)
{UINT32 ttbr;UINT32 ttbcr = OsArmReadTtbcr();//讀取TTB寄存器的狀態值if (archMmu) {ttbr = MMU_TTBRx_FLAGS | (archMmu->physTtb);//進程TTB物理地址值/* enable TTBR0 */ttbcr &= ~MMU_DESCRIPTOR_TTBCR_PD0;//使能TTBR0} else {ttbr = 0;/* disable TTBR0 */ttbcr |= MMU_DESCRIPTOR_TTBCR_PD0;}
#ifdef LOSCFG_KERNEL_VM/* from armv7a arm B3.10.4, we should do synchronization changes of ASID and TTBR. */OsArmWriteContextidr(LOS_GetKVmSpace()->archMmu.asid);//這里先把asid切到內核空間的IDISB; //指令必須同步 ,清楚流水線中未執行指令
#endifOsArmWriteTtbr0(ttbr);//通過r0寄存器將進程頁面基址寫入TTBISB; //指令必須同步OsArmWriteTtbcr(ttbcr);//寫入TTB狀態位ISB; //指令必須同步
#ifdef LOSCFG_KERNEL_VMif (archMmu) {OsArmWriteContextidr(archMmu->asid);//通過R0寄存器寫入進程標識符至C13寄存器ISB;}
#endif
}
至于具體內核哪些地方會觸發到?mmu
的切換,可前往翻看?(進程切換篇)
c4 寄存器
c4 沒有用于任何?ARMv7?實現,這么不待見4,難道原因跟中國人一樣覺得數字不吉利 ,但老師教的老外是不喜歡 13 啊 , 但c13確很重要
c5 c6 寄存器
c5和c6寄存器提供內存系統故障報告。此外,c6還提供了MPU區域寄存器。這一類寄存器在軟件排錯時可以提供非常大的幫助,比如通過 DFSR(數據狀態寄存器)、IFSR(指令狀態寄存器) 的 status bits 可以查到系統 abort 類型,內核中的缺頁異常就是通過該寄存器傳遞異常地址,從而分配頁面的。
/*!* Memory system fault registers (c5 & c6) | c5 - 內存失效狀態 c6 - 內存失效地址*/
#define DFSR CP15_REG(c5, 0, c0, 0) /*! Data Fault Status Register | 數據故障狀態寄存器 */
#define IFSR CP15_REG(c5, 0, c0, 1) /*! Instruction Fault Status Register | 指令故障狀態寄存器*/
#define DFAR CP15_REG(c6, 0, c0, 0) /*! Data Fault Address Register | 數據故障地址寄存器*/
#define IFAR CP15_REG(c6, 0, c0, 2) /*! Instruction Fault Address Register | 指令錯誤地址寄存器*/
c7 寄存器
c7寄存器提供高速緩存維護操作和內存屏障操作。
c8 寄存器
c8 寄存器提供 TLB 維護功能
TLB
是硬件上的一個cache
,因為頁表一般都很大,并且存放在內存中,所以處理器引入MMU
后,讀取指令、數據需要訪問兩次內存:首先通過查詢頁表得到物理地址,然后訪問該物理地址讀取指令、數據。為了減少因為MMU導致的處理器性能下降,引入了TLB
,可翻譯為“地址轉換后援緩沖器”,也可簡稱為“快表”。簡單地說,TLB
就是頁表的Cache
,其中存儲了當前最可能被訪問到的頁表項,其內容是部分頁表項的一個副本。只有在TLB
無法完成地址翻譯任務時,才會到內存中查詢頁表,這樣就減少了頁表查詢導致的處理器性能下降。詳細看
照著圖說吧,步驟是這樣的。
- 圖中的
page table
的基地址就是上面TTB
寄存器值,整個page table
非常大,有多大接下來會講,所以只能存在內存里,TTB
中只是存一個開始位置而已。 - 虛擬地址是程序的地址邏輯地址,也就是喂給
CPU
的地址,必須經過MMU
的轉換后變成物理內存才能取到真正的指令和數據。 TLB
是page table
的迷你版,MMU
先從TLB
里找物理頁,找不到了再從page table
中找,從page table
中找到后會放入TLB
中,注意這一步非常非常的關鍵。因為page table
是屬于進程的會有很多個,而TLB
只有一個,不放入就會出現多個進程的page table
都映射到了同一個物理頁框而不自知。一個物理頁同時只能被一個page table
所映射。但除了TLB
的唯一性外,要做到不錯亂還需要了一個東西,就是進程在映射層面的唯一標識符 -?asid
,具體可前往翻看?(進程切換篇)?有詳細說明。
c9 寄存器
c9 寄存器主要為 cache、分之預測 和 tcm 保留功能,這些保留功能由處理的實現決定
c10 寄存器
c10 寄存器主要提供內存重映射和 TLB 控制功能
c11 寄存器
c11 寄存器主要提供 TCM 和 DMA 的保留功能,這些保留功能由處理的實現決定
c12 寄存器
c12 安全擴展寄存器
c13 寄存器
c13 寄存器提供進程、上下文以及線程ID處理功能
/*!* Process, context and thread ID registers (c13) | c13 - 進程標識符*/
#define FCSEIDR CP15_REG(c13, 0, c0, 0) /*! FCSE Process ID Register | FCSE(Fast Context Switch Extension,快速上下文切換)進程ID寄存器 位于CPU和MMU之間*/
#define CONTEXTIDR CP15_REG(c13, 0, c0, 1) /*! Context ID Register | 上下文ID寄存器*/
#define TPIDRURW CP15_REG(c13, 0, c0, 2) /*! User Read/Write Thread ID Register | 用戶讀/寫線程ID寄存器*/
#define TPIDRURO CP15_REG(c13, 0, c0, 3) /*! User Read-Only Thread ID Register | 用戶只讀寫線程ID寄存器*/
#define TPIDRPRW CP15_REG(c13, 0, c0, 4) /*! PL1 only Thread ID Register | 僅PL1線程ID寄存器*/
c14 寄存器
c14 寄存器提供通用定時器擴展的保留功能
c15 寄存器
ARMv7 保留 c15 用于實現定義的目的,并且不對 c15 編碼的使用施加任何限制。
意思就是可以將他當通用寄存器來使用 語法:?c15 0-7 c0-c15 0-7
鴻蒙全棧開發全新學習指南
也為了積極培養鴻蒙生態人才,讓大家都能學習到鴻蒙開發最新的技術,針對一些在職人員、0基礎小白、應屆生/計算機專業、鴻蒙愛好者等人群,整理了一套純血版鴻蒙(HarmonyOS Next)全棧開發技術的學習路線【包含了大廠APP實戰項目開發】。
本路線共分為四個階段:
第一階段:鴻蒙初中級開發必備技能
第二階段:鴻蒙南北雙向高工技能基礎:gitee.com/MNxiaona/733GH
第三階段:應用開發中高級就業技術
第四階段:全網首發-工業級南向設備開發就業技術:gitee.com/MNxiaona/733GH
《鴻蒙 (Harmony OS)開發學習手冊》(共計892頁)
如何快速入門?
1.基本概念
2.構建第一個ArkTS應用
3.……
開發基礎知識:gitee.com/MNxiaona/733GH
1.應用基礎知識
2.配置文件
3.應用數據管理
4.應用安全管理
5.應用隱私保護
6.三方應用調用管控機制
7.資源分類與訪問
8.學習ArkTS語言
9.……
基于ArkTS 開發
1.Ability開發
2.UI開發
3.公共事件與通知
4.窗口管理
5.媒體
6.安全
7.網絡與鏈接
8.電話服務
9.數據管理
10.后臺任務(Background Task)管理
11.設備管理
12.設備使用信息統計
13.DFX
14.國際化開發
15.折疊屏系列
16.……
鴻蒙開發面試真題(含參考答案):gitee.com/MNxiaona/733GH
鴻蒙入門教學視頻:
美團APP實戰開發教學:gitee.com/MNxiaona/733GH
寫在最后
- 如果你覺得這篇內容對你還蠻有幫助,我想邀請你幫我三個小忙:
- 點贊,轉發,有你們的 『點贊和評論』,才是我創造的動力。
- 關注小編,同時可以期待后續文章ing🚀,不定期分享原創知識。
- 想要獲取更多完整鴻蒙最新學習資源,請移步前往小編:
gitee.com/MNxiaona/733GH