本小节,做一个实验,利用grub来启动一个最简单的小系统,这个系统的功能非常简单,先使用汇编初始化好C语言的运行环境(主要是配置好栈),然后向显示器输出"Welcom to Tiny System!"这几个字符。
注意,本小节笔记只是为了简单做实验的目的,其中有很多细节暂时还不会提及。在后续笔记中,会详细做解释。如果不清楚某些细节也可以跳过。
实验环境: Oracle VM VirtualBox虚拟机运行ubuntu 16.04
继续跟着LMOS大神学习,早日完成这个项目
X86上电引导Tiny System流程极简概述
此流程仅为了Tiny System阐述,很多细节都不会说,仅列出对本实验理解所需的重要步骤,如果想要了解详细的流程,CSDN上有很多大神有详细分析,请自行搜索,感谢。
1. X86上电后,CPU的程序计数器PC的值来自BIOS固件。BIOS负责初始化硬件设备如CPU,时钟,内存,基本外设等。
2. BIOS加载可引导设备的GRUB到内存,并且跳转到GRUB程序
3. GRUB运行后,加载硬盘分区中的Tiny System文件
4. GRUB工作完成,跳转至Tiny System的入口地址运行
5. Tiny System汇编部分代码初始化X86,关闭中断,创建C语言运行环境
6. Tiny System汇编部分工作完成,跳转到C语言入口函数
7. Tiny Sytem C语言部分将“Tiny System”输出到显示器上
关于ubuntu下的grub配置文件详细说明,有兴趣的可参考这里:
实验过程
ubuntu启动显示grub菜单
由于ubuntu默认的grub配置不会显示菜单,我们需要先将其打开。网上有很多文章讲这个操作,本笔记仅简单描述,这里也给出一个参考链接
sudo update-grub将配置更新
重启ubuntu,应该就可以看到grub菜单了
能显示grub菜单后,我们再进入后面的步骤
Tiny System汇编部分
Tiny System汇编代码主要是为了创建好C语言运行环境,由于C语言编译后的函数,都需要栈来实现函数的调用和返回,因此汇编部分最核心的工作是将栈指针初始化好。
关于X86汇编,目前不需要了解太多,这里给一篇参考,快速了解一下即可
MULBOOT_HEADER_FLAGS EQU 0x00010003
MULBOOT_HEADER2_MAGIC EQU 0xE85250D6 ;GRUB2 multiboot magic
global _start
extern main
[section .start.text]
[bits 32]
_start:
jmp _entry
ALIGN 8
mbt2_hdr:
dd MULBOOT_HEADER2_MAGIC
dd 0 ;architecture 0 - i386
dd mbt2_hdr_end - mbt2_hdr ; header_length
dd -(MULBOOT_HEADER2_MAGIC + 0 + (mbt2_hdr_end - mbt2_hdr))
dw 2, 0
dd 24
dd mbt2_hdr
dd _start
dd 0
dd 0
dw 3, 0
dd 12
dd _entry
dd 0
dw 0, 0
dd 8
mbt2_hdr_end:
ALIGN 8
_entry:
cli ;clear interrupts
in al, 0x70 ;disable NMI
or al, 0x80
out 0x70,al
lgdt [GDT_PTR]
jmp dword 0x8 :_32bits_mode
_32bits_mode:
;initialize all registers needed by C
mov ax, 0x10
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
xor eax,eax
xor ebx,ebx
xor ecx,ecx
xor edx,edx
xor edi,edi
xor esi,esi
xor ebp,ebp
xor esp,esp
;Initalize stack pointer register
mov esp,0x9000
call main
halt_step:
halt
jmp halt_step
GDT_START:
knull_dsc: dq 0
kcode_dsc: dq 0x00cf9e000000ffff
kdata_dsc: dq 0x00cf92000000ffff
k16cd_dsc: dq 0x00009e000000ffff
k16da_dsc: dq 0x000092000000ffff
GDT_END:
GDT_PTR:
GDTLEN dw GDT_END-GDT_START-1
目前这个汇编文件关键的功能在注释中给出。总体来说,汇编做的事情主要有:
1. 定义grub mutliboot2 的header
2. 关闭普通中断和NMI
3. 创建C语言运行环境
4. 跳转到C的main函数
现在这个阶段也不用过于纠结不懂的地方。在后续笔记中会深入细节讲解。
Tiny SytemC语言部分
#define VGA_DIAPLAY_BUFFER 0xb8000
void vga_display_string(char *string)
{
char *vga_buffer = (char *)VGA_DIAPLAY_BUFFER;
while (*string != '\0') {
*vga_buffer = *string++;
vga_buffer += 2;//VGA buffer format: ASCII + Character color
}
}
void main()
{
vga_display_string("Welcome to Tiny System");
}
C语言部分主要是向VGA字符模式下的buffer中写入字符串的ASCII码,显卡会将这块区域内的buffer显示到屏幕上。关于显卡的字符模式说明,参考这里
Tiny System Makefile
MAKEFLAGS = -sR
MKDIR = mkdir
RMDIR = rmdir
CP = cp
CD = cd
DD = dd
RM = rm
ASM = nasm
CC = gcc
LD = ld
OBJCOPY = objcopy
ASMBFLAGS = -f elf -w-orphan-labels
CFLAGS = -c -Os -std=c99 -m32 -Wall -Wshadow -W -Wconversion -Wno-sign-conversion -fno-stack-protector -fomit-frame-pointer -fno-builtin -fno-common -ffreestanding -Wno-unused-parameter -Wunused-variable
LDFLAGS = -s -static -T tiny_sys.lds -n -Map TinySystem.map
OJCYFLAGS = -S -O binary
TINYSYSTEM_OBJS :=
TINYSYSTEM_OBJS += tiny_system_entry.o main.o
TINYSYSTEM_ELF = TinySystem.elf
TINYSYSTEM_BIN = TinySystem.bin
.PHONY : build clean all link bin
all: clean build link bin
clean:
$(RM) -f *.o *.bin *.elf
build: $(TINYSYSTEM_OBJS)
link: $(TINYSYSTEM_ELF)
$(TINYSYSTEM_ELF): $(TINYSYSTEM_OBJS)
$(LD) $(LDFLAGS) -o $@ $(TINYSYSTEM_OBJS)
bin: $(TINYSYSTEM_BIN)
$(TINYSYSTEM_BIN): $(TINYSYSTEM_ELF)
$(OBJCOPY) $(OJCYFLAGS) $< $@
%.o : %.s
$(ASM) $(ASMBFLAGS) -o $@ $<
%.o : %.c
$(CC) $(CFLAGS) -o $@ $<
运行make命令(Makefile请在“本小节代码”一节中去下载,或者自己手动写也可以),生成TinySystem.bin。
让Grub启动Tiny System
修改grub.cfg添加启动项
df /boot查看boot分区所使用的块设备,我的ubuntu系统输出如下
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda5 65274444 11657876 50271112 19% /
grub配置sda,要换成hd0,msdos,因此我们要在grub.cfg中插入下面的内容添加一个启动项菜单
menuentry 'TinySytem' {
insmod part_msdos
insmod ext2
set root='hd0,msdos5'
multiboot2 /boot/TinySystem.bin
boot
}
添加后,重启ubuntu,应该可以看到grub菜单多出一项
选择TinySystem后,可以看到屏幕上输出了“Welcome to Tiny System!”
各位如果按照这个笔记里的C语言main函数代码写,会发现字符不是红色的。这是留给各位自己去实现的一个功能,去看如何修改程序让字符颜色变化。
本小节代码
TinySystem_1stDemo
参考资料
Grub Multiboot规范_加油小懒的博客-CSDN博客_grub multiboot
[操作系统原理与实现]Multiboot与GRUB_cloudblaze的博客-CSDN博客_grub multiboot