Arm-linux内存管理(2)
来源:互联网 发布:数据恢复大师手机版 编辑:程序博客网 时间:2024/06/05 16:23
毛德操《嵌入式系统》读书笔记。
1、在ARM-Linux内核的代码中,页面大小采用4KB,区段大小为1MB,并且使页面目录PGDIR对应于ARM的首层映射表,而中间目录PMD则设置成与PGDIR等同,这样就把概念上的三层映射合并成了物理上的二层映射。
#define PAGE_SHIFT 12
#define PAGE_SIZE (1UL << PAGE_SHIFT)
#define PMD_SHIFT 20
#define PGDIR_SHIFT 20
#define PMD_SIZE (1UL <<PMD_SHIFT)
#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
这就以为着,页面的大小为4KB;而一个PGDIR和一个PMD所覆盖的区间为1MB。
2、ARM-Linux内核怎样建立起具体页面映射
内核中有个函数create_mapping(),其作用就是为一个给定的区间建立页面映射。调用这个函数前要先准备好一个map_desc数据结构,其源码如下:
struct map_desc {
unsigned long virtual;虚拟地址起点
unsigned long pfn;物理地址起点
unsigned long length;长度
unsigned int type;说明这个区间所属的域,以及是否可读、写、可高速缓存等属性
};
ARM-linux的MMU允许使用16个不同的域,但内核只使用了3个:
* DOMAIN_IO - domain 2 includes all IO only
* DOMAIN_USER - domain 1 includes all user memory only
* DOMAIN_KERNEL - domain 0 includes all kernel memory only
#define DOMAIN_KERNEL0
#define DOMAIN_TABLE 0
#define DOMAIN_USER 1
#define DOMAIN_IO 2
注:这里的值如DOMAIN_USER都只是编号,说明这个域的访问控制位段在域访问控制寄存器中的位置,就好像下标,而控制着具体域的访问方式的是位段的值。每个域访问控制位段包含两位,所以有4种:
3、这样,一个map_desc数据结构就完整描述了一个内存区间,或者说板块的映射,调用create_mapping()就以此结构指针为调用参数。
/*
* Create the page directory entries and any necessary
* page tables for the mapping specified by `md'. We
* are able to cope here with varying sizes and address
* offsets, and we take full advantage of sections and
* supersections.
*/
void __init create_mapping(struct map_desc *md)
{
unsigned long phys, addr, length, end;
const struct mem_type *type;
pgd_t *pgd;
if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
printk(KERN_WARNING "BUG: not creating mapping for "
"0x%08llx at 0x%08lx in user region\n",
__pfn_to_phys((u64)md->pfn), md->virtual);
return;
}
if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
md->virtual >= PAGE_OFFSET && md->virtual < VMALLOC_END) {
printk(KERN_WARNING "BUG: mapping for 0x%08llx at 0x%08lx "
"overlaps vmalloc space\n",
__pfn_to_phys((u64)md->pfn), md->virtual);
}
type = &mem_types[md->type];得到映射类型和属性
/*
* Catch 36-bit addresses
*/
if (md->pfn >= 0x100000) {
create_36bit_mapping(md, type);
return;
}
addr = md->virtual & PAGE_MASK;
phys = (unsigned long)__pfn_to_phys(md->pfn);
length = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
if (type->prot_l1 == 0 && ((addr | phys | length) & ~SECTION_MASK)) {
printk(KERN_WARNING "BUG: map for 0x%08lx at 0x%08lx can not "
"be mapped using pages, ignoring.\n",
__pfn_to_phys(md->pfn), addr);
return;
}
pgd = pgd_offset_k(addr);
end = addr + length;
do {
unsigned long next = pgd_addr_end(addr, end);
alloc_init_section(pgd, addr, next, phys, type);以1MB逐段为单位建立单层映射。
phys += next - addr;
addr = next;
} while (pgd++, addr != end);
}
4、对于1MB的区段,这里采用的是一层映射。为什采用一层映射?
答:我们的目的是在1MB的虚拟地址与物理地址建立起映射,这个目的已经达到。我们并不采用内容的换入/换出,所以没有必要把这1MB空间分成页面。需要映射的时候,MMU以虚拟地址高12位为下标,从首层映射表中找到相应的表项。由于最低2位为10,MMU知道这是一层映射,所以表项的最高12位就是物理段地址,在后面拼接上虚拟地址的低20位,就得到32位的物理地址。
5、对于二层映射表,采用两套互相平行的页面映射表,一套是“逻辑的”,即Linux内核所要求的页面映射表。另一套是“物理的”即ARM MMU所要求的,而通过软件维持二者在逻辑上的一致。
- Arm-linux内存管理(2)
- ARM-linux内存管理
- ARM-linux内存管理
- arm-linux内存管理
- linux(arm架构)内存管理学习(2)
- Arm-linux内存管理(3)
- Arm-linux内存管理(4)
- Linux内核及ARM的内存管理(续)
- Linux内核及ARM的内存管理(再续)
- Linux内核及ARM的内存管理(再三续)
- Linux内核及ARM的内存管理(不厌其烦续)
- Linux内核及ARM的内存管理(前续)
- arm-linux内存管理学习笔记(3)-页表前戏
- arm-linux内存管理学习笔记(2)-内核临时页表的建立
- Linux内核及ARM的内存管理
- Linux内核及ARM的内存管理 .
- linux(arm架构)内存管理学习(1)
- arm-linux内存管理学习笔记(1)-内存页表的硬件原理
- 使用Python的OpenSSL库来进行RSA加密
- 全新S2SH配置一步一步过程详解
- 多重幂计数问题
- Using encodeURIComponent to avoid errors caused by special chars
- 坚持并专注于自己的梦想
- Arm-linux内存管理(2)
- 查看文件系统类型
- flash特效原理:链式模型的使用(2)
- 数组元素的访问方法
- 为ubuntu创建开机启动脚本
- linux内核结构图
- ODBC数据表绑定更新(改变与m_pSet关联的表)
- VC++6.0 调试指南(Happy Debugging)
- Struts2的学习笔记(4)