Z80 や x86 以外のほとんどのアーキテクチャでは,I/O アドレス空間,という概念は存在しません. このため,ターゲットに対し inb() や outb() などの関数をどう対応させるか,ということが問題となります.
単なるメモリマップド I/O の場合はまだいいのですが,PCI バスや PCMCIA バスなどではかなり難儀するでしょう. x86 の場合は,バスアドレスがそのまま I/O 空間にマップされていますが,そのほかのアーキテクチャでは別のアドレスにマップされていたりします. さらに困ったことに,これらのバスでは I/O アドレス空間とメモリアドレス空間を扱わなくてはなりません. ターゲット CPU アーキテクチャにはそのような概念は無いにも関わらず.
が問題になる場合もあるかもしれません.
最近の CPU の場合,エンディアンフリーである場合が多いのですが,Linux を移植する場合は,できれば(選択の余地があるならば)リトルエンディアンがよいでしょう. Linux カーネル自体は,PowerPC や SPARC などでも動作実績はあり,エンディ アンに関する問題はありません. が,PCI バスや PCMCIA などのデバイスまわりは PC/AT アーキテクチャが基 準となっており,リトルエンディアンが基本になっています.
CPU 内部のパイプライン処理が問題になる場合もあります. パイプラインの深さなどによっては,プログラム上の read / write と,バス上の実際の read cycle / write cycle の順番が入れ違ってしまう場合もあります. USB ホストドライバ はこの例です.
この場合は,例えば MIPS ならば sync 命令や多連続の nop などでパイプラインをフラッシュしてやります.
アドレスに対してワード境界をまたがるアクセスを許していない CPU が多数あります. RISC 系の CPU では,大抵がそうです.
ワード境界をまたがるアクセス,とは例えば
このため,構造体には,サイズ調整のための詰めもの(パディング)がされることがあります. パディングとは,例えば
struct sample_t {
char a;
int b;
};
という構造体の場合,CISC 系の場合,
char a
int b
char a
int b
これが問題になるのは,例えば受信ストリームを構造体のポインタでキャストして,解釈を行なおうとする場合です.
x86 系 CPU の場合,キャッシュコントローラのバススヌープ機能により,デバイスが RAM へ DMA 転送を行なった場合でも,RAM の内容とキャッシュの内容が食い違うことはありません.
が,バススヌープ機能が無い CPU が多々あります. この場合は,DMA 転送前に(少なくとも DMA 対象領域の)キャッシュの内容 をメモリに書き出したり破棄する処理が明示的に必要となります.
あたりが実装されていない場合が多々あります. ハードウェア直叩きのプログラムは困りますね. あと,Linux の X サーバは iopl() を使用しているので,これも困ります. ただし,フレームバッファはデバイスファイル経由のアクセスですが.
この場合の対処法としては,
ARM の場合,char = unsigned char であり,そのほかの CPU では char = signed char です. このこと自体は,ANSI 規格ではコンパイラの実装依存であるため,間違いではありません.
このため,ARM Linux でのコンパイルオプションには -fsigned-char (char を signed char として解釈する)オプションが付いています.
ユーザランドで動かすプログラムについても同様の注意が必要です.