【IMX6ULLドライバ開発学習】19.mmapメモリマッピング

mmap はファイルまたは他のオブジェクトをメモリにマップするため、アプリケーション層は copy_to_user 関数を使用せずにドライバー層のデータを直接読み取ることができます。
大量のデータの読み取りと書き込みが必要な LCD などの周辺機器に使用できます。データ。

1. アプリケーション層

mmap の使用法:

  • open システムコールでファイルを開き、記述子 fd を返します。
  • mmap でメモリ マップを作成し、マップの先頭アドレス ポインタの先頭を返します。
  • マッピング (ファイル)、表示 (printf)、変更 (strcpy、memncpy、sprintf、直接変更など) に対するさまざまな操作を実行します。
  • メモリ マッピングをオフにするには、 munmap (void *start, size_t length)を使用します
  • closeシステムコールでファイル fd を閉じます。

mmap関数:

void *mmap(void *addr, size_t length, int prot, int flags,
                  int fd, off_t offset);
パラメータ 意味
アドレス マップされるメモリの開始アドレスを指します。通常はNULLに設定されます。
これは、システムが自動的にアドレスを選択し、マッピングが成功した後にこのアドレスに戻ることを意味します。
長さ メモリにマップするファイルの量を表します。
プロット マップされた領域を保護する方法。次の方法を組み合わせることができます。
PROT_EXEC マッピング領域は実行可能
PROT_READマッピング領域は読み取り可能
PROT_WRITEマッピング領域は書き込み可能
PROT_NONE マッピング領域はアクセス不可
フラグ マップされたエリアに影響を与えるさまざまなプロパティ。
mmap() を呼び出すときは、MAP_SHAREDまたはMAP_PRIVATEを指定する必要があります。
fd メモリにマップするファイル記述子。
匿名メモリマッピングが使用される場合、flags に MAP_ANONYMOUS が設定され、fd が -1 に設定されます。
一部のシステムは匿名メモリ マッピングをサポートしていません。fopen を使用して /dev/zero ファイルを開き、
ファイルをマップすることで、匿名メモリ マッピングの効果を得ることができます。
オフセット ファイル マッピングのオフセットは通常 0 に設定され
ファイルの先頭から対応することを意味し、オフセットはページ サイズの整数倍でなければなりません。

メモリマッピング後、write と read を使用してメモリの読み書きを行うこともできますが、効率は低くなります mmap 関数によって返されたアドレスを直接操作したり、strcpy などの文字列処理関数を使用したりでき
ます


応用例:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>

#define   MMSIZE   128

int main(int argc, char *argv[])
{
    
    
    int len;
    char wr_buf[] = "hello mmap";
	char read_buf[1024];
	char *start;

	...
	...
	
    /*open*/
    int fd;
    fd = open(argv[1], O_RDWR);
    if(fd < 0){
    
    
        printf("open failed\n");
        return -2;
    }
	printf("pid = %d\n", getpid());
	/* 将文件映射到进程的虚拟内存空间 */
	start = mmap(NULL, MMSIZE, PROT_READ | PROT_WRITE, 
		         MAP_SHARED, fd, 0);
	printf("mmap address = 0x%x\n", start);
	/* 写数据 */
	strcpy(start, wr_buf);
	/* 读数据 */
	strcpy(read_buf, start);
//	read(fd, read_buf, MMSIZE);

	printf("new data = %s\n", start);
	printf("old data = %s\n", read_buf);
	while(1){
    
    
		sleep(5);
	}
	munmap(start, MMSIZE);
    close(fd);
    return 0;
}

2 番目にドライバー層

  • まず、ドライバーはメモリのセクションを割り当てます。
  • 次に、ユーザー プロセスは、ライブラリ関数 mmap() を通じてカーネル空間にマップするメモリ量をカーネルに伝えます。
  • 一連の関数呼び出しの後、カーネルは、対応するドライバーの file_operation で指定された xxx_mmap 関数を呼び出します。
  • xxx_mmap 関数でremap_pfn_range () を呼び出して、マッピング関係を確立します。

ドライバーの例:

......
......

#define   MM_SIZE   1024 * 8
#define   MIN(x,y)  (x < y ? x : y)

static char *buf = NULL;

static ssize_t hello_read (struct file *filp, char  *buff, size_t size, loff_t *offset)
{
    
    
	int err;
	err = copy_to_user(buff, buf, MIN(MM_SIZE, size));
	return MIN(MM_SIZE, size);
}

static int hello_mmap (struct file *filp, struct vm_area_struct *vma)
{
    
    	
	/*设置属性: cache,buffer */
	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);

	if(remap_pfn_range(vma,//虚拟内存区域,即设备地址将要映射到这里  
                       vma->vm_start,//虚拟空间的起始地址  
                       virt_to_phys(buf)>>PAGE_SHIFT,//与物理内存对应的页帧号,物理地址右移12位  
                       vma->vm_end - vma->vm_start,//映射区域大小,一般是页大小的整数倍  
                       vma->vm_page_prot))//保护属性,  
    {
    
      
        return -EAGAIN;  
    }  
    return 0;
}

/*定义 file_operations 结构体*/
static const struct file_operations hello_drv = {
    
    
	.read		= hello_read,
	.open		= hello_open,
	.mmap 		= hello_mmap,
	......
	......
};

/*入口函数*/
static int hello_init(void)
{
    
    
	//内核申请内存只能按页申请,申请该内存以便后面把它当作虚拟设备
	buf = kmalloc(MM_SIZE, GFP_KERNEL);
	strcpy(buf, "abc");  //先放入一些数据
	......
	......
	
	return 0;
}

/*退出函数*/
static void hello_exit(void)
{
    
    
	kfree(buf);
	......
	......
}	

......
......


3. テスト


mmap のパラメータがMAP_SHAREDの場合、 strcpy で読み取られるデータと書き込まれたデータは同じであり、
mmap のパラメータがMAP_PRIVATEの場合、 strcpy で読み取られるデータと書き込まれたデータは同じであり、データの読み取りと書き込み 入力が異なります (読み取りは元のメモリ データであるため、MAP_PRIVATE フラグにより​​、カーネルはメモリ データを書き込むときに自動的にメモリ空間をコピーします。そのため、読み取りは元のメモリで、書き込まれたデータはコピーされた新しいメモリに書き込まれます)
ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/HuangChen666/article/details/131683860