> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/man/man9/uio.9.md).

# uio.9

`uio` — 设备驱动程序 I/O 例程

## 名称

`uio`, `uiomove`, `uiomove_frombuf`, `uiomove_fromphys`, `uiomove_nofault`

## 概要

`#include <sys/types.h>`

`#include <sys/uio.h>`

```c
struct uio {
	struct iovec	*uio_iov;	/* 分散/聚集列表 */
	int		 uio_iovcnt;	/* 分散/聚集列表长度 */
	off_t		 uio_offset;	/* 在目标对象中的偏移量 */
	ssize_t		 uio_resid;	/* 剩余待处理字节数 */
	enum uio_seg	 uio_segflg;	/* 地址空间 */
	enum uio_rw	 uio_rw;	/* 操作 */
	struct thread	*uio_td;	/* 所有者 */
};
```

`int uiomove(void *buf, int howmuch, struct uio *uiop)`

`int uiomove_frombuf(void *buf, int howmuch, struct uio *uiop)`

`int uiomove_fromphys(vm_page_t ma[], vm_offset_t offset, int howmuch, struct uio *uiop)`

`int uiomove_nofault(void *buf, int howmuch, struct uio *uiop)`

## 描述

`uiomove()`、`uiomove_frombuf()`、`uiomove_fromphys()` 和 `uiomove_nofault()` 函数用于在缓冲区和可能跨越用户/内核空间边界的 I/O 向量之间传输数据。

作为传递给字符设备驱动程序的任何 read(2)、write(2)、readv(2) 或 writev(2) 系统调用的结果，将调用相应的驱动程序 `d_read` 或 `d_write` 入口，并传入指向 `struct uio` 的指针。传输请求编码在此结构中。驱动程序本身应使用 `uiomove()` 或 `uiomove_nofault()` 来访问此结构中的数据。

`uio` 结构中的字段如下：

**`UIO_USERSPACE`** I/O 向量指向进程的地址空间。

**`UIO_SYSSPACE`** I/O 向量指向内核地址空间。

**`UIO_NOCOPY`** 不复制，已在对象中。

**`UIO_READ`** 将数据从缓冲区传输到 I/O 向量。

**`UIO_WRITE`** 将数据从 I/O 向量传输到缓冲区。

**`uio_iov`** 待处理的 I/O 向量数组。在分散/聚集 I/O 的情况下，将有多个向量。

**`uio_iovcnt`** 存在的 I/O 向量数量。

**`uio_offset`** 设备中的偏移量。

**`uio_resid`** 剩余待处理的字节数，在传输后更新。

**`uio_segflg`** 以下标志之一：

**`uio_rw`** 所需传输的方向。支持的标志有：

**`uio_td`** 指向关联线程的 `struct thread` 的指针；如果 `uio_segflg` 指示传输要从/向进程地址空间进行，则使用此字段。

`uiomove_nofault()` 函数要求缓冲区和 I/O 向量可在不引发页错误的情况下访问。源地址和目标地址必须分别物理映射以进行读写访问，且源地址和目标地址都不可分页。因此，`uiomove_nofault()` 函数可从禁止获取虚拟内存系统锁或睡眠的上下文中调用。

`uiomove_frombuf()` 函数是 `uiomove()` 的便捷封装，适用于服务完全包含在内存中现有缓冲区内的数据的驱动程序。它根据现有缓冲区的大小验证 `uio_offset` 和 `uio_resid` 值，在请求部分重叠缓冲区时处理短传输。当 `uio_offset` 大于或等于缓冲区大小时，结果为成功但不传输任何字节，有效地发出 EOF 信号。

`uiomove_fromphys()` 函数提供了一种与机器无关的方式，用于在物理地址空间之间复制内存。`ma[]` 参数是物理页数组。数组中的每个物理页地址提供一个页大小的物理空间块。`offset` 参数是 `ma[]` 数组中的偏移量。特别是，偏移量不必位于第一页内。

## 返回值

成功时 `uiomove()`、`uiomove_frombuf()`、`uiomove_fromphys()` 和 `uiomove_nofault()` 将返回 0；出错时将返回适当的错误代码。

## 实例

其思路是驱动程序为其数据维护一个私有缓冲区，并以最大不超过此缓冲区大小的块处理请求。注意，下面的缓冲区处理非常简化，不会工作（在部分读取时缓冲区指针不会前进），此处仅用于演示 `uiomove_nofault` 处理。

```c
/* MIN() 可在此处找到： */
#include <sys/param.h>
#define BUFSIZE 512
static char buffer[BUFSIZE];
static int data_available;	/* 可读取的数据量 */
static int
fooread(struct cdev *dev, struct uio *uio, int flag)
{
	int rv, amnt;
	rv = 0;
	while (uio->uio_resid > 0) {
		if (data_available > 0) {
			amnt = MIN(uio->uio_resid, data_available);
			rv = uiomove(buffer, amnt, uio);
			if (rv != 0)
				break;
			data_available -= amnt;
		} else
			tsleep(...);	/* 等待更好的时机 */
	}
	if (rv != 0) {
		/* 在此处进行错误清理 */
	}
	return (rv);
}
```

## 错误

`uiomove()`、`uiomove_fromphys()` 和 `uiomove_nofault()` 在以下情况下将失败并返回以下错误代码：

**\[`EFAULT`]** 调用的 copyin(9) 或 copyout(9) 返回 `EFAULT`。

此外，`uiomove_nofault()` 在以下情况下将失败并返回以下错误代码：

**\[`EFAULT`]** 发生页错误。

## 参见

read(2), readv(2), write(2), writev(2), copyin(9), copyout(9), [sleep(9)](/man/man9/sleep.9.md)

## 历史

`uiomove_nofault` 机制出现在 UNIX 的某个早期版本中。

## 作者

本手册页由 J(:org Wunsch 编写。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://book.bsdcn.org/man/man9/uio.9.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
