经常看到这些个名词,大致弄清了他们的区别和联系,以x86架构为例,简要说明下。哪里不对,还请指正。

关键词:内存空间、I/O空间,I/O port,I/O mem

1 内存空间和I/O空间

所有的设备中的每一个可访问单元,要想被CPU访问,都要有一个独立的可识别的地址,不然就混乱了。CPU所能访问的全部地址范围,被化分到内存空间和IO空间。

两个空间彼此独立,各有自己的访问方式,硬件上是怎么实现的划分暂且不管,只要告诉CPU该地址是在哪个空间,并给出地址,CPU就能通过对应的方式,最终访问到该单元。

其中:

1)内存空间

范围:一般为48根地址线表示的256T。

访问方式:通过将物理地址映射成内存空间线性地址,直接访问。即常见的user/kernel space:其中用户空间使用的线性地址范围是0~0x00007fffffffffff,内核空间线性地址范围是0xfff800000000000~0xffffffffffffffff。

2)I/O空间

范围:为16根地址线对应的64k(无论是否专门额外提供了这16根线)。
     访问方式:通过将物理地址映射成I/O空间地址,采用特殊命令访问。直接映射到0x10000~0x1ffff。

可以看到,只给出物理地址而不告诉处于哪个空间,比如0x1400,是没有意义的。

2 I/O port和I/O mem

CPU外接的设备分为普通内存(理解为内存条)和外设(非内存条的其它设备)两类。

1)普通内存的可访问单元,就是映射到内存空间去访问的。

2)外设内部的可访问单元,可以映射到内存空间去访问(I/O mem),也可以映射到I/O空间访问(I/O port)。

注意:ISA设备使用的是地址低于0x10000的外设物理地址,只能映射为I/O port。其它的比如PCI设备,则映射为I/O mem。

3 内核空间下的I/O访问

3.1 I/O port的访问

1)首先申请对这块区域的占用,申请函数为request_region();

2)然后要将待访问的物理地址映射成I/O空间地址,映射函数为ioport_map(),x86下该函数的实现,就是address直接加上一个偏移量PIO_OFFSET并转为指针类型;

#define PIO_OFFSET   0x10000UL
#define PIO_MASK    0x0ffffUL
#define PIO_RESERVED    0x40000ULvoid __iomem *ioport_map(unsigned long port, unsigned int nr)
{/* 范围检查 */if (port > PIO_MASK)return NULL;return (void __iomem *) (unsigned long) (port + PIO_OFFSET);
}

3)读写访问,读byte为例,是用汇编命令inb,一般封装成inb()

static inline u8 inb(u16 port)
{u8 v;asm volatile("inb %1,%0" : "=a" (v) : "dN" (port));return v;
}

或者进一步封装成ioread8()等。函数源码如下:

unsigned int ioread8(void __iomem *addr)
{/* 该接口为IO访问通用接口, 内部根据类型不同细分,其中I/O port 使用 inb(), I/O mem 使用 readb() */IO_COND(addr, return inb(port), return readb(addr));return 0xff;
}#define IO_COND(addr, is_pio, is_mmio) do {            \unsigned long port = (unsigned long __force)addr; \if (port >= PIO_RESERVED) {                \ /* 这里看到 I/O mem 起始的范围是 PIO_RESERVED */is_mmio;                    \} else if (port > PIO_OFFSET) {             \port &= PIO_MASK;             \ /* 注意,将前面 map 时加上的 PIO_OFFSET 去除了 */is_pio;                        \} else                         \bad_io_access(port, #is_pio );         \
} while (0)

3.2 I/O mem的访问

1)还是首先进行区域申请,申请函数是request_mem_region();

2)映射函数为ioremap_nocache(),该函数实现比较复杂,其返回地址即是处于vmalloc/ioremap space的地址指针(0xffffc90000000000~0xffffe8ffffffffff)。此外还有ioremap_uc/ioremap_cache...等多种映射方式。

void __iomem *ioremap_nocache(resource_size_t phys_addr, unsigned long size)
{enum page_cache_mode pcm = _PAGE_CACHE_MODE_UC_MINUS;return __ioremap_caller(phys_addr, size, pcm,__builtin_return_address(0), false);
}

3)访问示例:可以使用同ioport公用的ioread8()函数,也可以使用readb()函数,也可以直接对该地址进行访问,如下:

void __iomem *ioaddr = ioremap_nocache(phys_addr, size);// exp 1:
result = ioread8(ioaddr);
// exp 2:
result = readb(ioaddr);
// exp 3:
result = *(unsigned char *)ioaddr;iounmap(ioaddr);

此外,实际使用时,针对I/O设备的访问,还有一些其它的封装和注意事项,比如PCI bus提供的pci_ioremap_bar(),pci_read_config_byte()等等。

4 用户空间的I/O访问

Linux的/dev/目录下分别存在一份全部mem空间和port空间的镜像,即/dev/mem和/dev/port。可以利用它们实现用户空间对I/O设备的访问。此外,设备I/O物理地址在内存空间和IO空间的信息,还会列在/proc/iomem和/proc/ioport两个文件中,内核态成功申请某一区域后,会在这两个用户文件中显示申请的结果信息。

4.1 I/O mem的访问

I/O mem的访问,主要是利用了/dev/mem,参见一个小工具devmem2,本文不再赘述。

4.2 I/O port的访问

I/O port的访问,主要是利用了/dev/port文件,示例如下:

#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>  #define ADDR 0x400
#define LEN 0x10int main(int argc, char *argv[])
{  char buf[LEN];char i;  int fd = open("/dev/port", O_RDWR | O_SYNC);  lseek(fd, ADDR, SEEK_SET);  read(fd, buf, LEN);for (i = 0; i < LEN; i ++)printf("%02 ", buf[i]);  close(fd);return 0;
}

补充:I/O port不能和I/O mem一样采用先mmap再访问,原因是该设备节点没有提供mmap系统调用。两个节点提供的file_operations结构是位于.\drivers\char\mem.c文件的mem_fops和port_fops局部静态变量。附全部的mem主设备节点下各子设备结构信息。

static const struct memdev {const char *name;umode_t mode;const struct file_operations *fops;struct backing_dev_info *dev_info;
} devlist[] = {[1] = { "mem", 0, &mem_fops, &directly_mappable_cdev_bdi },
#ifdef CONFIG_DEVKMEM[2] = { "kmem", 0, &kmem_fops, &directly_mappable_cdev_bdi },
#endif[3] = { "null", 0666, &null_fops, NULL },
#ifdef CONFIG_DEVPORT[4] = { "port", 0, &port_fops, NULL },
#endif[5] = { "zero", 0666, &zero_fops, &zero_bdi },[7] = { "full", 0666, &full_fops, NULL },[8] = { "random", 0666, &random_fops, NULL },[9] = { "urandom", 0666, &urandom_fops, NULL },
#ifdef CONFIG_PRINTK[11] = { "kmsg", 0644, &kmsg_fops, NULL },
#endif
};

参考链接:

https://blog.csdn.net/ce123_zhouwei/article/details/7204458

https://blog.csdn.net/deep_pro/article/details/5315655

etc.

Linux下的IO port, IO mem, IO space, Mem space及访问方式相关推荐

  1. linux下的CPU、内存、IO、网络的压力测试

    linux下的CPU.内存.IO.网络的压力测试 要远程测试其实很简单了,把结果放到一个微服务里直接在web里查看就可以了,或者同步到其他服务器上 一.对CPU进行简单测试: 1.通过bc命令计算特别 ...

  2. Linux下服务器基本环境搭建步骤详解(三种软件安装方式)

    Linux下服务器基本环境搭建 小伙伴们注意看:下面使用三种方式分别安装JDK.Tomcat.Docker进行演示 操作系统基于CentOs7. 文章目录 Linux下服务器基本环境搭建 前言 一.L ...

  3. Linux内存压力,linux下的CPU、内存、IO、网络的压力测试

    一.对CPU进行简单测试: 1.通过bc命令计算特别函数 例:计算圆周率 echo "scale=5000; 4*a(1)" | bc -l -q MATH LIBRARY If  ...

  4. linux下的CPU、内存、IO、网络的压力测试工具与方法介绍

    一.对CPU进行简单测试: 1.通过bc命令计算特别函数 例:计算圆周率 echo "scale=5000; 4*a(1)" | bc -l -q 2.我工作中一般用一个死循环进行 ...

  5. linux下的CPU、内存、IO、网络的压力测试工具与方法

    一.CPU压力测试工具Super Pi forLinux Super PI是利用CPU的浮点运算能力来计算出π(圆周率),所以目前普遍被超频玩家用做测试系统稳定性和测试CPU计算完后特定位数圆周率所需 ...

  6. linux 内存强度测试软件,linux下的CPU、内存、IO、网络的压力测试工具与方法介绍...

    使用工具stress Centos # yum -y install stress Ubantu # apt-get install stress # stress --help `stress' i ...

  7. 2. zabbix监控LINUX下监控CPU,硬盘,流量,内存 (图形化方式)【网络工程】(保姆级图文)

    目录 1. 主机监控设置 启用主机与更新主机 2.设置监控内容 cpu监控 硬盘文件监控 3. 创建一个监控,以内存监控为例 4. 图形可视化,以流量监控为例 总结 欢迎关注 『网络工程专业』 系列, ...

  8. linux下使用sort命令升序、降序、随机及组合方式排序方法

    示例文件: #################################################### 序号       优先级       字段1        字段2 1       ...

  9. LINUX下忘记MySQL的ROOT密码后修改,以及添加访问IP。

    网上有大概几种主要方法,试过之后,感觉都有些乱,有些也不管用,下面推荐一个算是主流的方法,已经测试完成,修改成功. 1.停止MySQL服务 执行:/etc/init.d/mysql stop,你的机器 ...

  10. linux 多核cpu监控,Linux 下多核CPU知识

    1. 在Linux下,如何确认是多核或多CPU: #cat /proc/cpuinfo 如果有多个类似以下的项目,则为多核或多CPU: processor  : 0 ...... processor  ...

最新文章

  1. 智源人工智能算法大赛开锣,百万奖金激励 AI 算法创新
  2. 浅谈我对DDD领域驱动设计的理解
  3. OOP设计模式[JAVA]——03职责链模式
  4. HDFS依然是存储的王者
  5. 数据库MySQL基础---JDBC开发步骤--JDBC封装工具类--PreparedStatement实现CRUD操作
  6. 剑指offer38 数字在排序数组中出现的次数
  7. springboot----热部署
  8. grid.getSelectionModel的所有操作
  9. 农业不一定靠规模赚钱
  10. # XAMPP 配置密码大全修改默认密码
  11. 随笔2010.01.25
  12. SVN的代码回滚,并不如预期的那样好
  13. python十六进制转pcap文件_python处理pcap文件——数据提取
  14. Swoole进阶——02 内存之Table
  15. CMDN Club每周精选(第4期)
  16. java — 多线程设计模式
  17. 通达信千元主图公式源码
  18. Linux命令rm -rf /无法完全删除问题处理
  19. [参考C3程序员] - C语言贪吃蛇(二维数组)
  20. HTML下载生成WORD 和PDF,及导出图片不能正常显示解决方案

热门文章

  1. jlink盗版导致keil闪退的解决办法
  2. 自研3D渲染引擎 置身游戏世界般的3D大屏体验 还不快来看看
  3. python画小猪佩奇代码
  4. Python——设计原则
  5. RecyclerView notifyDataSetChanged 图片重新加载问题
  6. 女生玩游戏专属神器,华为平板M5青釉版高颜值、强性能
  7. python pptp proxy_Python爬虫使用代理IP突破反爬虫限制
  8. 【笔记】浮动属性float的应用07——浮动可缩放的首字下沉(所有步骤组合在一起)
  9. Photoshop 之利用 调整边缘 抠图
  10. imatest软件的学习 及使用