深入理解mmap
[導(dǎo)讀]我們知道,linux系統(tǒng)中用戶空間和內(nèi)核空間是隔離的,用戶空間程序不能隨意的訪問內(nèi)核空間數(shù)據(jù),只能通過中斷或者異常的方式進(jìn)入內(nèi)核態(tài)
1.開場(chǎng)白
- 環(huán)境:處理器架構(gòu):arm64內(nèi)核源碼:linux-5.11ubuntu版本:20.04.1代碼閱讀工具:vim ctags cscope
下面是正常情況下用戶空間和內(nèi)核空間數(shù)據(jù)訪問圖示:
2. 體驗(yàn)一下
首先我們通過一個(gè)例子來感受一下:驅(qū)動(dòng)代碼:
注:驅(qū)動(dòng)代碼中使用misc框架來實(shí)現(xiàn)字符設(shè)備,misc框架會(huì)處理如創(chuàng)建字符設(shè)備,創(chuàng)建設(shè)備等通用的字符設(shè)備處理,我們只需要關(guān)心我們的實(shí)際的邏輯即可(內(nèi)核中大量使用misc設(shè)備框架來使用字符設(shè)備操作集如ioctl接口,像實(shí)現(xiàn)系統(tǒng)虛擬化kvm模塊,實(shí)現(xiàn)安卓進(jìn)程間通信的binder模塊等)。
0copy_demo.c
#include
#include
#include
#include
#include
#define MISC_DEV_MINOR 5
static char *kbuff;
static ssize_t misc_dev_read(struct file *filep, char __user *buf, size_t count, loff_t *offset)
{
int ret;
size_t len = (count > PAGE_SIZE ? PAGE_SIZE : count);
pr_info("###### %s:%d kbuff:%s ######\n", __func__, __LINE__, kbuff);
ret = copy_to_user(buf, kbuff, len); //這里使用copy_to_user 來進(jìn)程內(nèi)核空間到用戶空間拷貝
return len - ret;
}
static ssize_t misc_dev_write(struct file *filep, const char __user *buf, size_t count, loff_t *offset)
{
pr_info("###### %s:%d ######\n", __func__, __LINE__);
return 0;
}
static int misc_dev_mmap(struct file *filep, struct vm_area_struct *vma)
{
int ret;
unsigned long start;
start = vma->vm_start;
ret = remap_pfn_range(vma, start, virt_to_phys(kbuff) >> PAGE_SHIFT,
PAGE_SIZE, vma->vm_page_prot); //使用remap_pfn_range來映射物理頁(yè)面到進(jìn)程的虛擬內(nèi)存中 virt_to_phys(kbuff) >> PAGE_SHIFT作用是將內(nèi)核的虛擬地址轉(zhuǎn)化為實(shí)際的物理地址頁(yè)幀號(hào) 創(chuàng)建頁(yè)表的權(quán)限為通過mmap傳遞的 vma->vm_page_prot 映射大小為1頁(yè)
return ret;
}
static long misc_dev_ioctl(struct file *filep, unsigned int cmd, unsigned long args)
{
pr_info("###### %s:%d ######\n", __func__, __LINE__);
return 0;
}
static int misc_dev_open(struct inode *inodep, struct file *filep)
{
pr_info("###### %s:%d ######\n", __func__, __LINE__);
return 0;
}
static int misc_dev_release(struct inode *inodep, struct file *filep)
{
pr_info("###### %s:%d ######\n", __func__, __LINE__);
return 0;
}
static struct file_operations misc_dev_fops = {
.open = misc_dev_open,
.release = misc_dev_release,
.read = misc_dev_read,
.write = misc_dev_write,
.unlocked_ioctl = misc_dev_ioctl,
.mmap = misc_dev_mmap,
};
static struct miscdevice misc_dev = {
MISC_DEV_MINOR,
"misc_dev",





