はじめに
作りかけては断念し、というのを繰り返していたので、記録を兼ねて、記事にしていきます。
環境
今更、ブートローダーから書くのもだるいし、今時のOSっぽくないしということで、GRUBを使って起動させます。これで、アセンブリ言語を使う箇所が減らせます。
さらに、よくあるOS入門系の記事は、x86をターゲットに32bitOSを作っていますが、これも今時っぽくないので、x86_64をターゲットにしたいと思います。
なお、Bochsで、「The Multiboot Speci cation version 1.6」に準拠したものを起動させられなかったので、0.6.96準拠で行きたいと思います。
loader
GRUBに対応するには、multi boot headerが8192byte以内に存在している必要があります。それをloader.sで設定して上げる必要があります。
ついでに、なるべく早い段階でC言語で記述できるように、スタックポイントなどを指定して、メイン関数を呼び出します。
最低限の設定を行ったあと、C言語で記載した、カーネル本体にジャンプします。
loader.s
MAGIC_NUMBER equ 0x1BADB002
MAGIC_FLAGS equ 0x03
ALIGN_MODULE equ 0x00000000
CHECK_SUM equ -(MAGIC_NUMBER + MAGIC_FLAGS)
STACK_SIZE equ 0x1000 ; Kernel Stack Size
global loader
extern kmain
section .mbheader
align 8
mbheader:
dd MAGIC_NUMBER
dd MAGIC_FLAGS
dd CHECK_SUM
section .text
align 8
loader:
;;; Initilized Stack Point
mov esp, stack + STACK_SIZE
push ebx
push eax
call kmain
.loop:
hlt
JMP .loop
section .bss
align 8
stack:
resb STACK_SIZE
kernel.h
#ifndef __KERNEL_H__
#define __KERNEL_H__
typedef struct
{
unsigned int flags;
unsigned int mem_lower;
unsigned int mem_upper;
unsigned int boot_device;
unsigned int cmdline;
unsigned int mods_count;
unsigned int mods_addr;
unsigned int syms1;
unsigned int syms2;
unsigned int syms3;
unsigned int syms4;
unsigned int mmap_length;
unsigned int mmap_addr;
unsigned int drives_length;
unsigned int drives_addr;
unsigned int config_table;
unsigned int boot_loader_name;
unsigned int apm_table;
unsigned int vbe_control_info;
unsigned int vbe_mode_info;
unsigned short vbe_mode;
unsigned short vbe_interface_seg;
unsigned short vbe_interface_off;
unsigned short vbe_interrace_len;
} BOOTINFO;
void kmain(unsigned int magic, BOOTINFO *bootinfo);
#endif
kernel.c
#include <kernel.h>
void kmain(unsigned int magic, BOOTINFO *bootinfo)
{
}
link.ld
ENTRY(loader)
SECTIONS {
. = 0x00100000;
.mbheader ALIGN (0x1000):
{
_kernel_start = .;
*(.mbheader)
}
.text ALIGN (0x1000):
{
*(.text)
}
.rodata ALIGN (0x1000):
{
*(.rodata*)
}
.data ALIGN (0x1000):
{
*(.data)
}
.bss ALIGN (0x1000):
{
*(COMMON)
*(.bss)
_kernel_end = .;
}
}
初期化状態
カーネル本体にジャンプした時点で、下記のように設定されています。
- EAX 0x2BADB002
- EBX ブート情報を記録したアドレスへのポインタ
- CS 読み取り実行セグメント offset 0 limit 0xFFFFFFFF
- DS,ES,FS,GS,SS 読み取り書き込みセグメント offset 0 limit 0xFFFFFFFF
- A20GATE 有効
- CR0 PG clear PE set
- EFLAGS VM clear IF clear
今回のソース