感觉什么都懂,但什么都不会! 开始看linux源码, 希望自己能坚持下去!
强攻mmu和进程管理!
有用的网站
//include/asm-generic/memory_model.h
#define PHYS_PFN_OFFSET (PHYS_OFFSET >> PAGE_SHIFT)
#define ARCH_PFN_OFFSET PHYS_PFN_OFFSET
#define pfn_to_page __pfn_to_page
#define __pfn_to_page(pfn) (mem_map + ((pfn) - ARCH_PFN_OFFSET)) //根据页号转换为表述它的page的指针 mem_map是page* (前进多少个page*呢?当前页号相对于第一页的offset) 显然pfn是phy的而不是vir的,pfn比较好计算 pte(val)>>PAGE_SHIFT 而PAGE_SHIFT是12, 一页是4k
找这个宏费了不少时间,鄙视自己,接下来该描述arm页表和linux页表了,网上很少有人介绍这一部分!
先来个内核里的图
* This leads to the page tables having the following layout:
*
* pgd pte
* | |
* +--------+ +0
* | |-----> +------------+ +0
* +- - - - + +4 | h/w pt 0 |
* | |-----> +------------+ +1024
* +--------+ +8 | h/w pt 1 |
* | | +------------+ +2048
* +- - - - + | Linux pt 0 |
* | | +------------+ +3072
* +--------+ | Linux pt 1 |
* | | +------------+ +4096
typedef unsigned long pte_t;
typedef unsigned long pmd_t;
typedef unsigned long pgd_t[2];
typedef unsigned long pgprot_t;
#define pte_val(x) (x)
#define pmd_val(x) (x)
#define pgd_val(x) ((x)[0])
#define pgprot_val(x) (x)
#define __pte(x) (x)
#define __pmd(x) (x)
#define __pgprot(x) (x)
arm是两级页表pgd pte, linux是三级的pgd pmd pte, arm把pgd和pmd搞成一级了
arm是2048-512-4096
vir--->phy
根据cp15协处理器的c2找到pgd的基地址,利用虚拟地址的高11位找到pgd的入口 //pgd_offset
把*pgd加上虚拟地址次9位,找到pte的入口//pte_offset_map不过这个宏不太好理解,
把*pte加上虚拟地址最后的12位 就得到存有物理地址的这个地址了
/* Find an entry in the second-level page table.. */
#define pmd_offset(dir, addr) ((pmd_t *)(dir)) //这个宏就能看出是两极页表
举个例子
if (!mm)
mm = &init_mm; //mm是mm_struct, 是进程task_struct里的虚拟内存空间表述符,init_mm是内核进程idle的,就是进程号为0的那个!
printk(KERN_ALERT "pgd = %p\n", mm->pgd);
pgd = pgd_offset(mm, addr); //mm->pgd是swap_pg_dir 汇编里定义的 一般就是0xc0004000
printk(KERN_ALERT "[%08lx] *pgd=%08lx", addr, pgd_val(*pgd));
do {
pmd_t *pmd;
pte_t *pte;
if (pgd_none(*pgd))
break;
if (pgd_bad(*pgd)) {
printk("(bad)");
break;
}
pmd = pmd_offset(pgd, addr); //pmd_offset只是把pgd强制转换为了pmd而已
if (PTRS_PER_PMD != 1)
printk(", *pmd=%08lx", pmd_val(*pmd));
if (pmd_none(*pmd))
break;
if (pmd_bad(*pmd)) {
printk("(bad)");
break;
}
/* We must not map this if we have highmem enabled */
if (PageHighMem(pfn_to_page(pmd_val(*pmd) >> PAGE_SHIFT)))
break;
pte = pte_offset_map(pmd, addr);//这个结合上面的图应该可以理解,*pte+512*sizeof(void*)就找到pte的入口了 注意看图
printk(", *pte=%08lx", pte_val(*pte));
printk(", *ppte=%08lx", pte_val(pte[-PTRS_PER_PTE]));
pte_unmap(pte);
} while(0);
h/w pt 这个还有待研究
阅读(5059) | 评论(0) | 转发(0) |