为您找到与物理地址和虚拟地址转换相关的共200个结果:
虚拟地址转换为物理地址的第一步是将从处理器得到的虚拟地址和TLB中的虚拟地址进行比较。,今天读文网小编与大家分享下虚拟地址与物理地址的转换,有需要的朋友不妨了解下。
CPU通过地址来访问内存中的单元,地址有虚拟地址和物理地址之分,如果CPU没有MMU(Memory Management Unit,内存管理单元),或者有MMU但没有启用,CPU核在取指令或访问内存时发出的地址将直接传到CPU芯片的外部地址引脚上,直接被内存芯片(以下称为物理内存,以便与虚拟内存区分)接收,这称为物理地址(Physical Address,以下简称PA),如下图所示。
物理地址示意图
如果CPU启用了MMU,CPU核发出的地址将被MMU截获,从CPU到MMU的地址称为虚拟地址(Virtual Address,以下简称VA),而MMU将这个地址翻译成另一个地址发到CPU芯片的外部地址引脚上,也就是将虚拟地址映射成物理地址,如下图所示[1]。
虚拟地址示意图
MMU将虚拟地址映射到物理地址是以页(Page)为单位的,对于32位CPU通常一页为4K。例如,虚拟地址0xb700 1000~0xb700 1fff是一个页,可能被MMU映射到物理地址0x2000~0x2fff,物理内存中的一个物理页面也称为一个页框(Page Frame)。
内核也不能直接访问物理地址.但因为内核的虚拟地址和物理地址之间只是一个差值0xc0000000的区别,所以从物理地址求虚拟地址或从虚拟地址求物理地址很容易,+-这个差就行了
物理地址(physical address)
用于内存芯片级的单元寻址,与处理器和CPU连接的地址总线相对应。
——这个概念应该是这几个概念中最好理解的一个,但是值得一提的是,虽然可以直接把物理地址理解成插在机器上那根内存本身,把内存看成一个从0字节一直到最大空量逐字节的编号的大数组,然后把这个数组叫做物理地址,但是事实上,这只是一个硬件提供给软件的抽像,内存的寻址方式并不是这样。所以,说它是“与地址总线相对应”,是更贴切一些,不过抛开对物理内存寻址方式的考虑,直接把物理地址与物理的内存一一对应,也是可以接受的。也许错误的理解更利于形而上的抽像。
虚拟内存(virtual memory)
这是对整个内存(不要与机器上插那条对上号)的抽像描述。它是相对于物理内存来讲的,可以直接理解成“不直实的”,“假的”内存,例如,一个0x08000000内存地址,它并不对就物理地址上那个大数组中0x08000000 - 1那个地址元素;
之所以是这样,是因为现代操作系统都提供了一种内存管理的抽像,即虚拟内存(virtual memory)。进程使用虚拟内存中的地址,由操作系统协助相关硬件,把它“转换”成真正的物理地址。这个“转换”,是所有问题讨论的关键。
有了这样的抽像,一个程序,就可以使用比真实物理地址大得多的地址空间。(拆东墙,补西墙,银行也是这样子做的),甚至多个进程可以使用相同的地址。不奇怪,因为转换后的物理地址并非相同的。
——可以把连接后的程序反编译看一下,发现连接器已经为程序分配了一个地址,例如,要调用某个函数A,代码不是call A,而是call 0x0811111111 ,也就是说,函数A的地址已经被定下来了。没有这样的“转换”,没有虚拟地址的概念,这样做是根本行不通的。
打住了,这个问题再说下去,就收不住了。
逻辑地址(logical address)
Intel为了兼容,将远古时代的段式内存管理方式保留了下来。逻辑地址指的是机器语言指令中,用来指定一个操作数或者是一条指令的地址。以上例,我们说的连接器为A分配的0x08111111这个地址就是逻辑地址。
——不过不好意思,这样说,好像又违背了Intel中段式管理中,对逻辑地址要求,“一个逻辑地址,是由一个段标识符加上一个指定段内相对地址的偏移量,表示为 [段标识符:段内偏移量],也就是说,上例中那个0x08111111,应该表示为[A的代码段标识符: 0x08111111],这样,才完整一些”
线性地址(linear address)或也叫虚拟地址(virtual address)
跟逻辑地址类似,它也是一个不真实的地址,如果逻辑地址是对应的硬件平台段式管理转换前地址的话,那么线性地址则对应了硬件页式内存的转换前地址。
-------------------------------------------------------------
CPU将一个虚拟内存空间中的地址转换为物理地址,需要进行两步:首先将给定一个逻辑地址(其实是段内偏移量,这个一定要理解!!!),CPU要利用其段式内存管理单元,先将为个逻辑地址转换成一个线程地址,再利用其页式内存管理单元,转换为最终物理地址。
这样做两次转换,的确是非常麻烦而且没有必要的,因为直接可以把线性地址抽像给进程。之所以这样冗余,Intel完全是为了兼容而已。
物理地址就是,机器内主存的地址,包括RAM和ROM
逻辑地址就是,程序运行在内存中,使用的地址。
虚拟地址就是,cpu支持的内存空间远远大于机器主存的大小,这些多出来的空间对于程序来说是可以用的,这个时候的所有地址都称为虚拟地址
物理地址:最小系统下的存储器的实际地址,一般只是由CPU内存控制器(地址线)可以管理的容量为最大地址,而实际上这个容量(由地址产生的)远大于实际存在的容量;实际的存储器容量所需要的地址(内存)控制器管理的容量;它的大小一般由芯片决定
逻辑地址:相对程序员而言使用的地址,或说程序无需知道具体的实际地址管理数,而只要在系统(操作)允许范围内使用就行了(这时使用的是一种算法控制下的地址,实际上它只是借用地址概念产生的程序运行模式),它所要说明的是方便,也就是一个线性的(最好)的程序(指令)排列方式。它的大小一般由操作系统决定
虚拟地址:将具有存储功能的所有存储器(不仅仅是最小系统概念下的),进行“统一”编址,而不考虑存储器之间的差异(快慢等),这时的地址是一个比逻辑地址理会数学化的编号(地址),它的大小等往往由应用程序决定
看过“虚拟地址与物理地址的转换”
浏览量:2
下载量:0
时间:
内核也不能直接访问物理地址.但因为内核的虚拟地址和物理地址之间只是一个差值0xc0000000的区别,所以从物理地址求虚拟地址或从虚拟地址求物理地址很容易。那么虚拟地址和物理地址怎么转换?读文网小编整理了修改硬盘物理地址的相关资料。供大家参考!
MVA (Modified Virtual address,修改过的虚拟地址,这个地址由CPU产生#1)
step1.通过TTBR找到粗表描述符
转换表基地址#2 + MVA的粗页表索引 = 粗页表的物理地址
step2.通过粗表描述符找到小页描述符
粗页表基地址#3 + MVA的小页表索引 = 小页表的物理地址
step3.通过小页描述符找到物理地址
小页基地址#4 + MVA的页索引 = 物理地址
step1得到的粗页表的物理地址位定义
step2得到的小页表的物理地址位定义
step3得到的物理地址位定义
注1:严格的说,这个地址是可能是FCSE或ARM926ej-s处理器产生
注2:转换表基地址保存在TTBR,详见TTBR
注3:粗页表基地址保存在粗页表描述符中,详见粗页表描述符
注4:小页表基地址保存在粗页表描述符中,详见小页表描述符
--------------------------------------------------------------------------------------
CP15
系统控制协处理器(CP15)被用来配置和控制ARM926ej-s处理器。cache、mmu都通过CP15的寄存器来控制。需要使用专门的指令访问CP15的寄存器。
ARM926ej-s系统中的地址
ARM926ej-s产生的地址为虚地址(VA),FCSE(快速上下文切换控制器)将VA转换为修改过的虚地址(MVA)供MMU使用,MMU将MVA转换为TCM和AMBA总线的物理地址(PA)。
CP15的c1寄存器
c1寄存器是ARM926ej-s处理器的控制寄存器。该寄存器用来使能或禁用cache、配置MMU。
I 0: 禁用iCache,1使能iCache
C 0:禁用dCache,1使能dCache
如果c1寄存器禁用了cache,小页表的C、B位是无效的。
TLB
MMU是OS分页内存管理的硬件基础。MMU使用TLB(Translation lookaside buffer,即旁路转换缓冲,或称为页表缓冲;用来存放虚拟地址到物理地址的转换表)将虚拟地址转换为物理地址。
TLB保存在SDRAM中。
TTBR
TTBR是Translation Table Base Register的缩写,中文全称是:转换表基地址寄存器。TTBR是协处理器CP15的c2寄存器。
由于读取TTBR时Bit13~Bit0是不可预测的,所以粗页表的起始地址必须是按64K对齐的。
粗表描述符
填充为红色的位固定为0/1。Bit8~Bit5为域控制位,可以定义16个域。
小页描述符
填充为红色的位固定为0/1。AP3~AP0为访问控制位,访问控制位和域控制位配合完成了对内存访问权限的管理。在boot中,禁用域控制,同时将AP3~AP0全部设置为3(任何人都可以读写)。只关注 C cache控制位,B buffer控制位。
#写通。读命中,从Dcche读取数据,读未命中,(cache)行填充;写命中,写数据带Dcache,并缓冲到外边存储器写未命中,缓冲到外部存储器
#写回。读命中,从Dcache读取数据,读未命中,(cache)行填充;写命中,写数据带Dcache ;写未命中,缓冲到外部存储器
虚拟地址到物理地址的转换步骤
已知一个虚拟地址0x01AF5518, 则转换的过程如下:
注意: *这里讨论的以Windows下普通模式分页的情况, 也就是2级页表的情况*
1.首先把虚拟地址拆分成3个部分(低12位, 中10位, 高10位), 换成2进制如下:
-> 0000 0001 1010 1111 0101 0101 0001 1000
按照10, 10, 12的位数重新排列后
-> (页目录索引)00 000 00110, (页表项索引)10 1111 0101, (偏移)0101 0001 1000
换算成十六进制后可以得到如下结果
页目录索引 = 6, 页表项索引 = 0x2f5 , 偏移 = 0x518
2. 根据当前的CR3寄存器中的物理地址定位页目录表基址
Cr3中存放的是物理地址, 这个物理地址指向进程的页目录表基址, 由此可以得到
页目录表基址(PDE) = Cr3 = 0xAA0E5000
3. 计算页表项的地址
页表地址存放在页目录表(PDE)中的第6个项目中, 也就是
[0xAA0E5000 + 4 * 6] = [0xAA0E5018] = 0x3D955867, 其中0x00000867为该页表属性值, PTE = 0x3D955000
3. 计算页面物理地址
我们要找的页面在这个页表中的第0x2f5项, 所以虚拟地址所在的页的物理地址为
[0x3D955000 + 0x2f5 * 4] = [0x3D955BD4] =
假设[0x3D955BD4] = 0x7095e847, 页面的物理地址 x0x7095e000, 0x00000847表示的是页面属性
4. 计算最终的物理地址
由虚拟地址分离的偏移可以计算出最终的物理地址为
0x7095E000 + 0x00000518 = 0x7095E518.
看过“虚拟地址和物理地址转换 ”
浏览量:2
下载量:0
时间:
MAC(Media Access Control或者Medium Access Control)地址,意译为媒体访问控制,或称为物理地址、硬件地址,用来定义网络设备的位置。今天读文网小编给大家介绍一下物理地址虚拟地址转换。供大家参考!
物理地址按照页来分配成很多不同的页,每个页有页号
有的页里存放的是页表,有的页里存放的是可以写的内存
每个页的大小是4KB,32位机器有2^32个地址
因此有2^32/2^21=2^20个页号,即2的20次方个虚拟页
物理地址也按照4K来分,但是物理地址一般没有4G大小
|*****4K*****| 第0项
|*****4K*****| 第1项
|*****4K*****| 第2项
|*****4K*****| 第3项
|*****4K*****| 第4项
...
......
ARM的虚拟地址和物理地址的转换
比如按照10 10 12来划分
10位 10位 12位
|0000000010| - |0000000010| - |00000000010|
| 2 | | 2 | | 2 |
按照划分,首先虚拟地址向右便宜22位的到,第一级(首级)页表项
为数值2.
然后根据全局唯一的地址,即首级页表的存放地址,这部分是连续的。
比如地址是第0XFF00 00FF
则可以得到第一级页表内存放的内容:
即读取0XFF00 00FF + 2*4k这个物理地址中的内容,其中分为12bit+20bit
后面20bit表示了第二级页表所在的物理页,为什么用20bit,因为一共有20bit
个物理页,比如得到的值是3,则这个第二级页表的的物理地址是4k*3,然后
看第二个10位,即二级页表的页内便宜,得到的是2,则可以得到第二级页表的
物理得只是4k*3 + 2,然后读取(4k * 3) + 2中的值,32位,其中20位表示了
第三级页表的物理地址,比如是0x0000 FF00,然后读取后12位的值,即2
则得到在第0x0000 ff00这个页表中的第2位,从而得到物理地址。
页表最多占用多少内存?
2^10个32位 2^10个32位 + 2^12个32位
即2^11 + 2^12 = 2kb + 4kb = 6kb
如果不采用2级页表的话
那么有2^20次方个页表项,需要2^20次方个32位,即2^10kb=2MB
2MB也不是很大,可是在linux下,每个进程有自己的独立页表,
那每个进程一上来就分配2MB,这样的开销很大。
因此多级页表,主要是灵活,而且节省空间,每个32bit中有12bit的状态位
表示了页表的各种状态。
已知一个虚拟地址0x01AF5518, 则转换的过程如下:
注意: *这里讨论的以Windows下普通模式分页的情况, 也就是2级页表的情况*
1.首先把虚拟地址拆分成3个部分(低12位, 中10位, 高10位), 换成2进制如下:
-> 0000 0001 1010 1111 0101 0101 0001 1000
按照10, 10, 12的位数重新排列后
-> (页目录索引)00 000 00110, (页表项索引)10 1111 0101, (偏移)0101 0001 1000
换算成十六进制后可以得到如下结果
页目录索引 = 6, 页表项索引 = 0x2f5 , 偏移 = 0x518
2. 根据当前的CR3寄存器中的物理地址定位页目录表基址
Cr3中存放的是物理地址, 这个物理地址指向进程的页目录表基址, 由此可以得到
页目录表基址(PDE) = Cr3 = 0xAA0E5000
3. 计算页表项的地址
页表地址存放在页目录表(PDE)中的第6个项目中, 也就是
[0xAA0E5000 + 4 * 6] = [0xAA0E5018] = 0x3D955867, 其中0x00000867为该页表属性值, PTE = 0x3D955000
3. 计算页面物理地址
我们要找的页面在这个页表中的第0x2f5项, 所以虚拟地址所在的页的物理地址为
[0x3D955000 + 0x2f5 * 4] = [0x3D955BD4] =
假设[0x3D955BD4] = 0x7095e847, 页面的物理地址 x0x7095e000, 0x00000847表示的是页面属性
4. 计算最终的物理地址
由虚拟地址分离的偏移可以计算出最终的物理地址为
0x7095E000 + 0x00000518 = 0x7095E518.
读文网小编介绍了物理地址虚拟地址转换的相关知识,希望你喜欢。
浏览量:2
下载量:0
时间:
读文网小编今天为大家分享虚拟地址到物理地址的转换的操作方法,欢迎大家前来阅读。
已知一个虚拟地址0x01AF5518, 则转换的过程如下:
注意: *这里讨论的以Windows下普通模式分页的情况, 也就是2级页表的情况*
1.首先把虚拟地址拆分成3个部分(低12位, 中10位, 高10位), 换成2进制如下:
-> 0000 0001 1010 1111 0101 0101 0001 1000
按照10, 10, 12的位数重新排列后
-> (页目录索引)00 000 00110, (页表项索引)10 1111 0101, (偏移)0101 0001 1000
换算成十六进制后可以得到如下结果
页目录索引 = 6, 页表项索引 = 0x2f5 , 偏移 = 0x518
2. 根据当前的CR3寄存器中的物理地址定位页目录表基址
Cr3中存放的是物理地址, 这个物理地址指向进程的页目录表基址, 由此可以得到
页目录表基址(PDE) = Cr3 = 0xAA0E5000
3. 计算页表项的地址
页表地址存放在页目录表(PDE)中的第6个项目中, 也就是
[0xAA0E5000 + 4 * 6] = [0xAA0E5018] = 0x3D955867, 其中0x00000867为该页表属性值, PTE = 0x3D955000
3. 计算页面物理地址
我们要找的页面在这个页表中的第0x2f5项, 所以虚拟地址所在的页的物理地址为
[0x3D955000 + 0x2f5 * 4] = [0x3D955BD4] =
假设[0x3D955BD4] = 0x7095e847, 页面的物理地址 x0x7095e000, 0x00000847表示的是页面属性
4. 计算最终的物理地址
由虚拟地址分离的偏移可以计算出最终的物理地址为
0x7095E000 + 0x00000518 = 0x7095E518.
读文网小编分享了虚拟地址到物理地址的转换的操作方法,希望大家喜欢。
浏览量:2
下载量:0
时间:
在确保访问的数据已在物理内存中后,还需要先将虚拟地址转换为物理地址,即"地址映射",那么虚拟地址映射到物理地址怎么做呢?今天读文网小编与大家分享下虚拟地址映射到物理地的具体操作步骤,有需要的朋友不妨了解下。
Win32通过一个两层的表结构来实现地址映射,因为每个进程都拥有私有的4G的虚拟内存空间,相应的,每个进程都有自己的层次表结构来实现其地址映射。
第一层称为页目录,实际就是一个内存页,Win32的内存页有4KB大小,这个内存页以4个字节分为1024项,每一项称为“页目录项”(PDE);
第二层称为页表,这一层共有1024个页表,页表结构与页目录相似,每个页表也都是一个内存页,这个内存页以4KB的大小被分为1024项,页表的每一项被称为页表项(PTE),易知共有1024×1024个页表项。每一个页表项对应一个物理内存中的某一个“内存页”,即共有1024×1024个物理内存页,每个物理内存页为4KB,这样就可以索引到4G大小的虚拟物理内存。
如下图所示(注下图中的页目录项的大小应该是4个字节,而不是4kB):
Win32提供了4GB大小的虚拟地址空间。因此每个虚拟地址都是一个32位的整数值,也就是我们平时所说的指针,即指针的大小为4B。它由三部分组成,如下图:
这三个部分的第一部分,即前10位为页目录下标,用来寻址页目录项,页目录项刚好1024个。找到页目录项后,找对页目录项对应的的页表。第二部分则是用来在页表内寻址,用来找到页表项,共有1024个页表项,通过页表项找到物理内存页。第三部分用来在物理内存页中找到对应的字节,一个页的大小是4KB,12位刚好可以满足寻址要求。
具体的例子:
假设一个线程正在访问一个指针(Win32的指针指的就是虚拟地址)指向的数据,此指针指为0x2A8E317F,下图表示了这一个过程:
0x2A8E317F的二进制写法为0010101010_0011100011_000101111111,为了方便我们把它分为三个部分。
首先按照0010101010寻址,找到页目录项。因为一个页目录项为4KB,那么先将0010101010左移两位,001010101000(0x2A8),用此下标找到页目录项,然后根据此页目录项定位到下一层的某个页表。
然后按照0011100011寻址,在上一步找到页表中寻找页表项。寻址方法与上述方法类似。找到页表项后,就可以找到对应的物理内存页。
最后按照000101111111寻址,寻找页内偏移。
上面的假设的是此数据已在物理内存中,其实判断访问的数据是否在内存中也是在地址映射过程中完成的。Win32系统总是假设数据已在物理内存中,并进行地址映射。页表项中有一位标志位,用来标识包含此数据的页是否在物理内存中,如果在的话,就直接做地址映射,否则,抛出缺页中断,此时页表项也可标识包含此数据的页是否在调页文件中(外存),如果不在则访问违例,程序将会退出,如果在,页表项会查出此数据页在哪个调页文件中,然后将此数据页调入物理内存,再继续进行地址映射。为了实现每个进程拥有私有4G的虚拟地址空间,也就是说每个进程都拥有自己的页目录和页表结构,对不同进程而言,即使是相同的指针(虚拟地址)被不同的进程映射到的物理地址也是不同的,这也意味着在进程之间传递指针是没有意义的。
浏览量:2
下载量:0
时间:
虚拟地址是Windows程序时运行在386保护模式下,这样程序访问存储器所使用的逻辑地址称为虚拟地址,今天读文网小编与大家分享下虚拟地址与物理地址的概念,有需要的朋友不妨了解下。
CPU通过地址来访问内存中的单元,地址有虚拟地址和物理地址之分,如果CPU没有MMU(Memory Management Unit,内存管理单元),或者有MMU但没有启用,CPU核在取指令或访问内存时发出的地址将直接传到CPU芯片的外部地址引脚上,直接被内存芯片(以下称为物理内存,以便与虚拟内存区分)接收,这称为物理地址(Physical Address,以下简称PA),如下图所示。
物理地址示意图
如果CPU启用了MMU,CPU核发出的地址将被MMU截获,从CPU到MMU的地址称为虚拟地址(Virtual Address,以下简称VA),而MMU将这个地址翻译成另一个地址发到CPU芯片的外部地址引脚上,也就是将虚拟地址映射成物理地址,如下图所示[1]。
虚拟地址示意图
MMU将虚拟地址映射到物理地址是以页(Page)为单位的,对于32位CPU通常一页为4K。例如,虚拟地址0xb700 1000~0xb700 1fff是一个页,可能被MMU映射到物理地址0x2000~0x2fff,物理内存中的一个物理页面也称为一个页框(Page Frame)。
内核也不能直接访问物理地址.但因为内核的虚拟地址和物理地址之间只是一个差值0xc0000000的区别,所以从物理地址求虚拟地址或从虚拟地址求物理地址很容易,+-这个差就行了
物理地址(physical address)
用于内存芯片级的单元寻址,与处理器和CPU连接的地址总线相对应。
——这个概念应该是这几个概念中最好理解的一个,但是值得一提的是,虽然可以直接把物理地址理解成插在机器上那根内存本身,把内存看成一个从0字节一直到最大空量逐字节的编号的大数组,然后把这个数组叫做物理地址,但是事实上,这只是一个硬件提供给软件的抽像,内存的寻址方式并不是这样。所以,说它是“与地址总线相对应”,是更贴切一些,不过抛开对物理内存寻址方式的考虑,直接把物理地址与物理的内存一一对应,也是可以接受的。也许错误的理解更利于形而上的抽像。
虚拟内存(virtual memory)
这是对整个内存(不要与机器上插那条对上号)的抽像描述。它是相对于物理内存来讲的,可以直接理解成“不直实的”,“假的”内存,例如,一个0x08000000内存地址,它并不对就物理地址上那个大数组中0x08000000 - 1那个地址元素;
之所以是这样,是因为现代操作系统都提供了一种内存管理的抽像,即虚拟内存(virtual memory)。进程使用虚拟内存中的地址,由操作系统协助相关硬件,把它“转换”成真正的物理地址。这个“转换”,是所有问题讨论的关键。
有了这样的抽像,一个程序,就可以使用比真实物理地址大得多的地址空间。(拆东墙,补西墙,银行也是这样子做的),甚至多个进程可以使用相同的地址。不奇怪,因为转换后的物理地址并非相同的。
——可以把连接后的程序反编译看一下,发现连接器已经为程序分配了一个地址,例如,要调用某个函数A,代码不是call A,而是call 0x0811111111 ,也就是说,函数A的地址已经被定下来了。没有这样的“转换”,没有虚拟地址的概念,这样做是根本行不通的。
打住了,这个问题再说下去,就收不住了。
逻辑地址(logical address)
Intel为了兼容,将远古时代的段式内存管理方式保留了下来。逻辑地址指的是机器语言指令中,用来指定一个操作数或者是一条指令的地址。以上例,我们说的连接器为A分配的0x08111111这个地址就是逻辑地址。
——不过不好意思,这样说,好像又违背了Intel中段式管理中,对逻辑地址要求,“一个逻辑地址,是由一个段标识符加上一个指定段内相对地址的偏移量,表示为 [段标识符:段内偏移量],也就是说,上例中那个0x08111111,应该表示为[A的代码段标识符: 0x08111111],这样,才完整一些”
线性地址(linear address)或也叫虚拟地址(virtual address)
跟逻辑地址类似,它也是一个不真实的地址,如果逻辑地址是对应的硬件平台段式管理转换前地址的话,那么线性地址则对应了硬件页式内存的转换前地址。
-------------------------------------------------------------
CPU将一个虚拟内存空间中的地址转换为物理地址,需要进行两步:首先将给定一个逻辑地址(其实是段内偏移量,这个一定要理解!!!),CPU要利用其段式内存管理单元,先将为个逻辑地址转换成一个线程地址,再利用其页式内存管理单元,转换为最终物理地址。
这样做两次转换,的确是非常麻烦而且没有必要的,因为直接可以把线性地址抽像给进程。之所以这样冗余,Intel完全是为了兼容而已。
物理地址就是,机器内主存的地址,包括RAM和ROM
逻辑地址就是,程序运行在内存中,使用的地址。
虚拟地址就是,cpu支持的内存空间远远大于机器主存的大小,这些多出来的空间对于程序来说是可以用的,这个时候的所有地址都称为虚拟地址
物理地址:最小系统下的存储器的实际地址,一般只是由CPU内存控制器(地址线)可以管理的容量为最大地址,而实际上这个容量(由地址产生的)远大于实际存在的容量;实际的存储器容量所需要的地址(内存)控制器管理的容量;它的大小一般由芯片决定
逻辑地址:相对程序员而言使用的地址,或说程序无需知道具体的实际地址管理数,而只要在系统(操作)允许范围内使用就行了(这时使用的是一种算法控制下的地址,实际上它只是借用地址概念产生的程序运行模式),它所要说明的是方便,也就是一个线性的(最好)的程序(指令)排列方式。它的大小一般由操作系统决定
虚拟地址:将具有存储功能的所有存储器(不仅仅是最小系统概念下的),进行“统一”编址,而不考虑存储器之间的差异(快慢等),这时的地址是一个比逻辑地址理会数学化的编号(地址),它的大小等往往由应用程序决定
看过“虚拟地址与物理地址的概念”
浏览量:2
下载量:0
时间:
虚拟地址是Windows程序时运行在386保护模式下,这样程序访问存储器所使用的逻辑地址称为虚拟地址,大家知道虚拟地址怎样映射到物理地址吗?接下来大家跟着读文网小编一起来了解一下虚拟地址映射到物理地址的解决方法吧。
一般情况下,Linux系统中,进程的4GB内存空间被划分成为两个部分------用户空间和内核空间,大小分别为0~3G,3~4G。
用户进程通常情况下,只能访问用户空间的虚拟地址,不能访问到内核空间。
每个进程的用户空间都是完全独立、互不相干的,用户进程各自有不同的页表。而内核空间是由内核负责映射,它并不会跟着进程改变,是固定的。内核空间地址有自己对应的页表,内核的虚拟空间独立于其他程序。
3~4G之间的内核空间中,从低地址到高地址依次为:物理内存映射区—隔离带—vmalloc虚拟内存分配区—隔离带—高端内存映射区—专用页面映射区—保留区。
【内核空间内存动态申请】
主要包括三个函数:kmalloc(), __get_free_pages, vmalloc。
kmalloc(), __get_free_pages申请的内存位于物理地址映射区,而且在物理上也是连续的,它们与真实的物理地址只有一个固定的偏移,因此存在较简单的转换关系。而vmalloc申请的内存位于vmalloc虚拟内存分配区(这些区都是以线性地址为度量),它在虚拟内存空间给出一块连续的内存区,实质上,这片连续的虚拟内存在物理内存中并不一定连续,而vmalloc申请的虚拟内存和物理内存之间也没有简单的换算关系。
因为vmalloc申请的在虚拟内存空间连续的内存区在物理内存中并不一定连续,可以想象为了完成vmalloc,新的页表需要被建立,因此,知识调用vmalloc来分配少量内存是不妥的。
一般来讲,kmalloc用来分配小于128K的内存,而更大的内存块需要用vmalloc来实现。
【虚拟地址与物理地址关系】
对于内核物理内存映射区的虚拟内存(用kmalloc(), __get_free_pages申请的),使用virt_to_phys()和phys_to_virt()来实现物理地址和内核虚拟地址之间的互相转换。它实际上,仅仅做了3G的地址移位。
上述方法适用于常规内存(内核物理内存映射区),高端内存的虚拟地址与物理地址之间不存在如此简单的换算关系。因为它涉及到了分离物理页的页表控制机制。
【ioremap】
在ARM中,设备的寄存器或者存储块的这部分空间属于内存空间的一部分,我们称之为IO内存。
在内核中访问IO内存之前,我们只有IO内存的物理地址,这样是无法通过软件直接访问的,需要首先用ioremap()函数将设备所处的物理地址映射到内核虚拟地址空间(3GB~4GB)。然后,才能根据映射所得到的内核虚拟地址范围,通过访问指令访问这些IO内存资源。
在将I/O内存资源的物理地址映射成核心虚地址后,理论上讲我们就可以象读写RAM那样直接读写I/O内存资源了。为了保证驱动程序的跨平台的可移植性,我们应该使用Linux中特定的函数来访问I/O内存资源,而不应该通过指向核心虚地址的指针来访问。
【mmap】
用mmap映射一个设备,意味着使用户空间的一段地址关联到设备内存上,这使得只要程序在分配的地址范围内进行读取或者写入,实际上就是对设备的访问。这种数据传输是直接的,不需要用到内核空间作为数据转移的中间站。
remap_page_range函数的功能是构造用于映射一段物理地址的新页表,实现了内核空间与用户空间的映射。
在内核驱动程序的初始化阶段,通过ioremap()将物理地址映射到内核虚拟空间;在驱动程序的mmap系统调用中,使用remap_page_range()将该块ROM映射到用户虚拟空间。这样内核空间和用户空间都能访问这段被映射后的虚拟地址。
Ioremap:
进程空间ç内核空间çIO内存
其中,后面两个指的是同一段物理内存区域,只是一个为虚拟地址,一个为物理地址。进程空间和内核空间对应着不同的物理地址,它们之间的数据传递,是实际的数据的拷贝。
Mmap:
进程空间çIO内存
其中,进程空间mmap得到的那段虚拟地址跟IO内存对应着同一段物理地址。这个过程没有额外的数据中转,读写都直接针对硬件的物理地址进行。
一般来讲,小数据量的传输用ioremap()就足够了,
【IO内存的一般访问方法】
1. 首先是调用request_mem_region()申请资源,即告诉内核,本驱动正在使用这段物理内存,其他驱动不得访问它们。在设备驱动模块加载或open()函数中进行。
2. 接着讲寄存器地址通过ioremap()映射到内核空间虚拟地址,之后就可以通过Linux设备访问编程接口访问这些设备的寄存器了。在设备驱动初始化、write(),read(),ioctl()函数中进行。
3. 访问完成之后,应对ioremap()申请的虚拟地址进行释放,并释放release_mem_region()申请的IO内存资源。在设备驱动模块卸载或release()函数中进行。
看过“虚拟地址怎样映射到物理地址”
浏览量:3
下载量:0
时间:
虚拟地址)被不同的进程映射到的物理地址是不同的,那么大家知道虚拟地址如何映射到物理地址吗?下面跟着读文网小编来一起了解下虚拟地址映射到物理地址吧。
虚拟地址映射到物理地址方法
这里只谈分页管理的机制,也是目前最重要的内存管理机制。
最初的设计想法:
结构图如下:
页的尺寸是4KB,虚拟地址的前20位用于指定一个物理页,后12位用于访问页内偏移。
页表项的结构:
各个位的含义:
P--位0是存在(Present)标志,用于指明表项对地址转换是否有效。P=1表示有效;P=0表示无效。在页转换过程中,如果说涉及的页目录或页表的表项无效,则会导致一个异常。如果P=0,那么除表示表项无效外,其余位可供程序自由使用,如图4-18b所示。例如,操作系统可以使用这些位来保存已存储在磁盘上的页面的序号。
R/W--位1是读/写(Read/Write)标志。如果等于1,表示页面可以被读、写或执行。如果为0,表示页面只读或可执行。当处理器运行在超级用户特权级(级别0、1或2)时,则R/W位不起作用。页目录项中的R/W位对其所映射的所有页面起作用。
U/S--位2是用户/超级用户(User/Supervisor)标志。如果为1,那么运行在任何特权级上的程序都可以访问该页面。如果为0,那么页面只能被运行在超级用户特权级(0、1或2)上的程序访问。页目录项中的U/S位对其所映射的所有页面起作用。
A--位5是已访问(Accessed)标志。当处理器访问页表项映射的页面时,页表表项的这个标志就会被置为1。当处理器访问页目录表项映射的任何页面时,页目录表项的这个标志就会被置为1。处理器只负责设置该标志,操作系统可通过定期地复位该标志来统计页面的使用情况。
D--位6是页面已被修改(Dirty)标志。当处理器对一个页面执行写操作时,就会设置对应页表表项的D标志。处理器并不会修改页目录项中的D标志。
AVL--该字段保留专供程序使用。处理器不会修改这几位,以后的升级处理器也不会。
由于页表占用内存空间太大(1M个元素*4B大小=4MB,也可以这么看:每个进程的虚拟地址空间=4G,页面大小=4K,所以共有1M个页,需要1M个页表项,又因为每个页表项=4B,所以页表大小=4M),为了减少内存占用量,因此设计了层次化的分页结构:页目录表+页表。
层次化的设计想法:
因为4GB的虚拟内存共有1M=220=1048576个4K大小的页面。
我们将这些页面分成210=1024份,即从页表1到页表1024,由页目录表管理;
每一份(每一页表)有210=1024个页,由每一个页表管理,页在页表中是随机的,哪个页位于哪个页表中是没有规律的;
结构图如下:
每个任务都有这样的层次化的分页结构,即每个任务都有自己的页目录表和页表。
从硬件角度来分析:
在处理器中有个控制寄存器CR3,存放着当前任务页目录的物理地址,故又叫做页目录基址寄存器(Page Directory Base Register,PDBR),每个任务都存放了自己的页目录物理地址,当任务切换时,处理器切换到新任务开始执行,更新CR3寄存器的内容,以指向新任务的页目录位置;
相应的,页目录又指向了一个个的页表,每个页表又根据任务的页表项指向了相应的页。其中注意的是,页目录和页表也是普通的页,混迹于全部的物理页中,它们和普通页的不同之处仅仅在于功能不一样,当任务撤销之后, 它们和任务所占用的普通页一样会被回收, 并分配给其他任务(如下图所示)。
下面内容转自《分页机制》,写的很清楚。
地址变换的具体过程
对于Intel处理器来说, 有关分页, 最简单和最基本的机制就是这些; CR3寄存器给出了页目录的物理地址; 页目录给出了所有页表的物理地址, 而每个页表给出了它所包含的页的物理地址. 好了, 该清楚的都清楚了, 唯一还不明白的, 应该是如何用这种层次性的分页结构把线性地址转换成物理地址? 这里举个例子, 某任务加载后, 在4GB虚拟地址空间创建了一个段, 起始地址为0x00800000, 段界限为0x5000, 字节粒度. 当前任务执行时, 段寄存器DS指向该段. 又假设执行了下面一条指令
mov edx, [0x1050]
此时, 段部件会输出线性地址0x00801050. 在没有开启分页机制时, 这就是要访问的物理地址. 但现在开启了分页机制, 所以这是一个下虚拟地址, 要经过页部件转换, 才能得到物理地址.
如下图所示, 处理器的页部件专门负责线性地址到物理地址的转换工作. 它首先将段部件送来的32位线性地址分为3段, 分别是高10位, 中间10位, 低12位. 高10位是页目录的索引, 中间10位是页表的索引, 低12位则作为页内偏移量来用.
当前任务页目录的物理地址在处理器的CR3寄存器中, 假设它的内容为0x00005000. 段管理部件输出的线性地址是0x00801050, 其二进制的形式如图中给出. 高10位是十六进制的0x002, 它是页目录表内的索引,处理器将它乘以4(因为每个目录项4字节), 作为偏移量访问页目录. 最终处理器从物理地址00005008处取得页表的物理地址0x08001000.
线性地址的中间10位为0x001, 处理器用它作为页表索引取得页的物理地址. 将该值乘以4, 作为偏移量访问页表. 最终, 处理器又从物理地址08001004处取得页的物理地址, 这就是我们一直努力寻找的那个页.
页的物理地址是0x0000c000, 而线性地址的低12位是数据所在的页内偏移量. 故处理器将它们相加, 得到物理地址0x0000C050, 这就是线性地址0x00801050所对应的物理地址, 要访问的数据就在这里.
注意, 这种变换不是无缘无故的, 而是事先安排好的. 当任务加载时, 操作系统先创建虚拟的段, 并根据段地址的高20位决定它要用到哪些页目录项和页表项. 然后, 寻找空闲的页, 将原本应该写入段中的数据写到一个或者多个页中, 并将页的物理地址填写到相对应的页表项中. 只有这样做了, 当程序运行的时候, 才能以相反的顺序进行地址变换, 并找到正确的数据.
页目录项, 页表项, CR3和打开分页
页目录项和页表项
页目录和页表中分别存放为页目录项和页表项, 它们的格式如下:
可以看出, 在页目录和页表中, 只保存了页表或者页物理地址的高20位. 原因很简单, 页表或者页的物理地址, 都要求必须是4KB对齐的, 以便于放在一个页内, 故其低12位全是0. 在这种情况下, 可以只关心其高20位, 低12位安排其他用途.
P 是存在位, 为1时, 表示页表或者页位于内存中. 否则, 表示页表或者页不在内存中, 必须先予以创建, 或者从磁盘调入内存后方可使用.
RW 是读/写位. 为0时表示这样的页只能读取, 为1时可读可写
US 是用户/管理位. 为1时, 允许所有特权级别的程序访问; 为0时, 只允许特权级别为0, 1和2的程序访问.
PWT(Page-level Write-Through) 是页级通写位, 和高速缓存有关. "通写"是处理器高速缓存的一种工作方式, 这一位用来间接决定是否采用此种方式来改善页面的访问效率.
PCD(Page-level Cache Disable)是页级高速缓存禁止位, 用来间接决定该表项所指向的那个页是否使用高速缓存策略.
A 是访问位. 该位由处理器固件设置, 用来指示此表项所指向的页是否被访问过.
D(Dirty) 是脏位. 该位由处理器固件设置, 用来指示此表项所指向的页是否写过数据
看过“虚拟地址如何映射到物理地址”
浏览量:3
下载量:0
时间:
每个进程都是独立的虚拟地址空间,两个独立进程的相同地址互不干扰,但是在物理上对每个进程可能也就分了一部分空间给了某个进程,所以中间就要用到映射,那么虚拟地址与物理地址怎么映射呢?今天读文网小编与大家分享下虚拟地址与物理地址映射的具体操作步骤,有需要的朋友不妨了解下。
虚拟地址与物理地址映射过程
这里只谈分页管理的机制,也是目前最重要的内存管理机制。
最初的设计想法:
结构图如下:
页的尺寸是4KB,虚拟地址的前20位用于指定一个物理页,后12位用于访问页内偏移。
页表项的结构:
各个位的含义:
P--位0是存在(Present)标志,用于指明表项对地址转换是否有效。P=1表示有效;P=0表示无效。在页转换过程中,如果说涉及的页目录或页表的表项无效,则会导致一个异常。如果P=0,那么除表示表项无效外,其余位可供程序自由使用,如图4-18b所示。例如,操作系统可以使用这些位来保存已存储在磁盘上的页面的序号。
R/W--位1是读/写(Read/Write)标志。如果等于1,表示页面可以被读、写或执行。如果为0,表示页面只读或可执行。当处理器运行在超级用户特权级(级别0、1或2)时,则R/W位不起作用。页目录项中的R/W位对其所映射的所有页面起作用。
U/S--位2是用户/超级用户(User/Supervisor)标志。如果为1,那么运行在任何特权级上的程序都可以访问该页面。如果为0,那么页面只能被运行在超级用户特权级(0、1或2)上的程序访问。页目录项中的U/S位对其所映射的所有页面起作用。
A--位5是已访问(Accessed)标志。当处理器访问页表项映射的页面时,页表表项的这个标志就会被置为1。当处理器访问页目录表项映射的任何页面时,页目录表项的这个标志就会被置为1。处理器只负责设置该标志,操作系统可通过定期地复位该标志来统计页面的使用情况。
D--位6是页面已被修改(Dirty)标志。当处理器对一个页面执行写操作时,就会设置对应页表表项的D标志。处理器并不会修改页目录项中的D标志。
AVL--该字段保留专供程序使用。处理器不会修改这几位,以后的升级处理器也不会。
由于页表占用内存空间太大(1M个元素*4B大小=4MB,也可以这么看:每个进程的虚拟地址空间=4G,页面大小=4K,所以共有1M个页,需要1M个页表项,又因为每个页表项=4B,所以页表大小=4M),为了减少内存占用量,因此设计了层次化的分页结构:页目录表+页表。
层次化的设计想法:
因为4GB的虚拟内存共有1M=220=1048576个4K大小的页面。
我们将这些页面分成210=1024份,即从页表1到页表1024,由页目录表管理;
每一份(每一页表)有210=1024个页,由每一个页表管理,页在页表中是随机的,哪个页位于哪个页表中是没有规律的;
结构图如下:
每个任务都有这样的层次化的分页结构,即每个任务都有自己的页目录表和页表。
从硬件角度来分析:
在处理器中有个控制寄存器CR3,存放着当前任务页目录的物理地址,故又叫做页目录基址寄存器(Page Directory Base Register,PDBR),每个任务都存放了自己的页目录物理地址,当任务切换时,处理器切换到新任务开始执行,更新CR3寄存器的内容,以指向新任务的页目录位置;
相应的,页目录又指向了一个个的页表,每个页表又根据任务的页表项指向了相应的页。其中注意的是,页目录和页表也是普通的页,混迹于全部的物理页中,它们和普通页的不同之处仅仅在于功能不一样,当任务撤销之后, 它们和任务所占用的普通页一样会被回收, 并分配给其他任务(如下图所示)。
下面内容转自《分页机制》,写的很清楚。
地址变换的具体过程
对于Intel处理器来说, 有关分页, 最简单和最基本的机制就是这些; CR3寄存器给出了页目录的物理地址; 页目录给出了所有页表的物理地址, 而每个页表给出了它所包含的页的物理地址. 好了, 该清楚的都清楚了, 唯一还不明白的, 应该是如何用这种层次性的分页结构把线性地址转换成物理地址? 这里举个例子, 某任务加载后, 在4GB虚拟地址空间创建了一个段, 起始地址为0x00800000, 段界限为0x5000, 字节粒度. 当前任务执行时, 段寄存器DS指向该段. 又假设执行了下面一条指令
mov edx, [0x1050]
此时, 段部件会输出线性地址0x00801050. 在没有开启分页机制时, 这就是要访问的物理地址. 但现在开启了分页机制, 所以这是一个下虚拟地址, 要经过页部件转换, 才能得到物理地址.
如下图所示, 处理器的页部件专门负责线性地址到物理地址的转换工作. 它首先将段部件送来的32位线性地址分为3段, 分别是高10位, 中间10位, 低12位. 高10位是页目录的索引, 中间10位是页表的索引, 低12位则作为页内偏移量来用.
当前任务页目录的物理地址在处理器的CR3寄存器中, 假设它的内容为0x00005000. 段管理部件输出的线性地址是0x00801050, 其二进制的形式如图中给出. 高10位是十六进制的0x002, 它是页目录表内的索引,处理器将它乘以4(因为每个目录项4字节), 作为偏移量访问页目录. 最终处理器从物理地址00005008处取得页表的物理地址0x08001000.
线性地址的中间10位为0x001, 处理器用它作为页表索引取得页的物理地址. 将该值乘以4, 作为偏移量访问页表. 最终, 处理器又从物理地址08001004处取得页的物理地址, 这就是我们一直努力寻找的那个页.
页的物理地址是0x0000c000, 而线性地址的低12位是数据所在的页内偏移量. 故处理器将它们相加, 得到物理地址0x0000C050, 这就是线性地址0x00801050所对应的物理地址, 要访问的数据就在这里.
注意, 这种变换不是无缘无故的, 而是事先安排好的. 当任务加载时, 操作系统先创建虚拟的段, 并根据段地址的高20位决定它要用到哪些页目录项和页表项. 然后, 寻找空闲的页, 将原本应该写入段中的数据写到一个或者多个页中, 并将页的物理地址填写到相对应的页表项中. 只有这样做了, 当程序运行的时候, 才能以相反的顺序进行地址变换, 并找到正确的数据.
页目录项, 页表项, CR3和打开分页
页目录项和页表项
页目录和页表中分别存放为页目录项和页表项, 它们的格式如下:
可以看出, 在页目录和页表中, 只保存了页表或者页物理地址的高20位. 原因很简单, 页表或者页的物理地址, 都要求必须是4KB对齐的, 以便于放在一个页内, 故其低12位全是0. 在这种情况下, 可以只关心其高20位, 低12位安排其他用途.
P 是存在位, 为1时, 表示页表或者页位于内存中. 否则, 表示页表或者页不在内存中, 必须先予以创建, 或者从磁盘调入内存后方可使用.
RW 是读/写位. 为0时表示这样的页只能读取, 为1时可读可写
US 是用户/管理位. 为1时, 允许所有特权级别的程序访问; 为0时, 只允许特权级别为0, 1和2的程序访问.
PWT(Page-level Write-Through) 是页级通写位, 和高速缓存有关. "通写"是处理器高速缓存的一种工作方式, 这一位用来间接决定是否采用此种方式来改善页面的访问效率.
PCD(Page-level Cache Disable)是页级高速缓存禁止位, 用来间接决定该表项所指向的那个页是否使用高速缓存策略.
A 是访问位. 该位由处理器固件设置, 用来指示此表项所指向的页是否被访问过.
D(Dirty) 是脏位. 该位由处理器固件设置, 用来指示此表项所指向的页是否写过数据
PAT(Page Attribute Table) 页属性表支持位. 此位涉及更复杂的分页系统, 和页高速缓存有关, 可以不予理会, 在普通的4KB分页机制中, 处理器建议将其置0.
G 是全局位. 用来指示该表项所指向的页是否为全局性质的. 如果页是全局的, 那么, 它将在高速缓存中一直保存(也就意味着地址转换速度会很快). 因为页高速缓存容量有限, 只能存放频繁使用的那些表项. 而且, 当因任务切换等原因改变CR3寄存器的内容时, 整个页高速缓存的内容都会被刷新.
AVL位卑处理器忽略, 软件可以使用.
CR3(PDBR)和开分页机制
控制寄存器CR3, 也就是页目录表基地址寄存器PDBR, 该寄存器如上图所示.
由于页目录表必须位于一个自然页内(4KB对齐), 故其物理地址的低12位是全0. 低12位除了PCD和PWT外, 都没有使用. 这两位用于控制页目录的高速缓存特性, 参见上面解释.
控制寄存器CR0的最高位PG位, 用于开启分页或者关闭页功能. 当该位清0时, 页功能关闭, 从段部件来的线性地址就是物理地址. 当它置位时, 页功能开启. 只能在保护模式下才能开启分页功能, 当PE位清0时(实模式), 设置PG位将导致处理器产生一个异常中断.
不存在的页表:
使用二级表结构,并没有解决需要使用4MB内存来存放页表的问题。实际上,我们把问题搞得有些复杂了。因为我们需要另增一个页面来存放目录表。然而,二级表结构允许页表被分散在内存各个页面中,而不需要保存在连续的4MB内存块中。另外,并不需要为不存在的或线性地址空间未使用部分分配二级页表。虽然目录表页面必须总是存在于物理内存中,但是二级页表可以在需要时再分配。这使得页表结构的大小对应于实际使用的线性地址空间大小。
页目录表中每个表项也有一个存在(present)属性,类似于页表中的表项。页目录表项中的存在属性指明对应的二级页表是否存在。如果目录表项指明对应的二级页表存在,那么通过访问二级表,表查找过程第2步将同如上描述继续下去。如果存在位表明对应的二级表不存在,那么处理器就会产生一个异常来通知操作系统。页目录表项中的存在属性使得操作系统可以根据实际使用的线性地址范围来分配二级页表页面。
目录表项中的存在位还可以用于在虚拟内存中存放二级页表。这意味着在任何时候只有部分二级页表需要存放在物理内存中,而其余的可保存在磁盘上。处于物理内存中页表对应的页目录项将被标注为存在,以表明可用它们进行分页转换。处于磁盘上的页表对应的页目录项将被标注为不存在。由于二级页表不存在而引发的异常会通知操作系统把缺少的页表从磁盘上加载进物理内存。把页表存储在虚拟内存中减少了保存分页转换表所需要的物理内存量。
总结:给定虚拟地址,怎么找到它对应的物理地址?分两步!
第一步从虚拟地址到线性地址,第二步从线性地址从物理地址。
第一步从段描述符表描述的段基址加上段偏移生成线性地址。
IA32中线性地址高10位为页目录索引,通过此找到页表,线性地址中间10位为页表项索引,通过前面找到的页表加上这个索引,找到页表项。页表项指示着页框号,页框号加上线性地址低12位(页内偏移)就生成了物理地址。
看过“虚拟地址与物理地址怎么映射”
浏览量:2
下载量:0
时间:
IP地址与物理地址怎么转换?对于这个问题,相信网管们都会说很简单,不过我们小白朋友不知道啊,那么IP地址与物理地址怎么转换呢?今天读文网小编与大家分享下IP地址与物理地址转换的解决方法,有兴趣的朋友不妨了解下。
为什么要将IP段地址转化成数字地址?
根据TCP/IP协议规定,IP地址是由32位二进制数组成,而且在INTERNET范围内是唯一的。例如,某台联在因特网上的计算机的IP地址为:
11010010 01001001 10001100 00000010
很明显,这些数字对于人来说不太好记忆。人们为了方便记忆,就将组成计算机的IP地址的32位二进制分成四段,每段8位,中间用小数点隔开,然后将每八位二进制转换成十进制数,这样上述计算机的IP地址就变成了:118.123.15.102。
由于在同一个区域里,IP段都是很相近的,如果拿IP段(118.123.15.102)直接进行比较,在操作上很是麻烦,而且数据的存储也不易实现,所以才会把IP转换成数字地址,再来确定IP段的物理地址。
理解了IP的概念之后,诸如IP(118.123.15.102)怎样转换成数字地址呢?
IP本是32为二进制,为了方便记忆才转化成了四段十进制,所以只要把IP还原成二进制,再转换成十进制就可以得到IP的数字地址。
.NET C# IP与数字地址相互转化:
//IP转换成数字地址
public static uint IPToInt(string ipAddress)
{
string disjunctiveStr = ".,: ";
char[] delimiter = disjunctiveStr.ToCharArray();
string[] startIP = null;
for (int i = 1; i <= 5; i++)
{
startIP = ipAddress.Split(delimiter, i);
}
string a1 = startIP[0].ToString();
string a2 = startIP[1].ToString();
string a3 = startIP[2].ToString();
string a4 = startIP[3].ToString();
uint U1 = uint.Parse(a1);
uint U2 = uint.Parse(a2);
uint U3 = uint.Parse(a3);
uint U4 = uint.Parse(a4);
uint U = U1 << 24;
U += U2 << 16;
U += U3 << 8;
U += U4;
return U;
}
//数字地址转换成IP
public static string IntToIP(uint ipAddress)
{
long ui1 = ipAddress & 0xFF000000;
ui1 = ui1 >> 24;
long ui2 = ipAddress & 0x00FF0000;
ui2 = ui2 >> 16;
long ui3 = ipAddress & 0x0000FF00;
ui3 = ui3 >> 8;
long ui4 = ipAddress & 0x000000FF;
string IPstr = "";
IPstr = System.Convert.ToString(ui1) + "."
+ System.Convert.ToString(ui2) + "."
+ System.Convert.ToString(ui3)
+ "." + System.Convert.ToString(ui4);
return IPstr;
}
转换成数字地址以后是不是查询起来很是方便,只要介于某个IP段,就可以找出具体的物理地址了。当然,前提是有个巨大的IP库。手头上还有一个IP库,大概有36W+的记录。
IP段转换成真实的物理地址可以用在什么地方?
用途有很多啦,
1、比如流量统计啦,
2、I/M聊天工具里的地理位置显示啦,网页上的地理位置显示啦,
3、门户网站有诸多城市区分的,会根据访问者IP来判断访客应该去访问哪个城市的网站板块,
4、有的天气预报网站,默认的就是访客所在的城市。
看过“IP地址与物理地址怎么转换”
浏览量:3
下载量:0
时间:
逻辑地址和物理地址是什么?逻辑地址如何转换成物理地址?看到很多人都在问这个问题,小编为大家分享了逻辑地址如何转换成物理地址的方法,下面大家跟着读文网小编一起来了解一下吧。
在对硬盘进行故障维护或者进行相关软件开发时,不仅需要将硬盘的物理地址转换成逻辑地址,有时还需要知道逻辑地址转换为物理地址的方法。
根据计算机中符号的常用法则,我们用“div”表示除法运算,用“mod”表示取余数运算,其他参数如C、H、S依然表示硬盘当前的柱面、磁头和扇区号,C1、H1、S1、NS和NH含义也和上面一致。在已知硬盘逻辑地址即逻辑扇区号LS的情况下,求硬盘对应的物理地址的柱面号C、磁头号H和扇区号S的方法如下:
C=((Ls div NS)div NH)+ C1
H=((Ls div NS)mod NH)+ H1
S=(Ls mod NH)+ S1
实例:设硬盘的磁头号为4,每磁道17个扇区,其中逻辑硬盘D的第一个扇区在硬盘的柱面120、磁头1、扇区1上,求逻辑D盘上逻辑扇区为2757编号对应的物理地址是多少?
分析:根据上面的已知条件,我们可知C1=120, H1=1,S1=1,NS=17,NH=4,Ls=2757,则将这些数据代入上面的公式可得:
C=((2757 div 17)div 4)+120=160
H=((2757 div 17)mod 4)+1=3
S=(2757 mod 17)+1=4
即逻辑扇区号Ls为2757的硬盘对应的物理地址为柱面号是160、磁头号是3和扇区号为4。
看过“ 逻辑地址如何转换成物理地址”
浏览量:3
下载量:0
时间:
物理地址是明确的、最终用在总线上的编号。那么逻辑地址转物理地址怎么转?读文网小编为大家介绍逻辑地址转物理地址的解决方法。希望大家喜欢。
物理地址:加载到内存地址寄存器中的地址,内存单元的真正地址。在前端总线上传输的内存地址都是物理内存地址,编号从0开始一直到可用物理内存的最高端。这些数字被北桥(Nortbridge chip)映射到实际的内存条上。物理地址是明确的、最终用在总线上的编号,不必转换,不必分页,也没有特权级检查(no translation, no paging, no privilege checks)。
逻辑地址:CPU所生成的地址。逻辑地址是内部和编程使用的、并不唯一。例如,你在进行C语言指针编程中,可以读取指针变量本身值(&操作),实际上这个值就是逻辑地址,它是相对于你当前进程数据段的地址(偏移地址),不和绝对物理地址相干。
(具体步骤 共三步)
1.确定虚拟地址(物理地址)的有效位
例如:假设页面大小1KB,共32页。(页面:逻辑地址 页框:物理地址)
由32(KB)=32×1024(B) 即等于32×1024 字节
二进制用多少位能有效表示这么多字节呢——答是:15位 因为32×1024=2^5×2^10=2^15
2.再次确定逻辑地址页面位数 你应该知道:逻辑地址=页号+页面
还是以上假设,那么页面大小为1KB=1024字节 同样的方法计算出表示位数:10位
如果给你逻辑地址:0000 1111 1000 0000
那么由:011+11100000000(相当于 页号+页面(10位))推得出页号011=3
3.根据页号找出对应的页框号
由 物理地址=页框号×页块大小(页块大小是等于页面大小的)+页内位移(即页面逻辑地址)
根据上面 物理地址=页框号×1024B + 1110000000 ( 这里的相加是指位置上而言)
例如:110+110=110110(即高地址+低地址)
提问:在一分页存储管理系统中,逻辑地址长度为16位,页面大小为4096B,现有一逻辑地址为2F6AH,且第0、1、2页依次存放在物理块5、10、11中,问相应的物理地址为多少?
答:4096B=2^12B
16位寻址一共2^16B
分页存储。共分的页:2^16/2^12=2^4=16 共分16页。
第0页的地址范围 0 - FFFH
第1页的地址范围 1000H - 1FFFH
第2页得地址范围 2000H - 2FFFH
.....
第11页 B000H - BFFFH
第15页 F000H - FFFFH
2F6AH=10 1111 0110 1010 在2页的范围对应物理块11
所以物理地址为:
2F6AH - 2000H + B000H = F6AH + B000H= BF6AH
看过“ 逻辑地址转换物理地址公式 ”
浏览量:2
下载量:0
时间:
?读文网小编整理了虚拟地址物理地址的相关资料。供大家参考!
* /proc/pid/pagemap. This file lets a userspace process find out which
physical frame each virtual page is mapped to. It contains one 64-bit
value for each virtual page, containing the following data (from
fs/proc/task_mmu.c, above pagemap_read):
* Bits 0-54 page frame number (PFN) if present
* Bits 0-4 swap type if swapped
* Bits 5-54 swap offset if swapped
* Bit 55 pte is soft-dirty (see Documentation/vm/soft-dirty.txt)
* Bits 56-60 zero
* Bit 61 page is file-page or shared-anon
* Bit 62 page swapped
* Bit 63 page present
If the page is not present but in swap, then the PFN contains an
encoding of the swap file number and the page's offset into the
swap. Unmapped pages return a null PFN. This allows determining
precisely which pages are mapped (or in swap) and comparing mapped
pages between processes.
接下来,我们根据上述描述,给出获取虚拟地址对应的物理地址的代码
#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define page_map_file "/proc/self/pagemap"
#define PFN_MASK ((((uint64_t)1)<<55)-1)
#define PFN_PRESENT_FLAG (((uint64_t)1)<<63)
int mem_addr_vir2phy(unsigned long vir, unsigned long *phy)
{
int fd;
int page_size=getpagesize();
unsigned long vir_page_idx = vir/page_size;
unsigned long pfn_item_offset = vir_page_idx*sizeof(uint64_t);
uint64_t pfn_item;
fd = open(page_map_file, O_RDONLY);
if (fd<0)
{
printf("open %s failed", page_map_file);
return -1;
}
if ((off_t)-1 == lseek(fd, pfn_item_offset, SEEK_SET))
{
printf("lseek %s failed", page_map_file);
return -1;
}
if (sizeof(uint64_t) != read(fd, &pfn_item, sizeof(uint64_t)))
{
printf("read %s failed", page_map_file);
return -1;
}
if (0==(pfn_item & PFN_PRESENT_FLAG))
{
printf("page is not present");
return -1;
}
*phy = (pfn_item & PFN_MASK)*page_size + vir % page_size;
return 0;
}
如果担心vir地址对应的页面不在内存中,可以在调用mem_addr_vir2phy之前,先访问一下此地址。
例如, int a=*(int *)(void *)vir;
如果担心Linux的swap功能将进程的页面交换到硬盘上从而导致页面的物理地址变化,可以关闭swap功能。
下面两个C库函数可以阻止Linux将当前进程的部分或全部页面交换到硬盘上。
int mlock(const void *addr, size_t len);
int mlockall(int flags);
看过“虚拟地址空间映射到物理地址空间”
浏览量:2
下载量:0
时间:
读文网小编整理了虚拟地址空间映射到物理地址空间的相关资料。供大家参考!
诸如 Notepad.exe 和 MyApp.exe 的进程在用户模式下运行。核心操作系统组件和多个驱动程序在更有特权的内核模式下运行。有关处理器模式的详细信息,请参阅用户模式和内核模式。每个用户模式进程都有其各自的专用虚拟地址空间,但在内核模式下运行的所有代码都共享称为“系统空间”的单个虚拟地址空间。当前用户模式进程的虚拟地址空间称为“用户空间”。
在 32 位 Windows 中,可用的虚拟地址空间共计为 2^32 字节(4 GB)。通常较下的 2 GB 用于用户空间,较上的 2 GB 用于系统空间。
在 32 位 Windows 中,你可以指定(在启动时)超过 2 GB 用于用户空间。结果是系统空间可用的虚拟地址更少。可以将用户空间的大小增至 3 GB,在这种情形下系统空间仅有 1 GB。若要增大用户空间的大小,请使用 BCDEdit /set increaseuserva。
在 64 位 Windows 中,虚拟地址空间的理论大小为 2^64 字节(16 百亿亿字节),但实际上仅使用 16 百亿亿字节范围的一小部分。范围从 0x000'00000000 至 0x7FF'FFFFFFFF 的 8 TB 用于用户空间,范围从 0xFFFF0800'00000000 至 0xFFFFFFFF'FFFFFFFF 的 248 TB 的部分用于系统空间。
用户模式下运行的代码可以访问用户空间,但不能访问系统空间。此限制可防止用户模式代码读或更改受保护的操作系统数据结构。内核模式下运行的代码既可以访问用户空间,也可以访问系统空间。即,在内核模式下运行的代码可以访问系统空间和当前用户模式进程的虚拟地址空间。
在内核模式下运行的驱动程序必须在直接从用户空间地址中读取或写入这些地址时非常小心。此方案说明了原因。
用户模式程序发起从设备读取某些数据的请求。程序提供缓冲区的起始地址以接收数据。
在内核模式下运行的设备驱动程序例程启动读取操作并将控制权返回到其调用程序。
然后,设备中断了当前运行的任何线程以显示读取操作完成。 中断由在此任意线程上运行的内核模式驱动程序例程进行处理,该例程属于任意进程。
此时,驱动程序不得将数据写入用户模式程序在步骤 1 中提供的开始地址。此地址位于发起请求的进程的虚拟地址空间,该进程可能很大程度上不同于当前进程。
虚拟地址(Virtual Address Space)
Win32通过一个两层的表结构来实现地址映射,因为每个进程都拥有私有的4G的虚拟内存空间,相应的,每个进程都有自己的层次表结构来实现其地址映射。
第一层称为页目录,实际就是一个内存页,Win32的内存页有4KB大小,这个内存页以4个字节分为1024项,每一项称为“页目录项”(PDE);
第二层称为页表,这一层共有1024个页表,页表结构与页目录相似,每个页表也都是一个内存页,这个内存页以4KB的大小被分为1024项,页表的每一项被称为页表项(PTE),易知共有1024×1024个页表项。每一个页表项对应一个物理内存中的某一个“内存页”,即共有1024×1024个物理内存页,每个物理内存页为4KB,这样就可以索引到4G大小的虚拟物理内存。
如下图所示(注下图中的页目录项的大小应该是4个字节,而不是4kB):
Win32提供了4GB大小的虚拟地址空间。因此每个虚拟地址都是一个32位的整数值,也就是我们平时所说的指针,即指针的大小为4B。它由三部分组成,如下图:
这三个部分的第一部分,即前10位为页目录下标,用来寻址页目录项,页目录项刚好1024个。找到页目录项后,找对页目录项对应的的页表。第二部分则是用来在页表内寻址,用来找到页表项,共有1024个页表项,通过页表项找到物理内存页。第三部分用来在物理内存页中找到对应的字节,一个页的大小是4KB,12位刚好可以满足寻址要求。
具体的例子:
假设一个线程正在访问一个指针(Win32的指针指的就是虚拟地址)指向的数据,此指针指为0x2A8E317F,下图表示了这一个过程:
0x2A8E317F的二进制写法为0010101010_0011100011_000101111111,为了方便我们把它分为三个部分。
首先按照0010101010寻址,找到页目录项。因为一个页目录项为4KB,那么先将0010101010左移两位,001010101000(0x2A8),用此下标找到页目录项,然后根据此页目录项定位到下一层的某个页表。
然后按照0011100011寻址,在上一步找到页表中寻找页表项。寻址方法与上述方法类似。找到页表项后,就可以找到对应的物理内存页。
最后按照000101111111寻址,寻找页内偏移。
上面的假设的是此数据已在物理内存中,其实判断访问的数据是否在内存中也是在地址映射过程中完成的。Win32系统总是假设数据已在物理内存中,并进行地址映射。页表项中有一位标志位,用来标识包含此数据的页是否在物理内存中,如果在的话,就直接做地址映射,否则,抛出缺页中断,此时页表项也可标识包含此数据的页是否在调页文件中(外存),如果不在则访问违例,程序将会退出,如果在,页表项会查出此数据页在哪个调页文件中,然后将此数据页调入物理内存,再继续进行地址映射。为了实现每个进程拥有私有4G的虚拟地址空间,也就是说每个进程都拥有自己的页目录和页表结构,对不同进程而言,即使是相同的指针(虚拟地址)被不同的进程映射到的物理地址也是不同的,这也意味着在进程之间传递指针是没有意义的。
看过“虚拟地址空间映射到物理地址空间 ”
浏览量:2
下载量:0
时间:
?读文网小编整理了linux环境下虚拟地址物理地址的相关资料。供大家参考!
CPU通过地址来访问内存中的单元,地址有虚拟地址和物理地址之分,如果CPU没有MMU(Memory Management Unit,内存管理单元),或者有MMU但没有启用,CPU核在取指令或访问内存时发出的地址将直接传到CPU芯片的外部地址引脚上,直接被内存芯片(以下称为物理内存,以便与虚拟内存区分)接收,这称为物理地址(Physical Address,以下简称PA),如下图所示。
物理地址示意图
如果CPU启用了MMU,CPU核发出的地址将被MMU截获,从CPU到MMU的地址称为虚拟地址(Virtual Address,以下简称VA),而MMU将这个地址翻译成另一个地址发到CPU芯片的外部地址引脚上,也就是将虚拟地址映射成物理地址,如下图所示[1]。
虚拟地址示意图
MMU将虚拟地址映射到物理地址是以页(Page)为单位的,对于32位CPU通常一页为4K。例如,虚拟地址0xb700 1000~0xb700 1fff是一个页,可能被MMU映射到物理地址0x2000~0x2fff,物理内存中的一个物理页面也称为一个页框(Page Frame)。
内核也不能直接访问物理地址.但因为内核的虚拟地址和物理地址之间只是一个差值0xc0000000的区别,所以从物理地址求虚拟地址或从虚拟地址求物理地址很容易,+-这个差就行了
物理地址(physical address)
用于内存芯片级的单元寻址,与处理器和CPU连接的地址总线相对应。
——这个概念应该是这几个概念中最好理解的一个,但是值得一提的是,虽然可以直接把物理地址理解成插在机器上那根内存本身,把内存看成一个从0字节一直到最大空量逐字节的编号的大数组,然后把这个数组叫做物理地址,但是事实上,这只是一个硬件提供给软件的抽像,内存的寻址方式并不是这样。所以,说它是“与地址总线相对应”,是更贴切一些,不过抛开对物理内存寻址方式的考虑,直接把物理地址与物理的内存一一对应,也是可以接受的。也许错误的理解更利于形而上的抽像。
虚拟内存(virtual memory)
这是对整个内存(不要与机器上插那条对上号)的抽像描述。它是相对于物理内存来讲的,可以直接理解成“不直实的”,“假的”内存,例如,一个0x08000000内存地址,它并不对就物理地址上那个大数组中0x08000000 - 1那个地址元素;
之所以是这样,是因为现代操作系统都提供了一种内存管理的抽像,即虚拟内存(virtual memory)。进程使用虚拟内存中的地址,由操作系统协助相关硬件,把它“转换”成真正的物理地址。这个“转换”,是所有问题讨论的关键。
有了这样的抽像,一个程序,就可以使用比真实物理地址大得多的地址空间。(拆东墙,补西墙,银行也是这样子做的),甚至多个进程可以使用相同的地址。不奇怪,因为转换后的物理地址并非相同的。
——可以把连接后的程序反编译看一下,发现连接器已经为程序分配了一个地址,例如,要调用某个函数A,代码不是call A,而是call 0x0811111111 ,也就是说,函数A的地址已经被定下来了。没有这样的“转换”,没有虚拟地址的概念,这样做是根本行不通的。
Linux下获取虚拟地址对应的物理地址的方法
* /proc/pid/pagemap. This file lets a userspace process find out which
physical frame each virtual page is mapped to. It contains one 64-bit
value for each virtual page, containing the following data (from
fs/proc/task_mmu.c, above pagemap_read):
* Bits 0-54 page frame number (PFN) if present
* Bits 0-4 swap type if swapped
* Bits 5-54 swap offset if swapped
* Bit 55 pte is soft-dirty (see Documentation/vm/soft-dirty.txt)
* Bits 56-60 zero
* Bit 61 page is file-page or shared-anon
* Bit 62 page swapped
* Bit 63 page present
If the page is not present but in swap, then the PFN contains an
encoding of the swap file number and the page's offset into the
swap. Unmapped pages return a null PFN. This allows determining
precisely which pages are mapped (or in swap) and comparing mapped
pages between processes.
接下来,我们根据上述描述,给出获取虚拟地址对应的物理地址的代码
#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define page_map_file "/proc/self/pagemap"
#define PFN_MASK ((((uint64_t)1)<<55)-1)
#define PFN_PRESENT_FLAG (((uint64_t)1)<<63)
int mem_addr_vir2phy(unsigned long vir, unsigned long *phy)
{
int fd;
int page_size=getpagesize();
unsigned long vir_page_idx = vir/page_size;
unsigned long pfn_item_offset = vir_page_idx*sizeof(uint64_t);
uint64_t pfn_item;
fd = open(page_map_file, O_RDONLY);
if (fd<0)
{
printf("open %s failed", page_map_file);
return -1;
}
if ((off_t)-1 == lseek(fd, pfn_item_offset, SEEK_SET))
{
printf("lseek %s failed", page_map_file);
return -1;
}
if (sizeof(uint64_t) != read(fd, &pfn_item, sizeof(uint64_t)))
{
printf("read %s failed", page_map_file);
return -1;
}
if (0==(pfn_item & PFN_PRESENT_FLAG))
{
printf("page is not present");
return -1;
}
*phy = (pfn_item & PFN_MASK)*page_size + vir % page_size;
return 0;
}
如果担心vir地址对应的页面不在内存中,可以在调用mem_addr_vir2phy之前,先访问一下此地址。
例如, int a=*(int *)(void *)vir;
如果担心Linux的swap功能将进程的页面交换到硬盘上从而导致页面的物理地址变化,可以关闭swap功能。
下面两个C库函数可以阻止Linux将当前进程的部分或全部页面交换到硬盘上。
int mlock(const void *addr, size_t len);
int mlockall(int flags);
看过“虚拟地址物理地址linux ”
浏览量:2
下载量:0
时间:
CPU通过地址来访问内存中的单元,地址有虚拟地址和物理地址之分。那么虚拟地址到物理地址,怎么转换?读文网小编整理了修改硬盘物理地址的相关资料。供大家参考!
已知一个虚拟地址0x01AF5518, 则转换的过程如下:
注意: *这里讨论的以Windows下普通模式分页的情况, 也就是2级页表的情况*
1.首先把虚拟地址拆分成3个部分(低12位, 中10位, 高10位), 换成2进制如下:
-> 0000 0001 1010 1111 0101 0101 0001 1000
按照10, 10, 12的位数重新排列后
-> (页目录索引)00 000 00110, (页表项索引)10 1111 0101, (偏移)0101 0001 1000
换算成十六进制后可以得到如下结果
页目录索引 = 6, 页表项索引 = 0x2f5 , 偏移 = 0x518
2. 根据当前的CR3寄存器中的物理地址定位页目录表基址
Cr3中存放的是物理地址, 这个物理地址指向进程的页目录表基址, 由此可以得到
页目录表基址(PDE) = Cr3 = 0xAA0E5000
3. 计算页表项的地址
页表地址存放在页目录表(PDE)中的第6个项目中, 也就是
[0xAA0E5000 + 4 * 6] = [0xAA0E5018] = 0x3D955867, 其中0x00000867为该页表属性值, PTE = 0x3D955000
3. 计算页面物理地址
我们要找的页面在这个页表中的第0x2f5项, 所以虚拟地址所在的页的物理地址为
[0x3D955000 + 0x2f5 * 4] = [0x3D955BD4] =
假设[0x3D955BD4] = 0x7095e847, 页面的物理地址 x0x7095e000, 0x00000847表示的是页面属性
4. 计算最终的物理地址
由虚拟地址分离的偏移可以计算出最终的物理地址为
0x7095E000 + 0x00000518 = 0x7095E518.
看过“虚拟地址到物理地址 ”
浏览量:2
下载量:0
时间:
MAC(Media Access Control或者Medium Access Control)地址,意译为媒体访问控制,或称为物理地址、硬件地址,用来定义网络设备的位置。今天读文网小编给大家介绍一下物理地址与虚拟地址的映射吧。供大家参考!
参考如下
一般情况下,Linux系统中,进程的4GB内存空间被划分成为两个部分------用户空间和内核空间,大小分别为0~3G,3~4G。
用户进程通常情况下,只能访问用户空间的虚拟地址,不能访问到内核空间。
每个进程的用户空间都是完全独立、互不相干的,用户进程各自有不同的页表。而内核空间是由内核负责映射,它并不会跟着进程改变,是固定的。内核空间地址有自己对应的页表,内核的虚拟空间独立于其他程序。
3~4G之间的内核空间中,从低地址到高地址依次为:物理内存映射区—隔离带—vmalloc虚拟内存分配区—隔离带—高端内存映射区—专用页面映射区—保留区。
【内核空间内存动态申请】
主要包括三个函数:kmalloc(), __get_free_pages, vmalloc。
kmalloc(), __get_free_pages申请的内存位于物理地址映射区,而且在物理上也是连续的,它们与真实的物理地址只有一个固定的偏移,因此存在较简单的转换关系。而vmalloc申请的内存位于vmalloc虚拟内存分配区(这些区都是以线性地址为度量),它在虚拟内存空间给出一块连续的内存区,实质上,这片连续的虚拟内存在物理内存中并不一定连续,而vmalloc申请的虚拟内存和物理内存之间也没有简单的换算关系。
因为vmalloc申请的在虚拟内存空间连续的内存区在物理内存中并不一定连续,可以想象为了完成vmalloc,新的页表需要被建立,因此,知识调用vmalloc来分配少量内存是不妥的。
一般来讲,kmalloc用来分配小于128K的内存,而更大的内存块需要用vmalloc来实现。
【虚拟地址与物理地址关系】
对于内核物理内存映射区的虚拟内存(用kmalloc(), __get_free_pages申请的),使用virt_to_phys()和phys_to_virt()来实现物理地址和内核虚拟地址之间的互相转换。它实际上,仅仅做了3G的地址移位。
上述方法适用于常规内存(内核物理内存映射区),高端内存的虚拟地址与物理地址之间不存在如此简单的换算关系。因为它涉及到了分离物理页的页表控制机制。
【ioremap】
在ARM中,设备的寄存器或者存储块的这部分空间属于内存空间的一部分,我们称之为IO内存。
在内核中访问IO内存之前,我们只有IO内存的物理地址,这样是无法通过软件直接访问的,需要首先用ioremap()函数将设备所处的物理地址映射到内核虚拟地址空间(3GB~4GB)。然后,才能根据映射所得到的内核虚拟地址范围,通过访问指令访问这些IO内存资源。
在将I/O内存资源的物理地址映射成核心虚地址后,理论上讲我们就可以象读写RAM那样直接读写I/O内存资源了。为了保证驱动程序的跨平台的可移植性,我们应该使用Linux中特定的函数来访问I/O内存资源,而不应该通过指向核心虚地址的指针来访问。
【mmap】
用mmap映射一个设备,意味着使用户空间的一段地址关联到设备内存上,这使得只要程序在分配的地址范围内进行读取或者写入,实际上就是对设备的访问。这种数据传输是直接的,不需要用到内核空间作为数据转移的中间站。
remap_page_range函数的功能是构造用于映射一段物理地址的新页表,实现了内核空间与用户空间的映射。
在内核驱动程序的初始化阶段,通过ioremap()将物理地址映射到内核虚拟空间;在驱动程序的mmap系统调用中,使用remap_page_range()将该块ROM映射到用户虚拟空间。这样内核空间和用户空间都能访问这段被映射后的虚拟地址。
Ioremap:
进程空间ç内核空间çIO内存
其中,后面两个指的是同一段物理内存区域,只是一个为虚拟地址,一个为物理地址。进程空间和内核空间对应着不同的物理地址,它们之间的数据传递,是实际的数据的拷贝。
Mmap:
进程空间çIO内存
其中,进程空间mmap得到的那段虚拟地址跟IO内存对应着同一段物理地址。这个过程没有额外的数据中转,读写都直接针对硬件的物理地址进行。
一般来讲,小数据量的传输用ioremap()就足够了,
【IO内存的一般访问方法】
1. 首先是调用request_mem_region()申请资源,即告诉内核,本驱动正在使用这段物理内存,其他驱动不得访问它们。在设备驱动模块加载或open()函数中进行。
2. 接着讲寄存器地址通过ioremap()映射到内核空间虚拟地址,之后就可以通过Linux设备访问编程接口访问这些设备的寄存器了。在设备驱动初始化、write(),read(),ioctl()函数中进行。
3. 访问完成之后,应对ioremap()申请的虚拟地址进行释放,并释放release_mem_region()申请的IO内存资源。在设备驱动模块卸载或release()函数中进行。
读文网小编介绍了物理地址虚拟地址映射的相关知识,希望你喜欢。
浏览量:2
下载量:0
时间:
读文网小编今天为大家分享了虚拟地址和物理地址的区别和联系,欢迎大家前来阅读。
CPU通过地址来访问内存中的单元,地址有虚拟地址和物理地址之分,如果CPU没有MMU(Memory Management Unit,内存管理单元),或者有MMU但没有启用,CPU核在取指令或访问内存时发出的地址将直接传到CPU芯片的外部地址引脚上,直接被内存芯片(以下称为物理内存,以便与虚拟内存区分)接收,这称为物理地址(Physical Address,以下简称PA),如下图所示。
如果CPU启用了MMU,CPU核发出的地址将被MMU截获,从CPU到MMU的地址称为虚拟地址(Virtual Address,以下简称VA),而MMU将这个地址翻译成另一个地址发到CPU芯片的外部地址引脚上,也就是将虚拟地址映射成物理地址,如下图所示。
MMU将虚拟地址映射到物理地址是以页(Page)为单位的,对于32位CPU通常一页为4K。例如,虚拟地址0xb700 1000~0xb700 1fff是一个页,可能被MMU映射到物理地址0x2000~0x2fff,物理内存中的一个物理页面也称为一个页框(Page Frame)。
物理地址(physical address)
用于内存芯片级的单元寻址,与处理器和CPU连接的地址总线相对应。
——这个概念应该是这几个概念中最好理解的一个,但是值得一提的是,虽然可以直接把物理地址理解成插在机器上那根内存本身,把内存看成一个从0字节一直到最大空量逐字节的编号的大数组,然后把这个数组叫做物理地址,但是事实上,这只是一个硬件提供给软件的抽像,内存的寻址方式并不是这样。所以,说它是“与地址总线相对应”,是更贴切一些,不过抛开对物理内存寻址方式的考虑,直接把物理地址与物理的内存一一对应,也是可以接受的。也许错误的理解更利于形而上的抽像。
虚拟内存(virtual memory)
这是对整个内存(不要与机器上插那条对上号)的抽像描述。它是相对于物理内存来讲的,可以直接理解成“不直实的”,“假的”内存,例如,一个0x08000000内存地址,它并不对就物理地址上那个大数组中0x08000000 - 1那个地址元素;
之所以是这样,是因为现代操作系统都提供了一种内存管理的抽像,即虚拟内存(virtual memory)。进程使用虚拟内存中的地址,由操作系统协助相关硬件,把它“转换”成真正的物理地址。这个“转换”,是所有问题讨论的关键。
有了这样的抽像,一个程序,就可以使用比真实物理地址大得多的地址空间。(拆东墙,补西墙,银行也是这样子做的),甚至多个进程可以使用相同的地址。不奇怪,因为转换后的物理地址并非相同的。
——可以把连接后的程序反编译看一下,发现连接器已经为程序分配了一个地址,例如,要调用某个函数A,代码不是call A,而是call 0x0811111111 ,也就是说,函数A的地址已经被定下来了。没有这样的“转换”,没有虚拟地址的概念,这样做是根本行不通的。
打住了,这个问题再说下去,就收不住了。
逻辑地址(logical address)
Intel为了兼容,将远古时代的段式内存管理方式保留了下来。逻辑地址指的是机器语言指令中,用来指定一个操作数或者是一条指令的地址。以上例,我们说的连接器为A分配的0x08111111这个地址就是逻辑地址。
——不过不好意思,这样说,好像又违背了Intel中段式管理中,对逻辑地址要求,“一个逻辑地址,是由一个段标识符加上一个指定段内相对地址的偏移量,表示为 [段标识符:段内偏移量],也就是说,上例中那个0x08111111,应该表示为[A的代码段标识符: 0x08111111],这样,才完整一些”
线性地址(linear address)或也叫虚拟地址(virtual address)
跟逻辑地址类似,它也是一个不真实的地址,如果逻辑地址是对应的硬件平台段式管理转换前地址的话,那么线性地址则对应了硬件页式内存的转换前地址。
读文网小编分享了虚拟地址和物理地址的区别和联系,希望大家喜欢。
浏览量:2
下载量:0
时间: