博客首页 注册 建议与交流 排行榜 加入友情链接
推荐 投诉 搜索: 帮助

gliethttp

2005年07月毕业于桂林电子工业学院普通本科生的工作笔记--我们chinese人要学的东西还有很多很多,所以兄弟们可都要加油啊...... 欢迎访问~ luther.gliethttp Regards
  gliethttp.cublog.cn

关于作者
姓名:飞镖 luther
职业:摸索中
年龄:1982
邮箱:luther.ge@163.com
位置:北京朝阳区安贞西里2区
个性介绍:

0>需要能打,但更需要能挨;
  能打如卫青,能挨如李广.
1>UNIX is basically a simple 
  operating system, but you 
  have to be a genius to 
  understand the simplicity.
2>人以铜为镜,可以正衣冠;以
  史为镜,可以知兴亡;以人为
  镜,可以明得失
3>1只笼子养着两只公鸡,打鸣那
  是一个比一个响
4>要是甘蔗两端一样甜,那谁还
  会辛辛苦苦抢着吃后边那一节
5>审问、慎思、明辨、力行、
  观其人
6>宦海浮沉,世事难测;
  朝中熙熙,多为利来;
  宫中攘攘,多为利往。
7>桃花坞里桃花庵,
  桃花庵下桃花仙; 
  桃花仙人种桃树,
  又摘桃花换酒钱。
  ......
  别人笑我太疯癫,
  我笑他人看不穿; 
  不见五陵豪杰墓,
  无花无酒锄作田。哈哈哈哈哈
8>贵有恒,何必三更起五更勤;
  最无益,只怕一日曝十日寒
9>君不密,则失臣;
  臣不密,则失身;
  几事不密,则成害!
10>汉武帝的人生4目标:
  修身、齐家、治国、平天下

|| << >> ||
我的分类


浅析armlinux-setup_arch()->create_mapping()函数5-2-2

浅析armlinux-setup_arch()->create_mapping()函数5-2-2

文章来源:http://gliethttp.cublog.cn

建议首先参考《浅析armlinux2_4_19启动程序[head-armv.s文件][http://gliethttp.cublog.cn]
//----------------------------------------
//1.arch/arm/mm/Mm-armv.c->create_mapping()
static void __init create_mapping(struct map_desc *md)
{
    unsigned long virt, length;
    int prot_sect, prot_pte;
    long off;
    if (md->prot_read && md->prot_write &&
     !md->cacheable && !md->bufferable) {
//提示设置不合理
        printk(KERN_WARNING "Security risk: creating user "
         "accessible mapping for 0x%08lx at 0x%08lx\n",
         md->physical, md->virtual);
    }
    if (md->virtual != vectors_base() && md->virtual < PAGE_OFFSET) {
//仅仅能创建0xffff0000开始的用于中断向量的虚拟地址映射页目录
//请参见《浅析arm-linux中断vector向量表的建立流程》
        printk(KERN_WARNING "MM: not creating mapping for "
         "0x%08lx at 0x%08lx in user region\n",
         md->physical, md->virtual);
    }
//页表属性值
    prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
         (md->prot_read ? L_PTE_USER : 0) |
         (md->prot_write ? L_PTE_WRITE : 0) |
         (md->cacheable ? L_PTE_CACHEABLE : 0) |
         (md->bufferable ? L_PTE_BUFFERABLE : 0);
//页目录属性值
    prot_sect = PMD_TYPE_SECT | PMD_DOMAIN(md->domain) |
         (md->prot_read ? PMD_SECT_AP_READ : 0) |
         (md->prot_write ? PMD_SECT_AP_WRITE : 0) |
         (md->cacheable ? PMD_SECT_CACHEABLE : 0) |
         (md->bufferable ? PMD_SECT_BUFFERABLE : 0);
    virt = md->virtual;
    off = md->physical - virt;
    length = md->length;
    while ((virt & 0xfffff || (virt + off) & 0xfffff) && length >= PAGE_SIZE) {
//如果虚拟地址virt或者其对应的物理地址(virt + off),只要有一个非1M页目录对齐,
//那么首先调整成1M页目录对齐
//将virt和其对应的物理地址(virt + off)建立映射,如果没有设置页目录,那么alloc_init_page
//将自动设置
        alloc_init_page(virt, virt + off, md->domain, prot_pte);
        virt += PAGE_SIZE;
        length -= PAGE_SIZE;
    }
    while (length >= PGDIR_SIZE) {
//还有至少1M的空间需要映射,那么可以使用alloc_init_section进行快速1M大小的节映射
        alloc_init_section(virt, virt + off, prot_sect);
        virt += PGDIR_SIZE;
        length -= PGDIR_SIZE;
    }
    while (length >= PAGE_SIZE) {
//经过1M节映射之后,仍然还有一些余项,那么继续完成4k页表映射[gliethttp]
        alloc_init_page(virt, virt + off, md->domain, prot_pte);
        virt += PAGE_SIZE;
        length -= PAGE_SIZE;
    }
}
//----------------------------------------
//2.rch/arm/mm/Mm-armv.c->alloc_init_page
static inline void
alloc_init_page(unsigned long virt, unsigned long phys, int domain, int prot)
{
    pmd_t *pmdp;
    pte_t *ptep;
//获取中间级目录入口,对于2级小页映射,pmdp就等于一级页目录入口,即:pmdp = &swapper_pg_dir[i]
    pmdp = pmd_offset(pgd_offset_k(virt), virt);
//对于虚拟映射的原理问题,请参考《linux2.4.19下__ioremap函数中remap_area_pages虚拟地址映射建立函数的代码分析》
    if (pmd_none(*pmdp)) {
//如果1级页目录dir,是空的,那么创建之
//其中PTRS_PER_PTE=256项二级页表项
//所以首先申请2*256*4=2k空间,之所以要多申请出1K空间,是因为需要存储相应页表项对应的kernel信息
//详细说明见下面的分析.[gliethttp]
        pte_t *ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * sizeof(pte_t));
        ptep += PTRS_PER_PTE;//ptep指向页表项存储区的末端
//将swapper_pg_dir[i]=__mk_pmd(ptep, PMD_TYPE_TABLE | PMD_DOMAIN(domain)),
//一级页目录项,装入数值__mk_pmd(ptep, PMD_TYPE_TABLE| PMD_DOMAIN(domain))
        set_pmd(pmdp, __mk_pmd(ptep, PMD_TYPE_TABLE | PMD_DOMAIN(domain)));
    }
    ptep = pte_offset(pmdp, virt);//找到virt虚拟地址对应的pte页表项入口
    //ptep指向第256+(pte_t*)ptr项,即:1k~2k空间
    set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, __pgprot(prot)));
}
static inline pmd_t __mk_pmd(pte_t *ptep, unsigned long prot)
{
    unsigned long pte_ptr = (unsigned long)ptep;
    pmd_t pmd;
    pte_ptr -= PTRS_PER_PTE * sizeof(void *);//之前的pte_ptr指向的是页表项存储区的末端
    pmd_val(pmd) = __virt_to_phys(pte_ptr) | prot;
    return pmd;
}
//include/asm-arm/Pgtable.h有如下定义
#define pte_offset(dir, addr) ((pte_t *)pmd_page(*(dir)) + __pte_offset(addr))
#define __pte_offset(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
#define pfn_pte(pfn,prot) (__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)))
//include/asm-arm/proc-armv/Pgtable.h有如下定义
static inline unsigned long pmd_page(pmd_t pmd)
{
    unsigned long ptr;
    ptr = pmd_val(pmd) & ~(PTRS_PER_PTE * sizeof(void *) - 1);
    ptr += PTRS_PER_PTE * sizeof(void *);//指向第256+(pte_t*)ptr项,即:1k~2k空间[gliethttp]
    return __phys_to_virt(ptr);
}
//include/asm-arm/proc-armv/Pgtable.h有如下定义
#define set_pte(pmdp,pmd) cpu_set_pte(ptep,pte)
//include/asm-arm/cpu-single.h中有如下定义
#define cpu_set_pte cpu_fn(CPU_NAME,_set_pte)
翻译之后
#define cpu_set_pte cpu_arm920_set_pte
相应的
#define cpu_set_pgd cpu_arm920_set_pgd
#define cpu_set_pmd cpu_arm920_set_pmd
#define cpu_set_pte cpu_arm920_set_pte
以上三个函数位于arch/arm/mm/proc-arm920.S
    .align    5
ENTRY(cpu_arm920_set_pte)
    str    r1, [r0], #-1024//2*1k空间,0~1k被使用,且r0处于1k~2k之间,那么r0=r0-1k,就位于0~1k空间
    eor    r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY//异或
    bic    r2, r1, #0xff0
    bic    r2, r2, #3
    orr    r2, r2, #HPTE_TYPE_SMALL
    tst    r1, #LPTE_USER | LPTE_EXEC @ User or Exec?
    orrne  r2, r2, #HPTE_AP_READ
    tst    r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty?
    orreq  r2, r2, #HPTE_AP_WRITE
    tst    r1, #LPTE_PRESENT | LPTE_YOUNG @ Present and Young?
    movne  r2, #0
    str    r2, [r0]//对该pte在0~1k相应的页表项赋值,我想0~1k空间是有kernel使用,和硬件mmu无关
    mov    r0, r0
    mcr    p15, 0, r0, c7, c10, 1         @ clean D entry
    mcr    p15, 0, r0, c7, c10, 4         @ drain WB
    mov    pc, lr
//所以可以看出《linux2.4.19下__ioremap函数中remap_area_pages虚拟地址映射建立函数的代码分析》中的pte是
//一个示意图,并不是实际的物理图,实际的物理图应该如下:
       |->pte-256->存储pte+000对应的kernel信息
       |->pte-255->存储pte+001对应的kernel信息
       ...
       |->pte-002->存储pte+254对应的kernel信息
       |->pte-001->存储pte+255对应的kernel信息
dir+0000->pte+000->4k
       |->pte+001->4k
       |->pte+002->4k
        ...
       |->pte+253->4k
       |->pte+254->4k
       |->pte+255->4k


       |->pte-256->存储pte+000对应的kernel信息
       |->pte-255->存储pte+001对应的kernel信息
       ...
       |->pte-002->存储pte+254对应的kernel信息
       |->pte-001->存储pte+255对应的kernel信息
dir+0001->pte+000->4k
       |->pte+001->4k
       |->pte+002->4k
        ...
       |->pte+253->4k
       |->pte+254->4k
       |->pte+255->4k

       ...


       |->pte-256->存储pte+000对应的kernel信息
       |->pte-255->存储pte+001对应的kernel信息
       ...
       |->pte-002->存储pte+254对应的kernel信息
       |->pte-001->存储pte+255对应的kernel信息
dir+4094->pte+000->4k
       |->pte+001->4k
       |->pte+002->4k
        ...
       |->pte+253->4k
       |->pte+254->4k
       |->pte+255->4k

       |->pte-256->存储pte+000对应的kernel信息
       |->pte-255->存储pte+001对应的kernel信息
       ...
       |->pte-002->存储pte+254对应的kernel信息
       |->pte-001->存储pte+255对应的kernel信息
dir+4095->pte+000->4k
       |->pte+001->4k
       |->pte+002->4k
        ...
       |->pte+253->4k
       |->pte+254->4k
       |->pte+255->4k

发表于: 2007-08-04,修改于: 2007-08-04 18:26,已浏览1338次,有评论0条 推荐 投诉


网友评论
 发表评论