BAKの日記: OpenBlockS266 めも
in[bwl]( ) と out [bwl]( ) と read[bwl]( ) と write[bwl]( )
これらは Linux カーネルにおける入出力関数なのである.で,非 x86 CPU において,ここらはとても頭を悩ますところの一つである.
x86 Linux において,これらの関数は
- inb()/inw()/inl(): I/O アドレス空間に対する 8bit/16bit/32bit read
- outb()/outw()/outl(): I/O アドレス空間に対する 8bit/16bit/32bit write
- readb()/readw()/readl(): メモリアドレス空間に対する 8bit/16bit/32bit read
- writeb()/writew()/writel(): メモリアドレス空間に対する 8bit/16bit/32bit write
である.さらに PC/AT では,「レガシーデバイスの I/O 空間と PCMCIA バスの I/O 空間と PCI デバイスの I/O 空間がオーバラップしている」という事情がある.
と,書いたからには話の筋は大方見当はつくと思うのだが.
まず,I/O 空間であるが,これは 8080/Z80/x86 のインテル系 CPU 固有で,他の CPU にはほとんど見られない概念である.少なくとも 6809/680x0/ARM/MIPS/PowerPC/SH には存在しない.つまり,アドレス空間は,x86 でいうところのメモリ空間しか存在しないのである.I/O は全て「メモリマップド I/O」なのである.
さらに,組み込み系の石では,シリアルなどのレガシーデバイスは直接にメモリマップされている.で,PCMCIA バスや PCI バスについては,アドレス空間のある領域をまるごとこれらのバスに割り当てていることが多い.PC/AT のように,I/O アドレス空間の下位領域にいろんなバスのデバイスが霜降り状にひしめきあっている,ということはあまり無い.まぁ,考えてみれば,「まるごと割り当て」のほうがバスコントローラの制御が簡単になるので,わざわざ霜降りを実現する義理もないわけで.
で,入出力関数の話に戻ると,まぁ,こういうわけで,非 x86 の Linux では「in[bwl](), out[bwl]() をどう define してやればよいか」という問題が常に付きまとう.これらの事情からわかるように,「これだ」という解は存在していないのが実情である.
MIPS では,linux/include/asm-mips/io.h に以下のような定義がある.
#define inb(port) __inb(port)
…
static inline unsigned char __inb(unsigned long port)
{
return __ioswab8(*(volatile u8 *)(mips_io_port_base + port));
}
つまり,指定されたアドレスにある定数オフセット(mips_io_port_base)を加算したアドレスにアクセス」というマクロである.
で,MIPS の場合,この定数値は「各 CPU やボード毎に都合のいいように定義してちょうだい」というのが実情である.レガシーデバイス・PCMCIA デバイス・PCI デバイスの三者の面子を同時に立てる,という解は存在していないのから,こうなるのも仕方の無いわけで.
さて,OpenBlockS のアーキテクチャである PowerPC ではこれがどのように定義されているか,というと,linux/include/asm-ppc/io.h と linux/include/asm-ppc/ibm4xx.h に
#define _IO_BASE 0xe8000000 /* The PCI address window */
#define inb(port) in_8((u8 *)((port)+_IO_BASE))
と定義されている.変数とマクロ定数という違いがあるものの,ポリシーとしては MIPS と同様であると言えるだろう.
OpenBlockS266 めも More ログイン