FreeBSDのデバイスコンフィグレーション

現在のデバイスコンフィグレーションの仕組みは以下の四つがあります。

* ハードコードからのコンフィグレーション
* hintsによるコンフィグレーション
* fdtによるコンフィグレーション
* kldloadによるロード

ハードコードからのコンフィグレーションは親のデバイスのコードでのBUS_ADD_CHILD()メソッドにより実行されます。

hintsによるコンフィグレーションはbuildkernelでカーネル内に放り込まれたhintsの情報により読み込みが実行されます。BUS_ADD_CHILDで読み込まれているにも関わらずhintsでも指定するとカーネルが落ちます。

```
hint.spi.0.at="nexus0"
hint.spi.0.maddr=0x1f000000
hint.spi.0.msize=0x10
```

fdtによるコンフィグレーションはbootから引き渡されたdtbかbuildkernel時にスタティックに放り込まれたdtsをコンパイルしたdtbにより読み込まれます。

```
                spi0@84000 {
                        compatible = "lpc,spi";
                        reg = <0x84000 0x4000>;
                        interrupts = <20>;
                        interrupt-parent = <&PIC>;
                };
```

kldloadでのロードはコンフィグレーションではないですが、デバイスがコンフィグレーション同様に読み込まれます。

FreeBSDのブロジェクとの方針としてはfdtが一番推奨で、hintsが次で、おそらハードコードはあまり推奨されていないとおもいます。2016/03現在sys/armはfdtに移行していますがsys/mipsはあまりftdへの移行が進んでいませんが、少しずつコードは入ってきています。

子と親の関係は、ドラーバーコードのDRIVER_MODULEで定義されています。これはhintsベースでもFDTベースでも同じです。EARLY_DRIVER_MODULEで定義された物は先にロードされます。

FreeBSDの現在のデバイスのコンフィグレーションの問題として、デバイスのロードされる順番が明示的に設定できないケースがあります。デバイスがバスの場合、マイナー番号が変わってしまうと子になるデバイスが正しくロードできない可能性があります。

spiバスのmx25lがあるmipsなルータでgpiospiを追加したところgpiospiがspibus0になりhintsでspibus0としたmx25lが見えなくなる事がありました。現在のFreeBSDでは細かい順番が設定できないためmx25lのhintsをspibus1と書き換えるしかないです。

# コンソール

コンソールはデバイスがコンフィグレーションされる前に使用されるため上のコンフィグレーションとは別にコンソール用のコンフィグレーションで初期化されます。

コンソールはOSのソース内でCONSOLE_DRIVERで登録されたドライバの中でスコアの高いものをコンソールに選びます。シリアルコンソールの場合dev/uart/uart_tty.cに登録がありこれを使います。実体はuart_cpu_getdev()で取得するようになっています。

![uart.png](https://qiita-image-store.s3.amazonaws.com/0/104066/30a4fdd7-1cb8-4ca0-6ba7-7bd31d7c48aa.png)

uart_cpu_fdt.cではdtsファイルの"/chosen"のデバイスか"serial0"なデバイスが選択されるようです。そのデバイスのcompatibleがofw_compat_dataにあるソースのクラスが利用されます。

/sbin/initが起動されるまではコンソールドライバに出力され、init起動後はbusなuartが使われるようになります。コンソールへの出力ではFIFOが空になったという割り込みは使われません。これはシステム起動後には割り込みコントローラが(PIC)を処理するデバイスが登録されていない状態のためです。

# リソースと割り込み

FreeBSDでは古来からのprobe(),attach()を使ってデバイスのコンフィグレーションを行いますが、リソースの確保はbus_alloc_resource_any()で行われます。割り込みのハンドラの登録はbus_setup_intr()で行います。FreeBSDの割り込みハンドラは二つあり、filterとithreadと呼ばれています。

![freebsd_intr.png](https://qiita-image-store.s3.amazonaws.com/0/104066/c681e4d2-5579-ad73-4697-92d9ce8ef9c3.png)

二つに分けているのは割り込みの処理があまり大きくなって、パフォーマンスに影響するのを避けるためではないかと思われます。

## INTRNG

armのプロジェクトの成果のINTRNGが他のアーキテクチャでも使えるようになりました。INTRNGの目標はirq処理の整理とPICとBUSの分離またマルチプロセッサー上での最適化と思われます。

bus_setup_intr()は変えずにその中で処理される仕組みを変えています。

armはv4系ではハードウエア割り込みが1本ですが、v6以降では複数あるようです。

armv5tなRT1310の割り込みは以下のようになっています。

![arm_intr.png](https://qiita-image-store.s3.amazonaws.com/0/104066/3012765f-cec8-4667-21f3-478132f748b0.png)

mipsなar5315の割り込みは以下のようになっています。6本の割り込みはMIPS共通です。PICはそれぞれのSOC毎に違います。INTRNGではMIPS共通の割り込みの登録はcpu_establish_hardintrでおこないます。

![mips_intr.png](https://qiita-image-store.s3.amazonaws.com/0/104066/8d13c340-a89e-69c4-6ceb-b32cc706c867.png)

mips 4KではTimerが固定で用意されています。これ以外はボード毎に違っています。

BCM4712はPICはなくてMIPSの6本の割り込みだけになっている。0-4の割り込みに複数の割り込みをアサイン出来るようだ。

mips/mediatek(RT3050)のkern/subr_intr.cのデバッグログ

```
intr_pic_register(): PIC 0x805acdc0 registered for cpupic0 <dev 0x80554100, xref 3>
intr_pic_claim_root(): irq root set to cpupic0
intr_pic_register(): PIC 0x805ac080 registered for intc0 <dev 0x80553800, xref 1>
intr_setup_irq(): irq 2 add handler error 0 on intc0
intr_pic_register(): PIC 0x805abdc0 registered for gpio0 <dev 0x80553680, xref 9>
intr_setup_irq(): irq 14 add handler error 0 on gpio0
intr_setup_irq(): irq 20 add handler error 0 on uart0
intr_setup_irq(): irq 5 add handler error 0 on rt0
intr_setup_irq(): irq 7 add handler error 0 on cpupic0
```

subr_intr.cの中には同じpanicに同じメッセージのところがあり、どこで落ちたのかわかりません。なんともいけてないです。

subr_intr.cのirq_mapは4Kの割り込みは全部登録されていますが、PICは割り込みがあるものだけ登録するようです。