在内核空间访问用户空间的虚拟地址 /*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) |