- 嵌入式系統(tǒng)Linux內(nèi)核開發(fā)實戰(zhàn)指南(ARM平臺)
- 王洪輝編著
- 16字
- 2018-12-27 18:21:40
第6章 ARM處理器存儲訪問一致性問題
6.1 存儲訪問一致性問題介紹
當(dāng)存儲系統(tǒng)中引入了cache和寫緩沖區(qū)(Write Buffer)時,同一地址單元的數(shù)據(jù)可能在系統(tǒng)中有多個副本,分別保存在cache、Write Buffer及主存中,如果系統(tǒng)采用了獨(dú)立的數(shù)據(jù)cache和指令cache,同一地址單元的數(shù)據(jù)還可能在數(shù)據(jù)cache和指令cache中有不同的版本。位于不同物理位置的同一地址單元的數(shù)據(jù)可能會不同,使得數(shù)據(jù)讀操作可能得到的不是系統(tǒng)中“最新的數(shù)值”,這樣就帶來了存儲系統(tǒng)中數(shù)據(jù)的一致性問題。在ARM存儲系統(tǒng)中,數(shù)據(jù)不一致的問題則需要通過程序設(shè)計時遵守一定的規(guī)則來保證,這些規(guī)則說明如下。
6.1.1 地址映射關(guān)系變化造成的數(shù)據(jù)不一致性
當(dāng)系統(tǒng)中使用了MMU時,就建立了虛擬地址到物理地址的映射關(guān)系,如果查詢cache時進(jìn)行的相連比較使用的是虛擬地址,則當(dāng)系統(tǒng)中虛擬地址到物理地址的映射關(guān)系發(fā)生變化時,可能造成cache中的數(shù)據(jù)和主存中數(shù)據(jù)不一致的情況。
在虛擬地址到物理地址的映射關(guān)系發(fā)生變化前,如果虛擬地址A1所在的數(shù)據(jù)塊已經(jīng)預(yù)取到cache中,當(dāng)虛擬地址到物理地址的映射關(guān)系發(fā)生變化后,如果虛擬地址A1對應(yīng)的物理地址發(fā)生了改變,則當(dāng)CPU訪問A1時再使用cache中的數(shù)據(jù)塊將得到錯誤的結(jié)果。
同樣當(dāng)系統(tǒng)中采用了Write Buffer時,如果CPU寫入Write Buffer的地址是虛擬地址,也會發(fā)生數(shù)據(jù)不一致的情況。在虛擬地址到物理地址的映射關(guān)系發(fā)生變化前,如果CPU向虛擬地址為A1的單元執(zhí)行寫操作,該寫操作已經(jīng)將A1以及對應(yīng)的數(shù)據(jù)寫入到Write Buffer中,當(dāng)虛擬地址到物理地址的映射關(guān)系發(fā)生變化后,如果虛擬地址A1對應(yīng)的物理地址發(fā)生了改變,當(dāng)Write Buffer將上面被延遲的寫操作寫到主存中時,使用的是變化后的物理地址,從而使寫操作失敗。
為了避免發(fā)生這種數(shù)據(jù)不一致的情況,在系統(tǒng)中虛擬地址到物理地址的映射關(guān)系發(fā)生變化前,根據(jù)系統(tǒng)的具體情況,執(zhí)行下面操作序列中的一種或幾種:
1)如果數(shù)據(jù)cache為write back類型,清空該數(shù)據(jù)的cache;
2)使數(shù)據(jù)cache中相應(yīng)的塊無效;
3)使指令cache中相應(yīng)的塊無效;
4)將Write Buffer中被延遲的寫操作全部執(zhí)行;
5)有些情況可能還要求相關(guān)的存儲區(qū)域被設(shè)置成非緩沖的。
6.1.2 指令cache的數(shù)據(jù)不一致性問題
當(dāng)系統(tǒng)中采用獨(dú)立的數(shù)據(jù)cache和指令cache時,下面的操作序列可能造成指令不一致的情況:
1)讀取地址為A1的指令,從而包含該指令的數(shù)據(jù)塊被預(yù)取到指令cache中。
2)與A1在同一個數(shù)據(jù)塊中的地址為A2的存儲單元的數(shù)據(jù)被修改,這個數(shù)據(jù)寫操作可能影響數(shù)據(jù)cache、Write Buffer和主存中地址為A2的存儲單元的內(nèi)容,但是不影響指令cache中地址為A2的存儲單元的內(nèi)容。
3)如果地址A2存放的是指令,當(dāng)該指令執(zhí)行時,就可能發(fā)生指令不一致的問題。如果地址A2所在的塊還在指令cache中,系統(tǒng)將執(zhí)行修改前的指令。如果地址A2所在的塊不在指令cache中,系統(tǒng)將執(zhí)行修改后的指令。
為了避免這種指令不一致情況的發(fā)生,在上面第1)步和第2)步之間插入下面的操作序列:
1)對于使用統(tǒng)一的數(shù)據(jù)cache和指令cache的系統(tǒng),不需要任何操作;
2)對于使用獨(dú)立的數(shù)據(jù)cache和指令cache的系統(tǒng),使指令cache的內(nèi)容無效;
3)對于使用獨(dú)立的數(shù)據(jù)cache和指令cache的系統(tǒng),如果數(shù)據(jù)cache是write back類型的,清空數(shù)據(jù)cache。
當(dāng)數(shù)據(jù)操作修改了指令時,最好執(zhí)行上述操作序列,保證指令的一致性。下面是上述操作序列的一個典型應(yīng)用場合。當(dāng)可執(zhí)行文件加載到主存中后,在程序跳轉(zhuǎn)到入口點(diǎn)處開始執(zhí)行之前,先執(zhí)行上述的操作序列,以保證下面指令的是新加載的可執(zhí)行代碼,而不是指令中原來的舊代碼。
6.1.3 DMA造成的數(shù)據(jù)不一致問題
DMA操作直接訪問主存,而不會更新cache和Write Buffer中相應(yīng)的內(nèi)容,這樣就可能造成數(shù)據(jù)的不一致。
如果DMA從主存中讀取的數(shù)據(jù)已經(jīng)包含在cache中,而且cache中對應(yīng)的數(shù)據(jù)已經(jīng)被更新,這樣DMA讀到的將不是系統(tǒng)中最新的數(shù)據(jù)。同樣DMA寫操作直接更新主存中的數(shù)據(jù),如果該數(shù)據(jù)已經(jīng)包含在cache中,則cache中的數(shù)據(jù)將會比主存中對應(yīng)的數(shù)據(jù)“老”,也將造成數(shù)據(jù)的不一致。
為了避免這種數(shù)據(jù)不一致情況的發(fā)生,根據(jù)系統(tǒng)的具體情況,執(zhí)行下面操作序列中的一種或幾種:
1)將DMA訪問的存儲區(qū)域設(shè)置成非緩沖的,即uncachable及unbufferable;
2)將DMA訪問的存儲區(qū)域所涉及數(shù)據(jù)cache中的塊設(shè)置成無效,或者清空數(shù)據(jù)cache;
3)清空Write Buffer(執(zhí)行Write Buffer中延遲的所有寫操作);
4)在DMA操作期間限制處理器訪問DMA所訪問的存儲區(qū)域。
6.1.4 指令預(yù)取和自修改代碼
在ARM中允許指令預(yù)取,在CPU執(zhí)行當(dāng)前指令的同時,可以從存儲器中預(yù)取其后若干條指令,具體預(yù)取多少條指令,不同的ARM實現(xiàn)中有不同的數(shù)值。
當(dāng)用戶讀取PC寄存器的值時,返回的是當(dāng)前指令下面第2條指令的地址。比如當(dāng)前執(zhí)行的是第N條指令,當(dāng)用戶讀取PC寄存器的值時,返回的是指令N+2的地址。對于ARM指令來說,讀取PC寄存器的值時,返回當(dāng)前指令地址值加8個字節(jié);對于Thumb指令來說,讀取PC寄存器的值時,返回當(dāng)前指令地址值加4個字節(jié)。
6.2 Linux中解決存儲訪問一致性問題的方法
在Linux中,是用barrier()宏來解決以上存儲訪問一致性問題的,barrier()的定義如下所示:
#define barrier() __asm__ __volatile__("": : :"memory")
另外在barrier()的基礎(chǔ)上還衍生出了很多類似的定義,如:
#define mb() __asm__ __volatile__ ("" : : : "memory") #define rmb() mb() #define wmb() mb() #define smp_mb() barrier() #define smp_rmb() barrier() #define smp_wmb() barrier()
barrier是內(nèi)存屏障的意思,CPU越過內(nèi)存屏障后,將刷新自己對存儲器的緩沖狀態(tài)。barrier()宏定義這條語句實際上不生成任何代碼,但可使gcc在barrier()之后刷新寄存器對變量的分配。具體分析如下。

概括起來說barrier()起到兩個作用:
1)告訴編譯器不要優(yōu)化這部分代碼,保持原有的指令執(zhí)行順序;
2)告訴CPU執(zhí)行完barrier()之后要進(jìn)行同步操作,更新registers、cache、寫緩存和內(nèi)存中的內(nèi)容,全部重新從內(nèi)存中取數(shù)據(jù)。
- 用Proteus可視化設(shè)計玩轉(zhuǎn)Arduino
- 輕松學(xué)會單片機(jī)
- 單片機(jī)應(yīng)用項目化教程
- TinyML:基于TensorFlow Lite在Arduino和超低功耗微控制器上部署機(jī)器學(xué)習(xí)
- 嵌入式產(chǎn)品分析與設(shè)計
- 嵌入式系統(tǒng)設(shè)計與實踐:Linux篇
- 單片機(jī)原理與應(yīng)用技術(shù)
- 單片機(jī)原理與接口技術(shù)
- 零基礎(chǔ)學(xué)51單片機(jī)(C語言版)
- C51單片機(jī)項目設(shè)計實踐教程(第2版)
- 案例解說組態(tài)軟件典型控制應(yīng)用
- 深度學(xué)習(xí)實踐教程
- 單片機(jī)原理與工程應(yīng)用
- 高分辨率遙感影像變化檢測
- 51單片機(jī)應(yīng)用開發(fā)案例手冊