admin管理员组文章数量:1794759
从零开始制作Linux
提到制作Linux,大家都能想到如雷贯耳、大名鼎鼎的Linux from scratch。但Linux from scratch的复杂性不是普通人能轻易掌握的,对于初学者来说,任何步骤出现不一致,会让初学者遇到挫拆,攻破LFS的信心越来越低。
本文教大家制作一个比LFS更简单的Linux系统,只有Grub、Linux kernel和最小的根文件系统initrd,原理和过程都非常简单。大家可以在这个基础的Linux之上,再增加其它的功能,逐步走向LFS。
制作Linux,首先该系统是放到磁盘上的,所以涉及启动引导操作系统的知识,我们使用著名的Grub引导程序来实现,Grub执行之后,由它来加载OS kernel和文件系统。 对于OS kernel,我们利用比较新版本的kernel代码来编译即可,而根文件系统,我们使用一个工具来生成最小的initrd。
整个制作过程,首先都有一个磁盘,这个磁盘可以是软盘,可以是USB,也可以是SSD磁盘或者HDD。但考虑到很多朋友身边没有这些东西,我们使用Qemu来试验,原理与直实硬件完全一样,唯一不同的是Qemu的磁盘可以用Host OS的文件来代替。
计算机启动过程在制作过程中,难免会无法理解纷繁复杂的操作过程,到底为什么需要这样操作,这需要对计算启动过程的原理有些基本的认识。计算机是如何启动的,这个问题在网上可以搜到大量文章,可以参考阮一峰大牛写的《计算机是如何启动的?》,我将关键过程列在这里:
简化版本启动过程,BIOS是主机提供的,而Bootloader,OS kernel和initrd都需要制作安装。
制作涉及的软件说明本文使用Qemu来验证,所以需要Qemu模拟的硬盘(实际是Linux的一个磁盘文件),Qemu提供BIOS功能,所以只需要安装Bootloader, OS kernel和initrd,各组件选用如下表所示:
Bootloader | Grub | 2.00 |
OS kernel | linux kernel | 4.9 |
initrd | mkinitramfs | xx |
下面是制作过程是涉及软件的版本
Ubuntu | 12.04 | 直接安装 |
grub-install | 2.00~rc1 | 源码编译安装 |
qemu | 2.10.0 | 源码编译安装 |
fdisk | 2.20.1 | 直接安装 |
losetup | xxx | 直接安装 |
使用dd命令,创建一个64M大小的文件,命令如下:
dd if=/dev/zero of=disk.img bs=1M count=64
运行过程如图1所示:
图1:dd命令运行过程 步骤2:对磁盘分区,整个磁盘只建一个分区使用fdisk命令对disk.img磁盘进行分区,使用n命令创建新的、主分区,该分区为整个磁盘大小,命令如下:
fdisk disk.img
fdisk命令交互过程如图2所示:
图2:fdisk命令运行过程 步骤3:将磁盘分区关联到/dev/loop7设备如果你稍为对磁盘结构有点了解,应该如何磁盘最开始扇区是MBR,里面有分区表,记录磁盘上有多少分区,每个分区从哪个扇区开始,以及分区占用多少扇区,往往第一个分区的开始扇区并不是从第2个扇区开始。
我们使用fdisk -l disk.img命令可以看到该磁盘只有一个主分区,是从第2048个扇区开始:
ivan@ivan:~/minilinux$ fdisk -l disk.img Disk disk.img: 67 MB, 67108864 bytes 41 heads, 32 sectors/track, 99 cylinders, total 131072 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0xa711cdff Device Boot Start End Blocks Id System disk.img1 2048 131071 64512 83 Linux我们接下来要在该分区建立文件系统,以及往里面放kernel和initrd,这一步需要将该分区与直接的磁盘设备关联,才能对该分区进行格式化和文件拷贝。使用losetup命令将该分区与一个/dev/loop7设备进行关联,命令如下:
losetup -o 1048576 /dev/loop7 disk.img
-o表示该分区在disk.img的偏移量(字节为单,即2048 x 512 = 1048576 )
命令运行如图3所示:
图3:losetup运行过程 步骤4:格式化分区和挂载分区接下来将分区格式化为ext3,命令如下:
mkfs.ext3 /dev/loop7
mkfs.ext3命令运行过程如图4所示:
图4:mkfs.ext3命令运行过程格式化后,将该分区挂载到mnt目录(在工作目录创建mnt目录,或者直接使用系统提供的/mnt均可,本文使用前者):
mkdir mnt mount -t ext3 /dev/loop7 ./mnt/
mount命令运行过程如图5所示:
图5:mount命令运行过程 步骤5:安装grub磁盘和分区已经做完了,下一步是安将Grub,安装命令如下:
grub-install –boot-directory=./mnt/boot/ –target=i386-pc –modules=part_msdos disk.img
运行结果如图6所示:
图6:grub-install命令运行过程运行grub-install命令之后,会将disk.img磁盘第一个扇区修改成MBR,同时将grub代码安装到第一个分区之前的扇区里(通常是0号到64号扇区之间),最后将grub代码运行所需要其它模块和配置文件保存到 ./mnt/boot/grub目录下。
步骤6:下载、编译内核首先在kernel官网下载linux-4.9.tar.gz文件,如下图7所示:
图7:下载kernel然后使用默认配置编译x86_64内核和拷贝到distk.img磁盘的 boot/目录,命令如下:
make x86_64_defconfig make bzImage -j4 sudo cp arch/x86/boot/bzImage ~/minilinux/mnt/boot/
上述命令运行过程如图8所示:
图8:内核编译和拷贝过程 步骤7:制作initrd使用mkinitramfs命令可以制作简化版本的文件系统, 使用mkinitramfs命令生成极简的initrd,放到boot目录下,命令如下:
mkinitramfs -o ./mnt/boot/initrd
运行过程如图9所示:
图9:生成initrd根文件系统 步骤8:编写grub.cfg,让Grub引导kernel运行万事俱备,只欠东风,Grub、kernel和initrd都已准备好的,剩下的事件就是写grub.cfg配置文件,告诉Grub从哪个目录可以找到bzImage和initrd文件,具体命令如下:
cat - > ./mnt/boot/grub/grub.cfg << EOF menuentry “FreshLinux” { linux (hd0,msdos1)/boot/bzImage console=tty0 initrd (hd0,msdos1)/boot/initrd } EOF
上述是非交互式命令,它的工作是用vim编辑mnt/boot/grub/grub.cfg文件,增加引导bzImage和initrd的描述,交互式的过程如图10所示:
图10:编辑mnt/boot/grub/grub.cfg过程
hd0表示第一个硬盘,而msdos1表示该硬盘的第一个分区(注:Grub对硬盘和分区的标识略有不同,硬盘从编号0开始,而分区却从编号1开始)。
linux (hd0,msdos1)/boot/bzImage console=tty0 表示:系统第一个硬盘,第一个分区的boot/bzImage文件是内核压缩镜像,而后面的console=tty0是内核启动参数,告诉内核输出到控制台上,而非图形化界面。
initrd (hd0,msdos1)/boot/initrd 表示:系统第一个硬盘,第一个分区的boot/initrd是根文件系统。
到此为止,Linux已经制作完成,只需将解挂载/dev/loop7即可将 刚刚建立的文件内容刷新到disk.img磁盘文件上,命令如下:
umount /dev/loop7 losetup -d /dev/loop7
步骤9:从磁盘运行LinuxOK,包含完整系统的Linux磁盘(disk.img)已制作完成,使用qemu将它运行起来,命令如下:
qemu-system-x86_64 -hda disk.img
然后进入Grub界面,选择我们刚刚制作的FreshLinux,按回车运行。过程如图11所示:
图11: qemu启动和grub操作过程接下来进入kernel启动,接着运行init进程,最后运行sh进程,等待用户输入命令,如图12是输入ls和pwd命令的运行过程:
[图12:运行ls和pwd命令过程大功告成,一个极简的Linux系统构建完成了……
自动化脚本建议大家挽起袖子,将上述过程一步步运行,感受DIY带来的乐趣。如果制作过程中遇到问题,可以试试下面这个自动化脚本。
#!/bin/bash dd if=/dev/zero of=disk.img bs=1M count=64 fdisk disk.img << EOF n p w EOF losetup -o 1048576 /dev/loop7 disk.img mkfs.ext3 /dev/loop7 mkdir ./mnt mount -t ext3 /dev/loop7 ./mnt/ mkdir -p ./mnt/boot/grub grub-install --boot-directory=./mnt/boot/ --target=i386-pc --modules=part_msdos disk.img mkinitramfs -o ./mnt/boot/initrd # 请根据内核编译路径进行修改 cp /home/ivan/kernel/linux-4.9/arch/x86/boot/bzImage ./mnt/boot cat - > ./mnt/boot/grub/grub.cfg << EOF menuentry "FreshLinux" { linux (hd0,msdos1)/boot/bzImage console=tty0 initrd (hd0,msdos1)/boot/initrd } EOF umount /dev/loop7 losetup -d /dev/loop7 qemu-system-x86_64 -hda disk.img 写在后面估计有读者会问,制作这个极简的Linux有何意义呢? 我认为至少有以下两个意义: 1. 使用几个简单的命令,理清操作系统的运行过程,相比LFS来说,更容易成功,成就感极强 2. 可以在此极简的Linux上,增加更复杂的功能,一步步逼近LFS,千里之行,始下足下
如果试验成功,那如何在真正的硬盘上制作Linux呢?相信你会给出正确的答案,原理与本文全完一样,只是磁盘相关的步骤从disk.img文件,替取成了真正的磁盘/dev/hdX或者/dev/sdX而已,其它不变。
版权声明:本文标题:从零开始制作Linux 内容由林淑君副主任自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.xiehuijuan.com/baike/1686941972a120846.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论