uboot中的mmu和cache開啟(基本協處理器操作)
參考的書籍主要是<深度探索嵌入式作業系統> 彭東 著 第三章的內容 結合uboot 編譯rpi遇到的問題
mmu主要是實體地址和虛擬地址的轉換
cache主要有icache指令快取和dcache資料快取。比如在cpu執行for迴圈的時候需要重複訪問一句指令或者一個數據。訪問記憶體是慢一點的。cache是比記憶體更快一點的
在第二個階段的board_r的initr_caches中
static int initr_caches(void)
{
/* Enable caches */
enable_caches();
return 0;
}
enable_caches在arm/cpu/arm11當中
void enable_caches(void)
{
icache_enable();
dcache_enable();
}
分別使用
cache_enable(CR_I); 開啟icache
cache_enable(CR_C);開啟dcache
基本的CR_X定義在
arch\arm\include\asm\system.h中有
#define CR_M(1 << 0) /* MMU enable*/
#define CR_C(1 << 2) /* Dcache enable*/
#define CR_I(1 << 12) /* Icache enable*/
arch\arm\lib\cache-cp15.c中對於cache_enable定義,主要看這一部分
/* cache_bit must be either CR_I or CR_C */
cache_bit必須是CR_I或者CR_C。也就是cache_enable只對於ICACHE和DCACHE有效
static void cache_enable(uint32_t cache_bit)
{
uint32_t reg;
如果是開啟dcache。那麼必須先開啟mmu。因為dcache只有在mmu開啟的時候才有效
/* The data cache is not active unless the mmu is enabled too */
if ((cache_bit == CR_C) && !mmu_enabled())
mmu_setup();
reg = get_cr();/* get control reg. */
cp_delay();
set_cr(reg | cache_bit);
}
開啟mmu呼叫的是mmu_setup() 後續看。
先看統一的
arm\include\asm\system.h定義。armv6系列不支援虛擬化lape所以就是
{
unsigned int val;
asm volatile("mrc p15, 0, %0, c1, c0, [email protected] get CR" : "=r" (val)
:
: "cc");
將p15協處理器的c1的暫存器的值放到val中
return val;}
static inline void set_cr(unsigned int val)
{
asm volatile("mcr p15, 0, %0, c1, c0, [email protected] set CR" :
: "r" (val)
: "cc");
將val的值放到p15協處理器的c1的暫存器中
isb();
將0寫入p15協處理器的c7暫存器中,附加暫存器c5和4操作碼。
通過查表知道這個操作是清空預取緩衝區,把預取緩衝區的資料回寫到儲存器中。
/*
isb在asm/barriers.h中等同於
asm volatile ("mcr p15, 0, %0, c7, c5, 4" : : "r" (0))
*/
}
主要通過操作arm cp15協處理 暫存器來實現 (還有其他的cpXXX協處理器操作其他功能)。
常用操作協處理器的指令有mrc和mcr {}中表示可選<>表示必選
把資料從協處理暫存器放到普通Rn暫存器中
mrc{cond} <coproc>,<opcode_1>,<Rd>,<CRn>,<CRm> {,opcode_2}
把資料從普通Rn暫存器放到協處理暫存器中
mcr{cond} <coproc>,<opcode_1>,<Rd>,<CRn>,<CRm> {,opcode_2}
1 {cond}是條件,滿足條件就執行,沒有的話無條件執行。
2 <coproc>表示要處理的協處理器編號
3<opcode_1> 是協處理暫存器的操作碼1
4<Rd>需要操作的普通暫存器d
5<CRn>需要操作的協處理暫存器n
6<CRm>需要操作的附加的協處理暫存器m
7{,opcode_2}協處理器的操作碼2可能需要多個
CP15協處理器是一個統稱。CP15包括了16個32bit的暫存器 c0-c15具體每個暫存器功能要查表。比如c0可能對應兩個物理暫存器。操作的時候需要通過opcode_2來區分到底是哪一個
看到gercr和setcr主要是操作了cp15協處理器的c1暫存器 c1暫存器是儲存系統的控制暫存器 第0位CR_M控制MMU開啟關閉 第2位CR_C控制資料cache的開啟關閉 第12位CR_I控制指令cache的開啟關閉 0表示關閉 1表示開啟 因此對於開啟icache和dcache就是簡單地設定了一個cp15的cr1對應的標誌位。目前只瞭解cache的開啟和關閉就行了。 但是使用dcache之前開啟了mmu,mmu是有必要了解清楚的。 mmu_setup()也在cache-cp15.c中 /* to activate the MMU we need to set up virtual memory: use 1M areas */static inline void mmu_setup(void)
{
int i;
u32 reg;
空函式
arm_init_before_mmu();
/* Set up an identity-mapping for all 4GB, rw for everyone */ //#define MMU_SECTION_SHIFT20 /* i<(4GB>>20) 也就是1MB i<4096 */ 這裡uboot的mmu用段來表示。也就是1M為大小,1級頁表4096個條目恰好是4GB。 還可以用64KB 4kb1kb來表示。那就需要多級頁表了。 for (i = 0; i < ((4096ULL * 1024 * 1024) >> MMU_SECTION_SHIFT); i++) { 設定1M頁表的每一項內容 每一個頁表項的31:20bit是記憶體空間的實體地址。段頁是1M,因此低20位一定為0.剛好可以做控制位。具體可以看段頁表低20bit各個位內容。 set_section_dcache(i, DCACHE_OFF); }
在rpi定義裡面有#define CONFIG_NR_DRAM_BANKS1 因此只要執行一次dram_bank_mmu_setup(0)
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 將所有是有效的記憶體設定DCACHE為DCACHE_WRITEBACK
dram_bank_mmu_setup(i);
}
/* Copy the page table address to cp15 */ 將頁表地址tlb_addr放到c2暫存器當中。c2存放一級頁表基地址。這個地址是實體地址
asm volatile("mcr p15, 0, %0, c2, c0, 0"
: : "r" (gd->arch.tlb_addr) : "memory"); 將0xFFFFFFFF放到c3暫存器當中。c3暫存器每兩位定義了一個訪問許可權,。0b11表示不做許可權檢查,0xffffffff就是全部是1,任何人都能訪問。
/* Set the access control to all-supervisor */
asm volatile("mcr p15, 0, %0, c3, c0, 0"
: : "r" (~0)); 空函式
arm_init_domains();
/* and enable the mmu */ 以下是開啟MMU的程式碼
reg = get_cr();/* get control reg. */
cp_delay();
set_cr(reg | CR_M);
}
在reserve_mmu裡面對於 tlb_addr和tlb_size都有初始化 tlbsize=4096*4 也就是tlb表為64KB 設定頁表項的函式。 void set_section_dcache(int section, enum dcache_option option)
{
u32 *page_table = (u32 *)gd->arch.tlb_addr; //#define TTB_SECT_AP(3 << 10) 訪問控制位。是段頁項的10 11bit因此左移10. 11代表的是可讀可寫。 //但是由於後面C3暫存器被設定為任何人都能訪問,因此這裡的AP位是無效的。 //C3暫存器 為01時。AP位才有效,和C1的R S位來確定訪問許可權。
u32 value = TTB_SECT_AP;
/* Add the page offset */ 設定頁表條目記憶體空間的實體地址。 前面的的for迴圈從0-4095因此4096個頁表的基地址依次是 0x00000000 0x00100000 0x00200000 ... ... 0xFFF00000 每個段1M恰好4GB
value |= ((u32)section << MMU_SECTION_SHIFT); 新增cachebit設定 enum dcache_option {
DCACHE_OFF = 0x12,
DCACHE_WRITETHROUGH = 0x1a,
DCACHE_WRITEBACK = 0x1e,
DCACHE_WRITEALLOC = 0x16,
};
DCACHE_OFF =0x12=0b 1(4bit) 0(3bit) 0(2bit) 1(1bit) 0(0bit) 1:0bit 是 10 表示當前條目是段頁 3:2bit是 00表示無快取 4bit是向後相容 最好為1 /* Add caching bits */
value |= option;
/* Set PTE */
page_table[section] = value;
}
對於rpi只執行了一次dram_bank_mmu_setup(0) void dram_bank_mmu_setup(int bank)
{
bd_t *bd = gd->bd;
inti;
debug("%s: bank: %d\n", __func__, bank); /* bi_dram的初始化是 __weak void dram_init_banksize(void)
{
gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
gd->bd->bi_dram[0].size = get_effective_memsize();
} CONFIG_SYS_SDRAM_BASE 是0 get_effective_memsize();返回的是ram_size大小 448MB */ 這裡也就是將所有的有效記憶體都設定為DCACHE_WRITEBACK 因此這裡就是從i從 0-448都設定為DCACHE_WRITEBACK 448-4095都是DCACHE_OFF
for (i = bd->bi_dram[bank].start >> MMU_SECTION_SHIFT;i < (bd->bi_dram[bank].start >> MMU_SECTION_SHIFT) +(bd->bi_dram[bank].size>>MMU_SECTION_SHIFT);i++) {
set_section_dcache(i, DCACHE_WRITEBACK);
} } 對於1M段mmu 虛擬地址到實體地址的轉換。
-
虛擬地址的[31:20]位存放一級頁表的入口index,[19:0]位存放段偏移;
-
從TTBR(translation table base register,協處理器CP15中的一個暫存器,用於存放一級頁表的基址)暫存器中獲取一級頁表的基址;
-
一級頁表基址+ VA[31:20] = 該虛擬地址對應的頁表描述符的入口地址;
-
頁表描述符的[31:20]位為該虛擬地址對應的物理段基址;
-
物理段基址+ VA[19:0]段偏移= 實體地址
cp_delay();
set_cr(reg | CR_M); } void disable_mmu() { u32 reg; reg = get_cr(); /* get control reg. */
cp_delay();
set_cr(reg &(~CR_M)); }
相關推薦
uboot中的mmu和cache開啟(基本協處理器操作)
參考的書籍主要是<深度探索嵌入式作業系統> 彭東 著 第三章的內容 結合uboot 編譯rpi遇到的問題 mmu主要是實體地址和虛擬地址的轉換 cache主要有icache指令快取和dcache資料快取。比如在cpu執行for迴圈的時候需要重複訪問一句指令或者
關閉mmu和cache
進程 software body con global ack fetch 寄存器 單元 處理器內部寄存器,訪問速度最快,但是數量少 TCM:緊耦合存儲器(Cache、主存儲器) 輔助存儲器(Flash、SD等) Cache是一種容量小但是存取速度非常快的存儲器 它保存
Django中Cookie和Session的基本配置以及設置
Cookie Session Django中Cookie和Sessi Cookie1、獲取Cookie:request.COOKIES['key'] request.get_signed_cookie(key, default=RAISE_ERROR, salt=''
SQL中varchar和nvarchar的基本介紹及其區別
SQL中varchar和nvarchar的基本介紹及其區別 varchar(n) 長度為 n 個位元組的可變長度且非 Unicode 的字元資料。n 必須是一個介於 1 和 8,000 之間的數值。儲存大小為輸入資料的位元組的實際長度,而不是 n 個位元組。 nvarchar(n)
js中typeof和instanceof的基本用法以及區別
JavaScript 中 typeof 和 instanceof 通常都會用來判斷一個變數是否為空,或者是什麼型別的。但在具體使用中它們之間還是有區別的: 首先我們來說一下typeof的用法以及需要注意的地方: typeof 是一個一元運算,放在一個運算數之前,這個運算數可以是任意的
Gensim中word2vec和doc2vec的基本用法
一、 word2vec: from gensim.models.word2vec import Word2Vec model = Word2Vec(lines, sg=1, size=100, wi
Swift開發筆記3.Swift中setter和getter的基本用法
Swift中有儲存屬性和計算屬性兩種。其中在計算屬性中可以實現setter和getter方法,我們在playground中定義兩個結構體: struct Point { var x = 0.0, y = 0.0 } struct Size { var wi
Linux中Buffer和Cache的區別
2. Buffer:緩衝區,用於儲存速度不同步的裝置或優先順序不同的裝置之間傳輸資料;通過buffer可以減少程序間通訊需要等待的時間,當儲存速度快的裝置與儲存速度慢的裝置進行通訊時,儲存慢的資料先把資料存放到buffer,達到一定程度儲存快的裝置再讀取buffer的資料,在此期間儲存快的裝置CPU可以幹其他
Java中堆和棧的基本概念
Java把記憶體分成兩種,一種叫做棧記憶體,一種叫做堆記憶體。 在函式中定義的一些基本型別的變數和物件的引用變數都是在函式的棧記憶體中分配。當在一段程式碼塊中定義一個變數時,java就在棧中為這個變數分配記憶體空間,當超過變數的作用域後,java會自動釋放掉為該變數
HBase建表高階屬性,hbase應用案例看行鍵設計,HBase和mapreduce結合,從Hbase中讀取資料、分析,寫入hdfs,從hdfs中讀取資料寫入Hbase,協處理器和二級索引
1. Hbase高階應用 1.1建表高階屬性 下面幾個shell 命令在hbase操作中可以起到很到的作用,且主要體現在建表的過程中,看下面幾個create 屬性 1、 BLOOMFILTER 預設是NONE 是否使用布隆過慮及使用何種方式 布隆
Groovy中map和陣列的基本使用
groovy也提供了像java一樣的maph\和陣列但是使用起來比java要簡單的多,而且使用起來更靈活,像map集合省事的不只一點點,來看看下面的程式碼 package org.lxh class UseMap { public static main(def
JQuery 中this和$(this)獲取對象、操作DOM對象的元素屬性
class 獲取對象 clas details 對象 query 操作 active html $(‘.button‘).click(function () { var active = $(‘.buttons-tab a‘).children(‘input‘).at
vi和vim編譯器基本介紹及操作
一、基本介紹 所有的Linux系統都會內建vi文字編輯器 vim可以看作是vi的增強版,可以主動的以字型顏色辨別語法的正確性,方便程式設計。程式碼不全、編譯及錯誤跳轉等方便程式設計的功能特別豐富。 二、vi和vim的三種常見模式 a.一般模式 在此模式下
Android中java和smali轉化一鍵化操作工具java2smali原理分析
最近在小密圈中,有同學諮詢到如何快速的將java檔案轉化成smali檔案,因為我們知道在反編譯之
Centos中iptables和firewall防火墻開啟、關閉、查看狀態、基本設置等(轉)
firewall 開啟 highlight tar service服務 sha sysconfig linu accept iptables防火墻 1、基本操作 # 查看防火墻狀態 service iptables status # 停止防火墻 service ip
Centos中iptables和firewall防火牆開啟、關閉、檢視狀態、基本設定等
iptables防火牆 1、基本操作 # 檢視防火牆狀態 service iptables status # 停止防火牆 service iptables stop # 啟動防火牆 service iptables start # 重啟防火牆 s
java中的棧Stack的基本使用和應用(一)
string emp tac logs tor str col () bject 棧 定義 棧是一種只能在一端進行插入或刪除操作的線性表。(先進後出表) java中的Stack繼承Vector 實例化 Stack stack=new Stack(); 基本使用 判斷是
linux中的buffer和cache的區別
做成 內存 緩沖 交換 簡單 text 操作 進程 linux系統中 ***今天我們再來簡單討論下linux系統中關於Buffer和Cache的區別,buffer與cache操作的對象就不一樣、``` 1.buffer(緩沖區) 是為了提高內存的硬盤(或其他i/o設備)
Confluence 6 中進行用戶管理的優化配置和限制的基本建議
Confluence避免跨目錄的多個用戶名:如果你連接了超過一個的目錄服務器,我們建議你需要確定你的用戶名在目錄服務器中是唯一的。例如:我們不建議你定義一個用戶同時在'Directory1' 和 'Directory2' 中都定義 jsmith 這個用戶。這樣要求的原因是避免在
Centos 7.4 中http-2.4 的基本實現和 https 的實現
http-2.4 https 1.建立httpd服務,要求: 1) 提供兩個基於名稱的虛擬主機www1, www2;要求每個虛擬主機都有單獨的錯誤日誌和訪問日誌; 2) 通過www1的/server-status提供狀態信