Kmap

kmap的实现分析与实验 kmap的实现分析 kmap的实验 阅读详情

Kmap


void *kmap(struct page *page)

这个函数在高端内存或低端内存上都能用。如果page结构对应的是低端内存中的一页,函数只会单纯的返回该页的虚拟地址。如果页位于高端内存,则会建立一个永久映射,再返回地址。这个函数可以睡眠,因此kmap()只能在进程上下文中。
因为允许永久映射是有限的,当不需要高端内存时,应该接触映射,可以通过以下函数解除。

void kunmap(struct page *page)

高端内存

Linux将内核地址空间划分为三部分ZONE_DMA ZONE_NORMAL ZONE_HIGHMEM,高端内存HIGH_MEM地址空间范围为 0xF8000000 ~ 0xFFFFFFFF(896MB~1024MB)。那么如内核是如何借助128MB高端内存地址空间是如何实现访问可以所有物理内存?
当内核想访问高于896MB物理地址内存时,从0xF8000000 ~ 0xFFFFFFFF地址空间范围内找一段相应大小空闲的逻辑地址空间,借用一会。借用这段逻辑地址空间,建立映射到想访问的那段物理内存(即填充内核PTE页面表),临时用一会,用完后归还。这样别人也可以借用这段地址空间访问其他物理内存,实现了使用有限的地址空间,访问所有所有物理内存。如下图。
这里写图片描述

例 如内核想访问2G开始的一段大小为1MB的物理内存,即物理地址范围为0×80000000 ~ 0x800FFFFF。访问之前先找到一段1MB大小的空闲地址空间,假设找到的空闲地址空间为0xF8700000 ~ 0xF87FFFFF,用这1MB的逻辑地址空间映射到物理地址空间0×80000000 ~ 0x800FFFFF的内存。映射关系如下:

逻辑地址物理内存地址
0xF87000000×80000000
0xF87000010×80000001
0xF87000020×80000002
……
0xF87FFFFF0x800FFFFF

当内核访问完0×80000000 ~ 0x800FFFFF物理内存后,就将0xF8700000 ~ 0xF87FFFFF内核线性空间释放。这样其他进程或代码也可以使用0xF8700000 ~ 0xF87FFFFF这段地址访问其他物理内存。


具体实现

void *kmap(struct page *page)
{
    might_sleep();
    if (!PageHighMem(page))//如果是低端内存,直接返回内存页对应的虚拟地址。
        return page_address(page);
    return kmap_high(page);//否则 需要进行高端内存映射
}

void *kmap_high(struct page *page)
{
    unsigned long vaddr;

    /*
     * For highmem pages, we can't trust "virtual" until
     * after we have the lock.
     */
    lock_kmap();//防止并发
    vaddr = (unsigned long)page_address(page);//直接进行映射
    if (!vaddr)//如果上一步失败
        vaddr = map_new_virtual(page);//建立新的映射
    pkmap_count[PKMAP_NR(vaddr)]++;//如果建立成功,引用加1,表示已被映射,2表示此映射还有额外的引用
    BUG_ON(pkmap_count[PKMAP_NR(vaddr)] < 2);
    unlock_kmap();
    return (void*) vaddr;
}

static inline unsigned long map_new_virtual(struct page *page)
{
    unsigned long vaddr;
    int count;

start:
    count = LAST_PKMAP;
    /* Find an empty entry */
    for (;;) {
        last_pkmap_nr = (last_pkmap_nr + 1) & LAST_PKMAP_MASK;
        if (!last_pkmap_nr) {
            flush_all_zero_pkmaps();//先解除一部分映射
            count = LAST_PKMAP;
        }
        if (!pkmap_count[last_pkmap_nr])//计数为零 证明没有人在使用
            break;  /* Found a usable entry */
        if (--count)//遍历整个kmap空间,如果不存在未使用的映射,就睡眠等待kunmap
            continue;

        /*
         * Sleep for somebody else to unmap their entries
         */
        {
            DECLARE_WAITQUEUE(wait, current);

            __set_current_state(TASK_UNINTERRUPTIBLE);
            add_wait_queue(&pkmap_map_wait, &wait);
            unlock_kmap();
            schedule();
            remove_wait_queue(&pkmap_map_wait, &wait);
            lock_kmap();

            /* Somebody else might have mapped it while we slept */
            if (page_address(page))
                return (unsigned long)page_address(page);

            /* Re-start */
            goto start;
        }
    }
    vaddr = PKMAP_ADDR(last_pkmap_nr);
    set_pte_at(&init_mm, vaddr,
           &(pkmap_page_table[last_pkmap_nr]), mk_pte(page, kmap_prot));

    pkmap_count[last_pkmap_nr] = 1;
    set_page_address(page, (void *)vaddr);

    return vaddr;
}

实现流程图

这里写图片描述


参考文档

linux 用户空间与内核空间——高端内存详解

Linux内核高端内存管理:kmap机制详解与优化 内存管理是操作系统核心功能之一,其中虚拟地址到物理内存的映射机制尤为关键。在32位Linux系统中,由于地址空间限制,内核需要特殊机制管理超过896MB的物理内存(称为高端内存)。kmap()函数族通过动态建立临时映射,使内核能够访问这些区域。该机制涉及映射池管理、原子上下文支持等关键技术,直接影响系统性能和稳定性。随着64位系统的普及,地址空间限制基本消除,但理解kmap工作原理仍对优化内存密集型应用(如数据库、大数据处理)有重要价值。本文深入解析kmap的实现原理、使用场景及性能优化方法,帮助开发者正确 阅读详情

相关推荐

kMaper.py:CMS 漏洞扫描器 - 基于 Exploit-DB

kMaper.py CMS 漏洞扫描器 - 基于 Exploit-DB

vmap与kmap介绍

vmap与kmap功能介绍,函数作用,以及区别与联系

OS Developer的博客 2524

linux的VMALLOC虚拟地址空间管理

在内核地址空间中为kmap和vmalloc各保留了一段地址空间。linux内核使用vm_struct结构体表示映射的地址空间,并且被组织在链表vmlist中,同时为了快速搜索VMA中一块连续的虚拟地址空间采用了红黑树进行管理,另外根据红黑树的层次结构将红黑树的各节点信息保存在vmap_area_list双向链表中。

linux内存管理:kmap、vmap、ioremap

目录 散列表也是哈希表 kmap实现 page_address_map pkmap_count page_address_slot 哈希函数 kmap函数实现 kmap_init kmap kmap_high page_address map_new_virtual set_page_address kunmap kunmap_high(struct page *page)函数实现 vmap实现 vmap函数 vunmap函数 ioremap ioremap函数 _

RToax 8931

别再怕DRIVER_VERIFIER_DMA_VIOLATION蓝屏:手把手教你用WinDbg分析IOMMU与驱动冲突

本文深入解析DRIVER_VERIFIER_DMA_VIOLATION蓝屏错误,从IOMMU原理到实战排错,手把手教你使用WinDbg分析驱动冲突。通过理解DMA与IOMMU的核心机制、搭建分析环境、解读DMAR表与设备拓扑,最终定位问题驱动并提供解决方案,帮助开发者和IT运维人员有效应对此类系统崩溃问题。

weixin_30298497的博客 804

Gazebo仿真平台模型搭建与修改

ROS里踩过的坑(一)Gazebo仿真平台模型搭建与修改文件讲解Models 文件World文件Launch文件模型编辑可视化编辑配置文件编辑模型展示如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出...

Redglass的博客 1万+

Linux内存管理--高端内存映射之kmap持久内核映射

在x86_32体系结构总, 高于896MB的所有物理内存的范围大都是高端内存, 它并不会永久地或自动映射到内核地址空间, 尽管X86处理器能够寻址物理RAM的范围达到4GB(启用PAE可以寻址64GB), 一旦这些页被分配, 就必须映射到内核的逻辑地址空间上. 在x86_32上, 高端地址的页被映射到内核地址空间(即虚拟地址空间的3GB~4GB)如果需要将高端页帧长期映射(作为持久映射)到内核地址空间中, 必须使用kmap函数. 需要映射的页用指向page的指针指定,作为该函数的参数。

m0_74282605的博客 552

Win10环境借助DockerDesktop部署Open web UI集成DeepSeek

Win10环境借助DockerDesktop部署Open web UI集成DeepSeek,并借助DuckDuckGo实现联网查询

虎鲸不是鱼 1705

高端内存映射之kmap持久内核映射--Linux内存管理(二十)

日期 内核版本 架构 作者 GitHub 优快云 2016-09-29 Linux-4.7 X86 & arm gatieme LinuxDeviceDrivers Linux内存管理 在内核初始化完成之后, 内存管理的责任就由伙伴系统来承担. 伙伴系统基于一种相对简单然而令人吃惊的强大算法.Linux内核使用二进制伙伴算法来管理和分配物理内存页面, 该算

OSKernelLAB(gatieme) 1万+

搭建适用于lammps中opls-aa力场的文件流程

现在我已经解决了以上问题,并且通过我的方法可以实现从空白文档到搭建完成以上全部内容,后期只要细心检查即可。需要的data文件最关键是获得相应阴阳离子的mmol文件,因此问题转化为构建一份mmol文件。主要用到的软件及程序:gaussian09,makemol程序(tranal),opls-aa的参数文件。二面角个数:成角原子序号及对应的参数(这里PF6的结构没有二面角,所以为0)参考文献个数:文献名(空够行数即可,这些是给自己的备忘))和自身体系对应的参考文献,修改或填入对应的参数即可。

baguette的博客 2888

基于Arduino的智能垃圾桶

通过本次简单的Arduino智能垃圾桶小实验可以快速了解Arduino的基本用法 1、材料准备 Arduino UNO HC-SR04超声波模块 SG90舵机 杜邦线 电源 电脑 2、代码分析 电机的控制 #include<Servo.h> #define duoji D5 Servo myduoji; void setup() { myduoji.attach(duoji); //舵机连接 Serial.begin(115200); } void loop() { myduoji.w

weixin_41679960的博客 1万+

关于kmalloc、vmalloc及kmap

 1、  kmalloc()是内核中最常见的内存分配方式,它最终调用伙伴系统的__get_free_pages()函数分配,根据传递给这个函数的flags参数,决定这个函数的分配适合什么场合,如果标志是GFP_KERNEL则仅仅可以用于进程上下文中,如果标志GFP_ATOMIC则可以用于中断上下文或者持有锁的代码段中。kmalloc返回的线形地址是直接映射的,而且用连续物理页满足分配请求,

gxfan的专栏 2万+

基于PPT的三维光路结构示意图绘制实例演示-技术细节

基于PPT的三维光路结构示意图绘制实例演示-技术细节

简单光学 7480

LWN:把atomic kmap改成local kmap!

关注了就能看到更多这么棒的文章哦~Atomic kmaps become localBy Jonathan CorbetNovember 6, 2020DeepL assisted tr...

Linux News搬运工 594

【Unity大规模RTS/攻城战框架】Large Scale Combat System - RTS Sieges深度解析

本文介绍了Unity专业级大规模RTS战斗框架Large Scale Combat System(LSCS)。该系统通过Job System+Burst技术解决了万人级单位的性能问题,提供完整的RTS操作体系、动态阵型系统、战术AI和攻城战功能。其亮点包括可破坏城门、行走城墙、战术AI配置系统,支持URP渲染管线,适用于Total War风格的大规模兵团对战项目。LSCS不仅提供核心战斗系统,还包含UI、小地图等配套模块,是Unity中少有的专业级RTS解决方案,特别适合需要深度战术玩法和大规模战斗的开发者

2403_88403568的博客 1335

使用Transformer实现自动调制识别(RML2018)

image_size = 1024 # resize重置输入大小patch_size = 16 # 从输入图片中将被提取的块大小# 分成 num_patches 个块num_patches = (image_size // patch_size) #(72/6)**2 横着裁剪),],return x})

QAQIknow的博客 1325

Linux kmap和kmap_atomic解析

原文链接:https://blog.youkuaiyun.com/zhanghaiyang9999/article/details/82143032 名为解析,名不符实,简单记录一下。 首先得知道这个函数的主要目的是实现page 到 vaddr的转化。 kmap函数将分配到的高端内存映射到永久内存映射区域(PKMap Region)。 kmap函数不能用于中断处理程序, 因为它可能进入睡眠状态。 ...

z1026544682的专栏 838

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

dma-buf 由浅入深(二) —— kmap / vmap

在上一篇《最简单的 dma-buf 驱动程序》中,我们学习了编写 dma-buf 驱动程序的三个基本步骤,即 dma_buf_ops 、 dma_buf_export_info、 dma_buf_export()。在本篇中,我们将在 exporter-dummy 驱动的基础上,对其 dma_buf_ops 的 kmap / vmap 接口进行扩展,以此来演示这两个接口的使用方法。

hexiaolong2009的专栏 3万+

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

kmap_atomic的细节以及改进

<br />kmap_atomic用于高端内存映射,用于紧急的,短时间的映射,它没有使用任何锁,完全靠一个数学公式来避免混乱,它空间有限且虚拟地址固定,这意味着它映射的内存不能长期被占用而不被unmap,kmap_atomic在效率上要比kmap提升不少,然而它和kmap却不是用于同一场合的。不管怎么说,它的设计是很完美的。<br />      kernel可以在多个cpu上同时运行不同的task,然而它们共同使用一个内存地址空间,也就是说,地址空间对于多个cpu看到的是同一个,kmap_atomic使

TCP/IP 1万+

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

内核 kmap_atomic分析

主要谈三个问题。 1、为什么会有这个函数? 我想主要的原因就是kmap_atomic在效率上要比kmap提升不少。 在kmap函数中,会有如下几个比较耗时的部分: 1)、page_address函数 2)、Sleep for somebody else to unmap their entries 代码如下: 171 ____________DECLARE_WAITQUEUE(wait, current); 173 ______________set_current_state(TASK_UNINTERRU

runshui27的博客 582

kmap的实现分析

kmap的实现分析 kmap/unkmap系统调用是用来映射高端物理内存页到内核地址空间的api函数,他们分配的内核虚拟地址范围属于[PKMAP_BASE,PAGE_OFFSET]即[0xbfe00000,0xc0000000]范围,大小是2M的虚拟空间,为了映射该块虚拟地址,所使用的二级页表的大小刚好是一个物理page的总计是两个pte table(4KB) kmap的调用流程分析: ar

JK198310的专栏 1726

Android内核之物理地址映射到kernel虚拟地址:kmap用法实例(七十七)

本篇目的:Android内核之物理地址映射到kernel虚拟地址:kmap用法实例kmap()函数在Linux内核中的作用是将物理地址映射到内核虚拟地址空间中的一个区域。在Linux内核中,由于内存管理的复杂性,需要经常访问物理地址,但同时又需要在内核虚拟地址空间中进行操作。kmap()函数允许内核通过临时映射的方式在内核虚拟地址空间中访问物理页面,以便执行各种操作,比如数据复制、处理等。

Android系统攻城狮 1329

Linux内核之临时映射内核内存:kmap_atomic用法实例(六十二)

本篇目的:Linux内核之临时映射内核内存:kmap_atomic用法实例kmap_atomic 和 kunmap_atomic 是 Linux 内核中用于在驱动程序中临时映射内核内存的函数。它们通常用于驱动程序中需要在中断上下文中访问内核内存时。

Android系统攻城狮 2146

[Linux内存]永久内存映射kmap

一:kmap()和kunmap()函数 永久内核映射允许内核建立高端页框到内核地址空间的长期映射。他使用主内核页表中一个专门的页表,其页表地址存放在pkmap_page_table中,页表包含512项或1024项, 因此,内核一次最多访问2M或4M的高端内存(地址范围是 4G-8M 到 4G-4M 之间,这个地址空间起叫“内核永久映射空间”或者“永久内核映射空间”)。 kmap()和kunm

知了112的专栏 3668

kmalloc、vmalloc、kmap、malloc的区别

简单的说: kmalloc和vmalloc是分配的是内核的内存,malloc分配的是用户的内存kmalloc保证分配的内存在物理上是连续的,vmalloc保证的是在虚拟地址空间上的连续,malloc不保证任何东西(猜测的,不一定正确)kmalloc能分配的大小有限,vmalloc和malloc能分配的大小相对较大内存只有在要被DMA访问的时候才需要物理上连续vmalloc比kmalloc要慢

michaelcao1980的专栏 5119
上一篇: linux系统调用书写
下一篇: printk浅析
code__L
博客等级 码龄10年 3粉丝 8原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值