ARM Linux的拜访权限操控
ARM1176JZF-S处理器为拜访权限操控界说了两个层次:榜首层是”域”(Domain)的拜访类型,第二层是页或许段的”读写权限”(Access Permission)。具体来说,进程是这样的:
1.
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 |
关于每一个域所对应的两个bit,拜访类型设置办法如下:
值 | 拜访类型 | 意义 |
---|---|---|
0b00 | 无拜访权限 | 此刻拜访该域将发生拜访失效 |
0b01 | 用户(client) | 依据CP15的C1操控寄存器中的R和S位以及页表中地址改换条目中的拜访权限操控位AP来确认是否答应各种体系作业形式的存储拜访 |
0b10 | 保存 | 运用该值会发生不行预知的成果 |
0b11 | 管理者(Manager) | 不考虑CP15的C1操控寄存器中的R和S位以及页表中地址改换条目中的拜访权限操控位AP,在这种情况下不论体系作业在特权形式仍是用户形式都不会发生拜访失效 |
[c]struct mem_type {unsigned int prot_pte;unsigned int prot_l1;unsigned int prot_sect;unsigned int domain;};[/c]
其间处成员意义如下:
prot_pte代表页表项的拜访操控权,pte即第二级映射表项(页表项)。
prot_l1代表段表项的拜访操控位,l1即榜首级映射表项(段表项/主页表项)。
prot_sect代表主页表(留意,不是主页表项)的拜访操控位和内存域。
domain代表所属的内存域。
关于ARM处理器,Linux界说了一个类型为struct mem_type的部分静态数组(arch/arm/mm/mmu.c)。依据不同的映射类型,界说了不同的拜访权限。
[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]
体系中界说了多个映射类型,最常用的是MT_MEMORY,它对应RAM;MT_DEVICE则对应了其他I/O设备,应用于ioremap;MT_ROM对应于ROM;MT_LOW_VECTORS对应0地址开端的向量;MT_HIGH_VECTORS对应高地址开端的向量,它有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]
内存空间和三种域的对应联系如下:
内存空间 | 域 |
---|---|
设备空间 | DOMAIN_IO |
内部高速SRAM空间/内部MINI Cache空间 | DOMAIN_KERNEL |
RAM内存空间/ROM内存空间 | 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在体系引导设置MMU时初始化c3寄存器来完成对内存域的拜访操控。其间对DOMAIN_USER,DOMAIN_KERNEL和DOMAIN_TABLE均设置DOMAIN_MANAGER权限;对DOMAIN_IO设置DOMAIN_CLIENT权限。
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]
在体系的引导进程中对这3个域的拜访操控位并不是原封不动的,它供给了一个名为modify_domain的宏来修正域拜访操控位。体系在setup_arch中调用early_trap_init后,DOMAIN_USER的权限位将被设置成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]