TOPPERS/ASPをRustから使う(タスク・ハンドラの定義、カーネルとのリンク)

# はじめに

[前回](https://qiita.com/s_meika/items/3621ec9027ebc5f64218)、表示系を作った。
まずはタスクなどの実行単位を定義していく。
前回のスクリーンショットはこの作業が終わったあとのもの。

sample1では以下の実行単位を使用している。

- タスク
- タスク例外
- 周期ハンドラ
- アラームハンドラ
- CPU例外

それ以外には以下があるが、sample1アプリケーションでは使用していない。
とはいえ、今回紹介する内容さえわかればさして難しくはないはず。

- 割込みハンドラ
- ISR
- 初期化/終了ハンドラ

# タスク

並列実行される基本単位。C言語では以下で表される。

```C
void task(intptr_t exinf);
```

intptr_tはC99で導入された、整数型とポインタを格納できるサイズを持つ型である。
（TOPPERS/ASPのカーネルはC89でも動くが、型はC99のものを使っている※ベースのITRON4.0仕様とは異なる）

この型はRustでも定義されているが、`i64`で定義されている。
残念ながらターゲットに依存して変わる定義ではないようなので使えない。
※target_pointer_widthなるfeatureがあることが書いていてわかったのでそのうち対応

よって、タスク引数はCoretx-M4Fのbit長である`i32`にする。

関数名は、C言語とリンクするために`extern "C"`をつける。
またマングリングがあるとNGなので、防止のためのアトリビュートもつける。

main_taskには、起動したことを表示するためにsyslogを入れておく。

```rust
#[no_mangle]
#[allow(unreachable_code)]
extern "C" fn task(exinf: i32) {
    body;
}

#[no_mangle]
#[allow(unreachable_code)]
extern "C" fn main_task(exinf: i32) {

    toppers_syssvc_syslog!(LOG_NOTICE, "Sample program starts (exinf = %d).", exinf as u32);

    body;
}

```

task関数は無限ループが中に存在していることから未到達コードへの警告が検出されるため、`#[allow(unreachable_code)]`もつけておく。普通に終了するタスクでは不要である。

#タスク例外

C言語では以下で表される。

```C
typedef	uint_t		TEXPTN;		/* タスク例外要因のビットパターン */
void tex_routine(TEXPTN texptn, intptr_t exinf);
```

TEXPTNもターゲット依存の型なのだが、カーネル側で定義するものなので別途ファイルを作って（今はstddef.rsとしている)以下のように定義した。命名規則はRustのそれに合わせている。

```rust
pub type TexPtn = u32;
```

intptr_tは先と同じなので、

```rust
#[no_mangle]
extern "C" fn tex_routine(texptn: TexPtn, exinf: i32) {
    body;
}
```
となる。

# 周期ハンドラ、アラームハンドラ

2つとも同じ規則のI/Fであり、C言語では以下の通り。

```C
void cyclic_handler(intptr_t exinf);
void alarm_handler(intptr_t exinf);
```

sample11のこれらのハンドラでは、exinfは使わないので、未使用であることを示す`_`をつける。

```rust
#[no_mangle]
extern "C" fn cyclic_handler(_exinf: u32) {
    :
}

#[no_mangle]
extern "C" fn alarm_handler(_exinf: u32) {
    :
}
```

# CPU例外ハンドラ

C言語では以下の通り。ターゲット依存の情報を扱うため、voidポインタを使う。

```c
void cpuexc_handler(void *p_excinf);
```
このポインタにはCPU例外発生時のシステム状態が入っており、`xsns_xpn/xsns_dpn`に渡して使用する。中の構造はアプリケーションにはわからない。FILE*みたいなイメージ。

voidポインタをRustで使うのは`c_void`モジュールを使う。
モジュール宣言をしておく。

```Rust
use core::ffi::c_void;
```

c_void = voidなので、引数としてはvoidへの参照の形ととって、以下のようになる。

```Rust
#[no_mangle]
extern "C" fn cpuexc_handler(p_excinf: &c_void) {
    body;
}
```

# TOPPERS/ASPとリンクする
## TOPPERS/ASP側のライブラリ化

TOPPERS/ASPはそれなりの規模の大きさなのでいくつかの領域に分割されている。

- カーネル側
    - カーネルライブラリであるlibkernel.a
    - システムサービス群であるオブジェクトファイル群(*.o)
- アプリケーション側
    - アプリ
    - コンフィギュレーションファイル(*.cfg -> *.c -> *.o)

上で作ってきたのはアプリであり、その他の部分をリンクする必要がある。

[一度C言語環境でsample1を作っておく](https://qiita.com/s_meika/items/7fb359e9f183ae06023f)。

RustはC言語で作成したバイナリをリンクできるが、調べた限り.oを直接Rustコンパイラからリンクする術がわからない。そのため、いったん`*.oを.aに`まとめる(Makefileを適当に編集したが、直接タイプしてもいいだろう）。

```sh
arm-none-eabi-ar -rcs libsyssvc.a   target_serial.o  banner.o syslog.o serial.o logtask.o  log_output.o vasyslog.o t_perror.o strerror.o
arm-none-eabi-ranlib libsyssvc.a
rm -rf libcfg.a
arm-none-eabi-ar -rc libcfg.a kernel_cfg.o 
arm-none-eabi-ranlib libcfg.a
```

作ったライブラリはRustのディレクトリにコピーしておく。

## Rust側でリンクするライブラリを指定する

適当な.rsに以下を記述する。ソース本体とは分けたほうがいいだろう。
以下の記述はldの`-l`スイッチにあたる。

```rust
#[link(name = "syssvc", kind = "static")]
#[link(name = "kernel", kind = "static")]
#[link(name = "cfg", kind = "static")]
extern "C"{

}
```

今回はアプリとライブラリ層を階層ワケしているので、build.rsを作ってライブラリのパスを指定した。
カーネルそのものとコンフィギュレーションファイルも別のディレクトリにしておいた。
`rustc-link-search`はldコマンドの`-l`スイッチに相当する・

```rust
use std::env::var;

fn main() {
    let manifest_dir = var("CARGO_MANIFEST_DIR").unwrap();
    println!("cargo:rustc-link-search={}/src/toppers", manifest_dir);
    println!("cargo:rustc-link-search={}/src/toppers_cfg", manifest_dir);    
}
```

## リンカスクリプトの指定

C言語環境側から、リンカスクリプトをコピーして、`.cargo/config`で指定しておく。
このあたりは同じリンカへのスイッチなのに書き先が違ってややこしい ~~全部configでいいのに~~ 。

```
[build]
target = "thumbv7em-none-eabihf"

[target.thumbv7em-none-eabihf]
runner = "hf2 elf"
rustflags = [
  "-C", "link-arg=-Tsamd51.ld",
]
```

# まとめ

C言語インターフェース周りは特に難しくない。
苦労したのはリンカスイッチ周りだろうか。

現状ビルド手順が手で操作しているので、動作確認が終わればここの自動化が必要だと思っている。
幸い、cmakeがbuild.rsが呼び出せるとのことなので、どうにかなるだろう。