mem: get physical address of any pointer
authorThomas Monjalon <thomas.monjalon@6wind.com>
Thu, 20 Mar 2014 14:05:16 +0000 (15:05 +0100)
committerThomas Monjalon <thomas.monjalon@6wind.com>
Thu, 20 Mar 2014 14:35:08 +0000 (15:35 +0100)
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 <thomas.monjalon@6wind.com>
Acked-by: Olivier Matz <olivier.matz@6wind.com>
lib/librte_eal/common/include/rte_memory.h
lib/librte_eal/linuxapp/eal/eal_memory.c

index 4ae3bf7..4f04f4a 100644 (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.
index 39b2d48..73a6394 100644 (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,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 "