RustでVGAに画像(色)を出すまで
―― UEFIに迷い込み、VGAが「OSの入口」だと気づいた話 ――
※ 本記事は個人環境(VirtualBox / QEMU / Windows)での検証結果をまとめたものです。
※ UEFI / VGA の挙動は環境や実装により異なる場合があります。
※ 本記事は「Rustで画面を出すまで」の技術記録です。
はじめに
RustでOS開発を始めると、最初にぶつかる壁は 「画面が出ない」 ことだ。
UEFI Framebuffer、Graphics Output Protocol、ESP、ISO、VirtualBox……。
調べれば調べるほど「正しいが遠回りな道」に迷い込む。
しかし、ある時気づいた。
VGAは、すでに“OSとして成立する最短ルート”だった。
この記事では、
なぜUEFIで詰んだのか
なぜVGAは「完成していた」のか
RustでVGAに色を出す最小構成
を、実体験ベースでまとめる。
前提環境
OS: Windows 11
Rust: nightly
エミュレータ: QEMU
ターゲット: x86_64-unknown-none
ブート方式: legacy / VGA text mode
UEFIでやろうとして詰んだ話
最初は「今どきだからUEFIでやるべき」と思い、
x86_64-unknown-uefi
uefi / uefi-services
GOP (Graphics Output Protocol)
ESP 作成
BOOTX64.EFI
VirtualBox / QEMU
を一通り触った。
結果:
ビルドは通る
EFIはできる
でも 何も表示されない
仮想環境ごとの差異が多すぎる
「OS以前の世界」で消耗する
ここで気づいた。
UEFIで作っていたのは OS ではなく、
UEFIアプリケーションだった。
「OSを作りたい」ならVGAでいい
VGA(0xB8000)は、
BIOSが初期化済み
文字・色が即出る
依存が少ない
QEMUで一発
つまり、
OSとして「立ち上がった感」を最短で得られる
RustでVGAに出す最小コード
Cargo.toml
[package]
name = "rustos"
version = "0.1.0"
edition = "2021"
[dependencies]
bootloader = { version = "0.9.34", features = ["vga_320x200"] }
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
src/main.rs
#![no_std]
#![no_main]
use core::panic::PanicInfo;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
#[no_mangle]
pub extern "C" fn _start() -> ! {
let vga = 0xb8000 as *mut u8;
let msg = b"HELLO RUST OS";
for (i, &c) in msg.iter().enumerate() {
unsafe {
*vga.add(i * 2) = c;
*vga.add(i * 2 + 1) = 0x0F; // white on black
}
}
loop {}
}
実行(QEMU)
qemu-system-x86_64 -kernel target/x86_64-unknown-none/debug/rustos
👉 この瞬間、画面に文字が出る

ここで初めて「OSになった」
main が呼ばれる
画面が出る
ループで生き続ける
これはもう OSの最初の一歩。
UEFIでやっていた時は、
仕様と格闘
ツールと格闘
仮想環境と格闘
だった。
VGAでは、
「コードを書いた結果が、即画面に出る」





背景画像を出したくなったら?
ここから先は本当に「OS開発」。
VGA graphics mode (Mode 13h)
フレームバッファ管理
自前メモリ管理
ドライバ
つまり、
UEFIでやろうとしてたことは
OSとしては“後半戦”だった
結論
UEFIは「間違い」ではない
でも OS入門としては重すぎる
VGAはすでに「完成していた」
RustでOSを作っている実感を得るなら VGAが最短
次にやること(予告)
VGA 320x200 モードで画像表示
RustでBMPを直描き
VGA → Framebuffer 移行
「UEFIに戻る意味」が分かる瞬間
Github
https://github.com/kyo-na/rustos-vga-256-demo
