Linux内核之Binder驱动内存映射实现:binder_update_page_range实例用法(三十八)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!

优质专栏:Audio工程师进阶系列原创干货持续更新中...... 】🚀
优质专栏:多媒体系统工程师系列原创干货持续更新中...... 】🚀
优质视频课程:AAOS车载系统+AOSP14系统攻城狮入门实战课原创干货持续更新中......】🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
更多原创,欢迎关注:Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉

🌻1.前言

本篇目的:Linux内核之binder_update_page_range实例用法

🌻2.Linux内核之binder_update_page_range介绍

  • Android Binder是Android系统中用于进程间通信(IPC)的一种机制。Binder驱动程序负责实现Binder机制的核心功能,包括数据的传递、线程的管理等。在Binder驱动程序中,binder_update_page_range函数是一个重要的函数,用于处理内存映射的相关操作。

🐓2.1 功能概述

  • binder_update_page_range函数主要处理Binder内存映射的更新。在Binder通信中,客户端与服务端通过Binder机制进行数据交换,这些数据通常存储在内核空间的内存中。为了减少数据复制,Binder机制采用了内存映射的方式,将内核空间的内存直接映射到用户空间的内存。binder_update_page_range函数在这个过程中起到了关键作用,它负责更新内存映射的范围,确保数据的一致性和安全性。

🐓2.2 技术细节

  • 当Binder驱动需要更新内存映射的范围时,它会调用binder_update_page_range函数。这个函数接收四个参数:
  1. proc:指向当前进程的Binder进程结构体。
  2. vma:指向内存区域的结构体,代表了用户空间的虚拟内存区域。
  3. start:需要更新的内存区域的起始地址。
  4. end:需要更新的内存区域的结束地址。
  • 函数首先会检查传递的参数是否有效。如果参数无效,函数会直接返回错误代码。
  • 接下来,函数会遍历proc中的buffers链表,查找与startend地址匹配的内存缓冲区。对于找到的每个缓冲区,函数会执行以下操作:
  1. 如果缓冲区是写缓冲区(is_buffer为真),并且当前进程有写权限,则设置相应的页面为可写。
  2. 如果缓冲区是读缓冲区(is_buffer为假),则设置相应的页面为只读。
  3. 如果end地址在缓冲区的范围内,但start地址不在,则设置end地址对应的页面为只读。
  • 在更新页面权限的过程中,函数会使用vm_insert_pagevm_set_page_range等函数来操作虚拟内存区域。

🐓2.3 安全性考虑

  • binder_update_page_range函数在更新内存映射时,会根据进程的权限来设置页面的读写权限。这样可以防止没有权限的进程修改其他进程的数据,从而保证了数据的安全性和一致性。

🐓2.4 总结

  • binder_update_page_range函数是Binder驱动程序中一个关键的函数,它负责更新Binder内存映射的范围,确保数据的一致性和安全性。通过合理的参数检查和页面权限设置,该函数有效地管理了Binder通信过程中的内存映射,提高了Android系统的稳定性和可靠性。

🌻3.代码实例

cpp 复制代码
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>

#define PAGE_SIZE 4096

struct binder_lru_page {
    void *page_ptr;
    struct list_head lru;
    struct binder_alloc *alloc;
};

struct binder_alloc {
    int pid; // 进程ID
    unsigned char buffer[PAGE_SIZE]; // 缓冲区
    struct binder_lru_page *pages; // 内存页面列表
    struct vm_area_struct *vma; // 进程的虚拟内存区域
    struct mm_struct *vma_vm_mm; // 进程的内存描述符
    size_t pages_high; // 分配的页面数量
};

// 模拟 binder_update_page_range 函数,这里简单返回 0 表示成功
static int binder_update_page_range(struct binder_alloc *alloc, int allocate,
                                    void __user *start, void __user *end)
{
    printk(KERN_INFO "Binder update page range called\n");
    return 0;
}

static int __init my_module_init(void)
{
    void __user *start_addr = (void *)0x10000000; // 虚拟地址起始位置
    void __user *end_addr = (void *)(0x10000000 + PAGE_SIZE); // 虚拟地址结束位置
    struct binder_alloc alloc;
    int ret;

    printk(KERN_INFO "Module init\n");

    // 初始化Binder分配器
    alloc.pid = 1; // 设置进程ID
    alloc.pages = kmalloc(sizeof(struct binder_lru_page), GFP_KERNEL);
    if (!alloc.pages) {
        printk(KERN_ERR "Failed to allocate memory for pages\n");
        return -ENOMEM;
    }
    // 调用binder_update_page_range()函数分配内存页面并建立映射
    ret = binder_update_page_range(&alloc, 1, start_addr, end_addr);
    if (ret < 0) {
        printk(KERN_ERR "Failed to map virtual address to physical space\n");
        kfree(alloc.pages);
        return ret;
    }

    printk(KERN_INFO "Mapped virtual address to physical space\n");

    return 0;
}

static void __exit my_module_exit(void)
{
    printk(KERN_INFO "Module exit\n");
}

module_init(my_module_init);
module_exit(my_module_exit);

MODULE_LICENSE("GPL");
  • binder_update_page_range 函数是 Android Binder 驱动中的一个关键部分,用于管理 Binder 缓冲区的内存分配和映射。它的作用包括:

  • 1.分配或释放用户空间和内核空间之间的内存页面。

  • 2.在用户空间和内核空间之间建立内存页面的映射。

  • 3.管理内存页面的LRU(最近最少使用)列表,以便在需要时可以快速访问。

  • binder_update_page_range数的主要功能:

    接收参数 alloc,它是一个指向 binder_alloc 结构体的指针,包含了内存分配器的信息。
    接收参数 allocate,用于指示是分配内存页面还是释放内存页面。
    接收参数 start 和 end,表示用户空间的虚拟地址范围。
    遍历指定范围内的每个页面,检查是否已经分配了相应的页面,如果没有,则进行分配。

  • 对于分配的页面,将其映射到用户空间。

  • 对于释放的页面,将其重新加入到LRU列表中以便重复使用。

  • 最后,根据需要释放锁和资源,并返回适当的错误码。

相关推荐
内核程序员kevin4 天前
使用Go语言开发eBPF入门教程
golang·linux内核·ebpf·系统调用
嵌入式小李3 个月前
Linux并发与竞争
linux·linux内核·并发与竞争
格桑阿sir4 个月前
Docker核心技术:Docker原理之Namespace
linux·docker·容器·linux内核·namespace·隔离性·容器标准
格桑阿sir4 个月前
Docker核心技术:Docker原理之Cgroups
linux·docker·容器·linux内核·cpu·资源限制·cgroups
_三分糖4 个月前
【Linux内核编程--模块机制】
android·linux·运维·服务器·linux内核·c·linux驱动
flashing-c4 个月前
Linux HOOK机制与Netfilter HOOK
linux·运维·网络·linux内核·netfilter·linux hook
橘色的喵5 个月前
针对ARM64嵌入式系统的Linux内核参数优化
性能优化·linux内核·嵌入式·arm·内存管理·arm64·网络优化
回眸&啤酒鸭5 个月前
Linux 内核 (十二)进程间通讯 之 消息队列
linux·linux内核
嵌入式产品侠5 个月前
一起学习Linux内核模块的知识,为编写复杂的设备驱动做好准备
linux内核·内核模块·module
iriczhao7 个月前
【linux kernel】杂项(misc)设备驱动总结
linux·linux内核·c·linux驱动开发