Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2279772
  • 博文数量: 668
  • 博客积分: 10016
  • 博客等级: 上将
  • 技术积分: 8588
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-29 19:22
文章分类

全部博文(668)

文章存档

2011年(1)

2010年(2)

2009年(273)

2008年(392)

分类:

2008-08-30 15:48:54

 

LINUX的分页策略

标准Linux的分页是三级页表结构,除了X86支持的页目录和页,还有一级被称为中间页目录。因此,线性地址在转换为物理地址的过程中,线性地址就被解释为四个部分(不是X86所认识的三个部分),增加了页中间目录中的索引。当运行在X86平台上时,Linux通过将中间页目录最大的页目录项个数定义为1,并提供一组相关的宏(这些宏将中间页目录用页目录来替换)将三级页面结构分解过程完美的转换为X86使用的二级页面分解。这样,无需改动内核中页面解释的主要代码(这些代码都是认为线性地址由四个部分组成)。关于这些宏定义参见Linux源码"/include/asm/pgtable.h","/include/asm/page.h"。

内核态虚拟空间从3GB到3GB+4MB的一段(对应进程页目录第768项指引的页表),被映射到物理地址0x0~0x3FFFFF(4MB)。因此,进程处于内核态时,只要通过访问3GB到3GB+4MB就可访问物理内存的低4MB空间。所有进程从3GB到4GB的线性空间都是一样的,由同样的页目录项,同样的页表,映射到相同的物理内存段。Linux以这种方式让内核态进程共享代码和数据。

Linux分段分页初始化

无论Linux系统如何被引导,经过zImage(参见arch/i386/boot/bootsect.s)或经过LILO,最后都会跳转执行arch/i386/boot/setup.s(被装载到SETUPSEG,物理地址 0x90200),setup.s从BIOS中获取计算机系统的硬件参数(如硬盘参数),放到内存参数区(临时寄放),同时做一些初步的状态检查,为进入保护模式做准备。

保护模式下的内核初始化模块从物理地址0x100000开始执行,该地址开始的代码和数据结构都对应在arch/i386/kernel/head.s中,参见附表3。初始化模块主要功能是对相关寄存器IDT,GDT,页目录及页表等进行初始化。下面,忽略head.s执行流程的细节,概要阐述head.s主要的初始化功能。

1. 部分寄存器的初始化:将段寄存器DS、ES、GS和FS用__KERNEL_DS(0x18,include/asm-i386/segment.h)来初始化(通过前面对段寄存器的描述和段选择符的介绍可知道,其作用是将定位到GDT中的第三项(内核数据段),并设置对该段的操作特限级为0);置位CR0的PG位,并根据CPU的型号选择置位AM, WP, NE 和 MP;用0x101000初始化CR3(页目录swapper_pg_dir的地址);置ESP高32bits为__KERNEL_DS(0x18),低32bits为init_user_stack+8192;LDTR初始化为0。

2. 有关IDT的初始化:这只是临时初始化IDT,进一步的操作在start_kernel中进行;用于表示IDT的变量(idt_table[ ])在arch/i386/kenel/traps.c中定义,变量类型(desc_struct)定义在include/asm-i386/desc.h。IDT共有IDT_ENTRIES(256)个中断描述符,属性字均为0x8E00,每个中断描述符都指向同一个中断服务程序ignore_init。Ignore_int的功能仅仅是输出消息int_msg("unknown interrupt")。而IDTR的值为通过命令lidt idt_descr实现。通过在head.s中查看idt_descr的值可以计算得知,IDT的基地址为idt_table的地址,表长IDT_ENTRIES*8-1(0x7FF)。

3. 有关GDT的初始化:GDT共有GDT_ENTRIES个段描述符。GDT_ENTRIES的计算公式为:12+2*NR_TASKS。其中12表示前面提到的Linux在GDT中保留的12项,NR_TASKS(512)指系统设定容纳的进程数,定义在include/linux/tasks.h。GDT在head.s直接分配存储单元(标号为gdt_table)。初始化后的GDT如附表1所示。GDTR的值通过命令lgdt gdt_descr实现。通过在head.s中查看gdt_descr的值可以计算得知,GDT的基地址为gdt_table的地址,表长GDT_ENTRIES*8-1(0x205F)。

4. 页目录的初始化:页目录由变量swapper_pg_dir表示,共有1024个页目录项。其第0项和第768项均指向pg0(第0页),初始化值为0x00102007(根据其高20bits的值0x102换算:0x102*4KB=0x102000,第0页紧跟页目录后,物理地址为0x102000),由此可知,Linux 4GB空间中的虚拟地址0x0和0xBFFFFFFF(3GB)均由pg0映射(物理地址0x0~0x3FFFFF(4MB));其他页目录项初始值为0x0。

5. pg0的初始化:第n项对应第n页,属性为0x007;即第n项的初始化值的高20bits值为n,底12bits值为0x007;由此可见pg0映射了物理空间的低4MB空间;

6. 初始化empty_zero_page:该页的前2KB空间用来存储setup.s保存在内存参数区的来自BIOS的系统硬件参数;后2KB空间作为命令行缓冲区.

阅读(1074) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~