LinuxÇý¶¯IOƪ¡ª¡ªmmap²Ù×÷
Ç°ÑÔ
ƽʱÎÒÃÇдLinuxÇý¶¯ºÍÓû§¿Õ¼ä½»»¥Ê±£¬¶¼ÊÇͨ¹ýcopy_from_user°ÑÓû§¿Õ¼ä´«¹ýÀ´µÄÊý¾Ý¾ÙÐп½±´£¬ÎªÊ²Ã´ÒªÕâô×öÄØ£¿
ÓÉÓÚÓû§¿Õ¼äÊDz»¿ÉÖ±½ÓÄں˿ռäÊý¾ÝµÄ£¬ËûÃÇÓ³ÉäµÄÊDzî±ðµÄµØµã¿Õ¼ä£¬Ö»ÄÜÏȽ«Êý¾Ý¿½±´¹ýÀ´£¬È»ºóÔÙ²Ù×÷¡£
ÈôÊÇÓû§¿Õ¼äÐèÒª´«¼¸MBµÄÊý¾Ý¸øÄںˣ¬ÄÇôÔÀ´µÄ¿½±´·½·¨ÏÔȻЧÂÊÌØÊâµÍ£¬Ò²²»Ì«ÏÖʵ£¬ÄÇÔõô°ìÄØ£¿
ÏëÏ룬֮ÒÔÊÇÒª¿½±´ÊÇÓÉÓÚÓû§¿Õ¼ä²»¿ÉÖ±½Ó»á¼ûÄں˿ռ䣬ÄÇÈôÊÇ¿ÉÒÔÖ±½Ó»á¼ûÄں˿ռäµÄbuffer£¬ÊDz»ÊǾͽâ¾öÁË¡£
¼òÆÓÀ´Ëµ£¬¾ÍÊÇÈÃÒ»¿éÎïÀíÄÚ´æÓµÓÐÁ½·ÝÓ³É䣬¼´ÓµÓÐÁ½¸öÐéÄâµØµã£¬Ò»¸öÔÚÄں˿ռ䣬һ¸öÔÚÓû§¿Õ¼ä¡£¹ØϵÈçÏ£º
ͨ¹ýmmapÓ³Éä¾Í¿ÉÒÔʵÏÖ¡£
Ó¦Óòã
Ó¦Óòã´úÂëºÜ¼òÆÓ£¬Ö÷Òª¾ÍÊÇͨ¹ýmmapϵͳŲÓþÙÐÐÓ³É䣬Ȼºó¾Í¿ÉÒÔ¶Ô·µ»ØµÄµØµã¾ÙÐвÙ×÷¡£
char * buf; /* 1. ·¿ªÎļþ */ fd = open("/dev/hello", O_RDWR); if (fd == -1) { printf("can not open file /dev/hello\n"); return -1; } /* 2. mmap * MAP_SHARED : ¶à¸öAPP¶¼Å²ÓÃmmapÓ³Éäͳһ¿éÄÚ´æʱ, ¶ÔÄÚ´æµÄÐ޸ĸ÷È˶¼¿ÉÒÔ¿´µ½¡£ * ¾ÍÊÇ˵¶à¸öAPP¡¢Çý¶¯³ÌÐòÏÖʵÉÏ»á¼ûµÄ¶¼ÊÇͳһ¿éÄÚ´æ * MAP_PRIVATE : ½¨ÉèÒ»¸öcopy on writeµÄ˽ÓÐÓ³Éä¡£ * µ±APP¶Ô¸ÃÄÚ´æ¾ÙÐÐÐÞ¸Äʱ£¬ÆäËû³ÌÐòÊÇ¿´²»µ½ÕâЩÐ޸ĵġ£ * ¾ÍÊǵ±APPдÄÚ´æʱ, Äں˻áÏȽ¨ÉèÒ»¸ö¿½±´¸øÕâ¸öAPP, * Õâ¸ö¿½±´ÊÇÕâ¸öAPP˽ÓеÄ, ÆäËûAPP¡¢Çý¶¯ÎÞ·¨»á¼û¡£ */ buf = mmap(NULL, 1024*8, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
µÇ¼ºó¸´ÖÆ
mmapµÄµÚÒ»¸ö²ÎÊýÊÇÏëÒªÓ³ÉäµÄÆðʼµØµã£¬Í¨³£ÉèÖÃΪNULL£¬ÌåÏÖÓÉÄÚºËÀ´¾öÒé¸ÃÆðʼµØµã¡£
µÚ¶þ²ÎÊýÊÇÒªÓ³ÉäµÄÄÚ´æ¿Õ¼äµÄ¾Þϸ¡£
µÚÈý¸ö²ÎÊýPROT_READ | PROT_WRITEÌåÏÖÓ³ÉäºóµÄ¿Õ¼äÊǿɶÁ¿ÉдµÄ¡£
µÚËĸö²ÎÊý¿ÉÌîMAP_SHARED»òMAP_PRIVATE£º
MAP_SHARED£º¶à¸öAPP¶¼Å²ÓÃmmapÓ³Éäͳһ¿éÄÚ´æʱ, ¶ÔÄÚ´æµÄÐ޸ĸ÷È˶¼¿ÉÒÔ¿´µ½¡£¾ÍÊÇ˵¶à¸öAPP¡¢Çý¶¯³ÌÐòÏÖʵÉÏ »á¼ûµÄ¶¼ÊÇͳһ¿éÄÚ´æ¡£
MAP_PRIVATE£º½¨ÉèÒ»¸öcopy on writeµÄ˽ÓÐÓ³Éä¡£µ±APP¶Ô¸ÃÄÚ´æ¾ÙÐÐÐÞ¸Äʱ£¬ÆäËû³ÌÐòÊÇ¿´²»µ½ÕâЩÐ޸ĵġ£¾ÍÊǵ±APP дÄÚ´æʱ, Äں˻áÏȽ¨ÉèÒ»¸ö¿½±´¸øÕâ¸öAPP£¬Õâ¸ö¿½±´ÊÇÕâ¸öAPP˽ÓеÄ, ÆäËûAPP¡¢Çý¶¯ÎÞ·¨»á¼û¡£
Çý¶¯²ã
Çý¶¯²ãÖ÷ÒªÊÇʵÏÖmmap½Ó¿Ú£¬¶ømmap½Ó¿ÚµÄʵÏÖ£¬Ö÷ÒªÊÇŲÓÃÁËremap_pfn_rangeº¯Êý£¬º¯ÊýÔÐÍÈçÏ£º
int remap_pfn_range( struct vm_area_struct *vma, unsigned long addr, unsigned long pfn, unsigned long size, pgprot_t prot);
µÇ¼ºó¸´ÖÆ
vma£ºÐÎòһƬӳÉäÇøÓòµÄ½á¹¹ÌåÖ¸Õë
addr£ºÒªÓ³ÉäµÄÐéÄâµØµãÆðʼµØµã
pfn£ºÎïÀíÄÚ´æËù¶ÔÓ¦µÄÒ³¿òºÅ£¬¾ÍÊǽ«ÎïÀíµØµã³ýÒÔÒ³¾Þϸ»ñµÃµÄÖµ
size£ºÓ³ÉäµÄ¾Þϸ
prot£º¸ÃÄÚ´æÇøÓòµÄ»á¼ûȨÏÞ
Çý¶¯Ö÷Òª°ì·¨£º
1¡¢Ê¹ÓÃkmalloc»òÕßkzallocº¯Êý·ÖÅÉÒ»¿éÄÚ´ækernel_buf£¬ÓÉÓÚÕâÑù·ÖÅɵÄÄÚ´æÎïÀíµØµãÊÇÒ»Á¬µÄ£¬mmapºóÓ¦Óòã»á¶ÔÕâÒ»¸ö»ùµØµãÈ¥»á¼ûÕâ¿éÄÚ´æ¡£
2¡¢ÊµÏÖmmapº¯Êý
static int hello_drv_mmap(struct file *file, struct vm_area_struct *vma) { /* »ñµÃÎïÀíµØµã */ unsigned long phy = virt_to_phys(kernel_buf);//kernel_bufÊÇÄں˿ռä·ÖÅɵÄÒ»¿éÐéÄâµØµã¿Õ¼ä /* ÉèÖÃÊôÐÔ£ºcache, buffer*/ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); /* map */ if(remap_pfn_range(vma, vma->vm_start, phy>>PAGE_SHFIT, vma->vm_end - vma->start, vma->vm_page_prot)){ printk("mmap remap_pfn_range failed\n"); return -ENOBUFS; } return 0; } static struct file_operations my_fops = { .mmap = hello_drv_mmap, };
µÇ¼ºó¸´ÖÆ
1¡¢Í¨¹ývirt_to_phys½«ÐéÄâµØµãתΪÎïÀíµØµã£¬ÕâÀïµÄkernel_bufÊÇÄں˿ռäµÄÒ»¿éÐéÄâµØµã¿Õ¼ä
2¡¢ÉèÖÃÊôÐÔ£º²»Ê¹ÓÃcache£¬Ê¹ÓÃbuffer
3¡¢Ó³É䣺ͨ¹ýremap_pfn_rangeº¯ÊýÓ³É䣬phy>>PAGE_SHIFT×Åʵ¾ÍÊÇ°´pageÓ³É䣬³ýÁËÕâ¸ö²ÎÊý£¬ÆäËûµÄÆðʼµØµã¡¢¾ÞϸºÍȨÏÞ¶¼¿ÉÒÔÓÉÓû§ÔÚϵͳŲÓú¯ÊýÖÐÖ¸¶¨¡£
µ±Ó¦ÓòãŲÓÃmmapºó£¬¾Í»áŲÓõ½Çý¶¯²ãµÄmmapº¯Êý£¬×îÖÕÓ¦ÓòãµÄÐéÄâµØµãºÍÇý¶¯ÖеÄÎïÀíµØµã¾Í½¨ÉèÁËÓ³Éä¹Øϵ£¬Ó¦ÓòãÒ²¾Í¿ÉÒÔÖ±½Ó»á¼ûÇý¶¯µÄbufferÁË¡£
ÒÔÉϾÍÊÇLinuxÇý¶¯IOƪ¡ª¡ªmmap²Ù×÷µÄÏêϸÄÚÈÝ£¬¸ü¶àÇë¹Ø×¢±¾ÍøÄÚÆäËüÏà¹ØÎÄÕ£¡