DEV Community

YT
YT

Posted on

Rustで自作OS 3日目

"第2章 EDK II入門とメモリマップ"を進めていく。
自作OS本を読んだところ、USBブートするためにBoot Loaderを作っていくようで、昨日までで作ったUEFIアプリをEDK IIで書き直すらしい。
昨日出てきたOVMFはUEFI BIOSのOSS実装で、EDK IIはUEFI BIOS上で動くアプリだけでなく、UEFI BIOS自体を開発するためにも使われるとのこと。

Rustで書くときにどうすれば良いのか調べたが、いまいちピンとこない。そもそもUEFIとEDK IIがよく分かってない。

osdev-jpを見ると、

スタンドアロンの UEFI アプリは UEFI Shell が起動する前に起動することができます。OS のブートローダーを作る場合などはスタンドアロンとして構成します。

スタンドアロンの UEFI アプリのエントリポイントは一般的な C 言語プログラムと違い、EFI_HANDLE と EFI_SYSTEM_TABLE * を引数として受け取ります。

ということは、昨日までのuefi crateを使ったUEFIアプリはこの特徴を満たしているのでは?なんなら使用可能メモリを表示する過程でメモリマップを取得しているのでは?

#![no_std]
#![no_main]
#![feature(asm)]
#![feature(abi_efiapi)]
#![feature(alloc)]

extern crate uefi;
extern crate uefi_services;
extern crate rlibc;
extern crate alloc;
extern crate log;

use uefi::prelude::*;
use crate::alloc::vec::Vec;
use uefi::table::boot::MemoryType;
use log::info;

const EFI_PAGE_SIZE: u64 = 0x1000;

#[entry]
fn uefi_start(_image_handler: uefi::Handle, system_table: SystemTable<Boot>) -> Status {
    uefi_services::init(&system_table).expect_success("Failed to initialize utils");
    system_table
        .stdout()
        .reset(false)
        .expect_success("Failed to reset output buffer");
    {
        let rev = system_table.uefi_revision();
        let (major, minor) = (rev.major(), rev.minor());
        info!("UEFI {}.{}", major, minor);
        memory_map(&system_table.boot_services());
    }
    loop{};
    Status::SUCCESS;
}

fn memory_map(bt: &BootServices) {
    let map_size = bt.memory_map_size();
    let mut buffer = Vec::with_capacity(map_size);
    unsafe {
        buffer.set_len(map_size);
    }

    let (_k, desc_iter) = bt
        .memory_map(&mut buffer)
        .expect_success("Failed to retrieve UEFI memory map");

    let descriptors = desc_iter.copied().collect::<Vec<_>>();

    assert!(!descriptors.is_empty(), "Memory map is empty");

    info!("efi: usable memory ranges ({} total)", descriptors.len());
    descriptors
        .iter()
        .for_each(|descriptor| match descriptor.ty {
            MemoryType::CONVENTIONAL => {
                let size = descriptor.page_count * EFI_PAGE_SIZE;
                let end_address = descriptor.phys_start + size;
                info!(
                    "> {:#x} - {:#x} ({} KiB)",
                    descriptor.phys_start, end_address, size
                );
            }
            _ => {}
        })
}
Enter fullscreen mode Exit fullscreen mode

適当に写経してたからuefi::table::bootとか使ってるのに気づかなかった。
この構成でブートローダーとして機能するかはわからないので、とりあえず本を読み進める。
元になったブログでもメモリマップ取得までやってたので、UEFIアプリのHello Worldは画面表示だけでなくメモリマップまでなのかもしれない。
ちなみに自作OS本ではメモリマップをファイルに保存するUEFIアプリを作ってた。

EDK IIを使ってるかは分からないが、今回の場合はueif crateを使ってboot loaderを作れればそれで良さそう。

Top comments (0)