分段模式和特权级

来源:互联网 发布:淘宝累计账单 编辑:程序博客网 时间:2024/05/21 17:12

实现特权级从外层到内层变换的普通途径是:
使用段间调用指令call,通过调用门进行转移。
实现特权级从内层到外层变换的普通途径是:
使用段间返回指令ret。

特权级:
CPL(Current Privilege Level):
当前执行的程序或任务的特权级,被存储在CS和SS的第0位和第1位上。
DPL(Descriptor Privilege Level):
描述符特权级,规定所描述段或门的特权级,被存储在段描述符或门描述符的DPL字段中。
RPL(Requested Privilege Level):
请求特权级,用于特权检查,被存储在选择子的第0位和第1位上。
可以看成是每次访问时的附加限制,RPL=0时附加限制最小,RPL=3时附加限制最大。对于特权级高的进程RPL的作用是防止自己不小心访问到一些资料段。比方说,如果进程A的CPL=0,它知道它的委托进程B的DPL=3,也知道数据段C的DPL=2,而这数据段是不能让CPL>2的进程访问的。

特权级检查的时间
1、访问数据段
 数据段的访问原则就是可以被高级的代码段访问,不能被比自己权限低的代码访问,这里,RPL可能会削弱CPL的作用,访问数据段或堆栈段时,默认用CPL和RPL中最小特权段去访问数据段,所以要求max{CPL,RPL}<=DPL。
2、访问代码段
 1)所有的程序跳转,CPU都不会把段选择子的RPL赋给跳转后程序的CS.RPL(CS.RPL=CPL),段选择子不过是一个给CPU的"引导"作用。段选择子完成了引导作用后的工作就是进程跟新的段的瓜葛了。
 2)跳转后程序的CPL(CS.RPL)只会有两种可能:
  如果成功跳转到一致代码段
  跳转后程序的CPL(CS.RPL)=跳转前程序的CPL(CS.RPL)
  如果成功跳转到非一致代码段
  跳转后程序的CPL(CS.RPL)=跳转后程序的DPL(CodeDescriptor.DPL)
3、如何能成功跳转
 1)高特权级不找低特权级办事,低特权级找高特权级帮忙,相同的一定没问题。
 2)一致代码段的意义:让客人很方便的利用主人(一致代码段)的东西为自己办事,但客人这身份没有改变(NewCS.RPL=OldCS.RPL),所以只能帮自己办事。
 3)非一致代码段的意义:主人(非一致代码段)可以帮客人,但一定是用自己的身份(NewCS.RPL=DestinationDescriptorCode.DPL),这里可能有安全问题,搞不好很容易农民变县长。RPL可以用来限制这个问题。
 4)让程序有需要的时候可以表示一个特权级更低的身份(max{RPL,CPL})而不会失去本身的特权级CPL(CS.RPL),有需要的时候是指要检查身份的时候。事实上RPL跟段本身的特权级DPL和当前特权级CPL没有什么关系,因为RPL的值在成功跳转后并不赋给跳转后的CS.RPL。

特权级的跳转:
1、直接(普通)跳转:(jmp与call指令功能相同,不改变CPL)
 即jmp或call后跟着48位全指针,且其中的段选择子指向代码段描述符。普通跳转不能使特权级发生跃迁,即不会引起CPL的变化。
 1)目标是一致代码段:
  要求:CPL(CS.RPL)>=DestinationDescriptorCode.DPL,其他RPL是不检查的。
  跳转后程序的CPL(NewCS.RPL)=跳转前程序的CPL(OldCS.RPL)
 2)目标是非一致代码段
  要求:CPL(CS.RPL)=DestinationDescriptorCode.DPL && RPL<=CPL(CS.RPL)
  跳转后程序的CPL(NewCS.RPL)=DestinationDescriptorCode.DPL
 3)程序访问数据段或堆栈段时,实现相同或高特权级-低特权级的访问,即max{CPL, RPL}<=DPL。数据段和堆栈段永远都是非一致的。
2、通过Gate的跳转:(对非一致代码段,jmp与call指令功能不同,可改变CPL)
 当段间转移指令jmp和短剑转移指令call后跟着的目标段选择子指向一个调用门描述符时,该跳转就是利用调用门的跳转。这是如果选择子后跟着32位的地址偏移,也不会被CPU使用,因为调用门描述符已经记录了目标代码的偏移。
 使用调用门进行的跳转比普通跳转多一个步骤,即在访问调用门描述符时要将描述符当作一个数据段来检查访问权限,要求指示调用门的选择子的RPL<=门描述符DPL,同时当前代码段CPL<=门描述符DPL,就如同访问数据段一样。
 从调用门中读取到目标代码的段选择子和地址偏移后,我们当前掌握的信息又回到了先前,和普通跳转站在了同一条起跑线上(普通跳转一开始就得到了目标代码的段选择子和地址偏移),有所不同的是,此时,CPU会将读到的目标代码段选择子中的RPL清0,即忽略调用门代码段选择子的RPL的作用。完成这一步后,CPU开始对当前程序的CPU,目标代码段选择子的RPL(事实上被清0后总能满足要求)以及由目标代码选择子指示的目标代码段描述符中的DPL进行特权级检查,并根据情况进行跳转
 1)目标是一致代码段
  要求:CPL(CS.RPL)>=DestinationDescriptorCode.DPL,RPL不检查(被清零,永远满足RPL<=DPL)
  跳转后程序的CPL(NewCS.RPL)=跳转前程序的CPL(OldCS.RPL),特权级没有发生跃迁。
 2)目标是非一致代码段
  a. 当用JMP指令跳转时:
   要求:CPL(CS>RPL)=DestinationDescriptorCode.DPL,RPL不检查(被清零,永远满足RPL<=DPL)
   跳转后程序的CPL(NewCS.RPL)=跳转前程序的CPL(OldCS.RPL),特权级没有发生跃迁。
  b. 当用CALL指令跳转时:
   要求:CPL(CS.RPL)>=DestinationDescriptorCode.DPL
   跳转后程序的CPL(NewCS.RPL)=DestinationDescriptorCode.DPL

段定义:
段基地址(Base Address):32位
段界限(Limit):20位,以字节(1M)或4k字节(4G)为单位
段属性(Attributes)

段描述符(8byte):
存储段描述符(代码段和数据段描述符)
 1byte   2byte   3byte     2byte 
 Base(31-24) |Attributes |Segment Base(23-0) |Segment Limit(15)-0
Attributes
 1bit 1bit 1bit 1bit 4bit   1bit 2bit 1bit 4bit
 G D 0 AVL Limit(19-16) P DPL DT1 TYPE
TYPE
 E=0 ED W A
 E=1 C R A
 G位:段界限粒度(Granularity)位,0表示byte,1表示4Kbyte。
 D位:1、可执行段:0表示16位代码段,1表示32位代码段。
      2、向低扩展数据段:0表示段的上部界限为64K,1表示段的上部界限为4G。
      3、堆栈段:0表示使用SP,1表示使用ESP。
 P位:存在(Present)位,1表示有效,0表示无效。
 DPL位:描述符特权级(Descriptor Privilege Level)位,规定所描述段的特权级。
 DT位:描述符的类型,1表示存储段描述符,0表示系统段描述符和门描述符。
系统段描述符
门描述符
 2byte   2byte   2byte   2byte
 Offset(31-16) |Attributes |Selector |Offset(15-0)
Attributes
 1bit  2bit  1bit  4bit  3bit  5bit
 P |DPL  |DT0  |TYPE |000  |Dword Count

段选择子
 13byte  1byte  2byte
 INDEX |TI  |RPL
 INDEX:表示所标识的段描述符在段描述符表中的索引。
 TI:0表示在全局描述符表(GDT)中,1表示在本地描述符表(LDT)中。
 RPL:请求特权级别。

进入保护模式的步骤
1、准备GDT(Global Descriptor Table)
2、用lgdt指令加载gdtr
3、打开A20地址线
4、置cr0的PE位
5、跳转,进入保护模式

LDT(Local Descriptor Table)建立
 可以在LDT中添加代码段、数据段和堆栈段等,这样一来,可以把一个单独的任务所用到的所有东西封装在一个LDT中,从而构成多任务处理的一个雏形。
1、在GDT段中添加LDT描述符与LDT选择子
2、建立相应的LDT表段
3、为添加的LDT描述符增加初始化代码,主要是针对段基址
4、在LDT中,增加所需代码的LDT目标段描述符,并确定LDT长度,再添加相应的LDT选择子
5、在实模式初始化代码中,为添加的LDT目标代码段描述符进行初始化
6、建立以上提及的LDT目标代码段,并添加所需的代码
7、加载ldtr,并跳入LDT代码中执行

一致与非一致代码段的设置原则
 系统要保证安全,所以内核要和用户程序分开,内核一定要安全,不能被用户程序干涉,有时用户程序需要访问内核数据,于是OS将内核程序开辟一些可以供用户程序访问的段,但是不允许用户程序写入数据。
1、内核不用知道用户程序的数据,内核不用调用用户程序的数据,内核不用转移到用户程序中来
2、用户程序只能访问到内核的某些共享的段,我们称这些段为一致代码段
3、用户程序不能访问内核不共享的段

一致与非一致代码段的访问原则
对于一致代码段:
1、特权级高的程序不允许访问特权级低的数据(CPL>=DPL),即,核心态不允许调用用户态的数据
2、特权级低的程序可以访问到特权级高的数据(如访问内核某些共享的数据段),但特权级CPL不会改变,即,用户态还是用户态
对于非一致代码段:
1、只允许同级访问(CPL=DPL)
2、绝对禁止不同级访问:核心态不使用用户态,用户态也不使用核心态

原创粉丝点击