qemu中跑linux
来源:互联网 发布:淘宝网店怎么上架宝贝 编辑:程序博客网 时间:2024/06/05 22:45
http://blog.csdn.net/g__gle/article/details/7004956
用官方源码编译内核,在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=都不起作用.
- qemu中跑linux
- 如何在代码中跑Linux指令
- qemu调试 linux-kernel
- Building QEMU for Linux
- Qemu运行linux 4.9
- Qemu调试Linux内核
- Debug Linux Kernel with Qemu
- 使用qemu调试linux内核
- Linux下qemu的使用
- QEMU下安装linux教程
- qemu busybox模拟Linux启动
- Qemu+Gdb debug linux kernel
- QEMU虚拟机安装linux操作系统
- Linux-KVM, QEMU, Virtualbox, VMWare
- 用qemu调试linux内核
- linux编译安装kvm、qemu
- linux内核调试+qemu+eclipse
- QEMU 运行ARM Linux Kernel
- 注册自定义URL协议
- 软件体系结构课程
- python多线程
- MySql常用命令总结
- BaseEntity类
- qemu中跑linux
- 立波权限检测:普及android手机permission的科普应用(souapp.com搜应用网推荐)
- 蓝牙core spec v4.0研读笔记(四)
- 一次谷歌面试趣事
- CF 1A(隐式转换)
- c++中怎么防止一个应用程序的多个实例同时运行
- Jquery $.ajax异步请求webmethod方法示例
- Linux Make 命令详解
- 每种设计模式的特点