ARM Linux (S3C6410架构/2.6.35内核)的内存映射(五)
2013-08-05 13:50
260 查看
ARM Linux的访问权限控制
ARM1176JZF-S处理器为访问权限控制定义了两个层次:第一层是"域"(Domain)的访问类型,第二层是页或者段的"读写权限"(Access Permission)。具体来说,过程是这样的: 1. 在ARM处理器中,MMU将整个存储空间分成最多16个域,记作D0~D15,每个域对应一定的存储区域,该区域具有相同的访问控制属性。每个域的访问权限分别由CP15的C3寄存器中的两位来设定,c3寄存器的大小为32bits,刚好可以设置16个域的访问权限。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 |
值 | 访问类型 | 含义 |
---|---|---|
0b00 | 无访问权限 | 此时访问该域将产生访问失效 |
0b01 | 用户(client) | 根据CP15的C1控制寄存器中的R和S位以及页表中地址变换条目中的访问权限控制位AP来确定是否允许各种系统工作模式的存储访问 |
0b10 | 保留 | 使用该值会产生不可预知的结果 |
0b11 | 管理者(Manager) | 不考虑CP15的C1控制寄存器中的R和S位以及页表中地址变换条目中的访问权限控制位AP,在这种情况下不管系统工作在特权模式还是用户模式都不会产生访问失效 |
APX | AP[1:0] | 特权模式访问权限 | 用户模式访问权限 |
---|---|---|---|
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] 参考ARM1176JZF-S Revision: r0p7->6.5.2 Access permissions |
在谈到create_mapping之前,必须说明一下Linux是如何实现对页面的访问控制的。 Linux使用结构体mem_type来定义不同的内存映射类型(arch/arm/mm/mm.h),不同的映射类型定义了不同的访问权限:
[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 3 arch/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 |
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 register mcr p15, 0, r4, c2, c0, 0 @ load page table pointer b __turn_mmu_on ENDPROC(__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]本文出自 “第二月的博客” 博客,请务必保留此出处http://2ndmoon.blog.51cto.com/6542214/1283719
相关文章推荐
- ARM Linux (S3C6410架构/2.6.35内核)的内存映射(二)
- ARM Linux (S3C6410架构/2.6.35内核)的内存映射(三)
- ARM Linux (S3C6410架构/2.6.35内核)的内存映射(四)
- ARM big.LITTLE大小核架构在Linux和Android内核下多核调度算法
- ARM Linux (S3C6410架构…
- ARM Linux (S3C6410架构…
- ARM架构内核启动分析-head.S(1.1、vmlinux.lds 链接脚本分析)
- ARM Linux (S3C6410架构…
- ARM Linux (S3C6410架构…
- ARM Linux 内核启动总结 之 创建临时页表
- 每天一个linux命令-uname,输出操作系统信息(内核版本、硬件架构32位/64位等)
- ARM LINUX内核初始化分析
- linux-3.2.36内核启动1-启动参数(arm平台 启动参数的获取和处理,分析setup_arch)
- 【ARM-Linux开发】用VS2013+VELT-0.1.4进行海思平台 Linux内核 的开发
- CodeSourcery提供的基于GCC改造的能够兼容多种ARM架构的交叉编译工具链arm-none-linux-gnueabi:
- Arm linux 内核移植及系统初始化过程分析
- linux下用arm-none-linux-gnueabi交叉编译arm内核模块
- arm linux 内核生成过程
- 制作S3C6410 的交叉编译链(arm-linux-gcc 4.8.1)
- ARM-Linux内核移植之(二)——Linux2.6.22内核移植