可以被GRUB启动的简单内核
1. 准备开发环境
apt install build-essential nasm grub-pc-bin xorriso
2. 项目结构
myos/
├── boot/
│ ├── boot.asm # 汇编启动代码
│ └── grub.cfg # GRUB配置文件
├── kernel/
│ └── main.c # 主内核代码
├── linker.ld
└── Makefile # 构建脚本
3. 引导代码 (boot/boot.asm)
boot.asm
; boot.asm - 多引导头定义
section .multiboot
align 4
; 多引导头定义
multiboot_header:
dd 0x1BADB002 ; 魔数
dd 0x00 ; 标志
dd -(0x1BADB002 + 0x00) ; 校验和
global start
extern kernel_main ; 声明在C代码中定义的主函数
section .text
start:
; 设置栈指针
mov esp, stack_top
; 调用C内核
call kernel_main
; 如果内核返回,进入无限循环
cli
hlt
section .bss
align 16
stack_bottom:
resb 16384 ; 16KB栈空间
stack_top:
4. 内核 (kernel/main.c)
main.c
// VGA文本模式缓冲区地址
volatile unsigned short *vga_buffer = (unsigned short *)0xB8000;
const int VGA_COLS = 80;
const int VGA_ROWS = 25;
// 清屏函数
void clear_screen() {
for (int i = 0; i < VGA_COLS * VGA_ROWS; i++) {
vga_buffer[i] = (unsigned short)0x0F00 | ' ';
}
}
// 打印字符串函数
void print_string(const char *str, int row, int col) {
int index = row * VGA_COLS + col;
for (int i = 0; str[i] != '\0'; i++) {
vga_buffer[index++] = (unsigned short)0x0F00 | str[i];
}
}
// 内核主函数
void kernel_main() {
clear_screen();
print_string("Hello from MyOS Kernel!", 12, 30);
// 无限循环
while (1);
}
5. GRUB配置文件 (boot/grub.cfg)
set timeout=0
set default=0
menuentry "MyOS" {
clear
multiboot /boot/myos.bin
boot
}
6. Maklefile
# 目标名称
KERNEL := myos.bin
ISO := myos.iso
# 工具链
ASM := nasm
CC := gcc
LD := ld
GRUB_MKRESCUE := grub-mkrescue
# 编译选项
ASMFLAGS := -f elf32
CFLAGS := -m32 -ffreestanding -nostdlib -Wall -Wextra -c
LDFLAGS := -m elf_i386 -T linker.ld -nostdlib
# 源文件
BOOT_SRC := boot/boot.asm
KERNEL_SRC := kernel/main.c
OBJS := boot/boot.o kernel/main.o
all: $(ISO)
$(ISO): $(KERNEL)
mkdir -p isodir/boot/grub
cp $(KERNEL) isodir/boot/$(KERNEL)
cp boot/grub.cfg isodir/boot/grub
$(GRUB_MKRESCUE) -o $(ISO) isodir
rm -rf isodir
$(KERNEL): $(OBJS)
$(LD) $(LDFLAGS) -o $(KERNEL) $(OBJS)
boot/boot.o: $(BOOT_SRC)
$(ASM) $(ASMFLAGS) -o $@ $<
kernel/main.o: $(KERNEL_SRC)
$(CC) $(CFLAGS) -o $@ $<
clean:
rm -f $(OBJS) $(KERNEL) $(ISO)
run: $(ISO)
qemu-system-x86_64 -cdrom $(ISO)
.PHONY: all clean run
7. 链接器脚本 (linker.ld)
ENTRY(start)
SECTIONS {
. = 1M;
.text : ALIGN(4K) {
*(.multiboot)
*(.text)
}
.rodata : ALIGN(4K) {
*(.rodata)
}
.data : ALIGN(4K) {
*(.data)
}
.bss : ALIGN(4K) {
*(COMMON)
*(.bss)
*(.stack)
}
}
工作原理
- 引导过程:
- GRUB加载内核时,会查找多引导头
- 找到后,GRUB将控制权交给我们的汇编启动代码
- 汇编代码设置栈并调用C内核
- 内核功能:
- 清屏并在屏幕中央显示"Hello from MyOS Kernel!"
- 使用VGA文本模式缓冲区直接写入显存