内存访问与映射是linux驱动常见操作,操作硬件时离不开内存的映射,本章比较重要。

 11.1 CPU与内存、I/O

  • 目前的嵌入式处理器,都不提供专门的I/O空间,而仅存在内存空间;各种外设寄存器都直接映射到内存空间,可以通过指针直接访问
  • x86一般提供专门的I/O空间, 用特殊指令访问这些空间;
  • CPU访问虚拟地址,MMU把虚拟地址转换为物理地址。MMU的知识点还是比较多,也比较复杂,可以看看ARM的介绍性文档,例如“DEN0013*_cortex_a_series_PG_Programmer’s Guide”,对cache和MMU的介绍比较详细,可以作为入门资料,此处不展开了。

 11.2 linux内存管理

  • 共4GB空间,0~3G为用户空间,3G~4G为内核空间;
  • 用户空间和内核空间都是虚拟地址
  • 用户空间每个进程单独映射,互不干扰
  • 内核空间内核自己映射,所有进程共享,独立于

  

  linux使用buddy算法进行这些区域的管理,以2^n为单位进行管理,文件/proc/buddyinfo显示空闲的页数,依次为2^0,2^1,2^2的剩余页面个数。

$ cat /proc/buddyinfo
Node , zone DMA
Node , zone DMA32
              2^0 2^1 2^2 2^3 ......对应的空闲页面数

 !!! 11.3 内存存取

  11.3.1 用户空间内存申请

  • C库实现的,malloc()与free()成对儿使用,C库的malloc一般通过brk和mmap两个系统调用来实现的;
  • malloc是按需分配,也叫写时分配,写时,会发生MMU页错误,然后进入中断进行内存分配。
#include <malloc.h>

extern void *malloc (size_t __size);
返回值:
  NULL:出错

  11.3.2 内核空间内存申请

    11.3.2.1 kmalloc 

实现是调用了更底层的__get_free_pages()函数,flags的前导GFP_也是这个函数的缩写。 kmalloc申请的是连续内存

#include <linux/slab.h>

/**
* kmalloc - allocate memory
* @size: how many bytes of memory are required.
* @flags: the type of memory to allocate.
*
* kmalloc is the normal method of allocating memory
* for objects smaller than page size in the kernel.
*
* The @flags argument may be one of:
*
* %GFP_USER - Allocate memory on behalf of user. May sleep.
*
* %GFP_KERNEL - Allocate normal kernel ram. May sleep. 可能阻塞
*
* %GFP_ATOMIC - Allocation will not sleep. May use emergency pools.
* For example, use this inside interrupt handlers.
* 在中断处理函数、tasklet和内核定时器等非进程上下文不能阻塞,或者进程上下文但持有自旋锁时也不能阻塞,就需要用这个flag申请内存了。
*
* %GFP_HIGHUSER - Allocate pages from high memory.
*
* %GFP_NOIO - Do not do any I/O at all while trying to get memory.
*
* %GFP_NOFS - Do not make any fs calls while trying to get memory.
*
* %GFP_NOWAIT - Allocation will not sleep.
*
* %__GFP_THISNODE - Allocate node-local memory only.
*
* %GFP_DMA - Allocation suitable for DMA.
* Should only be used for kmalloc() caches. Otherwise, use a
* slab created with SLAB_DMA.
*
* Also it is possible to set different flags by OR'ing
* in one or more of the following additional @flags:
*
* %__GFP_COLD - Request cache-cold pages instead of
* trying to return cache-warm pages.
*
* %__GFP_HIGH - This allocation has high priority and may use emergency pools.
*
* %__GFP_NOFAIL - Indicate that this allocation is in no way allowed to fail
* (think twice before using).
*
* %__GFP_NORETRY - If memory is not immediately available,
* then give up at once.
*
* %__GFP_NOWARN - If allocation fails, don't issue any warnings.
*
* %__GFP_REPEAT - If allocation fails initially, try once more before failing.
*
* There are other flags available as well, but these are not intended
* for general use, and so are not documented here. For a full list of
* potential flags, always refer to linux/gfp.h.
*/
static __always_inline void *kmalloc(size_t size, gfp_t flags);
void kfree(const void *);  // 注意不要忘记释放

  11.3.2.2 __get_free_pages

  linux底层分配内存的方法,buddy算法,2^n为单位。用的比较少,不写了

  11.3.2.3 vmalloc

  大量内存映射,开销较大, 实际调用GFP_KERNEL和kmalloc实现,可能引起阻塞。

#include <linux/vmalloc.h>

void * vmalloc( unsigned long size );  
void * vfree( const void * addr );

  11.3.2.4 slab

  用的少,不说了。

 !!! 11.4 设备I/O端口和I/O内存的访问

    概念:

  • x86:设备的多个寄存器如果位于I/O空间,则被称为I/O端口;
  • ARM/PPC等主流嵌入式:设备的多个寄存器如果位于内存空间,则被称为I/O内存;

    11.4.1  I/O端口与I/O内存访问

   11.4.1.1 I/O端口

    inb/outb/inw/outw等,嵌入式基本没用。

     11.4.1.2 I/O内存

    在使用前,先要通过ioremap()函数,将物理地址转换为虚拟地址上,才能访问。转换的虚拟地址位于vmalloc区。

    ioremap()函数不进行内存分配,但需要建立新的页表(vmalloc同时进行内存分配和新建页表)。

#include <asm/io.h>

/* ioremap映射后必须使用iounmap解除映射 */
#define ioremap(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE)
#define ioremap_nocache(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE)
#define ioremap_cache(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE_CACHED)
#define ioremap_wc(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE_WC)
#define iounmap __arm_iounmap void __iomem *__arm_ioremap(phys_addr_t phys_addr, size_t size, unsigned int mtype);  
void __arm_iounmap(volatile void __iomem *addr); /* 有一个ioremap的变体,退出或出错不需要解除映射 */
void __iomem *devm_ioremap(struct device *dev, resource_size_t offset,unsigned long size)

  带devm的跟dev挂钩,设备(device)被detached或者驱动(driver)卸载(unloaded)时,内存会被自释放

    映射以后,理论上可以直接通过虚拟地址的指针操作访问IO内存了,不过linux提供了一套更好的API,应使用这套API访问IO内存。

【注】没有_relaxed后缀的接口,会进行额外的内存屏障操作

#include <asm/io.h>
#define readb_relaxed(c) ({ u8 __r = __raw_readb(c); __r; })
#define readw_relaxed(c) ({ u16 __r = le16_to_cpu((__force __le16) \
__raw_readw(c)); __r; })
#define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32) \
__raw_readl(c)); __r; }) #define writeb_relaxed(v,c) __raw_writeb(v,c)
#define writew_relaxed(v,c) __raw_writew((__force u16) cpu_to_le16(v),c)
#define writel_relaxed(v,c) __raw_writel((__force u32) cpu_to_le32(v),c) #define readb(c) ({ u8 __v = readb_relaxed(c); __iormb(); __v; })
#define readw(c) ({ u16 __v = readw_relaxed(c); __iormb(); __v; })
#define readl(c) ({ u32 __v = readl_relaxed(c); __iormb(); __v; }) #define writeb(v,c) ({ __iowmb(); writeb_relaxed(v,c); })
#define writew(v,c) ({ __iowmb(); writew_relaxed(v,c); })
#define writel(v,c) ({ __iowmb(); writel_relaxed(v,c); })

  11.4.2  申请与释放I/O端口与I/O内存

   11.4.2.1 I/O端口申请

   11.4.2.2 I/O内存申请

  【注】如果request相关函数返回NULL,则说明申请失败。 request并进行页表映射,只是告诉内核我占用了这段物理地址,别人不能再占用了。  相当于内核提供了一种类似互斥的操作,驱动可以充分利用此特性,自然的实现共享资源的互斥访问。理论上,不进行request申请操作,直接ioremap应该也是可以的。

#include <linux/ioport.h>

#define request_region(start,n,name)        __request_region(&ioport_resource, (start), (n), (name), 0)  // IO端口
#define release_region(start,n) __release_region(&ioport_resource, (start), (n)) #define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name), 0)  // IO内存
#define release_mem_region(start,n) __release_region(&iomem_resource, (start), (n)) struct resource * __request_region(struct resource *,resource_size_t start,resource_size_t n,const char *name, int flags);
void __release_region(struct resource *parent, resource_size_t start,resource_size_t n)

  11.4.3  I/O端口与I/O内存访问流程

  11.4.4  将设备地址映射到用户空间

   显卡、显示器那类的驱动比较有用,后续添加。

 11.5 I/O内存静态映射

    不太重要

 11.6 DMA

    用时添加

《linux设备驱动开发详解》笔记——11内存与IO访问的更多相关文章

  1. Linux设备驱动开发详解-Note(11)--- Linux 文件系统与设备文件系统(3)

    Linux 文件系统与设备文件系统(3) 成于坚持,败于止步 sysfs 文件系统与 Linux 设备模型 1.sysfs 文件系统 Linux 2.6 内核引入了 sysfs 文件系统,sysfs ...

  2. linux设备驱动开发详解 笔记

      在目录的 Makefile 中关于 RTC_DRV_S3C 的编译脚本为: obj -$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o 上述脚本意味着如果 RTC_DRV_S3 ...

  3. Linux设备驱动开发详解

    Linux设备驱动开发详解 http://download.csdn.net/detail/wuyouzi067/9581380

  4. 《Linux设备驱动开发详解(第2版)》配套视频登录51cto教育频道

    http://edu.51cto.com/course/course_id-379-page-1.html http://edu.51cto.com/course/course_id-379-page ...

  5. 《linux设备驱动开发详解》笔记——14 linux网络设备驱动

    14.1 网络设备驱动结构 网络协议接口层:硬件无关,标准收发函数dev_queue_xmit()和netif_rx();  注意,netif_rx是将接收到的数据给上层,有时也在驱动收到数据以后调用 ...

  6. 《linux设备驱动开发详解》笔记——6字符设备驱动

    6.1 字符设备驱动结构 先看看字符设备驱动的架构: 6.1.1 cdev cdev结构体是字符设备的核心数据结构,用于描述一个字符设备,cdev定义如下: #include <linux/cd ...

  7. 《linux设备驱动开发详解》笔记——15 linux i2c驱动

    结合实际代码和书中描述,可能跟书上有一定出入.本文后续芯片相关代码参考ZYNQ. 15.1 总体结构 如下图,i2c驱动分为如下几个重要模块 核心层core,完成i2c总线.设备.驱动模型,对用户提供 ...

  8. 《linux设备驱动开发详解》笔记——12linux设备驱动的软件架构思想

    本章重点讲解思想.思想.思想. 12.1 linux驱动的软件架构 下述三种思想,在linux的spi.iic.usb等复杂驱动里广泛使用.后面几节分别对这些思想进行详细说明. 思想1:驱动与设备分离 ...

  9. Linux设备驱动开发详解-Note(5)---Linux 内核及内核编程(1)

    Linux 内核及内核编程(1) 成于坚持,败于止步 Linux 2.6 内核的特点 Linux 2.6 相对于 Linux 2.4 有相当大的改进,主要体现在如下几个方面. 1.新的调度器 2.6 ...

随机推荐

  1. Centos 7.x 安装 MongoDB

    官方安装资料:点击直达 本次以Centos为安装主机 1:首先先导入MongoDB的yum源,因为Centos默认是没有MongoDB的yum源,创建文件:/etc/yum.repos.d/mongo ...

  2. swiper 解决动态加载数据滑动失效的问题

    两种解决方法 第一种解决办法: success:function(result){ var resultdata =eval("("+result+")"); ...

  3. HDU-2182-Frog

    链接:https://vjudge.net/problem/HDU-2182 题意: 有一只青蛙,有n个节点,开始时在1节点,有k次往右跳的机会,每次跳的距离是a-b之间. 每个节点有一个值,到达那个 ...

  4. Shortest Path Codeforces - 59E || 洛谷P1811 最短路_NOI导刊2011提高(01)

    https://codeforces.com/contest/59/problem/E 原来以为不会..看了题解发现貌似自己其实是会的? 就是拆点最短路..拆成n^2个点,每个点用(i,j)表示,表示 ...

  5. IDEA自定义设置快捷键输出你想要的语句!

    转载,侵权必删 用Eclipse时间长了, 就习惯之前的快捷键! 当然, IDEA不愧是Java开发的”利器”! 写起代码就是一个字 – “爽”! 建议大家可以去尝试一下! 当然, 在IDEA中输出S ...

  6. 《javascript设计模式》笔记之第七章:工厂模式

    在读了这章之后,根据我个人现在的理解,工厂模式就是:将一个类或者一个方法称为一个工厂,然后再将一些模块交给这个工厂,让这个工厂按照给它的不同模块产出不同的实例. 下面为正文: 一:简单工厂: 例子: ...

  7. .NET Core 1.0 CentOS7 尝试(三、使用VSCode创建一个Web应用)

    参考地址:https://docs.asp.net/en/latest/tutorials/your-first-mac-aspnet.html 一.使用VSCode创建一个目录FirstWebApp ...

  8. Windows系统下如何优化Android Studio

    Android Studio将是Android开发大势所趋. 安装Android Studio时需注意的细节: · 找到安装目录bin目录下idea.properties 最后一行加入:    dis ...

  9. SqlServer表和excel数据批量复制方法

    SqlServer表和excel数据批量复制方法 一.SqlServer表数据复制到excel方法: 1.新建查询,用sql语句把表数据读出来 2.然后,选择数据,右键“复制”(如果需要表字段名称,则 ...

  10. HDU 4044 GeoDefense (树形DP,混合经典)

    题意: 给一棵n个节点的树,点1为敌方基地,叶子结点都为我方阵地.我们可以在每个结点安放炸弹,每点至多放一个,每个结点有ki种炸弹可选,且每种炸弹有一个花费和一个攻击力(1点攻击力使敌人掉1点hp). ...