8.操作系统实战——环境配置,用文件模拟硬盘(生成文件,格式化,安装GRUB,转换虚拟硬盘格式)

内核映像

GRUB 引导程序如果想一次性加载内核显然不现实,因为内核由多个文件组成,所以我们要尽可能把多个文件封装成一个文件。
这个被封装的文件我们称为内核映像文件
其中包括:
二级引导器模块
内核模块
以及图片和字库文件
8.操作系统实战——环境配置,用文件模拟硬盘(生成文件,格式化,安装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 

虚拟机

强烈建议使用ubuntu20.04、18.04不要用16.04
约定使用甲骨文公司的VirtualBox虚拟机。经过测试,我发现 VirtualBox 虚拟机有很多优点,它的功能相对完善、性能强、BUG 少,而且比较稳定。


sudo apt-get install virtualbox

然后在专家模式新建一个虚拟电脑
注意类型和版本选择,以及不需要虚拟硬盘
8.操作系统实战——环境配置,用文件模拟硬盘(生成文件,格式化,安装GRUB,转换虚拟硬盘格式)

手工生产硬盘

虚拟机中还没有硬盘,没有硬盘虚拟机就没地方加载数据,我们当然不是要买一块硬盘挂上去,而是要去手工生产一块硬盘。你马上就会发现,从零开始生产一块虚拟硬盘,这比从零开始写一个操作系统简单得多。
大多数虚拟机都是用文件来模拟硬盘的,即主机系统(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:表示输出多少块

8.操作系统实战——环境配置,用文件模拟硬盘(生成文件,格式化,安装GRUB,转换虚拟硬盘格式)
我们可以在home里面看见,多了一个100mb的文件
8.操作系统实战——环境配置,用文件模拟硬盘(生成文件,格式化,安装GRUB,转换虚拟硬盘格式)

格式化虚拟硬盘

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

sudo losetup /dev/loop0 hd.img

注意:
这一步可能出现:
8.操作系统实战——环境配置,用文件模拟硬盘(生成文件,格式化,安装GRUB,转换虚拟硬盘格式)

 losetup -a 命令看下,是不是自己用到的 loop 已经被使用

8.操作系统实战——环境配置,用文件模拟硬盘(生成文件,格式化,安装GRUB,转换虚拟硬盘格式)
上述说明5是空的,用5:

sudo losetup /dev/loop5 hd.img

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


sudo mkfs.ext4 -q /dev/loop5  

此时在Linux系统左边可以明显发现多了一块设备:
8.操作系统实战——环境配置,用文件模拟硬盘(生成文件,格式化,安装GRUB,转换虚拟硬盘格式)
3.将 hd.img 文件当作块设备,把它挂载到事先建立的 hdisk 目录下,并在其中建立一个 boot
我们用 Linux 下的 mount 命令,将 hd.img 文件当作块设备,把它挂载到事先建立的 hdisk 目录下,并在其中建立一个 boot,这也是后面安装 GRUB 需要的。如果能建立成功,就说明前面的工作都正确完成了。
mount 命令只能识别在纯二进制文件上建立的文件系统,如果使用虚拟机自己生成的硬盘文件,mount 就无法识别我们的文件系统了。

先创建一个hdisk目录,随便在哪儿创建都行

sudo mkdir hdisk

然后挂载硬盘文件,相当于给我们创建的二进制文件变成回环设备之后,建立文件系统,然后与这个二进制文件做一个映射


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

第一步会发现多了一个卷轴
第二步这个卷轴里多了一个boot目录,挂载成功。(你打开这个hdisk文件就自动跳转到这个卷轴)

安装GRUB

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

sudo grub-install --boot-directory=./hdisk/boot/ --force --allow-floppy /dev/loop5;
--boot-directory 指向先前我们在虚拟硬盘中建立的boot目录。;
--force --allow-floppy :指向我们的虚拟硬盘设备文件/dev/loop0

如果遇到EFI的问题:
添加参数:

sudo grub-install --target=i386-pc --boot-directory=./hdisk/boot/ --force --allow-floppy /dev/loop5 ;

正常报两个警告:
8.操作系统实战——环境配置,用文件模拟硬盘(生成文件,格式化,安装GRUB,转换虚拟硬盘格式)

但是还可能出现问题:

错误: /usr/lib/grub/i386-pc/modinfo.sh doesn't exist. Please specify --target or --directory.

这代表文件名和默认的不太一样

我们去到gurb这个文件夹里,发现没有i386这个文件:

执行以下操作:

sudo apt-get download grub-pc-bin
dpkg-deb -R grub-pc-bin_2.02~beta2-36ubuntu3.16_amd64.deb grub/
sudo mv grub/usr/lib/grub/i386-pc/ /usr/lib/grub/

就从网上下一个gurb的文件,然后解压产生一个i386

再次执行
通过 GRUB 的安装程序,把 GRUB 安装到指定的设备上:

sudo grub-install --target=i386-pc --boot-directory=./hdisk/boot/ --force --allow-floppy /dev/loop0

如果执行到这一步还有错,推荐使用ubuntu20.04可能较低版本的有问题。

建立一个 grub.cfg 文本文件(在gurb文件夹里)

sudo vi grub.cfg

menuentry 'xyOS' {
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=5 #等待5秒钟自动启动
fi

转换虚拟硬盘格式

纯二进制格式只能被Linux系统识别,但不能被虚拟机识别。所以我们要让虚拟机识别这个虚拟硬盘。


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

8.操作系统实战——环境配置,用文件模拟硬盘(生成文件,格式化,安装GRUB,转换虚拟硬盘格式)

安装虚拟硬盘

虚拟硬盘必需被安装到虚拟机菜可以运行,所以我们要让这个文件和虚拟机软件联系起来:
配置虚拟硬盘分两步:
第一步,配置硬盘控制器,我们使用 SATA 的硬盘,其控制器是 intelAHCI;
第二步,挂载虚拟硬盘文件。


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

这三个指令输入之后没有任何反应,没有报错就是最好的反应。。。

VBoxManage startvm xyos

回车运行:就能选择我们的 HelloOS,GRUB 就会加载我们的 HelloOS,但是会出现如下错误。

上面的错误显示,GRUB 没有找到 HelloOS.eki 文件,这是因为我们从来没有向虚拟硬盘中放入 HelloOS.eki 文件,所以才会失败。
但这是我们最成功的失败,因为我们配置好了虚拟机,手动建造了硬盘,并在其上安装了 GRUB,到这里我们运行测试环境已经准备好了
8.操作系统实战——环境配置,用文件模拟硬盘(生成文件,格式化,安装GRUB,转换虚拟硬盘格式)

总结

  1. 了解了内核映像格式
  2. 方便我们测试操作系统
  3. 手动建立虚拟硬盘,对其格式化,安装GURB引导器。

具体步骤:
分为两步:第一步:生成文件安装gurb:

  1. 生成一个纯二进制文件
  2. 将其格式化为回环设备(这样Linux认为其是个设备而不是文件)在该回环设备中建立EXT4文件系统
  3. 挂载硬盘文件,建立boot目录,并在其中安装GRUB,写入一个cfg文件(设置硬盘分区和boot应该加载的文件,引导其启动)

第二步,处理虚拟硬盘:

  1. 将虚拟硬盘转换成虚拟机能识别的格式
  2. 配置虚拟硬盘:控制器设置以及挂载虚拟硬盘的文件
上一篇:如何阅读uboot/grub/linux等内核源码


下一篇:原生js基础课程