r/osdev•
Scurry

Exposing driver functions to userspace

I wrote a VGA console driver for xv6 so I could later implement a library for curses-like functionality. My only source of confusion is how this type of code is typically exposed to user space applications. The only way I would know how to do it is by adding system calls, but as there is no console_write_char type syscalls in Linux or any other kernel I know of, I figure this is not the correct way.

Posted Oct 17, 2013, 12:06 AM UTC

65
kyleisme•

Generally in Unix systems, device drivers are often exposed as 'device special files' as noted in klange's comment. Some of these are 'block devices', which the programmer can generally treat like files (random-access read/write), roughly speaking. There are also 'character devices' which act like pipes/sockets (you can write data out as a stream, and read data coming in as a stream).

Terminal devices (whether virtual terminals, serial terminals, VGA consoles) in Unix systems are generally exposed as character devices with ioctls defined to change the behavior of the terminal device, and then you'd write out the data you want to display to the device. Opening a terminal device uses the same open call as for files, and writing would use the normal write call. For special control (e.g. colors, repositioning the cursor, clearing the screen), the terminal driver recognizes special 'escape codes' in the data you write. You need, of course, to know what those codes are, but you just send them embedded in your data that you write to the device.

For some references:

http://en.wikipedia.org/wiki/ANSI_escape_code -- which describes the escape codes commonly used now

http://www.freebsd.org/cgi/man.cgi?query=tty&sektion=4&apropos=0&manpath=FreeBSD+9.2-RELEASE -- FreeBSD's implementation of a tty device and its associated ioctls

http://msdn.microsoft.com/en-us/library/windows/desktop/ms682055%28v=vs.85%29.aspx -- The API for the Win32 console, for contrast, though even that uses the Win32 equivalent of read/write calls to send or receive text from the console

4
ScurryOP•

I knew that it should be available as special files (its xv6 so I'm doing everything the unix way). Escape codes were the missing link! I also knew about ioctl but using that for clearing the screen and such didn't sound right either. This is the exact response I was looking for, thank you!

My next task is writing an ethernet driver. I suspect I should use ioctls for all its special functions. Is there a standard for these things? How do network libraries avoid having to know the proper calls for every different ethernet driver? This question expands to any device really.

1
kyleisme•

Glad it helps!

For network drivers, pretty much all modern operating systems use the Berkeley Sockets interface to expose networking to userspace. Even Windows uses WinSock, which is a fairly direct port of the Sockets interface. Unlike most other hardware drivers, I don't believe network interfaces expose device files on Unix.

I'll give you a few FreeBSD manual pages again for starting points and it tends to be well documented (which is not to say that the Linux documentation isn't, I've just looked through FreeBSD manual pages more than Linux kernel docs).

http://en.wikipedia.org/wiki/Berkeley_sockets -- describes the Berkeley Sockets interface in general

http://www.freebsd.org/cgi/man.cgi?query=socket&apropos=0&sektion=0&manpath=FreeBSD+9.2-RELEASE&arch=default&format=html -- same, but FreeBSD specific

http://www.freebsd.org/cgi/man.cgi?query=netgraph&sektion=4&apropos=0&manpath=FreeBSD+9.2-RELEASE -- this seems to be the kernel-side architecture for implementing network drivers, it's a long read

--

In the Unix world, most device drivers are traditionally exposed as those special device files provided it can be classified as either character-special or block-special. Then you use standard open/close/read/write calls, and additionally ioctl. Basically, in Unix/Linux, drivers can't add arbitrary system calls since that all lives in a single system call table. It's just not practical. So ioctl is a very generic system call that essentially allows drivers to implement arbitrary operations that don't fit into the open/close/read/write file-like model. The BSD family mostly sticks to this traditional model, though and increasing number of Linux drivers (e.g. the CPU frequency drivers, to name one) use the sysfs interface instead (basically, a virtual file system that allows drivers to expose virtual files that can be read to find information, or written to modify driver configuration at runtime).

Network devices, and video devices (with Linux KMS) are major exceptions that have specialized interfaces (at least those are the two major exceptions I can think of). I don't do any kernel programming myself (someday I'd like to make my own hobby OS, but that goal is a way off), so I can't give you much more than the high-level overview, unfortunately. If you do want examples on how Linux does things, download the kernel source and look at the text files in the Documentation directory. For FreeBSD, the manual pages in section 4 describe individual kernel modules/subsystems/drivers, though with manual pages it's hard to just browse, you kinda have to know what you're looking for.

2
mantra•

One old-school Unix way is to have system driver work with named pipes, and then the user gets access based on file protections on the named pipe. This is essentially how RS232 drivers work (you open /dev/ttyS0 etc. do some ioctl's on the file handle and then read/write to the file. It allows HW IO to be done like file IO - keep the classical Unix paradigm of program design. HPUX used to do HW interfaces like GPIB this way pre-9.0 (until they fucked it up and started using a MS-DOS/Windows style of driver access). This might be a logical way to deal with a console-like stream.

1
klange•

These aren't named pipes but rather device special files. They can be character or block devices and can implement their own ioctl calls for device-specific operations.

1