ユーザ・ドライバ領域にベクタを書き込む [ColdFire V2]
SilentC のユーザ・ドライバ機能は、処理速度の遅いインタプリタを補うために必要です。 でも、 ColdFire にとって 4096 バイトの領域は決して十分とはいえません。 できれば、 0x00020000 からの 128k バイトの領域を優雅に使いたいところです。 いっそのこと、 0x00020000 からの領域へのベクタ・テーブルを書いて固定してしまおう。
SilentCだけで十分ですよ
"UserDriver" 領域に何か書き込むためには、バイナリ・ファイル "UserDriver.bin" を tftp で送り込んでおいて次回再起動の際に 0x00013000 からの領域へ SilentC に転記させるという方法が、公式とされています。 でも、バイナリ・ファイルを作らなきゃいけないし、ファイル・システムに 4096 バイトの空きが無ければ、ファイルを置くこともできないし。
今回書き込みたいのは、ベクタ・テーブルだけです。 このテーブルは、機械的な繰り返しで簡単に生成できるので、あらかじめ 4096 バイトのファイルを作る必要は無いと考えます。 そこで、 SilentC でベクタ・テーブルを書き込ませるプログラムを作成しました。
main(){ long *jump_table = 0x00013000; long table_size = 128; long hook_table = 0x00020000; long index; long *table_content; for (index = 0; index < table_size; index++) { if (jump_table[index] != -1) { PrStr("Jump Table not Erased\r\n"); return; } } table_content = MemoryAlloc(table_size * 4); for (index = 0; index < table_size; index++) { table_content[index] = hook_table + index * 6; } table_content[127] = 0x00013200; NvmWrite(jump_table+0xFFF00000, table_content, table_size * 4); MemoryFree(table_content); }
対応するベクタは、0から126の127種類です。 0x00020000 番地から6バイトずつ絶対番地 JMP 命令が並んでいるものとしてベクタを決めています。 また、ベクタ127だけは、 0x00013200 に分岐させて後述する別の用途で使用します。
00013000 0002 0000 dc.l hook_table+6*0 00013004 0002 0006 dc.l hook_table+6*1 00013008 0002 000C dc.l hook_table+6*2 0001300C 0002 0012 dc.l hook_table+6*3 : 000131F4 0002 02EE dc.l hook_table+6*125 000131F8 0002 02F4 dc.l hook_table+6*126 000131FC 0001 3200 dc.l 0x00013200
00013000 00 02 00 00 00 02 00 06 ........ 00013008 00 02 00 0c 00 02 00 12 ........ 00013010 00 02 00 18 00 02 00 1e ........ 00013018 00 02 00 24 00 02 00 2a ...$...* : 000131e0 00 02 02 d0 00 02 02 d6 ........ 000131e8 00 02 02 dc 00 02 02 e2 ........ 000131f0 00 02 02 e8 00 02 02 ee ........ 000131f8 00 02 02 f4 00 01 32 00 ......2.
ヘルプ表示機能
ベクタ・テーブルで消費したのは、512バイトです。 ユーザ・ドライバ領域は、 3.5k バイトも残っていますが、もともと固定して使うつもりでベクタ・テーブルを書いているので、プログラムを入れと本末転倒になってしまいます。 そこで、文字列形式のデータを入れておいて、その先頭アドレスをベクタ#127で返すようにしました。 プログラムは 0x00013200 から、データは 0x00013208 から入っています。
013200 203C 0001 3210 move.l #0x00013210,d0 013206 4E75 rts
プログラムは、こうなりました。
main(){ char *help_module = 0x00013200; long module_size = 0x00000E00; long program_size = 0x00000010; long content_size = module_size-program_size; char *help_file = "help.txt" long index; long fp; int *program; char *content; long actual_size; long addr; for (index = 0; index < module_size; index++) { if (help_module[index] != -1) { PrStr("Help module not Erased\r\n"); return; } } fp = OpenFile(help_file); if (fp == 0) { PrStr("Help file not found.\r\n"); return; } program = MemoryAlloc(program_size); content = MemoryAlloc(content_size); MemClear(program, program_size); MemClear(content, content_size); program[0] = 0x203c; // move.l #xx,d0 program[1] = help_module >> 16; program[2] = (help_module + program_size); program[3] = 0x4E75; // rts actual_size = ReadFile(fp, content, content_size-1); CloseFile(fp); actual_size = (actual_size + 4) & 0xFFFFFFFC; addr = help_module + 0xFFF00000; NvmWrite(addr, program, program_size); NvmWrite(addr + program_size, content, actual_size); MemoryFree(content); MemoryFree(program); }
文字列データ本体は、 "help.txt" というファイルに入れておいて書き込むようにしました。 ファイルのサイズが3576バイト以内に収まるように注意してください。 また、行末を "CR+LF" にするのもお忘れなく。 本当は、ネットワーク経由で送るようにすると、ファイル領域も喰わないし、もっと良いのでしょうね。
さて、文字列データの中身ですが、何を入れましょうか。 0x00000200 からの領域には、 SilentMoon オペレーティング・システムのシステム・コールへの入り口アドレスが記述されています。 ここでは、システム・コールのアドレス一覧を返すようにしてみました。 以下、実行後のメモリの内容です。
00013200 20 3c 00 01 32 10 4e 75 <..2.Nu 00013208 00 00 00 00 00 00 00 00 ........ 00013210 24 30 32 30 30 20 2d 20 $0200 - 00013218 4d 65 6d 6f 72 79 41 6c MemoryAl : 00013290 6d 65 72 0d 0a 24 30 32 mer..$02 00013298 31 43 20 2d 20 47 65 74 1C - Get 000132a0 54 69 6d 65 72 43 6f 75 TimerCou 000132a8 6e 74 0d 0a 00 00 00 00 nt...... 000132b0 ff ff ff ff ff ff ff ff ........
4バイト単位で必要なサイズだけ書き込んであります。
さあ、使ってみよう
早速、使ってみようと思いましたが、まだベクタ・テーブルを定義しただけで、肝心の中身がありません。 動くのは、ベクタ#127だけですね。
OK PrStr(UserDriver(127)) $0200 - MemoryAlloc $0204 - BufCopy $0208 - MemClear $020C - MemoryFree $0210 - SystemSleep $0214 - Sleep $0218 - CreateTimer $021C - GetTimerCount OK
ヘルプ・テキストは、まだ未完成です。
ベクタ・テーブルを書き換えたくなったら
このプログラムは、ユーザ・ドライバ領域が消去された状態であることを確認して、書き込み作業を行っています。 そのため、ユーザ・ドライバ領域を書き換える時にはあらかじめ消去する必要があります。 消去するためには、こんな命令を使います。
NvmErase(0xFFF13000); NvmErase(0xFFF13800);
プログラムに入れてしまっても良いのだけれど、うっかり走ってしまう事態を考えるとちょっと怖いので入れていません。 くれぐれもタイプミスにはご注意を。
参考文献
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
これも
Interface (インターフェース) 2008年 12月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/10/25
- メディア: 雑誌
>ここでは、システム・コールのアドレス一覧を返すようにしてみました。
そ、その情報は・・・・!
by 某氏 (2008-10-24 01:52)