首页 > 其他分享 >手搓操作系统-如何创建虚拟磁盘并装载内核(超详细版)

手搓操作系统-如何创建虚拟磁盘并装载内核(超详细版)

时间:2024-11-22 10:43:30浏览次数:3  
标签:操作系统 GRUB hd0 分区 磁盘镜像 内核 磁盘 disk

写在前面:

本篇是完整的在Linux环境下,创建一个虚拟磁盘,并且将内核安装到磁盘并用虚拟机运行的过程。需要对bootstrap过程有一定的基础知识。遇到不懂的概念,如MBR,Grub等请务必参考笔者的另一篇文章操作系统架构- Linux主机从按下电源键到加载内核,都经历了什么?(超详细版)此外,读者还需要对文件系统有基本的理解。

1. 创建磁盘镜像

1)通过在 Shell 提示符下输入以下命令创建磁盘镜像(提示符以 $ 表示)
注意:以下示例创建一个 30MB 的磁盘镜像,设置为虚拟磁盘,具有 60 个柱面、16 个磁头和每轨道 63 个扇区。可以根据需要调整配置。每个扇区大小为 512 字节,共有 60*16*63 个扇区。

$ dd if=/dev/zero of=disk.img bs=512 count=60480

参数解释:

  • dd 是一个低级字节拷贝工具,用于创建一个虚拟磁盘文件。
  • if=/dev/zero:从设备 /dev/zero 读取数据。/dev/zero 是 Linux 中的一个特殊设备文件,提供无穷的零字节流,保证磁盘文件为空。
  • of=disk.img:输出到文件 disk.img,即创建的磁盘镜像文件。
  • bs=512:每次写入的块大小是 512 字节(等于硬盘扇区的大小)。
  • count=60480:创建 60480 个扇区,总大小为 60480 * 512 = 30MB

2.用fdisk在虚拟磁盘中设置分区表

(示例中创建一个主分区,用于引导内核镜像,并将其类型设置为 Linux ext2/ext3 原生文件系统)。

$ fdisk disk.img

使用 fdisk 工具在磁盘镜像中创建分区表。fdisk 的操作实际上就是修改分区表中对应分区条目的内容。分区表定义了磁盘的逻辑布局,决定了如何划分磁盘空间。(详细请参考MBR的partion table)

Command (m for help): x

x 进入专家模式,允许我们手动修改磁盘的几何参数(柱面、磁头和扇区)

Expert command (m for help): h
Number of heads (1-256, default 255): 16
Expert command (m for help): s
Number of sectors (1-63, default 63): 63
Expert command (m for help): c
Number of cylinders (1-1048576): 60

设置磁头数为 16(一个磁盘柱面中有 16 个磁头),每个磁头下有 63 个扇区,磁盘有 60 个柱面。计算磁盘大小: 磁盘总容量 = 柱面数 × 磁头数 × 每磁头扇区数 × 每扇区字节数
60×16×63×512≈30MB

Expert command (m for help): r

设置好磁盘参数后,输入上面的指令r返回普通分区模式,然后创建主分区:

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-60, default 1): 
Using default value 1
Last cylinder or +size or +sizeM or +sizeK (1-60, default 60): 
Using default value 60

创建一个主分区,并且设置分区编号为1。然后会提示输入起始和结束柱面,直接回车选择默认值。这个分区覆盖整个磁盘(从柱面 1 到柱面 60)

Command (m for help): t
Selected partition 1
Hex code (type L to list codes): 83

将分区类型设置为 0x83,即 Linux 原生文件系统(如 ext2/ext3)

Command (m for help): a
Partition number (1-4): 1

设置刚才创建的分区1为可引导分区。输入 a,表示用户选择了设置或取消分区的引导标志(bootable flag)。(其实就是修改分区 1 的分区表条目(partition entry)中的标识符字段为 0x80)引导标志用于指示某个分区是可引导的(即启动时 BIOS 会将该分区作为引导设备)。

Command (m for help): w

保存并且退出fdisk。

完成后,fdisk 会尝试更新分区表。如果失败(例如内核未加载新分区表),会提示警告:

WARNING: Re-reading the partition table failed...

这通常不会影响后续操作,新分区表会在下一次重启时生效。

3. 创建文件系统

首先确保回环设备模块已加载:

$ modprobe loop

如果出现错误(FATAL: Module loop not found),说明该模块已经内置到内核中,可以跳过此命令。 

然后需要找到分区的偏移量:

$ fdisk -u disk.img

 使用 fdisk 查看磁盘镜像的分区表,选择 p 打印分区信息:

Disk disk.img: 30 MB, 31457280 bytes
16 heads, 63 sectors/track, 60 cylinders, total 61440 sectors
Units = sectors of 1 * 512 = 512 bytes

   Device Boot      Start         End      Blocks   Id  System
disk.img1   *          63       60479       30208+  83  Linux

找到分区起始位置(即 Start 列的值),它是以扇区为单位的偏移量。计算字节偏移量: 字节偏移量=Start值×每扇区字节数。示例中 Start=63,每扇区 512 字节,因此: 字节偏移量=63×512=32256。完成分区信息查看后,输入 q 退出 fdisk。

注:在早期的硬盘中,63 是每磁道扇区数的默认值(柱面-磁头-扇区模型,CHS),因此从第 63 扇区开始分区可以避免覆盖 MBR 或其他引导数据。起始扇区从 63 开始对齐时,正好位于第二个磁道的开头,这样可以避免交叉访问磁道,从而提升性能。对于现代存储设备(如 SSD),起始扇区通常会从 2048(1MB 对齐)开始以适应较大的块大小。

$ losetup -o 32256 /dev/loop0 disk.img

然后按上面的代码关联分区。losetup 命令用于将一个普通文件(如磁盘镜像文件)关联到一个回环设备(如 /dev/loop0),从而使该文件看起来像一个块设备,便于进一步操作。这里是从磁盘镜像文件 /path/to/disk.img 的偏移量 32256 字节 开始,将其绑定到回环设备 /dev/loop0。绑定后,/dev/loop0 会代表镜像文件的一个特定分区,操作 /dev/loop0 相当于操作该分区。

注:回环设备是一个虚拟的设备,专门用来对文件进行类似磁盘的操作。简单来说,它将文件“伪装”成设备,然后操作系统通过回环设备,使用标准的块设备接口(如读写操作)与文件交互。

$ mke2fs /dev/loop0

然后按照上面的代码,在 /dev/loop0 上创建 ext2 文件系统。操作系统通过 /dev/loop0 接口定位到磁盘镜像文件的对应分区(从偏移量 32256 开始)。mke2fs 在这个分区上创建 ext2 文件系统,格式化后可以用来存储文件。

注:因为镜像文件本身可能包含多个分区(由分区表决定)。所以必须用 losetup 将分区绑定到回环设备。然后对这个“分区设备”(即 /dev/loop0)创建文件系统。在挂载之前,我们的磁盘镜像没有文件系统(只是一个空的二进制文件或原始分区数据),因此需要先通过 losetup 绑定到回环设备,再用工具(如 mke2fs)创建文件系统。

$ losetup -d /dev/loop0

设置完成后,运行上面命令卸载(释放)loop 设备。卸载回环设备可以确保所有数据写入都完成。如果之后需要重新操作同一个磁盘镜像文件,可以再次绑定回环设备,重新分配资源。如果不卸载直接重新绑定,可能会导致系统冲突或设备忙(device is busy)错误。

4. 挂载镜像并复制文件

这一步的目的是将虚拟磁盘的分区挂载到主机操作系统上,使其像普通文件系统一样操作。

首先加载文件系统模块:

$ modprobe ext2

即,使用 modprobe ext2 命令加载 ext2 文件系统模块。如果系统提示 FATAL: Module ext2 not found 错误,表示文件系统模块已经被编译进了内核,无需额外加载。在现代 Linux 系统中,ext2 支持通常是内置的,特别是在简化发行版(如 Puppy Linux)中,因此可能会跳过此步骤。

然后创建挂载点目录: 

$ mkdir /mnt/C
$ mount disk.img /mnt/C -t ext2 -o loop,offset=32256

挂载磁盘分区到 /mnt/C。挂载(Mount)是将一个文件系统整合到操作系统的目录结构中的过程。挂载完成后,文件系统内容就可以像普通文件夹一样访问。将磁盘镜像挂载到 /mnt/C 后,访问 /mnt/C 就相当于访问磁盘镜像中的文件内容。使用 mount 命令挂载磁盘镜像,指定文件系统类型为 ext2(必须明确告诉操作系统磁盘镜像的文件系统类型,否则系统无法正确解析磁盘内容。,并使用回环设备模式挂载磁盘镜像的分区(回环设备将该文件模拟成一个磁盘分区),设置偏移量(offset)为分区起始地址。

为什么需要挂载:

disk.img 是一个 虚拟磁盘镜像文件,它模拟了一个真实磁盘的结构,包括:分区表(Partition Table)分区(Partitions)文件系统(File System)它本质上是一个普通的文件,但内容被设计为符合磁盘的格式,和电脑上的真实硬盘不同,它不能被操作系统直接识别和使用。真实磁盘(如电脑硬盘或 U 盘)连接到电脑时,操作系统可以自动识别它们,并将其挂载到系统中,比如自动在 /mediaD:/ 显示磁盘内容。虚拟磁盘镜像文件disk.img)是一个普通文件,操作系统无法自动知道如何解析它。通过挂载,操作系统会将 disk.img 看作一个磁盘。找到它的文件系统内容(比如 ext2),并且将这些内容映射到一个挂载点目录。指令里-o loop 参数的作用是创建一个临时的回环设备,将普通文件视为块设备。

5. 在磁盘镜像上安装 GRUB 引导程序

Grub作为引导加载程序,用于加载后续的内核镜像。
我们将引导加载程序的所有处理阶段文件复制到虚拟磁盘的适当子目录,然后通过 GRUB Shell 配置引导加载程序脚本。

$ mkdir /mnt/C/boot
$ mkdir /mnt/C/boot/grub
$ cp /boot/grub/{stage1,e2fs_stage1_5,stage2} /mnt/C/boot/grub
$ grub

以上将 GRUB 的引导阶段文件 stage1e2fs_stage1_5stage2 复制到虚拟磁盘的 grub 目录中。

然后在本机用启动 GRUB 的交互式 Shell:

$ grub

GRUB Shell 里运行的命令主要是为 stage2 服务的。这些命令将磁盘镜像文件 /path/to/disk.img 关联为 GRUB 的设备 (hd0) ,设置设备 (hd0) 的几何参数,设置 GRUB 根设备为第一个分区 (hd0,0),最后安装 GRUB 引导加载程序到设备 (hd0)。这些 GRUB 命令的核心目标就是在安装阶段生成一个完整的引导配置,并通过 setup 命令完成设置,并将 GRUB 的 stage1 引导代码写入 MBR

grub> device (hd0) disk.img
grub> geometry (hd0) 60 16 63
grub> root (hd0,0)
grub> setup (hd0)

执行完上述命令后,输入quit退出grub shell。 

以下是一些细节解释:

GRUB 使用 (hdX,Y) 的形式来标识磁盘和分区。

  • (hd0) 表示第一个磁盘。
  • (hd1) 表示第二个磁盘,以此类推。
  • (hd0,0) 表示第一个磁盘的第一个分区。

在实际硬件中,(hd0) 通常是主硬盘(如 /dev/sda)当使用虚拟磁盘(如 disk.img)时,GRUB 不知道 disk.img 是哪个磁盘。因此,需要通过device命令告诉 GRUB:把 disk.img 当成是 GRUB 的第一个磁盘 (hd0)。GRUB 内部的后续操作(如 geometrysetup)会通过 (hd0) 来访问 disk.img,而不是直接处理磁盘文件路径。

Grub不读取分区表中的几何信息,需要依赖用户手动提供磁盘的几何结构,即geometry (hd0) 60 16 63。如果几何参数错误:GRUB 可能会将引导文件(如 stage1 或内核)定位到错误的位置

root (hd0,0)告诉 GRUB 根设备(root)是 第一个磁盘的第一个分区,即 (hd0,0)。这段命令告诉 GRUB:去第一个磁盘的第一个分区中查找引导文件(例如 menu.lstgrub.cfg

6. 复制内核并创建菜单

$ cp my_kernel /mnt/C/boot/
$ nano /mnt/C/boot/grub/menu.lst

复制编译好的内核文件my_kernel到磁盘镜像。配置 GRUB 的启动菜单 menu.lstmenu.lst 是 GRUB 的配置文件,用于定义启动菜单项和内核加载方式。

菜单示例:

title MemOS-2
root (hd0,0)
kernel /boot/my_kernel
  • title My Linux Kernel: 定义引导菜单的标题为 "My Linux Kernel"。
  • root (hd0,0): 指定 GRUB 根设备为 (hd0,0),即虚拟磁盘的第一个分区。
  • kernel /boot/my_kernel: 告诉 GRUB 引导内核镜像文件 /boot/my_kernel

注:为什么还要设置 root(hd0,0)?因为之前在 GRUB Shell 中设置 root (hd0,0) 仅影响当前 GRUB Shell 的工作环境,是安装引导加载程序时所引用的设备路径。退出 GRUB Shell 后,这些设置并不会被保存下来。现在root(hd0,0)是为了启动时GRUB定位到目标分区。

 

7.用QEMU虚拟机运行内核

现在可以使用虚拟磁盘文件在任意 PC 模拟器中运行,例如 QEMU。笔者在puppy linux环境下使用下面命令运行。读者请根据自己的linux配置运行虚拟机。

用虚拟机装载磁盘: 

qemu-system-i386 -hda disk.img

此时会启动qemu的虚拟机服务端,需要另外打开一个客户端来查看;

./root/vnc/opt/Tigervnc/bin/vncviewer 127.0.0.1:5900

上图就是Grub成功读取到内核后的启动菜单画面。 

标签:操作系统,GRUB,hd0,分区,磁盘镜像,内核,磁盘,disk
From: https://blog.csdn.net/qq_44252574/article/details/143870401

相关文章

  • Linux内核中unlikely宏的作用
    Linux内核中unlikely宏的作用在Linux内核中,unlikely宏是一个非常重要的工具,它主要用于指导编译器进行代码优化,以提高程序的执行效率。unlikely宏的定义与作用定义:unlikely宏通常定义为__builtin_expect(!!(x),0),其中x是你要判断的表达式。作用:告诉编译器,表达式x的结果......
  • Linux内核中的PAGE_SHIFT
    Linux内核中的PAGE_SHIFT什么是PAGE_SHIFT?在Linux内核中,PAGE_SHIFT是一个非常重要的宏,它定义了一个页的大小,通常是2的幂次方。这个值表示了虚拟地址空间中一个页的偏移量占用了多少位。换句话说,它告诉我们一个页的大小是多少字节。PAGE_SHIFT的作用页大小的确定:PAGE_SHIFT......
  • linux之磁盘管理
    磁盘管理1.磁盘分类机械硬盘:盘片主轴传动手臂做机械运动类似DVD固态硬盘:内部是主板和U盘类似2.硬盘大小3.5英寸:台式机2.5英寸:笔记本服务器3.硬盘接口IDE接口过时scsi接口过时sata接口台式机3.0nvme接口固态硬盘SAS接口企业级4.硬盘存储......
  • 腾讯通RTX升级版方案:支持Linux内核国产系统及移动端
    一、腾讯通RTX继续使用的核心痛点作为国内最早一批内网即时通讯软件,腾讯通RTX在政企单位中曾占据重要地位。然而,自2015年停止更新后,不仅遗留了大量BUG,用户体验和功能也逐渐难以满足企业需求。以下是继续使用腾讯通RTX的主要痛点:●不兼容国产系统与移动端:RTX仅支持Windows和Mac,......
  • 内核同步机制与用户空间同步机制,它们有所不同?
    在操作系统中,同步机制是核心设计之一,其目的是管理并发任务,防止数据竞争和资源冲突。同步机制可以分为两类:内核同步机制和用户空间同步机制。虽然它们都用于协调并发,但在实现方式、性能和使用场景上存在显著差异。本文将从基本概念、设计原理、实现方式、性能对比和典型使用......
  • PATH 命令用于显示或设置可执行文件的搜索路径,帮助操作系统或命令行环境找到你需要运
    path|MicrosoftLearnC:\Users\Administrator>PATH/?为可执行文件显示或设置一个搜索路径。PATH[[drive:]path[;...][;%PATH%]PATH;键入PATH;清除所有搜索路径设置并指示cmd.exe只在当前目录中搜索。键入PATH但不加参数,显示当前路径。将%PATH%包括在新的路径......
  • subst 是 Windows 操作系统中的一个命令行工具,它允许用户将一个文件夹或目录映射为虚
    subst|MicrosoftLearnsubst/?将路径与驱动器号关联。SUBST[drive1:[drive2:]path]SUBSTdrive1:/D drive1:    指定要分配路径的虚拟驱动器。 [drive2:]path 指定物理驱动器和要分配给虚拟驱动器的路径。 /D      删除被替换的(虚拟)......
  • label 是一个用于 设置或更改磁盘分区的标签(卷标)的命令。卷标是一个可以帮助你识别存
    label|MicrosoftLearn LABEL/?创建、更改或删除磁盘的卷标。LABEL[drive:][label]LABEL[/MP][volume][label] drive:     指定驱动器号。 label     指定卷标。 /MP      指定卷应被视为装入点或卷名。 volume  ......
  • icacls 是 Windows 操作系统中用于管理文件和目录的访问控制列表(ACL)命令行工具。它可
    icacls|MicrosoftLearnicacls是Windows操作系统中用于管理文件和目录的访问控制列表(ACL)命令行工具。它可以用来查看、修改、备份和恢复文件和文件夹的权限设置。权限控制是Windows安全体系的重要组成部分,icacls是在命令行下管理这些权限的一种方式。1.什么是 icacls?......
  • NSIS (Nullsoft Scriptable Install System) 是一个开源的、灵活且高度可定制的安装包
     NSIS(NullsoftScriptableInstallSystem)是什么?NSIS(NullsoftScriptableInstallSystem)是一个开源的、灵活且高度可定制的安装包制作工具,用于在Windows操作系统上创建安装程序。它由Nullsoft公司开发,并以其轻量级、可扩展性和脚本驱动的特性而广受欢迎。NSIS允......