seo技术主管:内核代码学习==>深入介绍Linux内核(四)

来源:百度文库 编辑:中财网 时间:2024/05/02 06:44:26

深入介绍Linux内核(四)

深入介绍Linux内核(第四篇)

第四章


本文介绍的Linux作业系统是以Intel公司80X86及相关週边硬体组成的PC系统为基础的。有关80X86 CPU系统程式设计的最佳参考书籍当然是Intel公司发行的一套三卷的英文版《IA-32 Intel体系结构软体发展者手冊》,尤其足其中第3卷:《系统程式设计指南》是理解使用80X86 CPU的作业系统工作原理或进行系统程式设计必不可少的参考资料,实际上本章內容就主要取自於该书。这些资料可以从Intel公司的网站上免费下载。本章主要概要描述80X86 CPU的体系结构以及保护模式下程式设计的一些基础知识,为準备閱读基於80X86CPU的Linux內核原始码打下扎实基础。主要包括:1. 80X86基础知识:2. 保护模式记忆体管理:3. 各种保护措施:4. 中断和異常处理;5. 任务管理:6. 保护模式程式设计的初始化;7. 一个简单的多工內核例子。


本章最后部分介绍的一个简单多工內核足以Linux 0.12內核为基础的一个简化实例。该实例用於演示记忆体分段管理和任务管理的实现方法,沒有包括分页机制內容。但若能彻底理解这个实例的运作机制,那麼在随后閱读Linux內核原始码时就不应该再会碰到什麼大问题了。

若读者对这部分內容已经比较熟悉,那麼可以直接閱读本章最后给出的一个可执行的內核实例。当然,在閱读內核原始码时读者可以随时回过头来参考本章内容。因此並不勉強读者需要完全理解本章內容之后才开始閱读后续章节中的Linux內核代码。

4.180X86系统寄存器和系统指令

为了协助处理器执行初始化和控制系统操作,80X86提供了一个标志寄存器ELAGS和几个系统寄存器,除了一些通用状态标志外,EFLAGS中还包含几个系统标志。这些系统标志用於控制任务切換、中断处理、指令追蹤以及存取许可权。系统寄存器用於记忆体管理和控制处理器操作,含有分段和分页处理机制系统表的基底位址、控制处理器操作的Bit标志位元。


4.1.1 标志寄存器

标志寄存器EFLAGS中的系统标志和IOPL栏位用於控制I/O存取,可遮罩硬体中断,除错、任务切換以及虛拟-8086模式,见图4-l所示。通常只允许作业系统代码有权修改这些标志。EFLAGS中的其他标志是一些通用标志(进位元CF、奇偶PF、辅助进位元AF、零标志ZF、负号SF、方向DF、溢出OF)。这里我们仅对EFLAGS中的系统标志进行说明。





TF 位元8是追蹤标志(Trap Flag)。当设置该位时可为除错操作啟动单步执行方式;复位时则禁止单步执行。在单步执行方式下,处理器会在每个指令执行之后產生一个除错異常,这樣我们就可以观察执行程式在执行每条指令后的状态。如果程式使用POPF、POPFD或IREF指令设置了TF标志,那麼在随后指令之后处理器就会產生一个除错異常。


IOPL 位元13-12是I/O特权级(I/O Privilege Level)栏位。该栏位指明当前执行程式或任务的I/O特权级IOPL。当前执行程式或任务的CPL必须大於等於这个IOPL才能存取I/O位址空间。只有当CPL为特权级0时,程式才可以使用POPF或IRET指令修改这个栏位。 IOPL也是控制对IF标志修改的机制之一。

NT 位元14是巢状任务标志(Nested Task) 。它控制著被中断任务和呼叫任务之间的链结关系。在使用CALl+指令、中断或異常执行任务呼叫时,处理器会设置该标志。在透过使用IRET指令从一个任务返回时,处理器会检查並修改这个NT标志,使用POPF/POPFD指令也可以修改这个标志,但是在应用程式中改变这个标志的状态会產生不可意料的異常。


RF 位元16足恢复标志(Resume Flag) 。该标志用於控制处理器对中断点指令的回应。当设置时,这个标志会临时禁止中断点指令產生的除错異常;当该标志重定时,则中断点指令将会產生異常。RF标志的主要功能是允许在除错異常之后重新执行一条指令。当除错软体使用IRETD指令返回被中断程式之前,需要设置堆栈上EFLAGS內容中的RF标志,以防止指令中断点造成另一个異常。处理器会在指令返回之后自动地清除该标志,从而再次允许指令中断点異常。


VM 位元17是虛拟-8086方式(Virtual-8086 Mode)标志,当设置该标志时,就开啟虛拟一8086方式:当重定该标志时,则回到保护模式。


4.1.2 记忆体管理寄存器

处理器提供了4个记忆体管理寄存器(GDTR、LDTR、IDTR和TR) ,用於指定记忆体分段管理所用系统表的基底位址,见图4-2所示。处理器为这些寄存器的载入和保存提供了特定的指令。有关系统表的作用请参见下一节“保护模式记忆体管理”中的详细说明。






GDTR、LDTR、IDTR和TR都是段基址寄存器,这些段中含有分段机制的重要资讯表。GDTR、IDTR和LDTR用与定址存放描述呼号表的段。TR用于定址一个特殊的任务状态段TSS(Task State Segment)。TSS段中包含着当前执行任务的重要资讯。


1. 全域描述符号表寄存器GDTR

TDTR寄存器中用于存放全域描述符号表GDT的32位元的线性基底位址和16位元的表限长值。基底位址指定GDT表中位元组0在線性位址空间中的位址,表长度指明GDT表的位元组长度值。指令LTDT和SGDT分別用於载入和保存GDTR寄存器的內容。在机器刚加电或处理器复位后,基底位址被预设地设置为0,而长度值被设置成0xFFFF。在保护模式初始化行程中必须给GDTR载入一个新值。



2. 中断描述符号表寄存器IDTR

与GDTR的作用类似,IDTR寄存器用於存放中断描述符号表IDT的32位元線性基底位址和16位元表长度值,指令LIDT和SIDT分別用於载入和保存IDTR寄存器的內容。在机器刚加电或处理器复位后,基底位址被预设地设置为0,而长度值被设置成0xFFFF。


3. 区域描述符号表暂存器LDTR

LDTR寄存器中用於存放区域描述符号表LDT的32位元線性基底位址、16位元段限长和描述符号属性值。指令LLDT和SLDT分別用於载入和保存LDTR寄存器的段描述符号部分。包含LDT表的段必须在GDT表中有一个段描述符号项。当使用LLDT指令把含有LDT表段的选择符号载入进LDTR时,LDT段描述符号的段基底位址、段限长度以及描述符号属性会被自动地载入到LDTR中。当进行任务切換时,处理器会把新任务LDT的段选择符号和段描述符号自动地载入进LDTR中。在机器加电或处理器复位后,段选择符号和基底位址被预设地设置为0,而段长度被设置成0xFFFF。


4. 任务寄存器TR

TR寄存器用於存放当前任务TSS段的16位段选择符号、32位基底位址、16位段长度和描述符号属性值。它引用GDT表中的一个TSS类型的描述符号。指令LTR和STR分別用於载入和保存TR暂存器的段选择符号部分。当使用LTR指令把选择符号载入进任务寄存器时,TSS描述符号中的段基底位址、段限长度以及描述符号属性会被自动地载入到任务寄存器中。当执行任务切換时,处理器会把新任务的TSS的段选择符号和段描述符号自动地载入进任务寄存器TR中。



4.1.3 控制寄存器

控制寄存器(CR0、CR 1、CR2和CR3)用於控制和确定处理器的操作模式以及当前执行任务的特性,见图4-3所示。CR0中含有控制处理器操作模式和状态的系统控制标志;CR1保留不用;CR2含有导致页错误的線性位址。CR3中含有页目錄表实体记忆体基底位址,因此该寄存器也被称为页目录基底位址寄存器PDBR(Page-Directory Base address Register) 。





1. CR0中辅助运算器控制位

CR0的4个Bit位:扩允类型位ET、任务切換位TS、模拟位EM和数学存在位MP用於控制80X86浮点(数学)辅助运算器的操作。有关辅助运算器的详细說明,请参看往后介绍的11章內容。CR0的ET位元(标志)用於选择与辅助运算器进行通信所使用的协定,即指明系统中使用的是80387还是80287辅助运算器。TS、MP和EM位元用於确定浮点指令或WAlT指今是否应该產生一个设备不存在DNA(Device Not Available)異常。这个異常可用来仅为使用浮点运算的任务保存和恢复浮点寄存器。对於沒有使用浮点迎算的任务,这樣做可以加快它们之间的切換操作。

ET CR0的位4是扩允类型标志(Extension Type)。当该标志为l时,表示指明系统有80387辅助运算器存在,并使用32位元辅助运算器协定。ET=0指明使用80287辅助运算器。加果模拟位EM=1,则该位将被忽略。在处理器复位操作时,ET位元俞被初始化指明系统中使用的辅助器类型。如果系统中有80387,则ET被设置成1,否则若有一个80287或者没有辅助运算器,则ET被设置成0。


TS CR0的位3是任务已切換(Task Switched)标志。该标志用於推迟保存任务切換时的辅助运算器內容,直到新任务开始实际执行辅助运算器指令。处理器在每次任务切換时都会设置该标志,並且在执行辅助运算器指令时测试该标志。

如果设置了TS标志並且CR0的EM标志为0,那麼在执行任何辅助运算器指令之前会產生一个设备不存在DNA(Device Not Available)異常。如果设置了TS标志但沒有设置CR0的MP和EM标志,那么在执行辅助运算器指令WAIT/FWAIT之前不会產生设备不存在異常。如果设置了EM标志,那麼TS标志对辅助运算器指令的执行无影响。见表4-1所示。

在任务切換时,处理器並不自动保存辅助运算器的上下文,而是会设置TS标志。这个标志会使得处理器在执行新任务指令流的任何时候遇到一条辅助运算器指令时產生设备不存在異常。设备不存在異常的处理程式可使用CLTS指令清除TS标志,並且保存辅助运算器的上下文。如果任务从沒有使用过辅助运算器,那麼相应辅助运算器上下文就不用保存。

EM CR0的位元2是模拟(EMulation)标志。当该位设置时,表示处理器沒有內部或外部辅助运算器,执行辅助运算器指令时会引起设备不存在異;当清除时,表示系统有辅助运算器。设置这个标志可以迫使所有浮点指令使用软体来模拟。

MP CR0的位元l是监控辅助运算器(Monitor Coprocessor或Math Pesent)标志。用於控制WAIT/FWAIT指令与TS标志的交互作用。如果MP=1、TS=1,那麼执行WAIT指令将產生一个设备不存在異常;如果MP=0,则TS标志不会影响WAIT的执行。





2. CR0中保护控制位

PE CR0的位元。是啟用保护(Protection Enable)标志。当设置该位元时即开啟了保护模式;当重定时即进入真实位址模式。这个标志仅开啟段级保护,而並沒有啟用分页机制。若要啟用分页机制,那麼PE和PG标志都要置位元。


PG CR0的位元31是分页(Paging)标志。当设置该位时即开啟了分页机制;当重定时则禁止分页机制,此时所有線性位址等同於实体位址,在开啟这个标志之前必须已经或者同时开啟PE标志。即若要啟用分页机制,那麼PE和PG标志都要置位元。


WP 对於Intel 80486或以上的CPU、CR0的位元16是防写(Write Protect)标志。当设置该标志时,处理器会禁止超级用戶程式(例如特权级0的程式)向用戶级唯读页面执行写操作;当该位复位时则反之。该标志有利於UNIX类作业系统在建立进程时实现写时复制(Copy on Write)技术。


NE 对於Intel 80486或以上的CPU,CR0的位元5是辅助运算器错误(Numeric Error)标志。当设置该标志时,就啟用了X87辅助运算器错误的內部报告机制;若重定该标志,那麼就使用PC机形式的X87辅助运算器错误报告机制。当NE为重定模式並且CPU的IGNNE输入接腳有信号时,那麼数学辅助运算器X87错误将被忽略。当NE为重定模式並且CPU的IGNNE输入接腳无信号时,那麼非遮罩的数学辅助运算器X87错误将导致处理器透过FERR接腳在外部產生一个中断,並且在执行下一个等待形式浮点指令或WAIT/FWAIT指令之前立刻停止指令执行。CPU的FERR接腳用於模拟外部辅助运算器80387的ERROR接腳,因此通常连接到中断控制器输入请求接腳上。NE标志、IGNNE接腳和FERR接腳用於利用外部逻辑来实现PC机形式的外部错误报告机制。


啟用保护模式PE(Protected Enable)位元(位0)和开敔分页PG(Paging)位元(位31)分別用於控制分段和分页机制。PE用於控制分段机制。如果PE=l,处理器就工作在开啟分段机制环境下,即执行在保护模式下。如果PE=0,则处理器关闭了分段机制,並如同8086工作於真实位址模式下。PG用於控制分页机制。如果PG=1,则开启了分页机制。如果PG=-0,分页机制被禁止,此时线性位址被直接为实体位址使用。

如果PE=0、PG=0,处理器工作在真实位址模式下;如果PG=0、PE=l,处理器工作在沒有开啟分页机制的保护模式下;如果PG=l、PE=0,此时由於不在保护模式下不能啟用分页机制,因此处理器会產生一个一般保护異常,即这种标志组合无效;如果PG=1、PE=l,则处理器工作在开啟了分页机制的保护模式下。

当改变PE和PG位时,我们必须小心。只有当执行程式起码有部分代码司资料在線性位址空间和实体位址空间中具有相同位址时,我们才能改变PG位的设置。此时这部分具有相同位址的代码在分页和未分页世界之问起著桥樑的作用。无论是否开啟分页机制,这部分代码部具有相同的位址。另外,在开啟分页(PG=l)之前必须先更新页高速缓冲TLB。

在修改该了PE位元之后程式必须立刻使用一条跳转指令,以更新处理器执行管道中已经获取的不同模式下的任何指令。在设置PE位元之前,程式必须初始化几个系统段和控制寄存器。在系统刚上电时,处理器被复位成PE=0、PG=0(即实模式状态),以允许开机代码在啟用分段和分页机制之前能夠初始化这些寄存器和资料结构。


3. CR2和CR3

CR2和CR3用於分页机制。CR3含有存放页目錄表页面的实体位址,因此CR3也被称为PDBR。因为页目錄表页面是页对齐的,所以该寄存器只有高20位是有效的。而低12位保留供更高级处理器使用,因此在往CR3中载入一个新值时低12位必须设置为0。


使用MOV指令载入CR3时具有让页高速缓冲无效的副作用。为了減少位址转換所要求的汇流排週期数量,最近存取的页目錄和页表会被存放在处理器的页高速缓冲器件中,该缓冲器件被称为转換查找缓冲区TLB(Translation Lookaside Buffer) 。只有当TLB中不包含要求的页表项时才会使用额外的汇流排週期从记忆体中读取页表项。

即使CR0中的PG位处於重定模式(PG=0) ,我们也能先载入CR3。以允许对分页机制进行初始化。当切換任务时,CR3的內容也会随之改变。但是如果新任务的CR3值与原任务的一樣,处理器就无需更新页高速缓冲。这樣共用页表的任务可以执行得更快。


CR2用於出现页異常时报告出错资讯。在报告页異常时,处理器会把引起異常的線性位址存放在CR2中。因此作业系统中的页異常处理程式可以透过检查CR2的內容来确定線性位址空间中哪一个页面引发了異常。


4.1.4 系统指令

系统指令用於处理系统级功能,例如载入系统寄存器、管理中断等。大多数系统指令只能由处於特权级。的作业系统软体执行,其余一些指令可以在任何特权级上执行,因此应用程式也能使用。表4-2中列出了我们将用到的一些系统指令。其中还指出了它们是否受到保护。





4.2 保护模式记忆体管理

4.2.1 记忆体定址


记忆体是指一组有序位元组组成的阵列,每个位元组有唯一的记忆体位址。记忆体定址则是指对储存在记忆体中的某个指定资料物件的位址进行定位。这里,资料物件是指储存在记忆体中的一个指定资料类型的数值或字串。80X86支持多种资料类型:1位元组、2位元组(1个字)或4位元组(双字或长字)的无符号整型数或带符号整型数,以及多位元组字元串等。通常位元组中某一Bit位的定位或定址可以基於位元组来定址,因此最小资料类型的定址是对l位元组资料(数值或字元)的定位。通常记忆体位址从。开始编址,对於80X86 CPU来說,其位址汇流排宽度为32位元,因此一共有2^32个不同实体位址。即记忆体实体位址空间有4G,总共可以定址4G位元组的实体记忆体。对於多位元组资料类型(例如2位元组整数资料类型),在记忆体中这些位元组相邻存放。80X86首先存放低值位元组,随后位址处存放高值位元组。因此80X86 CPU是一种先存小值(Little Endium)的处理器。

对於80X86 CPU,一条指令主要由操作码(Opcode)和操作对象即运算元(Operand)构成。运算元可以位於一个寄存器中,也可以在记忆体中。若要定位记忆体中的运算元,就要进行记忆体定址。80X86有许多指令的运算元涉及记忆体定址,並且针对所定址物件资料类型的不同,也有很多不同的定址方案可供选择。

为了进行记忆体定址,80X86使用了一种称为段(Segment)的定址技术。这种定址技术把记忆体空间分成一个或多个称为段的線性区域,从而对记忆体中一个资料物件的定址就需要使用一个段的起始位址(即段位址)和一个段內偏移位址两部分构成。段位址部分使用16位元的段选择符号指定,其中14位可以选择2^14次方即16384个段。段內偏移位址部分使用32位元的值来指定,因此段內位址可以是O到4G。即一个段的最大长度可达4G。程式中由16位元的段和32位的偏移构成的48位位址或长指标称为一个逻辑位址(虛拟位址) 。它唯一确定了一个资料物件的段位址和段內偏移位址。而仅由32位偏移位址或指标指定的位址是基於当前段的物件位址。

80X86为段部分提供了6个存放段选择符号的段寄存器:CS、DS、ES、SS、FS和GS。其中CS总是用於定址代码段,而堆栈段则专门使用SS段寄存器。在任何指定时刻由CS定址的段称为当前代码段。此时EIP寄存器中包含了当前代码段內下一条要执行指令的段內偏移位址。因此要执行指令的位址可表示成CS : [EIP]。后面将說明的段间控制转移指令可以被用来为CS和EIP代入新值,从而可以把执行位置政变到其他的代码段中,这樣就实现了在不同段中程式的控制传递。

由段寄存器SS定址的段称为当前堆栈段。堆栈顶端由ESP寄存器內容指定。因此堆栈顶端位址是SS :[ESP]。另外4个段寄存器是通用段寄存器。当指令中沒有指定所运算元据的段时,那麼DS将足预设的资料段寄存器。

为了指定记忆体运算元的段內偏移位址,80X86指令规定了计算偏移量的很多方式,称为指令定址方式。指令的偏移量由三部分相加组成:基底位址寄存器、变址暂存器和一个偏移常数。即:

偏移位址 = 基底位址+ (变址 x 比例 因数) +偏移量


4.2.2 地址变換

任何完整的记忆体管理系统都包含两个关键部分:保护和地址变換。提供保护措施是可以防止一个任务存取另一个任务或作业系统的记忆体区域。位址变換能夠让作业系统在给任务分配记忆体时具有灵活性,並且因为我们可以让某些实体位址不被任何逻辑位址所映射,所以在位址变換行程中同时也提供了记忆体保护功能。

正如上面提到的,电脑中的实体记忆体是位元组的線性阵列,每个位元组具有一个唯一的实体位址;程式中的位址是由两部分构成的逻辑地址。这种逻辑位址並不能直接用於存取实体记忆体,而需要使用位址变換机制将它变換或映射到实体记忆体位址上。记忆体管理机制即用於将这种逻辑位址转換成实体记忆体位址。


为了減少确定位址变換所需要的资讯,变換或映射通常以记忆体块作为操作单位。分段机制和分页机制是两种广泛使用的位址变換技术。它们的不同之处在於逻辑位址是如何组织成被映射的记忆体区块、变換资讯如何指定以及程式设计人员如何进行操作。分段和分页操作都使用驻留在记忆体中的表来指定它们各自的变換资讯。这些表只能由作业系统存取,以防止应用程式擅自修改。


80X86在从逻辑位址到实体位址变換行程中使用了分段和分页两种机制,见图4-4所示。第一阶段使用分段机制把程式的逻辑位址变換成处理器可定址记忆体空问(称为線性位址空间)中的位址。第二阶段使用分页机制把線性位址转换为实体位址。在位址变換行程中,第一阶段的分段变換机制总是使用的,而第二阶段的分页机制则是供选用的。如果沒有啟用分页机制,那麼分段机制產生的线性位址空间就直接映射到处理器的实体位址空间上。实体位址空间定义为处理器在其位址汇流排上能夠產生的位址范围。







⒈ 分段机制

分段提供了隔絕各个代码、资料和堆栈区域的机制,因此多个程式(或任务)可以执行在同一个处理器上而不会互相干扰。分页机制为传统需求页、虛拟记忆体系统提供了实现机制。其中虛拟记忆体系统用於实现程式码按要求被映射到实体记忆体中。分页机制当然也能用於提供多工之间的隔离措施。

如图4-5所示,分段提供了一种机制,用於把处理器可定址的線性位址空间划分成一些较小的称为段的受保护位址空间区域。段可以用来存放程式的代码资料和堆栈,或者用来存放系统资料结构(例如TSS或LDT)。如果处理器中有多个程式或任务在执行,那麼每个程式可分配各自的一套段。此时处理器就可以加強这些段之间的界限,並且确保一个程式不会透过存取另一个程式的段而干扰程式的执行。分段机制还允许对段进行分类。这樣,对特定类型段的操作能够受到限制。


一个系统中所有使用的段都包含在处理器線性位址空间中。为了定位指定段中的一个位元组,程式必须提供一个逻辑位址。逻辑位址包括一个段选择符号和一个偏移量。段选择符号是一个段的唯一标识。另外,段选择符号提供了段描述符号表(例如全域描述符号表GDT)中一个资料结构(称为段描述符号)的偏移量。每个段都有一个段描述符号。段描述符号指明段的大小、存取许可权和段的特权级、段类型以及段的第l个位元组在線性位址空间中的位置(称为段的基底位址)。逻辑位址的偏移量部分加到段的基底位址上就可以定位段中某个位元组位置。因此基底位址加上偏移量就形成了处理器線性位址空间中的位址。


線性位址空间与实体位址空间具有相同的结构。相对於二维的逻辑位址空间来说,它们两者都是一维位址空间。虛拟位址(逻辑位址)空间可包含最多16K的段,而每个段最长可达4GB,使得虛拟位址空问容量达到64T。線性位醱和实体位址空间都是4GB(2³²)。实际上,如果禁用分页机制,那麼線性位址空间就是实体位址空间。






⒉ 分页机制

因为多工系统通常定义的线性位址空间都要比其含有的实体记忆体容量大得多,所以需要使用某种“虚拟化”线性位址空间的方法,即使用虚拟储存技术。虚拟储存是一种记忆体管理技术,使用这种管理技术可让程式人员产生记忆体空间要比电脑中实际记忆体容量大很多的错觉。利用这种错觉,我们可以随意编制大型程式而无考虑实际实体记忆体究竟有多少。


分页机制支援虛拟储存技术。在使用虛拟储存的环境中,大容量的線性位址空间需要使用小块的实体记忆体(RAM或ROM)以及某些外部储存空间(例如大容量硬碟)来模拟。当使用分页时,每个段被划分成页面(通常每页为4KB大小),页面会被储存於实体记忆体中或硬碟上。作业系统透过维护一个页目錄和一些页表来留意这些页面。当程式(或任务)试图存取線性位址空间中的一个位址位置时,处理器就会使用页目錄和页表把線性位址转換成一个实体位址,然后在该记忆体位置上执行所要求的操作(读或写) 。

如果当前被存取的页面不在实体记忆体中,处理器就会中断程式的执行(透过產生一个页错误異常)。然后作业系统就可以从硬碟上把该页面读入实体记忆体中,並继续执行刚才被中断的程式。当作业系统严格实现了分页机制时,那麼对於正确执行的程式来說页面在实体记忆体和硬碟之间的交換就是透明的。

80X86分页机制最适合支援虛拟储存技术。分页机制会使用大小固定的记忆体块,而分段管理则使用了大小可变的区块来管理记忆体。无论在实体记忆体中遗是在硬碟上,分页使用固定大小的区块更为适合管理实体记忆体。另一方面,分段机制使用大小可变的区块更适合处理复杂系统的逻辑分区。可以定义与逻辑区块大小适合的记忆体单元而无需受到固定大小页面的限制。每个段都可以作为一个单元来处理,从而简化了段的保护和共用操作。


分段和分页是两种不同的位址变換机制,它们都对整个位址变換操作提供独立的处理阶段。尽管两种机制都使用储存在记忆体中的变換表,但所用的表结构不同。实际上,段表储存在線性位址空间,而页表则保存在实体位址空间。因而段变換表可由分页机制重新定位而无需段机制的资讯或合作。段变換机制把虛拟位址(逻辑位址)变換成線性位址,並且在線性位址空间中存取自己的表,但是並不知晓分页机制把这些線性位址转換到实体位址的行程。类似地,分页机制也不知道程式產生位址的虛拟位址空间。分页机制只是简单地把線性位址转換成实体位址,並且在实体记忆体中存取自己的转換表。


4.2.3 保护

80X86支持两类保护。其一是透过给每个任务不同的虛拟位址(逻辑位址)空间来完全隔离各个任务。这是透过给每个任务逻辑位址到实体位址不同的变換映射来做到。另一个保护机制对任务进行操作,以保护作业系统记忆体段和处理器特殊系统暂存器不被应用程式存取。


⒈ 任务之间的保护

保护的一个重要方面是提供应用程式各任务之间的保护能力。80X86使用的方法是透过把每个任务放置在不同的虛拟位址空间中,並给予每个任务不同的逻辑位址到实体位址的变換映射。每个任务中的位址变換功能被定义成一个任务中的逻辑位址映射到实体记忆体的一部分区域,而另一个任务中的逻辑位址映射到实体记忆体中的不同区域中。这樣,因为一个任务不可能生成能夠映射到其他任务逻辑位址对应使用的实体记忆体部分,所以所有任务都被隔絕开了。只需给每个任务各自独立的映射表,每个任务就会有不同的位址变換函数。在80X86中,每个任务都有自己的段表和页表。当处理器切換云执行一个新任务时,任务切換
的关键部分就是切換到新任务的变換表。

透过在所有任务中安排具有相同的虛拟到实体位址映射部分,並且把作业系统储存在这个公共的虛拟位址空间部分,作业系统可以被所有任务共用。这个所有任务都具有的相同虛拟位址空间部分被称为全域位址空间(Global address space) 。这也正是现代Linux作业系统使用虛拟位址空间的方式。

每个任务唯一的虛拟位址空间部分被称为区域位址空间(Local address space)。区域位址空间含有需要与系统中其他任务区別开的私有的代码和资料,由於每个任务中具有不同的区域位址空间,因此两个不同任务中对相同虛拟位址处的引用将转換到不同的实体位址处。这使得作业系统可以给与每个任务的记忆体相同的虛拟位址,但仍然能隔絕每个任务。另一方面,所有任务在全域位址空间中对相同虛拟位址的引用将被转換到同一个实体位址处。这让公共代码和资料(例如作业系统)的共用有了支援。


⒉ 特权级保护

在一个任务中,定义了4个执行特权级(Privilege Levels) ,用於依据段中含有资料的敏感度以及任务中不同程式部分的受信程度,来限制对任务中各段的存取。最敏感的资料被赋予了最高特权级,它们只能被任务中最受信任的部分存取。不太敏感的资料被赋予较低的特权级,它们可以被任务中较低特权级的代码存取。
特权级用数字0到3表示,0具有最高特权级,而3则是最低特权级。每个记忆体段都与一个特权级相关联。这个特权级限制具有足夠特权级的程式来存取一个段。我们知道,处理器从CS暂存器指定的段中取得和执行指令,当前特权级(Current Privilege Level) ,即CPL就是当前活动代码段的特权级,並且它定义了当前所执行程式的特权级別。CPL确定了哪些段能夠被程式存取。


每当程式企图存取一个段时,当前特权级就会与段的特权级进行比较,以确定是否有存取许可。在给定CPL执行的一个程式被允许存取同级別的资料段,或者低级別段。任何对高级別段的参照引用都是非法的,並且会引发一个異常来通知作业系统。

每个特权级都有自己的程式堆栈,以避免使用共用堆栈带来的保护问题。当程式从一个特权级切換到另一个特权级上执行时,堆栈段也随之改換到新级別的
堆栈中。


4.3 分段机制

分段机制可用於实现多种系统设计。这些设计范围从使用分段机制的最小功能来保护程式的平坦模型,到使用分段机制建立一个可同时可靠地执行多个程式(或任务)的具有稳固操作环境的多段模型。

多段模型能夠利用分段机制全部功能提供由硬体增強的代码、资料结构、程式和任务的保护措施。通常,每个程式(或任务)都使用自己的段描述符号表以及自己的段。对程式来說段能夠完全是私有的,或者是程式之间共用的,对所有段以及系统上执行程式各自执行环境的存取都由硬体控制。

存取检查不仅能夠用来保护对段界限以外位址的引用,而且也能用来在某些段中防止执行不允许的操作。例如,因为代码段被设计成是唯读形式的段,因此可以用硬体来防止对代码段执行写操作。段中的存取许可权资讯也可以用来设置保护环或级別。保护级別可用於保护作业系统程式不受应用程式非法存取。


4.3.1 段的定义

在上一节概述中已经提到,保护模式中80X86提供了4GB的实体位址空间。这是处理器在其位址汇流排上可以定址的位址空间。这个位址空间是平坦的,位址范围从。到0xFFFFFFFF。这个实体位址空间可以映射到读写记忆体、唯读记忆体以及记忆体映射I/O中。分段机制就是把虛拟位址空间中的虛拟记忆体组织成一些长度可变的称为段的记忆体块单元。80386虛拟位址空问中的虛拟位址(逻辑位址)由一个段部分和一个偏移部分构成。段是虛拟位址到線性位址转換机制的基础。每个段由三个参数定义:

1.段基底位址(Base address),指定段在線性位址空间中的开始位址。基底位址足線性
位址,对应于段中偏移0处。

2.段限长(1imit),是虛拟位址空间中段內最大可用偏移位置。它定义了段的长度。


3. 段属性(Attributes)指定段的特性。例如该段是否可读、可写或可作为一个程式执行;段的特权级等。

段限长定义了在虛拟位址空间中段的大小。段基址和段限长定义了段所映响的線性位址范围或区域。段內0到limit的位址范围对应線性位址中范围base到base + limit。偏移量大於段限长的虛拟位址是无意义的,如果使用则会导致异常,另,若存取一个段並沒有得到段属性许可则也会导致異常。例如,如果你试图写一个唯读的段,那麼80386就会產生一个異常。另外,多个段映射到線性位址中的范围可以部分重疊或覆盖,甚至完全重疊,见图4-6所示。在本文章中介绍的Linux 0.1x系统中,一个任务的代码段和资料段的段限长相同,並被映射到線性位址完全相同而重疊的区域上。






段的基底位址、段限长以及段的保护属性储存在一个称为段描述符号(Segment Descriptor)的结构项中。在逻辑位址到線性位址的转換映射行程中会使用这个段描述符号。段描述符号保存在记忆体中的段描述符号表(Descriptor table)中。段描述符号表是包含段描述符号项的一个简单阵列。前面介绍的段选择符号即用於透过指定表中一个段描述符号的位置来指定相应的段。


即使利用段的最小功能,使用逻辑位址也能存取处理器位址空间中的每个位元组。逻辑位址由16位元的段选择符号和32位的偏移量组成,见图4-7所示。段选择符号指定位元组所在的段,而偏移量指定该位元组在段中相对于段基底位址的位置。处理器会把每个逻辑位址转換成線性位址。線性位址是处理器線性位址空间中的32位元位址。与实体位址空间类似,線性位址空问也是平坦的4GB位址空间,位址范围从。到0xFFFFFFFF 。線性位址空间中含有为系统定义的所有段和系统表。

为了把逻辑位址转換成一个線性位址,处理器会执行以下操作:

⒈使用段选择符号中的偏移值(段索引)在GDT或LDT表中定位相应的段描述符号。
(仅当一个新的段选择符号载入到段暂存器中时才需要这一步。)

⒉利用段描述符号检验段的存取许可权和范围,以确保该段是可存取的並且偏移量位於段
界限內。

⒊把段描述符号中取得的段基底位址加到偏移量上,最后形成一个線性位址。





如果沒有开啟分页,那麼处理器直接把線性位址映射到实体位址(即線性位址被送到处理器位址汇流排上)。如果对線性位址空间进行了分页处理,那麼就会使用二级位址转換把線性位址转換成实体位址。页转換将在稍后进行說明。



注译:

Stack - 堆叠 或者称呼为 堆栈
Segment - 段
Flag - 旗标 或者称呼为 标志
暂存器又称呼为寄存器