Browse Source

Allow mapping of arbitrary memory areas

Suren A. Chilingaryan 8 years ago
parent
commit
a21dea7a0d
7 changed files with 120 additions and 6 deletions
  1. 2 2
      CMakeLists.txt
  2. 32 0
      driver/dev.c
  3. 1 1
      driver/ioctl.c
  4. 1 0
      driver/ioctl.h
  5. 3 3
      pcilib/CMakeLists.txt
  6. 52 0
      pcilib/mem.c
  7. 29 0
      pcilib/mem.h

+ 2 - 2
CMakeLists.txt

@@ -1,8 +1,8 @@
 project(pcitool C)
 
 set(RELEASE "3")
-set(PCILIB_VERSION "0.2.7")
-set(PCILIB_ABI_VERSION "2")
+set(PCILIB_VERSION "0.2.8")
+set(PCILIB_ABI_VERSION "0")
 
 cmake_minimum_required(VERSION 2.8)
 #set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH true)

+ 32 - 0
driver/dev.c

@@ -127,6 +127,35 @@ static int pcidriver_mmap_bar(pcidriver_privdata_t *privdata, struct vm_area_str
 #endif /* PCIDRIVER_DUMMY_DEVICE */
 }
 
+
+static int pcidriver_mmap_area(pcidriver_privdata_t *privdata, struct vm_area_struct *vmap)
+{
+    int ret = 0;
+
+    unsigned long vma_size;
+    unsigned long addr = vmap->vm_pgoff;
+
+    mod_info_dbg("Entering mmap_addr\n");
+
+    /* Check sizes */
+    vma_size = (vmap->vm_end - vmap->vm_start);
+
+    if (addr % PAGE_SIZE) {
+	mod_info("mmap addr (0x%lx) is not aligned to page boundary\n", addr);
+        return -EINVAL;
+    }
+
+    ret = remap_pfn_range(vmap, vmap->vm_start, (addr >> PAGE_SHIFT), vma_size, vmap->vm_page_prot);
+
+    if (ret) {
+        mod_info("remap_pfn_range failed\n");
+        return -EAGAIN;
+    }
+
+    return 0;	/* success */
+}
+
+
 /**
  *
  * This function is the entry point for mmap() and calls either pcidriver_mmap_bar
@@ -156,6 +185,9 @@ static int pcidriver_mmap(struct file *filp, struct vm_area_struct *vma)
         }
         ret = pcidriver_mmap_bar(privdata, vma, bar);
         break;
+    case PCIDRIVER_MMAP_AREA:
+	ret = pcidriver_mmap_area(privdata, vma);
+	break;
     case PCIDRIVER_MMAP_KMEM:
         ret = pcidriver_mmap_kmem(privdata, vma);
         break;

+ 1 - 1
driver/ioctl.c

@@ -54,7 +54,7 @@
  */
 static int ioctl_mmap_mode(pcidriver_privdata_t *privdata, unsigned long arg)
 {
-    if ((arg != PCIDRIVER_MMAP_PCI) && (arg != PCIDRIVER_MMAP_KMEM))
+    if ((arg != PCIDRIVER_MMAP_PCI) && (arg != PCIDRIVER_MMAP_KMEM) && (arg != PCIDRIVER_MMAP_AREA))
         return -EINVAL;
 
     /* change the mode */

+ 1 - 0
driver/ioctl.h

@@ -18,6 +18,7 @@
 /* mmap mode of the device */
 #define PCIDRIVER_MMAP_PCI		0
 #define PCIDRIVER_MMAP_KMEM 		1
+#define PCIDRIVER_MMAP_AREA		2
 
 /* Direction of a DMA operation */
 #define PCIDRIVER_DMA_BIDIRECTIONAL	0

+ 3 - 3
pcilib/CMakeLists.txt

@@ -8,8 +8,8 @@ include_directories(
     ${UTHASH_INCLUDE_DIRS}
 )
 
-set(HEADERS pcilib.h pci.h datacpy.h memcpy.h pagecpy.h cpu.h timing.h export.h value.h bar.h fifo.h model.h bank.h register.h view.h property.h unit.h xml.h py.h kmem.h irq.h locking.h lock.h dma.h event.h plugin.h tools.h error.h debug.h env.h config.h version.h build.h)
-add_library(pcilib SHARED pci.c datacpy.c memcpy.c pagecpy.c cpu.c timing.c export.c value.c bar.c fifo.c model.c bank.c register.c view.c unit.c property.c xml.c py.c kmem.c irq.c locking.c lock.c dma.c event.c plugin.c tools.c error.c debug.c env.c)
+set(HEADERS pcilib.h pci.h datacpy.h memcpy.h pagecpy.h cpu.h timing.h export.h value.h mem.h bar.h fifo.h model.h bank.h register.h view.h property.h unit.h xml.h py.h kmem.h irq.h locking.h lock.h dma.h event.h plugin.h tools.h error.h debug.h env.h config.h version.h build.h)
+add_library(pcilib SHARED pci.c datacpy.c memcpy.c pagecpy.c cpu.c timing.c export.c value.c mem.c bar.c fifo.c model.c bank.c register.c view.c unit.c property.c xml.c py.c kmem.c irq.c locking.c lock.c dma.c event.c plugin.c tools.c error.c debug.c env.c)
 target_link_libraries(pcilib dma protocols views ${CMAKE_THREAD_LIBS_INIT} ${UFODECODE_LIBRARIES} ${CMAKE_DL_LIBS} ${EXTRA_SYSTEM_LIBS} ${LIBXML2_LIBRARIES} ${PYTHON_LIBRARIES})
 add_dependencies(pcilib dma protocols views)
 
@@ -21,7 +21,7 @@ install(FILES pcilib.h
     DESTINATION include
 )
 
-install(FILES bar.h kmem.h locking.h lock.h bank.h register.h xml.h dma.h event.h model.h error.h debug.h env.h tools.h timing.h cpu.h datacpy.h pagecpy.h memcpy.h export.h view.h unit.h
+install(FILES mem.h bar.h kmem.h locking.h lock.h bank.h register.h xml.h dma.h event.h model.h error.h debug.h env.h tools.h timing.h cpu.h datacpy.h pagecpy.h memcpy.h export.h view.h unit.h
     DESTINATION include/pcilib
 )
 

+ 52 - 0
pcilib/mem.c

@@ -0,0 +1,52 @@
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "pcilib.h"
+#include "locking.h"
+#include "mem.h"
+#include "error.h"
+#include "pci.h"
+
+
+
+void *pcilib_map_area(pcilib_t *ctx, uintptr_t addr, size_t size) {
+    void *res;
+    int err, ret; 
+
+    err = pcilib_lock_global(ctx);
+    if (err) {
+	pcilib_error("Error (%i) acquiring mmap lock", err);
+	return NULL;
+    }
+
+    ret = ioctl( ctx->handle, PCIDRIVER_IOC_MMAP_MODE, PCIDRIVER_MMAP_AREA );
+    if (ret) {
+	pcilib_unlock_global(ctx);
+	pcilib_error("PCIDRIVER_IOC_MMAP_MODE ioctl have failed");
+	return NULL;
+    }
+
+    res = mmap( 0, size, PROT_WRITE | PROT_READ, MAP_SHARED, ctx->handle, addr );
+
+    pcilib_unlock_global(ctx);
+
+    if ((!res)||(res == MAP_FAILED)) {
+	pcilib_error("Failed to mmap area 0x%lx of size %zu bytes", addr, size);
+	return NULL;
+    }
+
+    return res;
+}
+
+void pcilib_unmap_area(pcilib_t *ctx, void *addr, size_t size) {
+    munmap(addr, size);
+}

+ 29 - 0
pcilib/mem.h

@@ -0,0 +1,29 @@
+#ifndef _PCILIB_MEM_H
+#define _PCILIB_MEM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Maps the specified memory area in the address space of the process. 
+ * @param[in,out] ctx 	- pcilib context
+ * @param[in] addr	- hardware address (should be page-aligned)
+ * @param[in] size	- size (should be multiple of page size)
+ * return 		- the address where the memory area is mapped
+ */
+void *pcilib_map_area(pcilib_t *ctx, uintptr_t addr, size_t size);
+
+/**
+ * Unmaps the specified memory area in the address space of the process. 
+ * @param[in,out] ctx 	- pcilib context
+ * @param[in] addr	- pointer to the virtual address where the area is mapped
+ * @param[in] size	- size (should be multiple of page size)
+ */
+void pcilib_unmap_area(pcilib_t *ctx, void *addr, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PCILIB_MEM_H */