Ioctl
2023-01-15 12:54:33 阿炯

在计算机中,ioctl 是对设备特定的输入/输出操作和其他不能用常规系统调用表达的操作的系统调用。它需要一个指定请求代码的参数,调用的效果完全取决于请求代码,请求代码通常是特定于设备的。

例如,可以指示物理设备弹出光盘的 CD-ROM 设备,则驱动程序将提供 ioctl 请求代码来执行此操作。与设备无关的请求代码有时用于让用户空间访问仅由核心系统软件使用或仍在开发中的内核功能。ioctl 系统调用以该名称首次出现在 Unix 版本 7 中。大多数 Unix 和类 Unix 系统都支持它,包括 Linux 和 macOS,但可用的请求代码因系统而异。Microsoft Windows 在其 Win32 API 中提供了一个类似的函数,名为“DeviceIoControl”。

传统的操作系统可以分为两层,用户空间和内核。文本编辑器等应用程序代码驻留在用户空间,而操作系统的底层设施(如网络堆栈)驻留在内核中。内核代码处理敏感资源并实现应用程序之间的安全性和可靠性屏障; 因此操作系统会阻止用户模式应用程序直接访问内核资源。用户空间应用程序通常通过系统调用向内核发出请求,其代码位于内核层。系统调用(system call),指运行在用户空间的程序向操作系统内核请求需要更高权限运行的服务。系统调用提供用户程序与操作系统之间的接口,大多数系统交互式操作需求在内核态执行,如设备IO操作或者进程间通信。Glibc就是这样的一个核心库。

系统调用通常采用“系统调用向量”的形式,其中用索引号指示所需的系统调用。例如,exit() 可能是 1 号系统调用,而 write() 号是 4。系统调用向量然后用于为请求找到所需的内核函数,这样传统的操作系统通常会向用户空间提供数百个系统调用。尽管系统调用是访问标准内核设施的权宜之计,但系统调用有时不适用于访问非标准硬件外围设备。必然地,大多数硬件外围设备(也称为设备)只能在内核中直接寻址。但是用户代码可能需要直接与设备通信;例如管理员可能会在以太网接口上配置媒体类型。现代操作系统支持多种设备,其中许多设备提供大量功能。内核设计者可能没有预见到其中一些设施,因此内核很难提供使用这些设备的系统调用。

为了解决这个问题,内核被设计成可扩展的,并且可以接受一个额外的模块,称为设备驱动程序,它运行在内核空间,可以直接寻址设备。ioctl 接口是一个单一的系统调用,用户空间可以通过它与设备驱动程序进行通信。 设备驱动程序上的请求根据此 ioctl 系统调用进行引导,通常通过设备句柄和请求编号进行引导。因此基本内核可以允许用户空间访问设备驱动程序,而无需了解设备支持的设施,也不需要难以管理的大量系统调用。

硬件设备配置

ioctl 的一个常见用途是控制硬件设备。例如在 Win32 系统上,ioctl 调用可以与 USB 设备通信,或者它们可以发现附加存储设备的驱动器几何信息。在 OpenBSD 和 NetBSD 上,bio(4) 伪设备驱动程序和 bioctl 实用程序使用 ioctl 在类似于 ifconfig 的统一供应商不可知接口中实现 RAID 卷管理。

终端

在向最终用户应用程序公开的代码中,ioctl 的一种用途是终端 I/O。Unix 操作系统传统上大量使用命令行界面。Unix 命令行界面创建在伪终端 (ptys) 之上,它模拟硬件文本终端,例如 VT100s。使用 ioctl 调用,可以像硬件设备一样控制和配置 pty。 例如pty的窗口大小是使用 TIOCSWINSZ 调用设置的。TIOCSTI(terminal I/O control,模拟终端输入)的ioctl函数可以将一个字符压入设备流。