<i id='pmyf1'></i>
      <dl id='pmyf1'></dl>
      <i id='pmyf1'><div id='pmyf1'><ins id='pmyf1'></ins></div></i>

      <fieldset id='pmyf1'></fieldset>
    1. <tr id='pmyf1'><strong id='pmyf1'></strong><small id='pmyf1'></small><button id='pmyf1'></button><li id='pmyf1'><noscript id='pmyf1'><big id='pmyf1'></big><dt id='pmyf1'></dt></noscript></li></tr><ol id='pmyf1'><table id='pmyf1'><blockquote id='pmyf1'><tbody id='pmyf1'></tbody></blockquote></table></ol><u id='pmyf1'></u><kbd id='pmyf1'><kbd id='pmyf1'></kbd></kbd>

      <code id='pmyf1'><strong id='pmyf1'></strong></code>
    2. <acronym id='pmyf1'><em id='pmyf1'></em><td id='pmyf1'><div id='pmyf1'></div></td></acronym><address id='pmyf1'><big id='pmyf1'><big id='pmyf1'></big><legend id='pmyf1'></legend></big></address>

          <ins id='pmyf1'></ins>
            <span id='pmyf1'></span>

            解析Linux系统下的高端内存

            • 时间:
            • 浏览:12
            • 来源:124软件资讯网

                Linux内核地址空间划分

                通常32位Linux内核虚拟地址空间划分0~3G为用户空间 ,3~4G为内核空间(注重  ,内核可以使用的线性地址只有1G)  。注重这里是32位内核地址空间划分  ,64位内核地址空间划分是差别的  。

                通常32位Linux内核虚拟地址空间划分0~3G为用户空间  ,3~4G为内核空间(注重 ,内核可以使用的线性地址只有1G)  。注重这里是32位内核地址空间划分  ,64位内核地址空间划分是差别的  。

                Linux内核高端内存的由来

                当内核模块代码或线程会见内存时  ,代码中的内存地址都为逻辑地址  ,而对应到真正的物理内存地址 ,需要地址一对一的映射 ,如逻辑地址0xc0000003对应的物理地址为0×3  ,0xc0000004对应的物理地址为0×4 ,… … ,逻辑地址与物理地址对应的关系为

                物理地址 = 逻辑地址 – 0xC0000000:这是内核地址空间的地址转换关系  ,注重内核的虚拟地址在“高端” ,可是ta映射的物理内存地址在低端 。

                现实上  ,“内核直接映射空间”也达不到 1G  , 还得留点线性空间给“内核动态映射空间” 呢 。

                因此 ,Linux 划定“内核直接映射空间” 最多映射 896M 物理内存  。

                对于高端内存  ,可以通过 alloc_page() 或者其它函数获得对应的 page  ,可是要想会见现实物理内存  ,还得把 page 转为线性地址才行(为什么?想想 MMU 是怎样会见物理内存的)  ,也就是说 ,我们需要为高端内存对应的 page 找一个线性空间 ,这个历程称为高端内存映射 。

                假 设根据上述简朴的地址映射关系  ,那么内核逻辑地址空间会见为0xc0000000 ~ 0xffffffff ,那么对应的物理内存规模就为0×0 ~ 0×40000000  ,即只能会见1G物理内存 。若机械中安装8G物理内存  ,那么内核就只能会见前1G物理内存  ,后面7G物理内存将会无法会见  ,由于内核 的地址空间已经所有映射到物理内存地址规模0×0 ~ 0×40000000  。纵然安装了8G物理内存 ,那么物理地址为0×40000001的内存  ,内核该怎么去会见呢?代码中必须要有内存逻辑地址 的  ,0xc0000000 ~ 0xffffffff的地址空间已经被用完了 ,以是无法会见物理地址0×40000000以后的内存  。

                显 然不能将内核地址空间0xc0000000 ~ 0xfffffff所有用来简朴的地址映射  。因此x86架构中将内核地址空间划分三部门:ZONE_DMA、ZONE_NORMAL和 ZONE_HIGHMEM  。ZONE_HIGHMEM即为高端内存 ,这就是内存高端内存观点的由来  。

                在x86结构中  ,三种类型的区域(从3G最先盘算)如下:

                ZONE_DMA 内存最先的16MB

                ZONE_NORMAL 16MB~896MB

                ZONE_HIGHMEM 896MB ~ 竣事(1G)

                高端内存是指物理地址大于 896M 的内存  。对于这样的内存 ,无法在“内核直接映射空间”举行映射  。

                为什么?

                由于“内核直接映射空间”最多只能从 3G 到 4G  ,只能直接映射 1G 物理内存  ,对于大于 1G 的物理内存  ,无能为力  。

                高端内存映射有三种方式:

                1、映射到“内核动态映射空间”

                这种方式很简朴 ,由于通过 vmalloc() ,在“内核动态映射空间”申请内存的时间 ,就可能从高端内存获得页面(参看 vmalloc 的实现) ,因此说高端内存有可能映射到“内核动态映射空间” 中  。

                2、永世内核映射

                若是是通过 alloc_page() 获得了高端内存对应的 page ,怎样给它找个线性空间?

                内核专门为此留出一块线性空间 ,从 PKMAP_BASE 到 FIXADDR_START  ,用于映射高端内存  。在 2.4 内核上  ,这个地址规模是 4G-8M 到 4G-4M 之间 。这个空间起叫“内核永世映射空间”或者“永世内核映射空间”

                这个空间和其它空间使用同样的页目录表  ,对于内核来说  ,就是 swapper_pg_dir  ,对通俗历程来说 ,通过 CR3 寄存器指向 。

                通常情形下  ,这个空间是 4M 巨细 ,因此仅仅需要一个页表即可  ,内核通过来 pkmap_page_table 寻找这个页表  。

                通过 kmap()  , 可以把一个 page 映射到这个空间来

                由于这个空间是 4M 巨细  ,最多能同时映射 1024 个 page  。因此  ,对于不使用的的 page ,应该实时从这个空间释放掉(也除映射关就是解系)  ,通过 kunmap()  ,可以把一个 page 对应的线性地址从这个空间释放出来  。

                3、暂时映射

                内核在 FIXADDR_START 到 FIXADDR_TOP 之间保留了一些线性空间用于特殊需求  。这个空间称为“牢固映射空间”

                在这个空间中  ,有一部门用于高端内存的暂时映射  。

                这块空间具有如下特点:

                1、 每个 CPU 占用一块空间

                2、 在每个 CPU 占用的那块空间中  ,又分为多个小空间  ,每个小空间巨细是 1 个 page ,每个小空间用于一个目的  ,这些目的界说在 kmap_types.h 中的 km_type 中 。

                当要举行一次暂时映射的时间 ,需要指定映射的目的 ,凭据映射目的 ,可以找到对应的小空间  ,然后把这个空间的地址作为映射地址  。这意味着一次暂时映射会导致以前的映射被笼罩 。

                通过 kmap_atomic() 可实现暂时映射  。

                下图简朴简朴表达怎样对高端内存举行映射

                Linux内存线性地址空间巨细为4GB  ,分为2个部门:用户空间部门(通常是3G)和内核空间部门(通常是1G)  。在此我们主要关注内核地址空间部门  。

                内核通过内核页全局目录来治理所有的物理内存 ,由于线性地址前3G空间为用户使用 ,内核页全局目录前768项(恰好3G)除0、1两项外所有为0 ,后256项(1G)用来治理所有的物理内存  。内核页全局目录在编译时静态地界说为swapper_pg_dir数组  ,该数组从物理内存地址0x101000处最先存放 。

                由图可见  ,内核线性地址空间部门从PAGE_OFFSET(通常界说为3G)最先  ,为了将内核装入内存 ,从PAGE_OFFSET最先8M线性地址用来映射内核所在的物理内存地址(也可以说是内核所在虚拟地址是从PAGE_OFFSET最先的);接下来是mem_map数组  ,mem_map的起始线性地址与系统结构相关  ,好比对于UMA结构  ,由于从PAGE_OFFSET最先16M线性地址空间对应的16M物理地址空间是DMA区  ,mem_map数组通常最先于PAGE_OFFSET+16M的线性地址;从PAGE_OFFSET最先到VMALLOC_START – VMALLOC_OFFSET的线性地址空间直接映射到物理内存空间(逐一对应影射 ,物理地址<==>线性地址-PAGE_OFFSET)  ,这段区域的巨细和机械现实拥有的物理内存巨细有关  ,这儿VMALLOC_OFFSET在X86上为8M  ,主要用来防止越界错误;在内存比力小的系统上 ,余下的线性地址空间(还要再减去空缺区即VMALLOC_OFFSET)被vmalloc()函数用来把不一连的物理地址空间映射到一连的线性地址空间上  ,在内存比力大的系统上  ,vmalloc()使用从VMALLOC_START到VMALLOC_END(也即PKMAP_BASE减去2页的空缺页巨细PAGE_SIZE(诠释VMALLOC_END))的线性地址空间  ,此时余下的线性地址空间(还要再减去2页的空缺区即VMALLOC_OFFSET)又可以分成2部门:第一部门从PKMAP_BASE到FIXADDR_START用理由kmap()函数来建设永世映射高端内存;第二部门  ,从FIXADDR_START到FIXADDR_TOP ,这是一个牢固巨细的暂时映射线性地址空间  ,(引用:Fixed virtual addresses are needed for subsystems that need to know the virtual address at compile time such as the APIC)  ,在X86系统结构上  ,FIXADDR_TOP被静态界说为0xFFFFE000,此时这个牢固巨细空间竣事于整个线性地址空间最后4K前面  ,该牢固巨细空间巨细是在编译时盘算出来并存储在__FIXADDR_SIZE变量中  。

                正是由于vmalloc()使用区、kmap()使用区及牢固巨细区(kmap_atomic()使用区)的存在才使ZONE_NORMAL区巨细受到限制  ,由于内核在运行时需要这些函数  ,因此在线性地址空间中至少要VMALLOC_RESERVE巨细的空间  。VMALLOC_RESERVE的巨细与系统结构相关  ,在X86上 ,VMALLOC_RESERVE界说为128M  ,这就是为什么ZONE_NORMAL巨细通常是16M到896M的缘故原由  。