14
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

aarch64でEL (Exception Level)を変更する

Last updated at Posted at 2018-05-19

aarch64でEL (Exception Level)を変更してみました。

あまり良く分かっていないのですが、aarch64でOSをブートするためにはExceptin Levelを変更する必要があります。

ELについて

EL : Exception Level 例外レベル
ARMv8では4つの例外レベルが定義されている。

EL 説明
EL0 アプリ
EL1 OS
EL2 ハイパーバイザ
EL3 セキュアモニタ

分かったこと

  • Aarch32の User modeがEL0
  • Aarch32のIRQ Mode, FIQ ModeがEL1
  • ELの数値が下がるほど、アクセス可能なシステムレジスタが少なくなる。
  • CPUはEL3で動作開始する。
  • Linux起動時は事前にEL2/EL1に設定しておく。

Raspberry Pi 3Bについて

  • kernel_old=1 で起動するとEL3で起動する。
  • kernel_old=1 を指定しないと、EL2で起動する。

ELを確認する。

ELの数値をレジスタx0に代入するアセンブリコード。

mrs   x0, CurrentEL

bit3とbit2がELの値でb、it31-4とbit1とbit0は0となる。
つまり、EL3なら0xC, EL2なら0x8, EL1なら0x4, EL0なら0x0となる。(だがEL0からはこのレジスタにアクセスできない。EL0の判定はどうやるのか?)

CurrentELの仕様は、ARMv8のアーキテクチャリファレンスマニュアル C5.2.1 にある。

ELを変更する。

ELを変更するアセンブリーコードです。

EL3 to EL2

EL3からEL2に変更するアセンブリコード。

#define MODE_AARCH64_EL2H 0x9
mov   x0, #0x4b1    // RW=1, SMD=1, RES=1, NS=1
msr   scr_el3, x0
adr   x0, start_el2
msr   elr_el3, x0
mov   x0, #MODE_AARCH64_EL2H
msr   spsr_el3, x0
eret

EL2に変更する例外を発生

  • EL3の例外リンクアドレスレジスタ elr_el3,に、EL2に変更できた際の開始アドレス(start_el2)を設定する。
  • EL3のセーブドプログラムステータスレジスタ spsr_el3に例外の戻り先のモードをEL2hに設定する。

とするとeretの後にELがEL3からEL2hに変更になる。

この時に指定するモードは同じELでも2種類あるEL2hとEL2tがある。EL2tだとEL変更後スタックポインタSP0を使う。
EL2hだとEL変更後はSP_EL2を使う

elr_el3の仕様は、ARMv8のアーキテクチャリファレンスマニュアル C5.2.7 にある。
spsr_el3の仕様は、ARMv8のアーキテクチャリファレンスマニュアル C5.2.20 にある。

EL2 to EL1

ほぼ同様です。

#define MODE_AARCH64_EL1H 0x5
mov   x2, #(1 << 31)      // AArch64
orr   x2, x2, #(1 << 1)   // SWIO hardwired on Pi3
msr   hcr_el2, x2
mrs   x0, hcr_el2
adr   x0, start_el1
msr   elr_el2, x0
mov   x0, #MODE_AARCH64_EL1H
msr   spsr_el2, x0
eret

EL1 to EL0

ほぼ同様です。

#define MODE_AARCH64_EL0 0x0
adr   x0, start_el0
msr   elr_el1, x0
mov   x0, #MODE_AARCH64_EL0
msr   spsr_el1, x0
eret

ERETによるEL変更

ERETでは数字が同じか小さいいELに変更できる

  • EL3はEL3, EL2、EL1、EL0に変更できる。
  • EL2はEL2, EL1、EL0に変更できる。
  • EL1はEL1, EL0 に変更できる

数字が小さいELから大きいELに変更するためには、IRQ、FIQなどの外部割り込みを発生させるか、SVC, HVC, SMC命令を使う。

ELを変更する実行例

コードをQEMUで実行した場合のトレース。

  • 1回目のeretの後にelr_el3に設定した0x30番地にジャンプしている。
  • 2回目のeretの後にelr_el2に設定した0x54番地にジャンプしている。
  • 3回目のeretの後にelr_el1に設定した0x68番地にジャンプしている。
0x00000010:  58000441  ldr      x1, #0x98
0x00000014:  d2809622  movz     x2, #0x4b1
0x00000018:  d51e1102  msr      scr_el3, x2
0x0000001c:  d2800122  movz     x2, #0x9
0x00000020:  d51e4002  msr      spsr_el3, x2
0x00000024:  10000062  adr      x2, #0x30
0x00000028:  d51e4022  msr      elr_el3, x2
0x0000002c:  d69f03e0  eret     

0x00000030:  d2b00002  movz     x2, #0x8000, lsl #16
0x00000034:  b27f0042  orr      x2, x2, #2
0x00000038:  d51c1102  msr      hcr_el2, x2
0x0000003c:  d53c1100  mrs      x0, hcr_el2
0x00000040:  d28000a2  movz     x2, #0x5
0x00000044:  d51c4002  msr      spsr_el2, x2
0x00000048:  10000062  adr      x2, #0x54
0x0000004c:  d51c4022  msr      elr_el2, x2
0x00000050:  d69f03e0  eret     

0x00000054:  d2800002  movz     x2, #0
0x00000058:  d5184002  msr      spsr_el1, x2
0x0000005c:  10000062  adr      x2, #0x68
0x00000060:  d5184022  msr      elr_el1, x2
0x00000064:  d69f03e0  eret     

0x00000068:  9100003f  mov      sp, x1

このトレースはqemuの-d in_asm で出力しました。この機能は便利です。

参考にしたページ

14
10
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
14
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?