《linux 内核完全剖析》 chapter 4 80x86 保护模式极其编程

来源:互联网 发布:音乐cms 编辑:程序博客网 时间:2024/05/22 12:27

80x86 保护模式极其编程


      首先我不得不说,看这章真的很纠结。。。看了半天,不知道这个东西能干嘛,我感觉唯一有点用的就是对于内存映射的理解。。。我如果不在底层给80x86写汇编的话,我真不知道这章能对我有什么用。。。


update:
{

          当我决定暂停下来的时候,暂停这篇blog,我觉得反思这种行为都是伟大的。对于之前“能对我有什么用”的想法有了不同的见解。我发现这个保护模式极其编程还是挺有意思的,我之前不知道APUE里面讲current saved privilege是什么意思,那几种权限搞的我晕,感觉同样是“对我好像没什么用”。但是慢慢的我发现这些东西是有联系的,多看一点看似“无关紧要”的知识,往往对其他的知识的理解能够起到很大的帮助。这个保护模式比较难啃,暂停并不是停止,我喜欢回过头来看问题。喜欢update。
}



还是留下自己觉得重要的理解了的笔记吧。。。



4.1.1标志寄存器--EFLAGS


2014.11.15勘误:PF是不是恢复标志位,是奇偶校验位!


    • TF:trap flag 当设置该位的时候,可为调试操作启动单步调试执行方式,复位时则禁止单步执行。

    • IOPL: I/O privilege level。指明当前运行程序的IO特权级IOPL。当前运行程序的CPL必须小于或者等于这个IOPL才能访问这个IO地址空间。

    • NT:nested task。控制着被中断任务和调用任务之间的链接关系。

    • RF:resume flag。用于控制处理器对断点指令的响应,当设置时,这个标志位会临时禁止断点指令产生的调试异常;当标志位复位的时候,断点指令将会产生异常。

    • VM: vitual 8086 Mode。设置则开启虚拟8086方式;复位则回到保护模式。



4.1.2内存管理寄存器-- GDTR, LDTR, IDTR and TR




GDTR: global  descriptor table register

IDTR  : 

LDTR: local descriptor table register

 TR : task register. 用于存放当前任务(TSS,taks state segment)段的16位选择符,32位基地址,16位段长度,和描述                               符属性值。






4.1.3控制寄存器 CR0-CR3






4.2保护模式的内存寻址


4.2.1内存寻址


        内存是指一组有序的字节组成的数组,每个字节有唯一的内存地址,内存寻址则是指对内存在内存中的某个指定数据对象的地址。



         80x86支持多种数据类型:1字节,2字节,4字节。最小数据类型的寻址是对1字节数据的定位。80x86是一种先存小值(small endian)的处理器


         为了进行内存寻址,80x86是使用了一种称作段(segment)的寻址技术。这种寻址技术把内存空间分成一个或者多个称为段的线性区域,从而对内存中的一个数据对象的寻址就需要使用一个段的起始地址(段地址)和一个段内偏移地址两部分组成。


         程序中由16位的段和32位的偏移构成的48位地址或者长指针称为一个逻辑地址(虚拟地址)。仅由32位偏移地址或者指针确定的地址是基于当前段的对象地址。

          80x86为段部分提供了6个存放段选择符的段寄存器:CS,DS,ES,SS,FS,GS。

          CS(code segment resigter)总是用来寻址代码段.在任何指定时刻由CS寻址的段称为当前代码段。

          由段寄存器SS寻址的段称为当前堆栈段(stack segment register)


指令寻址方式:
偏移地址 =  基地址+(变地址*比例因子)+偏移量;


4.2.2 地址变换


       任何完整的内存管理系统都包含两个关键部分:保护和地址变换。提供保护措施可以防止一个任务访问另外一个任务或者操作系统的内存区域。

        程序中的地址是由两部分组成的逻辑地址,这种逻辑地址并不能直接用于访问物理内存,而需要使用地址变换机制将它变换或者映射到物理内存地址上。

        在地址比那还过程中,第一阶段的分段变换机制总是存在的,而第二阶段的分页机制则是供选用的









4.3.2 保护


1.任务之间的保护


        80x86使用的方法是通过每个任务放置在不同的虚拟地址空间中,并给予每个任务不同的的逻辑地址到物理地址的变换映射。每个任务中的地址变换功能被定义成一个任务中的逻辑地址映射到物理内存的一部分区域,而另一个任务中的逻辑地址映射到物理内存中的不同区域中。由于一个任务不可能生成能够映射到其他任务逻辑地址对应使用的物理内存部分,所以所有任务都被隔绝开了。。。。。。。。其实我觉得这里的映射更应该做函数讲,这是数学上的概念,一一对应的映射是函数。



所有任务都具有的相同虚拟地址空间部分被称为全局地址空间(global address space)。每个任务唯一的虚拟地址空间部分被称为局部地址空间(local address space)。

2. 特权级保护。


          在一个任务中,定义了4个执行特权级(privilege levels),用于依据段中含有的数据的铭感度以及任务中不同程序部分的受信程度,来执行对任务中各段的访问。

          当一个程序企图访问一个段时,当前特权级就会与段的特权级进行比较,以确定是否有访问许可。在给定CPL(current privilege level)级别上执行的程序允许访问同级别或者低级别的数据段。任何高级别段的引用都是非法的,并且会引发一个异常来通知操作系统。

          每个特权级都有自己的程序栈,以避免使用共享栈带来的保护问题。当一个程序从一个特权级切换到另外一个特权级的时候,堆栈段也随之该换到新的级别的堆栈中。








update : 2014.05.03

果然分页是必不可免的!

于是乎,补呗!


4.4分页机制


分段机制和逻辑地址转换成线性地址,而分页则线性地址转换成物理地址。

分页与分段的最大不同在于分页使用了固定长度的页面。段的长度通常与存放在其中的代码和数据结构具有相同的长度。与段不同,页面具有固定的长度。如果仅使用分段地址转换,那么储存在物理地址中的一个数据结构包含其所有的部分。但如果使用了分页,那么一个数据结构就可以分一部分储存在物理内存中,而另一部分保存在磁盘中。


为了减少地址转换所要求的总线周期数量,最近访问的页目录和页表会被存放在处理器缓冲器件中,TLB(http://blog.csdn.net/cinmyheart/article/details/24888847 MOS 的第三章有讲这个)


4.4.1页表结构


1.两级页表结构







2.不存在的页表

           目录表项中的存在位还可以用于在虚拟内存中存放二级页表。这意味着在任何时候只有部分二级页表需要存放在物理内存中,而其余的可保存在磁盘上。处于物理内存中页表对应的页目录项将被标注为存在,以表明可用他们进行分页转换。处于磁盘上的页表对应的页目录项将被标注为不存在。由于二级页表不存在而引发的异常会通知操作系统把缺少的页表从磁盘上加载进物理内存。把页表储存在虚拟内存中减少了保存分页转换表所需要的物理内存量。



4.4.2页表项格式









P 位0是存在标志,用于指明页表项对地址转换是否有效。1有效,0无效

R/W  位1是读写标识。0表示只读或只可执行

U/S 位2是用户/超级用户标识。1,任何特权级都可以访问该页面。0,那么页面只能被运行在超级用户特权级上的程序访问。对所有映射的页面有效

A 位5是已访问位。当处理器访问这个页面时,会被置1

D 位6是页面已经被修改标识。置1表示是dirty page

AVL 该字段是保留字段。处理器不会修改这些位。




















0 0
原创粉丝点击