热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

在qemu虚拟机中运行Linux系统

用官方源码编译内核,在qemu中使其尽快跑至shell。以为很简单的事,?果折腾了半个下午。表面上看来,这件事就像极端简化的LFS。Ubuntu的仓库里居然还有静态编译的busybox!辅以initramfs,用户态的初始环境很容易就构造了。比较麻烦的是bootloader,内核

用官方源码编译内核,在qemu中使其尽快跑至shell。以为很简单的事,?果折腾了半个下午。

表面上看来,这件事就像极端简化的LFS。Ubuntu的仓库里居然还有静态编译的busybox!辅以initramfs,用户态的初始环境很容易就构造了。

比较麻烦的是bootloader,内核要怎么到内存中来?好在qemu有个-kernel参数,后加bzImage文件就可以完成bootloader所做的事。看起来只需要两步就OK了:

1.make defconfig && make bzImage

2.qemu -kernel arch/x86/boot/bzImage

?果是Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(8,5)

暂不想操心硬盘的事,只想在内存里跑。新建文件夹,把静态编译好的busybox复制至其中并命名为init。在menuconfig里将initramfs路径指向文件夹,再来。另外不想让qemu用图形界面。

qemu -kernel arch/x86/boot/bzImage -nographic

?果,显示qemu的几行启动信息之后,神马反应也没有,杀也杀不掉。想了一下,默认的console应该是VGA显卡,在cmdline里指定为串口试一下。

qemu -kernel arch/x86/boot/bzImage -append “cOnsole=ttyS0”  -nographic

好了,有输出了,但是最后停在[    1.577268] Switching to clocksource tsc,怎么按键盘都没反应。往上看两行注意到了[    1.253342] Warning: unable to open an initial console。看了一下本机上的console文件,字符设备,5,1.在initramfs文件夹里新建dev目录,再在其中sudo mknod console c 5 1,重编译,再试。终于出现init找不到配置文件之类的提示。

暂不想管inittab什么的,直接让shell做1号进程。在initramfs文件夹里新建bin目录,将init移动为bin下的sh。编译,cmdline中指定init,再试。

qemu -kernel arch/x86/boot/bzImage -append "cOnsole=ttyS0 init=/bin/sh" -nographic

?果居然是[    1.402899] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(8,5)!

为什么有initramfs还会去尝试挂载根文件系统?研究了一下代码,发现是自己以前看代码不仔细。再试。

qemu -kernel arch/x86/boot/bzImage -append "cOnsole=ttyS0 rdinit=/bin/sh" -nographic

终于启动成功了,shell也可以跑了。里面什么命令也没有,预先在initramfs文件夹里建一些指向busybox的软链接就好了。

=========================================================

关于启动的细节。以前的认识有些偏差。且不说initrd,内核镜像里总有一个内嵌initramfs的cpio包,好像还压缩了。在初始化的时候,先初始rootfs,在内存中构建了最初的文件系统。然后不管三七二十一,将镜像中的cpio包释放出来。

怎么会报Unable to mount root fs的错呢?进行到kernel_init时,有这样的代码:

if (!ramdisk_execute_command)  

        ramdisk_execute_command = "/init";  

if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {  

        ramdisk_execute_command = NULL;  

        prepare_namespace();  

}  

也就是说,如果在初始的文件系统中找不到ramdisk_execute_command(默认是init,可以在cmdline中覆盖),则进入prepare_namespce。这个里面就会有尝试mount root fs的动作。如果只想在内存中跑,一定要使sys_access成功。而覆盖ramdisk_execute_command的命令行参数不是init=而是rdinit=!

在其后的init_pos中。如果ramdisk_execute_command非空,则执行该程序,内核的工作到此为此,带起系统的事是initramfs里的init负责。如果initramfs里没有能带起系统的init,内核则尝试挂载真正的物理根文件系统(prepare_namespace),然后再执行真正根文件系统的init程序。这个程序的路径由init=所指定,如果不指定,则做如下尝试:

run_init_process("/sbin/init");  

run_init_process("/etc/init");  

run_init_process("/bin/init");  

run_init_process("/bin/sh");  

总结:

    1.如果initramfs里有init(rdinit指定或者是/init),1号进程会执行它,系统启动则完全交给它了。

 2.initramfs里的init执行失败(不存在或者其它原因),内核会默不作声地进入老式启动流程。

 3.从上一步滑下来了,则尝试挂载根文件系统所在设备(老式的启动流程),设备号默认为编译内核的主机上挂载在/下设备的设备号,在cmdline中可以用root=覆盖之。VFS: Unable to mount root fs就是这时产生的。挂载完根文件系统中之后,执行execute_command,即cmdline中init=所指定的。如果没有指定,则尝试默认四种可能。如果killing init导致panic并且提示你加init=的话,那应该就是挂载了真正的根文件系统里没有init=所指定的程序且四个默认的init程序皆执行失败。

 4.如果没有指定initramfs source,内核会生成一个最小的initramfs cpio包,这个包不是空的!它有一个dev目录,下面有一个console结点,它还有一个root目录。如果指定initramfs source,则自己的initramfs目录里最好有dev目录及其下在的console结点。另外,如果内核去挂载根文件系统所在设备,这个设备会被挂载在/root下!假设自己提供initramfs,内核里没能执行其中的init,这个initramfs里又没有/root目录,在内核尝试挂载根文件系统所在设备时会失败,因为挂载点不存在(报错却报却是VFS: Cannot open root device;当然也有可能真没那个设备)。

    5.由于代码流程,如果initramfs里有init,cmdline里的root=和init=都不起作用.


推荐阅读
  • Bootstrap Paginator 分页插件详解与应用
    本文深入探讨了Bootstrap Paginator这款流行的JavaScript分页插件,提供了详细的使用指南和示例代码,旨在帮助开发者更好地理解和利用该工具进行高效的数据展示。 ... [详细]
  • 本文介绍了Linux操作系统的核心组成部分——内核及其版本分类,以及市面上常见的几种Linux发行版,旨在为初学者提供一个清晰的学习路径。 ... [详细]
  • 在Ubuntu 18.04上使用Nginx搭建RTMP流媒体服务器
    本文详细介绍了如何在Ubuntu 18.04上使用Nginx和nginx-rtmp-module模块搭建RTMP流媒体服务器,包括环境搭建、配置文件修改和推流拉流操作。适用于需要搭建流媒体服务器的技术人员。 ... [详细]
  • AcetoneISO:Ubuntu Linux下的全能虚拟光驱工具
    AcetoneISO 是一款功能强大的虚拟光驱软件,适用于 Linux 和 Mac 系统。它支持多种映像文件格式的挂载和转换,并提供丰富的文件管理功能。 ... [详细]
  • 本文介绍了在 Ubuntu 系统中通过终端打开各种图形界面应用程序的常用命令,包括系统设置、文件管理器和系统监视器等。 ... [详细]
  • 本文详细介绍了在 Ubuntu 系统上安装和配置 MySQL、Tomcat 和 JDK 的步骤。通过本文,您将了解如何顺利安装这些组件,并确保它们能够正常协同工作。 ... [详细]
  • Java中的引用类型详解
    本文详细介绍了Java中的引用类型,包括强引用、软引用、弱引用和虚引用的特点和应用场景。 ... [详细]
  • MySQL Administrator: 监控与管理工具
    本文介绍了 MySQL Administrator 的主要功能,包括图形化监控 MySQL 服务器的实时状态、连接健康度、内存健康度以及如何创建自定义的健康图表。此外,还详细解释了状态变量和系统变量的管理。 ... [详细]
  • Ubuntu 14.04 系统安装后网卡名称修改方法
    本文介绍了在安装 Ubuntu 14.04 Server 版本后,如何将默认的网卡名称从非 eth 格式修改为传统的 eth 格式,并提供了详细的步骤和示例。 ... [详细]
  • Vulnhub DC3 实战记录与分析
    本文记录了在 Vulnhub DC3 靶机上的渗透测试过程,包括漏洞利用、内核提权等关键步骤,并总结了实战经验和教训。 ... [详细]
  • Ubuntu 环境下配置 LAMP 服务器
    本文详细介绍了如何在 Ubuntu 系统上安装和配置 LAMP(Linux、Apache、MySQL 和 PHP)服务器。包括 Apache 的安装、PHP 的配置以及 MySQL 数据库的设置,确保读者能够顺利搭建完整的 Web 开发环境。 ... [详细]
  • Bootstrap 插件使用指南
    本文详细介绍了如何在 Web 前端开发中使用 Bootstrap 插件,包括自动触发插件的方法、插件的引用方式以及具体的实例。 ... [详细]
  • Ubuntu 22.04 安装搜狗输入法详细指南及常见问题解决方案
    本文将详细介绍如何在 Ubuntu 22.04 上安装搜狗输入法,并提供常见问题的解决方法。包括下载安装包、更新源、安装依赖项等步骤。 ... [详细]
  • 本文详细介绍如何在忘记MySQL服务器密码的情况下进行密码重置,包括具体的步骤和注意事项。 ... [详细]
  • 阿里云服务器搭建详解——Ubuntu
    由于自己电脑配置跟不上,双系统一开,整个电脑就会变得非常卡顿,所以决定在阿里云买一个云服务器。听朋友说,学生买的话是非常便宜 ... [详细]
author-avatar
用户2ng6zjfjen
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有