5.3.6 虚拟地址、线性地址和物理地址之间的关系

内核代码和数据的地址linux

  对于linux 0.11内核代码和数据来讲,在head.s程序的初始化操做中已经把内核代码段和数据段都设置成长度为16M的段。在线性地址空间中这两个段的范围重叠,都是从线性地址0开始到地址0XFFFFFF共16M地址范围。在该范围中含有内核全部的代码、内核段表(GDT,IDT,TSS)、页目录表和内核的二级页表、内核局部数据和内核临时堆栈(将被用做第一个任务即任务0的用户堆栈)。其页目录表和二级页表已设置成把0-16M的线性地址空间一一对应到物理地址上,占用了4个目录项即4个二级页表。所以对于内核代码和数据来讲,咱们能够直接把它看做是物理内存中的地址。以下图:shell

  所以,默认状况下Linux 0.11内核最多可管理16MB的物理内存,共有4096个物理页面,每一个页面4KB。经过上述分析能够看出:数据结构

1.内核代码段和数据段区域在线性地址空间和物理地址空间中是同样的,这样设置能够大大简化内核的初始化操做函数

2.GDT和IDT在内核数据段中,所以他们的线性地址也一样等同于他们的物理地址。在实模式下setup.s程序初始化操做中,咱们曾经设置过临时的GDT和IDT,这是进入保护模式以前必须设置的。因为这两个表当时处于物理内存大约0x90200处,而进入保护模式以后内核系统模块处于物理内存0开始位置,而且0x90200处的空间也被挪做他用(用于高速缓冲),所以在进入保护模式后,在运行的第一个程序head.s中要从新设置这两个表。即设置GDTR和IDTR指向新的GDT和IDT,描述符也须要从新加载。因为开启分页机制时这两个表的位置没有变更,所以无需再从新创建或移动表位置。spa

3.除任务0之外,全部其余任务所须要的物理页面与线性地址中不一样或部分不一样,所以内核须要动态的在主内存区中为他们做映射操做,动态的创建页目录项和页表项。虽然任务的代码和数据也在内核中,但因为它须要另行分配得到内存,所以也须要本身的映射表项。blog

任务0的地址对应关系进程

  任务0是系统中第一我的工启动的任务。他的代码段和数据段长度被设置为640kb。该任务的代码和数据直接包含在内核代码和数据中,是从地址0开始的640KB的内容,所以它能够直接使用内核代码已经设置好的页目录和页表进行分页地址变换,一样,它的代码和数据在线性地址空间也是重叠的,对应的任务状态段TSS0也是手工预设值好的,而且位于任务0数据结构中,参见sched.h第113行开始的内容。TSS0段位于内核sched.c程序的代码中,长度为104字节,具体位置参加图5-23中"任务0结构信息"所示。三个位置的对应关系如图5-15所示:内存

 

  因为任务0直接包含在内核中,再也不须要为其从新分配内存页,它运行时须要的内核态堆栈和用户态堆栈空间也都在内核代码区中,而且因为在内核初始化时(head.s)这些内核页面在页表项中的属性都已经被设置成了0b111,即对应页面用户可读写且存在,所以用户堆栈user_stack[]空间虽然在内核空间中,但任务0仍能对其进行读写操做。it

任务1的地址对应关系内存管理

  与任务0相似,任务1也是一个特殊任务。它的代码也在内核代码区域中。与任务0不一样的是在线性地址空间中系统在使用fork()建立任务1(init进程)时为存听任务1的二级页表而在内存中申请了一页内存区域来存放,并复制了父进程的页目录和二级页表项。所以任务1拥有本身的页目录和页表表项,它把任务1占用的线性空间范围64M-128M(其实是64M-64M+640KB)也一样映射到物理地址0-640KB处。此时任务1的长度也是640KB,而且其代码段和数据段相重叠,只占用一个页目录项和一个二级页表。另外,系统还会为任务1在主内存区域中申请一页内存来存放它的任务数据结构和用做任务1的内核堆栈空间。任务数据结构中包括任务1的TSS段结构信息,以下图:


  任务1的用户态堆栈空间将直接共享使用处于内核代码和数据区域(线性地址0-640KB)中任务0的用户态堆栈空间user_stack[](参见kernek/sched.c,第67-72行),所以这个堆栈须要在任务1实际使用时保持“干净”,以确保被复制用于任务1的堆栈不含有无用数据,在刚开始建立任务1时,任务0的用户态堆栈user_stack[]与任务1共享使用,但当任务1 开始运行时,因为任务1映射到user_stack[]处的页表被设置成只读,使得任务1在执行堆栈操做时将会引发写页面异常,从而由内核另行分配主内存区页面做为堆栈空间使用。

  其余任务的地址对应关系

  对于被建立的从任务2开始的其余任务,它们的父进程都是init(任务1)进程,咱们已经知道,在linux 0.11系统中共能够有64个进程同时存在,下面以任务2为例来讲明其余任何任务队地址空间的使用状况。

  从任务2开始若是任务号以nr表示,那么任务nr在线性地址空间中的起始位置被设定在nr*64M处,例如任务2的开始位置=nr*64M=2*64M=128M。任务代码段和数据段的最大长度被设置为64M,所以任务2占有的线性地址空间范围是128M-192M,共占用64M/4M=16个页目录项,虚拟空间中任务代码段和数据段都被映射到线性地址空间中相同的范围,所以它们也会彻底重叠。图5-17显示出了任务2的代码段和数据段在三种地址空间中的对应关系。


  在任务2被建立出来以后,将在其中运行execve()函数来执行shell程序,当内核经过复制任务1刚建立任务2时,除了占用线性地址空间范围不一样之外(128M-128M+640K),此时任务2的代码和数据在三种地址空间中的对应关系和任务1的相似。当任务2的代码(init())调用execve()系统调用开始加载并执行shell()程序时,该系统调用会释放掉从任务1复制的页目录和页表表项及相应的内存页面,而后为新的执行程序shell从新设置页目录和页表表项。在执行execve()函数时,系统虽然为任务2分配了64M的空间范围,可是内核并不会马上为其分配和映射物理页面,只有当任务2开始执行时因为发生缺页而引发异常时才会由内存管理程序为其在主内存区中分配并映射一页物理内存到其线性地址空间中,这种分配和映射物理内存的方法称为需求加载(load on demand).

相关文章
相关标签/搜索