我想知道"身体" 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?
答案 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;
}