• 操作系统---IO权限管理和敏感指令


    简化版

    使用IOPL设置一个特权级的用户程序对所有端口的访问权限,使用I/O位图对一个特权级的用户程序设置个性化的端口访问权限(能访问部分端口、不能访问另外的端口)。

    用户程序的CPL<IOPL,用户程序能访问所有端口。否则,从I/O位图中查找用户程序对端口的访问权限。

    IOPL存储在eflags中,只能在0特权级的下通过popfiretd修改。

    I/O位图存储在TSS中。

    I/O操作也可以看作一种特权资源,也有“访问门槛”。代码段和数据段的访问“门槛”是DPL,存储在段描述符中。

    I/O操作的访问门槛存储在eflagsIOPL位。但是否具有I/O操作的权限,还受I/O位图影响。

    敏感指令是指这些指令:in、ins、out、outs、pof、iretd

    IOPL

    规则

    数值上,CPL <= IOPL,权限上,当前代码段的特权级高于或等于IOPL中存储的特权等级,当前代码段才能执行I/O操作。

    CPL = 0,用户程序才能执行敏感指令。

    eflags

    eflagsflags的32位扩展寄存器,保护许多标志位,例如cf、zf等。IOPL也存储在eflags中,占用2个bit,正好能表示四个特权级:00、01、10、11

    更新

    没有能直接更新eflags的指令,只能间接修改eflags从而修改IOPL。方法是使用两个指令:popfiretd

    只有特权级是0的用户程序才能成功修改eflags中的IOPL。特权不是0的用户程序也能执行popfiretd来修改IOPL,只不过修改无效,也就是说,能执行、无效果、不报错。

    popf

    popf的示意代码如下:

    pushf		; 把eflags中的值入栈
    mov			[esp],  要更新到eflags中的值
    popf		; 把栈中的值存储到eflags
    

    popf除了能修改IOPL,还能修改IF。这不难理解。因为popf是把栈中的整个符合eflags结构的数据更新到eflags中,只需把那个结构的IF位修改为目标值就能修改eflags中的IF位。

    popf用来修改IF位的时候,和sti、cli一样是敏感指令,需要满足特权级检查规则:CPL <= IOPL。

    popf用来修改IOPL位的时候,需要满足特权级检查规则:CPL = 0。

    同一个指令,修改的内容不同,需满足的特权级检查规则不同,这种设计,不好。若我来设计,我会设计成两个指令,每个指令完成各自的功能。

    iretd

    中断发生时,eflags会入栈中断例程的堆栈。修改这个堆栈中的eflags的值,然后再使用iretd就能把栈中的新eflags值更新到eflags中。

    IO位图

    IOPL对一个特权级的所有用户程序的I/O权限做“一刀切”的限制,要么这个特权级的所有用户程序拥有所有端口的I/O权限,要么拥有0个端口的I/O权限。IO位图允许对每个用户程序在I/O端口限制上做个性化配置。

    如果用户进程的CPL <= IOPL,那么,IO位图的值是多少不影响用户进程的I/O权限。如果用户进程的CPL > IOPL,那么,IO位图的值决定了用户进程能读写哪些I/O端口。

    位图

    位图,又叫bitmap。一个bit能表示两种值,0或1。1kb的空间拥有1024个bit,1Mb的空间拥有1024*1024个bit。

    假如我们的硬件一共有65536个I/O端口,只需要8Kb的空间就能标识出这么多端口的权限状态。给8kb空间中的65536个bit依次编号,若第0号I/O端口在能被当前用户进程读写,将此bit设置为1,否则设置为0;剩余的第1到第65535个bit依次按对应的I/O端口依次设置值。

    TSS的尺寸

    如果用户程序存在I/O位图,它将出现在用户程序的TSS的顶端。正因为如此,TSS的尺寸是不固定的。如果不包含I/O位图,TSS的尺寸是104字节。如果包含I/O位图,TSS的尺寸是“I/O位图地址 + 8192字节 + 1字节”。

    包含/IO位图,TSS的尺寸为什么不是“104字节 + 8192字节 + 1字节”?

    因为I/O位图有可能不是紧挨着保存"I/O位图地址"的那个 字节,二者之间可能有空白空间。I/O位图地址是I/O位图在TSS中的偏移量,注意,I/O位图在TSS中,它与TSS中的其他元素都在TSS中。也就是说,从TSS的初始位置开始到I/O位图地址,也许包含部分没有存储数据的空间,都是TSS的一部分。TSS的空间被I/O位图地址分割为两个部分,前一部分的大小是I/O位图地址,后一部分是8192个字节(65536个端口需要65536个bit)+1字节(位图的结束标志必须是0xff)。

    说得简单点,就是,I/O位图和TSS中的其他元素可能不是紧紧挨着。

    0xff

    位图为什么要用0xff作为结束标志?我没有弄明白。

    代码

    不知道TSS中的保留位是什么,更不知道怎么在代码中表示保留位。这里的代码只保证正确表示I/O位图。

    怎么写代码?

    1. 表示I/O位图地址、I/O位图自身。
    2. I/O位图自身
      1. 全部bit的数量并不一定需要是65536个。
      2. 只需用0xff结尾就行。
    [SECTION .tss3]
    LABEL_TSS3:
    			;TSS中的其他元素
    			; 最纠结的语句。$ - LABEL_TSS3是当前行在TSS中的偏移量。
    			; 本语句占用2个字节,2个字节之后是I/O位图。
    			dw		$ - LABEL_TSS3 + 2
    times		 12		 db 	0ffh					; 12个字节,96个bit,都设置为1,表示当前用户程序有端口0到端口95的读写权限。
    			; 端口96到102只有端口97对当前用户程序开放了读写权限。从右到左编号,所以第2个0表示97号端口。
    			db		1111101b	
          ; I/O位图的结束标志
          db		0xff
    
    
    TSS3_LEN			equ				$$ - LABEL_TSS3
    
    求道之人,不问寒暑。
  • 相关阅读:
    3步学会用gulp
    div需要重置吗?
    HTML元素遮挡Flash之梦
    移动WEB开发常用技巧
    四:分组查询
    三:函数
    二:查询
    一:MySQL
    三:JVM(重点)
    二:JAVA通知唤醒机制,Lock替换synchronize
  • 原文地址:https://www.cnblogs.com/chuganghong/p/14476184.html
Copyright © 2020-2023  润新知