Linux内核开发之内存与I/O访问(四)

内核驱动之I/O内存访问 内核驱动之I/O内存访问 I/O 内存访问流程: 1. request_mem_region()  申请IO内存 2.ioremap() 将物理地址映射到虚拟地址 3.ioread8() 、ioread16()、ioread32()、iowrite8()、iowrite16()、iowrite32() 读写 4.iounmap() 释放虚拟内存 5.release_mem_region 阅读详情

时间:晚上7点

地点:寝室中..

“小王,今天就不多话了,接着昨天没讲完的,不然连不起来了,都..”我催促着。

  上节讲到kmalloc()申请的内存若要被映射到用户空间可以通过mem_map_reserve()设置为保留后进行。具体怎么操作呢,给你一个模版吧:

// 内核模块加载函数
int __init kmalloc_map_init(void)
{
    ../申请设备号,添加cedv结构体
  buffer = kmalloc(BUF_SIZE, GFP_KERNEL); //申请buffer
  for(page = virt_to_page(buffer); page< virt_to_page(buffer+BUF_SIZE); page++)
  {
     mem_map_reserve(page);  //置业为保留
  }
}
//mmap()函数
static int kmalloc_map_mmap(struct file *filp, struct vm_area_struct *vma)
{
    unsigned long page, pos;
    unsigned long start = (unsigned long)vma->start;
    unsigned long size = (unsigned long)(vma->end - vma->start);
    printk(KERN_INFO, "mmaptest_mmap called\n");
    if(size > BUF_SIZE)  //用户要映射的区域太大
        return - EINVAL;
    pos = (unsigned long)buffer;
    while(size > 0)   //映射buffer中的所有页
    {
        page = virt_to_phys((void *)pos);
        if(remap_page_range(start, page, PAGE_SIZE, PAGE_SHARRED))
            return -EAGAIN;
        start += PAGE_SIZE;
        pos +=PAGE_SIZE;
        size -= PAGE_SIZE;
    }
    return 0;
}

另外通常,IO内存被映射时需要是nocache的,这个时候应该对vma->vm_page_prot设置nocache标志。如下:

static int xxx_nocache_mmap(struct file *filp, struct vm_area_struct *vma)
{
  vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);   //赋nocache标志
  vma->vm_pgoff = ((u32)map_start >> PAGE_SHIFT);
  if(rempa_pfn_range(vma, vma->vm_start, vma->vm_pgoff, vma->vm_end - vm_start, vma->vm_page_prot));
     return - EAGGIN;
  return 0;
}

这段代码中的pgprot_noncached()是一个宏,它实际上禁止了相关页的cache和写缓冲(write buffer),另外一个稍微少的一些限制的宏是:

#define pgprot_writecombine(prot)  __pgprot(pgprot_val (prot) & –L_PTE_CACHEABLE);    它则没有禁止写缓冲

而除了rempa_pfn_range()外,在驱动程序中实现VMA的nopage()函数通常可以为设备提供更加灵活的内存映射途径。当发生缺页时,nopage()会被内核自动调用,。这是因为,当发生缺页异常时,系统会经过如下处理过程:

1)找到缺页的虚拟地址所在的VMA             2)如果必要,分配中间页目录表和页表              

3)如果页表项对应的物理页表不存在,则调用这个VMA的nopage()方法,它返回物理页面的页描述符。

4)将物理页面的地址填充到页表中。

实现nopage后,用户空间可以通过mremap()系统调用重新绑定映射区所绑定的地址,下面给出一个在设备驱动中使用nopage()的典型范例:

static int xxx_mmap(struct file *filp, struct vm_area_struct *vma);
{
     unsigned long offset = vma->vm_pgoff << PAGE_OFFSET;
     if(offset >= _ _pa(high_memory) || (filp->flags &O_SYNC))
             vma->vm_flags |=VM_IO;
     vma->vm_ops = &xxx_nopage_vm_ops;
     xxx_vma_open(vma);
     return 0;
}
struct page *xxx_vma_nopage(struct vm_area_struct *vma, unsigned long address, int *type)
{
   struct page *pageptr;
   unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
   unsigned long physaddr = address - vma->vm_start + offset;   //物理内存
   unsigned long pageframe = physaddr >> PAGE_SHIFT;  //页帧号
   if(!pfn_valid(pageframe))   //页帧号有效
      return NOPAGE_SIGBUS;
   pageptr = pfn_to_page(pageframe);    //页帧号->页描述符
   get_page(pageptr);   //获得页,增加页的使用计数
   if(type)
      *type = VM_FAULT_MINOR;
   return pageptr;    //返回页描述符
}

上述函数对常规内存进行映射,返回一个页描述符,可用于扩大或缩小映射的内存区域,由此可见,nopage()和remap_pfn_range()一个较大的区别在于remap_pfn

_range()一般用于设备内存映射,而nopage()还可以用于RAM映射。

 

小王,这节和前边一节是在一起看的,我也可以喘口气歇歇了,你慢慢看吧,就不烦你了,晚上吃饭叫上我哈..

访问I/O内存和I/O端口设备 前面为了写pwm驱动,仔细研究了下I/O内存和I/O端口设备的区别,以及访问方式。不过,其实也没必要纠结这个了,因为现在绝大部分设备都使用I/O内存映射的。 I/O独立编址和I/O统一编址         首先有两个概念:I/O独立编址和I/O统一编址;记住这两种编址方式都是由CPU架构决定的。         I/O独立编址:应该只有X86处理器才是I/O独立编址,其他的处理器 阅读详情

相关推荐

第11章 内存与IO访问之设备IO端口和I/O内存的访问

11.4 设备I/O端口和I/O内存的访问    设备通常会提供一组寄存器来控制设备、读写设备和获取设备状态,即控制寄存器、数据寄存器和状态寄存器。这些寄存器可能位于I/O空间中,也可能位于内存空间中。当寄存器位于I/O空间时,被称为I/O端口;当寄存器位于内存空间时,对应的内存空间被称为I/O内存。11.4.1 Linux I/O端口和I/O内存访问接口1.I/O端口    在Linux设备驱动...

xiezhi123456的博客 3205

linux中的DMA提速1:各种内存分配验证

linux中的DMA提速1:各种内存分配验证

3914

Linux设备驱动之I/O端口与I/O内存

从CPU连出来一把线:数据总线、地址总线、控制总线,这把线上挂着N个接口,有相同的,有不同的,名字叫做存储器接口、中断控制接口、DMA接口、并行接口、串行接口、AD接口……一个设备要想接入,就用自己的接口和总线上的某个匹配接口对接……于是总线上出现了各种设备:内存、硬盘,鼠标、键盘,显示器…… 对于CPU而言,如果它要发数据到某个设备,其实是发到对应的接口,接口电路里有多个寄存器(也称为端口

u014379540的博客 1992

一文读懂 Linux mmap 内存映射

mmap(memory map)即内存映射,用于将一个文件或设备映射到进程的地址空间,或者创建匿名的内存映射。请注意,虽然 mmap() 最初是为映射文件而设计的,但它实际上是一个通用映射工具。它可用于将任何适当的对象(例如内存、文件、设备等)映射到进程的地址空间。以文件映射到内存为例,实现这样的映射后,进程虚拟地址空间中一段内存地址将与文件磁盘地址一一对应,进程就可以采用指针的方式读写这段内存,系统会自动回写脏页到对应的磁盘文件。

Doublelv 的博客专栏。 9678

从零开始:手把手教你规划与部署华为FusionCompute虚拟化平台(含网络规划避坑指南)

本文详细介绍了华为FusionCompute虚拟化平台的规划与部署流程,特别针对网络规划中的常见问题提供了避坑指南。从硬件软件清单检查、网络平面配置到VRM部署方案选择,帮助用户高效完成部署并优化性能,适用于云计算环境中的虚拟化平台搭建。

weixin_28693447的博客 243

逆向实战:从x-mini签名到RPC调用,Frida动态分析小红书加密协议

本文通过实战案例,详细拆解了小红书App的加密协议逆向分析过程。从识别x-mini签名等关键参数入手,结合静态分析与Frida动态Hook技术,追踪到核心的RPC调用入口,并最终封装成可独立调用的RPC函数,为安全研究和协议理解提供了完整的技术路径。

moss5的博客 1029

解读Linux零拷贝之mmap

文章目录0x01 内核态mmap0x02 用户态mmap0x03 映射I/O内存关闭Cache0x04 利用/dev/mem进行mmap 0x01 内核态mmap 内核态mmap函数如下,vm_area_struct 结构体记录一片虚存区域,在一定范围内的页将被映射至该区域内。 static int rdma_mmap(struct file *fp, struct vm_area_struct *vma) 在驱动中只需要为用户空间虚拟地址和物理地址建立新的页表即可完成映射。 remap_pfn_rang

qq_40807206的博客 2924

HMMER实战:从零部署到序列分析

本文详细介绍了HMMER工具的安装与使用,从源码编译到环境配置,再到核心工具hmmbuild、hmmsearch等的实战应用。通过球蛋白序列分析案例,展示了HMMER在生物信息学中的强大功能,帮助读者快速掌握序列分析技巧。

weixin_42529366的博客 251

mremap()

mremap() 扩大/缩小现有内存映射,flags参数还可以控制??? #define_GNU_SOURCE #include<unistd.h> #include<sys/mman.h> void * mremap(void *old_address, size_t old_size , size_t new_size, int flags.../* void *new_address */); 参数 old_address:旧地址已经被page aligned页对齐 o

weixin_41540614的博客 3609

高通平台Android 无线 UWB 开发全解析:UWB系统设计、天线与校准全流程指南

为使 UWB 系统达到目标性能,在整个开发流程中遵循一套设计最佳实践至关重要。系统架构:需基于飞行时间(ToF)功能的基准方案(POR)定义系统框图,这是整体系统架构的基础。天线布局:天线位置对性能影响极大,需尽可能贴近 UWB 芯片,以减少信号损耗、保持高传输效率。器件选型:需谨慎选择元器件,推荐使用单刀双掷(SPDT)或双刀双掷(DPDT)开关、UWB 带通滤波器射频同轴测试接头,以保障信号传输路径与测试能力。原理图优化:原理图开发阶段,走线损耗优化极为关键。

专业开发者的博客,一个从事Android WiFi和蓝牙的工程师 171

图解电动汽车:电动汽车主要参数

动力性指标 汽车的动力性指标主要有最高车速、加速时间、最大爬坡等,体现了汽车在行驶过程中能达到的极限运动水平。对于电动汽车,其动力性由搭载的驱动电动机决定,主要的参数包括最大扭矩、额定功率、最大功率、最大转速等。 功率是指物体在单位时间内所做的功的多少,是描述做功快慢的物理量,单位是 kW。 扭矩是指机械元件转动的力矩,也称转矩,表示转动力量的大小,单位是 N·m。 转速是指发动机/电动机的转速,的单位是 rpm,即转每分钟。额定转速是指在额定功率下电动机的转速,最大转速则是在最大功率下电动机的转速。

程序员「阿基米东」的编程之旅 2万+

【Linux设备驱动】中的内存管理与I/O访问

通过对Linux设备驱动中的内存管理和I/O访问的深入探讨,我们了解了这些技术的重要性及其背后的实现原理。合理的内存管理可以提升驱动程序的性能和系统的稳定性;高效的I/O访问则能够加速设备与内核之间的数据交换。通过使用内核提供的API和工具,我们可以构建出既高效又可靠的Linux设备驱动程序。希望本文能够帮助读者更好地理解和掌握Linux设备驱动开发的关键技术。

极客代码 1581

最优化方法与数学建模

在本篇博客中,我们将探讨最优化方法在数学建模中的应用。首先,我们将介绍几种常见的最优化方法,如梯度下降、牛顿法和遗传算法。接着,我们将详细阐述这些方法的原理和算法。最后,我们将通过一个数学建模案例,展示如何使用Matlab实现这些方法。本文旨在为大家提供一个清晰的思路,以便更好地理解和应用最优化方法。

YOLO 439

Linux 内存与I/O访问

内存空间与I/O空间

Dylan的博客 855

PCB Layout工程师核心能力与实战进阶指南

PCB Layout是电子硬件从原理图到物理实现的关键环节,本质是将电路逻辑转化为受电磁场、热力学与制造工艺约束的三维空间结构。其设计质量直接决定信号完整性(SI)、电源完整性(PI)和电磁兼容性(EMC)等核心性能指标。随着高速接口(如PCIe Gen5、USB3.2)、高密度封装(BGA微间距、HDI)及车规/工业级可靠性要求提升,Layout已从‘连线’演进为多目标协同优化的系统工程。掌握Altium Designer等EDA工具、理解叠层设计与DFM规则、具备SI/PI仿真意识,并能贯通芯片Data

weixin_42589700的博客 87

fanuc机器人KAREL中 函数的应用

本次课程讲解编程的思路。很多的同学都玩过积木,一个一个的模块逐渐累积起来,通过彼此之间的相互联系,最终形成一个完整的整体。其实编程也是这样。 将一个对象根据其特点进行模块化拆分,尤其是一些特点非常相似的内容,将其变成一个模块。然后通过传递参数,实现不同的功能,这就是模块化编程。

haier123888的博客 2744

【Linux驱动开发】Linux设备驱动中内存与I/O访问的底层机制及技术实现深度解析

本文深入探讨了Linux设备驱动开发中内存与I/O访问的核心技术。主要内容包括:1) 内存访问原理,详细解析MMU的页表结构、地址转换过程和内存映射类型;2) 内核地址空间划分机制,重点介绍DMA内存区域管理;3) 内存屏障与缓存一致性实现;4) 直接内存访问(DMA)操作技术,包括Scatter-Gather机制实现。通过剖析Linux 5.x内核源码,揭示了底层硬件访问的关键机制和优化技术,为设备驱动开发人员提供了深入理解内核内存与I/O管理的重要参考。

love131452098的博客 1117

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

【Linux驱动设备开发详解】11.内存与I/O访问

外设可处于CPU的I/O空间和内存空间,除x86外,嵌入式处理器一般只存在内存空间。在Linux系统中,为I/O内存和I/O端口的访问提供了一套同一的方法,访问流程一般为"申请资源->映射->访问->去映射->释放资源"对于有MMU的处理器而言, Linux系统的内部布局比较复杂, 可直接映射的物理内存称为常规内存,超出部分为高端内存。kmalloc() 和__get_free_pages() 申请的内存在物理上连续, 而vmalloc() 申请的内存在物理上不连续。

qq_38089448的博客 985

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Linux设备驱动程序学习(八)——内存与I/O访问

内存空间和I/O空间   在X86处理器中存在着I/O空间的概念,I/O空间是相对于内存空间而言的,它通过特定的指令in、out来访问。端口号标识了外设的寄存器地址。Intel语法中的in、out指令格式如下: IN 累加器, {端口号│DX} OUT {端口号│DX},累加器   目前,大多数嵌入式微控制器(如ARM、PowerPC等)中并不提供I/O空间,而仅存在内存空间。内存空间可以直接通...

Alex_wu的博客 3058

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Linux 内核源码分析---I/O 体系结构与访问设备

学习记录

学习记录 1845

深入理解 Linux 内核中的 __iomem:I/O 内存访问的 “安全标签”

_iomem// 兼容模式下的定义(如部分编译器不支持扩展属性)但这只是表象。// 主流架构下的实际定义无论形式如何,__iomem的本质是一个用于标记 “I/O 内存指针” 的类型限定符。它不分配内存,不修改指针值,只为编译器和开发者提供 “类型元信息”。__iomem。

2301_80317247的博客 1253

Linux学习一 I/O内存分配与I/O访问

C++中有些用的二联符和三联符 ??=  表示 #    ??)   表示]      ??(   表示[ ??!  表示 |     ??/   表示\      ??-   表示~ ??>  表示 }     ?? %>  表示 }      bitor  表示|     or_eq  表示|= :>  表示 ]      xor    表示^     not    

ShyBoyes的专栏 1302

linux驱动开发--I/O内存的访问流程

设备通常会提供一组寄存器来用于控制设备、读写设备和获取设备状态,既控制寄存器、数据寄存器和状态寄存器、这些寄存器可能位于I/O空间,也可能位于内存空间。当位于I/O空间时,通常被称为I/O端口,位于内存空间时,对应的内存空间被称为I/O内存(现在一般都是统一编址) 1、对于I/O端口 有专门的函数提供读取端口上的数据,例如读写字节端口(8字节宽) Unsigned inb(unsigned

鱼思故渊的专栏 2168

Linux内核架构浅谈63 - Linux设备驱动资源分配:I/O内存与I/O端口的管理

本文深入解析了Linux设备驱动开发中I/O内存与I/O端口的管理机制。I/O端口通过独立地址空间实现硬件交互,需使用专用指令;I/O内存则将外设寄存器映射到内存地址空间。文章详细介绍了端口资源的申请与释放(request_region/release_region)、内存映射方法(ioremap/iounmap)及专用访问接口(inb/ioread等),并强调资源管理的重要性,包括通过/proc文件系统调试资源占用。开发中应遵循"先申请后使用、适配场景选择接口、专用方法访问、及时释放资源&quo

文石_2009的博客 754
上一篇: Linux内核开发之内存与I/O访问(三)
下一篇: Linux内核开发之内存与I/O访问(五)
wustdatamining
博客等级 码龄15年 12粉丝 81原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值