有没有办法知道附加共享内存的物理地址?

时间:2017-07-05 08:01:58

标签: linux arm kernel tlb

我想知道"身体" Linux内核上新连接的共享内存的地址。

据我所知,do_shmat()返回"虚拟"共享内存的地址。 所以我尝试使用TLB转换do_shamt()的返回值,方法是修改内核中的shmat,如下所示。

SYSCALL_DEFINE3(shmat, int, shmid, char __user *, shmaddr, int, shmflg)

{
    unsigned long ret; 
    unsigned long phys_ret;
    unsigned int regVal;

    long err; 

    pgd_t *pgd;
    pud_t *pud;
    pmd_t *pmd;
    pte_t *pte;

    err = do_shmat(shmid, shmaddr, shmflg, &ret, SHMLBA);
    if (err)
            return err; 
    force_successful_syscall_return();

    pgd = pgd_offset(current->mm, ret);
    pmd = pmd_offset(pgd, ret);
    pte = pte_offset_kernel(pmd, ret);

    printk("*pte = 0x%lx\n", *pte);

    return (long)ret;
}

但是pte指向一个有0的地址,所以我实际上无法获得物理地址。 为什么我的代码中没有正确的pte?

1 个答案:

答案 0 :(得分:0)

试试这个:

#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/cma.h>
#include <linux/dma-contiguous.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/highmem.h>

/***************************************************************************************
 * phys_addr_t getPhysicalPageAddress(unsigned long va)
 *
 * Description
 *  Virtual to Physical address translation method.
 *  Performs a page walk to translate the given virtual address
 *  to its physical page address.
 *
 ***************************************************************************************/
phys_addr_t getPhysicalPageAddress(unsigned long va)
{
    phys_addr_t pa;
    pgd_t *pgd;
    pud_t *pud;
    pmd_t *pmd;
    pte_t *ptep , pte;
    struct page *pagina;
    struct mm_struct * mm;
    int pfn;
    pa = 0;
    mm = current->mm;
    //  Variable initialization
    pagina = NULL;
    pgd    = NULL;
    pmd    = NULL;
    ptep   = NULL;

    // Using Page Tables (this mechanism is known as "Page Walk"), we find the page that corresponds to Virtual Address
    pgd = pgd_offset(mm, va);
    if (!pgd_none(*pgd) || !pgd_bad(*pgd))
    {
        pud = pud_offset(pgd , va);
        if (!pud_none(*pud) || !pud_bad(*pud))
        {
            pmd = pmd_offset(pud, va);
            if (!pmd_none(*pmd) || !pmd_bad(*pmd))
            {
                ptep = pte_offset_map(pmd, va);
                if (ptep)
                {
                    pte = *ptep;
                    pte_unmap(ptep);
                    pagina = pte_page(pte);
                    //  The page has been found
                    //  Seek Page Frame Number for this page
                    pfn = page_to_pfn(pagina);
                    //  Seek Physical Address for this page, using "page_to_phys()" macro
                    pa = page_to_phys(pagina);
                } else printk(KERN_ERR, "Page Walk exception at pte entry. The Virtual Address 0x%lx cannot be translated for this process", va );
            } else printk(KERN_ERR, "Page Walk exception at pmd entry. The Virtual Address 0x%lx cannot be translated for this process", va );
        } else printk(KERN_ERR, "Page Walk exception at pud entry. The Virtual Address 0x%lx cannot be translated for this process", va );
    } else printk(KERN_ERR, "Page Walk exception at pgd entry. The Virtual Address 0x%lx cannot be translated for this process", va );

    return pa;
}