玄人志向のUSB5+eSATA-PCI でSATAからブートさせる

2006.10.3 まりも

 どんなデバイスか

 玄人志向のUSB5+eSATA-PCIには、NEC USB2.0と SiliconImage SATAlink 3512 のチップが使われています。SiliconImageのSATAは大熊猫氏の98用BIOSを入れればハードディスクからの起動ができると期待されました。しかし後述のように、PC-9821ではこのボードのSATA BIOSは全く出現しませんでした。

 デバイス構成は、装着したスロットのデバイス番号で、

 という位置にそれぞれのデバイスが存在するというようになっています。ボードを見ると黒い紙が貼られた3つほどのIC(74xx TLL-ICなど汎用2個と不明品1個)があります。これらのICは、SATAがマルチファンクション3に見えるように、そしてバスマスタ信号をUSBとSATAに振り分けるようにすべく、PCIバスに介入動作するものと考えられます。この部分はボード製造元のLycomのオリジナルと思われます。"Lycomブリッジ使用"などとパッケージに印刷されていますが、通常のPCI-PCIブリッジという意味のチップは使われていません。

 マルチファンクションの一つとしてSATAが存在するという構成ですが、PC-9821のおかしなシステムBIOSでは、I/Oアドレスを使用するデバイスがファンクション0に存在しないと、以降のファンクション番号のデバイスはPCIデバイススキャンから漏れてしまうようです。この結果、USB2.0とSATAには全くリソース割り当てもなされない状態となり、SATAからのブートもできません。バッファローのIFC-PCI7ESAU2も見かけ同じ構成ですが、こちらはデバイススキャンが正常になされブートできます。違いはファンクション0と1のVIA UHCI USB 1.1デバイスがI/Oアドレスを使用する点くらいです。

 他力ブートの方法

 さてPC-9821でブートできないとわかった玄人志向のUSB5+eSATA-PCIですが、PCI-PCIブリッジを使用していない点で、RvII26での動作安定が期待できるので、なんとしてもブートさせたいところです。そこで、このボードのROMではなく、別のPCIボードのROM BIOSにこのボードの大熊猫氏BIOSを書き入れて起動させることを思いつきました。この方法をとりあえずヤドカリブートとでも呼んでおくことにします。

 動作原理の説明のため、まずPCIブートROMの起動について簡単に書いておきます。通常、PCI拡張ROMからのブートは以下のようなステップで進みます。

 さてSTEP4 で呼ばれたBIOS側は、レジスタAXの初期値で自身のデバイスアドレスを知ることができるわけですが、AXの値が変数に保存される前に、AXを他のデバイスのアドレス値にすり替えてしまえば、そのデバイスからブートしたROMが動いているのと全く同じことになると考えられます。AXの内容を、別スロットに存在するUSB5+eSATA-PCIのSATAのデバイスアドレスにすればよいわけです。たとえばバス#0、デバイス#12のスロットに挿しているのであれば、ファンクションが3ですので、AXの値は 0063h というようになります。以降、大熊猫BIOSのルーチンはこの値を自身のデバイスのアドレスとして使うので、実際にブートしたROMとSATAデバイスが同じところになくてもよいのです。

 ただしこれだけではダメで、他にも大熊猫BIOSに付加して行うべき仕事がたくさんあります。最低限必要なのは、IRQの設定、I/Oアドレスの設定、メモリアドレス設定、コマンドレジスタ活性化 などです。I/Oアドレスは他と競合しなければ何でもよいので、シャレで3512h近辺を割り当ててみることにしました(実際には境界値で切られるので3510hから)。メモリアドレスは初期値ゼロのままですとメインメモリとぶつかってエラーを起こしかねないので、メモリのない高いアドレスに適当に配置しておきます。

 コマンドレジスタについては、少なくとも、I/O、メモリ、バスマスタはアセスアクセス可にしておく必要があります。通常は値0157hを書き入れておけばOKです。しかしIRQだけは大きな問題で、これはシステム構成によって変化し、他のデバイスとの共有があり得るので、勝手に決め打ちはできません。ではどこを参照すればIRQがわかるのか、ですが、USB5+eSATA-PCIのファンクション0がデバイススキャンされる前には、IRQを知る確実な方法がありません。CバスブリッジのIRQルーティングを調べても、デバイススキャンされる前にはIRQの値は確定していないのです。 しかしINT#Aの割り当てから、ファンクション0のUSBと同3のSATAは同じ割り込みを使うことが明らかですので、USB5+eSATA-PCIのスキャンが完了してUSBのIRQが確定したあとに、これとSATAのIRQとを一致させればよいということになります。以上のように、デバイススキャン順序の制約はありますが、比較的簡単にIRQ決定の問題は解決できます。

 さてこのように改造したブートROMは、別のデバイスに入れるわけですから、PCI構造体部に書かれる当該デバイスのベンダ/デバイス(通常はオフセット54hにある)IDは、この別デバイスのものにしておかなければなりません。しかしこれでは起動した後にSiI3512から起動したと見なされなくなるおそれがあるので、BIOSの初期化ルーチンの最後のほうで、自身のベンダー/デバイスIDを 1095:3512hに置き換えて、さもSiI3512からのブートROMであるように偽装してからチェックサムを復元し、システムにリターンするようにします。

 あとは、以上の仕事を付加した大熊猫氏BIOSを別デバイスのROMに書き入れればよいということになります。繰り返しますが、この別デバイスはUSB5+eSATA-PCIより後にスキャンされるスロットに入れる必要があります。今回は、ROM書き込みプログラムが存在し、かつボード自体も使用価値があるという点で、ミレニアムMGA2064Wを使うことにしました。これはデバイス#13かそれ以上のデバイス番号のスロットに挿す必要がありますが、CHANPON-ZEROなどが遊んでいる場合はその上のスロットで構いません。バス#0以外はデバイススキャンの順位が後となるためです。

 適用例

 PC-9821RvII26で、スロット2(デバイス#12)にUSB5+eSATA-PCIを入れ、スロット3(デバイス#13)にミレニアムを入れた状態で、このミレニアムのROMに乗っ取りBIOSを書き入れて使っています。スロット1が空いたので、ここにPCIビデオカードを載せたりSCSIアダプタを載せることができるなど、スロットの節約となります。またファンクション/バスマスタ振り分けのLycom独特の回路が動作を遅くすることが心配されましたが、SATAのハードディスクベンチマークをとってみると、速度の低下はさほど大きくありませんでした。この点、バッファローのIFC-PCI7ESAU2よりも優れています。IFC-PCI7ESAU2ですと、35000KB/s程度のdisk read速度で頭打ちとなります。

 なおこのボードはオーバークロック耐性がかなりよいようです。ベースクロック86MHz(PCI43MHz)のPC-9821Ra300でも動作します。もともとSiImageのSATAチップは66MHz動作を考慮しているため、単独にはオーバークロック耐性が高いと予想できましたが、ファンクション/バスマスタ振り分けのLycom独特の回路がオーバークロック動作可能かどうかは疑問でした。

 お約束と注意事項 <必ず守ってください>

 この記事は、USB5+eSATA-PCIのブートに関する実験記事です。この記事は、大熊猫氏のソースを読める人であり、自身のデバイス環境に合わせてソースおよびBIOSバイナリを作成し、フラッシュライタを使ってPCIブートROMに格納することができる人を対象として書かれています。

 ブートさせるためのBIOSバイナリデータを配布することはできません。再配布について大熊猫氏の許可を取っていませんし、それ以前に、どのスロットに何を挿すかというデバイス構成によって、相当にカスタマイズしなくてはなりません。汎用的に使えるバイナリを作成するのはほぼ不可能です。大熊猫氏のソースを読める人が、自身のデバイス環境に合わせて作成してください。またこの記事に関して、大熊猫氏に問い合わや要求などを絶対に行わないように強くお願いします。

 参考資料 ソース改変・追加箇所の内容


大熊猫BIOSソースを改変・付加するときの参考にしてください。
(バージョン変更などで実際と異なる可能性があります)


;★プログラムの先頭にこれを書いておく
;   ↓はUSB5+eSATA-PCIのあるデバイス番号
SLOTDEVN        equ     12
;   ↓は ヤドカリするROMのあるデバイスのベンダ/デバイスID
FAKE_VENDOR     equ  102Bh  ; この例はミレニアム
FAKE_DEVICE     equ  0519h  ;


;★ PCI構造体つじつま合わせ
        ORG     0050h
PCIR    DB      'PCIR'  ;00h(4Bytes):シグネチャ
; この以下の二行を改変↓
        DW      FAKE_VENDOR     ; 04h(word):ベンダID
        DW      FAKE_DEVICE     ; 06h(word):デバイスID


;★ INIT1:というラベルのすぐ次に以下のコードを書く
        mov     ah,0
        mov     al,SLOTDEVN
        shl     al,3
        or      al,3    ; SATA部のデバイスアドレスをAXに生成
     :
     :
     :



;★ ;リソースの取得
        MOV     WORD PTR CS:CHIPPOS,AX
        OR      AH,AH
; ここに、次の二行を新規作成して挿入
        call    SET_REG_04_0C_24_3C
        jC      End_INIT1  ; 存在しないときはINIT1から一気に抜ける
;
        JZ      GRES1
        CALL    SETRES
     :
     :
     :


;★End_INIT1 というラベルを以下のところ(レジスタ待避の前)に挿入

End_INIT1:
        POP     ECX
        POP     EAX
     :
     :
     :


;★ リソース設定ルーチンの改変
SETRES: CMP     BYTE PTR CS:SRFLAG,01h
        JZ      SRES2;SRFLAGが1ならIOアドレスXFD0からにかためる
;下記の二行はコメントアウトにして、バス#0でない時と同じ動作にする
;;;     OR      AH,AH
;;;     JNZ     SRES1;バスが0でないなら強制的にIOアドレスを修正する

;★ SETRES2 に入るようにしておき、さらにI/Oアドレスの素を決め打ちする
SRES2:
        MOV     AL,10h;10h
        CALL    CONFRW
; の次に↓の一行を      (ベースアドレスが3510hからになる)
        mov cx,03510h
        JMP     SRES3
     :
     :
     :


;★  SET_REG_04_0C_24_3Cというサブルーチンを、
;ソースの後ろのほうの適当なところに作成する

SET_REG_04_0C_24_3C:
        mov     DI,0000h        ; まず存在チェック
        mov     BX,WORD PTR CS:CHIPPOS
        mov     AX,0B10Ah;
        int     1Ah
        cmp     ecx,35121095h
        jne     End_SET_REG4       ; 存在しなければcarry

        mov     ecx,35120000h  ; メモリアドレス適当にシャレで設定(>512MB)
        mov     DI,0024h
        mov     BX,WORD PTR CS:CHIPPOS
        mov     AX,0B10Dh;      CnfgW DWord
        int     1Ah

        mov     DI,000Ch       ; CacheLineSizeとLatency決め打ち
        mov     CX,6008h       ;
        mov     BX,WORD PTR CS:CHIPPOS
        mov     AX,0B10Ch;      CnfgW Word
        int     1Ah

;IRQの設定
        mov     bx,WORD PTR cs:CHIPPOS
        and     bx,0FFF8h       ; まずfunc0 USBのIRQをゲット
        mov     DI,003Ch
        mov     AX,0B108h;      CnfgR byte
        int     1Ah

        mov     bx,WORD PTR cs:CHIPPOS
        mov     DI,003Ch
        mov     AX,0B10Bh;      CnfgW byte
        int     1Ah             ; それをSATAのほうのIRQにする

        mov     DI,0004h ; コマンドレジスタ
        mov     CX,0157h ; フル活性化
        mov     BX,WORD PTR CS:CHIPPOS
        mov     AX,0B10Ch;      CnfgW Word
        int     1Ah

; ROM内のPCI構造体中のベンダーデバイスIDを偽装する
        push    es
        mov     ax,8000h
        mov     es,ax
        mov     eax,35121095h
        mov     es:[0054h],eax
        pop     es
        clc
        RET
End_SET_REG4:
        stc
        RET