1.实验环境:
1.1 系统环境
- Ubuntu 20.04.2.0 LTS
- vmware虚拟机
1.2 安装编译环境
- 安装汇编编译器
sudo apt-get install nasm
- 安装gcc(该命令会安装包括gcc在内的所有软件)
sudo apt install build-essential
2. HelloOS实现说明
2.1 HelloOS文件构成
- entry.asm
- 供grub调用的引导程序,用于设置CPU工作模式与工作环境,并调用C语言编写的main函数
main.c
- 打印字符串
#include "vgastr.h" void main() { printf("Hello OS!"); return; }
vgastr.c / vgastr.h
- 实现在显示屏上输出信息
void _strwrite(char *string) { char *p_strdst = (char *)(0xb8000); //指向显存开始的地址 while(*string) { *p_strdst = *string++; p_strdst += 2; //每两个字节对应一个字符,其中一个字节是字符的ASCII码,另一个字节为字符的的颜色值 } return; } void printf(char *fmt, ...) { _strwrite(fmt); return; }
hello.lds
- 链接器脚本,用于指导链接过程,设定不同程序段的布局
ENTRY(_start) OUTPUT_ARCH(i386) OUTPUT_FORMAT(elf32-i386) SECTIONS { . = 0x200000; __begin_start_text = .; .start.text : ALIGN(4) { *(.start.text) } __end_start_text = .; __begin_text = .; .text : ALIGN(4) { *(.text) } __end_text = .; __begin_data = .; .data : ALIGN(4) { *(.data) } __end_data = .; __begin_rodata = .; .rodata : ALIGN(4) { *(.rodata) *(.rodata.*) } __end_rodata = .; __begin_kstrtab = .; .kstrtab : ALIGN(4) { *(.kstrtab) } __end_kstrtab = .; __begin_bss = .; .bss : ALIGN(4) { *(.bss) } __end_bss = .; }
- Makefile
- 编译脚本
2.2 屏幕显示说明
若想使用屏幕显示出字符,则需要使用代码对显卡进行控制。
不论是集显、核显、独显,它们都支持VESA标准,该标准有两种工作模式:字符模式与图形模式。这些显卡为了兼容VESA标准,他们都会提供VGABIOS的固件程序。
2.2.1 显卡的字符模式
在字符模式下,屏幕将会被分为24行,每行80个字符,然后将这24 * 80个字符映射到从0xb8000地址开始的内存中,每两个字节对应一个字符,一个字节对应字符的ASCII码,一个字节对应字符的颜色。
更多关于显卡文本模式下输出字符,可参考下文的chapter 2:点击查看
2.3 部署HelloOS
部署之前,首先了解下HelloOS的引导流程
PC机的BIOS固化在主板上的ROM中,上电后第一条指令就是BIOS固件中的,它负责检测与初始化CPU,内存,主板,之后加载引导设备中的第一个扇区,到0x7c00地址开始的内存空间,然后跳转到0x7c00处执行指令。
本次实验使用的是GRUB引导程序。
2.3.1 准备文件
2.3.1.1 编译HelloOS
- 将生成的HelloOS.bin文件复制到boot文件夹下。(也可将bin文件放置在其他文件夹下,不过一般放在boot中)
sudo mv HelloOS.bin /boot/
2.3.1.2 修改启动项等待时间
- 修改默认启动项的等待时间,打开grub文件,修改GRUB_TIMEOUT参数,默认为10s
sudo gedit /etc/default/grub
- 修改之后使用以下命令更新文件设置,该命令会将/boot/grub/grub.cfg文件给初始化,若之前有所修改,则需要再次进行修改
sudo update-grub
2.3.1.3 虚拟机添加启动项
- 打开grub.cfg文件:
sudo gedit /boot/grub/grub.cfg
- 在文件中插入以下代码
- 代码之间使用的是空格,不能是tab键或其他字符(tab键将会导致启动时找不到相关命令)
menuentry 'HelloOS' { insmod part_msdos #GRUB加载分区模块识别分区 insmod ext2 #GRUB加载ext文件系统模块识别ext文件系统 set root='hd0,msdos5' #注意boot目录挂载的分区,这是我机器上的情况 multiboot2 /boot/HelloOS.bin #GRUB以multiboot2协议加载HelloOS.bin boot }
insmod 与 set root说明
set root=‘***’里面填写的是存放HelloOS.bin的文件夹,在 2.3.1.1 中其实说过,HelloOS.bin文件放在哪里都是可以的,不一定要放在/boot文件夹下。而set root=’'中填写的就是存放HelloOS.bin的文件夹所在的磁盘分区。
查找HelloOS.bin文件所在分区:
重启时长按ESC键,进入grub引导界面
按下c键进入命令交互模式
使用ls命令查看磁盘分区信息
使用ls (hdx,msdosx)/boot/ 命令查找HelloOS.bin文件,然后将包含有bin文件的磁盘写入set root参数
multiboot2说明
该参数是HelloOS.bin文件存放的路径,该参数设置错误的话,启动HelloOS时将会出现“HelloOS.bin not found”错误
boot挂载情况主要分为两种:独立分区单独挂载 与 属于根分区的一部分
使用df -h /boot/ 命令查看boot的挂载情况,也可使用df -h查看所有的挂在
属于根分区的一部分
multiboot2 /boot/HelloOS.bin
独立分区单独挂载
multiboot2 /HelloOS.bin
2.3.1.4 物理机添加启动项
- 参考 2.3.1.3 虚拟机添加启动项 进入grub引导界面,查看磁盘分区信息
- 这里物理机的磁盘分区为gpt方式,修改insmod参数
- insmod part_gpt
- 使用
ls (hdx,gptx)/
或ls (hdx,gptx)/boot/
命令进行查找bin文件(前者为单独分区,后者为属于根分区的一部分) - 启动代码
menuentry 'HelloOS' { insmod part_gpt #GRUB加载分区模块识别分区 insmod ext2 #GRUB加载ext文件系统模块识别ext文件系统 set root='hd0,gpt5' #注意boot目录挂载的分区,这是我机器上的情况 multiboot2 /HelloOS.bin #GRUB以multiboot2协议加载HelloOS.bin boot #GRUB启动HelloOS.bin }
- msdos与gpt这两种分区的区别:点击查看
HelloOS运行结果