ARM Linux (S3C6410架構(gòu)/2.6.35內(nèi)核)的內(nèi)存映射(五)
ARM Linux的訪問權(quán)限控制
ARM1176JZF-S處理器為訪問權(quán)限控制定義了兩個層次:第一層是"域"(Domain)的訪問類型,第二層是頁或者段的"讀寫權(quán)限"(Access Permission)。具體來說,過程是這樣的:
本文引用地址:http://m.butianyuan.cn/article/201611/317856.htm1.
Bits | 31, 30 | 29, 28 | 27, 26 | 25, 24 | 23, 22 | 21, 20 | 19, 18 | 17, 16 | 15, 14 | 13, 12 | 11, 10 | 9, 8 | 7, 6 | 5, 4 | 3, 2 | 1, 0 |
Domain | D15 | D14 | D13 | D12 | D11 | D10 | D9 | D8 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
對于每一個域所對應(yīng)的兩個bit,訪問類型設(shè)置方法如下:
值 | 訪問類型 | 含義 |
---|---|---|
0b00 | 無訪問權(quán)限 | 此時訪問該域?qū)a(chǎn)生訪問失效 |
0b01 | 用戶(client) | 根據(jù)CP15的C1控制寄存器中的R和S位以及頁表中地址變換條目中的訪問權(quán)限控制位AP來確定是否允許各種系統(tǒng)工作模式的存儲訪問 |
0b10 | 保留 | 使用該值會產(chǎn)生不可預(yù)知的結(jié)果 |
0b11 | 管理者(Manager) | 不考慮CP15的C1控制寄存器中的R和S位以及頁表中地址變換條目中的訪問權(quán)限控制位AP,在這種情況下不管系統(tǒng)工作在特權(quán)模式還是用戶模式都不會產(chǎn)生訪問失效 |
APX | AP[1:0] | 特權(quán)模式訪問權(quán)限 | 用戶模式訪問權(quán)限 |
---|---|---|---|
0 | b00 | 禁止訪問;S=1,R=0或S=0,R=1時只讀 | 禁止訪問;S=1,R=0時只讀 |
0 | b01 | 讀寫 | 禁止訪問 |
0 | b10 | 讀寫 | 只讀 |
0 | b11 | 讀寫 | 讀寫 |
1 | b00 | 保留 | 保留 |
1 | b01 | 只讀 | 禁止訪問 |
1 | b10 | 只讀 | 只讀 |
1 | b11 | 只讀 | 只讀 |
[8] |
[c]struct mem_type {unsigned int prot_pte;unsigned int prot_l1;unsigned int prot_sect;unsigned int domain;};[/c]
其中處成員含義如下:
prot_pte代表頁表項的訪問控制權(quán),pte即第二級映射表項(頁表項)。
prot_l1代表段表項的訪問控制位,l1即第一級映射表項(段表項/主頁表項)。
prot_sect代表主頁表(注意,不是主頁表項)的訪問控制位和內(nèi)存域。
domain代表所屬的內(nèi)存域。
對于ARM處理器,Linux定義了一個類型為struct mem_type的局部靜態(tài)數(shù)組(arch/arm/mm/mmu.c)。根據(jù)不同的映射類型,定義了不同的訪問權(quán)限。
[c]static struct mem_type mem_types[] = {[MT_DEVICE] = { .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED |L_PTE_SHARED,.prot_l1 = PMD_TYPE_TABLE,.prot_sect = PROT_SECT_DEVICE | PMD_SECT_S,.domain = DOMAIN_IO,},[MT_DEVICE_NONSHARED] = { .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_NONSHARED,.prot_l1 = PMD_TYPE_TABLE,.prot_sect = PROT_SECT_DEVICE,.domain = DOMAIN_IO,},[MT_DEVICE_CACHED] = { .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_CACHED,.prot_l1 = PMD_TYPE_TABLE,.prot_sect = PROT_SECT_DEVICE | PMD_SECT_WB,.domain = DOMAIN_IO,},[MT_DEVICE_WC] = { .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_WC,.prot_l1 = PMD_TYPE_TABLE,.prot_sect = PROT_SECT_DEVICE,.domain = DOMAIN_IO,},[MT_UNCACHED] = {.prot_pte = PROT_PTE_DEVICE,.prot_l1 = PMD_TYPE_TABLE,.prot_sect = PMD_TYPE_SECT | PMD_SECT_XN,.domain = DOMAIN_IO,},[MT_CACHECLEAN] = {.prot_sect = PMD_TYPE_SECT | PMD_SECT_XN,.domain = DOMAIN_KERNEL,},[MT_MINICLEAN] = {.prot_sect = PMD_TYPE_SECT | PMD_SECT_XN | PMD_SECT_MINICACHE,.domain = DOMAIN_KERNEL,},[MT_LOW_VECTORS] = {.prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |L_PTE_EXEC,.prot_l1 = PMD_TYPE_TABLE,.domain = DOMAIN_USER,},[MT_HIGH_VECTORS] = {.prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |L_PTE_USER | L_PTE_EXEC,.prot_l1 = PMD_TYPE_TABLE,.domain = DOMAIN_USER,},[MT_MEMORY] = {.prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,.domain = DOMAIN_KERNEL,},[MT_ROM] = {.prot_sect = PMD_TYPE_SECT,.domain = DOMAIN_KERNEL,},[MT_MEMORY_NONCACHED] = {.prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,.domain = DOMAIN_KERNEL,},};[/c]
系統(tǒng)中定義了多個映射類型,最常用的是MT_MEMORY,它對應(yīng)RAM;MT_DEVICE則對應(yīng)了其他I/O設(shè)備,應(yīng)用于ioremap;MT_ROM對應(yīng)于ROM;MT_LOW_VECTORS對應(yīng)0地址開始的向量;MT_HIGH_VECTORS對應(yīng)高地址開始的向量,它有vector_base宏決定。
[c]arch/arm/include/asm/io.h#define MT_DEVICE 0#define MT_DEVICE_NONSHARED 1#define MT_DEVICE_CACHED 2#define MT_DEVICE_WC 3arch/arm/include/asm/mach/map.h#define MT_UNCACHED 4#define MT_CACHECLEAN 5#define MT_MINICLEAN 6#define MT_LOW_VECTORS 7#define MT_HIGH_VECTORS 8#define MT_MEMORY 9#define MT_ROM 10[/c]
盡管ARM定義了16種不同的域,但是Linux只使用其中的三種:D0 ~ D2 (arch/arm/include/asm/domain.h)
[c]#define DOMAIN_KERNEL 0#define DOMAIN_TABLE 0#define DOMAIN_USER 1#define DOMAIN_IO 2[/c]
內(nèi)存空間和三種域的對應(yīng)關(guān)系如下:
內(nèi)存空間 | 域 |
---|---|
設(shè)備空間 | DOMAIN_IO |
內(nèi)部高速SRAM空間/內(nèi)部MINI Cache空間 | DOMAIN_KERNEL |
RAM內(nèi)存空間/ROM內(nèi)存空間 | DOMAIN_KERNEL |
高低端中斷向量空間 | DOMAIN_USER |
ARM處理器為每一個域定義了四種不兩只的訪問類型(0b00 ~ 0x11),Linux使用其中的三種(0b10不用),宏定義如下:
arch/arm/include/asm/domain.h
[c]#define DOMAIN_NOACCESS 0#define DOMAIN_CLIENT 1#define DOMAIN_MANAGER 3[/c]
Linux在系統(tǒng)引導(dǎo)設(shè)置MMU時初始化c3寄存器來實現(xiàn)對內(nèi)存域的訪問控制。其中對DOMAIN_USER,DOMAIN_KERNEL和DOMAIN_TABLE均設(shè)置DOMAIN_MANAGER權(quán)限;對DOMAIN_IO設(shè)置DOMAIN_CLIENT權(quán)限。
arch/arm/include/asm/domain.h
[c]#define domain_val(dom,type) ((type) << (2*(dom)))arch/arm/kernel/head.S......mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | domain_val(DOMAIN_IO, DOMAIN_CLIENT))mcr p15, 0, r5, c3, c0, 0 @ load domain access registermcr p15, 0, r4, c2, c0, 0 @ load page table pointerb __turn_mmu_onENDPROC(__enable_mmu)[/c]
在系統(tǒng)的引導(dǎo)過程中對這3個域的訪問控制位并不是一成不變的,它提供了一個名為modify_domain的宏來修改域訪問控制位。系統(tǒng)在setup_arch中調(diào)用early_trap_init后,DOMAIN_USER的權(quán)限位將被設(shè)置成DOMAIN_CLIENT。
arch/arm/include/asm/domain.h
[c]#define set_domain(x) do { __asm__ __volatile__( "mcr p15, 0, %0, c3, c0 @ set domain" : : "r" (x)); isb(); } while (0)#define modify_domain(dom,type) do { struct thread_info *thread = current_thread_info(); unsigned int domain = thread->cpu_domain; domain &= ~domain_val(dom, DOMAIN_MANAGER); thread->cpu_domain = domain | domain_val(dom, type); set_domain(thread->cpu_domain); } while (0)[/c]
評論