トップ «前の日記(2003年05月18日) 最新 次の日記(2003年05月20日)» 編集
2003|01|02|03|04|05|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|10|12|
2009|02|03|06|07|10|11|12|
2010|01|02|03|04|07|09|10|11|12|
2011|01|03|04|05|06|07|08|10|
2012|01|06|08|09|10|12|
2013|01|02|03|04|07|09|11|12|
2014|01|03|04|05|06|09|
2015|04|
2016|01|08|
ここは旧えびめもです。えびめも2に移行します(2016/12/1)

2003年05月19日 晴れ

[CAT709]

TOPPERSという uITRON4.0仕様のRTOSを移植した。sample1.cが動作したゾ(^0^/~~~~~~~~~~。とりあえず画面ダンプ だ。
JSP Kernel Release 1.3 (patchlevel = 0) for CAT709(LinuxKoubou SH7709S Embedded Microcomputer) (May 20 2003, 02:09:43)
Copyright (C) 2000-2002 by Embedded and Real-Time Systems Laboratory
                            Toyohashi Univ. of Technology, JAPAN
・erial driver service starts on port 1.
System logging task is started on port 1.
Sample task starts (exinf = 0).
task1 is running (001).   |
task1 is running (002).   |
task1 is running (003).   |
task1 is running (004).   |
task1 is running (005).   |
task1 is running (006).   |
task1 is running (007).   |
task1 is running (008).   |
task1 is running (009).   |
task1 is running (010).   |
最初、コンパイルしたELFモジュールをPARTNER-Jを使ってRAMにロードして動作させて動かしていた。上手くいくようになったのでROM化してみたら全然動かなかった。あれこれ追いかけてみるとどうもグローバル変数を触る箇所で死ぬ。config/sh3/shelf.ld (リンカースクリプト)を見てみたら、なんだ!!! デフォルトではまったくROM化を考えていないじゃないか。全部のセクションが0番地から順番に配置されるようになっていた。.dataセクションも.bssセクションも全部ROMん中だ。これじゃ動くはずがない。

原因がわかっちゃえば修正はちょちょいだ。MEMORY{ } コマンドを使って >ROM と >RAMに配置するようにしたらROM化しても動くようになった。スタンドアロンで動いているぞ。

うーむ、TOPPERSすばらしい。CAT709でuITRON4.0が動くんだもんな。ちなみに各セクションのサイズは↓こんな感じ。

.text0x5e6a (約24Kbyte)
.rodata0x0cb0 (3248byte)
.data0x025c (604byte)
.bss0x90bc (約36Kbyte)
.bssセクションのサイズが大きい気がするが、これはきっとTCBやタスク用のスタック領域を含んでいるんだろう。という雰囲気が伝わってくる。

軽くソースを読んで、スタックの扱いを追ってみた。システム用のスタックは config/sh3/cat709/sys_config.h ファイルで

/*
 *   スタック領域の定義
 */
#define STACKTOP    0x0c400000    /* タスク独立部用スタックの初期値 */
としてスタックボトムを与え、伸びていく方向は知らんぷりのようだ。まだ良く見ていないが、このスタックはコンテキストの外の時のスタックなんだろうな。タスク毎のスタックはTCB構造体内部にSPの保存フィールドがあって最初のタスクディスパッチの際に初期化されるらしい。なお、タスク毎のスタック領域は コンフィギュレータが作成する kernel_cfg.c 内で
static VP __stack_TASK1[TCOUNT_VP(8192)];
static VP __stack_TASK2[TCOUNT_VP(8192)];
static VP __stack_TASK3[TCOUNT_VP(8192)];
static VP __stack_MAIN_TASK[TCOUNT_VP(8192)];
static VP __stack_LOGTASK[TCOUNT_VP(LOGTASK_STACK_SIZE)];
 
const TINIB tinib_table[TNUM_TSKID] = {
        {TA_HLNG, (VP_INT)(( VP_INT ) 1), task, INT_PRIORITY(10), TROUND_VP(8192), __stack_TASK1, TA_HLNG, tex_routine},
        {TA_HLNG, (VP_INT)(( VP_INT ) 2), task, INT_PRIORITY(10), TROUND_VP(8192), __stack_TASK2, TA_HLNG, tex_routine},
        {TA_HLNG, (VP_INT)(( VP_INT ) 3), task, INT_PRIORITY(10), TROUND_VP(8192), __stack_TASK3, TA_HLNG, tex_routine},
        {TA_HLNG | TA_ACT, (VP_INT)(0), main_task, INT_PRIORITY(5), TROUND_VP(8192), __stack_MAIN_TASK, TA_NULL, NULL},
        {TA_HLNG | TA_ACT, (VP_INT)(( VP_INT ) 1), logtask, INT_PRIORITY(LOGTASK_PRIORITY), TROUND_VP(LOGTASK_STACK_SIZE), __stack_LOGTASK, TA_NULL, NULL}
};
といった具合で8Kバイト用意されていた。スタック領域の実体は__stack_TASK1 グローバル変数だから.bssセクションに入ると思われる。実際、objdumpでELFをダンプしてみると
8c00025c l     O .bss   00002000 ___stack_TASK1
8c00225c l     O .bss   00002000 ___stack_TASK2
8c00425c l     O .bss   00002000 ___stack_TASK3
8c00625c l     O .bss   00002000 ___stack_MAIN_TASK
8c00825c l     O .bss   00000800 ___stack_LOGTASK
なるほど、TOPPERSわかってきたぞ。TCB(タスクコントロールブロック ... linux kernelで言えば task_strcutの事だ)内にSP保存メンバー変数があり、ここにコンテキストとして保存される。わかりやすい構成だ。linuxはここらへんが変則的になっていて、プロセスのSPをコンテキストに保存しないのだ。linuxは逆にタスクのスタック領域の中(スタックトップ)にtask_structを保存していて、SP相対でカレントプロセスの管理構造体にアクセスする仕組みになっている。SPを切り替えることがすなわちタスクディスパッチになっている。

時間を作って勉強をかねながらTOPPERSのスレッドで動作するlinuxローダーを作ってみるつもり。