linux内核如何管理不到1GB的物理内存?

The*_*ker 48 kernel arm linux-device-driver linux-kernel embedded-linux

我正在学习linux内核的内部结构,在阅读"理解Linux内核"时,有很多与内存相关的问题让我感到震惊.其中之一是,如果我的系统上安装了仅512 MB的物理内存,Linux内核如何处理内存映射.

正如我所读到的,内核将0(或16)MB-896MB物理RAM 映射到0xC0000000线性地址并可直接对其进行寻址.所以,在上面描述的情况下,我只有512 MB:

  • 内核如何从512 MB映射896 MB?在所描述的方案中,内核进行设置,以便每个进程的页表将虚拟地址从0xC0000000映射到0xFFFFFFFF(1GB),直接映射到0x00000000到0x3FFFFFFF(1GB)的物理地址.但是当我只有512 MB物理RAM时,如何将虚拟地址从0xC0000000-0xFFFFFFFF映射到物理0x00000000-0x3FFFFFFF?点是我的物理范围只有0x00000000-0x20000000.

  • 在这种情况下用户模式进程怎么样?

  • 每篇文章都只解释了这种情况,当你安装了4 GB内存并且内核将1 GB映射到内核空间时,用户进程使用剩余的RAM量.

我很感激任何帮助,以提高我的理解.

谢谢..!

osg*_*sgx 45

并非所有虚拟(线性)地址都必须映射到任何地址.如果代码访问未映射的页面,则页面错误会增加.

物理页面可以同时映射到多个虚拟地址.

在4 GB虚拟内存中有2个部分:0x0 ... 0xbfffffff - 是进程虚拟内存和0xc0000000 .. 0xffffffff是内核虚拟内存.

  • 内核如何从512 MB映射896 MB?

它最多可映射到896 MB.因此,如果您只有512,则只会映射512 MB.

如果您的物理内存在0x00000000到0x20000000之间,它将被映射为直接内核访问虚拟地址0xC0000000到0xE0000000(线性映射).

  • 在这种情况下用户模式进程怎么样?

用户进程的物理内存将被映射(不是顺序的,而是随机的页面到页面映射)到虚拟地址0x0 .... 0xc0000000.此映射将是0..896MB页面的第二个映射.页面将从免费页面列表中获取.

  • 用户模式在Phys RAM中处理的位置在哪里?

无处不在.

  • 每篇文章都只解释了当你安装了4 GB内存时的情况

不是.每篇文章都解释了如何映射4 Gb的虚拟地址空间.虚拟内存的大小总是4 GB(对于没有内存扩展的32位机器,如x86的PAE/PSE/etc)

如Robert Love所8.1.3. Memory Zones着的书 Linux Kernel Development(我使用第三版)所述,有几个物理记忆区:

  • ZONE_DMA - 包含低于16 MB的内存页面帧
  • ZONE_NORMAL - 包含16 MB以上和896 MB以下的内存页面帧
  • ZONE_HIGHMEM - 包含896 MB及以上的内存页面帧

因此,如果您有512 MB,则ZONE_HIGHMEM将为空,并且ZONE_NORMAL将具有496 MB的物理内存映射.

另外,请看一下2.5.5.2. Final kernel Page Table when RAM size is less than 896 MB本书的部分内容.当你的内存少于896 MB时就是这种情况.

此外,对于ARM,还有一些虚拟内存布局的描述:http://www.mjmwired.net/kernel/Documentation/arm/memory.txt

线63 PAGE_OFFSET high_memory-1是存储器的直接映射部分


Tho*_*nin 17

硬件提供内存管理单元.它是一个能够拦截和改变任何存储器访问的电路.无论何时处理器访问RAM,例如读取下一条要执行的指令,或者作为由指令触发的数据访问,它都在某个地址处这样做,粗略地说,这是32位值.32位字可以有超过4亿个不同的值,因此存在4 GB 的地址空间:这是可以具有唯一地址的字节数.

因此,处理器将请求发送到其内存子系统,如"获取地址x处的字节并将其返回给我".该请求通过MMU决定如何处理请求.MMU虚拟地将4 GB空间分成页面 ; 页面大小取决于您使用的硬件,但典型大小为4和8 kB.MMU使用表来告诉它如何处理每个页面的访问:访问被授予重写的地址(页面条目说:"是的,包含地址x的页面存在,它在地址y的物理RAM中" )或拒绝,此时调用内核以进一步处理事情.内核可能决定终止违规进程,或者做一些工作并改变MMU表,以便可以再次尝试访问,这次成功.

这是虚拟内存的基础:从这个角度来看,进程有一些RAM,但是内核已经把它移到了硬盘上,在"交换空间"中.相应的表在MMU表中标记为"不存在".当进程访问其数据时,MMU调用内核,该内核从交换中获取数据,将其放回物理RAM中的某个空闲空间,并将MMU表更改为指向该空间.然后内核跳回到进程代码,就在触发整个事件的指令处.除了内存访问花了很长时间之外,进程代码看不到整个业务.

MMU还处理访问权限,这会阻止进程读取或写入属于其他进程或内核的数据.每个进程都有自己的一组MMU表,内核管理这些表.因此,每个进程都有自己的地址空间,就像在具有4 GB RAM的计算机上一样 - 除了进程最好不能访问它没有从内核中正确分配的内存,因为相应的页面被标记缺席或禁止.

当通过某个进程的系统调用调用内核时,内核代码必须在进程的地址空间内运行; 因此内核代码必须位于每个进程的地址空间中(但受保护:MMU表阻止从非特权用户代码访问内核内存).由于代码可以包含硬编码地址,因此内核最好在所有进程的同一地址; 通常,在Linux中,该地址是0xC0000000.每个进程的MMU表将地址空间的一部分映射到内核在引导时实际加载的任何物理 RAM块.请注意,内核内存永远不会被换出(如果可以从交换空间读回数据的代码本身被换掉,那么事情会变得非常快).

在PC上,事情可能会有点复杂,因为有32位和64位模式,段寄存器和PAE(它充当一种具有大页面的二级MMU).基本概念保持不变:每个进程都有自己的虚拟4 GB地址空间视图,内核使用MMU将每个虚拟页面映射到RAM中的适当物理位置,或者根本不存在.