mem: get physical address of any pointer

Extract rte_mem_virt2phy() from get_physaddr().

rte_mem_virt2phy() permits to obtain the physical address of any
virtual address mapped to the current process calling this function.
Note that this function is very slow and shouldn't be called
after initialization to avoid a performance bottleneck.

The memory must be locked with mlock(). The function rte_mem_lock_page()
is a mlock() helper that lock the whole page.

A better name would be rte_mem_virt2phys but rte_mem_virt2phy is more
consistent with rte_mempool_virt2phy.

Signed-off-by: Damien Millescamps <damien.millescamps@6wind.com>
Signed-off-by: Thomas Monjalon <thomas.monjalon@6wind.com>
Acked-by: Olivier Matz <olivier.matz@6wind.com>
This commit is contained in:
Damien Millescamps 2013-06-12 07:50:20 +02:00 committed by David Marchand
parent 3314648f83
commit 57c24af85d
2 changed files with 46 additions and 9 deletions

View File

@ -73,6 +73,7 @@ enum rte_page_sizes {
#define __rte_cache_aligned __attribute__((__aligned__(CACHE_LINE_SIZE)))
typedef uint64_t phys_addr_t; /**< Physical address definition. */
#define RTE_BAD_PHYS_ADDR ((phys_addr_t)-1)
/**
* Physical memory segment descriptor.
@ -97,6 +98,27 @@ struct rte_memseg {
#endif
} __attribute__((__packed__));
/**
* Lock page in physical memory and prevent from swapping.
*
* @param virt
* The virtual address.
* @return
* 0 on success, negative on error.
*/
int rte_mem_lock_page(const void *virt);
/**
* Get physical address of any mapped virtual address in the current process.
* It is found by browsing the /proc/self/pagemap special file.
* The page must be locked.
*
* @param virt
* The virtual address.
* @return
* The physical address or RTE_BAD_PHYS_ADDR on error.
*/
phys_addr_t rte_mem_virt2phy(const void *virt);
/**
* Get the layout of the available physical memory.

View File

@ -61,6 +61,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define _FILE_OFFSET_BITS 64
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
@ -113,16 +114,30 @@ static uint64_t baseaddr_offset;
#define RANDOMIZE_VA_SPACE_FILE "/proc/sys/kernel/randomize_va_space"
static uint64_t
get_physaddr(void * virtaddr)
/* Lock page in physical memory and prevent from swapping. */
int
rte_mem_lock_page(const void *virt)
{
unsigned long virtual = (unsigned long)virt;
int page_size = getpagesize();
unsigned long aligned = (virtual & ~ (page_size - 1));
return mlock((void*)aligned, page_size);
}
/*
* Get physical address of any mapped virtual address in the current process.
*/
phys_addr_t
rte_mem_virt2phy(const void *virtaddr)
{
int fd;
uint64_t page, physaddr;
uint64_t page, physaddr, virtual;
unsigned long virt_pfn;
int page_size;
/* standard page size */
page_size = getpagesize();
virtual = (uint64_t) virtaddr;
fd = open("/proc/self/pagemap", O_RDONLY);
if (fd < 0) {
@ -151,7 +166,7 @@ get_physaddr(void * virtaddr)
* the pfn (page frame number) are bits 0-54 (see
* pagemap.txt in linux Documentation)
*/
physaddr = ((page & 0x7fffffffffffffULL) * page_size);
physaddr = ((page & 0x7fffffffffffffULL) * page_size) + (virtual % page_size);
close(fd);
return physaddr;
}
@ -167,8 +182,8 @@ find_physaddrs(struct hugepage_file *hugepg_tbl, struct hugepage_info *hpi)
phys_addr_t addr;
for (i = 0; i < hpi->num_pages[0]; i++) {
addr = get_physaddr(hugepg_tbl[i].orig_va);
if (addr == (phys_addr_t) -1)
addr = rte_mem_virt2phy(hugepg_tbl[i].orig_va);
if (addr == RTE_BAD_PHYS_ADDR)
return -1;
hugepg_tbl[i].physaddr = addr;
}
@ -493,9 +508,9 @@ remap_all_hugepages(struct hugepage_file *hugepg_tbl, struct hugepage_info *hpi)
rte_snprintf(hugepg_tbl[page_idx].filepath, MAX_HUGEPAGE_PATH, "%s",
filepath);
physaddr = get_physaddr(vma_addr);
physaddr = rte_mem_virt2phy(vma_addr);
if (physaddr == (phys_addr_t) -1)
if (physaddr == RTE_BAD_PHYS_ADDR)
return -1;
hugepg_tbl[page_idx].final_va = vma_addr;
@ -516,7 +531,7 @@ remap_all_hugepages(struct hugepage_file *hugepg_tbl, struct hugepage_info *hpi)
expected_physaddr = hugepg_tbl[page_idx].physaddr + offset;
page_addr = RTE_PTR_ADD(vma_addr, offset);
physaddr = get_physaddr(page_addr);
physaddr = rte_mem_virt2phy(page_addr);
if (physaddr != expected_physaddr) {
RTE_LOG(ERR, EAL, "Segment sanity check failed: wrong physaddr "