源码下载:HelloOS.zip-OS文档类资源-CSDN文库
运行环境:VMware+Ubuntu20(虚拟机的安装和配置问题请参考:VMware虚拟机安装 Linux(Ubuntu)教程_一顿吃不饱的博客-CSDN博客)
Hello OS的引导程序用的是GRUB(多重操作系统启动管理器),当Ubuntu安装好以后,GRUB就已经存在了。
1.Hello OS的引导流程 简单解释一下,PC 机 BIOS 固件是固化在 PC 机主板上的 ROM 芯片中的,掉电也能保存,PC 机上电后的第一条指令就是 BIOS 固件中的,它负责检测和初始化 CPU、内存及主板平台,然后加载引导设备(大概率是硬盘)中的第一个扇区数据,到 0x7c00 地址开始的内存空间,再接着跳转到 0x7c00 处执行指令,在我们这里的情况下就是 GRUB 引导程序。
2.HelloOS的引导汇编代码 c是高级语言,它不能直接操作特定的硬件,所以我们用汇编代码处理c语言的工作环境。
MBT_HDR_FLAGS EQU 0x00010003 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 DW 0, 0 DD 8 mbt2_hdr_end: ;以上是GRUB2所需要的头 ;包含两个头是为了同时兼容GRUB、GRUB2 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 0x00009e000000ffff k16da_dsc: dq 0x000092000000ffff GDT_END: GDT_PTR: GDTLEN dw GDT_END-GDT_START-1 GDTbase dd GDT_START
以上的汇编代码分为 4 个部分:
- 代码 1~40 行,用汇编定义的 GRUB 的多引导协议头,其实就是一定格式的数据,我们的 Hello OS 是用 GRUB 引导的,当然要遵循 GRUB 的多引导协议标准,让 GRUB 能识别我们的 Hello OS。之所以有两个引导头,是为了兼容 GRUB1 和 GRUB2。
- 代码 44~52 行,关掉中断,设定 CPU 的工作模式。
- 代码 54~73 行,初始化 CPU 的寄存器和 C 语言的运行环境。
- 代码 78~87 行,GDT_START 开始的,是 CPU 工作模式所需要的数据。
#include "vgastr.h"
void main()
{
printf("Hello OS!");
return;
}
4.控制计算机屏幕
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;
}
printf 函数直接调用了 _strwrite 函数,而 _strwrite 函数正是将字符串里每个字符依次定入到 0xb8000 地址开始的显存中,而 p_strdst 每次加 2,这也是为了跳过字符的颜色信息的空间。
5.编译和安装Hello OS 的编译过程
经过上述流程,我们就会得到 Hello OS.bin 文件,但是我们还要让 GRUB 能够找到它,才能在计算机启动时加载它。这个过程我们称为安装,不过这里没有写安装程序,得我们手动来做。
HelloOS的启动项
menuentry 'HelloOS' {
insmod part_msdos #GRUB加载分区模块识别分区
insmod ext2 #GRUB加载ext文件系统模块识别ext文件系统
set root='hd0,msdos4' #注意boot目录挂载的分区,这是我机器上的情况
multiboot2 /boot/HelloOS.bin #GRUB以multiboot2协议加载HelloOS.bin
boot #GRUB启动HelloOS.bin
}
把上面启动项的代码插入到你的 Linux 机器上的 /boot/grub/grub.cfg 文件末尾,然后把 Hello OS.bin 文件复制到 /boot/ 目录下,一定注意这里是追加不是覆盖。最后重启计算机,你就可以看到 Hello OS 的启动选项了。
6.操作过程图解 6.1下载源码后解压 6.2打开终端,执行命令make -f Makefile 6.3将生成的HelloOS.bin文件拷贝到/boot文件夹下执行命令
sudo mv HelloOS.bin /boot
这个过程需要输入密码
6.4在/boot/grub/grub.cfg中添加menuentry执行命令
sudo gedit /boot/grub/grub.cfg
**注意:**添加的时候要根据自己的虚拟机情况修改代码
那么如何查看boot目录的挂载分区呢?
请参考链接:Linux如何查看boot目录的挂载分区呢_一顿吃不饱的博客-CSDN博客
6.5进入GRUB引导界面,运行HelloOS如何进入GRUB引导界面?
重启虚拟机的时候长按esc键
成功运行最简操作系统HelloOS



