软件工程实践 Blog9

软件工程实践 Blog9

2021SC@SDUSC


学习模块:计算机系统 —— 笔记 09
主要内容:储备系统原理的知识,自底向上的学习路线


011 设置工作模式与环境-1 启动初始化

对硬件抽象层进行初始化

从内核映像格式说起
一个内核工程肯定有多个文件组成,为了不让 GRUB 加载多个文件,因疲劳过度而产生问题,我们决定让 GRUB 只加载一个文件。

但是要把多个文件变成一个文件就需要封装,即把多个文件组装在一起形成一个文件。这个文件我们称为内核映像文件,其中包含二级引导器的模块,内核模块,图片和字库文件。为了这映像文件能被 GRUB 加载,并让它自身能够解析其中的内容,我们就要定义好具体的格式。如下图所示:

GRUB格式文件上图中的 GRUB 头有 4KB 大小,GRUB 正是通过这一小段代码,来识别映像文件的。另外,根据映像文件头描述符和文件头描述符里的信息,这一小段代码还可以解析映像文件中的其它文件。

映像文件头描述符和文件描述符是两个 C 语言结构体,如下所示:

//映像文件头描述符
typedef struct s_mlosrddsc
{
    u64_t mdc_mgic; //映像文件标识
    u64_t mdc_sfsum;//未使用
    u64_t mdc_sfsoff;//未使用
    u64_t mdc_sfeoff;//未使用
    u64_t mdc_sfrlsz;//未使用
    u64_t mdc_ldrbk_s;//映像文件中二级引导器的开始偏移
    u64_t mdc_ldrbk_e;//映像文件中二级引导器的结束偏移
    u64_t mdc_ldrbk_rsz;//映像文件中二级引导器的实际大小
    u64_t mdc_ldrbk_sum;//映像文件中二级引导器的校验和
    u64_t mdc_fhdbk_s;//映像文件中文件头描述的开始偏移
    u64_t mdc_fhdbk_e;//映像文件中文件头描述的结束偏移
    u64_t mdc_fhdbk_rsz;//映像文件中文件头描述的实际大小
    u64_t mdc_fhdbk_sum;//映像文件中文件头描述的校验和
    u64_t mdc_filbk_s;//映像文件中文件数据的开始偏移
    u64_t mdc_filbk_e;//映像文件中文件数据的结束偏移
    u64_t mdc_filbk_rsz;//映像文件中文件数据的实际大小
    u64_t mdc_filbk_sum;//映像文件中文件数据的校验和
    u64_t mdc_ldrcodenr;//映像文件中二级引导器的文件头描述符的索引号
    u64_t mdc_fhdnr;//映像文件中文件头描述符有多少个
    u64_t mdc_filnr;//映像文件中文件头有多少个
    u64_t mdc_endgic;//映像文件结束标识
    u64_t mdc_rv;//映像文件版本
}mlosrddsc_t;

#define FHDSC_NMAX 192 //文件名长度
//文件头描述符
typedef struct s_fhdsc
{
    u64_t fhd_type;//文件类型
    u64_t fhd_subtype;//文件子类型
    u64_t fhd_stuts;//文件状态
    u64_t fhd_id;//文件id
    u64_t fhd_intsfsoff;//文件在映像文件位置开始偏移
    u64_t fhd_intsfend;//文件在映像文件的结束偏移
    u64_t fhd_frealsz;//文件实际大小
    u64_t fhd_fsum;//文件校验和
    char   fhd_name[FHDSC_NMAX];//文件名
}fhdsc_t;

有了映像文件格式,我们还要有个打包映像的工具,我给你提供了一个 Linux 命令行下的工具,你只要明白使用方法就可以,如下所示:

lmoskrlimg -m k -lhf GRUB头文件 -o 映像文件 -f 输入的文件列表
-m 表示模式 只能是k内核模式
-lhf 表示后面跟上GRUB头文件
-o 表示输出的映像文件名 
-f 表示输入文件列表
例如:lmoskrlimg -m k -lhf grubhead.bin -o kernel.img -f file1.bin file2.bin file3.bin file4.bin 

准备虚拟机

打包好了映像文件,我们还有很重要的一步配置——准备虚拟机。

开发应用跟开发操作系统有什么不同呢?在开发应用程序时,可以在 IDE 中随时编译运行应用程序,然后观察结果状态是否正确,中间可能还要百度一下查找相关资料。但是你开发操作系统时,不可能写 5 行代码之后就安装在计算机上,重启计算机去观察运行结果,这非常繁琐,也很浪费时间。好在我们有虚拟机这个好帮手。虚拟机用软件的方式实现了真实计算机的全部功能特性,它在我们所使用的 Linux 下,其实就是个应用程序。使用虚拟机软件我们就可以在现有的 Linux 系统之上开发、编译、运行我们的操作系统了,省时且方便。

安装虚拟机

这里我们一致约定使用甲骨文公司的VirtualBox虚拟机。经过测试,我发现 VirtualBox 虚拟机有很多优点,它的功能相对完善、性能强、BUG 少,而且比较稳定。在现代 Linux 系统上安装 VirtualBox 虚拟机是非常简单的,你只要在 Linux 发行版中找到其应用商店,在其中搜索 VirtualBox 就行了。我们作为专业人士一条命令可以解决的事情,为什么要用鼠标点来点去呢,多浪费时间。所以,你只要在终端中输入如下命令就行了,我假定你安装了 Ubuntu 系的 Linux 发行版,这里 Ubuntu 的版本不做规定。

sudo apt-get install virtualbox-6.1

手工生产硬盘

大多数虚拟机都是用文件来模拟硬盘的,即主机系统(HOST OS 即你使用的物理机系统 )下特定格式的文件,虚拟机中操作系统的数据只是写入了这个文件中。

生产虚拟硬盘

其实虚拟机只是用特定格式的文件来模拟硬盘,所以生产虚拟硬盘就变成了生成对应格式的文件,这就容易多了。要建立 100MB 的硬盘,这意味着要生成 100MB 的大文件。下面我们用 Linux 下的 dd 命令(用指定大小的块拷贝一个文件,并在拷贝的同时进行指定的转换)生成 100MB 的纯二进制的文件(就是 1~100M 字节的文件里面填充为 0 ),如下所示:

dd bs=512 if=/dev/zero of=hd.img count=204800

;bs:表示块大小,这里是512字节
;if:表示输入文件,/dev/zero就是Linux下专门返回0数据的设备文件,读取它就返回0
;of:表示输出文件,即我们的硬盘文件。
;count:表示输出多少块

执行以上命令就可以生成 100MB 的文件。文件数据为全 0。由于我们不用转换数据,就是需要全 0 的文件,所以 dd 命令只需要这几个参数就行。

格式化虚拟硬盘

虚拟硬盘也需要格式化才能使用,所谓格式化就是在硬盘上建立文件系统。只有建立了文件系统,现有的成熟操作系统才能在其中存放数据。可是,问题来了。虚拟硬盘毕竟是个文件,如何让 Linux 在一个文件上建立文件系统呢?这个问题我们要分成三步来解决。第一步,把虚拟硬盘文件变成 Linux 下的回环设备,让 Linux 以为这是个设备。其实在 Linux 下文件可以是设备,设备可以是文件。下面我们用 losetup 命令,将 hd.img 变成 Linux 的回环设备,代码如下:

sudo losetup /dev/loop0 hd.img

第二步,将 losetup 命令用于设置回环设备。回环设备可以把文件虚拟成 Linux 块设备,用来模拟整个文件系统,让用户可以将其看作硬盘、光驱或软驱等设备,并且可用 mount 命令挂载当作目录来使用。我们可以用 Linux 下的 mkfs.ext4 命令格式化这个 /dev/loop0 回环块设备,在里面建立 EXT4 文件系统。

sudo mkfs.ext4 -q /dev/loop0  

第三步,我们用 Linux 下的 mount 命令,将 hd.img 文件当作块设备,把它挂载到事先建立的 hdisk 目录下,并在其中建立一个 boot,这也是后面安装 GRUB 需要的。如果能建立成功,就说明前面的工作都正确完成了。

手工生成硬盘的原因: 这是因为 mount 命令只能识别在纯二进制文件上建立的文件系统,如果使用虚拟机自己生成的硬盘文件,mount 就无法识别我们的文件系统了

sudo mount -o loop ./hd.img ./hdisk/ ;挂载硬盘文件
sudo mkdir ./hdisk/boot/ ;建立boot目录

进行到这里,我们会发现 hdisk 目录下多了一个 boot 目录,这说明我们挂载成功了。

安装 GRUB

正常安装系统的情况下,Linux 会把 GRUB 安装在我们的物理硬盘上,可是我们现在要把 GRUB 安装在我们的虚拟硬盘上,而且我们的操作系统还没有安装程序。所以,我们得利用一下手上 Linux(HOST OS),通过 GRUB 的安装程序,把 GRUB 安装到指定的设备上(虚拟硬盘)。

安装 GRUB 具体分为两步,如下所示:

第一步挂载虚拟硬盘文件为loop0回环设备
sudo losetup /dev/loop0 hd.img
sudo mount -o loop ./hd.img ./hdisk/ ;挂载硬盘文件
第二步安装GRUB
sudo grub-install --boot-directory=./hdisk/boot/ --force --allow-floppy /dev/loop0
;--boot-directory 指向先前我们在虚拟硬盘中建立的boot目录。
;--force --allow-floppy :指向我们的虚拟硬盘设备文件/dev/loop0

可以看到,现在 /hdisk/boot/ 目录下多了一个 grub 目录,表示我们的 GRUB 安装成功。请注意,这里还要在 /hdisk/boot/grub/ 目录下建立一个 grub.cfg 文本文件,GRUB 正是通过这个文件内容,查找到我们的操作系统映像文件的。

在这个grub.cfg文件里写入如下内容:

menuentry 'HelloOS' {
insmod part_msdos
insmod ext2
set root='hd0,msdos1' #我们的硬盘只有一个分区所以是'hd0,msdos1'
multiboot2 /boot/HelloOS.eki #加载boot目录下的HelloOS.eki文件
boot #引导启动
}
set timeout_style=menu
if [ "${timeout}" = 0 ]; then
  set timeout=10 #等待10秒钟自动启动
fi

转换虚拟硬盘格式

你可能会好奇,我们前面好不容易生产了 mount 命令能识别的虚拟硬盘,这里为什么又要转换虚拟硬盘的格式呢?这是因为这个纯二进制格式只能被我们使用的 Linux 系统识别,但不能被虚拟机本身识别,但是我们最终目的却是让这个虚拟机加载这个虚拟硬盘,从而启动其中的由我们开发的操作系统。好在虚拟机提供了专用的转换格式的工具,我们只要输入一行命令即可:

VBoxManage convertfromraw ./hd.img --format VDI ./hd.vdi
;convertfromraw 指向原始格式文件
;--format VDI  表示转换成虚拟需要的VDI格式

安装虚拟硬盘

好了,到这里我们已经生成了 VDI 格式的虚拟硬盘,这正是我们虚拟机所需要的。然而虚拟硬盘必须要安装虚拟机才可以运行,也就是这个 hd.vdi 文件要和虚拟机软件联系起来

因为我们之前在建立虚拟机时并没有配置硬盘相关的信息,所以这里需要我们进行手工配置。配置虚拟硬盘分两步:第一步,配置硬盘控制器,我们使用 SATA 的硬盘,其控制器是 intelAHCI;第二步,挂载虚拟硬盘文件。具体操作如下所示:

#第一步 SATA的硬盘其控制器是intelAHCI
VBoxManage storagectl HelloOS --name "SATA" --add sata --controller IntelAhci --portcount 1
#第二步
VBoxManage closemedium disk ./hd.vdi #删除虚拟硬盘UUID并重新分配
#将虚拟硬盘挂到虚拟机的硬盘控制器
VBoxManage storageattach HelloOS --storagectl "SATA" --port 1 --device 0 --type hdd --medium ./hd.vdi

因为 VirtualBox 虚拟机用 UUID 管理硬盘,所以每次挂载硬盘时,都需要删除虚拟硬盘的 UUID 并重新分配。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值