地址空间导论
已有 575 次阅读2009-4-22 10:58
|系统分类:嵌入式系统
在clf上看到有人在问地址空间的概念,因为我也是花了些时间的积累才理解的,所以在这里做个总结。这些名词仅凭我的理解描述,或许同学术著作有些不同之处。
物理地址:是由CPU地址总线[A0…An]时序决定的地址,物理地址空间的大小为2的n+1次方。比如说32bits的总线,这个空间的大小是0x00000000-0xFFFFFFFF。
总线地址:是由外设(包括RAM, ROM等)地址总线[A0…Am]时序决定的地址,空间大小也
是2的n+1次方。
物理地址空间,一部分给物理RAM用,一部分给总线用,这是由硬件设计来决定的,因此在
32 bits地址线的x86处理器中,物理RAM一般不能上到4GB,因为还有一部分要给总线用。
当然现在很多x86处理器address bus是36 bits或者更多。所以RAM容量支持还是蛮大的,
特别是在服务器中。
有硬件设计经验的都知道,给你一个1G的RAM,你在设计时可以把它译码到地址空间的
任何一个合适的地址,在PC机中,一般是把低端物理地址给RAM用,高端物理地址给总线用。
在ISA时代,CPU给出的部分地址(那个时代应该是IO地址)经过缓冲后就直接连到外设,
但是外设一旦设计完毕,就不可改变,所以你买回一个板卡时,要拨动那些烦人的拨码开关,
改变主板的译码逻辑,给每个外设分配一个独立的地址空间。
在PCI时代,物理地址空间经PCI桥处理后才送到外设,在PCI桥这里可以动态分配地址了,
这样就不会有重叠冲突的可能。
虚拟地址:是CPU取指令或者取数据逻辑使用的地址,尽管没有打开映射时他们和物理地址是
相同的。
为什么要有虚拟地址?
这个问题在操作系统中已经阐述的很明白,在多任务OS中,如果没有虚拟地址到物理
地址的映射,比如说在ARM7上跑的ucos ii,那么在编译链接时,每个task的地址空间
就得固定下来了,也就是说链接后,你想再添加一个task就不可能了,你想删除一个
task也不可能了,尽管它已经死了,永远不会再执行(或者重新上电复位才会再执行)。
而有虚拟地址这个概念后,可以给每个task都可以有一个0x00000000-0xFFFFFFFF的
地址空间(在6.0版本以前的wince中不是这样),程序员在编写程序时,不用考虑链接
到哪个地址,所有的task都是一样链接的,操作系统在装载task时,先申请一个物理
空间,再把这个物理空间映射到这个task的0x00000000-0xFFFFFFFF这个虚拟空间中,
就可以执行这个task了。(在linux,win32中,task高2Gb的虚拟空间每个进程都是重叠的,
也就是所谓的kernel空间)。这样不执行的task就可以删除,把空间留给别的task用。
当然虚拟地址的作用远比上述多得多,强得多,灵活得多,这里不展开来说了。
有了上面的描述,不难理解,CPU发出取指令请求时的地址是当前上下文的虚拟地址,
MMU再从页表中找到这个虚拟地址的物理地址,完成取指。同样读取数据的也是虚
拟地址,比如mov ax, var. 编译时var就是一个虚拟地址,也是通过MMU从也表中来
找到物理地址,再产生总线时序,完成取数据的,这其中还包含了缺页故障怎么处理,
展开来说,太多了!
物理空间和虚拟空间可以一样大,也可以比虚拟空间小,也可以比虚拟空间大,MMU的
页表映射也有些处理器是完全由硬件实现的,比如SHx系列。