目的
x86ベアメタルでBMP形式の画像を表示したいと思っています。
VBEという機能を使うと高解像度で画面表示を出来るようなので試してみます。
今回はBMPの画像と画面の解像度を完全に一致させることで変換処理を省きたいので、800×600で初期化します。
一旦BMPH画像を表示させることが目的なのでVBEの細かい設定仕様は一旦考えません。
コード
boot.asm及びenter.asmは筆者の以下の記事から持ってきます。
GRUBの画面表示仕組み
enter.asmの画面初期化処理のみ以下のように書き換えます
変更前
entry.asm
mov ax, 0x0003
int 0x10
変更後
entry.asm
; 800x600 24bpp (モード 0115h)
mov ax, 0x4F02 ; VBE Set Mode
mov bx, 0x4115 ; 0115h (24bpp) + ビット14
int 0x10
※QEMUなので一旦VRAMを0xFD000000と決め打ちしていますが、本来はBIOSの返り値を使う必要があります。
今後実機でやる予定なのでその時に考えます。
mainc.c
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
#define VRAM 0xFD000000
#define SCREEN_W 800
#define SCREEN_H 600
void kernel_main(){
volatile u32 *fb = (volatile u32 *)VRAM;
u8 *fb8 = (u8 *)fb;
for (int y = 0; y < 600; y++) {
for (int x = 0; x < 800; x++) {
u8 r, g, b;
if (y == 200 || y == 400) { r=255; g=255; b=255; } // 白
else if (y < 200) { r=0; g=0; b=255; } // 青
else if (y > 200 && y < 400) { r=255; g=0; b=0; } // 赤
else { r=0; g=255; b=0; } // 緑
// 24bppは BGR の順で書き込む
int p = (y * 800 + x) * 3;
fb8[p] = b;
fb8[p+1] = g;
fb8[p+2] = r;
}
}
while(1)asm volatile ("hlt");
}
nasm -f bin boot.asm -o boot.bin
nasm -f elf32 entry.asm -o entry.o
gcc -m32 -ffreestanding -c mainc.c -o mainc.o
ld -m elf_i386 -T linker.ld -o kernel.elf entry.o mainc.o
objcopy -O binary kernel.elf kernel.bin
cat boot.bin kernel.bin > disk.img
qemu-system-i386 -drive format=raw,file=disk.img -monitor stdio