【问题标题】:can we use virt_to_phys for user space memory in kernel module?我们可以在内核模块中使用 virt_to_phys 作为用户空间内存吗?
【发布时间】:2017-09-05 14:49:13
【问题描述】:

我将使用malloc在用户应用程序中分配内存,并将malloc返回的地址通过字符驱动接口发送给内核模块。

我将在内核模块中使用get_user_pages_fast 固定该内存的页面。

我可以使用virt_to_phys 来获取malloc 返回的地址吗? 它有效吗?如果没有,那么我怎样才能获得正确的物理地址?

我的目标是获取用户空间分配内存的物理地址。 我将传输大小限制为页面大小 (4KB)。

【问题讨论】:

  • 您需要实际的物理地址还是 DMA 地址?您可以在固定页面上使用dma_map_page(),或者如果您从固定页面创建了分散-聚集列表,则可以使用dma_map_sg()。如果您希望 CPU 访问该页面,您可以使用kmap_atomic() 来获取该页面的内核虚拟地址。请注意,使用kmap_atomic() 映射的页面需要以与映射顺序完全相反的顺序取消映射。

标签: memory memory-management linux-kernel malloc linux-device-driver


【解决方案1】:

不,你不能,virt_to_phys 将内核虚拟地址转换为物理地址。 linux中存在3(或4)种地址:

  • 内核虚拟地址:这是物理地址+/-一个偏移量(PAGE_OFFSET)。
  • 内核物理地址:实际物理地址(通过__pa或virt_to_phys函数获得)。
  • 用户虚拟地址:物理地址的转换在进程的页表中。

请注意,页表“布局”取决于处理器的架构,因此您需要实现与您所使用的架构相对应的软件页表遍历

最后一句话,存在的第四种地址是:

  • 总线地址:设备看到的地址。

【讨论】:

    【解决方案2】:

    malloc 返回用户虚拟地址。所以我认为你不能从驱动程序内部使用malloc返回的地址。

    virt_to_phys:返回的物理地址是给定内存地址的物理(CPU)映射。仅在通过 kmalloc 直接映射或分配的地址上使用此功能才有效。这意味着它被内核用来将内核虚拟地址(不是用户虚拟地址)转换为物理地址

    【讨论】:

      【解决方案3】:

      此程序将帮助您直接访问物理内存。想法是 mmap/dev/mem(RAM)

      #include <stdio.h>
      #include <stdlib.h>
      #include <fcntl.h>
      #include <sys/mman.h>
      #include <unistd.h>
      
      int main(int argc, char *argv[]) {
          if (argc < 3) {
              printf("Usage: %s <phys_addr> <offset>\n", argv[0]);
              return 0;
          }
      
          off_t offset = strtoul(argv[1], NULL, 0);
          size_t len = strtoul(argv[2], NULL, 0);
      
          // Truncate offset to a multiple of the page size, or mmap will fail.
          size_t pagesize = sysconf(_SC_PAGE_SIZE);
          off_t page_base = (offset / pagesize) * pagesize;
          off_t page_offset = offset - page_base;
      
          int fd = open("/dev/mem", O_SYNC);
          unsigned char *mem = mmap(NULL, page_offset + len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, page_base);
          if (mem == MAP_FAILED) {
              perror("Can't map memory");
              return -1;
          }
      
          size_t i;
          for (i = 0; i < len; ++i)
              printf("%02x ", (int)mem[page_offset + i]);
      
          return 0;
      }
      

      归功于Accessing physical address from user space

      【讨论】:

        猜你喜欢
        • 2013-03-28
        • 1970-01-01
        • 1970-01-01
        • 2016-02-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-18
        • 1970-01-01
        • 2023-03-12
        相关资源
        最近更新 更多