Chinaunix首页 | 论坛 | 博客
  • 博客访问: 72533
  • 博文数量: 11
  • 博客积分: 395
  • 博客等级: 一等列兵
  • 技术积分: 181
  • 用 户 组: 普通用户
  • 注册时间: 2009-05-12 18:29
文章分类

全部博文(11)

文章存档

2011年(7)

2010年(2)

2009年(2)

我的朋友

分类: LINUX

2011-08-08 16:30:34

感觉什么都懂,但什么都不会! 开始看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) |
给主人留下些什么吧!~~