Chinaunix首页 | 论坛 | 博客
  • 博客访问: 601630
  • 博文数量: 353
  • 博客积分: 1104
  • 博客等级: 少尉
  • 技术积分: 1457
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-23 23:02
个人简介

1、刚工作时做Linux 流控;后来做安全操作系统;再后来做操作系统加固;现在做TCP 加速。唉!没离开过类Unix!!!但是水平有限。。

文章存档

2015年(80)

2013年(4)

2012年(90)

2011年(177)

2010年(1)

2009年(1)

分类:

2011-12-08 13:10:46

在内核空间访问用户空间的虚拟地址
          /*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的修改可以参考上面的代码。

参考:




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