Rust勉強
UEFIローダのサンプル
RustでUEFIローダ書いてみてる人がいる
これやれば良さそう
uefi
クレートと、uefi-services
クレートを入れれば良さそう。
#![feature(asm)]
はもういらないらしい
代わりに use core::arch::asm;
でとりあえず通った.
数百年ぶりにしっかりMakefileかいた
webpackとかあのへんになれてる頃とかはMakefileとか古いなって思ってたけど、最近は何かと言って必要最小限でいい感じがしてきた
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のオプション勉強する必要ありそう
最新版のuefi-rs
だと、.cargo/config.toml
で、build-stdにallocを追加しないとビルドが通らない
build-std = ["core", "compiler_builtins","alloc"]
build-std-features = ["compiler-builtins-mem"]
こんなエラーが出る
ScopedProtocol
の get
もなくなっている
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
これのjson使ったら行けた。 linker-flavorの設定があるが、linkerの指定がなかったからか?
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"
}
CTFでも触れなければならないし、ELF周りはもうちょっと詳しくならねば
先駆者たちのzennにも「Rustを学びながらやるのはおすすめしない」って書いてあるのに、なぜ手を出してしまうのか
これで関数のポインタから変換している様子
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
が呼ばれないので少なくとも何か実行されてるっぽい
とても参考になってありがたい。
bootloaderからkernelを呼び出しが上手く行かなかった問題.
#[no_mangle]
の位置が悪くて上手く行ってなかったっぽい.
radareでみてもkernel_mainが定義された!
今頃だけどRustの文字列
Stringは有効なUTF-8の配列であることを保証されたバイトのベクタとして保持される。
ヒープ上で保存されて伸縮可能で終端にnull文字を含まない。
&strは有効なUTF-8の配列のスライスでいつでもStringに変換が出来る。&[T]とVec<T>の関係。
コンソールの実装、マクロ側でどうやってスクリーンのメモリ領域への参照をもたせているのだろう
普通にフレームバッファを受け取ってる
static
かつmut
な要素はunsafe
に囲まれたところでしか取得、編集できない
mut staticを使うと良い?
https://riptutorial.com/rust/example/29321/safe-static-mut-with-mut-static#:~:text=Mutable global items (called%20static,ensure%20they%20are%20used%20appropriately.
やっぱりstdがないとだめだ...
今頃だが、traitとして引数を受け取りたいときは &impl <Traint type>
で受け取れる。
pub fn notify(item: &impl Summary) {
println!("Breaking news! {}", item.summarize());
}
これは以下のシンタックスシュガー
pub fn notify<T: Summary>(item: &T) {
// 速報! {}
println!("Breaking news! {}", item.summarize());
}
複数のとき
pub fn notify(item: &(impl Summary + Display)) {
where
句を使うとわかりやすい?
fn some_function<T, U>(t: &T, u: &U) -> i32
where T: Display + Clone,
U: Clone + Debug
{
write!
macro
use std::io::Write;
let mut w = Vec::new();
write!(&mut w, "test").unwrap();
write!(&mut w, "formatted {}", "arguments").unwrap();
assert_eq!(w, b"testformatted arguments");
第一引数がWrite
traitを実装している必要があるっぽい。第二引数以降は format!
と同じ
こっちのほうが内容がそれっぽい
std::io::Write
だけではなくstd::fmt::Write
もある
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
は簡単に実装は出来る
パラメータの持たないコンストラクタのインスタンスは省略できる
struct ConsoleWrite;
...
let a = ConsoleWrite;
let b = a.borrow();
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使っててだめっぽい