So-net無料ブログ作成
検索選択

ユーザ・ドライバ領域にベクタを書き込む [ColdFire V2]このエントリーを含むはてなブックマーク#

1990557

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月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

これも

Interface (インターフェース) 2008年 12月号 [雑誌]

Interface (インターフェース) 2008年 12月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/10/25
  • メディア: 雑誌

nice!(0)  コメント(1)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 1

某氏

>ここでは、システム・コールのアドレス一覧を返すようにしてみました。

そ、その情報は・・・・!
by 某氏 (2008-10-24 01:52) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この記事のトラックバックURL:
※言及リンクのないトラックバックは受信されません。