- 论坛徽章:
- 13
|
本帖最后由 _nosay 于 2016-10-10 17:36 编辑
C语句:char *p = 0x21; *p = 'a';
汇编语句:IN AL, 21H
这两个十六进制的21,都是程序用于描述逻辑使用的“代号”(虚拟地址),它们最终要映射到一个真实物理介质的某个地方。
指令不同,指令中地址的含义也不同,就像我们说话时的场合不同,默认单位就不同。同样的值0x21,C语句中用*去访问,就表示要访问内存空间,汇编语句中用IN指令访问,就表示要访问I/O空间,这便是访问外设的其中一种方式:I/O映射式。这种方式需要硬件额外提供一套访问I/O空间的指令。
另外一种方式就是在内存空间中,划分一块专门用于映射外设,跟内核空间/用户空间的划分类似,是一种约定,规定某个范围的地址用于访问外设,其它地址用于访问内存,比如上述的0x21,划分到访问外设的地址范围,就不可能用它访问到内存了。
I/O地址区间很小,如今系统上可以同时插很多外设,并且有些外设中的寄存器、ROM也越来越大,所以现在的系统一般都支持将外设映射到内存空间,可以将外设认为是特殊的内存,但它只能映射到内核空间,所以不服从kswapd的换出(注意不能换出与不能释放是两回事,内核占用的内存页面不能换出,但只要是动态分配的就可以释放)。
Linux内核中的ioremap()就是用于将外设中的资源映射到虚拟地址,其中函数中的“re”是有缘故的,表示“反向”的意思:因为内核空间的虚拟地址与物理地址之间是固定的3G偏移,所以外设的物理地址(“总线地址”)确定,就必须用指定的内核虚拟地址跟它映射,因此相对于用户态的内存分配过程是反的,不是先分配虚拟地址,到需要时再分配物理地址并建立映射。
所以说外设和内存虽然都是物理介质,但它比内存更大牌,系统要访问它,必须一开始就“分配”它,并且再也不“释放”,不像内存那要,需要了就“分配”,不需要了就“释放”,招之即来,挥之即去。
详细过程读代码去吧,good good study, day day up~
所谓的物理地址,就是最终写到总线上面的地址,所以ioremap()只是完成了整个过程中的一半,另外还有总线地址与各种外设之间的映射,详见“《Linux内核源代码情况分析》8.4节说明的PCI总线”,比较复杂,以后再一起学习。
|
|