ラベル NetBSD の投稿を表示しています。 すべての投稿を表示
ラベル NetBSD の投稿を表示しています。 すべての投稿を表示

2011年4月24日

NetBSDのUSBホストコントローラのドライバIF

NetBSDカーネル内部の話になります。

NetBSDのUSB(ホスト)ドライバでは各種ホストコントローラ(以下、HC)とUSBプロトコルドライバ間でIFが切られています。上位のプロトコルドライバからはHC種別(ehci, ohci, uhci)は意識せず、このIF関数をコールすることでホストコントローラを制御しています。今回、このIF形式と各IF関数で行う処理内容に関して簡単にまとめます。

なお今回、NetBSD-5.1を対象に記載しています。NetBSDでUSBホストドライバがサポートされてからIFは大きく変わっていません。

インタフェース形式
HCドライバのIFは、usbd_bus_methods構造体とusbd_pipe_methds構造体で宣言されています。本構造体は dev/usb/usbdivar.h で型宣言されており以下のような構造になります。



struct usbd_bus_methods {
    usbd_status         (*open_pipe)(struct usbd_pipe *pipe);
    void                (*soft_intr)(void *);
    void                (*do_poll)(struct usbd_bus *);
    usbd_status         (*allocm)(struct usbd_bus *, usb_dma_t *, u_int32_t bufsize);
    void                (*freem)(struct usbd_bus *, usb_dma_t *);
    struct usbd_xfer *  (*allocx)(struct usbd_bus *);
    void                (*freex)(struct usbd_bus *, struct usbd_xfer *);
};

struct usbd_pipe_methods {
    usbd_status      (*transfer)(usbd_xfer_handle xfer);
    usbd_status      (*start)(usbd_xfer_handle xfer);
    void              (*abort)(usbd_xfer_handle xfer);
    void              (*close)(usbd_pipe_handle pipe);
    void              (*cleartoggle)(usbd_pipe_handle pipe);
    void              (*done)(usbd_xfer_handle xfer);
};

構造体名から想像できますが、usbd_bus_methodsはHCに紐付けられたHCとして行うべき関数をまとめた構造体です。一方usbd_pipe_methodsはUSBの転送パイプ(コントロール転送とかバルク転送)として行うべき関数をまとめた構造体になります。

各関数で行うべき処理に関して、以下に記載します。

open_pipe
  USB転送パイプのオープンを行います。上位で転送パイプを用いてデータ転送する場合にはまず本IFで転送パイプの初期化処理を行います。HCごとに転送パイプの取扱いおよび必要なデータ構造が異なるため本IFが用意されています。また本関数内部でUSB転送パイプとusbd_pipe_methodsの紐付けを行います。

soft_intr
  割り込み処理を行う関数です。NetBSDのUSBホストドライバではUSB関連の割り込み処理はハード割り込みのコンテキストではなく、ソフト割り込みのコンテキストで実行することが設計ポリシーとなっており、ソフト割り込み実行時にも本関数が実行されます。各HCドライバ内での動きとしては、ハード割り込みが発生した際にソフト割り込みのスケジューリングを行い、そのソフト割り込み内で割り込み処理を行う流れになります。

do_poll
  割り込をソフト側でポーリングするためのIFです。割り込み禁止状態でハードからのイベント(=割り込み)待ちが必要となるような場合に利用するIFです。

allocm
  HCに渡す送受信用データ領域のメモリ確保を行う際のIFです。メモリ領域確保自体はHCに依存する部分は少なくNetBSD-5.1でも各HCでほとんど共通の処理を行っています。(HCによって送受信データのアライメントがある場合や特殊制御が必要な場合には本IFが意味を持ちます。)

freem
  allocmで確保したメモリ領域を解放する際のIFです。

allocx
  USB転送(usbd_xfer)を確保する際のIFです。HCでは転送単位で必要となる処理が多いたえめ、本IFは(allocmと異なり)HCごとに大きく異なるため、各HCごとに必要なデータ領域の確保等を行います。

freex
  allocxで確保したUSB転送データ構造を解放する際のIFです。

transfer
  上位USBプロトコルドライバからUSB転送を開始する際のIFです。

start
  実際にHCに対してUSB転送を行う際のIFです。上記transferとstartの差異について説明しますが、NetBSDのUSBドライバの作りとしてUSB転送はパイプごとにキューイングする作りになっています。transfer()はこのキューにデータをエンキューするためのIFで、start()はキューのデータを実際に転送するIFです。またNetBSDのUSBドライバはデータ転送が終了した際にコールバック内でstart()を実行することで次の転送を開始するような作りにもなっています。

abort
  転送中のUSB転送を中止する際のIFです。

close
  open_pipe()でオープンしたパイプをクローズするIFです。

cleartoggle
  USBプロトコルで定められているトグルをクリアするIFです。トグルの制御方法はHCごとに異なっておりHC(ハード)が完全制御するもののありますが、ソフト側で制御が必要なものもあるため本IFが存在します。

以上。

2008年11月30日

NetBSDからExt2FSのパーティションをマウントする。

NetBSDから、データ用パーティション(こちらで検討したもので、10GBのEXT3FS)をマウントしようとすると、エラーになる。

# mount_ext2fs /dev/wd0j /home
Ext2 fs: unsupport inode size
mount_ext2fs: dev/wd0j on /home: incorrect super block


Linuxマシンから dumpe2fs コマンドでこのパーティションの内容を確認したところ、

Inode size: 256

となっていた。
一方で、NetBSDのカーネルソースコードを確認すると、NetBSDのExt2FSファイルシステムドライバは、inodeサイズを128までしかサポートしていない模様。

そこで、データ用パーティションをフォーマットしなおして(幸い、まだデータをほとんど置いていない)、inodeサイズを変更することにする。
Linuxマシンから、以下のコマンドでパーティションを再フォーマットする。

# mke2fs -j -I 128 /dev/hda6


これで、NetBSDからもマウントできるようになった!

2008年11月23日

NetBSD 4.0.1 のインストール

先日のLinuxのインストールに続いて、今度はNetBSDをインストールする。

NetBSDのサイトから、i386用のインストールCDイメージを取得してきてCD-Rに準備。
このインストーラから起動して、インストールを行う。

基本的にはインストーラに従ってインストールすれば良いが、注意点を以下に記載しておく。
  • HDDのディスクジオメトリの設定 : Linuxのインストール時には、C/H/S = 155061/16/63 として認識されていたが、NetBSDでは、C/H/S = ??/240/63として認識される。このままインストールすると、NetBSDのインストーラがMBRエントリを書き換えてしまうので、ジオメトリをLinuxインストール時と同じに設定すること。
  • MBRを消さない : インストール中に"MBRのエディット" or "ディスク全体を使用する"の選択を聞かれるが、間違ってもディスク全体は使用しないこと。(インストールしたLinuxが上書きされてしまうため)
  • bootcodeは書き込まない。Linuxインストール時にインストールしたGRUBをブートローダとして使用するため、NetBSDインストーラに含まれるブートローダはインストールしないようにする。
続いて、GRUBの設定ファイルにNetBSD用のエントリを追加する。
追加するエントリは以下の通り

#
# NetBSD
#
title NetBSD 4.0.1
root (hd0,4,a)
kernel /netbsd
boot

(hd0,4,a)の意味だが、"hd0"は最初のディスクをあらわしている。"4"パーティション構成で決めた通りパーティション4(0から始まる番号)にNetBSDをインストールしたので、このパーティションが選ばれるようにするため。"a"はNetBSDのdisklabelの『a』をあらわす。
これで、GRUBのメニューからNetBSDが起動できるようになった!

2008年5月25日

LTSLEEP(9)和訳

NetBSD2.1のマニュアルページ; LTSLEEP(9) を和訳してみる。


LTSLEEP(9) NetBSD Kernel Developer's Manual


NAME
ltsleep, tsleep, wakeup - プロセスコンテキストのsleepとwakeup

SYNOPSIS
#include

int
ltsleep(const void *ident, int priority, const char *wmesg, int timo,
__volatile struct simplelock *slock);

int
tsleep(const void *ident, int priority, const char *wmesg, int timo);

void
wakeup(const void *ident);

DESCRIPTION
これらの関数は、自発的なコンテキストスイッチを実現する。ltsleep()とtsleep()は現在のコンテキストが以下の理由で継続できない場合で使用される。
・カレントプロセスが、ペンディングされたI/Oオペレーションの結果を待つ必要がある
・カレントプロセスが、一時的に使用不可になっている資源(メモリ等)を必要とする
・カレントプロセスが、他のプロセスによりロックされているデータ構造にアクセスしようとしている。
wakeup()関数は、sleep状態になっているプロセスに可能な状態を通知するのに使用される。典型的に、起こされたプロセスは、(コンテキストを再び得た後)、"ブロッキングされた"状態がクリアになっていることを確認するようなリトライ処理を行う。

ltsleep()関数は以下の引数を持つ。
ident カレントプロセスがウェイトを行うリソースを表す"ウェイトチャネル"の識別子。典型的に、プロセスが競う資源に関連したカーネルのデータ構造の仮想アドレスとなる。同じ識別子がwakeup()でプロセスが再開する際に使用される。identはNULLであってはならない。

priority プロセスが起こされる際に使用されランニングプロセスキューにプットされるプロセスの優先度。このメカニズムはカーネルモードで実行されるプロセスの"スループット"を最適化するのに使用される。もしPCATCHがpriorityに指定された場合、プロセスはsleepする前後に渡されたシグナルをチェックする。もしPNORELOCKがpriorityに指定された場合、slockはプロセスがレジュームされた際にロックされない。

wmesg プロセスがsleepしている理由を表すための文字列へのポインタ。カーネルはこの文字列は使用しないが、ps(1)等のユーザレベルのユーティリティにおいて(プロセス構造体のp_wmesgフィールドによって)用いられる。

timo もし非ゼロだった場合、プロセスは最大で timo/hz 秒スリープする。もしこの時間が経過し、wakeup(ident)が実行されず、シグナルも送られなかった(PCATCHがセットされている場合)ときには、tsleep()はEWOULDBLOCKが返る。

tsleep()マクロは、機能的に以下と同等である。
ltsleep(ident, priority, wmesg, timo, NULL)

wakeup()関数は、識別子identで現在スリープしている全てのプロセスにマークする。結局、各プロセスはカーネルコンテキストで実行を再開され、tsleep()から返る。wakeup()はブロックされた状態を変更する可能性を通知するために、プロセスがスリープから戻った場合は再度ブロック条件を評価するべきである。例えば、2つ以上のプロセスが排他アクセスするロック(see lock(9))を待っている場合、そのうちの一つだけが、ロックが開放されたときにロックを取得することが可能である。他の全ては再度sleep状態となって次の機会を待つ必要がある。

返り値
ltsleep()は、wakeup()の結果として0を返す。もしltsleep()がシグナルによって返る時は、返り値はERESTARTになり、そうで無い場合はEINTRとなる。タイムアウトによりltsleep()が返る時は、EWOULDBLOCKが返る。

SEE ALSO
sigaction(2), hz(9), lock(9)

歴史
sleep/wakeupのプロセス同期のメカニズムは非常に古い。これはUnixの非常に初期のバージョンで導入された。tsleep()は、4.4BSDで導入された。ltsleep()はNetBSD1.5で導入された。

2008年2月18日

NetBSD(i386)でsysarchを追加する。

NetBSD-2.1(i386版)で、sysarchを追加してユーザランドプロセスからカーネルを好き勝手に操作できるようにしてみる。sysarchについては、NetBSDのmanページを参照のこと。

まず、sysarchの番号を追加する。番号はカーネルソースコードの arch/i386/include/sysarch.h に定義されている。
例えば以下のように、"I386_TESTSYS"を追加する。
#define I386_TESTSYS

続いて、sysarchの実行コードを作成する。i386のsysarchコードは、カーネルソースコードの arch/i386/i386/sys_machdep.c に記述されている。このファイルの sys_sysarch() 関数内のswitch文がsysarch()の切り分けを行っている箇所なので、その部分に case文(追加したsysarch番号のI386_TESTSYS)を追加する。

以上で、カーネルの設定は完了。カーネルをコンパイルしなおせばOK

ユーザランドプログラムから追加したsysarchを参照できるようにするため、ヘッダファイルを /usr/include 配下に反映させることを忘れないこと!