$30 off During Our Annual Pro Sale. View Details »

2019 年度 CPU 実験 余興: Linux が動く RISC-V CPUを作る

2019 年度 CPU 実験 余興: Linux が動く RISC-V CPUを作る

2019 年度 CPU 実験の最終発表会で使用したスライドです。
詳しくは https://diary.shift-js.info/building-a-riscv-CPU-for-linux をご覧ください。

Takashi Yoneuchi

February 28, 2020
Tweet

More Decks by Takashi Yoneuchi

Other Decks in Programming

Transcript

  1. 2019 年度 CPU 実験 余興:
    Linux が動く RISC-V CPUを作る
    (公開版)

    View Slide

  2. 背景: これまでの余興
    - 14er: xv6 on MIPS 系コア
    - CPU実験で自作CPUにUNIXライクOS (xv6) を移植した話
    http://nullpo-head.hateblo.jp/entry/2015/03/24/205419
    - 17er: 自作 OS on RISC-V 系コア
    - 東大のCPU実験で自作コア上の自作 OS上で自作シェルを動かした話
    http://yamaguchi-1024.hatenablog.com/entry/2018/02/27/172417
    - 18er: 自作 OS on RISC-V 系コア
    - RISC Vに従うCPUの上で動作するOSをRustで書く(CPU実験余興)
    https://moraprogramming.hateblo.jp/entry/2019/03/17/165802
    - 19er: ??

    View Slide

  3. 背景: 19er を取り巻く現状
    - 19er を取り巻く現状
    - 自作 CPU は比較的メジャーな趣味になってきている。
    - 弊学科以外でも自作 CPU に取り組む人が多い。
    - シミュレータ程度であれば、さらに多くの人が実装している。
    - CPU 実験において、自作 OS は既にそれなりに先駆者がいる領域である。
    - OS 移植系をするなら、xv6 はツールチェインの自作からやらねば、新規性がない。
    - 過去の先輩たちの夢の跡
    - “...Iwashi班という自作CPU上でlinuxを動かすことを目標とした余興班を ...”
    http://yamaguchi-1024.hatenablog.com/entry/2018/02/27/172417
    - “…Linuxに初めから、とは言わずも、 ucLinuxくらいには挑戦していればよかったかもしれない。 …”
    http://nullpo-head.hateblo.jp/entry/2015/03/24/205419

    View Slide

  4. 余興の概要
    - 目標: Linux が動く RISC-V CPU を作ること
    - Vivado から利用できる IP コアを除いて、基本的にハードウェア類は実装する。
    - 極力 Linux カーネル本体に変更は加えない。
    - 妥協点: SBI・ツールチェインは既存のものを利用する
    - SBI: OpenSBI (https://github.com/cpuex2019-yokyo/opensbi/)
    - エミュレータ: QEMU
    - コンパイラ等: riscv-gnu-toolchain (https://github.com/riscv/riscv-gnu-toolchain)
    - 作業期間: 1/17 - 2/28
    - 3A の試験後から発表会の日まで

    View Slide

  5. 全体構成図

    View Slide

  6. 全体構成図

    View Slide

  7. Linux 起動までの流れ
    - コアはメモリの 0x00000000 から命令実行を始める。
    - 0x00000000 にはブートローダがおいてあり、フラッシュメモリにおいてある「カーネ
    ルの ELF を展開した直後のメモリダンプ」を SDRAM に展開する。終わり次第
    SDRAM の先頭 (0x80000000) にジャンプする。
    - すると OpenSBI が起動し、適当に自身の使う領域を初期化した後、Linux カーネ
    ルのエントリポイントにジャンプする。
    - Linux カーネル色々初期化した後、 /init なる実行ファイル (initramfs 中に存在) を
    起動する (実態は busybox)。
    - 無事シェルが起動する。

    View Slide

  8. デモ (xv6)

    View Slide

  9. デモ (Linux) https://www.youtube.com/watch?v=Jd9sKKB3E4w

    View Slide

  10. 詳細

    View Slide

  11. Linux を動かすためのハードウェア面の準備
    - 実装したもの
    - コア (core.sv)
    - MMU + TLB (mmu.sv)
    - virtio-blk のハードウェア実装 (virtio*.sv)
    - PLIC (plic.sv)
    - CLINT (clint.sv)
    - キャッシュ (cache*.sv) (→ 現在も作業中)
    - クロック分割した乗算・除算モジュール (mul.sv / div.sv)
    - Vivado から IP コアを利用したもの
    - UART 16650A 相当のインターフェイス … AXI UART 16650
    - MMIO 処理 … AXI Interconnect

    View Slide

  12. Linux を動かすためのその他の準備
    - xv6-riscv を rv32imasu + Sv32 向けにポーティング
    - xv6-riscv: MIT のxv6 の RISC-V (rv64gc) 向けのポート
    - Linux より小さく、かつソースコードが読みやすい
    - 移植は素振り程度の気分ででき、かつ xv6 は割り込みや CSR 周りのデバッグに有用
    - ブートローダの開発
    - Linux カーネルのサイズは削ってもそれなりに大きいので、ブートするためには「どこかから
    SDRAM に ELF を展開するやつ」が必要。
    - その他たくさんの「やるだけ」の処理
    - Device Tree の調整
    - Linux, OpenSBI, xv6-riscv 全てにおけるメモリマップの調整
    - ツールチェインのバグを取る (?)
    - rv32* 向けのツールチェインはしばしば不可解な挙動をする

    View Slide

  13. CPU
    - CPU: シンプルな単一サイクルのコア
    - ISA: rv32imasu を採用 (Unprivileged ISA v2.2 + Privileged ISA v1.10)。
    - i: 整数演算等の、RISC-V コアを名乗るに最低限必要な命令
    - m: 乗算除算命令
    - a: アトミック命令
    - s: 特権命令
    - 注意点: いくつかの機能の実装は簡略化のために省略した。
    - e.g. PMP (Physical Memory Protection)
    - e.g. パフォーマンスカウンタ系
    - 単一サイクルコアな理由 : 割り込みや atomic 命令の処理が面倒そうだったため
    - fork 元の自班のレイトレ用のコア (cpuex2019-7th) は 5 段パイプライン
    - 実装: https://github.com/cpuex2019-yokyo/core/blob/master/src/core.sv

    View Slide

  14. MMU + TLB
    - MMU: Privileged ISA v1.10 に従って実装した。
    - ページングアルゴリズム : Sv32 を採用した。
    - 理由: 32bit アーキテクチャなので。
    - 基本的には (x86 よろしく) 二段のページングを行う。
    - TLB: 16 エントリのシンプルなもの。
    - 時間の都合上、TLB が一杯のときには、非常に雑に TLB エントリを置換する (!)。
    - これは結構大問題で、これのせいでとても TLB ミス率が高そう。
    - 実装: https://github.com/cpuex2019-yokyo/core/blob/master/src/mmu.sv

    View Slide

  15. 補足: Sv32
    - 32bit アーキテクチャ向けのシンプルなページングアルゴリズム
    - satp レジスタが最初のページテーブルの先頭アドレスを指す
    - つまり satp は x86 でいう cr3 レジスタ
    - VPN[1] を使って 1 つ目の PTE を得て、VPN[0] を使って物理アドレスを得る。もち
    ろん huge page も取れる。
    (画像は RISC-V Privileged ISA v1.10 から引用)

    View Slide

  16. virtio-blk のハードウェア実装とブートローダ
    - virtio-blk のハードウェア実装とブートローダ:
    - 問題: (注: xv6 では問題にならない )
    - カーネルを SDRAM に初期値としておいておくことは出来ない。
    - しかしLinux カーネルは大きいので、 BRAM にも乗らない。
    - 解決の方法:
    - フラッシュメモリにカーネルの ELF を適当に処理した後においておく。
    - 起動時に別途作成したブートローダから展開し、その後カーネルにジャンプする。
    - 余興の余興: ついでに xv6 の扱うファイルシステムをフラッシュメモリに置いて使った。
    - virtio-blk の仕様: Virtual I/O Device (VIRTIO) Version 1.1 のサブセットを実装した。
    - 実装:
    - virtio https://github.com/cpuex2019-yokyo/core/blob/master/src/virtio.sv
    - bootloader https://github.com/cpuex2019-yokyo/toolchain/tree/master/bootloader/linux

    View Slide

  17. 補足: xv6-riscv のディスク処理
    - xv6-riscv が使う範囲では、以下の手順でディスク関連の処理をする。
    - available リングと used リングという 2 つのリングバッファがある
    - ドライバ側は available リングに 3 つほどディスクリプタを置き、 MMIO で デバイスに available リン
    グの進行を伝える
    - その後デバイスは available リングを見て、そのディスクリプタの中身を見てディスクコントロールを
    行い、used リングにその処理結果を置き、割り込み信号をアサートする。
    - そこから巡り巡ってドライバに制御が渡り、あとはよしなに hoge される
    - しかし、Linux はおそらくもう少し色々な機能を使っていそう…
    - 仕様は一通り読んだし、 QEMU の実装も一通り読んだが、挫折
    - 結果 Linux は initramfs を利用することにした

    View Slide

  18. PLIC と CLINT
    - PLIC: Platform-Level Interrupt Controller
    - これは何: 外部割り込み信号のコントローラ
    - 仕様: Privileged ISA v1.10 を元に実装した。
    - 注: 一部の実装は仕様に準拠していないかもしれない
    - CLINT: Core-Local Interruptor
    - これは何: ソフトウェア割り込みとタイマ割り込み用のコントローラ
    - 仕様: SiFive の資料を元に実装した。
    - 注: CLINT の mtimecmp, mtime レジスタは CSR としてアクセスできる (Memory-mapped CSR);
    アクセスの際によしなに例外を生やすか、適当に配線する必要がある。
    - 実装:
    - PLIC https://github.com/cpuex2019-yokyo/core/blob/master/src/plic.v
    - CLINT https://github.com/cpuex2019-yokyo/core/blob/master/src/clint.v

    View Slide

  19. Linux 動作を目標とするということ
    - よいところ
    - 申し分のない強度の課題である。
    - 今回は「実質 1 ヶ月くらいしか作業できない & 基本的に全員自分の班の実験の作業や実験
    以外の活動がある」という制約があった。
    - 結構完成がギリギリだったのでヒヤヒヤした。
    - 仕様やソースコードを読む力が育てられる & そのへんのツールと仲良くなれる。
    - 理由: 様々な OSS のソースコードを嫌でも読む必要があるため。
    - 読んだ OSS: QEMU, OpenSBI, Linux カーネル, xv6-riscv, riscv-gnu-toolchain, ...
    - 現代の CPU たち、OS たち、コンパイラたち、全てに尊敬の念を抱けるようになる。
    - わるいところ
    - 回路規模が大きくなるので、 Vivado の意味不明な最適化バグを踏んだ瞬間に、バグフィックスのた
    めに数日溶ける。非人道的な作業が求められる。

    View Slide

  20. 最後に

    View Slide

  21. 学んだこと
    - 既存の著名なソフトウェアにおいてもバグや適当な実装は存在する
    - QEMU, riscv-gnu-toolchain, linux, OpenSBI, risv-tests, …
    - 発展途上の仕様にも案外穴がある
    - たくさん未定義動作でバグらせた。 RISC-V には今後も頑張ってほしい。
    - 大体の実装はやればできる
    - これは真理; しんどくでも十分時間根気強く見ればバグは見つかるし倒せる

    View Slide

  22. 今後
    - やりきれなかったこと
    - ネットワーク通信
    - KCU105 には Ethernet ポートがあるのに。
    - ただの Device Tree 調整ゲーでは?
    - 現実的な速度での Linux の動作・安定稼働の実現
    - 現状起動に 5 分かかるし、何回かコマンドを叩くと死ぬ (なぜ…)
    - 挑戦したら面白そうなこと
    - Chisel での CPU 実験; 脱 SystemVerilog をしていく [本当に可能?]
    - 自作 CPU 上でのハイパーバイザ的なものの実装 [本当に可能?]
    - 20er の皆さんに乞うご期待
    - これは冗談で、過去の代と張り合う必要はないと思います。余興などという「やらなくてもいいもの」
    を満足行くまでやりきるためには、自分が楽しいと思えることが大事そう。

    View Slide

  23. 謝辞
    - 余興班メンバの所属する各班のみなさん
    - 米内はレイトレ用コアの実装をめちゃくちゃサボりました。すみませんでした。
    - msyksphinz さん
    - 氏のブログなしではここまで到達できませんでした。ありがとうございました。
    - TSG の皆様
    - 色々とご助言を頂きありがとうございました。
    - IS の先輩各位
    - みなさまのブログのおかげで色々な沼を回避できました。
    - また今回の余興テーマの設定は、先人の取り組みがあってこそのものです (正直 OS 作るくらいで
    いいかなと思っていた )。ありがとうございました。

    View Slide

  24. お疲れさまでした

    View Slide