二 -- (2)
“
● 描述附表
lgdt,lldt,lidt
”
【00:12】描述附表 定义了 在80386这种保护模式下 用到的所有的段
【00:20】有3中类型的描述符表 (全局)gdt/(局部)ldt/(终端)idt。
【00:40】80386 用来寻址这3个表的寄存器 分为 gdtr(全局描述附表寄存器),ldtr(局部描述附表寄存器),idtr(中断描述附表寄存器),这3个寄存器 分别由指令 lgdt,lldt,lidt 来加载。
【01:22】描述符表 是一个 不定长的 数组,每项保存的是8个字节长的描述符。全局&局部描述附表 各自可以有8192项,中断描述符表 最多可以有256项。在 全局/局部描述附表 中,描述符的检索 是利用段寄存器中的 段选择子 来进行的
【02:00】这就是一个选择子 (ZC: JT01_描述附表.jpg 中的上面那个图),共16位。高13位 第3-15位 用来检索描述符。TI位 TI==1 表示是要检索 局部描述符表, TI==0 表示是要检索 全局描述符表。RPL 指示 请求优先级,有4级:0/1/2/3 。每当 新的选择子 被放到某个段寄存器中的时候,80386 就会访问 描述符表中的某一项,并且自动 将对应的描述符加载 段寄存器的 程序不可见部分(前面提到过 是cache)。【03:16】只要这个选择子跟段寄存器中的选择子保持相同,就不需要对描述符表有额外的访问了。
【03:32】从描述符表中取出一条新的描述符的操作,为什么是不可见的?∵保护模式下,每当段寄存器中的内容被修改的时候,微处理器是 自行完成这个过程,∴是不可见。
【03:55】描述符 的第一项 就是 描述符0。【04:07】局部描述符表,中断描述符表 编号都是从0开始的(ZC: 这里没有提到全局局部描述符表,但是应该是一样的吧?!)。【04:13】描述符0 必须是 空描述符。其他项寻址80386保护模式项 存储器当中的各种段
【04:33】全局描述符表 局部描述符表 的访问方式是相同的,区别在于访问全局描述符的时候 TI位被清零了,访问局部描述符LDT的时候 TI位被置位为1。如果检查 全局描述符表 和 局部描述符表 寄存器,还有另外一个区别,全局描述符表寄存器GDTR 它包含了 全局描述符表的 基地址 和 界限,局部描述符表寄存器 它只包含了一个选择子 并且是16位宽的。ldtr的内容 寻址 包含 LDT的基地址和界限 的 系统描述符。这种方案可以使得多个目录可以共用一个全局描述符表,如果需要 每个任务可以有一个或者多个描述符表。
【05:43】全局描述符 描述了系统的存储器。局部描述符 描述的是 应用程序 或者 任务 的 存储器。
【05:55】跟gdt很类似的,中断描述符表idt 通过把它的基地址和界限 存入到 中断描述符表寄存器中进行寻址。gdt和idt之间 主要区别在于 idt只包含了中断门(中断门 类似于指针),gdt和ldt 包含了系统 段的描述符 但是没有包含中断门
【06:35】看一下 中断门(刚才讲到的门)(ZC: JT01_描述附表.jpg 中的下面那个图)。门 类似于 一个指针。看一下为什么类似于一个指针。
【06:43】是64位的
【07:07】门描述符 包含了32位的偏移地址:最低2个字节 和 最高2个字节。
【07:23】一个字,8位的一个计数
【07:27】一个选择子(第16-31位)
【07:35】32位的偏移地址 指向的是 中断服务程序 或者是 其他程序的入口。
【07:43】字计数 指示 已经有多少个字 从调用者的堆栈(ZC: 这里听得不清楚) 传送到调用门所调用的过程的堆栈上。【07:50】这个 从调用者堆栈中传送数据的特性 对于实现高级的语言(如C) 是非常有用的。
【08:05】选择子 用来指示 任务状态段tss 在gdt中的位置。或者 如果是一个局部过程(ZC: "局部过程"怎么理解?) 指示在ldt当中的位置。
【08:23】每当一个门被访问的时候,选择子的内容就被加载到任务寄存器tr中,这样就导致一个任务切换。
【08:35】门的接收 只要取决于优先级。
【08:40】返回指令ret,是终止门调用过程。中断返回指令 nret,是终止中断门过程。任务通常使用call或者int来访问,call是调用过程 int是调用中断 一个服务过程。
【09:09】实模式中断 和 保护模式中断 区别,在保护模式下 中断向量表是idt idt仍然包括256级中断 但是每个中断都是通过中断门而不是中断向量来调用,这样 类型2中断位于idt的2号描述符的位置 类型3位于3号描述符的位置 以此类推。
【09:45】每个中断可以/平移/品修改(ZC: 这里不知道发的什么音...shit)。idt基地址 16个字节,也就是说 每个,就是说 存储器的前1k不是像实模式那样的中断向量表了(ZC: 1k?10k?听不清..操)。idt可以存在于存储系统的任意位置
【10:18】
“
● 任务状态段
”
【10:40】任务状态段描述符 和其他的描述符都是一样的,包含了任务状态段的 位置、大小、优先级别。它们之间的主要区别在于 任务状态段tss 它的描述符所描述的任务状态段不包含数据和代码,包含的是任务的状态和连系信息 以及任务可以被嵌套的信息。
【11:15】任务状态段描述符 由任务寄存器tr来寻址,tr的内容是由ltr指令 它是保护模式下运行的程序中的jmp或者call来改变。【11:30】ltr指令 是用来在系统中 在初始化过程中首次访问一项任务 初始化之后用call或者jmp对这个任务进行切换。【11:53】大多数情况下,我们用call来初始化一个新的任务。
【12:00】看图(JT02_任务状态段.jpg)
【12:05】任务状态段 是存储器中非常重要的部分,包含许多不同的类型信息。这个段的第一个字,这个 0 4 ,说明每一项是4个字节的。这一部分("Previous Task Link")就是一个字(两个字节),它是一个返回量的标记(ZC: 听得不清),是一个选择子,由返回指令ret或者nret 把它装入到tr寄存器 从而可以返回到前一个任务状态段。
【13:01】接下来这个是保留的
【13:08】然后接下来 第2-7个双字,是包含了优先级0-2的esp和ss 。当前任务被中断的时候 用这些值对优先级0-2的堆栈进行寻址
【13:49】第8个双字 包含的是 CR3的内容。CR3中保存的是 前一个状态的页目录寄存器的基地址。如果分页有效 必须保存这项信息。
【14:10】cr3之后的17个双字,装入的都是指定的寄存器。【14:37】在任务切换的时候,处理器当前所有的寄存器 都保存在这个状态段的这些单元中,各单元存放哪个寄存器是固定的,然后从新的任务的任务状态段里面的相同单元存入新的值。
【15:02】最后一个字(I/O Map Base Address) 包含的是io允许位图的基地址。 io允许位图 是什么呢?io允许位图 可以使得 任务状态段 通过一个否认IO,来允许中断封锁已经禁止的IO端口地址的操作。
【15:33】否认允许中断的类型,是一个一般错误保护中断。IO允许位图的基地址,是相对于任务状态段起始位置的偏移地址,这就使得同一个允许位图 可以为多个任务状态段使用。每一个IO允许位图 大小 是 64k位(就是8Kb)。起始地址是IO允许位图基地址 所表示的偏移地址。
【16:13】IO允许位图的首字节 是IO端口 是0--7的许可位。最右端的一位 是端口0的许可位,最左端的端口 是端口7的许可位。
【16:32】位图中每一位IO端口 对应关系 就是这样的,一直 到 位图 最后一个字节的 最左一位 与 最后一个端口FFFF对应。如果IO允许位图中的某个位是0的话,对应的IO端口地址是开放的。如果 逻辑为1,那么对应的IO端口 地址就被锁定了(封锁了)。
【17:20】回顾一下,任务的切换过程 和 任务的返回过程
【17:28】1、门 中 包含了 任务切换中 过程地址 和 要跳转的代码地址,另外 还包含了任务状态段描述符选择子号 和 参数的传递中 从调用者传送到用户栈的上面字的数目
【17:53】2、选择子 从门中 装入 TR寄存器。这一步 使用有效的任务状态段的描述符 相关的CALL/JMP指令来完成的。
【18:12】3、加 选择了任务状态段 (ZC: 什么 "加"?)
【18:18】4、处理器当前的状态保存到任务状态段中。"当前状态" 都包括哪些呢,就是我们提到的 任务链(ZC: 还是任务量?)、堆栈指针、段寄存器、IO位图,把这些保存到当前的任务状态段中,然后 从新任务的任务状态段中 装入新的任务(也就是 它所有寄存器的值)。当前状态 根据TR中当前的任务状态段选择子来保存。一旦存储完毕,一个新的任务状态段选择子的值,就通过CALL/JMP装入到TR中,并且从新的任务状态段中加载新的状态信息
【19:25】再来看一下 任务返回
任务返回 需要经过两个步骤
【19:30】1、当前处理器状态 装入到 当前的任务状态段中
【19:41】2、返回链选择子 装入到 TR中。访问一个状态段 任务状态段 使得处理器可以恢复到前一个状态。返回到调用的任务状态段 是由 IRET指令完成的
【20:08】
“
● 向保护模式转换
1、初始化中断描述符表
2、初始化全局描述符表
3、PE
4、JMP
5、选择子
● 虚拟8086模式
”
【20:15】"向保护模式转换" 意思就是从实模式到保护模式。
【20:22】在我们硬件复位(就是刚开机) 或者 把CR0中PE位变成0的时候,处理器是进入实地址模式的。【20:53】通过给CR0寄存器中PE位 置1,处理器进入保护模式,但是在进行这个操作之前 必须对其他方面做好初始化。我们看一下这个初始化的过程。这个初始化的过程 不一定按照 由 的过程,写程序的时候可以是按照不同的步骤来进行,但它执行的时候是按照这个步骤。
【21:33】1、初始化中断描述符表
它包含至少前32种终端类型有效的中断门。IDT(中断描述符表) 可以最多拥有256个 8个字节的中断门,可以定义256个中断类型
【22:03】2、初始化全局描述符表
GDT 它的描述符0 为 空的描述符,并且 使其中至少包含 一个有效的代码段描述符、一个有效的堆栈段描述符、一个有效的数据段描述符
【22:30】3、PE。把CR0中的PE位 置位,切换到保护模式
【22:40】4、JMP。执行一条JMP的跳转指令,清楚内部指令队列并且把任务状态段描述符的基地址装入到TR中
【23:03】5、选择子。把初始的选择子的值 装入到 所有的数据选择子中(也就是段寄存器中)
【23:18】经过这5步,80386 已经运行在保护模式下,它现在正在使用GDT和IDT中定义的描述符
【23:40】进入到保护模式 还有一种方法就是 利用任务切换来完成。它的完成 也需要5个步骤
【23:54】1、初始化中断描述符表。以使它可以用IDT中的至少32个描述符
【24:10】2、初始化全局描述符表GDT。以使 其至少有两个任务状态段 的描述符 和 初始任务所需要的原始代码 还有数据段的描述符
【24:30】3、初始化任务寄存器TR。使它指向一个有效的任务状态段。当初始任务发生切换 被访问新的任务状态段的时候,当前的寄存器值将保存在原始的任务状态段中
【24:51】4、用一条段内的近的跳转指令 把内部指令队列刷新 然后切换到保护模式下,把当前任务状态段的选择子放入到TR寄存器中
【25:13】5、用一条跳转指令 来装载TR寄存器 以便能够访问新的任务状态段 并且保存当前的状态
【25:25】经过以上的5步,在初始任务控制下,已经完成了 80386运行到保护模式
【25:43】接着来介绍一下 虚拟的8086模式
虚拟8086模式 是一种比较特殊的运行模式。这种模式 它的设计使得 多个8086实模式的应用软件可以同时运行。在PC机上运行的dos应用程序就是运行在这种模式下。操作系统允许多个应用程序同时执行。通常利用称为时间片的技术 实现这种要求。【26:35】操作系统为每个任务分配一定的事件。
【26:39】举个例子
【27:15】80386保护模式 和 虚拟8086模式,它的主要区别在于 微处理器对段寄存器的解释方式。在虚拟模式下 段寄存器的使用方式 和 在实模式下是相同的,能够寻址1M存储器空间的段地址和偏移地址。通过分页 程序仍然访问的是1M以内的存储器,微处理器可以访问存储器总共4G范围内任意的物理存储单元。【29:00】通过把eflag寄存器中vm置位(置位的时候为1) 就可以进入虚拟8086模式。【28:12】如果优先级为0 可以使用IRET中断返回指令进入这个模式,其它任何方式都不能够对vm位进行设置。【28:27】对1M范围以外的存储单元访问会引发一个中断。在虚拟模式下,通过对内存分区,每个用户都可以有一个分区,这样 就能使多个用户共享一个微处理器
【28:55】
“
● 内存分页机制
1、页目录
2、页表
(1)、cr3
(2)、31-22
(3)、4K
(4)、21-12
(5)、4K
(6)、11-0
”
【29:02】分页机制 可以把程序产生的线性地址放入分页机制产生的物理内存页中。线性内存页是在 实模式下 或者保护模式下用 选择子和偏移地址来寻址的页。物理内存页是实际存在物理存储单元中的页,比如说线性存储单元200000h 是通过分页机制映射到物理存储单元的300000H中,这就意味着 在访问200000h单元的时候实际上是访问的300000H单元。【29:55】每个80386的内存页大小是4Kb,利用分页机制对存储器进行分页 可以把系统软件放在任意物理地址。
【30:10】有3个组成部分用来 页地址转换:页目录、页表、实际的物理内存页
【30:22】先来看一下页目录。页目录 最多可以包含1024个 页转换表的地址。每一个页转换表 把一个逻辑地址转换成物理地址。页目录存储在内存中 并且通过页描述符地址寄存器CR3 CR3的另一个作者是PDTR 也就是说可以通过CR3来访问。CR3保存的是页目录的基地址,这个基地址 它的起始地址 是任意一个4K的边界,使用mov指令可以对CR3进行初始化。
【31:20】在 虚拟8086方式中,每个用户都有自己的分区 每个分区都为1M。每个分区都有自己的页目录。页目录最多包含1024项,每一项4个字节。页目录自身占用4K的内存页,页目录中每一项 转换 存储地址最左边的10位。线性地址的10位 用来在不同的页表中查找不同的页表项。存储在页目录项中的页地址是第32位--12位 可以访问4K长的页转换表。完全把线性地址转换成物理地址需要1024M大小为4K的页表 另外还要加上一个4Kb大小的页目录,这种转换机制要求 4M+4K的存储空间 来完成地址转换。这么大的一段地址只有庞大的操作系统才能支持。【32:49】常见的操作系统 在分页机制使用的时候 只转换存储系统的前16M,它单重包括了程序,这样就能大大节约存储器的空间
【33:08】看图(ZC: 我对应的是"页目录.jpg")
这个就是 页目录中的一个页表项(ZC: 既然是 页表项 你放在 页目录 的标题下面干什么?!)
【33:18】33-12位 存有物理地址的高20位,用来定位物理地址 一个页面 叫物理的基地址
【33:33】低12位 是页的属性信息
【33:39】P位:第0位:存在位标识。指明表项对地址转换是否有效。P==1:有效;P==0:无效
【33:53】R/W位:第1位:读写标识。R/W==1:页面可以被 读和写或者执行;R/W==0:表明页面是 只读 或者是 可执行
【34:16】U/S位:第2位:用户/超级用户 标识。U/S==1:运行在任何特权级上的程序都可以访问这个页面;U/S==0:这个页面只能被运行在超级用户特权级上程序访问
【34:42】A位:第5位:已访问位。当微处理器访问页表项映射的页面的时候,页表的表项这个标识被置1
【34:58】D位:第6位:页面已经被修改的标识
【35:05】Avail:供程序 保留 保留的 供以后升级的微处理器使用
【35:18】介绍一下页表
包含了1024项物理页的地址,它是用来把线性地址 转换到物理地址。
【35:38】每张页表 把线性地址 线性存储器中的一块4M的区域转换成物理存储器中的4M。页表项的格式和页目录项的格式是完全相同的,主要的区别在于,页目录项中页表的物理地址,而页表项中包含的是一个大小为4Kb的物理页的地址。还有一个区别 页目录项中的D位,没有定义,在页表中 这个位用来指示对应的物理页面已经被修改了(ZC: 应该就是 Dirty的意思)
【36:40】看一下,分页机制的工作方式
有6个步骤:
【36:52】1、4Kb长的页目录存储在由CR3指定的物理地址中,这个地址常被称为根地址。系统中同时只有一个页目录。在虚拟8086模式中,每个任务都有自己的页目录,可以把物理存储器的不同区域分配给不同的虚拟8086任务
【37:25】2、由 描述符/实地址 决定的线性地址的最高10位(第31--22位),在分页机制中用来选择页目录 页目录中的一项,这样 使页目录项和线性地址最左边的10位对应起来
【37:51】3、页表通过页目录中的项进行寻址。在采用全地址转换的系统中 最多允许4K个页表
【38:07】4、接下来的10位(第21--12位) 线性地址用来寻址页表中的项。
【38:18】5、页表项中包含4K大小的(物理?)内存页 实际的物理地址
【38:29】6、线性地址的最右边12位(第11--0位) 用来选定物理内存页中的单元
【38:48】保护模式 这一章结束
【完毕】
1、JT01_描述附表.jpg
2、JT02_任务状态段.jpg
3、页目录.jpg
X