2026年2月8日日曜日

Rust@Hello x86!!

Rust@Hello x86!!

OS自作をRustに切り替えるかはまだ模索中だけれど、まずはx86-pc上で「Hello x86!!」を表示するカーネルこと始めをしてみた。

やりたいこと

  • OSとカーネルはGitリポジトリを別にする
  • IBM PC/AT互換機上(QEMU)で動作させる
  • ブートにGNU GRUBを使用する
  • カーネルのファイル形式はELFを使用する

環境を作る

nightly版rustをインストールしておく

参考:付録G: Rustの作られ方と“Nightly Rust”

$ rustup install nightly

ディレクトリを作る

MochiOSというプロジェクトディレクトリ配下に作っていく。
とりあえず、OSで使用するカーネルは別プロジェクトとしたいので、depsディレクトリ内にkernelプロジェクトcargoで作る。
また、kernelはnightly版rustを使用する前提にしておく。

$ mkdir MochiOS
$ cd MochiOS
$ git init
$ mkdir deps
$ cd deps
$ touch .gitkeep
$ cargo new kernel
$ cd kernel
$ rustup override set nightly

OSプロジェクトではdeps配下のディレクトリを管理したくないので、.gitignore、deps/.gitkeepを作成しておく。

# .gitignore

/deps/*

今は作成しないけど、deps配下の各サブプロジェクトはクローンしてくるシェルスクリプトを作る予定。

「Hello x86!!」を表示するコードを書く

標準ライブラリの無効化、Panic処理の実装、VGAのテキストバッファに文字列「Hello x86!!」の書込みを行って無限ループ。

// MochiOS/deps/kernel/src/main.rs

#![no_std]
#![no_main]

use core::panic::PanicInfo;

const VGA_BUFFER: *mut u8 = 0xB8000 as *mut u8;

#[panic_handler]
fn panic( _info: &PanicInfo ) -> !
{
    loop {}
}

#[unsafe( no_mangle )]
pub extern "C" fn _start() -> !
{
    let str = b"Hello x86!!";

    for ( idx, &byte ) in str.iter().enumerate() {

        unsafe {
            *VGA_BUFFER.add( idx * 2 )     = byte;
            *VGA_BUFFER.add( idx * 2 + 1 ) = 0x0F;
        }

    }

    loop {}
}

multibootヘッダを書く

これ書いとけばGRUBがカーネルをロードしてくれるってよ。(自前でローダ用意しなくていいから楽だなぁ)

// MochiOS/deps/kernel/src/multiboot.rs

#[repr( C ) ]
pub struct MultibootHeader {
    magic   : u32,
    flags   : u32,
    checksum: i32,
}

#[unsafe( link_section = ".multiboot" )]
#[unsafe( no_mangle )]
pub static _MULTIBOOT_HEADER: MultibootHeader = MultibootHeader {
    magic   : 0x1BADB002,
    flags   : 0,
    checksum: -( 0x1BADB002 as i32 ),
};

ファイル追加したのでmain.rsにモジュール宣言を追記。

// MochiOS/deps/kernel/src/main.rs

module multiboot

コンパイルする

ターゲットファイルを作る

MochiOS/deps/kernel/src/x86_32.json(JSONってコメント書けないからパス表示を欄外に・・・)

{
    "llvm-target"         : "i686-unknown-none",
    "data-layout"         : "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128",
    "target-pointer-width": 32,
    "arch"                : "x86",
    "vendor"              : "unknown",
    "os"                  : "none",
    "linker"              : "rust-lld",
    "linker-flavor"       : "ld.lld",
    "disable-redzone"     : true,
    "panic-strategy"      : "abort"
}

リンカスクリプトを書く

// MochiOS/deps/kernel/src/x86_32.lds

ENTRY( _start )

MEMORY {
    KERNEL : ORIGIN = 0x00100000, LENGTH = 0x100000
}

SECTIONS {
    .multiboot : {
        KEEP( *( .multiboot ) )
    } > KERNEL

    .text : {
        *( .text* )
    } > KERNEL

    .rodata : {
        *( .rodata* )
    } > KERNEL

    .data : {
        *( .data* )
    } > KERNEL

    .bss : {
        *( .bss* )
        *( COMMON )
    } > KERNEL
}

cargoの設定を書く

# MochiOS/deps/kernel/.cargo/config.toml

[unstable]
build-std        = [ "core" ]
json-target-spec = true

[build]
target = "./src/x86_32.json"

[target.'cfg( all( target_arch = "x86" ) )']
rustflags = [ "-C", "link-arg=-Tsrc/x86_32.lds" ]

実行する

イメージファイルのディレクトリを作る

$ cd MochiOS
$ mkdir -p iso/boot/grub

カーネルを置く

$ copy deps/kernel/target/x86_32/debug/kernel iso/boot/

grub.confを作る

# MochiOS/iso/boot/grub/grub.cfg

set timeout=0
set default=0

menuentry "MochiOS" {
    multiboot /boot/kernel
    boot
}

イメージファイルを作る

$ grub-mkrescue -o mochios.iso iso/

QEMUで実行する

デスクトップ環境でなはないので、VNCサーバを立ち上げて別PCからリモート接続。

$ qemu-system-i386 -cdrom mochios.iso -vnc :0

enter image description here
できた。

手こずりpoints

ldスクリプトが反映されない

試行錯誤中にreadelf -a kernelして確認すると.multibootセクションが作られていなくて。
原因は、cargo君がファイル依存関係でldスクリプトを知らないので、更新されてもコンパイルし直しが発生しなかった。
なので、下記コマンドで対応。

$ cargo clean
$ cargo build

(っていうかtargetディレクトリの容量がえげつないなrust・・・coreとかbinutlもクロス先用にコンパイルしているからなんだろうけど)

流石に、手で毎回clean打つのはめんどくさいので、ldスクリプトファイルをcargo君に監視してもらうようにした。

# MochiOS/deps/kernel/Cargo.toml

[package]
build = "build.rs"
# MochiOS/deps/kernel/build.rs

fn main()
{
    println!( "cargo::rerun-if-changed=./src/x86_32.lds" );
}

grub-rescue実行してもISOファイルが生成されない

下記インストールで対応

$ sudo apt install grub-pc-bin xorriso
  • grub-pc-binは、「DebianやUbuntuなどのLinux環境において、BIOSベースのPCでGRUB 2ブートローダを使用するために必要な、GRUBのコアイメージ(モジュール)群を収録したバイナリパッケージ」だそう。
  • xorriso(えぐぞりっそ)は、「ISO 9660(Rock Ridge拡張対応)イメージの作成、操作、およびCD/DVD/BDメディアへの書き込みをコマンドラインで行う多機能ツール」だそう。

0 件のコメント:

コメントを投稿

Rust@Hello x86!!

Rust@Hello x86!! OS自作をRustに切り替えるかはまだ模索中だけれど、まずはx86-pc上で「Hello x86!!」を表示するカーネルこと始めをしてみた。 やりたいこと OSとカーネルはGitリポジトリを別にする...