Upgrade to Pro — share decks privately, control downloads, hide ads and more …

第13回Kernel/VM勉強会発表資料

orumin
July 22, 2017

 第13回Kernel/VM勉強会発表資料

2017/07/22 に行なわれた Kernel/VM 勉強会の発表資料です。

orumin

July 22, 2017
Tweet

More Decks by orumin

Other Decks in Programming

Transcript

  1. C 以外でのベアメタルプログラミング
    XXX
    Jul 22th, 2017
    1 / 27

    View Slide

  2. 自己(事故)紹介
    orumin
    Twitter ID: @kotatsu_mi
    最近自宅のサーバの電源と PT3 が雷に撃たれました。
    雷サージ対策は忘れずにやろうね!
    アンテナ線にも電話線にもサージプロテクタは存在する
    2 / 27

    View Slide

  3. 緒言
    ベアメタルプログラミング
    いわゆる freestanding 環境
    libc 他が存在しない
    みなさんよくやってますよね?
    よくつかわれるのは C や C++
    どうして C をつかうのか
    3 / 27

    View Slide

  4. ベアメタルプログラミングと C
    メリット 生ポインタで特定のアドレスへの I/O 操作といったことが簡単にでき
    る,また,この分野で枯れており,ノウハウも豊富
    デメリット 型システムが貧弱,最近のクールな言語機能が使えない
    4 / 27

    View Slide

  5. C 以外でベアメタルプログラミング
    複数の代替手段
    D 言語,C♯,Rust …
    (いますぐ採用するとかなくても)今後のために C 以外でやるノウハウも得てお
    かないとそのうち死ぬので
    Rust
    既にかなりの規模のそれなりにちゃんと動く OS が作られている(Redox)実績
    C♯ も 2011 年ぐらいから Cosmos という OS があったりする
    C♯ でのベアメタルプログラミングも調べて話そうとすると話者の力量不足でどっち
    つかずの内容になるので割愛しました
    そのうちやるかも?
    5 / 27

    View Slide

  6. Rust
    OCaml と C++ の血を感じる言語
    ML 系の強力な型システム
    所有権など,独特だが C++ を既に知ってる人間がわりと違和感なく使える強力な
    機能
    nightly コンパイラで freestanding をサポート
    stable 入りはまだですかー!
    様々な機能や設計が C++ のカウンターっぽい
    c.f.) 過去の KernelVM での @omasanori さんの発表
    https://speakerdeck.com/omasanori/rustru-men-yi-qian-fa-biao-ban
    6 / 27

    View Slide

  7. Rust(nightly)のインストールとテスト
    $ curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain=nightly -y
    $ . ~/.cargo/env
    $ cargo new --bin hello-rust
    7 / 27

    View Slide

  8. Rust のテスト
    右のようなディレクトリツリーが出来あがる
    作成されるファイルは下例
    実行は cargo run
    cargo は gem みたいなもの。ビルドツールか
    つパッケージマネージャ。
    Rust のパッケージは https://crates.io に
    ある
    hello-rust
    Cargo.toml
    src/
    main.rs
    [package]
    name = ”hello-rust”
    version = ”0.1.0”
    authors = [”orumin ”]
    [dependencies]
    fn main() {
    println!(”Hello, world!”);
    }
    8 / 27

    View Slide

  9. Rust でベアメタルをするにはどうすれば良いか
    UEFI apps を例に step-by-step で紹介します!
    Linux の人は手元で試してみてください
    TL;DR
    https://github.com/orumin/rust-uefi-sample.git を clone して make
    run
    rust-uefi-sample/
    Makefile
    Cargo.toml
    x86_64-unknown-efi.json
    src/
    lib.rs
    9 / 27

    View Slide

  10. Cargo.toml
    [package]
    name = ”uefi-sample”
    version = ”0.1.0”
    authors = [”orumin ”]
    [dependencies]
    uefi = { git = ”https://github.com/orumin/rust-uefi” }
    rlibc = ”1.0”
    [lib]
    crate-type = [”staticlib”]
    [profile.dev]
    panic = ”abort”
    [profile.release]
    panic = ”abort”
    10 / 27

    View Slide

  11. Cargo.toml
    パッケージ名や依存パッケージを記述
    [lib] セクションをつくり,src/lib.rs を記述するとライブラリとして作られる
    今回はオブジェクトファイルだけ作成して手動でリンクしたかった
    依存パッケージは名前だけ書いておくと crates.io からもってくる
    path = に続けてパスを記述すると他のディレクトリのプロジェクトを依存に指定
    git = に続けて Git repo を記述すると自動で clone とビルドしてくれます
    11 / 27

    View Slide

  12. target json
    Cargo は json で custom ターゲットを作れる
    {
    ”arch”: ”x86_64”,
    ”os”: ”efi”,
    ”llvm-target”: ”x86_64-efi-none-gnu”,
    ”target-endian”: ”little”,
    ”target-pointer-width”: ”64”,
    ”function-sections”: false,
    ”no-compiler-rt”: true,
    ”data-layout”: ”e-m:e-i64:64-f80:128-n8:16:32:64-S128”,
    ”linker”: ”x86_64-efi-pe”,
    ”linker-flavor”: ”ld”,
    ”pre-link-args”: [
    ”subsystem”,
    ”10”
    ]
    }
    12 / 27

    View Slide

  13. target json
    今回は UEFI 向けに PE バイナリを作りたいので target の json を記述
    arm-none-eabi などでも記述
    ただの x86_64 の ELF なら要らないかも?
    13 / 27

    View Slide

  14. ソースコード
    #![no_std]
    #![feature(asm)]
    #![feature(intrinsics)]
    #![feature(lang_items)]
    extern crate uefi;
    extern crate rlibc;
    use core::mem;
    #[allow(unreachable_code)]
    #[no_mangle]
    pub extern ”win64” fn efi_main(hdl: uefi::Handle, sys: uefi::SystemTable)
    -> uefi::Status {
    uefi::initialize_lib(&hdl, &sys);
    let bs = uefi::get_system_table().boot_services();
    let rs = uefi::get_system_table().runtime_services();
    14 / 27

    View Slide

  15. ソースコード
    uefi::get_system_table().console().write(”Hello, World!\n\rvendor: ”);
    uefi::get_system_table().console().write_raw(uefi::get_system_table().vendor());
    uefi::get_system_table().console().write(”\n\r”);
    loop {
    }
    uefi::Status::Success
    }
    #[no_mangle]
    pub fn abort() -> ! {
    loop {}
    }
    #[no_mangle]
    pub fn breakpoint() -> ! {
    loop {}
    }
    #[no_mangle]
    pub extern ”C” fn _Unwind_Resume() -> ! {
    loop {}
    }
    #[lang = ”eh_personality”]
    #[no_mangle]
    pub extern fn rust_eh_personality() {}
    15 / 27

    View Slide

  16. ソースコード
    #[lang = ”panic_fmt”]
    #[no_mangle]
    pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
    _file: &’static str,
    _line: u32) -> ! {
    loop {}
    }
    16 / 27

    View Slide

  17. ソースコード解説
    #![no_std]
    標準ライブラリをリンクしなくなる
    標準ライブラリのうち,アーキテクチャ非依存な便利機能は core ライブラリを
    use すれば使えるものもある
    17 / 27

    View Slide

  18. no_std でフォーマット出力
    e.g.)
    use core::fmt::Write;
    impl Write for Writer {
    fn write_str(&mut self, s: &str) -> core::fmt::Result {
    引数でうけた文字列 s について出力を自分で実装;
    Ok(()) // 失敗なら Err(foo) でエラーの値返す
    }
    }
    これだけで,write!() マクロの実装が得られる
    let mut w = Writer {};
    write!(w, ”foo {}”, bar).unwrap();
    18 / 27

    View Slide

  19. #![feature(lang_items)]
    eh_personality とか panic_fmt とか
    eh_personality
    GCC の personality 関数の代わりのシンボル
    LLVM で言語の例外ハンドリングに使う
    unwind
    panic_fmt
    Rust で panic!() を使うときのシンボル
    デバッグ文字列出力とか作っておくと良い
    19 / 27

    View Slide

  20. extern
    extern “C” などとすると C 互換の ABI になる
    #[no_mangle] 付けると名前マングルをしない
    既存のライブラリを置き換える何かを作るのにもべんりかも
    UEFI は x86_64 だと Microsoft’s 64-bit call convention を使う
    extern “win64” で対応
    20 / 27

    View Slide

  21. ではビルドをしてみましょう
    $ cargo install xargo
    $ xargo build --target x86_64-unknown-efi
    Xargo を導入
    cargo build の際に core ライブラリなどをターゲットのアーキでビルドしてく
    れる
    素の cargo だとヘンなアーキテクチャ使うのに core をそこに合わせてビルドしな
    いといけない
    21 / 27

    View Slide

  22. binutils とリンク
    今回は UEFI ターゲットの PE バイナリを作りたいので普通の binutils だとダメ
    $ curl -O https://orum.in/distfiles/x86_64-efi-pe-binutils.tar.xz
    $ mkdir -p $PWD/toolchain
    $ tar xf x86_64-efi-pe-binutils.tar.xz -C $PWD/toolchain
    $ export PATH=$PATH:$PWD/toolchain/usr/bin/
    $ pushd
    $ cd target/x86_64-unknown-efi/debug
    $ ar x *.a
    $ popd
    $ x86_64-efi-pe-ld --gc-sections --oformat pei-x86-64 \
    --subsystem 10 -pie -e efi_main \
    -o bootx64.efi \
    target/x86_64-unknown-efi/debug/*.o
    22 / 27

    View Slide

  23. 実行
    $ dd if=/dev/zero of=fat.img bs=1k count=1440
    $ mformat -i fat.img -f 1440 ::
    $ mmd -i fat.img ::/EFI
    $ mmd -i fat.img ::/EFI/BOOT
    $ mcopy -i fat.img bootx64.efi ::/EFI/BOOT
    $ curl -O https://orum.in/distfiles/ovmf.fd
    $ qemu-system-x86_64 -enable-kvm -net none -m 1024 \
    -bios ovmf.fd -usb -usbdevice disk::fat.img
    23 / 27

    View Slide

  24. これだと見えづらいので……
    https:
    //github.com/orumin/rust-uefi-sample/blob/master/src/lib.rs
    Graphic Output Protocol の取得,設定
    BLT
    24 / 27

    View Slide

  25. conclusion
    Rust 便利
    C 以外でもベアメタルしたい!
    25 / 27

    View Slide

  26. こぼれ話1
    質問:@nullpo_head さん「自作 OS 勉強会だと Box が使えなくて辛いとかあっ
    たけどどうやってるの?

    回答:
    「まだそこらへんがっつりやるステージに入れてないが,そもそも Box と
    かは自前実装する方法があるので問題がないと思う。

    https://rust-lang-ja.github.io/the-rust-programming-language-ja/
    1.6/book/custom-allocators.html
    実は上記の通り公式ドキュメントがある
    ベアメタル以外でも使えるのでゲームエンジンとかやる人にも良いのではないか
    26 / 27

    View Slide

  27. こぼれ話2
    Rust のコンパイラ機能
    #[start]
    特定のシンボルの前(たとえば pub fn app_main() とかの前の行)に付けておく
    と,エントリポイントにしてくれる
    #[link_section = “.test_section”]
    この行のところが ELF の.test_section になる。便利。
    27 / 27

    View Slide