玄人志向の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