原文地址:http://blog.sina.com.cn/s/blog_6a627cc70101obxd.html
(详细内容请参考《Linux内核完全注释(高清版)》)
5.3 Linux内核对内存的管理和使用
5.3.1 物理内存
Linux0.11默认是使用16MB的内存空间。
前640K用来作内核的代码段和数据段。后面用于主内存区,也就是页。
CPU Intel 80386可以使用两种内存管理(地址变换):分段和分页。其中分段是必需的,分页是可选的。Linux0.11是两者都使用。
5.3.2 内存地址空间概念
虚拟地址、逻辑地址、线性地址、物理地址的区分
虚拟地址:程序产生的由段选择符和段内偏移地址两部分组成的地址。
逻辑地址:程序产生的与段相关的偏移地址。有时虚拟地址也称为逻辑地址。
线性地址:逻辑地址,或者说是段中的偏移地址,加上相应段的基地址就生成了一个线性地址。Intel 80386线性地址空间容量为4G。
物理地址:如果启用了分页机制,线性地址使用页目录和页表中的项变换成物理地址。如果没有使用分页机制,线性地址直接就是物理地址。
Linux0.11给每个程序(进程)划分了64MB的虚拟内存空间。逻辑地址范围是0x0000000到0x4000000
5.3.3 内存分段机制
Intel CPU分段有实模式和保护模式下寻址方式两种。
实模式:使用段和偏移值,段值放在段寄存器,并且段的长度被固定为64KB。段内偏移地址放在任意一个可寻址的寄存器。根据段寄存器和偏移寄存器的值就可以算出实验指向的内存地址。
保护模式:段寄存器放的是一个段描述符表中某一描述符项的索引值。指定的段描述符项中含有段基地址值、段长度值和访问特权级别等。寻址的内存位置于段描述符项中的段基地址值和一个段内偏移值组合而成。段寄存器称为段选择符。
每个描述符占8个字节。一个段可以定义最长长度是4GB。
描述符表有3种,全局描述符表GDT、中断描述符表IDT、局部描述符表LDT。其中LDT应用于多任务系统中,通常每个任务使用一个LDT表。这些表可以保存在线性地址空间的任何地方。需要为CPU分别设置GDTR、IDTR、LDTR三个特殊寄存器来让CPU定位GDT、IDT、LDT。
在Linux0.11中,程序逻辑地址到线性地址的变换过程使用CPU的GDT和LDT。每个任务的LDT本身是由GDT中描述符定义的一个内存段,在该段中存放相应任务的代码段和数据段描述符。每个任务的任务状态段TSS也是GDT中描述符定义的一个内存段。TSS用于任务切换时CPU自动保存或恢复相关任务的当前执行上下文(CPU当前状态)。
5.3.4 内存分页管理
将CPU整个线性内存区域划分成4096字节为1页的内存页面。申请使用内存时以及内存页为单位分配。80386使用页目录表和页表。页目录表项和页表项格式基本相同,占用4个字节,每个页目录表或页表必须只包含1024个页表项。
控制寄存器CR3保存当前页目录表在物理内存的基地址。32位线性地址分成三部分。1个页表有1024项,一个页表最多可映射1024*4KB=4MB内存;一个页目录项最多有1024项,一个页目录项表最多可以映射1024*4MB=4GB内存。
Linux0.1x系统中内存和所有任务都共用一个页目录表,处理器线性地址空间到物理地址空间的映射函数一样。因此它们必须从虚拟地址空间映射到线性地址空间的不同位置。
一个任务的虚拟地址需要首先通过其LDT变换为线性地址,再使用页目录表PDT和页表PT映射到实验物理地址页上。Linux0.11每个进程最大可用虚拟内存空间为64MB,每个进程的逻辑地址加上(任务号)*64MB即可转换为线性地址。0.11内核中人工定义最大任务数NR_TASKS=64个。64*64MB=4G。
5.3.5 CPU多任务和保护方式
5.3.6 虚拟地址、线性地址和物理地址之间的关系
内核代码和数据的地址
页目录表和二级页表已设置成把0-16MB线性地址空间一一对应到物理地址上,占用4个目录项,即4个二级页表。默认情况下Linux0.11内核最多可管理16MB物理内存。
除任务0以外,所有其他任务所需要的物理内存页面与线性地址中的不同或部分不同,因此内核需要动态在主内存区为它们作映射操作,动态建立页目录项和页表项。