当前位置:网站首页>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
边栏推荐
- 73. 矩阵置零(标记法)
- Project training of Software College of Shandong University - Innovation Training - network attack and defense shooting range experimental platform of Software College of Shandong University (XXV) - p
- 电控学习 第二周
- Authorization in Golang ProjectUseing Casbin
- 赛程更新| 2022微软与英特尔黑客松大赛火热报名中
- EasyCode模板
- Figma from getting started to giving up
- Application case of smart micro 32-bit MCU for server application cooling control
- EASYCODE template
- Vant3+ts encapsulates uploader upload image component
猜你喜欢

文章名字

消息队列存储消息数据的 MySQL 表格

进阶之大山-asp.net core 路由程序基础使用演示0.1

Advanced mountain -asp Net core router basic use demo 0.1

Lightweight and convenient small program to app technology solution to realize interconnection with wechat / traffic app

全局锁、表锁、行锁

用好IDE,研发效能提速100%

Click the list page of vant3+ts+pinia tab to enter the details. The tab on the details page is highlighted in the original position, and the refresh highlight is in the first item by default

C operation database added business data value content case school table

Article name
随机推荐
TensorFlow从网络读取数据
赛程更新| 2022微软与英特尔黑客松大赛火热报名中
[CSP]202012-2期末预测之最佳阈值
Guitar Pro tutorial how to set up a MIDI keyboard
ssm常用到的依赖
566. reshaping the matrix
Two ways of tensorflow2 training data sets
迄今微软不同时期发布的SQL Server各版本之间的大致区别,供参考查阅
Resttemplateconfig configuration print request response log under soringboot
idea 常用快捷键
C# 业务流水号规则生成组件
关于数据集
channel原创
Reconstruction -- sort out and decompose the inheritance system
Is Huishang futures company reliable in opening accounts and safe in trading?
Lambda - 1
Arm64栈回溯
Vant3 +ts packaged simple step advancer component
Vant3+ts encapsulates uploader upload image component
leetcode 674 最长递增子串