UIO: User-space I/O その1

UIO: ユーザー空間でデバイスドライバ作成が可能に

 UIOがLinux Kernel 2.6.23-rc1でマージされました。UIOはユーザー空間でドライバを作成するための仕組みです。Hans-Jurgen Kochの提案したパッチで、Greg K-H経由でマージされています。


 UIOは、これらのハードルがあるカーネル空間でのドライバ開発部分をテンプレート化することで簡便にしてしまいます。一部の定義をカーネル空間で用意する必要がありますが、大半の部分をユーザー空間だけで実装できるようです。メモリにデバイスレジスタなどさえマップできればよい、あるいは割り込みの通知さえ行えればよいのであれば利用できます。



 ユーザー空間でUIOを利用する側からは、/dev/uio0をopenしてmmapすると、デバイスのメモリ空間が見えます。また/dev/uio0からreadすると、割り込みが起きるまでブロックし、発生した割り込みの回数を32-bit integerで取得できます。この仕組みを利用するためにUIOのカーネル側で必要な準備としては、uio_info構造体を定義する最低限のカーネルモジュールを定義するだけです。


Linux Kernel Watch: 9月版 ユーザー空間でのデバイスドライバ作成に道開ける

linuxカーネル2.6.23がリリースされました。今回もいろいろ機能が追加されたり、修正/改善(改悪もか?)が入っております。

  • スケジューラとしてCFSという新しいものが入りました
  • 仮想化機能のひとつとしてlguestが追加されました(rc時代だと実験コードという感じだったけどどうなったかな…)
  • 同様にXenのサポートも入りましたが、こちらはdomUのみです、他にも制限がいくつかある模様
  • UIO(userspace I/O)の導入でユーザランド空間で動くドライバの開発ができるようになった
  • x86ベースのアセンブラ(起動時に使ってる部分)をよりまともにした
  • 各種ハードウェアのドライバ追加/改良

スラッシュドット ジャパン | linux 2.6.23リリース

うおー、すげーいい。

ミーハー心やその他好事家的視点でカッコイイと思った機能は数あれど、
Linux Kernelの特定バージョンの特定機能が欲しくなったの初めてだ。

今ある某カーネルモジュールを UIOで書き換えられるかな……。手順調べてみよう。


UIO is a framework that allows to implement drivers in userspace.
This kind of thing causes much noise due to "monolithic vs microkernel" topic.
To the surprise of many, the Linux ecosystem has actually supported userspace drivers for cases that had sense for a long time.
libusb allows to access the USB bus from userspace and implement drivers there.
This is why you don't have specific drivers for, f.e., your scanner or USB digital camera, programs like sane, gphoto, gnokii, gtkam, hplip, or even some music players like rhythmbox or amarok, use libusb to access the USB bus and talk to USB devices directly.
The 2D X.org drivers that you configure in your x.org file are another popular example of drivers that not only they run in userspace, they also are portable to other unix operative systems (they're also an example of why userspace drivers can't avoid hanging your machine due to a bug in the driver that triggers a hardware hang).
CUPS and programs accessing the serial port like pppd are yet another example of userspace programs accessing the devices directly - the kernel doesn't implement any specific LPT printer or serial modem driver, those userspace programs implement the driver that knows how to talk to the printer.



UIOは userspaceでカーネルを実装するためのフレームワークです。
この種のメカニズムはモノリシックカーネル vs マイクロカーネル論争の原因となりがちです。
驚くべき事に Linuxエコシステムはユーザースペースのドライバを長い間サポートしてきました。
libusbは USBをユーザスペースからアクセス可能なドライバの例です。
USBに関するあれやこれやのアプリケーションがUSBデバイスに直接アクセス可能ですが、これは libusbによって実現されています。
X.orgの 2D描写はユーザスペースからのハードウェアアクセスの好例です。
(一方で、これはハードウェアによる問題がユーザスペースドライバを介して kernel panicを引き起こすことの好例でもあります)
CUPSや PPPdはシリアルポートやその他のハードウェアにダイレクトにアクセスしますが、これもユーザモードドライバの例です。
LPTやその他のデバイスに対するドライバがカーネルで実現しているわけではありませんし、どーやって喋るか知っている訳でもありません。


In other words, userspace drivers are not new.
UIO is not a try to migrate all the Linux kernel drivers to userspace.
In fact, a tiny (150 lines in the sample driver, including comments etc) kernel-side driver to handle some basic interrupt routine is needed as part of every UIO driver.
UIO is just a simple way to create very simple, non-performance critical drivers, which has probably been merged more with a "merge-and-see-if-it-happens-something-interesting" attitude than anything else.
For now UIO doesn't allow to create nothing but very very simple drivers: No DMA, no network and block drivers....


別の言葉で言えば、ユーザスペースドライバ(UIO)は全然新しくありません。
また、UIOは Linuxカーネルドライバをユーザスペースに移行するという話し(はなしし)でもありません。
実際に 150行(コメント含む)のサンプル用の小さなカーネルドライバは全ての UIOドライバに必要な割り込みルーチンです。
UIOは非常にシンプルに作られており、パフォーマンスが重要な用途向けではありません。
これは「何かおもしろいことが起こるか、とりあえずマージして試してみよう」ということを意図して、Linux Kernelにマージされました。
UIOは新しいものを全く創出しませんし。また、DMAやネットワークの I/Oあるいはブロックデバイスのような用途にも向きません。


Linux 2 6 23 - Linux Kernel Newbies: 2.11. UIO


CPUおごることで適当なパフォーマンスが出るんだと、UIOでインチキなドライバ使う、というのでもいいなあ。
PCIバイス向けのドライバに使うのは狂ってるのかもしれないが、ドライバのコーディングコストが安くなるなら ok牧場

UIO: user-space drivers
[Posted May 1, 2007 by corbet]

The concept of supporting user-space drivers has appeared on this page a few times before.
It's back; this time there is a version of the patch (now called "UIO") which is being proposed for inclusion into 2.6.22.
The interface has changed somewhat, so another look is called for.
Like the previous version, UIO does not completely eliminate the need for kernel-space code.
A small module is required to set up the device, perhaps interface to the PCI bus, and register an interrupt handler.
The last function (interrupt handling) is particularly important; much can be done in user space, but there needs to be an in-kernel interrupt handler which knows how to tell the device to stop crying for attention.


ユーザスペースドライバのコンセプトは少し前に紹介しました。
ちょっと振り返ってみると、user-space driverのためのパッチ(今は UIOと呼ばれています)は 2.6.22の頃に投稿されました。
インタフェースがちょっと変わりましたので、もう一回見直してみます。
以前のバージョンと同様に、UIOがカーネルスペースで動作するカーネルモジュールを撲滅するという訳ではありません。
PCIや割り込みレジスタのハンドラなどをカーネルモジュールとして組み込むことが必要です。
殆どの部分はユーザスペースで動作可能ですが、割り込みハンドラは結構重要でありカーネル内部に組み込むことが必要です。

The kernel module includes .
If it's a driver for a PCI device, it should register itself as a PCI driver in the usual way.
When it comes time to connect a device (perhaps in the PCI probe() function), the driver fills in a uio_info structure:

カーネルモジュールは includes が必要です。
もしPCIバイス向けモジュールの場合、ふつーのPCIドライバと同じように登録が必要です。
もし PCI probe()等を用いてデバイスとお喋りしようとすると、以下のような uio_info構造体をでっち上げることが必要です。

    struct uio_info {
	char			*name;
	char			*version;
	struct uio_mem		mem[MAX_UIO_MAPS];
	long			irq;
	unsigned long		irq_flags;
	void			*priv;
	irqreturn_t (*handler)(int irq, struct uio_info *dev_info);
	int (*mmap)(struct uio_info *info, struct vm_area_struct *vma);
	int (*open)(struct uio_info *info, struct inode *inode);
	int (*release)(struct uio_info *info, struct inode *inode);
	/* Internal stuff omitted */
    };

Here, name is the name of the device and version is the driver version (which will show up in sysfs).
The number of the interrupt used by the device (if any) goes into irq, with irq_flags being the flags which will be passed to request_irq().
The function which handles interrupts is handler().
This handler should acknowledge the interrupt; it usually does not need to do anything else.
The mmap(), open(), and release() functions are called from the equivalent file_operations members.


ここで "name"はデバイス名で、"version"はバージョンです。こいつらは sysfs上に表示されます。
割り込みは "irq"によって制御され、irq_flagsはフラグとして request_irq()に渡されます。
ハンドラは割り込みに対して ackを返す必要がありますが、何でもかんでも返す必要があるわけではありません。
mmap(), open(), release()は file_operationsメンバ関数から呼び出されます。


The mem array describes any memory areas which can be mapped into user space.
The uio_mem structure looks like:


memアレイ(mem配列?)はユーザスペースに配置可能なメモリ領域を記述しています。
uio_mem構造体は以下のような構造をしています。

    struct uio_mem {
	unsigned long addr;
	unsigned long size;
	int memtype;
	void __iomem *internal_addr;
	/* ... */
    };

For each mappable area, addr is the relevant address, and size is the size of the area.
If it's an I/O memory area, internal_addr is the address returned by ioremap().
The memtype field describes what the area really is:


配置可能な領域のそれぞれについて、"addr"はアドレスを表し、"size"は領域のサイズを示しています。
I/O空間の場合、"internal_addr"は ioremap()の返値を示しています。
memtypeはこの領域が本当は何なのかを示しています。

  • UIO_MEM_PHYS indicates that addr is a physical address, generally for an I/O memory area.
  • UIO_MEM_LOGICAL is memory in the kernel logical address space, such as that returned by kmalloc().
  • UIO_MEM_VIRTUAL is memory in the kernel virtual address space - the space used by vmalloc_user() and friends.
  • "UIO_MEM_PHYSは、このアドレスが物理アドレスで、I/O用のメモリ空間であることを示しています。
  • "UIO_MEM_LOGICAL"は、カーネルの論理空間であることを示し、kmalloc()の返値などで使います。
  • "UIO_MEM_VIRTUAL"は、カーネルの仮想空間であえることを示し、vmalloc_user()の返値などで使います。

Once the structure is filled in, the driver stub passes it to:

もし構造体が適当に記述されたら、ドライバは以下のように処理されます。

    int uio_register_device(struct device *parent, struct uio_info *info);

The parent pointer tells the kernel which "real" device is associated with the UIO device; if the driver is for a PCI device, parent will be pci_dev->dev.

parentポインタは UIOデバイスが実際にはどの物理デバイスに関連づけられているかを表現しています。
もしドライバが PCIバイスのためであれば、parentは pci_dev->devになります。


There is not much more to the kernel-space UIO API.
When a device goes away, the driver should call:


これだけだとカーネルスペースにおける UIO APIは十分ではありません。
バイスが不要になったら以下を呼び出す必要があります。

    void uio_unregister_device(struct uio_info *info);

The final function of note is:


この final関数は以下のようになってます。

    void uio_event_notify(struct uio_info *info);


Its purpose is to notify the UIO core that an event (typically an interrupt) has occurred.
The stub driver need not call uio_event_notify() for real interrupts, but it can be used to simulate interrupts in other situations.


目的は UIOコアになんかのイベント(たいていは割り込み)が起きたことを通知することです。
スタブドライバは uio_event_notify()を本当の割り込みに呼ぶ必要はありませんが、他の状況に置いて割り込みの代わりに使うことが出来ます。


On the user space side, the first UIO-handled device will show up as /dev/uio0 (assuming a normal udev setup).
The user-space driver will open the device.
Reading the device returns an int value which is the event count (number of interrupts) seen by the device; if no interrupts have come in since the last read, the operation will block until an interrupt happens (though non-blocking operation is supported in the usual way as well).
The file descriptor can be passed to poll().


ユーザースペース側では、最初の UIOデバイスで制御されたデバイス/dev/uio0として見えるでしょう。
ユーザスペースドライバはデバイスとして openできます。
バイスを readすると、イベントカウント(割り込みの回数)が見えます。
もし割り込みがなければ、割り込みが起こるまで固まります。
もちろん、通常求められるようなノンブロッキングなオペレーションも可能です。
ファイルディスクリプタ poll()に記述されます。



The memory areas described by the kernel-space driver can be mapped into user space with the mmap() call.
The interface is just a little strange: the offset value passed to mmap() should be N times the page size for the Nth memory area.
So, on a system with 4096-byte pages, the first memory area will be found with an offset of zero, the second at 4096, the third at 8192, etc.
Once that is figured out, though, everything is pretty straightforward.


mmap()コールするとカーネルスペースドライバに記述されたメモリ領域がユーザスペースに確保されます。
このインタフェースはちょっと変わっています。
mmap()から渡されるオフセット値は N個目のメモリ領域へのページサイズの N倍になっています。
もしシステムのページサイズが 4096バイトでオフセットサイズがゼロだったら、一つめは0、二つめは 4096、三つ目は 8192になっています。
でも、これが一回理解できれば、他の全ては非常にシンプルです。


There are some limitations, of course.
UIO drivers are char drivers; there is no provision for creating user-space block or network drivers at this time.
It is not possible to set up DMA operations from user space.
But, for drivers which can be implemented with I/O memory access and simple interrupt handlers, the necessary pieces are in place.
The patch set includes an example driver to show how it all works.
According to Thomas Gleixner, the original, fully in-kernel version of the driver had to implement 68 different ioctl() commands and was over 5,000 lines long.
The associated user-space code was over 3,000 lines as well.
The new driver eliminates all of that, with a total of 156 lines of kernel code and just under 3,000 lines in user space.


もちろん、いくつかの制限事項があります。
UIOドライバはキャラクタデバイスのためのドライバです。
今回はユーザスペースでのブロックデバイスやネットワークデバイス向けのドライバではありません。
UIOはユーザモードでの DMAを提供していません。
しかし、メモリアクセスI/Oおよび単純な割り込みハンドラが必要なドライバにとって、必要となるパーツが用意されています。
パッチ群は UIOがどう働くか知るためのサンプルドライバを含んでいます。


Thomas Gleixnerによると、カーネルスペースドライバは 68種類の ioctl()コマンドが必要で、5000行くらい必要になります。
そしてこれと強調動作するためのユーザモードでのコードは 3000行くらいになると見積もっています。
一方で、UIOはこれらの殆どを撲滅してしまい、156行のカーネルスペースのコードおよび 3000行のユーザスペースプログラムに集約出来ます。


Andrew Morton has expressed some reservations about the patch:


Andrew Mortonは UIOについていくつかの予言を表明しました。



I'm a bit uncertain about the whole UIO idea, really.
I have this vague feeling that we'd prefer to encourage people to move device drivers into GPL'ed kernel rather than encouraging them to do closed-source userspace implementations which will probably end up being slower, less reliable and unavailable on various architectures, distros, etc


私は UIOについて何も確信を持っていません。
GPLで汚染されたカーネル空間ではなく、もう少し閉鎖的なユーザスペースモジュールへ移行したがる人々がいるのではないかという曖昧な感触を持っています。


The authors respond that it's not really about doing proprietary drivers, though some of that will undoubtedly go on.
There's a number of people, especially in the embedded space, who want to do user-space drivers, for prototyping purposes if nothing else.
The UIO framework gives them a relatively safe and standard way to write these drivers, which is seen as being better than having them each create their own kernel hooks.
The patch has not been merged as of this writing, but, unless stronger objections arise, it's chances of getting into 2.6.22 are reasonably good.


プロプライエタリなドライバが全てこのように振る舞うとは断言しませんが、いくつかのドライバが UIOへ移行するだろうと思います。
特に組み込み向けの世界ではプロトタイピングのためだけにユーザスペースドライバを必要としている人がいます。
UIOフレームワークはユーザが自前でカーネルドライバを書くよりも比較的安全で標準化されたドライバを提供します。
この文章を書いている時点ではパッチがマージされていませんが、強い反論が出なければ 2.6.22にマージされる可能性があります。


UIO: user-space drivers [LWN.net]

UIO: user-space drivers

Posted Jul 29, 2007 21:43 UTC (Sun) by subscriber vphirric (#32877) [Link]

Hear hear -- and may I also add that there are lots of specialized little hardware widgets that need software control that simply do not present a character- or block- device paradigm.
If your widget is some bizzare one-shot FPGA interface or the like, the existence of this kind of infrastructure is huge help. Thanks much!


ブロックデバイスとかキャラクタデバイスといったパラダイムでは表現しづらい、ソフトウェア制御を必要とする細々としたハードウェアがたくさんある。
もしあなたのハードウェアコンポーネントが、一品限りのFPGAインタフェースボードやその他の奇妙なものだったら、
支援するインフラが組み込まれるととっても助けになる。
さんきゅー!

UIO: user-space drivers


いや、まさにそのとおり。すんげー助けになる。
誰か標準的な PCIコアに対するロジックの書き込み機能もスケルトンつくってください……。