#概要
athrill(アスリル)は,PC上で組み込み系のプログラムを手軽にデバッグできるようにしたCPUエミュレータです.これまでのathrillの進化状況は,シングルコア⇒マルチコアまででした.
今回,ようやくメモリ保護対応できましたので,その一端をご紹介をします.
※メモリ保護対応athrillの名前は,マルチコア対応と同じで athrill2 としています.
#動作環境
athrill2の動作環境は従来通りです.
また,athrill2 のメモリ保護機能は,v850e2m をベースに作成しています.
#ダウンロード/インストール方法
従来通り athrill2 をダウンロード/インストールするだけですので,特別な作業は不要です.
#事前準備
メモリ保護の動作確認ができるように,デモプログラムを athrill 開発プロジェクト で公開しています.
サンプル・バイナリの配置場所は,
" athrill/sample/athrill2/mputest/build/mputest.elf"
です.
#サンプルプログラムのメモリレイアウト
サンプルプログラムのメモリレイアウトは以下のとおりで,カーネル用※とユーザ用の領域を用意しました.
※カーネル用のメモリ領域は CPU が特権モードでしかアクセスできません.
メモリ種別 | アドレス | サイズ(KB) | メモリ保護 |
---|---|---|---|
ROM | 0x00000000 | 512 | あり(カーネル用) |
RAM | 0x06000000 | 512 | あり(カーネル用) |
ROM | 0x00100000 | 512 | なし(ユーザ用) |
RAM | 0x07000000 | 512 | なし(ユーザ用) |
#サンプルプログラム構成
サンプルプログラムは,大きく分けて以下の2つに分類しています.
分類 | プログラム | 配置フォルダ |
---|---|---|
カーネル | 特権モードでしか実行できないプログラム | kernelフォルダ |
ユーザ | 非特権モードで実行するプログラム | userフォルダ |
ユーザ側のプログラムは,非特権モードで動作しますから,カーネルのプログラムへのアクセスはハードウェアレベル(仮想マシン)で禁止されています.
そのため,ユーザ側のプログラムがカーネル側のサービス関数を呼び出したいときは,v850e2mの特別な命令syscallを使用しなければなりません.
今回のサンプルプログラムは,3つのサービス関数を定義して,ユーザ側のプログラムから呼び出しています(user/user_task.c).svc_xxx()関数がサービスコール関数です.
void user_task(void)
{
SrvUint32 data;
ServiceReturnType ret;
ret = svc_set_data(0, 324);
if (ret == SERVICE_E_OK) {
(void)svc_get_data(0, &data);
}
svc_printf("Hello User World!!\n");
while (1) {
;
}
return;
}
svc_xxx()関数の実体は以下のようにアセンブラで定義しています(kernel/svc_asm.S).
.section ".text_user" , "ax"
.align 4
.globl _svc_call_get_data
.type _svc_call_get_data, @function
_svc_call_get_data:
syscall 0
jmp [lp]
.size _svc_call_get_data, .-_svc_call_get_data
#デモ
それでは,早速デバッグしてみましょう.
##起動
デモ用バイナリを athrill2 で起動してみましょう.
$ athrill2 -c1 -m memory.txt -d device_config.txt -i mputest.elf
※-c オプションはコア数の指定です.今回はシングルコアですので1を指定します.
※マルチコアでのメモリ保護はまだ動作確認できていません.
##ユーザプログラムのデバッグ
ユーザプログラムの先頭(user_task())でブレークし,CPU情報を参照してみましょう.
###ブレーク設定
b user_task
break user_task 0x100000
###プログラム実行
プログラムを実行すると,最初にカーネル側の初期化プログラムが実行されます.
初期化成功すると,"Hello Kernel World!!"というメッセージが出力された後,
ユーザ側のプログラムに処理が移り,user_task()関数の先頭でブレークされます.
[DBG>c
[CPU>Hello Kernel World!!
HIT break:0x100000 user_task(+0x0)
[NEXT> pc=0x100000 user_task.c 8
###CPU状態参照
ユーザ側のプログラムに入った直後のCPU状態を参照してみましょう.
cpu
***CPU<0>***
PC 0x100000 user_task(+0x0)
R0 0x0
:
PSW 0xf0000
:
PSWの上位ビットが0xfになっています.これは19,18,17,16ビットがすべて1であることを示しております.これらのビットが全て1の場合は,非特権モードであると言えます.
※このCPU状態で,メモリ保護された領域へのアクセスを実行するとCPU例外が発生します.
###サービスコールを実行
このまま引き続きsyscall命令を実行するところまでデバッグを進めましょう.
[NEXT> pc=0x100090 svc_asm.S 181
[DBG>n
[DONE> core0 pc=0x100090 svc_call_get_data(+0) 0x100090: SYSCALL vector8=0 addr=0x1000c0:0x1000cc
[NEXT> pc=0x1000cc svc_asm.S 12
上記は,syscall命令を実行したときのログ情報です.
syscall命令を実行した直後,プログラムの実行位置が急に変化していることがわかります.
※以下の12行目のところにプログラムカウンタが移動しています.
4 .section .text , "ax"
5 .align 4
6 .globl _svc_table
7 .type _svc_table, @function
8 _svc_table:
9 .word (12) /* get_data */
10 .word (8) /* set_data */
11 .word (4) /* printf */
12 jr _svc_exception ★CPUが移動した場所
さらに,このときのCPU状態を見てみましょう.
PSW 0x60
PSWの上位ビットが0xfが消えていますよね.これは19,18,17,16ビットがすべて0であることを示しており,CPUが特権モードに切り替わったことを示しています.
この状態ですと,カーネル側のプログラムにアクセスできるようになりますので,
カーネルのサービス関数を実行できるようになったわけです.
ちなみに,sycall命令を使わずに直接カーネルのサービス関数を呼び出すと以下のように
CPU例外が発生します.
[CPU>Hello Kernel World!!
ERROR:no permission: access_addr=0xf1e access_end=0xf1f config_addr=0x0 config_end=0xfffff
Exception happened!!
#今後の展開
メモリ保護対応したathrill2は,まだできたてのホヤホヤですので,まだ品質は不安定と考えています.今後,TOPPERS/HRP2カーネル移植作業を通して,品質を安定させていきたいと考えております.
#関連記事
- athrill(アスリル) を使用して TOPPERS OS(ASP3) をデバッグ
- マルチコア対応仮想環境(athrill)を使用して TOPPERS/ATK2 を実行する
- 今さらなぜCPUエミュレータを自作しようとおもったのか?
- athrill(アスリル)を使用してC言語ポインタ変数を理解する
- athrill(アスリル)機能マニュアル
- athrill(アスリル) を使用してベアメタル・プログラミング(1回目:main関数が動き出すまで)
- athrill(アスリル) を使用してベアメタル・プログラミング(2回目:割り込みがソフトウェアに通知されるまで)
- TOPPERS/ATK2カーネル向け実機レス環境(athrill2)