当前位置:网站首页>DRM driven MMAP detailed explanation: (I) preliminary knowledge
DRM driven MMAP detailed explanation: (I) preliminary knowledge
2022-06-12 17:56:00 【_ kerneler】
!!! Statement !!!
This article is transferred from : Hexiaolong
link :https://blog.csdn.net/hexiaolong2009/article/details/87392266
Reprint just to learn to back up .
video : Three mmap Driver implementation method
Preface
In the last article 《DRM GEM Driver development (dumb)》 We learned how to write the simplest DRM GEM The driver . The driver only provides dumb buffer The ability to operate , Allow applications to dumb buffer Conduct create and mmap operation .
dumb buffer Simple operation , But in drm Drive directory , The implementation of various manufacturers is diverse . because dumb buffer Only through mmap To visit , So this series of articles will take you to learn more DRM Medium mmap Drive development .
In the official explanation DRM mmap Before , I think it is necessary to let you know a common mmap How drivers should be written . This article is not intended to explain mmap The principle of system call and its related details , Because it involves linux Many concepts of memory management , You just need to know how to write a simple mmap The driver is OK , For subsequent drm mmap Prepare for writing the driver . If you read this article , Want to learn more mmap Knowledge of system calls , I recommend you to read pengdonglin's blog 《 Memory mapping functions remap_pfn_range Study 》 And Hu Xiao's blog 《 Careful analysis mmap: What is it? Why? How to use it? 》.
Text
stay kernel Driving medium , Realization mmap System calls are inseparable from two key steps :(1) Memory allocation (2) Establish a mapping relationship . This just corresponds to DRM Medium dumb_create and mmap operation .
Let's start with mapping , stay linux There are mainly two methods to establish mapping relationship in driver :
- One time mapping —— stay mmap In the callback function , Establish the mapping relationship of the whole block of memory at one time , Usually, the
remap_pfn_range()
As a representative . - Page Fault —— mmap Don't create a mapping relationship first , When the upper layer triggers a page missing exception , stay fault Establish a mapping relationship in the interrupt handling function , Which one is missing, which one is missing , Usually, the
vm_insert_page()
As a representative .
The timing of memory allocation will also affect the design of the driver , It can be roughly divided into the following three types :
- stay mmap Assign before system call
- stay mmap Allocated during system call
- stay fault Allocated in the interrupt handler
So different allocation timing + Different mapping mechanisms , You'll get a different answer mmap The implementation strategy of . That's why DRM Driving medium , Each family's dumb_create and mmap The reason why the implementation code is very different .
The following is a sample code to show you several typical mmap Driver implementation mode .
Example 1
mmap Before the assignment + One time mapping :
describe :
- The driver shall be allocated before initialization 3 individual PAGE.
- The upper layer executes mmap When the system is called , In the underlying mmap The callback function passes remap_pfn_range() Set up all the mapping relationships at once , And return the mapped starting virtual address to the application .
- The application uses the returned virtual address for memory read and write operations .
Driver code :
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/slab.h>
static void *kaddr;
static int my_mmap(struct file *file, struct vm_area_struct *vma)
{
return remap_pfn_range(vma, vma->vm_start,
(virt_to_phys(kaddr) >> PAGE_SHIFT) + vma->vm_pgoff,
vma->vm_end - vma->vm_start, vma->vm_page_prot);
}
static struct file_operations my_fops = {
.owner = THIS_MODULE,
.mmap = my_mmap,
};
static struct miscdevice mdev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "my_dev",
.fops = &my_fops,
};
static int __init my_init(void)
{
kaddr = kzalloc(PAGE_SIZE * 3, GFP_KERNEL);
return misc_register(&mdev);
}
module_init(my_init);
Example 2
mmap Before the assignment + Page Fault:
describe :
- The driver is pre allocated during initialization 3 individual PAGE.
- The upper layer executes mmap system call , The underlying drivers are mmap No mapping relationship is established in the callback function , It will be implemented locally vm_ops Attached to the process vma->vm_ops On the pointer , Then the function returns .
- The upper layer obtains an unmapped process address space , And read and write the memory , This causes a page missing exception to be triggered . The page missing exception will eventually call the previously attached vm_ops->fault() Callback interface , In this connection and adjustment, pass vm_insert_page() Establish the mapping relationship between physical memory and user address space .
- After the exception returns , The application can then resume the previously interrupted read / write operation .
Be careful : This happens every time Page Fault Only one interrupt can be mapped Page.
Driver code :
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/slab.h>
static void *kaddr;
static int my_fault(struct vm_fault *vmf)
{
struct vm_area_struct *vma = vmf->vma;
int offset, ret;
offset = vmf->pgoff * PAGE_SIZE;
ret = vm_insert_page(vma, vmf->address, virt_to_page(kaddr + offset));
if (ret)
return VM_FAULT_SIGBUS;
return VM_FAULT_NOPAGE;
}
static const struct vm_operations_struct vm_ops = {
.fault = my_fault,
};
static int my_mmap(struct file *file, struct vm_area_struct *vma)
{
vma->vm_flags |= VM_MIXEDMAP;
vma->vm_ops = &vm_ops;
return 0;
}
static struct file_operations my_fops = {
.owner = THIS_MODULE,
.mmap = my_mmap,
};
static struct miscdevice mdev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "my_dev",
.fops = &my_fops,
};
static int __init my_init(void)
{
kaddr = kzalloc(PAGE_SIZE * 3, GFP_KERNEL);
return misc_register(&mdev);
}
module_init(my_init);
DRM Typical driving representatives :tegra
、udl
Example 3
Page Fault The distribution of + mapping :
describe :
The mapping process is exactly the same as in example 2 , The timing of memory allocation is just page fault In the interrupt handler .
Driver code :
Here to simplify the code , Only one... Is allocated in total page, Multiple page It can be done by vmf->pgoff To distinguish .
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/slab.h>
static struct page *page;
static int my_fault(struct vm_fault *vmf)
{
struct vm_area_struct *vma = vmf->vma;
int ret;
if (!page)
page = alloc_page(GFP_KERNEL);
ret = vm_insert_page(vma, vmf->address, page);
if (ret)
return VM_FAULT_SIGBUS;
return VM_FAULT_NOPAGE;
}
static const struct vm_operations_struct vm_ops = {
.fault = my_fault,
};
static int my_mmap(struct file *file, struct vm_area_struct *vma)
{
vma->vm_flags |= VM_MIXEDMAP;
vma->vm_ops = &vm_ops;
return 0;
}
static struct file_operations my_fops = {
.owner = THIS_MODULE,
.mmap = my_mmap,
};
static struct miscdevice mdev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "my_dev",
.fops = &my_fops,
};
static int __init my_init(void)
{
return misc_register(&mdev);
}
module_init(my_init);
DRM Typical driving representatives :vkms
、vgem
Example 4
Same as example 2 (mmap Before the assignment + Page Fault mapping ), The difference lies in fault Interrupt handling function , No longer use vm_insert_page() To map , Instead, the physics page Return to vmf->page The pointer .
Driver code :
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/slab.h>
static void *kaddr;
static int my_fault(struct vm_fault *vmf)
{
vmf->page = virt_to_page(kaddr + vmf->pgoff * PAGE_SIZE);
get_page(vmf->page);
return 0;
}
static const struct vm_operations_struct vm_ops = {
.fault = my_fault,
};
static int my_mmap(struct file *file, struct vm_area_struct *vma)
{
vma->vm_flags |= VM_MIXEDMAP;
vma->vm_ops = &vm_ops;
return 0;
}
static struct file_operations my_fops = {
.owner = THIS_MODULE,
.mmap = my_mmap,
};
static struct miscdevice mdev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "my_dev",
.fops = &my_fops,
};
static int __init my_init(void)
{
kaddr = kzalloc(PAGE_SIZE * 3, GFP_KERNEL);
return misc_register(&mdev);
}
module_init(my_init);
Be careful : Use vmf->page Mode mapping ,fault The return value of the interrupt function should be 0. While using vm_insert_page() Mode mapping , The return value should be VM_FAULT_NOPAGE
.
DRM Typical driving representatives :
vkms
、vgem
Example 5
mmap The distribution of + Page Fault mapping : The code is actually the same as example 3 (Page Fault The distribution of + mapping ) Little difference , It's just mmap Memory allocation in callback , I'm not going to do that here .
DRM Typical driving representatives :
shmem
(linux 4.19)
The test program
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int fd;
fd = open("/dev/my_dev", O_RDWR);
char *str = mmap(NULL, 4096 * 3, PROT_WRITE, MAP_SHARED, fd, 0);
strcpy(str, "hello world\n");
munmap(str, 4096 * 3);
str = mmap(NULL, 4096 * 3, PROT_READ, MAP_SHARED, fd, 0);
printf("%s\n", str);
munmap(str, 4096 * 3);
close(fd);
return 0;
}
describe :
Execute successively 2 Time mmap/munmap operation , The first is a write operation , The second is a read operation .
Running results :
# ./a.out
hello world
Conclusion
No matter what DRM Drive development , Or other device driver development , The above examples are worth referring to . I hope that through this article , It can make beginners understand mmap The implementation of driver has a general understanding , In this way, we will follow up DRM Only in the driving explanation can we know well .
Source download
Github: sample-code/mmap
Test platform :QEMU vexpress-a9
Reference material
- 《 Memory mapping functions remap_pfn_range Study 》
- 《 Careful analysis mmap: What is it? Why? How to use it? 》
- LWN: fault()
Extended reading :《dma-buf from the shallower to the deeper ( Four ) —— mmap》
A summary of the article :DRM (Direct Rendering Manager) Learn about
边栏推荐
- 使用MongoDB官方go库操作MongoDB原创
- 二分查找的理解
- Vulnhub[DC3]
- TensorFlow求梯度时提示TypeError: unsupported operand type(s) for *: ‘float‘ and ‘NoneType‘
- Deep interest evolution network for click through rate prediction
- 118. 杨辉三角(动态规划)
- App中快速复用微信登录授权的一种方法
- 一种好用、易上手的小程序IDE
- 字节飞书人力资源套件三面
- String s = null ; String s = new String(); String s = "; what is the difference between string s?
猜你喜欢
Schedule update | 2022 Microsoft and Intel hacker song competition is in hot registration
JDBC快速入門教程
USB转串口那些事儿—最大峰值串口波特率VS连续通信最高波特率
The server time zone value ‘� й ��� ʱ ��‘ is unrecognized or represents more than one time zone. ......
C operation database added business data value content case school table
NixOS 22.05安装过程记录
vant3+ts 封装uploader上传图片组件
文章名字
1.5 what is an architect (serialization)
Arm64 stack backtracking
随机推荐
office应用程序无法正常启动0xc0000142
grpc-swift入门
SqlServer常用语句及函数
Figma from getting started to giving up
二分查找的理解
LCD参数解释及计算
Hangzhou AI developer meetup registration opens!
Office application cannot start normally 0xc0000142
1.5 什么是架构师(连载)
JDBC快速入门教程
JDBC几个坑
Vulnhub[DC3]
Application case of smart micro 32-bit MCU for server application cooling control
leetcode 674 最长递增子串
小程序+App,低成本获客及活跃的一种技术组合思路
JDBC several pits
关于数据集
406. reconstruct the queue based on height
vant3+ts 封装uploader上传图片组件
String s = null ; String s = new String();String s =““ ;String s ;有什么区别?