`
freesoftman
  • 浏览: 319794 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

有关mmap

阅读更多

 

近日,一直忙于android的研究。好久没有记录点什么了

今天在分析binder的时候,看到了一个函数,mmap, 这个函数以前看过很多遍,但是没有

一次真正去深入了解它, 今天就开始深入了解一下了。

 

以下来自于网络:

-------------------------

Linux提供了内存映射函数mmap, 它把文件内容映射到一段内存上(准确说是虚拟内存上), 通过对这段内存的读取和修改, 实现对文件的读取和修改, 先来看一下mmap的函数声明:

  • 头文件:
    • <unistd.h>
    • <sys/mman.h>
  • 原型: void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offsize);
  • 返回值: 成功则返回映射区起始地址, 失败则返回MAP_FAILED(-1).
  • 参数:
    • addr: 指定映射的起始地址, 通常设为NULL, 由系统指定.
    • length: 将文件的多大长度映射到内存.
    • prot: 映射区的保护方式, 可以是:
      • PROT_EXEC: 映射区可被执行.
      • PROT_READ: 映射区可被读取.
      • PROT_WRITE: 映射区可被写入.
      • PROT_NONE: 映射区不能存取.
    • flags: 映射区的特性, 可以是:
      • MAP_SHARED: 对映射区域的写入数据会复制回文件, 且允许其他映射该文件的进程共享.
      • MAP_PRIVATE: 对映射区域的写入操作会产生一个映射的复制(copy-on-write), 对此区域所做的修改不会写回原文件.
      • 此外还有其他几个flags不很常用, 具体查看linux C函数说明.
    • fd: 由open返回的文件描述符, 代表要映射的文件.
    • offset: 以文件开始处的偏移量, 必须是分页大小的整数倍, 通常为0, 表示从文件头开始映射.

    下面说一下内存映射的步骤:

  • 用open系统调用打开文件, 并返回描述符fd.
  • 用mmap建立内存映射, 并返回映射首地址指针start.
  • 对映射(文件)进行各种操作, 显示(printf), 修改(sprintf).
  • 用munmap(void *start, size_t lenght)关闭内存映射.
  • 用close系统调用关闭文件fd.

一切还是用程序来说明会比较直观:

 

// Linux Device Driver Template/Skeleton with mmap
// Kernel Module
#include <linux/module.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/vmalloc.h>
#include <linux/mman.h>
#include <linux/slab.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
#include <linux/wrapper.h>
#endif
#define SKELETON_MAJOR 240
#define SKELETON_NAME "skeleton"
#define CASE1 1
#define CASE2 2
static unsigned int counter = 0;
static char string [128];
static int data;
//#define USEASCII
#ifdef USEASCII
static char *kmalloc_area = NULL;
static char *kmalloc_ptr = NULL;
#else
static unsigned int *kmalloc_area = NULL;
static unsigned int *kmalloc_ptr = NULL;
#endif
#define LEN (64*1024)
unsigned long virt_addr;
DECLARE_WAIT_QUEUE_HEAD(skeleton_wait);
static int data_not_ready = 0;
// open function - called when the "file" /dev/skeleton is opened in userspace
static int skeleton_open (struct inode *inode, struct file *file) {
 printk("skeleton_openn");
 // we could do some checking on the flags supplied by "open"
 // i.e. O_NONBLOCK
 // -> set some flag to disable interruptible_sleep_on in skeleton_read
 return 0;
}
// close function - called when the "file" /dev/skeleton is closed in userspace 
static int skeleton_release (struct inode *inode, struct file *file) {
 printk("skeleton_releasen");
 return 0;
}
// read function called when from /dev/skeleton is read
static ssize_t skeleton_read (struct file *file, char *buf,
  size_t count, loff_t *ppos) {
 int len, err;
 
 // check if we have data - if not, sleep
 // wake up in interrupt_handler
 while (data_not_ready) {
  interruptible_sleep_on(&skeleton_wait);
 }
 //data_not_ready = 1;
 
 if( counter <= 0 )
  return 0;
 err = copy_to_user(buf,string,counter);
 if (err != 0)
  return -EFAULT;
 len  = counter;
 counter = 0;
 return len;
}
// write function called when to /dev/skeleton is written
static ssize_t skeleton_write (struct file *file, const char *buf,
  size_t count, loff_t *ppos) {
 int err;
 err = copy_from_user(string,buf,count);
 if (err != 0)
  return -EFAULT;
 counter += count;
 return count;
}
// ioctl - I/O control
static int skeleton_ioctl(struct inode *inode, struct file *file,
  unsigned int cmd, unsigned long arg) {
 int retval = 0;
 switch ( cmd ) {
  case CASE1:/* for writing data to arg */
   if (copy_from_user(&data, (int *)arg, sizeof(int)))
   return -EFAULT;
   break;
  case CASE2:/* for reading data from arg */
   if (copy_to_user((int *)arg, &data, sizeof(int)))
   return -EFAULT;
   break;
  default:
   retval = -EINVAL;
 }
 return retval;
}
#ifndef VMALLOC_VMADDR
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
#endif
// From: http://www.scs.ch/~frey/linux/memorymap.html
volatile void *virt_to_kseg(volatile void *address) {
 pgd_t *pgd; pmd_t *pmd; pte_t *ptep, pte;
 unsigned long va, ret = 0UL;
 va=VMALLOC_VMADDR((unsigned long)address);
 /* get the page directory. Use the kernel memory map. */
 pgd = pgd_offset_k(va);
 /* check whether we found an entry */
 if (!pgd_none(*pgd)) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
  /* get the page middle directory */
  pmd = pmd_offset(pgd, va);
#else
  // I'm not sure if we need this, or the line for 2.4
  //    above will work reliably too
  // If you know, please email me :-)
  pud_t *pud = pud_offset(pgd, va);  
  pmd = pmd_offset(pud, va);
#endif
  /* check whether we found an entry */
  if (!pmd_none(*pmd)) {
   /* get a pointer to the page table entry */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
   ptep = pte_offset(pmd, va);
#else
   ptep = pte_offset_map(pmd, va);
#endif
   pte = *ptep;
   /* check for a valid page */
   if (pte_present(pte)) {
    /* get the address the page is refering to */
    ret = (unsigned long)page_address(pte_page(pte));
    /* add the offset within the page to the page address */
    ret |= (va & (PAGE_SIZE -1));
   }
  }
 }
 return((volatile void *)ret);
}
static int skeleton_mmap(struct file * filp, struct vm_area_struct * vma) {
 int ret;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
 ret = remap_page_range(vma->vm_start,
   virt_to_phys((void*)((unsigned long)kmalloc_area)),
   vma->vm_end-vma->vm_start,
   PAGE_SHARED);
//          vma->vm_page_prot);
#else
        ret = remap_pfn_range(vma,
               vma->vm_start,
               virt_to_phys((void*)((unsigned long)kmalloc_area)) >> PAGE_SHIFT,
               vma->vm_end-vma->vm_start,
               PAGE_SHARED);
//               vma->vm_page_prot);
#endif
 if(ret != 0) {
  return -EAGAIN;
 }
 return 0;
}
// define which file operations are supported
struct file_operations skeleton_fops = {
 .owner = THIS_MODULE,
 .llseek = NULL,
 .read  = skeleton_read,
 .write = skeleton_write,
 .readdir = NULL,
 .poll  = NULL,
 .ioctl = skeleton_ioctl,
 .mmap  = skeleton_mmap,
 .open  = skeleton_open,
 .flush = NULL,
 .release = skeleton_release,
 .fsync = NULL,
 .fasync = NULL,
 .lock  = NULL,
 //.readv = NULL,
 //.writev = NULL,
};
// initialize module
static int __init skeleton_init_module (void) {
 int i;
#ifndef USEASCII
 int tmp, tmp2;
#endif
 printk("initializing modulen\n");
 
 i = register_chrdev (SKELETON_MAJOR, SKELETON_NAME, &skeleton_fops);
 if (i != 0) return - EIO;
 
 // reserve memory with kmalloc - Allocating Memory in the Kernel
 kmalloc_ptr = kmalloc(LEN + 2 * PAGE_SIZE, GFP_KERNEL);
 if (!kmalloc_ptr) {
  printk("kmalloc failedn\n");
  return 0;
 }
#ifdef USEASCII
 kmalloc_area = (char *)(((unsigned long)kmalloc_ptr + PAGE_SIZE -1) & PAGE_MASK);
#else
 kmalloc_area = (unsigned int *)(((unsigned long)kmalloc_ptr + PAGE_SIZE -1) & PAGE_MASK);
#endif
 for (virt_addr=(unsigned long)kmalloc_area; virt_addr < (unsigned long)kmalloc_area + LEN;
  virt_addr+=PAGE_SIZE) {
   // reserve all pages to make them remapable
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
   mem_map_reserve(virt_to_page(virt_addr));
#else
   SetPageReserved(virt_to_page(virt_addr));
#endif
 }
 printk("kmalloc_area at 0x%p (phys 0x%lx)\n", kmalloc_area,
  virt_to_phys((void *)virt_to_kseg(kmalloc_area)));
#ifdef USEASCII
 // fill allocated memory with 0123456789 ascii
 for( i = 48; i < 58; i++) {
  kmalloc_ptr[i-48] = (char)i;
 }
 i = 0;
 kmalloc_ptr[58-48] = (char)i;
#else
 // fill allocated memory with integers
 tmp = sizeof(int);
 for( i = 0; i < (10 * tmp); i = i + tmp) {
  kmalloc_ptr[i] = (unsigned int)i;
     
  tmp2 = (unsigned int)kmalloc_ptr[i];
  printk("kmalloc_ptr[%d]=%d\n", i, tmp2);
 }
#endif
 return 0;
}
// close and cleanup module
static void __exit skeleton_cleanup_module (void) {
 printk("cleaning up modulen");
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 for (virt_addr=(unsigned long)kmalloc_area; virt_addr < (unsigned long)kmalloc_area + LEN;
  virt_addr+=PAGE_SIZE) {
   // clear all pages
   ClearPageReserved(virt_to_page(virt_addr));
 }
#endif
 kfree(kmalloc_ptr);
 unregister_chrdev (SKELETON_MAJOR, SKELETON_NAME);
}
module_init(skeleton_init_module);
module_exit(skeleton_cleanup_module);
MODULE_AUTHOR("www.captain.at");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Linux Device Driver Template with MMAP");
 
 
---------------Makefile----------------------
obj-m:=skeleton.o
 
分享到:
评论

相关推荐

    mmap的使用说明

    要使用PACKET_MMAP,首先需要通过`socket()`函数创建一个捕获套接字,接着通过`setsockopt()`函数设置PACKET_MMAP的相关参数,具体包括环形缓冲区的大小和数量。这一步骤涉及的`struct tpacket_req`结构体包含了缓冲...

    mmap打开工具快速安装

    标题中的“mmap打开工具快速安装”指的是使用特定软件(如MindManager)来处理和查看mmap文件。mmap,全称Memory-Mapped File,是一种内存映射文件的技术,允许程序将文件的内容直接映射到内存空间,以便高效地读写...

    mmap内核驱动与应用程序

    `mmap1.c`和`mymap_app.c`作为用户端示例,演示了如何使用mmap与内核驱动进行交互,而`mymap.c`则是内核驱动的核心,负责处理mmap相关的系统调用并完成实际的映射操作。对于理解和开发涉及大文件操作或设备驱动的...

    深入解析Windows操作系统.mmap

    深入解析Windows操作系统.mmap

    mmap代码例子大全

    mmap代码例子大全 mmap(Memory Mapping)是一种进程间通信(IPC)机制,允许多个进程共享同一个文件的内容。下面我们将通过代码示例来详细介绍mmap的使用和原理。 mmap的基本概念 mmap是一种将文件映射到进程...

    ShareMem(mmap)

    标题中的"ShareMem(mmap)"指的是在Android平台上,使用JNI(Java Native Interface)与C/C++原生代码交互时,实现内存共享的一种方法。这里提到的mmap是操作系统的内存映射函数,它允许程序将文件或者设备的存储区域...

    mmcp.zip_MMCP_mmCP路xyz_mmap_mmap 实现cp功能_mmap.xyz.com

    《mmap技术在实现cp功能中的应用》 在IT领域,高效的数据处理是至关重要的,尤其是在处理大量数据时。本文将深入探讨一个名为"mmcp"的工具,它利用mmap(Memory Mapped Files,映射文件到内存)技术来实现文件复制...

    Mmap设备的方法

    ### Mmap设备的方法 #### 一、Mmap系统调用详解 **Mmap**(Memory Map)是Linux系统中一种非常重要的内存管理机制,它允许...掌握好`mmap`的相关知识对于深入理解Linux系统的内存管理和设备驱动开发都是非常有益的。

    mmap测试例程应用实例

    内存映射(mmap)是Linux系统中一种高效的数据访问技术,它允许程序直接通过内存地址来访问文件,而无需经过传统的I/O操作。这种方式极大地优化了大文件处理的性能,因为它减少了磁盘I/O的次数,提高了数据的吞吐量...

    mmap2.rar_mmap

    在linux环境下,用c语言编写的关于mmap使用方法的小程序

    mmap-record-android,MMAP记录.zip

    **mmap-record-android** 是一个开源项目,其主要目的是提供一种在Android平台上进行持久化存储的方法,灵感来源于xlog技术。mmap-record-android利用了内存映射(Memory-Mapped Files,简称mmap)这一功能,它允许...

    matlab的mmap

    5. **相关函数**: - `mmapfile`:创建内存映射文件对象。 - `fopen`和`fclose`:用于常规文件的打开和关闭,但在使用mmap时,一般使用`mmapfile`替代。 - `fwrite`和`fread`:用于读写内存映射文件中的数据。 -...

    16-mmap.rar

    在Linux和UNIX系统中,mmap(映射内存)是一种高效的数据访问机制,它允许将文件或者其他输入输出源直接映射到进程的地址空间中,从而实现文件内容与内存的直接交互。这种方式避免了传统的I/O操作,如read和write...

    mmap2mm一拖得win

    标题"Mmap2mm一拖得win"涉及到的是一个转换工具,用于将MindManager创建的.mmap格式思维导图文件转换成FreeMind支持的.mm格式。这个工具特别适用于Windows用户,因为描述中提到“目前只能在Windows上使用”。 ...

    Vue.mmap笔记

    Vue.mmap笔记

    GPIO.rar_GPIO_linux mmap gp_mmap_mmap gpio_mmap gpio 50c

    标签中的"linux_mmap_gp"、"mmap_gpio_50c"表明了这是关于Linux下的GPIO操作,特别是涉及到mmap的实现,并且可能与GPIO编号50c有关。在Linux中,GPIO编号不一定与实际物理引脚号一致,而是需要通过GPIO控制器驱动...

    linux中mmap总结

    Linux中的mmap(内存映射)是一种高效的数据访问机制,它允许将文件或者其他对象直接映射到进程的虚拟内存空间中,使得程序可以直接通过内存访问这些数据,而无需调用read和write等I/O函数。这种方法可以提高I/O操作...

    linux zero copy mmap

    ### Linux Zero Copy mmap #### 概述 零拷贝(Zero Copy)技术是现代操作系统中一项重要的优化技术,主要用于减少数据在不同内存区域之间的复制次数,从而提高系统的整体性能。在Linux系统中,mmap机制作为一种...

    linux驱动层mmap创建页表流程

    有时候,应用层需要直接访问物理地址,这时应用层就需要调用应用层mmap接口继而调用驱动层的mmap接口将希望的物理地址映射成用户态能访问的虚拟地址。由于操作系统事先并没有创建这块物理地址与虚拟地址的映射关系,...

    nanopi m1关于mmap对gpio进行控制

    - 文件包含相关的头文件,如`&lt;sys/mman.h&gt;`,`&lt;fcntl.h&gt;`,`&lt;unistd.h&gt;`等,这些头文件提供了mmap、open、write等函数的声明。 - 打开GPIO设备节点,获取文件描述符。 - 使用mmap函数映射GPIO控制器的内存。 - ...

Global site tag (gtag.js) - Google Analytics