oremap_nocache()函数我想大家都不陌生,现在我就把此函数分析一下,不当之处请大家谅解!

对于EHCI来说它把它本身的寄存器和内存映射到内存中区!但是站在CPU的角度来说,我们无法直接访问这块内存空间,需要将设备的总线地址映射成一个cpu可访问的线性地址!

调用ioremap_nocache()函数之后,返回一个线性地址,此时CPU可以访问设备的内存(已经将其映射到了线性地址空间中了),此时CPU可以使用访问内存的指令访问设备的内存空间(host bridge判断访问物理内存还是设备中的内存),此时我们就可以像访问内存一样来访问设备的内存(寄存器)!

内核版本2.6.22.1

cat /proc/iomem

此时我们就以此区间(0xd8426800 – 0xd8426bff)表示EHCI总线地址区间(机器内存3G)

/**

* ioremap_nocache-map bus memory into CPU space

* @offset:bus address of the memory

* @size:size of the resource to map

*

* ioremap_nocache performs a platform specific sequence of operations to

* make bus memory CPU accessible via the readb/readw/readl/writeb/

* writew/writel functions and the other mmio helpers. The returned

* address is not guaranteed to be usable directly as a virtual

* address.

*

* This version of ioremap ensures that the memory is marked uncachable

* on the CPU as well as honouring existing caching rules from things like

* the PCI bus. Note that there are other caches and buffers on many

* busses. In particular driver authors should read up on PCI writes

*

* It's useful if some control registers are in such an area and

* write combining or read caching is not desirable:

*

* Must be freed with iounmap.

*/

void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size)

{

phys_addr EHCI总线地址

size区间大小(1023)

unsigned long last_addr;

void __iomem *p = __ioremap(phys_addr, size, _PAGE_PCD);

#define _PAGE_PCD0x010

if (!p)

return p;

/* Guaranteed to be > phys_addr, as per __ioremap() */

last_addr = phys_addr + size - 1;

if (last_addr < virt_to_phys(high_memory) - 1) {

struct page *ppage = virt_to_page(__va(phys_addr));

unsigned long npages;

phys_addr &= PAGE_MASK;

/* This might overflow and become zero.. */

last_addr = PAGE_ALIGN(last_addr);

/* .. but that's ok, because modulo-2**n arithmetic will make

* the page-aligned "last - first" come out right.

*/

npages = (last_addr - phys_addr) >> PAGE_SHIFT;

if (change_page_attr(ppage, npages, PAGE_KERNEL_NOCACHE) < 0) {

iounmap(p);

p = NULL;

}

global_flush_tlb();

}

return p;

}

非连续映射地址空间

非连续映射地址空间用于将连续的线性地址映射到不连续的物理地址!同时它也提供了一种访问高物理内存的方法!

内核主要在一下三种情况使用非连续映射地址空间

l映射设备的I/O空间

l为内核模块分配空间

l为交换分区分配空间

非连续映射地址空间的起始地址在常规映射地址空间的结束地址后8MB-16MB之间,而且保证8MB对齐(地址的低24位为0)

/*

* Remap an arbitrary physical address space into the kernel virtual

* address space. Needed when the kernel wants to access high addresses

* directly.

*

* NOTE! We need to allow non-page-aligned mappings too: we will obviously

* have to convert them into an offset in a page-aligned mapping, but the

* caller shouldn't need to know that small detail.

*/

void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)

{

void __iomem * addr;

struct vm_struct * area;

unsigned long offset, last_addr;

pgprot_t prot;

/* Don't allow wraparound or zero size */

last_addr = phys_addr + size - 1;

总线地址末端

if (!size || last_addr < phys_addr)

return NULL;

/*

* Don't remap the low PCI/ISA area, it's always mapped..

*/

if (phys_addr >= ISA_START_ADDRESS && last_addr < ISA_END_ADDRESS)

return (void __iomem *) phys_to_virt(phys_addr);

#define ISA_START_ADDRESS0xa0000

#define ISA_END_ADDRESS0x100000

640kb-1Mb之间(此空洞用于连接到ISA总线上的设备)

/*

* Don't allow anybody to remap normal RAM that we're using..

*/

if (phys_addr <= virt_to_phys(high_memory - 1)) {

high_memory为896Mb对应线性地址

phys_addr在小于896Mb的常规内存空间中

char *t_addr, *t_end;

struct page *page;

t_addr = __va(phys_addr);

转化成线性地址

t_end = t_addr + (size - 1);

若小于896MB则此页框应该被设置为保留

for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++)

if(!PageReserved(page))

return NULL;

}

prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY

| _PAGE_ACCESSED | flags);

#define __pgprot(x)((pgprot_t) { (x) }

/*

* Mappings have to be page-aligned

*/

offset = phys_addr & ~PAGE_MASK;

取一页页框的偏移

phys_addr &= PAGE_MASK;

总线地址按4KB对齐

#define PAGE_SHIFT12

#define PAGE_SIZE(1UL << PAGE_SHIFT)

#define PAGE_MASK(~(PAGE_SIZE-1))

size = PAGE_ALIGN(last_addr+1) - phys_addr;

#define PAGE_ALIGN(addr)(((addr)+PAGE_SIZE-1)&PAGE_MASK)

/*

* Ok, go for it..

*/

area = get_vm_area(size, VM_IOREMAP | (flags << 20));

#define VM_IOREMAP0x00000001/* ioremap() and friends */

申请一个非连续映射节点描述符

if (!area)

return NULL;

area->phys_addr = phys_addr;

总线地址

addr = (void __iomem *) area->addr;

起始线性地址

if (ioremap_page_range((unsigned long) addr,

(unsigned long) addr + size, phys_addr, prot)) {

vunmap((void __force *) addr);

return NULL;

}

return (void __iomem *) (offset + (char __iomem *)addr);

offset + addr

offset为0

addr为线性地址,此地址被CPU用于读写EHCI I/O mem空间

这也验证那句话:在X86平台上总线地址就是物理地址

}

/**

*get_vm_area-reserve a contingous kernel virtual area

*@size:size of the area

*@flags:%VM_IOREMAP for I/O mappings or VM_ALLOC

*

*Search an area of @size in the kernel virtual mapping area,

*and reserved it for out purposes.Returns the area descriptor

*on success or %NULL on failure.

*/

struct vm_struct *get_vm_area(unsigned long size, unsigned long flags)

{

return __get_vm_area(size, flags, VMALLOC_START, VMALLOC_END);

}

struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,

unsigned long start, unsigned long end)

{

return __get_vm_area_node(size, flags, start, end, -1, GFP_KERNEL);

}

linux arm 地址映射 ioremap_nocache 使用,ioremap_nocache 函数分析相关推荐

  1. linux arm 地址映射 ioremap_nocache 使用,ioremap_nocache 函数分析(二)

    ioremap_nocache函数分析(二) 非连续映射地址空间 static struct vm_struct *__get_vm_area_node(unsigned long size, uns ...

  2. linux skb 结构和相关操作函数分析

    sk_buff是Linux网络中最核心的结构体,它用来管理和控制接收或发送数据包的信息.各层协议都依赖于sk_buff而存在.内核中sk_buff结构体在各层协议之间传输不是用拷贝sk_buff结构体 ...

  3. linux C函数之strdup函数分析【转】

    本文转载自:http://blog.csdn.net/tigerjibo/article/details/12784823 linux C函数之strdup函数分析 一.函数分析 1.函数原型: [c ...

  4. linux C函数之strdup函数分析

    本文转载自:http://blog.csdn.net/tigerjibo/article/details/12784823 linux C函数之strdup函数分析 一.函数分析 1.函数原型: #i ...

  5. Linux C flie操作: open write read lseek close函数分析

    函数类型:open. write. read. lseek. close函数属于文件的系统调用. 包含有文件:<sys/stat.h>,<sys/types.h>,<fc ...

  6. arm linux 存储,linux arm的存储分布那些事

    原标题:linux arm的存储分布那些事 linux arm 内存分布总览 上图是linux的arm的虚拟地址分布总览,我们按从低地址到高地址的顺序逐个描述,每项的描述包括如下的内容的组和: 地址范 ...

  7. linux培训描述,【linux培训班】关于linux系统记录和描述进程的分析

    从C语言源代码分析,神秘的Linux系统是如何记录和描述进程的?也许我们习惯用Windows系统,可程序员最爱的还是linux系统,毕竟这样的系统安全性比较高,可操作的难度也是有的,不适合小白来使用. ...

  8. Linux_arm_启动_c语言部分详解,[原创]Linux arm 启动 c语言部分详解第四讲

    Linux arm启动c语言部分详解第四讲(from setup_per_cpu_areas();) Written by leeming 上面的setup_arch花了我们大量的篇幅,现在我们要继续 ...

  9. 安卓逆向_16 --- ARM 静态分析( 使用 IDA Pro 分析 ARM 汇编【java_ 和 JNI_OnLoad】 )

    菜鸟总结 so 分析,arm 汇编,IDA 静态分析:https://www.52pojie.cn/thread-695063-1-1.html JNI 静态注册 so 和 IDA 导入的 JNI.h ...

最新文章

  1. 2019山东夏令营摸鱼记
  2. 并发环境下HashMap引起的full gc排查
  3. java implements interface_Java 接口 interface implements
  4. 为什么有些xpath绝对路径拿不到数据_Python爬虫,登陆神器Selenium之xpath的使用
  5. mysql 执行计划 代价_mysql explain执行计划详解
  6. 【转】3.5(译)构建Async同步基元,Part 5 AsyncSemaphore
  7. 【React框架-1】React概览
  8. 如何用 10 句话激怒程序猿?
  9. PCWorld:IT界14对经典“生死冤家”
  10. ArcCatalog中连接SDE数据库
  11. 初识app之产品需求分析文档设计
  12. 显示杂谈(7)-色坐标图的来源1
  13. 关于el-dialog中@close事件和取消确认按钮并用,会触发两次关闭表单的操作(!表单为子组件时)
  14. VMware ESXI虚拟机修改MAC地址的方法
  15. matlab解方java_学习笔记190—利用matlab求解方程组的解
  16. c语言编程一张纸对折,【动手试试】把一张纸对折
  17. 【干货福利】67个拯救web开发者的工具、库和资源!——爱创课堂
  18. c++ grpc compress(deflate算法) demo编译
  19. VSCode中使用 eslint+prettier完成代码格式化以及自动化整理
  20. 人手,人力,人才,人物

热门文章

  1. 架构师带你实时解读微服务架构改造案例:天气预报系统的架构设计
  2. java md密码加密_JavaSE_对密码进行MD5加密
  3. github最火12306购票小助手操作指南(windos系统下)(零基础版)
  4. pyecharts 进阶之地图+涟漪散点图+路径图(六)
  5. Java笔记——控制台模拟“双色球”福利彩票游戏
  6. 新手站长如何选择虚拟主机商
  7. 管理软件风险,防患于未然
  8. Android 检测手机IMEI值
  9. 火山 xl,xa,xg,xk,xh,xm 六神签名参数
  10. win10如何设置计算机网络访问,win10系统让网络自动连接的设置步骤