简体   繁体   中英

Is there any way to know the physical address of attached shared memory?

I want to know the "physical" address of a newly attached shared memory on Linux kernel.

As far as I know, do_shmat() returns the "virtual" address of shared memory. So I tried to translate the return value of do_shamt() using TLB, by modifying shmat in the kernel like below.

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;
}

But pte points to an address which has 0 so I cannot actually get the physical address. Why can't I get the right pte in my code?

Try this:

#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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM