From 3097de6e6bfb955758dc9995d64b73daea4fc411 Mon Sep 17 00:00:00 2001 From: Thomas Monjalon Date: Thu, 20 Mar 2014 15:05:16 +0100 Subject: [PATCH] mem: get physical address of any pointer Insert get_physaddr() into public API as rte_mem_virt2phy(). rte_mem_virt2phy() permits to obtain the physical address of any virtual address mapped to the current process. get_physaddr() was working only for addresses pointing exactly to the first byte of a page. 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: Thomas Monjalon Acked-by: Olivier Matz --- lib/librte_eal/common/include/rte_memory.h | 22 +++++++++++++ lib/librte_eal/linuxapp/eal/eal_memory.c | 37 +++++++++++++++------- 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/lib/librte_eal/common/include/rte_memory.h b/lib/librte_eal/common/include/rte_memory.h index 4ae3bf75a7..4f04f4a9d1 100644 --- a/lib/librte_eal/common/include/rte_memory.h +++ b/lib/librte_eal/common/include/rte_memory.h @@ -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. diff --git a/lib/librte_eal/linuxapp/eal/eal_memory.c b/lib/librte_eal/linuxapp/eal/eal_memory.c index 39b2d48991..73a6394500 100644 --- a/lib/librte_eal/linuxapp/eal/eal_memory.c +++ b/lib/librte_eal/linuxapp/eal/eal_memory.c @@ -61,6 +61,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#define _FILE_OFFSET_BITS 64 #include #include #include @@ -113,8 +114,21 @@ 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; @@ -128,7 +142,7 @@ get_physaddr(void * virtaddr) if (fd < 0) { RTE_LOG(ERR, EAL, "%s(): cannot open /proc/self/pagemap: %s\n", __func__, strerror(errno)); - return (uint64_t) -1; + return RTE_BAD_PHYS_ADDR; } off_t offset; @@ -138,20 +152,21 @@ get_physaddr(void * virtaddr) RTE_LOG(ERR, EAL, "%s(): seek error in /proc/self/pagemap: %s\n", __func__, strerror(errno)); close(fd); - return (uint64_t) -1; + return RTE_BAD_PHYS_ADDR; } if (read(fd, &page, sizeof(uint64_t)) < 0) { RTE_LOG(ERR, EAL, "%s(): cannot read /proc/self/pagemap: %s\n", __func__, strerror(errno)); close(fd); - return (uint64_t) -1; + return RTE_BAD_PHYS_ADDR; } /* * 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) + + ((unsigned long)virtaddr % 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 " -- 2.20.1