当前位置:网站首页>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
边栏推荐
猜你喜欢
随机推荐
Hangzhou AI developer meetup registration opens!
Resttemplateconfig configuration print request response log under soringboot
New media operation material website sharing enables you to create current affairs with half the effort
Make good use of IDE, speed up R & D efficiency by 100%
续2 asp.net core 路由程序基础使用演示0.2 默认控制器数据的获取到
ssm常用到的依赖
利用小程序快速生成App,只需七步
C operation database added business data value content case school table
C# 业务流水号规则生成组件
轻量、便捷的小程序转App技术方案,实现与微信/流量App互联互通
String s = null ; String s = new String(); String s = "; what is the difference between string s?
Sqlserver common statements and functions
Arm64 stack backtracking
Lambda - 1
Use the official go Library of mongodb to operate the original mongodb
SqlServer常用语句及函数
消息队列存储消息数据的 MySQL 表格
Continued 2 asp Net core router basic use demonstration 0.2 acquisition of default controller data
Hangzhou AI developer meetup registration opens!
《用户体验要素:以用户为中心的产品设计》笔记