Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5699925
  • 博文数量: 675
  • 博客积分: 20301
  • 博客等级: 上将
  • 技术积分: 7671
  • 用 户 组: 普通用户
  • 注册时间: 2005-12-31 16:15
文章分类

全部博文(675)

文章存档

2012年(1)

2011年(20)

2010年(14)

2009年(63)

2008年(118)

2007年(141)

2006年(318)

分类: LINUX

2008-08-07 23:30:27

在内核空间访问用户空间的虚拟地址
          /*get phyaddr*/
        pgd = pgd_offset(current->mm, vaddr);
        if ( pgd_none(*pgd) || pgd_bad(*pgd) )
        {
                __DEBUG_MSG("invalid pgd\n");
                retval = -1;
                goto error;
        }

        pud = pud_offset(pgd, vaddr);
        if ( pud_none(*pud) || pud_bad(*pud) )
        {
                __DEBUG_MSG("invalid pud\n");
                retv        /*get phyaddr*/
        pgd = pgd_offset(current->mm, vaddr);
        if ( pgd_none(*pgd) || pgd_bad(*pgd) )
        {
                __DEBUG_MSG("invalid pgd\n");
                retval = -1;
                goto error;
        }

        pud = pud_offset(pgd, vaddr);
        if ( pud_none(*pud) || pud_bad(*pud) )
        {
                __DEBUG_MSG("invalid pud\n");
                retval = -1;
                goto error;
        }

        pmd = pmd_offset(pud, vaddr);
        if ( pmd_none(*pmd) || pmd_bad(*pmd) )
        {
                __DEBUG_MSG("invalid pmd\n");
                retval = -1;
                goto error;
        }
        __DEBUG_MSG("before pte_offset_map\n");
        pte = pte_offset_map(pmd, vaddr);
        __DEBUG_MSG("after pte_offset_map\n");
        if ( pte_none(*pte) )
        {
                __DEBUG_MSG("bad pte va: %X pte: %p pteval: %lX\n", vaddr, pte, pte_val(*pte));
                retval = -1;
                goto error;
        }


        mypage = pte_page(*pte);
        phy = (pte_val(*pte)) & PAGE_MASK + (vaddr&(PAGE_SIZE-1));

  laddr1 = __va(phy);
    __DEBUG_MSG("the vir addr1 is %lx\n", laddr1);
    laddr2 = kmap_atomic(mypage, KM_USER0) + ( phy&(PAGE_SIZE-1) );
    __DEBUG_MSG("the vir addr2 is %lx\n", laddr2);

       laddr3 = ioremap(phy,24);
       __DEBUG_MSG("the vir addr3 is %lx\n", laddr3);

       strcpy((char *)(laddr3), "hello test");
       kunmap_atomic(laddr2, KM_USER1);
       iounmap(laddr3);
       laddr3 = ioremap(phy,24);
       __DEBUG_MSG("the vir addr3 is %lx\n", laddr3);

       strcpy((char *)(laddr3), "hello test");
       kunmap_atomic(laddr2, KM_USER1);
       iounmap(laddr3);


访问物理内存,一定需要有内存的映射,返回的虚拟地址一定在3G~4G之间。

当物理内存很大的时候,那么直接通过__va就不行了,#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
__va仅仅是加上3G的偏移,如果物理内存地址是2G,那么就会超过4G,得到的虚拟地址不在3G~4G之间。

解决方法:
用kmap_atomic来得到 kernel address, I386上对892M以上的内存直接用va是不对的,因为没有Identity mapping 对应。映射一个随便的用户虚拟地址,可以通过在kmap_atomic之后再加上页内offset。

代码:
大部分可以参考
关于kmap_atomic的修改可以参考上面的代码。

参考:




阅读(1281) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~