LoginSignup
2
0

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-07-09

概要

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カーネル移植作業を通して,品質を安定させていきたいと考えております.

関連記事

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0