2017-07-05 2 views
0

Je veux connaître l'adresse "physique" d'une mémoire partagée nouvellement attachée sur le noyau Linux. Pour autant que je sache, do_shmat() renvoie l'adresse "virtuelle" de la mémoire partagée. J'ai donc essayé de traduire la valeur de retour de do_shamt() en utilisant TLB, en modifiant shmat dans le noyau comme ci-dessous. Mais pte pointe vers une adresse qui a 0, donc je ne peux pas réellement obtenir l'adresse physique. Pourquoi est-ce que je ne peux pas obtenir le bon pte dans mon code?Est-il possible de connaître l'adresse physique de la mémoire partagée jointe?

Répondre

0

Essayez ceci:

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