Open40

Rust勉強

kyasbalkyasbal

#![feature(asm)]はもういらないらしい

代わりに use core::arch::asm;でとりあえず通った.

kyasbalkyasbal
	qemu-system-x86_64 -smp 4 -m $(MEMORY_SIZE) \
		-drive if=pflash,format=raw,readonly=on,file=./ovmf/OVMF_CODE.fd \
		-drive if=pflash,format=raw,file=./ovmf/OVMF_VARS.fd \
		-drive if=none,id=drive0,format=raw,file=$(DISK_IMAGE_LOCATION) \
		-device isa-debug-exit,iobase=0xf4,iosize=0x04 \
		-device virtio-blk-pci,drive=drive0

qemuのオプション勉強する必要ありそう

kyasbalkyasbal

OVMFはUEFIで起動するために必要っぽい。

BIOS -> OVMF -> UEFI -> bootloader みたいな感じになるのかな

kyasbalkyasbal

最新版のuefi-rsだと、.cargo/config.tomlで、build-stdにallocを追加しないとビルドが通らない

build-std = ["core", "compiler_builtins","alloc"]
build-std-features = ["compiler-builtins-mem"]
kyasbalkyasbal

kernelビルドしたらエントリポイントが0x0になってる。
これはおかしい気がする。 --image-baseは0x1000なのに。

 readelf -h ./kernel/target/x86_64-unknown-none-mikanos-rust/debug/kernel
ELF ヘッダ:
  マジック:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  クラス:                            ELF64
  データ:                            2 の補数、リトルエンディアン
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI バージョン:                    0
  型:                                EXEC (実行可能ファイル)
  マシン:                            Advanced Micro Devices X86-64
  バージョン:                        0x1
  エントリポイントアドレス:               0x0
  プログラムヘッダ始点:          64 (バイト)
  セクションヘッダ始点:          4592 (バイト)
  フラグ:                            0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         3
  Size of section headers:           64 (bytes)
  Number of section headers:         13

kyasbalkyasbal

OKな設定

{
  "abi-return-struct-as-int": true,
  "allows-weak-linkage": false,
  "arch": "x86_64",
  "cpu": "x86-64",
  "data-layout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
  "disable-redzone": true,
  "emit-debug-gdb-scripts": false,
  "exe-suffix": ".elf",
  "executables": true,
  "features": "-mmx,-sse,+soft-float",
  "is-builtin": false,
  "is-like-msvc": false,
  "is-like-windows": false,
  "linker": "ld.lld",
  "linker-flavor": "ld",
  "linker-is-gnu": false,
  "llvm-target": "x86_64-elf",
  "max-atomic-width": 64,
  "os": "none",
  "panic-strategy": "abort",
  "pre-link-args": {
    "ld": [
      "--entry=kernel_main",
      "--image-base=0x100000",
      "--static"
    ]
  },
  "post-link-args": {
    "ld": [
      "-z",
      "norelro"
    ]
  },
  "singlethread": true,
  "split-debuginfo": "packed",
  "stack-probes": {
    "kind": "call"
  },
  "target-pointer-width": "64"
}

NGな設定

  
{
  "arch": "x86_64",
  "code-model": "kernel",
  "cpu": "x86-64",
  "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
  "disable-redzone": true,
  "executables": true,
  "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float",
  "linker-flavor": "ld.lld",
  "llvm-target": "x86_64-unknown-none-elf",
  "max-atomic-width": 64,
  "os": "none",
  "panic-strategy": "abort",
  "relro-level": "off",
  "position-independent-executables": false,
  "post-link-args": {
    "ld.lld": [
      "--entry=kernel_main",
      "--image-base=0x100000",
      "--static"
    ]
  },
  "target-pointer-width": "64"
}
kyasbalkyasbal

CTFでも触れなければならないし、ELF周りはもうちょっと詳しくならねば

kyasbalkyasbal

先駆者たちのzennにも「Rustを学びながらやるのはおすすめしない」って書いてあるのに、なぜ手を出してしまうのか

kyasbalkyasbal

https://doc.rust-lang.org/stable/std/mem/fn.transmute.html

これで関数のポインタから変換している様子

kyasbalkyasbal
    let kernel_entry = load_kernel("kernel.elf",_image,&st);
    info!("kernel entry: {}",kernel_entry);
    let entry_point: extern "sysv64" fn() = unsafe {
        mem::transmute(kernel_entry)
    };

    entry_point();
    info!("After kernel call");

これでAfter kernel callが呼ばれないので少なくとも何か実行されてるっぽい

kyasbalkyasbal

bootloaderからkernelを呼び出しが上手く行かなかった問題.
#[no_mangle]の位置が悪くて上手く行ってなかったっぽい.

radareでみてもkernel_mainが定義された!

kyasbalkyasbal

今頃だけどRustの文字列

Stringは有効なUTF-8の配列であることを保証されたバイトのベクタとして保持される。
ヒープ上で保存されて伸縮可能で終端にnull文字を含まない。

&strは有効なUTF-8の配列のスライスでいつでもStringに変換が出来る。&[T]とVec<T>の関係。

kyasbalkyasbal

コンソールの実装、マクロ側でどうやってスクリーンのメモリ領域への参照をもたせているのだろう
https://github.com/yubrot/ors/blob/1180bc755ab18d288a32b948bec4304c7957cd45/ors-kernel/src/shell.rs#L33

kyasbalkyasbal

static かつmutな要素はunsafeに囲まれたところでしか取得、編集できない

kyasbalkyasbal

今頃だが、traitとして引数を受け取りたいときは &impl <Traint type>で受け取れる。

pub fn notify(item: &impl Summary) {
    println!("Breaking news! {}", item.summarize());
}
kyasbalkyasbal

これは以下のシンタックスシュガー

pub fn notify<T: Summary>(item: &T) {
    // 速報! {}
    println!("Breaking news! {}", item.summarize());
}
kyasbalkyasbal

where 句を使うとわかりやすい?

fn some_function<T, U>(t: &T, u: &U) -> i32
    where T: Display + Clone,
          U: Clone + Debug
{
kyasbalkyasbal
pub trait Write {
    fn write_str(&mut self, s: &str) -> Result<(), Error>;

    fn write_char(&mut self, c: char) -> Result<(), Error> { ... }
    fn write_fmt(&mut self, args: Arguments<'_>) -> Result<(), Error> { ... }
}

fmt::Writeは簡単に実装は出来る

kyasbalkyasbal

パラメータの持たないコンストラクタのインスタンスは省略できる

struct ConsoleWrite;
...
        let a = ConsoleWrite;
        let b = a.borrow();
kyasbalkyasbal
   Compiling acpi v4.1.0
error[E0463]: can't find crate for `alloc`
  --> /home/kyasbal/.cargo/registry/src/github.com-1ecc6299db9ec823/acpi-4.1.0/src/lib.rs:53:1
   |
53 | extern crate alloc;
   | ^^^^^^^^^^^^^^^^^^^ can't find crate

error[E0283]: type annotations needed
    --> /home/kyasbal/.cargo/registry/src/github.com-1ecc6299db9ec823/acpi-4.1.0/src/mcfg.rs:25:71
     |
25   |         Ok(PciConfigRegions { regions: mcfg.entries().iter().copied().collect() })
     |                                                                       ^^^^^^^ cannot infer type for type parameter `B` declared on the associated function `collect`
     |

acpi クレートがalloc使っててだめっぽい