热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

寄存器是外部设备吗,外存是可以直接访问的存储器

前言x86有IO端口与IO内存的概念x86可以只有IO内存x86可以有两个:IO内存和IO端口arm只有IO内存的概念参考犹豫的蛋挞linux

前言 x86 有 I/O端口与I/O内存 的概念x86 可以只有 IO内存x86 可以 有 两个 : IO内存 和 IO端口arm 只有 IO内存的概念参考 犹豫的蛋挞 linux 4.0 设备驱动 开发详解 首先从IO讲起,关于IO 有很多概念:IO端口 IO接口 IO内存而我们一般放在一块讨论的是 IO端口与IO接口 IO端口与IO内存, 这两个话题中的IO端口不是一个东西 而且我们讨论的外设寄存器 是 片上外设寄存器,IO内存涉及到 类ram接口的存储器和其他类ram接口设备而一般来说其他片外的外设如果和soc不是以类ram接口相连而是以其他总线方式(I2C SPI MDIO)相连则是无法通过 IO端口或者IO内存的方式访问的, 一般通过(I2C SPI MDIO)总线方式访问这些片外外设里面的寄存器(注意:片外设备中也集成有存储模块,而我们把一个单元叫做一个寄存器,这里的寄存器不同于soc中的寄存器) I/O端口与I/O接口 //这是硬件上的概念I/O接口 : 通常把介于主机和外设之间的一种缓冲电路称为I/O接口电路,简称I/O接口I/O端口 : CPU与外设进行信息交换时,各类信息通过I/O接口存入不同的寄存器中.这些寄存器被称作I/O端口。若干端口加上相应的控制电路才构成接口 I/O端口分为 控制寄存器、状态寄存器和数据寄存器 I/O端口与I/O内存 编址指的是访问外设寄存器的方式,相对访问内存来说的.访问外设寄存器的方式,分为两种(根据外设编址分类) 1/统一编址 内存和IO空间(外设有自己的内存、缓冲区,外设的寄存器和内存)统一编址在总线上拿东西的. 操作外设和内存的汇编指令相同,指令一般都是RISC 统一编址也称为“I/O内存”方式,外设寄存器位于“内存空间”,而内存空间的布局在数据手册中已经确定. 2/独立编址 内存和IO空间 独立编址 就是说内存一部分的地址和I/O地址是重叠的 操作外设和内存的汇编指令不同,指令一般都是CISC,soc上多一个外设就要多几个汇编指令(用来操作soc中新添加的外设,这就是soc的升级) 独立编址也称为“I/O端口”方式,外设寄存器位于“I/O(地址)空间” 究竟采用哪一种取决于系统的总体设计。在一个系统中也可以同时使用两种方式,也即是说部分设备 独立编址,部分设备统一编址.Intel的x86微处理器支持I/O 独立编址,因为它们的指令系统中都有I/O指令,并设置了可以区分I/O访问和存储器访问的控制信号引脚。一些微处理器或单片机,为了减少引脚,减少芯片占用面积,不支持I/O独立编址,只能采用存储器统一编址,例如arm处理器. I/O内存(统一编址) //尽管 I/O 端口在x86世界中非常流行,但是用来和设备通讯的主要机制是通过内存映射的寄存器和设备内存,两者都称为I/O 内存,因为寄存器和内存之间的区别对软件是透明的。//I/O 内存仅仅是一个类似于RAM 的区域,处理器通过总线访问该区域,以实现对设备的访问。同样,读写这个区域是有边际效应。//I/O 内存可分为可以或者不可以通过页表来存取。若通过页表存取,内核必须先重新编排物理地址,使其对驱动程序可见,这就意味着在进行任何I/O操作之前,你必须调用ioremap;如果不需要页表,I/O内存区域就类似于I/O端口,你可以直接使用适当的I/O函数读写它们。//由于边际效应的缘故,不管是否需要 ioremap,都不鼓励直接使用I/O内存指针,而应使用专门的I/O内存操作函数。这些I/O内存操作函数不仅在所有平台上是安全,而且对直接使用指针操作 I/O 内存的情况进行了优化。访问I/O内存的流程是: 1/ request_mem_region()//这个函数的实现和 request_region 一样,目的一样 //在访问I/O内存之前,分配I/O内存并不是唯一要求的步骤,你还必须保证内核可存取该I/O内存。访问I/O内存并不只是简单解引用指针,在许多体系中,I/O 内存无法以这种方式直接存取。因此,还必须通过ioremap 函数设置一个映射。 2/ioremap() //把设备所处的物理地址映射到虚拟地址 //映射之后就可以通过指针来访问这些地址,但是最好不用,最好用linux内核的一组函数来读写, //ioremap用于将I/O内存区映射到虚拟地址。参数phys_addr为要映射的I/O内存起始地址,参数size为要映射的I/O内存的大小,返回值为被映射到的虚拟地址 3/ioread8()/iowrite16()/ioread8_rep()/iowrite8_rep() //用完了之后要这么做 4/iounmap() 5/release_mem_region() I/O端口(独立编址) I/O映射方式 通过 I/O映射方式 访问I/O端口的流程是1/ request_region//不映射到内存空间,直接使用 intb()/outb()之类的函数来读写IO端口2/ inb/outb/inw/outw/inl/outl3/ release_region 内存映射方式 为什么要使用内存映射方式?内存映射方式的重点是什么?这里的内存映射方式的目的是为了封装IO端口 ,操作起来像IO内存一样操作,即用 IO内存的api ioread8()/iowrite16()/ioread8_rep()/iowrite8_rep() 操作IO端口关键函数是 ioport_map ,这个函数实现了封装.封装之后,就可以用IO内存的api操作IO端口 ioport_map 实现了把IO端口映射到IO内存(“内存空间”)如果不用这个函数封装,那么就要用 inb/outb/inw/outw/inl/outl 操作,这样 IO端口 和 IO内存 的接口就不一样了.访问 内存映射方式 访问I/O端口的流程是1/ request_region//#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), 0)/** * __request_region - create a new busy resource region * @parent: parent resource descriptor * @start: resource start address * @n: resource region size * @name: reserving caller's ID string * @flags: IO resource flags *///struct resource * __request_region(struct resource *parent,// resource_size_t start, resource_size_t n,// const char *name, int flags)//其实是可以直接映射的,但是会出现一个问题,这个端口如果已经被映射了,我就不应该再映射这个端口.所以为了实现这个东西,就做了一个函数 request_region ,这个函数实现了对 端口映射到内存 的同步2/ ioport_map//void __iomem *ioport_map(unsigned long port, unsigned int nr)//可以把port开始的count个连续的IO端口映射为一段“内存空间”,然后就可以在其返回的地址是像访问IO内存一样访问这些IO端口3/ 用IO内存的api ioread8()/iowrite16()/ioread8_rep()/iowrite8_rep() //大部分硬件会将8位、16位和32位端口区分开,无法像访问内存那样混淆使用。驱动程序必须调用不同的函数来访问不同大小的端口。//仅支持单地址空间的计算机体系通过将I/O端口地址重新映射到内存地址来伪装端口I/O 。为了提高移植性,内核对驱动隐藏了这些细节。4/ ioport_unmap5/ release_region//用完I/O端口后(可能在模块卸载时),应当调用release_region将I/O端口返还给系统。参数start和n应与之前传递给request_region一致 //可以用 check_region 来检查某些端口是否被占用 注意: 本文中的函数的参数如果用到了地址,除了下面的函数,其他用到的地址都是虚拟地址 void * ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags); 参数中用到的是物理地址,返回的是虚拟地址 而这些虚拟地址的获得有两种方案 1/ioremap 2/.h文件中的地址 ioread8 //ioread8 在 arm 中用的是#define ioread8(p) ({ unsigned int __v = __raw_readb(p); __iormb(); __v; })static inline u8 __raw_readb(const volatile void __iomem *addr){ u8 val; asm volatile("ldrb %1, %0" : "+Qo" (*(volatile u8 __force *)addr), "=r" (val)); return val;} 参考资料

IO端口和IO内存的区别及分别使用的函数接口

统一编址&独立编址


推荐阅读
  • Linux如何安装Mongodb的详细步骤和注意事项
    本文介绍了Linux如何安装Mongodb的详细步骤和注意事项,同时介绍了Mongodb的特点和优势。Mongodb是一个开源的数据库,适用于各种规模的企业和各类应用程序。它具有灵活的数据模式和高性能的数据读写操作,能够提高企业的敏捷性和可扩展性。文章还提供了Mongodb的下载安装包地址。 ... [详细]
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 本文介绍了django中视图函数的使用方法,包括如何接收Web请求并返回Web响应,以及如何处理GET请求和POST请求。同时还介绍了urls.py和views.py文件的配置方式。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • 使用正则表达式爬取36Kr网站首页新闻的操作步骤和代码示例
    本文介绍了使用正则表达式来爬取36Kr网站首页所有新闻的操作步骤和代码示例。通过访问网站、查找关键词、编写代码等步骤,可以获取到网站首页的新闻数据。代码示例使用Python编写,并使用正则表达式来提取所需的数据。详细的操作步骤和代码示例可以参考本文内容。 ... [详细]
  • 服务器上的操作系统有哪些,如何选择适合的操作系统?
    本文介绍了服务器上常见的操作系统,包括系统盘镜像、数据盘镜像和整机镜像的数量。同时,还介绍了共享镜像的限制和使用方法。此外,还提供了关于华为云服务的帮助中心,其中包括产品简介、价格说明、购买指南、用户指南、API参考、最佳实践、常见问题和视频帮助等技术文档。对于裸金属服务器的远程登录,本文介绍了使用密钥对登录的方法,并提供了部分操作系统配置示例。最后,还提到了SUSE云耀云服务器的特点和快速搭建方法。 ... [详细]
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
author-avatar
工农大路店NOKIA客户服务中心
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有