[原]80386保护模式软件体系结构
保护模式的寄存器模型:
保护模式新增四个寄存器: 全局描述符寄存器GDTR, 中断描述符寄存器IDTR, 局部描述符LDTR, 任务寄存器TR. 另外一些寄存器的功能得到了扩展. 例如指令指针EIP现在为32位; 标志寄存器EFLAGS的更多位得到了利用; 并且所有四个控制器CR0~CR3都具有了相应的功能.
全局描述符表寄存器:
全局描述符寄存器在物理存储器地址空间定义了一个称为全局描述符表GDT. 全局描述符表是存储管理系统的一个重要组成部分.
GDTR是48位寄存器. 该寄存器低2位标识为limit, 规定了GDT按字节大小. LIMIT的值比实际小1. GDTR的高4个字节标为BASE, 指示物理存储器中的GDT的开始位置. 该32位基地址允许该表定义在内存中线性地址的任何地方.
GDT是用来定义80386全局存储器地址空间的一种机制. 全局存储器是一种可能被许多任务共享的通用资源. 也就是说, 全局存储器中存储地址可被微处理器上所有任务共享.
该表包含一项系统分段描述符. 这些描述符标识全局存储器中的段.
80386在从实模式转到保护模式之前必须将BASE和LIMIT的值装入到GDTR. 80386系统控制命令提供此类命令.
中断描述符表寄存器:
IDTR在内存中定义了一个表. 该表包含中断描述符. 该寄存器和描述符表提供一种机制, 它将程序控制转给中断并执行中断服务程序.
IDTR 48位长,低2字节表示LIMIT, 80386支持256个异常和中断, 因此IDT的大小不能超过256. IDTR高4个字节表示BASE.
IDT中用到的描述符为中断门. 提供了一种将程序控制转给中断服务程序入口的手段. 每个门8字节长, 包含服务程序的属性和起始地址.
IDTR和GDTR一样要在保护模式之前装入. 关于IDTR的装入和保存有特殊的指令. 一旦地址设定, 一般不改变.
LDTR:
局部描述符寄存器: 是存储器管理机制的一部分. 每个任务除了可以访问GDT之外, 还可以访问自己的LDT, 它定义了任务用到的局部存储器地址.
LDTR并不直接定义一个局部描述符, 它只是指向GDT中的LDT描述符的选择符. 如果LDTR装入了相应的选择符, 就能从全局描述符中读出局部描述符, 放到高速缓存中. 只是描述符才定义局部描述符表.
控制寄存器:
CR0~CR3: CR0的低五位是系统控制标志, 组成机器状态字, 80386中使用到寄存器CR0, CR2, CR3中其他位.
PE保护模式允许, MP数字协处理器, EM数字模拟, TS任务切换, R80387协处理器, PG分页允许.
CR2缺页保留线性地址;
CR3页目录基本地址寄存器.
任务寄存器:
TR是任务切换的重要机制. 存放16位选择符. TR由软件装入, 开始第一个任务, 之后在任务切换指令自动修改选择符.
TR用于指定全局描述符表中描述符的位置. 当选择符装入TR时, 相应的TSS描述符自动从存储器中读出并装入到任务描述符缓存中. 该描述符定义任务状态段的存储块, 提供段起始地址BASE, 和LIMIT. 每个任务都有自己的TSS. TSS包含任务启动的必要信息.
改变功能的寄存器:
实模式段寄存器, 保护模式段选择符寄存器. 选择符并不直接规定存储器地址, 他选择一个定义存储段的大小, 和属性的描述符.
选择符格式, 索引, TI, RPL. 这里我们看到最低位的两位标为RPL, 代表请求特权级. 它指定了选择符的请求特权级(RPL), 第二位TI任务指示府, 选择表.
80386切换到保护模式下改变功能的另一个寄存器是标志寄存器. 标志寄存器新增位: IOPL, IO特权级, NT任务嵌套标志, RF恢复标志, VM.
每个标志都是系统标志, 代表保护模式系统操作.
保护模式的存储器管理和地址转换:
虚拟地址和虚拟地址空间(VM)
保护模式存储器管理使用48位的存储器指针, 分为两部分: 选择符和偏移量. 该48位存储器指针为虚拟地址, 他用在程序中, 用以规定指令或数据的存储位置. 如果要访问存储器中的代码, 则活动段选择符应放在CS中. 指针的这一部分实际选择的是虚拟地址空间的一个特定的段.
偏移量放在80386其他用户可访问的寄存器中.
16为选择符分为13为索引, 表选择位, 2位请求特权级. 其中, 2位RPL并不用于存储器段选择, 因此只用14位寻址.
虚拟地址空间的分段:
80386的存储器管理单元MMU, 实现了虚存的分段和分页模型. 在分段中64T字节的虚拟地址空间分成32T字节的全局存储器地址空间和32T字节的局部存储地址空间, 该划分大致可见图:
局部段:
32 T
全局段:
32 T
每个地址空间可允许最多8192个存储器段.
在80386多处理软件环境中, 一个应用表示为任务的集合. 所有的任务共享全局地址空间.
物理地址空间和虚实地址转换:
我们已经知道对程序员有64T字节, 但是80386的32位操作模式地址总线只支持4G字节的物理地址空间. 因此, 一次只有虚存的一部分信息可以放到内存中去.
如果, 程序访问一个不再内存的段, 并且物理内存还有空间, 从硬盘读了这段并拷贝到物理存储器中.
段式地址转化:
让我们看一下地址转换过程, 在关闭分页机制时.
段寄存器选择进入全局描述符还是局部描述符表. 当选择符值装入到段寄存器时, 由T1位选中表中指向的描述符自动从存储器取出, 并装入相应段描述符还存取寄存器中, 段地址, 大小, 属性是描述符, 而非选择符.
对80386每个段选择符寄存器都有一个64位内部段描述符缓存寄存器. MMU检查描述符中信息是否有效.
我们可以看到缓存中的段描述符随着任务的执行而改变. 每次存储器管理机制只允许6个存储器段处于活动状态, 这些段对应的段选择符寄存器分别cs, ds, es, fs, gs, 和ss, 他们可以放在局部或者全局存储器中. 如果描述符已被缓存, 就没有必要在装入.
看到该数据描述符分为三个部分: 12位访问权限, 32位机地址和20位段限长.
数据段中的操作数的位置由虚拟地址中的偏移量来决定。
虚拟地址空间的分页:
分页管理机制在分段管理机制下工作。 我们已知如果不分页则每个段最多4g空间。 但如果分了页, 物理地址被划分为1m页面, 每页4k。
分段转换的线性地址不再用于物理地址, 还要经过第二个转换。 12位偏移地址,10位也目录, 10位页祯。
CR3中的页目录指定也目录在位置, PDBR。 这20位是MSB。 低12位假定偏移。
描述符和页表:
描述符分为全局描述符, 局部描述符, 中断描述符。 (段描述符和系统描述符), 段分为数据(堆栈, 数据), 代码. 系统分为陷阱, 中断, 任务状态, 任务门, 调用门.
页表项分为页目录, 页帧.
描述符都是8字节长, 基本结构包含限长, 基地址, 标志位(G粒度, X, 0 AVL), 以及类型字节(P有效, DPL优先级, S系统还是段, 类型, A访问过).
系统描述符主要是类型位设置, 包括TSS任务状态段, 调用门(call), 任务门(task), 中断门, 陷阱门.
页表项:
基地址, AVL, D脏项, A访问过, U/S, R/W, P 管理员, 可读写, 有效.
保护模式西系统控制指令:
LGDT, SGDT, LIDT, SIDT, LMSW, SMSW(machine state word).
LLDT, SLDT, LTR, STR,
LAR装入访问权限, S选择符, D存储位置.
LSL装入限长, S选择符, R16字寄存器.
ARPL D, R16调整RPL域.
VERR s 验证读访问.
VERW s验证写访问.
CLTS 清除任务切换位.
多任务和保护:
保护和保护模式:
分段, 分页, 描述符是保护机制的关键元素. 使用分段时, 段具有一项保护属性的虚拟存储器地址空间的最小单位. 其属性由段描述符中的访问权限, 和限长决定.
硬件执行一系列检查: 类型检查, 限长检查, 地址域限制, 过程入口点检查, 指令集限制.
虚拟地址指针: 选择符, 偏移量 (类型, 限长检查)-> 选择符, 访问权限, 限长, 基地址 -> 存储器
描述符表寄存器 : 限长, 基地址.
访问权限包括: 数据段, 代码段, 读写控制, 有效, 堆栈, 普通数据, DPL特权级.
在一段被访问后, 其描述符被缓存到对应选择符的高速缓冲区中. 但是装入之前, MMU要验证选中段当前是否在内存中, 当前访问者有无权限(当前代码的CPL和要访问的数据的RPL), 以及要访问段的类型是否与选择符寄存器一致(CS代码段, 其他数据段), 以及对该段的引用没有超出段边界. 如果违反一项规则, 则发出一错误报告. 存储管理程序可以确定原因, 解决问题并重启操作(内部故障, 中断处理).
违反规则例子: 如果装入CS的指向数据段描述符, 则类型检查会产生违规错误. 试图访问标为不可读的代码段中的操作数. 试图访问数据字节偏移量大于LIMIT.
指令集上的保护措施:
特权级可以划分不同任务, 某一特权级任务只可以利用更高级程序, 但是不能修改其内容.
系统控制指令, 仅可以在保护级为0的代码段中执行. 每个任务的局部描述符表不能被其他任务引用, 就可以与其他任务隔离.
特权级指定给代码段和数据段:
任务运行时, 既可以对局部, 又可以对全局代码段, 数据段, 和堆栈段访问. 特权级通过段描述符中的访问权限指定.
指令IN, INS, OUT, OUTS, CLI, STI称为信任指令. 他们只能在大于或者等于IOPL特权级上执行. IOPL是标志位, 可以通过软件指定. IOPL随任务不同改变.
保护模式下访问代码和数据:
任务执行中, 可能需要将控制权转给其他优先级程序, 或者访问不同特权级数据. 访问不同特权级代码和数据有严格的限制.
DPL, IOPL描述符, IO优先级.
CPL, RPL当前, 请求优先级.
CPL是当前CS, 或者DS中的优先级(是描述符缓存中的DPL). RPL是希望装入选择符的优先级. 对于代码来言就是要装入DS, 对于数据就是要装入CS.
数据如何被当前特权级代码访问: MOV ds, ax., 一般规则, 代码之可以访问相同或较低特权级数据. 但是对于堆栈SS, DPL必须等于CPL.
程序控制转移可以发生在相同特权级和不同之间. 规则是不同的.
转移到同一代码段时, 仅需要作跳转, 或者调用即可, 仅作限长检查.
转移到不同代码段时(相同, 或不同特权级), 必须使用远跳转, 或者调用指令. 既要检查限长, 也要检查类型. 程序控制转移需要两个条件: CPL = DPL, 则两段保护级相同; 如果CPL高于DPL, 且新段中验证位C置1, 则程序在CPL特权级上运行.
将控制转移到不同特权级代码, 遵循的规则是新代码必须比当前特权级高. 一种门描述符可以进行特权级改变. 将控制转给高特权级, 仍采用远跳转, 远调用指令(jmpf, callf). 这次指令不直接规定代码位置, 引用一个门描述符.
门调用结构:
选择符, 偏移量, 访问权限, 门类型, 双字计数.
调用门, 任务门, 中断门, 陷阱门. 调用门实现从CPL到更高级的间接调用. 在更高级中定义一个有效的入口点, 调用门的值就是入口点的虚拟地址: 目标选择符, 和偏移值.
调用门可以放在GDT或LDT中.
调用门机制进行的操作:
call 选择符
门描述符: 偏移, 选择符 -> 加载段.
我们看到调用指令包括选择符, 和偏移, 选择符加载到CS中, 选择门, 接着, 调用门加载自己的选择符, 到CS中. 偏移到IP中, 导致被调用代码段描述符被缓存, 为存储器提供基地址.
每当任务特权级改变时都会激活一个新的堆栈. 作为程序context的一部分, 就得ESp, SS, EIP, CS被存储到新的堆栈中去.
现在高级特权级过程开始了. 执行结束RET指令将程序控制权返回给调用者. RET导致旧的EIP, CS弹出, 一些参数和ESP, SS也弹出. 这就恢复了原来的环境. 现在程序从低特权级开始执行. 成功的调用DPL的特权级等于CPL, 被调用代码RPL高于CPL.
任务切换和任务状态段表:
任务是多进程的基础. 任务可以间接, 直接的激活, 只需要执行段间跳转(调用)就可以了,. 在利用转移指令启动任务切换, 不保存前一个任务的返回链接, 如果是调用, 则会保存返回链接, 该信息保证新任务执行完成后可以顺利返回.
80386在执行每个任务时都指定了一个选择符TR, 任务状态选择符TSS. 该选择符指向全局描述符表中的任务状态段.
格式:
基地址, 限长, 标志, 访问权限.
如果转移或调用将任务选择符作为其操作数, 那么任务有一个直接的入口. (任务状态段独自占有一页, 除自身空间外, 其余作为堆栈),
回指链接
CPL不同级别的ESP, SS(堆栈, 每个级别都有)
CR3页目录
EIP
EFLAGS
EAX
ECX
EDX
EBX
ESP
EBP
ESI
EDI
ES
CS
SS
DS
FS
GS
LDT
执行一条调用指令时, 选择符装入TR寄存器中(这是个TSS, 忙? 可用), 然后从GDT中读出描述符内容, 以上只在描述符的访问权限信息声明的条件满足时才发生. P=1, TSS不忙, CPL=DPL.
装入TSS描述符之后, 基地址和限长将定义TSS的初始点和大小, TSS包含所有任务启动停止的信息.
典型的TSS段最小103字节. 包含CPU状态(寄存器, 选择符, IP, 标志), 前一个活动任务TSS的返回链接选择符, 局部描述符选择符, 特权级堆栈选择符, 栈顶, IO允许位图.
(内核任务, 用户态任务, 中断任务, 系统调用任务, 内部故障任务)
任务启动过程:
新任务被调用前, 已经有一活动任务, 新任务为嵌套任务, NT被设为1. 任务首先挂起, 接着80386的寄存器保存到TSS中. 接着新任务B位被设置忙, 标志为TS为1表示任务活动状态,; 新任务TSS被装入MPU; 旧任务TSS选择符作为返回链接保存到新任务TSS中. 任务切换结束, 接着加载TSS中的CS和IP.
(TSS中关于任务的堆栈, 寄存器, 被恢复).
旧的程序上下文通过旧的TSS保存, 并由新的TSS的返回链接存储其选择符. 在新任务结束时, ret将会重新加载TR. 激活旧的TSS, 恢复环境.
间接激活任务的方法是选择一个任务门. 这是一种将控制传给RPL比CPL高的任务的方法(确定的入口地址). 任务通过调用GDT或者LDT中的任务门, 从而由任务门决定相应的任务TSS段, 从而装入TSS选择符到TR中.
一个任务切换原则的例子: TSS描述符DESCRIPTOR0~3, 描述TSS的基地址, 和限长. 为激活数据段中的选择符所代表的任务, 可以使用如下序列:
MOV ax, SELECTOR_DATA
mov DS, AX
由于每个选择符8字节长,
MOV EBX, 0f
JMP DOWORDPTR[EBX]
段间跳转
该指令执行将程序控制权交给选择符规定的任务.
CALL DWORDPTR[EBX]
保留链接.
保护模式新增四个寄存器: 全局描述符寄存器GDTR, 中断描述符寄存器IDTR, 局部描述符LDTR, 任务寄存器TR. 另外一些寄存器的功能得到了扩展. 例如指令指针EIP现在为32位; 标志寄存器EFLAGS的更多位得到了利用; 并且所有四个控制器CR0~CR3都具有了相应的功能.
全局描述符表寄存器:
全局描述符寄存器在物理存储器地址空间定义了一个称为全局描述符表GDT. 全局描述符表是存储管理系统的一个重要组成部分.
GDTR是48位寄存器. 该寄存器低2位标识为limit, 规定了GDT按字节大小. LIMIT的值比实际小1. GDTR的高4个字节标为BASE, 指示物理存储器中的GDT的开始位置. 该32位基地址允许该表定义在内存中线性地址的任何地方.
GDT是用来定义80386全局存储器地址空间的一种机制. 全局存储器是一种可能被许多任务共享的通用资源. 也就是说, 全局存储器中存储地址可被微处理器上所有任务共享.
该表包含一项系统分段描述符. 这些描述符标识全局存储器中的段.
80386在从实模式转到保护模式之前必须将BASE和LIMIT的值装入到GDTR. 80386系统控制命令提供此类命令.
中断描述符表寄存器:
IDTR在内存中定义了一个表. 该表包含中断描述符. 该寄存器和描述符表提供一种机制, 它将程序控制转给中断并执行中断服务程序.
IDTR 48位长,低2字节表示LIMIT, 80386支持256个异常和中断, 因此IDT的大小不能超过256. IDTR高4个字节表示BASE.
IDT中用到的描述符为中断门. 提供了一种将程序控制转给中断服务程序入口的手段. 每个门8字节长, 包含服务程序的属性和起始地址.
IDTR和GDTR一样要在保护模式之前装入. 关于IDTR的装入和保存有特殊的指令. 一旦地址设定, 一般不改变.
LDTR:
局部描述符寄存器: 是存储器管理机制的一部分. 每个任务除了可以访问GDT之外, 还可以访问自己的LDT, 它定义了任务用到的局部存储器地址.
LDTR并不直接定义一个局部描述符, 它只是指向GDT中的LDT描述符的选择符. 如果LDTR装入了相应的选择符, 就能从全局描述符中读出局部描述符, 放到高速缓存中. 只是描述符才定义局部描述符表.
控制寄存器:
CR0~CR3: CR0的低五位是系统控制标志, 组成机器状态字, 80386中使用到寄存器CR0, CR2, CR3中其他位.
PE保护模式允许, MP数字协处理器, EM数字模拟, TS任务切换, R80387协处理器, PG分页允许.
CR2缺页保留线性地址;
CR3页目录基本地址寄存器.
任务寄存器:
TR是任务切换的重要机制. 存放16位选择符. TR由软件装入, 开始第一个任务, 之后在任务切换指令自动修改选择符.
TR用于指定全局描述符表中描述符的位置. 当选择符装入TR时, 相应的TSS描述符自动从存储器中读出并装入到任务描述符缓存中. 该描述符定义任务状态段的存储块, 提供段起始地址BASE, 和LIMIT. 每个任务都有自己的TSS. TSS包含任务启动的必要信息.
改变功能的寄存器:
实模式段寄存器, 保护模式段选择符寄存器. 选择符并不直接规定存储器地址, 他选择一个定义存储段的大小, 和属性的描述符.
选择符格式, 索引, TI, RPL. 这里我们看到最低位的两位标为RPL, 代表请求特权级. 它指定了选择符的请求特权级(RPL), 第二位TI任务指示府, 选择表.
80386切换到保护模式下改变功能的另一个寄存器是标志寄存器. 标志寄存器新增位: IOPL, IO特权级, NT任务嵌套标志, RF恢复标志, VM.
每个标志都是系统标志, 代表保护模式系统操作.
保护模式的存储器管理和地址转换:
虚拟地址和虚拟地址空间(VM)
保护模式存储器管理使用48位的存储器指针, 分为两部分: 选择符和偏移量. 该48位存储器指针为虚拟地址, 他用在程序中, 用以规定指令或数据的存储位置. 如果要访问存储器中的代码, 则活动段选择符应放在CS中. 指针的这一部分实际选择的是虚拟地址空间的一个特定的段.
偏移量放在80386其他用户可访问的寄存器中.
16为选择符分为13为索引, 表选择位, 2位请求特权级. 其中, 2位RPL并不用于存储器段选择, 因此只用14位寻址.
虚拟地址空间的分段:
80386的存储器管理单元MMU, 实现了虚存的分段和分页模型. 在分段中64T字节的虚拟地址空间分成32T字节的全局存储器地址空间和32T字节的局部存储地址空间, 该划分大致可见图:
局部段:
32 T
全局段:
32 T
每个地址空间可允许最多8192个存储器段.
在80386多处理软件环境中, 一个应用表示为任务的集合. 所有的任务共享全局地址空间.
物理地址空间和虚实地址转换:
我们已经知道对程序员有64T字节, 但是80386的32位操作模式地址总线只支持4G字节的物理地址空间. 因此, 一次只有虚存的一部分信息可以放到内存中去.
如果, 程序访问一个不再内存的段, 并且物理内存还有空间, 从硬盘读了这段并拷贝到物理存储器中.
段式地址转化:
让我们看一下地址转换过程, 在关闭分页机制时.
段寄存器选择进入全局描述符还是局部描述符表. 当选择符值装入到段寄存器时, 由T1位选中表中指向的描述符自动从存储器取出, 并装入相应段描述符还存取寄存器中, 段地址, 大小, 属性是描述符, 而非选择符.
对80386每个段选择符寄存器都有一个64位内部段描述符缓存寄存器. MMU检查描述符中信息是否有效.
我们可以看到缓存中的段描述符随着任务的执行而改变. 每次存储器管理机制只允许6个存储器段处于活动状态, 这些段对应的段选择符寄存器分别cs, ds, es, fs, gs, 和ss, 他们可以放在局部或者全局存储器中. 如果描述符已被缓存, 就没有必要在装入.
看到该数据描述符分为三个部分: 12位访问权限, 32位机地址和20位段限长.
数据段中的操作数的位置由虚拟地址中的偏移量来决定。
虚拟地址空间的分页:
分页管理机制在分段管理机制下工作。 我们已知如果不分页则每个段最多4g空间。 但如果分了页, 物理地址被划分为1m页面, 每页4k。
分段转换的线性地址不再用于物理地址, 还要经过第二个转换。 12位偏移地址,10位也目录, 10位页祯。
CR3中的页目录指定也目录在位置, PDBR。 这20位是MSB。 低12位假定偏移。
描述符和页表:
描述符分为全局描述符, 局部描述符, 中断描述符。 (段描述符和系统描述符), 段分为数据(堆栈, 数据), 代码. 系统分为陷阱, 中断, 任务状态, 任务门, 调用门.
页表项分为页目录, 页帧.
描述符都是8字节长, 基本结构包含限长, 基地址, 标志位(G粒度, X, 0 AVL), 以及类型字节(P有效, DPL优先级, S系统还是段, 类型, A访问过).
系统描述符主要是类型位设置, 包括TSS任务状态段, 调用门(call), 任务门(task), 中断门, 陷阱门.
页表项:
基地址, AVL, D脏项, A访问过, U/S, R/W, P 管理员, 可读写, 有效.
保护模式西系统控制指令:
LGDT, SGDT, LIDT, SIDT, LMSW, SMSW(machine state word).
LLDT, SLDT, LTR, STR,
LAR装入访问权限, S选择符, D存储位置.
LSL装入限长, S选择符, R16字寄存器.
ARPL D, R16调整RPL域.
VERR s 验证读访问.
VERW s验证写访问.
CLTS 清除任务切换位.
多任务和保护:
保护和保护模式:
分段, 分页, 描述符是保护机制的关键元素. 使用分段时, 段具有一项保护属性的虚拟存储器地址空间的最小单位. 其属性由段描述符中的访问权限, 和限长决定.
硬件执行一系列检查: 类型检查, 限长检查, 地址域限制, 过程入口点检查, 指令集限制.
虚拟地址指针: 选择符, 偏移量 (类型, 限长检查)-> 选择符, 访问权限, 限长, 基地址 -> 存储器
描述符表寄存器 : 限长, 基地址.
访问权限包括: 数据段, 代码段, 读写控制, 有效, 堆栈, 普通数据, DPL特权级.
在一段被访问后, 其描述符被缓存到对应选择符的高速缓冲区中. 但是装入之前, MMU要验证选中段当前是否在内存中, 当前访问者有无权限(当前代码的CPL和要访问的数据的RPL), 以及要访问段的类型是否与选择符寄存器一致(CS代码段, 其他数据段), 以及对该段的引用没有超出段边界. 如果违反一项规则, 则发出一错误报告. 存储管理程序可以确定原因, 解决问题并重启操作(内部故障, 中断处理).
违反规则例子: 如果装入CS的指向数据段描述符, 则类型检查会产生违规错误. 试图访问标为不可读的代码段中的操作数. 试图访问数据字节偏移量大于LIMIT.
指令集上的保护措施:
特权级可以划分不同任务, 某一特权级任务只可以利用更高级程序, 但是不能修改其内容.
系统控制指令, 仅可以在保护级为0的代码段中执行. 每个任务的局部描述符表不能被其他任务引用, 就可以与其他任务隔离.
特权级指定给代码段和数据段:
任务运行时, 既可以对局部, 又可以对全局代码段, 数据段, 和堆栈段访问. 特权级通过段描述符中的访问权限指定.
指令IN, INS, OUT, OUTS, CLI, STI称为信任指令. 他们只能在大于或者等于IOPL特权级上执行. IOPL是标志位, 可以通过软件指定. IOPL随任务不同改变.
保护模式下访问代码和数据:
任务执行中, 可能需要将控制权转给其他优先级程序, 或者访问不同特权级数据. 访问不同特权级代码和数据有严格的限制.
DPL, IOPL描述符, IO优先级.
CPL, RPL当前, 请求优先级.
CPL是当前CS, 或者DS中的优先级(是描述符缓存中的DPL). RPL是希望装入选择符的优先级. 对于代码来言就是要装入DS, 对于数据就是要装入CS.
数据如何被当前特权级代码访问: MOV ds, ax., 一般规则, 代码之可以访问相同或较低特权级数据. 但是对于堆栈SS, DPL必须等于CPL.
程序控制转移可以发生在相同特权级和不同之间. 规则是不同的.
转移到同一代码段时, 仅需要作跳转, 或者调用即可, 仅作限长检查.
转移到不同代码段时(相同, 或不同特权级), 必须使用远跳转, 或者调用指令. 既要检查限长, 也要检查类型. 程序控制转移需要两个条件: CPL = DPL, 则两段保护级相同; 如果CPL高于DPL, 且新段中验证位C置1, 则程序在CPL特权级上运行.
将控制转移到不同特权级代码, 遵循的规则是新代码必须比当前特权级高. 一种门描述符可以进行特权级改变. 将控制转给高特权级, 仍采用远跳转, 远调用指令(jmpf, callf). 这次指令不直接规定代码位置, 引用一个门描述符.
门调用结构:
选择符, 偏移量, 访问权限, 门类型, 双字计数.
调用门, 任务门, 中断门, 陷阱门. 调用门实现从CPL到更高级的间接调用. 在更高级中定义一个有效的入口点, 调用门的值就是入口点的虚拟地址: 目标选择符, 和偏移值.
调用门可以放在GDT或LDT中.
调用门机制进行的操作:
call 选择符
门描述符: 偏移, 选择符 -> 加载段.
我们看到调用指令包括选择符, 和偏移, 选择符加载到CS中, 选择门, 接着, 调用门加载自己的选择符, 到CS中. 偏移到IP中, 导致被调用代码段描述符被缓存, 为存储器提供基地址.
每当任务特权级改变时都会激活一个新的堆栈. 作为程序context的一部分, 就得ESp, SS, EIP, CS被存储到新的堆栈中去.
现在高级特权级过程开始了. 执行结束RET指令将程序控制权返回给调用者. RET导致旧的EIP, CS弹出, 一些参数和ESP, SS也弹出. 这就恢复了原来的环境. 现在程序从低特权级开始执行. 成功的调用DPL的特权级等于CPL, 被调用代码RPL高于CPL.
任务切换和任务状态段表:
任务是多进程的基础. 任务可以间接, 直接的激活, 只需要执行段间跳转(调用)就可以了,. 在利用转移指令启动任务切换, 不保存前一个任务的返回链接, 如果是调用, 则会保存返回链接, 该信息保证新任务执行完成后可以顺利返回.
80386在执行每个任务时都指定了一个选择符TR, 任务状态选择符TSS. 该选择符指向全局描述符表中的任务状态段.
格式:
基地址, 限长, 标志, 访问权限.
如果转移或调用将任务选择符作为其操作数, 那么任务有一个直接的入口. (任务状态段独自占有一页, 除自身空间外, 其余作为堆栈),
回指链接
CPL不同级别的ESP, SS(堆栈, 每个级别都有)
CR3页目录
EIP
EFLAGS
EAX
ECX
EDX
EBX
ESP
EBP
ESI
EDI
ES
CS
SS
DS
FS
GS
LDT
执行一条调用指令时, 选择符装入TR寄存器中(这是个TSS, 忙? 可用), 然后从GDT中读出描述符内容, 以上只在描述符的访问权限信息声明的条件满足时才发生. P=1, TSS不忙, CPL=DPL.
装入TSS描述符之后, 基地址和限长将定义TSS的初始点和大小, TSS包含所有任务启动停止的信息.
典型的TSS段最小103字节. 包含CPU状态(寄存器, 选择符, IP, 标志), 前一个活动任务TSS的返回链接选择符, 局部描述符选择符, 特权级堆栈选择符, 栈顶, IO允许位图.
(内核任务, 用户态任务, 中断任务, 系统调用任务, 内部故障任务)
任务启动过程:
新任务被调用前, 已经有一活动任务, 新任务为嵌套任务, NT被设为1. 任务首先挂起, 接着80386的寄存器保存到TSS中. 接着新任务B位被设置忙, 标志为TS为1表示任务活动状态,; 新任务TSS被装入MPU; 旧任务TSS选择符作为返回链接保存到新任务TSS中. 任务切换结束, 接着加载TSS中的CS和IP.
(TSS中关于任务的堆栈, 寄存器, 被恢复).
旧的程序上下文通过旧的TSS保存, 并由新的TSS的返回链接存储其选择符. 在新任务结束时, ret将会重新加载TR. 激活旧的TSS, 恢复环境.
间接激活任务的方法是选择一个任务门. 这是一种将控制传给RPL比CPL高的任务的方法(确定的入口地址). 任务通过调用GDT或者LDT中的任务门, 从而由任务门决定相应的任务TSS段, 从而装入TSS选择符到TR中.
一个任务切换原则的例子: TSS描述符DESCRIPTOR0~3, 描述TSS的基地址, 和限长. 为激活数据段中的选择符所代表的任务, 可以使用如下序列:
MOV ax, SELECTOR_DATA
mov DS, AX
由于每个选择符8字节长,
MOV EBX, 0f
JMP DOWORDPTR[EBX]
段间跳转
该指令执行将程序控制权交给选择符规定的任务.
CALL DWORDPTR[EBX]
保留链接.
作者:liyonghelpme 发表于2010/6/11 13:13:00 原文链接
阅读:559 评论:0 查看评论