用户模式进程的I/O指令

问题描述 投票:0回答:2

有两种方式访问硬件:

  • 通过内存映射 I/O (MMIO)
  • 通过 I/O 端口

如果用户模式进程想要在不使用系统调用的情况下直接访问 I/O,并且它知道某个特定的硬件,则它无法通过内存映射 I/O 访问它,因为它不在其地址空间中,因此将会发生分段错误。但是使用 I/O 端口来实现这一点又如何呢?由于I/O端口不在内存地址空间中,而是由处理器直接执行的指令访问,那么会发生什么情况,进程是否可以访问它们?

io operating-system
2个回答
1
投票

精简版

不。例如,在 x86 架构中,

in
out
是特权指令,只能在 Ring 0 中运行。由于用户模式应用程序在 Ring 3 中运行,因此 CPU 在尝试执行该指令时会出现故障。

长版

一般来说,在强制内存保护和进程分离的操作系统中(例如Windows、Linux、Mac OS,但不是DOS),用户模式应用程序无法直接访问硬件,而是使用系统调用来询问硬件内核代表它们执行所需的操作。然后内核可以决定应用程序是否有权执行所述操作、该操作是否安全等。

如果用户模式应用程序能够执行通常只能由内核完成的任何操作,那么它就是内核(或者有时是 CPU 本身)中的错误/后门和巨大的安全漏洞。

在 x86 架构上,I/O 端口指令在除实模式之外的所有操作模式下都具有特权。尝试执行任何特权指令都会生成故障(具体来说,

#GP
,一般保护故障,对应于
INT 0xD
)。

为了允许用户模式驱动程序等进程工作,操作系统能够通过两种方式覆盖 I/O 指令的特权状态:

  1. 使用
    IOPL
    寄存器(位 12 和 13)中的
    FLAGS
    (I/O 权限级别)字段。这是一个从 0 到 3 的数字,指定可以运行 I/O 指令的最低特权环。将
    IOPL
    设置为 3 将允许所有进程访问任何 I/O 端口,这是不安全的,并且违背了保护内存等其他所有内容的目的。因此,操作系统通常将此字段设置为 0。
  2. 使用任务状态段 (TSS) 结构中的
    IOPB
    (I/O 权限位图)位字段。这只是 65536 位的集合,每个位指定是否可以访问 I/O 端口 (
    0
    ) 或不可以 (
    1
    )。如果用户模式驱动程序需要访问端口
    0xAB
    ,那么操作系统可以清除 TSS 中的相应位,并允许用户模式代码仅访问该端口,即使是
    IOPL=0
    。如果操作系统不包含所有 65536 位,则 CPU 会假定缺少的部分具有特权,因此无法访问。

0
投票

当然。访问 I/O 端口的权限位于标志寄存器的两位中。由于每个任务都有自己唯一的标志寄存器副本,因此每个任务可以具有不同的访问权限或 I/O 权限级别 (

IOPL
)。主要功能是执行 I/O(内核模式或用户模式驱动程序)的任务可以从
IOPL
3
中受益,从而允许任务的所有过程执行 I/O。其他任务通常将 IOPL 设置为
0
1
,保留为最具特权的过程执行 I/O 指令的权利。因此,如果您想访问特定任务的 I/O 端口,您应该为此任务设置
IOPL=3

在 Windows XP 等旧版 Windows 中,可以通过调用

NtSetInformationProcess
并将
ProcessInformationClass.ProcessUserModeIOPL
设置为
3
来完成。

不知道新版本。

这里有一个示例

© www.soinside.com 2019 - 2024. All rights reserved.