|
[ここに書いてる内容は、FM TOWNSの技術情報を残すことを目的に書いてるので、どんどん転載しちゃってください。]
Bit0: ?
Bit1: ?
Bit2: Boot Drive Number
LSB (0=A drive)
Bit3: Boot Drive Number
Bit4: Boot Drive Number
Bit5:
Boot Drive Number
Bit6: Boot Drive Number MSB
Bit7: ?
Bit2 to Bit6 is the boot drive. By writing a different drive number to this I/O, FM TOWNS will believe the system started from the number in here.
Bit0, Bit1, and Bit7 seem to have a meaning. Therefore, when modifying, the program must make sure it first read the byte, and the only update bit2 to bit6.
If 'R' is written to 3A34H and 'A' is written to 3A36H, SYSINIT.EXE shows progress and debugging information. It is unknown if other processes are referring to these I/O addresses.
Input:
AH=0FDH
Command Code.
AL=0BxH Device
Id. x is SCSI ID.
CX=0000H
LUN. Must be zero.
DS:[DI-]
Data Return Buffer Pointer and SCSI Command Information.
DS:[DI]
Data Return Buffer Address
DS:[DI+2] Data
Return Buffer Segment
DS:[DI+4...15] SCSI Command Up to 12 bytes.
Return:
CH!=0
Could not communicate with the SCSI device.
CH=0
Successfully communicated with the SCSI device. AH=STATUS,
AL=MESSAGE
CDSD.SYSの解析で、FM-R/TOWNSがSCSI CD-ROMドライブにアクセスするには、I/Oを直接攻撃する以外にはこの隠し機能を使うしかないらしい。AL=0BxHのxはSCSI ID。
SCSI Commandは最長12バイトらしい。何バイトのコマンドなのか、上位3ビットで決まるらしい。(https://www.staff.uni-mainz.de/tacke/scsi/SCSI2-07.html) 上位3ビットが000の場合6バイト、001または010の場合10バイトコマンド、101の場合12バイトコマンドになる、とある。
そのコマンドを発行した結果デバイスから返ってくるデータはアドレスがWORD PTR DS:[DI]、セグメントがWORD PTR DS:[DI+2]からに格納される。
この機能は実行結果をAH, CL, CHに格納して返すことを突き止めた。TOWNS OS V2.1 L31の解析の結果、
CH=0, AH=DS:[051AH], AL=DS:[051BH], CH=0
または、
CH=1または2, AH=不定, AL=不定
のいずれかが返る。
戻り値を設定している箇所は、FM TOWNS、TOWNS OS V2.1 L31のBIOS逆アセンブリから、(アドレスはいずれも物理アドレス)
Successfully sent an started a SCSI comman? 557f: 8a 26 1a 05 mov 0x51a,%ah 5583: a0 1b 05 mov 0x51b,%al 5586: b5 00 mov $0x0,%ch Probably the SCSI device does not become READY within timeout period: In Sub-routine at 561b called from Sub-routine at 54E7 564b: b5 01 mov $0x1,%ch Probably the SCSI device does not become BUSY within timeout period: (Called from 5553->) In Sub-routine at 5663 called from Sub-routine at 5553 called from Sub-routine at 54E7 5701: b5 02 mov $0x2,%ch
どうも、CH=2というのはそもそもSCSIデバイスにコマンドを送ったけど何も応答がなかった、CH=1というのはそもそもコマンドを受け取らなかった、という意味のように見える。
コマンドを実際送信している箇所、DS:[051AH], DS:[051BH]に値を格納している箇所も見つけた。(アドレスはいずれも物理アドレス)
CS=0421H, IP=146BH 567b: 8b 1e 1c 05 mov 0x51c,%bx 0x051c=Counter. 567f: 8b 14 mov (%si),%dx -> AH=0FDH, SCSI Disk -> DX=0x0C30 -> IO[0x0C30]=SCSI Data Register RedBook(*) pp. 262 5681: 1e push %ds 5682: 8b 3e 12 05 mov 0x512,%di 5686: 8e 1e 14 05 mov 0x514,%ds 568a: 8a 01 mov (%bx,%di),%al 568c: ee out %al,(%dx) 568d: 1f pop %ds 568e: ff 06 1c 05 incw 0x51c 5692: c3 ret (*) Red Book for FM TOWNS users means "FM TOWNS Technical Guidebook" CS=0421H, IP=1483H 5693: 8b 14 mov (%si),%dx DS:[SI]=0C30H, SCSI I/F Data Register 5695: ec in (%dx),%al 5696: a2 1a 05 mov %al,0x51a 5699: c3 ret CS=0421H, IP=148AH 569a: 8b 14 mov (%si),%dx DS:[SI]=0C30H, SCSI I/F Data Register 569c: ec in (%dx),%al 569d: a2 1b 05 mov %al,0x51b 56a0: c3 ret
これらのプロシージャを呼んでいるのは、
Jump Table 571d: 1491 <- Vector for NOP 0 0 0 -> Data Out Phase: Data 571f: 146b <- Vector for CMD write 0 0 1 -> Command Phase: Command 5721: 1491 <- Vector for NOP 0 1 0 -> Reserved 5723: 1491 <- Vector for NOP 0 1 1 -> Message Out Phase: Message 5725: 1491 <- Vector for NOP 1 0 0 -> Data In Phase: Data 5727: 1483 <- Vector for Read and store in [0x51a] 1 0 1 -> Status Phase: Status 5729: 1491 <- Vector for NOP 1 1 0 -> Reserved 572b: 148a <- Vector for Read and store in [0x51b] 1 1 1 -> Message-In Phase: Message CS=0x421 -> IP=151D Vector to this address is found at Physcai address 0000d990 1D 15 21 04 (DS:[0x520]) 572d: b8 47 0d mov $0xd47,%ax 572f: 8e d8 mov %ax,%ds 5732: be 39 05 mov $0x539,%si 5735: 8b 54 02 mov 0x2(%si),%dx DX=0x0C32 SCSI Status Register 5738: ec in (%dx),%al 5739: a8 80 test $0x80,%al Transfer Request? REQ (Active High) 573b: 74 0d je 0x574a Jump if no request. 573d: 24 70 and $0x70,%al 573f: c0 e8 03 shr $0x3,%al After shift AL Bit2=(0:Output 1:Input), Bit1=(0:Data 1:MSG), Bit0=(0:Data 1:Control) 5742: 98 cbtw 5743: 8b d8 mov %ax,%bx 5745: 2e ff 97 0d 15 call *%cs:0x150d(%bx) CS:[150DH]=4210H+150DH=571DH(Jump Table) 574a: cb lret <- Returninb by lret, implies that it is called from FM-R BIOS
どこかで割り込み登録されている模様。割り込みベクターは物理アドレスのD990Hに書いてあった。割り込み登録箇所はおそらく、
fbe4: bf 1e 05 mov $0x51e,%di fbe7: b2 08 mov $0x8,%dl fbe9: b4 00 mov $0x0,%ah fbeb: cd ae int $0xae
仮にDS=0D47とするとDS:[051EH]は物理アドレスのD98EHに対応する。割り込み登録INT 0AEHはDS:[DI+2]が呼び出しアドレスだから部t理アドレスD990Hに完全に一致。
これによって、戻り値のAH=DS:[051AH]はSCSI STATUS, AL=DS:[051BH]はSCSI MESSAGEと特定できた。 なお、STATUSはhttps://www.staff.uni-mainz.de/tacke/scsi/SCSI2-07.htmlによると、次の通りらしい。
(STATUS&0x3E)==0: Good
(STATUS&0x3E)==2: Check Condition
(STATUS&0x3E)==4: Condition Met
(STATUS&0x3E)==8: Busy
(STATUS&0x3E)==16: Intermediate
(STATUS&0x3E)==20: Intermediate Condition Met
(STATUS&0x3E)==24: Reservation
Conflict
(STATUS&0x3E)==34: Command Terminated
(STATUS&0x3E)==40: Queue
Full
FM TOWNS CD-ROM BIOSの未公開機能AH=0EHは、基本的にTest Unit Ready (ドライブにディスクが入って使用可能かチェック)と同じ。ただし、違うのは、ドライブが使用可能状態でかつ内部フラグDS:[564H]が1のときは、内部フラグをクリアした上で、Media Changed Errorを返す。
なぜこの機能が必要か。SCSI CD-ROMドライブ自体に使用可能かどうか問い合わせるコマンド Test Unit Ready がある。これを使うことえ、ドライブが使用可能状態かどうかを調べることができる。CD-ROMドライブは、直前になんらかのCDアクセスがあってからTest Unit Readyコマンドが発行されるまでの間にCDメディアの入れ替えがあった場合、Media Changed Errorを返す。これを利用して、コンピュータはCDが交換されたかどうかを知ることができる。
しかし、ここにキャッシュが関わるとややこしくなる。CD-ROMドライブはどうしてもハードディスクなどと比べて遅い。とくにヘッドを特定セクタに移動するのが遅い。CD-ROMディスクのディレクトリは変化しないから、ファイルを読むたびにヘッドを内側に移動してディレクトリを読み直すよりは、一度ディレクトリ情報をキャッシュして次からは読み込まないようにした方がいい。
ところが、たとえばCDプレイヤーアプリケーションを起動したとする。その後CDを入れ替え再生する。すると、FM TOWNSのCD-ROM BIOSは再生する前にCDの入れ替えがあったことを通知するが、その後はMedia Changed Errorは返さない。CDプレイヤーを終了して、ふたたびディレクトリを参照しようとしたとき、すでに一度Media Changed Errorはコンピュータ側に通知されてしまった後なので、Test Unit ReadyコマンドはMedia Changedエラーを返さない。その結果、CDは入れ替わっているにも関わらず、前に入っていたCDのディレクトリが表示されてしまう。
これを防止するために、FM TOWNSのTOWNS_CDドライバは未公開機能AH=0EHを使う。FM TOWNSのCD-ROM BIOSのどの機能でも、Media Changed Errorを検出すると、DS:[0564H]に1を書き込む。TOWNS_CDドライバはファイルアクセスの前に必ずAH=0EHを呼ぶ。仮にCDドライブがReadyと言ったとしても、もしもDS:[564H]が0以外の場合は、DS:[564H]を0にクリアした上でMedia Changed Errorを返す。もしもCDドライブがReadyではなかった場合、単にDS:[564H]をクリアしてCDドライブが返したエラーをそのまま返す。
この方法で、AH=0EHは、最後にファイルまたはディレクトリにアクセスして以降のCD交換を検出する。TOWNS_CDの管轄外でCDメディアの交換があったとしても正しくCDの交換に対応できる。
Input: CL=5, 1, 2, 4, 8, or 16
この未公開機能AH=0FHは、CD-ROM BIOSの内部フラグに直接アクセスするための機能らしい。ただしCL=5以外で使われている形跡は無かった。デバッグ用に追加した機能をそのまま残したのかもしれない。CD-ROM BIOSにはなんらかのキャッシュと思われるフラグが5か所見つかった。
DS:[564H] Media Changed Error Cache (See
AH=0EH)
DS:[565H] Set to 1 upon error, reset, or media change, but
nothing is referring to it?
DS:[566H] Checked and cleared at the
beginning of CS:[0C16H](Physical 6906H)
DS:[567H] Set to 1 upon error,
reset, or media change, but nothing is referring to it?
DS:[568H] PAUSE
flag (1:Paused 2:Unpaused)
このうち意味がわかったのはDS:[564H]とDS:[568H]のみ。残りはDS:[564H]と似た働きをしているようだが、まだ解明できていない。未公開機能 AH=0FH はこれらのフラグに直接アクセスするためのものらしい。C++風に書くとこんな感じ。
int CDROM_BIOS_INT93H_0FH(unsigned char CL,unsigned char &DL) { switch(CL) { case 5: DL=flag_0567H; flag_0567H=0; return NO_ERROR; case 0: DL=flag_0564H; // Media_Changed_Cache return NO_ERROR; case 1: flag_0564H=DL; // Media_Changed_Cache flag_0566H|=DL; return NO_ERROR; case 2: DL=flag_0565H; flag_0565H=0; return NO_ERROR; case 4: flag_0566H|=DL; return NO_ERROR; case 8: DL=flag_0568H; // Pause flag return NO_ERROR; case 16: flag_0568H=DL; // Pause flag return NO_ERROR; default: return PARAMETER_ERROR; } }
CL==1の場合を見るとどうも0564Hと0566Hはかかわりがありそうな感じがする。もう少し使われ方を詰めればわかると思うんだけど。
この機能はコマンドダンプで実際使われている場面をまだ見たことが無い。CH!=0 || DL!=1の場合PARAMETER ERRORを返す。CH==0 && DL==1の場合、8バイトのパラメータバッファをクリアするもののコマンドは発行しない。そのままABNORMAL TERMINATION ERRORを返す。事実上何もしない。
5a2d: b4 80 mov $0x80,%ah 5a2f: b9 02 00 mov $0x2,%cx 5a32: 8a 46 07 mov 0x7(%bp),%al AL=Incoming_CH 5a35: 3c 00 cmp $0x0,%al 5a37: 75 16 jne 0x5a4f 5a39: 8a 46 08 mov 0x8(%bp),%al AL=Incoming_DL 5a3c: 3c 01 cmp $0x1,%al 5a3e: 77 0f ja 0x5a4f 5a40: e8 8e 0c call 0x66d1 Clear 8 bytes from 57f (parameter buffer) Registers Preserved 5a43: 3c 01 cmp $0x1,%al AL is already checked. AL==1 5a45: 75 06 jne 0x5a4d Therefore never jumps. 5a47: b4 80 mov $0x80,%ah 5a49: b9 08 00 mov $0x8,%cx Abnormal Termination 5a4c: c3 ret 5a4d: b4 00 mov $0x0,%ah 5a4f: c3 ret
電源切断時、リセット時にAH=11Hが呼ばれるのだが、これは何もしていなかった。
CD-ROM BIOS INT 93H AL=C0H, AH=11H Unpublished
5a50: b4 00 mov $0x0,%ah
5a52: c3 ret
Input: DS:[DI] Electric Volume
Buffer
DS:[DI] 0
DS:[DI+1] Left Channel Electric Volume 0 to 255
DS:[DI+2] 1
DS:[DI+3] Right Channel Electric
Volume 0 to 255
DS:[DI+4] 2
DS:[DI+5] Microphone Electric Volume (Probably)
DS:[DI+6] 3
DS:[DI+7] Modem Electric Volume
(Probably)
CD-ROMの電子ボリュームを設定する。電子ボリュームはDS:[DI]からの8バイトのバッファに書いてあるはずだが、この機能はDS:[DI+1]およびDS:[DI+3]以外はアクセスしない。
Output: DS:[DI] Electric Volume
Buffer
DS:[DI] 0
DS:[DI+1] Left Channel Electric Volume 0 to 255
DS:[DI+2] 1
DS:[DI+3] Right Channel Electric
Volume 0 to 255
DS:[DI+4] 2
DS:[DI+5] Microphone Electric Volume (Probably)
DS:[DI+6] 3
DS:[DI+7] Modem Electric Volume
(Probably)
電子ボリュームを返す。CD-ROM以外にもマイクとモデムのボリュームも結果的に返ってしまう模様。
Input:
DL=0,1,2,3
When DL=0:
Towns OS V1.1 CL:Third parameter to the command 3FH
Towns OS V2.1 BL:Third parameter to the command 3FH
このコマンドは実際TOWNS_CDドライバから呼ばれているが、効果は不明。C++風に書くとこうなる。
int CDROM_BIOS_INT93H_61H(unsigned char DL,unsigned char &BL) { if(DL==0) { DS:[0x740]=BL; return IssueCommand(0x3f,{0x02,0x00,0x0d,BL,0,0,0,0}) } else if(DL==1) { DS:[0x741]=BL; return NO_ERROR; } else if(DL==0x10) { BL=DS:[0x740]; return NO_ERROR; } else if(DL==0x11) { BL=DS:[0x741]; return NO_ERROR; } return PARAMETER_ERROR; }
Linux for FM TOWNSのソース (towns_cd.h) を見るとかなりのCD-ROMコマンドがわかるのだが、3FH (Return State Request Flag + 1FH) は不明と書いてある (CDxxx)。YSSCSICD.SYSではこの機能は常にNO ERROR扱いにしている。
Towns OSにはメジャーバージョンV1.1とV2.1がある。V2.1の方がV1.1よりもはるかに洗練されたユーザーインターフェースになっていて、V2.1L31以降はCooperative Multi Taskingを実現している。内部的にもいくつもの違いがあって、これまでに解析してわかったことを以下にまとめる。
Towns OS V1.1ではDOSはすべて下位640KBに収まっているらしく、UMB (640KB~1MB)は空き空間とされているらしい。これに対して、Towns OS V2.1では一部の機能をUMBに置いてDOSアプリケーションが使えるRAMを増やしているらしい。Galaxy Force IIがなぜV2.1から起動できないのかを調べていて、Towns OS V2.1はDOSが物理メモリ空間FC000~FFFFFを使用しているらしいということがわかった。この領域を破壊するとシステムがクラッシュしてしまう。Towns OS V1.1ではこの領域を破壊しても何も問題が起こらない。
Towns OS V2.1付属のDOS Extender (RUN386.EXE) はmalloc時UMB領域でDOSが使用する範囲を認識して回避する。しかし、Towns OS V1.1付属のDOS ExtenderはUMBの使用状態を認識しない。このため、Towns OS V2.1上でTowns OS V1.1のRUN386.EXEを使うと、DOSが使用するUMB領域を破壊してしまう危険がある。
Towns OS V1.1では基本的に起動ドライブが常にカレントドライブとなっている。DOSのデフォルトドライブって言うからきっと起動ドライブはカレントドライブと別におぼえているもんだと思ったら、同じものだった。
Towns OS V2.1では未公開I/O 3C32Hに起動ドライブが記録されている。多分これは起動時にブートローダーが書き込むものだと思うんだけど、起動後に変更も可能でYSSCSICD.SYSはそれを利用することでTowns OS V2.1にCDから起動したと思わせることに成功した。
多分実機が現役だったころは知ってたことなんだろうけど最近再度発見したこと。Towns OS V1.1のTBIOSは486DX以降の高速機に対応していないらしくマウスカーソルが飛びまくってしまう。この問題は、Towns OS V2.1 L20のTBIOS.SYSとTBIOS.BINをV1.1の起動ドライブにコピーすることで解決できて、とくに副作用も無いらしい。
Comments are welcome. Send E-Mail to: |