内存与IO访问

xiaoxiao2021-02-28  29

IO空间是相对于内存空间而言的, x86一般使用IO空间 arm等嵌入式cpu一般不提供IO空间,只存在内存空间

详看宋宝华第三版第11章:内存与IO访问 1.内存空间可以直接通过地址,指针来访问,程序即在程序运行中使用的变量和其他数据都有存在于内存空间中,所以变量有一个地址,这个地址一定是MMU映射过的一个va, 我们在程序中操作的寄存器的地址也是一个va(虚拟地址),只是这两个地址的映射来源不一样而已。 2.如果外设挂接在内存空间中(这个说法是不准确的),那么我们就可以像访问一个内存单元一样去访问这些寄存器的地址(或者IO端口)

总结:物理地址到虚拟地址的映射,内存空间与IO空间的概念很乱也不好理清,这里总结一下: 1.我们的程序都是运行在内存之中包括那些变量和其他数据,而又因为需要扩大进程所需要的寻址地址范围,我们发明了虚拟地址(这里所谓的地址仅仅是虚拟的内存地址), 这里就需要用到物理地址到虚拟地址的映射这个概念。如果没有用到虚拟地址,那么我们寻址变量所需要的地址就实实在在的物理地址。 2.一定要树立一个概念,我们在内存中操作的地址都是MMU映射后的虚拟地址,这个虚拟地址的来源分为两种:一种是将DDR的物理地址映射,一种是将非DDR的其他总线地址进行映射。 由1可只,程序中使用的地址都是虚拟地址,这个虚拟地址由MMU来进行映射转换,mmu转换的都是总线上的地址,他不会知道这个地址是留给ram还是其他模块上用的。我们倒着来, 我们需要在程序中定义一个变量int a = 1,此时我们是找到a的虚拟地址,然后赋值为1,这个地址由编译器在编译的时候指定?(这句话还没有验证),此时指定映射这个 虚拟地址的总线地址就是总线上的物理地址,所以这个操作是内存的物理地址上进行的。

如果我们这样ioremap(0x18xxxx) = 0xxxxxx;此时我们调用ioremap得到0x18xxx的虚拟地址,并给该地址赋值为0xxxx,此时,是指定ioremap这个操作所得到的虚拟地址是由总线上的 其他非预留给RAM的物理地址映射而来的。如果这个0x18xxx地址跃进了内存物理地址,也是一样的,对他而言,他只是将总线上的地址映射到内核空间中划分为IO内存空间的虚拟地址, 所以这个函数实际上可以映射总线上的任何地址)

所以上面这句话应该更正为: 如果我们这样ioremap(0x18xxxx) = 0xxxxxx;此时我们调用ioremap得到0x18xxx的虚拟地址,并给该地址赋值为0xxxx,此时,是指定ioremap这个操作所得到的虚拟地址是由总线上的 物理地址映射而来。如果这个(0x18xxxx是预留给ddr的物理地址,那么你得到的就是一个由内存物理地址映射而来的va,如果这个(0x18xxxx是总线上的其他地址,而这个地址上刚好 挂载着一个ip,那么我们得到的就是一个总线上的寄存器地址映射而来的va。但是通常我们不会去指定的去读写由内存物理地址映射而来的虚拟地址空间,这样会导致程序出错(你 清除掉一个你不知道存放什么数据的内存地址是一个危险操作)。那么我们要去操作非预留给DDR的物理地址空间,我们就要使用ioremap这个函数去映射了。但是一定不要地址越界(和内存地 址)。 也就是说同样是虚拟地址,但是他们的来源不同,非RAM空间的地址总线寻址就需要这些特殊的接口来访问才可以。 这样物理地址到虚拟地址的映射,内存空间与IO空间的概念就可以清楚些

高端内存的使用: 在32位系统中,线性地址空间是4G,其中规定3~4G的范围是内核空间(1G),0~3G是用户空间(3G)。如果把这1G的内核线性地址空间全部拿来直接一一映射物理内存 的话,在内核态的所有进程(线程)能使用的物理内存总共最多只有1G,很显然,如果你有4G内存,3G都不能用来做内核空间,太浪费了!为了能使在内核态的所有进程 能使用更多的物理内存,linux采取了一种变通的形式:它将1G内核线性地址空间分为2部分,第一部分为1G的前896M,这部分内核线性空间与物理内存的0~896M一一映 射,第二部分为1G的后128M的线性空间,拿来动态映射剩下的所有物理内存(即高端内存)。

用户进程没有高端内存概念。只有在内核空间才存在高端内存。用户进程最多只可以访问3G物理内存,而内核进程可以访问所有物理内存(如果ddr小于896M, 虚拟地址一一对应物理地址,若大于896M,则会出现一个高端内存的概念,多余的物理内存则由1G虚拟内存剩余的(1G-896 = )128M虚拟地址空间动态的去访问剩余的所有物理内存)。

转载请注明原文地址: https://www.6miu.com/read-2630705.html

最新回复(0)