HelloOS
PC机的引导流程
PC机加电 -> PC机 BIOS 固件 -> 加载可引导设备中的GRUB -> GRUB引导 -> 加载硬盘分区中的 Hello OS 文件
Hello OS 引导汇编代码
PC机上电后的第一条指令就是BIOS固件中的,它负责检测和初始化CPU、内存和主板平台,然后加载引导设备(硬盘)中的第一个扇区数据,到0x7c00地址开始的内存空间执行指令,在我们这里就是GRUB引导程序
MBT_HDR_FLAGS EQU 0x00010003 ;1
MBT_HDR_MAGIC EQU 0x1BADB002 ;多引导协议头魔数
MBT_HDR2_MAGIC EQU 0xe85250d6 ;第二版多引导协议头魔数
global _start ;导出_start符号
extern main ;导入外部的main函数符号
[section .start.text] ;定义.start.text代码节
[bits 32] ;汇编成32位代码
_start:
jmp _entry
ALIGN 8
mbt_hdr:
dd MBT_HDR_MAGIC
dd MBT_HDR_FLAGS
dd -(MBT_HDR_MAGIC+MBT_HDR_FLAGS)
dd mbt_hdr
dd _start
dd 0
dd 0
dd _entry
;以上是GRUB所需要的头
ALIGN 8
mbt2_hdr:
DD MBT_HDR2_MAGIC
DD 0
DD mbt2_hdr_end - mbt2_hdr
DD -(MBT_HDR2_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
DD 0, 0
DD 8
mbt2_hdr_end:
;以上是GRUB2所需要的头
;包含两个头是为了同时兼容GRUB、GRUB2 40
ALIGN 8
_entry:
;关中断
cli
;关不可屏蔽中断
in al, 0x70
or al, 0x80
out 0x70, al
;重新加载GDT
lgdt [GDT_PTR]
jmp dword 0x8 :_32bits_mode
_32bits_mode:
;下面初始化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
;初始化栈,C语言需要栈才能工作
mov esp,0x9000
;调用C语言函main
call main
;让CPU停止执行指令
halt_step:
halt
jmp halt_step
GDT_START:
knull_dsc:dq 0
kcode_dsc:dq 0x00cf9e000000ffff
kdata_dsc:dq 0x00cf92000000ffff
k16cd_dsc:dq 0x0000f9e000000ffff
k16da_dsc:dq 0x0000f92000000ffff
GDT_END:
GDT_PTR:
GDTLEN dw GNT_END-GDT_START-1
GDTBASE dd GDT_START
/lesson01/HelloOS/entry.asm
1.代码 1~40行 ,用汇编定义的GRUB的多引导协议头,就是一定格式的数据,Hello OS是用GRUB引导的,要遵循GRUB的多引导协议标准,才能让GRUB识别我们的Hello OS
2.代码44~52行,关掉中断
3.代码54~73行,初始化cpu的寄存器和C语言的运行环境
4.代码78~87行,GDT_START开始的,是cpu工作模式所需要的数据
Hello OS 的主函数
#include "vgastr.h"
void main()
{
printf("Hello OS!");
return;
}
控制计算机屏幕
显卡都支持一种VESA的标准,这种标准下有两种工作模式:字符模式和图形模式。显卡为了兼容这种标准,自己提供一种叫VGABIOS的固件程序
字符模式工作细节:把屏幕分成24行,每行80个字符,把24*80个位置映射到以0x8000地址开始的内存中,每两个字节对应一个字符,其中一个字节是字符的ASCII码,另一个字节为字符的颜色值
void _strwrite(char* string)
{
char* p_strdst = (char*)(0xb8000);//指向显存的开始地址
while(*string)
{
*p_strdst = *string++;
p_strdst += 2;
}
return ;
}
void printf(char* fmt, ...)
{
_strwrite(fmt);
return ;
}
编译和安装 Hello OS
make 工具
make 是一个工具程序,他读取"makefile"文件,这个文件中写好了构建软件的规则,make根据这些规则自动化构建软件
makefile文件中的规则:首先一个或者多个构建目标称为"target"
目标后面紧跟着用于构建该目标所需要的文件
目标下面是构建该目标所需要的命令及参数
Linux都默认自带这个make程序
下面是一个例子
CC = gcc #定义一个宏CC 等于gcc
CFLAGS = -c #定义一个宏 CFLAGS 等于-c
OBJS_FILE = file.c file1.c file2.c file3.c file4.c #定义一个宏
.PHONY : all everything #定义两个伪目标all 、 everything
all:everything #伪目标all依赖于伪目标everything
everything :$(OBJS_FILE) #伪目标everything依赖于OBJS_FILE.
#而OBJS_FILE是宏会被替换成file.c #file1.c file2.c file3.c file4.c
%.o : %.c
$(CC) $(CFLAGS) -o $@ $<
.PHONY 定义为伪目标,伪目标,就是它不代表一个真正的文件名,在执行make 的时候可以指定这个目标来执行其所在的规则定义的命令,伪目标可以依赖一个伪目标或者一个文件
%.o : %.c 表示所有以".o"结尾的文件依赖与所有以".c"结尾的文件
编译
安装 Hello OS
经过上述流程,我们得到了 Hello OS.bin 文件,还要让GRUB能够找到它,才能让计算机启动时加载它。这个过程为安装,安装程序要自己写
GRUB启动时会加载,grub.cfg
的文本文件,根据其中的内容执行相应的操作,其中一部分是启动项
GRUB首先会显示启动项,选择启动项后,GRUB根据启动项对应的信息,加载OS文件到内存
menuentry 'HelloOS'{
insmod part_msdos #GRUB加载分区模块识别分区
insmod ext2 #GRUB加载ext文件系统模块识别ext文件系统
set root='hd0,msdos1'#注意boot目录挂载的分区
multiboot2 /boot/HelloOS.bin #GRUB以multiboot2协议加载HelloOS.bin
boot #GRUB启动该HelloOS.bin
}