分类: LINUX
2019-05-30 23:55:06
基于kernel 4.0分析create_mapping()函数,此函数用于创建内存页表,函数定义如下:
不考虑LPAE情况,代码忽略。
1.首先判断虚拟地址在用户区域,并且不是中断向量表(中断向量表可以在虚拟地址0开始的地方)。
2.然后判断内存类型为IO和ROM类型的不允许映射在低端内存或高于VMALLOC_END区域,个人理解应该只能映射在vmalloc区域。
分析映射代码:
typedef unsigned long pte_t;
typedef unsigned long pmd_t;
typedef unsigned long pgd_t[2];
typedef unsigned long pgprot_t;
pgd_t pgd;
pgd = pgd_offset_k(addr); addr 是虚拟地址
找到addr这个虚拟地址在内核页表中的位置,PGDIR_SHIFT等于21(使一级页表项8字节对齐),内核进程pgd的起始地址在0xC0004000,所以(init_mm)->pgd + ((addr) >> 21) = (pgd_t )0xc0004000 + (addr >> 21)。如果addr值为0xC0000000,它右移21位值为0x600,但是(pgd_t )0xc0004000 + 0x600 = 0xc0007000,是因为前面有强制类型转换(pgd_t ),而这个结构的定义是两个ulong,所以(pgd_t )0xc0004000 + 0x600 =(pgd_t )0xc0004000 + 0x600*8 = 0xc0007000。
仿真结果如下图:vexpress_defconfig板子
end = addr + length; end指的是要映射的虚拟地址的结尾,它的值为0xc0000000 + 0x1100000(17M) = 0xC1100000;
要映射的虚拟地址起始位置0xC0000000,结束地址0xC1100000,一共17M,映射的物理地址是0x60000000。
此时的pgd=0xc0007000,end=0xc1100000,addr=0xc0000000。
第一次循环:next = 0xc0200000
unsigned long next = pgd_addr_end(addr, end); 获取addr后下一个2M的虚拟起始地址,保证不超过end,如果超过end,则返end。
这个宏定义同时还保证了2M对齐。
phys += next - addr; 物理地址增加到已映射结束的位置
addr = next; 虚拟地址增加到已映射结束的位置
这个循环周而复始直到映射完。
pgd=0xc0007000,addr=0xc0000000,end=0xc0200000,phys=0x60000000
pud 和pgd是同样的类型,pud=0xc0007000,
进入循环:
next = pud_addr_end(addr, end);获取addr后下一个2M的虚拟起始地址,不过end就是addr后的2M位置,所以next=0xc0200000。
pud和pgd一样都是2M循环。
这里有对一级页表的初始化__map_init_section(pmd, addr, next, phys, type);
也有对二级页表的初始化alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys), type);
pud=0xc0007000,addr=0xc0000000,end=0xc0200000,phys=0x60000000
pmd_t *pmd = pmd_offset(pud, addr);转化成long型指针
pmd = 0xc0007000
next = pmd_addr_end(addr, end);
next = 0xc0200000
如果符合段映射则进入__map_init_section(pmd, addr, next, phys, type);
pmd = 0xc0007000,addr=0xc0000000,next = 0xc0200000,phys=0x60000000
do 循环里运行了2次,每次addr加1M,2次后addr==end。
一级页表里的内容是*pmd = __pmd(phys | type->prot_sect); 0x6021140e
pte指向一页的起始地址
arch/arm/mm/proc-v7-2level.S
r0:页表项地址
r1:页表属性|物理地址偏移(Linux 模拟的表项)
将页表属性r1配置给页表项r0
写入HW页表内容,HW页表位于软件页表+2048字节处
arch/arm/include/asmpgtable-2level.h
这张图说明了2级页表的布局