转载自:http://blog.csdn.net/qq_21792169/article/details/48104665

(一)地址的概念

1)物理地址:

CPU地址总线传来的地址,由硬件电路控制其具体含义。物理地址中
很大一部分是留给内存条中的内存的,但也常被映射到其他存储器上 (如显存、
BIOS等)。在程序指令中的虚拟地址经过段映射和页面映射后,就生成了物理地址,
这个物理地址被放到CPU的地址线上。
物理地址空间,一部分给物理RAM(内存)用,一部分给总线用,这是由硬件设计来决定的,
因此在32 bits地址线的x86处理器中,物理地址空间是2的32次方,即4GB,但物理RAM一般
不能上到4GB,因为还有一部分要给总线用(总线上还挂着别的 许多设备)。在PC机中,
一般是把低端物理地址给RAM用,高端物理地址给总线用。

标题2)总线地址:

总线的地址线或在地址周期上产生的信号。外设使用的是总线地址,
CPU使用的是物理地址。
物理地址与总线地址之间的关系由系统的设计决定的。在x86平台上,物理地址就是总线地址,
这是因为它们共享相同的地址空间——这句话有点难理解,详见下 面的“独立编址”。在其他平台上,
可能需要转换/映射。比如:CPU需要访问物理地址是0xfa000的单元,那么在x86平台上,
会产生一个PCI总线 上对0xfa000地址的访问。因为物理地址和总线地址相同,所以凭眼睛
看是不能确定这个地址是用在哪儿的,它或者在内存中,或者是某个卡上的存储单元,
甚至可能这个地址上没有对应的存储器。

标题3)虚拟地址:

现代操作系统普遍采用虚拟内存管理(Virtual Memory Management)机制,
这需要MMU(Memory Management Unit)的支持。MMU通常是CPU的一部分,如果处理器没有MMU,
或者有MMU但没有启用,CPU执行单元发出的内存地址将直接传到芯片引脚上,被 内存芯片
(物理内存)接收,这称为物理地址(Physical Address),如果处理器启用了MMU,
CPU执行单元发出的内存地址将被MMU截获,从CPU到MMU的地址称为虚拟地址(Virtual Address),
而MMU将这个地址翻译成另一个地址发到CPU芯片的外部地址引脚上,也就是将虚拟地址映射
成物理地址。
Linux中,进程的4GB(虚拟)内存分为用户空间、内核空间。用户空间分布为0~3GB(
即PAGE_OFFSET,在0X86中它等于 0xC0000000)
,剩下的1G为内核空间。程序员只能使用虚拟地址。系统中每个进程有各自的私有用
户空间(0~3G),这个空间对系统中的其他进程是不可见的。
CPU发出取指令请求时的地址是当前上下文的虚拟地址,MMU再从页表中找到这个虚拟地址
的物理地址,完成取指。同样读取数据的也是虚拟地址,比如mov ax, var. 编译时var就
是一个虚拟地址,也是通过MMU从也表中来找到物理地址,再产生总线时序,完成取数据的。

二)编址方式

1)外设都是通过读写设备上的寄存器来进行的,外设寄存器也称为“I/O端口”,而IO端口有
两种编址方式:独立编址和统一编制。

统一编址:

外设接口中的IO寄存器(即IO端口)与主存单元一样看待,每个端口占用一个
存储单元的地址,将主存的一部分划出来用作IO地址空间,如,在 PDP-11中,把最高的
4K主存作为IO设备寄存器地址。端口占用了存储器的地址空间,使存储量容量减小。
统一编址也称为“I/O内存”方式,外设寄存器位于“内存空间”(很多外设有自己的内存、
缓冲区,外设的寄存器和内存统称“I/O空间”)。
如,Samsung的S3C2440,是32位ARM处理器,它的4GB地址空间被外设、RAM等瓜分:
0x8000 1000 LED 8*8点阵的地址
0x4800 0000 ~ 0x6000 0000 SFR(特殊暂存器)地址空间
0x3800 1002 键盘地址
0x3000 0000 ~ 0x3400 0000 SDRAM空间
0x2000 0020 ~ 0x2000 002e IDE
0x1900 0300 CS8900

独立编址(单独编址):

IO地址与存储地址分开独立编址,I/0端口地址不占用存储空间的
地址范围,这样,在系统中就存在了另一种与存储地址无关的IO地 址,CPU也必须具有专
用与输入输出操作的IO指令(IN、OUT等)和控制逻辑。独立编址下,地址总线上过来一
个地址,设备不知道是给IO端口的、还是 给存储器的,于是处理器通过MEMR/MEMW和IOR
/IOW两组控制信号来实现对I/O端口和存储器的不同寻址。如,intel 80x86就采用单独编址,
CPU内存和I/O是一起编址的,就是说内存一部分的地址和I/O地址是重叠的。
独立编址也称为“I/O端口”方式,外设寄存器位于“I/O(地址)空间”。
对于x86架构来说,通过IN/OUT指令访问。PC架构一共有65536个8bit的I/O端口,组成64K
个I/O地址空间,编号从 0~0xFFFF,有16位,80x86用低16位地址线A0-A15来寻址。连续两
个8bit的端口可以组成一个16bit的端口,连续4个组成一个 32bit的端口。I/O地址空间和
CPU的物理地址空间是两个不同的概念,例如I/O地址空间为64K,一个32bit的CPU物理地址
空间是4G。 如,在Intel 8086+Redhat9.0 下用“more /proc/ioports”可看到:
0000-001f : dma1
0020-003f : pic1
0040-005f : timer
0060-006f : keyboard
0070-007f : rtc
0080-008f : dma page reg
00a0-00bf : pic2
00c0-00df : dma2
00f0-00ff : fpu
0170-0177 : ide1
……

不过Intel x86平台普通使用了名为内存映射(MMIO)的技术,该技术是PCI规范的一部分,
IO设备端口被映射到内存空间,映射后,CPU访问IO端口就如同访 问内存一样。看Intel
TA 719文档给出的x86/x64系统典型内存地址分配表:

系统资源 占用

BIOS 1M
本地APIC 4K
芯片组保留 2M
IO APIC 4K
PCI设备 256M
PCI Express设备 256M
PCI设备(可选) 256M
显示帧缓存 16M
TSEG 1M

对于某一既定的系统,它要么是独立编址、要么是统一编址,具体采用哪一种则取决于
CPU的体系结构。 如,PowerPC、m68k等采用统一编址,而X86等则采用独立编址,存
在IO空间的概念。目前,大多数嵌入式微控制器如ARM、PowerPC等并 不提供I/O空间,
仅有内存空间,可直接用地址、指针访问。但对于Linux内核而言,它可能用于不同的CPU,
所以它必须都要考虑这两种方式,于是它采 用一种新的方法,将基于I/O映射方式的或内
存映射方式的I/O端口通称为“I/O区域”(I/O region),不论你采用哪种方式,都要先
申请IO区域:request_resource(),结束时释放 它:release_resource()。

2)对外设的访问

1、访问I/O内存的流程是:

request_mem_region() -> ioremap() -> ioread8()/iowrite8()
-> iounmap() -> release_mem_region() 。
前面说过,IO内存是统一编址下的概念,对于统一编址,IO地址空间是物理主存的一部分,
对于编程而言,我们只能操作虚拟内存,所以,访问的第一步就是要把设备所处的物理地址
映射到虚拟地址,Linux2.6下用ioremap():
void *ioremap(unsigned long offset, unsigned long size);
然后,我们可以直接通过指针来访问这些地址,但是也可以用Linux内核的一组函数来读写:
ioread8(), iowrite16(), ioread8_rep(), iowrite8_rep()…

2、访问I/O端口

访问IO端口有2种途径:I/O映射方式(I/O-mapped)、内存映射方式(Memory-mapped)。
前一种途径不映射到内存空间,直接使用 intb()/outb()之类的函数来读写IO端口;后一种
MMIO是先把IO端口映射到IO内存(“内存空间”),再使用访问IO内存的函数来访问 IO端口。
void ioport_map(unsigned long port, unsigned int count);
通过这个函数,可以把port开始的count个连续的IO端口映射为一段“内存空间”,
然后就可以在其返回的地址是像访问IO内存一样访问这些IO端口。

Linux下的IO端口和IO内存

CPU对外设端口物理地址的编址方式有两种:一种是IO映射方式,另一种是内存映射方式。
 Linux将基于IO映射方式的和内存映射方式的IO端口统称为IO区域(IO region)。
  IO region仍然是一种IO资源,因此它仍然可以用resource结构类型来描述。

Linux管理IO region:

1) request_region()

把一个给定区间的IO端口分配给一个IO设备。

2) check_region()

检查一个给定区间的IO端口是否空闲,或者其中一些是否已经分配给某个IO设备。

3) release_region()

释放以前分配给一个IO设备的给定区间的IO端口。

Linux中可以通过以下辅助函数来访问IO端口:

inb(),inw(),inl(),outb(),outw(),outl()

“b”“w”“l”分别代表8位,16位,32位。

对IO内存资源的访问

1) request_mem_region()

请求分配指定的IO内存资源。

2) check_mem_region()

检查指定的IO内存资源是否已被占用。

3) release_mem_region()

释放指定的IO内存资源。

其中传给函数的start address参数是内存区的物理地址(以上函数参数表已省略)。

驱动开发人员可以将内存映射方式的IO端口和外设内存统一看作是IO内存资源。

ioremap()用来将IO资源的物理地址映射到内核虚地址空间(3GB - 4GB)中,
参数addr是指向内核虚地址的指针。

Linux中可以通过以下辅助函数来访问IO内存资源:

readb(),readw(),readl(),writeb(),writew(),writel()。

Linux在kernel/resource.c文件中定义了全局变量ioport_resource和iomem_resource,
来分别描述基于IO映射方式的整个IO端口空间和基于内存映射方式的IO内存资源空间(
包括IO端口和外设内存)。

1)关于IO与内存空间:

在X86处理器中存在着I/O空间的概念,I/O空间是相对于内存空间而言的,它通过特定的指令in、
out来访问。端口号标识了外设的寄存器地址。Intel语法的in、out指令格式为:
IN 累加器, {端口号│DX}
OUT {端口号│DX},累加器
目前,大多数嵌入式微控制器如ARM、PowerPC等中并不提供I/O空间,而仅存在内存空间。
内存空间可以直接通过地址、指针来访问,程序和程序运行中使用的变量和其他数据都存
在于内存空间中。
即便是在X86处理器中,虽然提供了I/O空间,如果由我们自己设计电路板,外设仍然可以
只挂接在内存空间。此时,CPU可以像访问一个内存单元那样访问外设I/O端口,而不需要设
立专门的I/O指令。因此,内存空间是必须的,而I/O空间是可选的。

2)inb和outb:

在Linux设备驱动中,宜使用Linux内核提供的函数来访问定位于I/O空间的端口,这些函数包括:
· 读写字节端口(8位宽)
unsigned inb(unsigned port);
void outb(unsigned char byte, unsigned port);
· 读写字端口(16位宽)
unsigned inw(unsigned port);
void outw(unsigned short word, unsigned port);
· 读写长字端口(32位宽)
unsigned inl(unsigned port);
void outl(unsigned longword, unsigned port);
· 读写一串字节
void insb(unsigned port, void *addr, unsigned long count);
void outsb(unsigned port, void *addr, unsigned long count);
· insb()从端口port开始读count个字节端口,并将读取结果写入addr指向的内存;
outsb()将addr指向的内存的count个字节连续地写入port开始的端口。
· 读写一串字
void insw(unsigned port, void *addr, unsigned long count);
void outsw(unsigned port, void *addr, unsigned long count);
· 读写一串长字
void insl(unsigned port, void *addr, unsigned long count);
void outsl(unsigned port, void *addr, unsigned long count);
上述各函数中I/O端口号port的类型高度依赖于具体的硬件平台,因此,
只是写出了unsigned。

物理地址和虚拟地址的区别相关推荐

  1. 逻辑地址、线性地址、物理地址和虚拟地址初步认识

    早期的内存分配机制 在早期的计算机中,要运行一个程序,会把这些程序全都装入内存,程序都是直接运行在内存上的,也就是说程序中访问的内存地址都是实际的物理内存地址.当计算机同时运行多个程序时,必须保证这些 ...

  2. 树莓派IO口驱动代码的编写、微机总线地址、物理地址、虚拟地址、BCM2835芯片手册

    地址总线: 百度百科解释: 地址总线 (Address Bus:又称:位址总线) 属于一种电脑总线 (一部份),是由CPU 或有DMA 能力的单元,用来沟通这些单元想要存取(读取/写入)电脑内存元件/ ...

  3. 物理地址和虚拟地址的概念

    虚拟地址和物理地址的概念     CPU通过地址来访问内存中的单元,地址有虚拟地址和物理地址之分,如果CPU没有MMU(Memory Management Unit,内存管理单元),或者有MMU但没有 ...

  4. 计算机物理地址和逻辑地址的区别和联系,物理地址和逻辑地址的区别

    今天学习啦小编给大家介绍一下物理地址和逻辑地址的区别.供大家参考! 物理地址和逻辑地址的区别 参考如下 MAC地址也叫物理地址.硬件地址或链路地址,由网络设备制造商生产时写在硬件内部.IP地址与MAC ...

  5. 微机总线地址,物理地址 ,虚拟地址

    总线地址 地址总线 (Address Bus:又称:位址总线) 属于一种电脑总线 (一部份),是由CPU 或有DMA 能力的单元,用来沟通这些单元想要存取(读取/写入)电脑内存元件/地方的实体位址. ...

  6. 树莓派高级开发------总线地址、物理地址和虚拟地址的认识

    一.微机总线地址 百度百科的解释:地址总线 (Address Bus:又称:位址总线) 属于一种电脑总线 (一部份),是由CPU 或有DMA 能力的单元,用来沟通这些单元想要存取(读取/写入)电脑内存 ...

  7. 内存管理:物理地址、虚拟地址、逻辑地址

    内存管理:物理地址.虚拟地址.逻辑地址 1.物理地址.虚拟地址.逻辑地址 1.1 物理地址和虚拟地址 1.2 管理物理地址和虚拟地址之间关系的方式 1.2.1 内存分段 1.2.2 内存分页 1.3 ...

  8. 浅谈物理地址、虚拟地址和逻辑地址

    从最根本的角度来看,地址只分为两类:物理地址.虚拟地址. 1.物理地址 CPU地址总线传来的地址,由硬件电路控制其具体含义.物理地址中很大一部分是留给内存条中的内存的,但也常被映射到其他存储器上(如显 ...

  9. 逻辑地址、线性地址、物理地址和虚拟地址

    --引用地址:http://linux.chinaunix.net/bbs/thread-919019-1-1.html 要过年了,发个年终总结贴,只是个人理解,不包正确哈. 本贴涉及的硬件平台是X8 ...

最新文章

  1. linux git文件图标,分享|三款 Linux 下的 Git 图形客户端
  2. 上传数据时 ajax请求成功 上传完成,ajaxSubmit请求返回数据成功,但是不执行success回调函数...
  3. kill -0 pid是做什么用的?
  4. [AngularJS] Reusable directive, require from parent controller
  5. python deque索引超出范围_Python基础语法
  6. java 抽象类_什么是final?Java抽象类又是什么?抽象类能使用 final 修饰吗?
  7. 使用英文做LDA建模
  8. 远程服务器传数据库,怎样把本机的mysql数据库上传到远程主机上
  9. 黑马vue实战项目-(八)项目的上线
  10. 计算机操作系统第四版课后全部习题答案
  11. 初识C语言———C语言基础入门
  12. 西瓜书习题 - 4.决策树
  13. 第1015期机器学习日报(2017-06-29)
  14. 汇编:裴波那契数列前50项
  15. 看完电视剧“天道“的第一次感想记录
  16. 个人开源项目视频播放器~ERPlayer
  17. centos搭建samba服务器
  18. NAS-Bert——确保One-shot与Task-agnostic
  19. 一款IOS小游戏的数据抓包篡改实践
  20. Hi3518开发板开发总结

热门文章

  1. 和海鲜浴血奋战一天,垮了5人
  2. android+背景图片不显示,背景图片显示问题 图片显示错误 android开发
  3. slim linux,SLiM (简体中文)
  4. SMTP电子邮件格式及源码解析
  5. 恒生电子白硕:金融分布式数据库LightDB自主可控、更懂金融、更懂客户
  6. 中国前列腺癌的诊断与治疗行业市场供需与战略研究报告
  7. 中国商标网网上服务系统 错误解决
  8. windows下G++的安装配置与使用
  9. 一文带你了解开源数据库中的佼佼者 TOP 10
  10. [zt] NBA季后赛赛程