RISC-VでLinuxを動かすためのレジスタ制御

RISC-Vのシステムレジスタ

前回は、RISC-Vを学ぶにあたり最も基本となる命令セットについて紹介しました。

RISC-Vには、基本となる命令セットに加えてシステムレジスタも定義されています。RISC-Vでオペレーティングシステムを動作させたり、アプリケーションを開発するためには、このシステムレジスタについて理解する必要があるでしょう。例えば、特権命令はどのような構成になっているのか?割り込みや例外はどのように処理すればよいのか?今回は、これらのシステムレジスタやRISC-Vの動作モードなどについて見ていきます。

ちなみに、これらのシステムレジスタ・動作モードについて最新の仕様は、RISC-V Privileged Specification 1.10 で見ることが出来ます。もっと詳細を学びたいと思った方は、以下の資料を見てみることをお勧めします。

RISC-V Privileged ISA Specification

オペレーティングシステムを動作させるために~RISC-Vの動作モードと制御レジスタ~

通常のCPUには、オペレーティングシステムを動作させたり、セキュリティ上CPU上で動作するアプリケーションを分離したりなどのためにさまざまな動作モードあります。動作モードは、もちろんRISC-Vにも定義されています。RISC-Vには以下の動作モードがあります。

  • ユーザモード(User Mode)
  • スーパバイザーモード(Supervisor Mode)
  • マシンモード(Machine Mode)

これらのモードについてはだいたい意味が分かると思います。マシンモードは、全てのシステムレジスタにアクセスできるモードです。スーパバイザモードは、オペレーティングシステムを動作させるためのモード、ユーザモードは、ユーザアプリケーションを動作させるためのモードです。それぞれのモードで、アクセスできるシステムレジスタや、実行できる特権命令が異なります。

ユーザモード中でプログラムを実行中に例外が発生すると、基本的にはマシンモードに状態が遷移され、処理が行われると考えてよいでしょう(ただし後述するように例外・割り込みの委譲レジスタにより、例外・割込みハンドラをマシンモード以外の動作モードに委譲することができます)。

現在RISC-Vチップがどのモードで動作しているかは、以下のようにエンコーディングされます(ちなみに、Level-2としてかつてはハイパーバイザーモードも定義されていましたが、これは仕様の策定が進まずに削除されてしまいました。ですが、いつかは復活することでしょう)。

【表1:RISC-Vの動作モード】
レベル エンコーディング 名前 略称
0 00 ユーザ・アプリケーションモード U
1 01 スーパバイザーモード S
2 10 予約
3 11 マシンモード M

RISC-VのCPU実装としては、基本的にはマシンモードを備えていれば良いとされています(これは最もシンプルな構成)。

あるいは、ユーザモードとマシンモードをサポートした構成や、ユーザモード・スーパバイザモード・マシンモードのすべてを搭載する実装が許されています。

制御&状態レジスタについて

次に、RISC-Vの制御レジスタについて見ていきましょう。

RISC-Vの制御レジスタは、CSR(Control and Status Register)と呼ばれています。CSRは動作モードに応じて定義されています。

制御レジスタとしては、最も基本となるCPUの状態を示すためのレジスタや、割り込み・例外を管理するためのレジスタ、仮想メモリの設定を行うためのレジスタ、さらにタイマやカウンタを制御するためのレジスタなど、CPUとしての一通りの機能を実現するためのレジスタが定義されています。

CSRにアクセスするためには、専用のシステムレジスタ転送命令を利用します。オペレーティングシステムを実装したり、タイマなどの機能にアクセスするためには、このシステムレジスタ転送命令を理解しなければなりません。

まず、CSRには12ビットのアドレスが付与されています。このアドレスによりアクセスするCSRが決まります。

例えば、マシンモードのCSRの一部を抜粋してみました。以下はRead-onlyなCSRです。

【表2:RISC-VのCSRの一部(Read-onlyなCSR)】
CSRアドレス 名前 説明
0xF11 mvendorid ベンダID
0xF12 marchid アーキテクチャID
0xF13 mimpid 実装ID
0xF14 mhartid ハードウェアスレッドID

Read/Write可能なCSRは例えば以下のようなものが定義されています。

【表3:RISC-VのCSRの一部(Read/Write可能なCSR)】
CSRアドレス 名前 説明
0x300 mstatus マシン状態レジスタ
0x301 misa ISAと拡張情報レジスタ
0x302 medeleg マシン例外の委譲レジスタ
0x303 mideleg マシン割り込みの委譲レジスタ
0x304 mie マシンの割り込み許可レジスタ
0x305 mtvec マシンのトラップハンドリングのベースレジスタ
0x306 mcounteren マシンのカウンタEnableレジスタ

これらのシステムレジスタの詳細については、最初に紹介した "RISC-V Privileged Instruction Manual Ver.1.10" を参照してください。

CSRにアクセスするための転送命令

では、CSRにアクセスするためにはどうすれば良いのでしょうか。これには、CSR転送のための専用命令を使います。CSR転送命令は、以下の6命令が定義されています。

  • CSRRW / CSRRWI(CSR Read / Write): CSRと汎用レジスタのアトミック交換
  • CSRRS / CSRRSI(CSR Read / Bit Set): CSRの読み込みとビットセット
  • CSRRC / CSRRCI(CSR Read / Bit Clear): CSRの読み込みとビットクリア

まず、CSRRW命令は汎用レジスタとCSRの値を交換します。

csrrw x2、csr_addr、x1csr_addrで指定されるCSRの値をx2レジスタに書き込み、x1レジスタの値をCSRに書き込みます。これはアトミックに行われます。これで、プログラムはCSRの値を取得し、CSRに値を書き込むことが出来ます。

これ以外にもあります。CSRRSはCSRの特定のビットに1を設定します。つまりRSのSは"Set"の意味ですね(予想ですが)。csrrs x2、csr_addr、x1csr_addrで指定されるCSRの値をx2レジスタに書き込み、CSRのビットのうち、x1レジスタの1が立っているビットを1に設定します。

CSRRCはその逆です。csrrc x2、csr_addr、x1と書くと、CSRのビットのうちx1レジスタの1が立っているビットを0にクリアします。

さらにこのCSRの設定・クリアレジスタには汎用レジスタの変わりに即値を取る命令も用意されています(csrrwi、csrrsi、csrrci命令)。

この命令の即値フィールドは5ビットしかありません。従って、このCSR即値命令ではCSRビットのうち下位の5ビットしか設定することが出来ません。

少し不便と言えば不便ですが、CSRの重要なビットは下位に固められているため、この即値命令も十分に活用することが出来る、という発想のようです。

さらに、RISC-Vのアセンブリコードを読むためには、以下の擬似アセンブリコードも理解しておくと良いでしょう(これらの疑似アセンブリコードは、逆アセンブルのためのobjdumpコマンドの出力にも出てくるため、理解しておくと良いです)。

【表4:CSRに関連する疑似アセンブリコード】
擬似コード オリジナルの命令 説明
csrr rd、csr csrrs rd、csr、x0 CSR読み込み(CSRの内容は更新しません)
csrw csr、rs csrrw x0、csr、rs CSR書き込み(汎用レジスタは更新しません)
csrs csr、rs csrrs x0、csr、rs CSRのビット設定(汎用レジスタは更新しません)
csrc csr、rs csrrc x0、csr、rs CSRのビットクリア(汎用レジスタは更新しません)
csrwi csr、imm csrrwi x0、csr、imm CSRの即値書き込み(汎用レジスタは更新しません)
csrsi csr、imm csrrsi x0、csr、imm CSRの即値ビット設定(汎用レジスタは更新しません)
csrci csr、imm csrrci x0、csr、imm CSRの即値ビットクリア(汎用レジスタは更新しません)

CSRの役目を理解するための用語

CSRの仕様書を読み進めていくと、レジスタフィールドの意味を示す用語がいくつも出てきます。

CSRには、Read-onlyなフィールド、Rea-Writeはできるがいくつか制限があるフィールドなど、フィールドの特性に応じてその特性を現す用語が付けられています。

この用語は忘れやすいので、一旦まとめておくのが良いでしょう。

Reserved Writes Ignored Read Ignore Value(WIRI)

Read-onlyなフィールドです。このフィールドに書き込んでも何の効果もありません。ただし、CSR全体がWIRIの場合、そのレジスタに書き込みを行うと例外が発生するので注意が必要です。

Reserved Write Preserve Values、Read Ignore Values(WPRI)

将来のために予約されているフィールドです。このフィールドに書き込んでも、何の効果もないですし、常に固定値が読みだされます。

Write/Read Only Legal Values(WLRL)

読み書き可能なフィールドです。書き込む場合は、意味のある値を書き込む必要があります。もし意味のない(例えば範囲外のような)値を書き込んだ場合、その後の正常な動作は保証されません。

Write Any Values、Read Legal Values(WARL)

読み書き可能なフィールドです。書き込む場合には、意味のない値を書き込んだときには、意味のある値がキープされます。

主要なCSRの紹介

次に、RISC-Vのアプリケーションを作成したり、オペレーティングシステムを動作させるために必要な主要なCSRについて紹介します。

mstatus レジスタ

mstatusレジスタは全てのRISC-V実装に搭載されているべきレジスタで、CPUの現在の状態を示しているレジスタです。

サブセットとしてsstatusレジスタおよびustatusレジスタがあり、sstatusの場合はスーパバイザモードで、ustatusレジスタはユーザモードで、mstatusレジスタの一部にアクセスすることが出来ます。

RV32(32-bit版の実装)とRV64(64-bit版の実装)で、mstatusの内部のビットフィールドは異なります。それぞれのモードで、mstatusレジスタは以下のように構成されています。

図1:mstatusレジスタの詳細。RISC-V Privileged Instruction Set Manual 1.10より抜粋図1:mstatusレジスタの詳細。RISC-V Privileged Instruction Set Manual 1.10より抜粋

重要なものだけ引っ張り出していきましょう。

MIE、SIE、UIEビットは、マシンモード・スーパーバイザーモード・ユーザモードでの割り込み許可を示すビットです。

また、MPIE、SPIE、UPIEビットはトラップにより割り込みが発生したときに、トラップに入る前のMIE、SIE、UIEビットの値を保持しています。

また、MPP、SPP ビットは、トラップにより割り込みが発生したときに、トラップに入る前の動作モードの状態を保持しています。

RISC-Vには、割り込み応答性を向上させるために上記のような、トラップ発生前の状態を保持しておくビットがいくつもあります。

これらのビットは、MRET / SRET / URET 命令によって元のビット位置に書き戻されます。

これによりトラップが発生しても現在の状態を保持するために多くの命令を実行する必要が無く、割り込み応答性を向上させることが出来ると考えられます。

高速な割り込み動作を実現するためのCSR(mideleg、medeleg)

RISC-Vには、実装に応じて複数の動作モードを持つことが出来ますが、例えばユーザモード中に例外が発生し、その割り込み処理をスーパバイザーモードで処理する場合はどのようにすればよいのでしょうか。

例外が発生すると、CPUの動作モードはマシンモードに遷移します。

その後、例外の種類を特定してどの例外であればどの動作モードで処理を行うか決めて、例外処理ルーチンにジャンプするわけですが、

RISC-VのCSRには、「一旦マシンモードに移ってから、別の動作モードに移動する」という処理を省略することができるCSRが存在します。

日本語では「委譲」の意味を持つ"delegation" の名前が付けられているmideleg/medelegCSRです。このレジスタに値を設定することにより、通常はマシンモードで受け付けられる割り込み・例外を、スーパバイザモードやユーザモードに委譲することができます。マシンモード・スーパバイザモード・ユーザモードのすべてをサポートしており、ユーザモードで割り込み・例外をサポートすることができる実装の場合は、mideleg/medelgレジスタで以上された処理をさらにsideleg/sedelegレジスタを使ってさらにユーザモードにまで処理を移譲することができます。

  • 割り込み動作を移譲しない場合の動作。いったんマシンモードで割り込みを受け取り、割り込みコードを判定してスーパバイザモードに移行する。
  • 割り込み動作を移譲する場合。マシンモードで受け取る際に移譲レジスタを読み取り、発生した割り込みに相当するビットが立っている場合、すぐにスーパバイザモードに移行する。

図mideleg/medelegの効果。マシンモードから別の動作モードに委譲することにより、割り込み応答性を向上させることができる。

mideleg/medelegの詳細は省略しますが、このCSRのビットフィールドは、RISC-Vで規定されたエンコーディングによって指定するビット位置が決められます。

【表5:RISC-Vの割り込みコード】
割り込みコード
0 ユーザソフトウェア割り込み
1 スーパバイザソフトウェア割り込み
2 予約
3 マシンソフトウェア割り込み
4 ユーザタイマ割り込み
5 スーパバイザタイマ割り込み
6 予約
7 マシンタイマ割り込み
8 ユーザ外部割込み
9 スーパバイザ外部割込み
10 予約
11 マシン外部割込み
>=12 予約
【表6:RISC-Vの例外コード】
例外コード
0 命令アドレスミスアライン例外
1 命令アクセス例外
2 不定命令例外
3 ブレークポイント例外
4 ロードアドレスミスアライン例外
5 ロードアクセス例外
6 ストア/アトミックアクセスミスアライン例外
7 ストア/アトミックアクセス例外
8 ユーザモードからのEnvironment Call
9 スーパバイザモードからのEnvironment Call
10 予約
11 マシンモードからのEnvironmental Call
12 ページアクセス例外(命令フェッチ)
13 ページアクセス例外(ロード)
14 予約
15 ページアクセス例外(ストア・アトミック)
>= 16 予約

割り込みや例外を扱うためのCSR

当然ですが、RISC-Vでは割り込みや例外を扱うことができます。割り込み・例外の制御を行うために、いくつかのCSRが用意されています。

トラップベースアドレスレジスタ(mtvec / stvec)

割り込み・例外が発生した場合にジャンプするPCを格納しておきます。

例外プログラムカウンタレジスタ(mepc / sepc)

例外が発生した命令が格納されているプログラムカウンタを格納しています。

例外要因レジスタ(mcause / scause)

割り込み・例外が発生した要因を格納しています。表5, 表6 に基づく割り込み・例外コードが格納されます。

トラップ値レジスタ(mtval / stval)

例外の情報を格納します。このレジスタに書き込まれる値は、発生する例外の種類に応じて異なります。例えば、不貞命令例外の場合は、その例外を発生させた命令自体を格納しますが、それ以外にメモリアクセス時に例外が発生した場合、例外が発生した実効アドレスの値が格納されます(mepcは例外が発生した命令のPCアドレスを格納しているので、これとは異なります)。

RISC-Vの関数呼び出し規約

最後に、RISC-Vの関数呼び出しの規約についてざっと見ておきます。

関数呼び出しの規約というのは、C言語などで関数を呼び出すときに、引数や戻り値の渡し方、レジスタの値は関数の呼び出し側と呼び出し元のどちらが保存するか、などといったことが規定されています。

【表7:整数レジスタの関数呼び出し規約】
ABI名 意味 保存の責任者
x0 zero ゼロ固定
x1 ra リターンアドレス 呼び出し側
x2 sp スタックポインタ 関数側
x3 gp グローバルポインタ
x4 tp スレッドポインタ スレッドポインタ
x5 t0 一時レジスタ・リンクレジスタ 呼び出し側
x6-x7 t1-t2 一時レジスタ 呼び出し側
x8 s0/fp 保存レジスタ・フレームポインタ 関数側
x9 s1 保存レジスタ 関数側
x10-x11 a0-a1 引数・戻り値レジスタ 呼び出し側
x12-x17 a2-a7 引数レジスタ 呼び出し側
x18-x27 s2-s11 保存レジスタ 関数側
x28-x31 t3-t6 一時レジスタ 呼び出し側
【表8:浮動小数点レジスタ】
ABI名 意味 保存の責任者
f0-f7 ft0-ft7 浮動小数点一時レジスタ 呼び出し側
f8-f9 fs0-fs1 浮動小数点保存レジスタ 関数側
f10-f11 fa0-fa1 浮動小数点引数・戻り値レジスタ 呼び出し側
f12-f17 fa2-fa7 浮動小数点引数 呼び出し側
f18-f27 fs2-fs11 浮動小数点保存レジスタ 関数側
f28-f31 ft8-ft11 浮動小数点一時レジスタ 呼び出し側

以上、駆け足ですが、RISC-Vのシステムレジスタや割り込み・例外・ABIについて取り上げました。

これらはRISC-Vの仕様の一部分にすぎません。繰り返しになりますが、より詳細な仕様を学びたければ、RISC-V Privileged Instruction Manual を参照することをお勧めします。

RISC-V Privileged ISA Specification

前の記事を読む