bbsxjtu 发表于 2010-11-27 16:33

问个内存分配和访问的问题

在user mode写了一个 application,内核有一个char设备驱动。

现在user mode的application打算ioctl到驱动程序,分配一段物理内存,同时map这段物理内存到用户态,这样应用程序就可以访问了。应该怎么实现??

我在内核驱动程序中使用get_free_pages,但是在用户态打开/dev/mem了,mmap不能成功啊。
大家一般怎么应对这种情况

EZWORD 发表于 2010-11-27 16:53

本帖最后由 EZWORD 于 2010-11-27 16:56 编辑

论坛上精典帖子里有这个源代码,不知道是哪位大神写的了。驱动如下:#include <linux/version.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/mm.h>

#define PROC_MEMSHARE_DIR "memshare"
#define PROC_MEMSHARE_PHYADDR "phymem_addr"
#define PROC_MEMSHARE_SIZE "phymem_size"

/*alloc one page. 4096 bytes*/
#define PAGE_ORDER 8
/*this value can get from PAGE_ORDER*/
#define PAGES_NUMBER 38

struct proc_dir_entry *proc_memshare_dir ;
unsigned long kernel_memaddr = 0;
unsigned long kernel_memsize= 0;

static int proc_read_addr(char *page, char **start, off_t off, int count,int *eof, void *data)
{
      return sprintf(page, "%08lx\n", __pa(kernel_memaddr));
}
static int proc_read_size(char *page, char **start, off_t off, int count,int *eof, void *data)
{
      return sprintf(page, "%lu\n", kernel_memsize);
}

static int __init init(void)
{
      /*build proc dir "memshare"and two proc files: phymem_addr, phymem_size in the dir*/
      proc_memshare_dir = proc_mkdir(PROC_MEMSHARE_DIR, NULL);
      create_proc_read_entry(PROC_MEMSHARE_PHYADDR, 0, proc_memshare_dir, proc_read_addr,NULL);
      create_proc_read_entry(PROC_MEMSHARE_SIZE, 0, proc_memshare_dir, proc_read_size,NULL);
                // for old kernel 2.6.26,use below format
                //create_proc_info_entry(PROC_MEMSHARE_PHYADDR, 0, proc_memshare_dir, proc_read_addr);
      //create_proc_info_entry(PROC_MEMSHARE_SIZE, 0, proc_memshare_dir, proc_read_size);


      /*alloc one page*/
      kernel_memaddr =__get_free_pages(GFP_KERNEL, PAGE_ORDER);
      if(!kernel_memaddr)
      {
                printk("Allocate memory failure!\n");
      }
      else
      {
                SetPageReserved(virt_to_page(kernel_memaddr));
                kernel_memsize = PAGES_NUMBER * PAGE_SIZE;
                printk("Allocate memory success!. The phy mem addr=%08lx, size=%lu\n", __pa(kernel_memaddr), kernel_memsize);
      }
      return 0;
}

static void __exit fini(void)
{
      printk("The content written by user is: %s\n", (unsigned char *) kernel_memaddr);
      ClearPageReserved(virt_to_page(kernel_memaddr));
      free_pages(kernel_memaddr, PAGE_ORDER);
      remove_proc_entry(PROC_MEMSHARE_PHYADDR, proc_memshare_dir);
      remove_proc_entry(PROC_MEMSHARE_SIZE, proc_memshare_dir);
      remove_proc_entry(PROC_MEMSHARE_DIR, NULL);

      return;
}
module_init(init);
module_exit(fini);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Godbach (nylzhaowei@163.com)");
MODULE_DESCRIPTION("memory dynamic alloc and use it at user space.");
测试如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>

int main(int argc, char* argv[])
{
      if(argc != 2)
      {
                printf("Usage: %s string\n", argv);
                return 0;
      }
      
      unsigned long phymem_addr, phymem_size;
      char *map_addr;
      char s;
      int fd;
      
      /*get the physical address of allocated memory in kernel*/
      fd = open("/proc/memshare/phymem_addr", O_RDONLY);
      if(fd < 0)
      {
                printf("cannot open file /proc/memshare/phymem_addr\n");
                return 0;
      }
      read(fd, s, sizeof(s));
      sscanf(s, "%lx", &phymem_addr);
      close(fd);

      /*get the size of allocated memory in kernel*/
      fd = open("/proc/memshare/phymem_size", O_RDONLY);
      if(fd < 0)
      {
                printf("cannot open file /proc/memshare/phymem_size\n");
                return 0;
      }
      read(fd, s, sizeof(s));
      sscanf(s, "%lu", &phymem_size);
      close(fd);
      
      printf("phymem_addr=%lx, phymem_size=%lu\n", phymem_addr, phymem_size);
      /*memory map*/
      int map_fd = open("/dev/mem", O_RDWR);
      if(map_fd < 0)
      {
                printf("cannot open file /dev/mem\n");
                return 0;
      }
      
      map_addr = mmap(0, phymem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, phymem_addr);
      strcpy(map_addr, argv);
      munmap(map_addr, phymem_size);
      close(map_fd);
      return 0;
      
}以上为大神所做与本人无任何关系:m01:

EZWORD 发表于 2010-11-27 16:56

原文链接http://blog168.chinaunix.net/space.php?uid=10167808&do=blog&cuid=1271210

bbsxjtu 发表于 2010-11-27 17:22

相当不错,赞,谢谢

Godbach 发表于 2010-11-28 12:29

呵呵,很荣幸啊。是偶的拙作。

至于 /dev/mem 能否被读取或者映射,也是和内核版本以及内核配置有关的。

Godbach 发表于 2010-11-28 12:30

这个毕竟相当于读到了系统的内存空间,牵涉到了安全的问题
页: [1]
查看完整版本: 问个内存分配和访问的问题