メモリ保護対応版 athrill(アスリル) のご紹介

#概要
athrill(アスリル)は，PC上で組み込み系のプログラムを手軽にデバッグできるようにしたCPUエミュレータです．これまでのathrillの進化状況は，シングルコア⇒[マルチコア](https://qiita.com/kanetugu2018/items/b43c5715124f42a0393d)まででした．

今回，ようやくメモリ保護対応できましたので，その一端をご紹介をします．
※メモリ保護対応athrillの名前は，マルチコア対応と同じで athrill2 としています．

#動作環境
athrill2の動作環境は[従来通り](https://qiita.com/kanetugu2018/items/1f2ef93c9e1fa7a29f97)です．

また，athrill2 のメモリ保護機能は，v850e2m をベースに作成しています．

#ダウンロード/インストール方法
従来通り [athrill2](https://qiita.com/kanetugu2018/items/1f2ef93c9e1fa7a29f97#%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89%E6%96%B9%E6%B3%95) をダウンロード/インストールするだけですので，特別な作業は不要です．

#事前準備
メモリ保護の動作確認ができるように，デモプログラムを [athrill 開発プロジェクト](https://github.com/tmori/athrill/tree/master/sample/athrill2/mputest) で公開しています．

サンプル・バイナリの配置場所は，
　" athrill/sample/athrill2/mputest/build/mputest.elf"
です．


#サンプルプログラムのメモリレイアウト

サンプルプログラムのメモリレイアウトは以下のとおりで，カーネル用※とユーザ用の領域を用意しました．

※カーネル用のメモリ領域は CPU が特権モードでしかアクセスできません．

|メモリ種別|アドレス|サイズ（KB)|メモリ保護|
|---------|-------|----------|---------|
|ROM|0x00000000|512|あり(カーネル用)|
|RAM|0x06000000|512|あり(カーネル用)|
|ROM|0x00100000|512|なし(ユーザ用)|
|RAM|0x07000000|512|なし(ユーザ用)|

#サンプルプログラム構成
サンプルプログラムは，大きく分けて以下の２つに分類しています．

|分類|プログラム|配置フォルダ|
|---------|-------|----------|
|カーネル|特権モードでしか実行できないプログラム|kernelフォルダ|
|ユーザ|非特権モードで実行するプログラム|userフォルダ|

ユーザ側のプログラムは，非特権モードで動作しますから，カーネルのプログラムへのアクセスはハードウェアレベル(仮想マシン)で禁止されています．

そのため，ユーザ側のプログラムがカーネル側のサービス関数を呼び出したいときは，v850e2mの特別な命令syscallを使用しなければなりません．

今回のサンプルプログラムは，３つのサービス関数を定義して，ユーザ側のプログラムから呼び出しています(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カーネル](https://www.toppers.jp/hrp2-kernel.html)移植作業を通して，品質を安定させていきたいと考えております．


#関連記事

* [athrill(アスリル) を使用して TOPPERS OS(ASP3) をデバッグ](https://qiita.com/kanetugu2018/items/1f2ef93c9e1fa7a29f97)
* [マルチコア対応仮想環境(athrill)を使用して TOPPERS/ATK2 を実行する](https://qiita.com/kanetugu2018/items/b43c5715124f42a0393d)
* [今さらなぜCPUエミュレータを自作しようとおもったのか？](https://qiita.com/kanetugu2018/items/d692e612c3d4d715c0ad)
* [athrill(アスリル)を使用してC言語ポインタ変数を理解する](https://qiita.com/kanetugu2018/items/b9ad84c2f74324174864)
* [athrill(アスリル)機能マニュアル](https://qiita.com/kanetugu2018/items/cf3dea16710a3f0737e8)
* [athrill(アスリル) を使用してベアメタル・プログラミング(１回目：main関数が動き出すまで)](https://qiita.com/kanetugu2018/items/7d2ce8def53cb9bda06b)
* [athrill(アスリル) を使用してベアメタル・プログラミング(2回目：割り込みがソフトウェアに通知されるまで)](https://qiita.com/kanetugu2018/items/8cb411717511ca96bc64)
* [TOPPERS/ATK2カーネル向け実機レス環境(athrill2)](https://qiita.com/kanetugu2018/items/75dadc340f3db2a344ab)