Slide 1

Slide 1 text

試して理解 ARMv8 MMU Toshifumi NISHINAGA(@tnishinaga) 2018/11/10 KernelVM Hokuriku@4 コードはこちら https://github.com/tnishinaga/kernelvm_hokuriku4 v6 まにあわなかった

Slide 2

Slide 2 text

$ who ● Name: Toshifumi NISHINAGA ● Attribute: Hobby embedded programmer ● Activities: ○ Google Summer of Code 2016(Linux foundation) ■ https://summerofcode.withgoogle.com/archive/2016/projects/661784 9892175872/ ■ Porting Linux to ARM Cotex-M7 microcontroller. ○ U-Boot contributor(not active recently…) ● link: ○ https://github.com/tnishinaga ○ https://speakerdeck.com/tnishinaga 3

Slide 3

Slide 3 text

ARMとは ● 今最もアツい(個人の感想です) ARM社の RISC CPU ● 組み込み機器で多く利用 ● 最近はサーバー向けにも進出 ● 今買うならSynQuacerってマシン がおすすめ 4

Slide 4

Slide 4 text

今回のお話 ● MMUの概要と実際の設定方法をご紹介 5

Slide 5

Slide 5 text

もくじ ● MMUの概要 ○ MMUとは ■ アクセス制御 ■ アドレス変換 ○ 実践:アクセス制御 ● 実践:MMUを動かしてみる ○ アドレス変換の仕組み ○ アドレス変換テーブル ○ MMU Discriptor ● 実践:アドレス変換 6

Slide 6

Slide 6 text

もくじ ● MMUの概要 ○ MMUとは ■ アクセス制御 ■ アドレス変換 ○ 実践:アクセス制御 ● 実践:MMUを動かしてみる ○ アドレス変換の仕組み ○ アドレス変換テーブル ○ MMU Discriptor ● 実践:アドレス変換 7

Slide 7

Slide 7 text

Memory Management Unit(MMU)とは ● 仮想メモリの管理やアクセス制御などを行うユニット ● Linuxなどの最近の一般的なOSは基本的にMMUがあること前提 ○ NOMMU Linuxもあるけどできることがかなり限られる ■ forkが使えないなど ■ (MMUがないとアドレス空間が分けられないから?) 8

Slide 8

Slide 8 text

MMUがあるとできること ● 読み書き実行アクセス制御 ● メモリアドレス変換(VA -> PA) ● その他(キャッシュ可否など。説明skip) 9

Slide 9

Slide 9 text

読み書き実行アクセス制御 ● 特定メモリ領域の読み書き実行可否設定ができる ● セキュリティ対策に使える。 ● ● 例:スタックのメモリを実行不可にする ○ スタックにコードを置いて実行する攻撃を防げる ■ Buffer over flow攻撃など 10

Slide 10

Slide 10 text

アドレス変換 ● 仮想アドレス(Virtual Address, VA)を物理アドレス(Physical Address, PA)に変換する機能 ● プロセスごとに独立したメモリ空間を用意できる ○ プログラマやコンパイラがプログラムがどのアドレスに配置されるか気にしなく て良い ○ メモリ空間がプロセスごとに分かれているので、他プロセスのデータにアクセス はできない 11 proc1の メモリ空間 proc1 proc2の メモリ空間 proc2 仮想メモリ 0x00 0x00 0xff.. 0xff.. proc1の メモリ空間 proc2の メモリ空間 0x00 0xff.. 物理メモリ

Slide 11

Slide 11 text

もくじ ● MMUの概要 ○ MMUとは ■ アクセス制御 ■ アドレス変換 ○ 実践:アクセス制御 ● 実践:MMUを動かしてみる ○ アドレス変換の仕組み ○ アドレス変換テーブル ○ MMU Discriptor ● 実践:アドレス変換 12

Slide 12

Slide 12 text

実践: アクセス制御 ● 確かめたいこと ○ メモリに対するアクセス制御ができることを調べたい ● 検証方法 ○ 実行不可としたスタック上にコードを入れて動かしてみる ○ /proc/self/maps を覗いてstackの読み書き実行フラグ状態を調べる ● 期待する動作 ○ 実行フラグがOFFなっている ○ SEGVする 13

Slide 13

Slide 13 text

検証コード ● stackに置くコード ○ https://github.com/tnishinaga/kernelvm_hokuriku4/blob/master/stack_exe c_test/ret1.S ● stackのメモリ属性を参照して、stackのコードを実行するコード ○ https://github.com/tnishinaga/kernelvm_hokuriku4/blob/master/stack_exe c_test/stack_exec.c 14

Slide 14

Slide 14 text

実行結果 15 pi@raspberrypi:~/kernelvm_hokuriku/stack_exec_test $ ./stack_noexec.elf buf address: 0xbeaf3490 bead3000-beaf4000 rw-p 00000000 00:00 0 [stack] ret1 addr: 0x106d0 ret1_fin addr: 0x106d8 Segmentation fault 実行権限xがつ いてない

Slide 15

Slide 15 text

結果 ● 実行不可としたスタック上でコードが動かないことを確認した ● メモリの属性も実行不可となっているのを確認した 16

Slide 16

Slide 16 text

Tips: stack実行可否の制御 ● 一部例外を除いてstackは実行不可になっている ● 例外: ○ コンパイルオプションに-z execstackをつける(リンカのお仕事) ○ -z noexecstack をつけずに.cと.Sの混ぜてビルドする ■ 参考: https://qiita.com/rarul/items/e1920e7ae5d5a28eec03 17

Slide 17

Slide 17 text

もくじ ● MMUの概要 ○ MMUとは ■ アクセス制御 ■ アドレス変換 ○ 実践:アクセス制御 ● 実践:MMUを動かしてみる ○ アドレス変換の仕組み ○ アドレス変換テーブル ○ MMU Discriptor ● 実践:アドレス変換 18

Slide 18

Slide 18 text

MMUを動かしてみる ここからはARMv6 MMU(VMSAv6)を実際に設定しつつ、MMUの動作を手を 動かしながら学びます 簡単のため、設定するMMUの仕様は以下 ● 変換レベルは1段 ● ストレートマップ(VA = PA) ● 解説は基本アドレス変換のみに絞る。その他はskip 19

Slide 19

Slide 19 text

アドレス変換の仕組み ● アドレス変換は変換表を見て対応するアドレスに変換してる ● アドレス変換はある程度まとまった単位で行われる ○ 1byteづつで変換するとメモリと同じサイズの変換テーブルが必要 ● ARMではVAの上位n bit(変換段数で変化)を使って変換 ● それ以下はVA = PAとしてアドレスを作る CCCC 0xAA CCCC 0xBB 0xBB 0xAA 0x00 0x.. 変換テーブル Virtual Address Physical Address 20

Slide 20

Slide 20 text

アドレス変換テーブル ● アドレス変換はアドレス変換テーブルを参照して行われる ● 変換テーブルはメモリ上に置かれる ● 場所をTTBRレジスタにセットするとアドレス変換に使われる ○ TTBR0とTTBR1の2つあるが、簡単のためTTBR0を利用 メモリ 変換テーブル 0xAA 0xAA TTBR0 21

Slide 21

Slide 21 text

TTBR0への変換テーブル設定コード ● TTBR0はシステムレジスタなのでMCR命令で書き込む ● テーブルのアドレスは16KiB alignである必要がある ● ARMv8前のシステムレジスタ指定は難しい ○ マニュアルから探すしか無い ○ http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211k/Bhcbiigc.html 22 static inline void set_ttbr0(uint32_t *pagetable) { __asm__ volatile("mcr p15, 0, %[p], c2, c0, 0" : : [p] "r" (pagetable) : ); }

Slide 22

Slide 22 text

MMU Descriptor ● 変換テーブルにはMMU Descriptorが詰まっている ● 変換するアドレスの情報を記す ● descriptorの形式は複数ある。1段めには以下の2種が作れる ○ セクション ○ ページテーブル ● 簡単のために今回はセクションを使う ○ 1段で変換できるので簡単 23

Slide 23

Slide 23 text

MMU Descriptorのセクション ● セクションはVAの上位12bitを変換する ○ 1セクション1MBを変換できる ○ 4096エントリで全メモリを変換可能 ● ● ディスクリプタ構造の詳細は以下参考 ○ http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0301h/ch06s12s02.html ○ Figure 6.12. Translation for a 1MB section, ARMv6 format 24

Slide 24

Slide 24 text

セクション作成コード void vmsav6_set_mmu_section( uint32_t va, uint32_t pa, uint32_t options ) { uint32_t idx = va >> 20; uint32_t entry = (pa & 0xfff00000) | (options & 0x7ffc) | VMSAv6_SECTION_FLAG; ttbr0_lv1_section[idx] = entry; return; } 25 void create_straight_section(void) { uint32_t entry = 0; uint32_t peri_base = 0x10000000; uint32_t entry_peri_base = peri_base >> 20; for (entry = 0; entry < 4096; entry++) { uint32_t addr = entry << 20; vmsav6_set_mmu_section( addr, addr, VMSAv6_SECTION_AP_FULLACCESS ); } }

Slide 25

Slide 25 text

MMUの有効化 ● ARMv6ではControl Registerを制御してMMUを有効化する ● 1bit目を1にするとMMUが有効になる ● 参考 ○ http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0301h/Bgbciiaf.html ● 26 図はARM1176JZF-S Technical Reference Manual(Revision: r0p7)のFigure 3.26から引用 http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0301h/Bgbciiaf.html

Slide 26

Slide 26 text

MMUを有効化するコード static inline void enable_mmu(void) { volatile uint32_t mmu_en_mask = 0; mmu_en_mask |= 1; // M = 1 mmu_en_mask |= 1 << 2; // C = 1 mmu_en_mask |= 1 << 16; // I = 1 __asm__ volatile( "mrc p15, 0, r0, c1, c0, 0;" "orr r0, r0, %[x];" "mcr p15, 0, r0, c1, c0, 0;" : : [x] "r" (mmu_en_mask) : "r0" ); } 27

Slide 27

Slide 27 text

その他 ● MMU有効化前に以下も行う必要があるが説明省略 ○ キャッシュのinvalidate ○ TLBのinvalidate ○ ドメインの設定 28

Slide 28

Slide 28 text

実践: MMUの有効化 ● 確かめたいこと ○ これまでの手順でMMUの有効化ができることを確認する ● 検証方法 ○ MMUを有効化してもコードの実行が止まらなければOK ■ MMUの設定に失敗すると落ちるので…… 29

Slide 29

Slide 29 text

コード int main(void) { set_vector_table(0); pl011_init(STDIO, UART_CLOCK); my_puts(STDIO, "HelloWorld!\n"); init_mmu(); // MMU有効化 my_puts(STDIO, "Hello MMU World!\n"); return 0; } 30 全コードはこちら https://github.com/tnishinaga/kernelvm_hokuriku4/tree/master/mmu_enable_test 設定が正しければこの文が出てくる

Slide 30

Slide 30 text

実行結果 tnishinaga@tx230> ./run_qemu.sh HelloWorld! Hello MMU World! 31

Slide 31

Slide 31 text

結果 ● MMUを有効化はうまく行った ● でもVA=PAだと効果がよくわからない ● もっとわかりやすい実験はできないものか? ○ 次の実践でやろう! 32

Slide 32

Slide 32 text

もくじ ● MMUの概要 ○ MMUとは ■ アクセス制御 ■ アドレス変換 ○ 実践:アクセス制御 ● 実践:MMUを動かしてみる ○ アドレス変換の仕組み ○ アドレス変換テーブル ○ MMU Discriptor ● 実践:アドレス変換 33

Slide 33

Slide 33 text

実践: アドレス変換 ● 確かめたいこと ○ VAに対応するPAが自由に変換できることを確認する ● 検証方法 ○ メモリ上のアドレス0x00500000 と 0x00600000 をMMUの機能を使って入れ 替えてみる ○ 予めそれぞれのアドレスに値を入れ、MMU有効後に値を確認する 34 VA 0x00500000 0x00600000 PA 0x00500000 0x00600000 0x00500000 0x00600000

Slide 34

Slide 34 text

コード *addr_0x00500000 = 0x00500000; *addr_0x00600000 = 0x00600000; (skip) uint32_t tmp = ttbr0_lv1_section[5]; ttbr0_lv1_section[5] = ttbr0_lv1_section[6]; ttbr0_lv1_section[6] = tmp; init_mmu(); my_puts(STDIO, "\nMMU enabled:\n"); show_5_6(); // 0x00500000と0x00600000の中身を表示 35 全コードはこちら https://github.com/tnishinaga/kernelvm_hokuriku4/blob/master/mmu_exchange_test Entry 5と6を入れ替えて PAとVAの対応を入れ替える

Slide 35

Slide 35 text

実行結果 MMU disabled: 0x00500000 = 00500000 0x00600000 = 00600000 Create straight section Exchange entry 5 with 6 MMU enabled: 0x00500000 = 00600000 0x00600000 = 00500000 36 入れ替わった

Slide 36

Slide 36 text

結果 ● 変換テーブルを入れ替えることでVAとPAの対応を変更できることが分かっ た 37

Slide 37

Slide 37 text

まとめ ● MMUはアドレス変換とアクセス制御の機能を提供する ● 昨今のOSには無くてはならない機能 ● ARMのMMU有効化は基本は以下の手順でできる ○ セクション作成 ○ 変換テーブル登録 ○ MMUのON 38