为什么使用I/O内存要先申请I/O内存再映射

    几乎每一种外部设备都是通过读写设备上的外部寄存器来实现具体的操作,这些外部寄存器存储和控制着设备的状态。通常包括控制寄存器、状态寄存器和数据寄存器三大类,而且外设的寄存器通常被连续的编址,所以对这些外设寄存器的访问都是连续的。

    一般台式机在设计时,内存地址空间比较紧张,所以一般将外部设备连接到专门设计的I/O地址空间上;而对于嵌入式设备来说,内存一般比较充裕,大多数嵌入式处理器支持1G的内存空间,所以可以直接将外部设备连接到多余的内存空间上。因此,根据CPU体系结构的不同,CPU对I/O端口的编址方式有如下两种:

    (1)I/O映射方式。如X86处理器为外设专门实现了一个单独的地址空间,称为“I/O地址空间”或“I/O端口空间”,CPU则通过专门的I/O指令,IN指令和OUT指令对这些地址单元(端口)进行数据的读取或写入。对不同功能的寄存器写入不同的值,就能够使外部设备完成相应的工作。

    (2)内存映射方式。RISC指令系统的CPU(MIPS、PowerPC、ARM)通常只实现一个物理地址空间,因此外设的I/O端口的物理地址就只能被映射到内存地址空间中,外设I/O端口成为内存的一部分,可以将内存挂接在低地址空间,将外部设备挂接在未使用的内存地址空间中。所以CPU可以像访问一个内存单元那样访问外设I/O端口,而不需要设立专门的外设I/O指令。

    但一般来说,在系统运行时,外设的I/O内存资源的物理地址是已知的,由硬件的设计决定。但是CPU通常并没有为这些已知的外设I/O内存资源的物理地址预定义虚拟地址范围,当然驱动程序并不可以用物理地址去访问I/O资源,必须通过建立页表将它们映射到虚拟地址空间内,然后根据映射到的虚拟地址通过相应指令访问这些I/O内存资源。主要用函数ioremap(),定义在io.h头文件中。

void __iomem* ioremap(unsigned long phys_addr, unsigned long size);

    但是要使用I/O内存首先要申请,或者叫请求,让内核知道你将要访问这个端口或者使用这个资源,这样内核知道了以后就不会让别的进程也来访问这个资源了,毕竟内存资源是有限的。也方便内核管理这些资源。申请I/O端口的函数是request_mem_region(),定义在include/linux/ioport.h

#define request_region(start,n,name)    __request_region(&ioport_resource, (start), (n), (name))

#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name))

#define rename_region(region, newname) do { (region)->name = (newname); } while (0)

extern struct resource * __request_region(struct resource *, resource_size_t start, resource_size_t n, const char *name);

    request_mem_region()函数并没有做实际性的映射工作,只是告诉内核要使用一块内存地址,声明占有。最重要的还是ioremap()函数,ioremap主要是检查传入地址的合法性,建立页表,包括访问权限,完成物理地址到虚拟地址的映射。

    

转载于:https://my.oschina.net/u/1474234/blog/228635

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值