UIO(9)
π UIO(9) β the kernel dev manual, bestie edition π
okay so welcome to UIO(9), the page all about uio, uiomove, uiomove_frombuf, and uiomove_nofault β aka the device driver I/O routines. this is the kernel developer's manual and honestly? it's giving backstage pass to how drivers actually move your bytes around. π
β¨ NAME β¨
uio, uiomove, uiomove_frombuf, uiomove_nofault β device driver I/O routines. periodt. π
πΈ SYNOPSIS πΈ
first up, the includes you're gonna need, no skipping:
#include <sys/types.h>
#include <sys/uio.h>
and here's the icon itself, the struct uio (copy it exactly, bestie, every field matters):
struct uio {
struct iovec *uio_iov; /* scatter/gather list */
int uio_iovcnt; /* length of scatter/gather list */
off_t uio_offset; /* offset in target object */
ssize_t uio_resid; /* remaining bytes to copy */
enum uio_seg uio_segflg; /* address space */
enum uio_rw uio_rw; /* operation */
struct thread *uio_td; /* owner */
};
and the three functions, all returning int:
int
uiomove(void *buf, int howmuch, struct uio *uiop);
int
uiomove_frombuf(void *buf, int howmuch, struct uio *uiop);
int
uiomove_nofault(void *buf, int howmuch, struct uio *uiop);
π¦ DESCRIPTION π¦
so uiomove(), uiomove_frombuf(), and uiomove_nofault() are the girlies that transfer data between buffers and I/O vectors β and lowkey the whole plot twist is that those vectors might cross the user/kernel space boundary. π
here's the tea: whenever a read(2), write(2), readv(2), or writev(2) system call gets handed off to a character-device driver, the driver's d_read or d_write entry gets called with a pointer to a struct uio. that struct is the transfer request, encoded. your driver should then use uiomove() or uiomove_nofault() to actually get at the data inside. no cap. π₯
now let's do a vibe check on each field:
uio_iovβ the array of I/O vectors getting processed. for scatter/gather I/O this is gonna be more than one vector, bestie.uio_iovcntβ how many I/O vectors are present.uio_offsetβ the offset into the device.uio_residβ how many bytes are left to process. gets updated after the transfer. β¨uio_segflgβ one of these flags, choose wisely:UIO_USERSPACEβ the I/O vector points into a process's address space.UIO_SYSSPACEβ the I/O vector points into the kernel address space.UIO_NOCOPYβ do not copy, it's already in the object.
uio_rwβ the direction of the desired transfer, eitherUIO_READorUIO_WRITE.uio_tdβ pointer to astruct threadfor the associated thread. used whenuio_segflgsays the transfer is happening to/from a process's address space.
π§ uiomove_nofault() β the picky one
this function requires that the buffer and I/O vectors be accessible without incurring a page fault. like, the source and destination addresses must be physically mapped for read and write access respectively, and neither the source nor the destination address may be pageable. so basically uiomove_nofault() can be called from contexts where acquiring virtual memory system locks or sleeping is prohibited. it's the "we literally cannot afford to sleep rn" girlie. π
π uiomove_frombuf() β the convenience queen
uiomove_frombuf() is a convenience wrapper around uiomove() for drivers that serve data wholly contained within an existing buffer in memory. she validates the uio_offset and uio_resid values against the size of that existing buffer, and handles short transfers when the request only partially overlaps the buffer. and when uio_offset is greater than or equal to the buffer size? result is success with no bytes transferred β which effectively signals EOF. iconic behaviour, honestly. π
β RETURN VALUES β
on success, uiomove(), uiomove_frombuf(), and uiomove_nofault() all return 0. on error they return an appropriate error code. that's it, that's the whole thing. π«Ά
π EXAMPLES π
okay so the idea here is that the driver keeps a private buffer for its data and processes the request in chunks of max the size of that buffer. but hear me out β the buffer handling below is very simplified and will not work (the buffer pointer isn't being advanced in case of a partial read). it's just here to demonstrate the uio handling. do not ship it. π
/* MIN() can be found there: */
#include <sys/param.h>
#define BUFSIZE 512
static char buffer[BUFSIZE];
static int data_available; /* amount of data that can be read */
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(...); /* wait for a better time */
}
if (rv != 0) {
/* do error cleanup here */
}
return (rv);
}
π ERRORS π
uiomove() and uiomove_nofault() will fail and return this error code if:
[EFAULT]β the invokedcopyin(9)orcopyout(9)returnedEFAULT.
and in addition, uiomove_nofault() will fail and return this error code if:
[EFAULT]β a page fault occurs.
fr fr, read those twice.uiomove_nofault()has two ways to hand you anEFAULTand one of them is just "a page fault happened". π
π₯ SEE ALSO π₯
read(2), readv(2), write(2), writev(2), copyin(9), copyout(9), sleep(9)
π HISTORY π
the uio mechanism appeared in some early version of Unix. ancient. legendary. the blueprint. π
π AUTHORS π
this manual page was written by JΓΆrg Wunsch. thank you for your service, king. π«Ά
okay that's the whole page bestie, you're officially uio-pilled πβ¨ this was Debian's UIO(9), dated March 11, 2017 β go forth and move those bytes responsibly. mwah. ππ¦π
π¦ where this page comes from
- debian bookworm: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- debian trixie: freebsd-manpages 12.2-2 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu jammy: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu noble: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu questing: freebsd-manpages 12.2-2
- ubuntu resolute: freebsd-manpages 12.2-2build1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu stonking: freebsd-manpages 12.2-2build1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- Copyright (c) 1997 Joerg Wunsch
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms