内核里虚拟地址转物理地址的方法
static u32 mxc_ipu_uservirt_to_phys(u32 virtp)
{unsigned long physp = 0;
struct vm_area_struct *vma;
struct mm_struct *mm = current->mm;
int i;
/* For kernel direct-mapped memory, take the easy way */
if (virtp >= PAGE_OFFSET)
return virt_to_phys((void *) virtp);
down_read(¤t->mm->mmap_sem);
vma = find_vma(mm, virtp);
// printk("-----nn =%d, %d, %d", vma, (vma->vm_flags & VM_IO), vma->vm_pgoff);
if (vma && (vma->vm_flags & VM_IO) && vma->vm_pgoff) {
/* this will catch, kernel-allocated, mmaped-to-usermode
addresses */
physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start);
up_read(¤t->mm->mmap_sem);
} else {
/* otherwise, use get_user_pages() for general userland pages */
int res, nr_pages = 1;
struct page *pages;
res = get_user_pages(current, current->mm, virtp, nr_pages, 0,
0, &pages, NULL);
up_read(¤t->mm->mmap_sem);
if (res == nr_pages) {
physp = __pa(page_address(&pages[0]) +
(virtp & ~PAGE_MASK));
} else {
// Maybe gpu allocal page
struct page * pageabc = 0;
if (vma && (vma->vm_flags & VM_PFNMAP)) {
pte_t * pte;
spinlock_t * ptl;
u32 logical = virtp;
for (i = 0; i < 1; i++) {
pgd_t * pgd = pgd_offset(current->mm, logical);
pud_t * pud = pud_offset(pgd, logical);
if (pud) {
pmd_t * pmd = pmd_offset(pud, logical);
pte = pte_offset_map_lock(current->mm, pmd, logical, &ptl);
if (!pte) {
//gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
}
} else {
//gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
}
pageabc = pte_page(*pte);
pte_unmap_unlock(pte, ptl);
/* Advance to next. */
logical += PAGE_SIZE;
}
}
physp = __pa(page_address(pageabc) +
(virtp & ~PAGE_MASK));
if(physp){
return physp;
}
else{
printk("get_user_pages failed %X %d\n", physp, nr_pages );
return 0;
}
}
}
return physp;
}