Bootstrap

linux工具---用qemu调试linux内核

一.qemu模拟x86
1.1 qemu的安装
        ubuntu 12.04下安装qemu很简单, 
        sudo apt-get install qemu
1.2 linux内核的编译
    www.kernel.org 下载内核, 以linux-3.0.1为例
    sun@ubuntu:/work/x86/kernel$ tar xf ./linux-3.0.1.tar.bz2
    sun@ubuntu:/work/x86/kernel$ cd linux-3.0.1/
    sun@ubuntu:/work/x86/kernel/linux-3.0.1$ make menuconfig
    sun@ubuntu:/work/x86/kernel/linux-3.0.1$ make bzImage 
    这样就会生成内核文件 arch/x86/boot/bzImage
1.3 busybox的编译
    http://www.busybox.net/ 下载busybox, 以busybox-1.21.1.tar.bz2为例
    sun@ubuntu:/work/x86/kernel$ tar xv busybox-1.21.1.tar.bz2 
    sun@ubuntu:/work/x86/kernel$ cd busybox-1.21.1/
    sun@ubuntu:/work/x86/kernel/busybox-1.21.1$ make menuconfig 
     Busybox Settings  --->  
           Build Options  ---> 
               [*] Build BusyBox as a static binary (no shared libs)           //静态方式编译
     Networking Utilities  --->
          [ ] inetd                                                                                 //去掉inetd
   sun@ubuntu:/work/x86/kernel/busybox-1.21.1$ make install 
       这会生成 _install目录
1.4 最小文件系统的建立
只用一个脚本creatfs.sh就可以生成cramfs文件系统
  1. #!/bin/sh
  2. KERNEL=$(pwd)
  3. BUSYBOX=$(find busybox* -maxdepth 0)
  4. LINUX=$(find linux* -maxdepth 0)

  5. #create filesystem
  6. cd $BUSYBOX
  7. mkdir -pv proc sys dev etc etc/init.d      //先创建系统目录
  8. cat << EOF > etc/init.d/rcS                //生成rcS文件
  9. #!/bin/sh
  10. mount -t proc none /proc
  11. mount -t sysfs none /sys
  12. /sbin/mdev -s
  13. EOF

  14. chmod 777 ./etc/init.d/rcS                //修改rcS权限
  15. cd -

  16. #create cpio img
  17. cd $BUSYBOX/_install
  18. find . | cpio ---format=newc > $KERNEL/rootfs.img  
  19. cd -

  20. #create zip img
  21. cd $KERNEL
  22. gzip -c rootfs.img > rootfs.img.gz
1.5 启动qemu
  1. #!/bin/sh
  2. LINUX=$(find linux* -maxdepth 0)
  3. #启动qemu
  4. if [ $# = 0 ] ; then
  5.     qemu-system-i386 -kernel $LINUX/arch/i386/boot/bzImage -initrd rootfs.img.gz -append "root=/dev/ram rdinit=sbin/init noapic"
  6. fi

  7. if [ "$1" = "s" ] ; then
  8.     qemu-system-i386 ---kernel $LINUX/arch/i386/boot/bzImage -initrd rootfs.img.gz -append "root=/dev/ram rdinit=sbin/init noapic"
  9. fi
如果没有参数直接运行qemu, 如果有参数s, 则进入调试模式
qemu参数:  
    -s  :  在1234接受gdb调试连接
    -S :   虚拟机启动后立即暂停,等侍gdb连接
最后所有文件如下:
sun@ubuntu:/work/x86/kernel$ tree -L 1 
.
├── busybox-1.21.1        //busbyox及_install 
├── creatfs.sh                 //文件系统生成脚本    
├── linux-3.0.1              //Linux源码,及 bzImage
└── start.sh                   //启动qemu

注意:
a. 将linux启动信息打印到串口

在qemu启动时加上: 
      qemu-system-i386 -kernel $LINUX/arch/i386/boot/bzImage -initrd rootfs.img.gz -append "root=/dev/ram rdinit=sbin/init noapic console=ttyS0-serial file:/tmp/serial.out
就会在/tmp/serial.out中出现系统的信息
b.  将linux启动信息直接打印到控制台
加入 -nographic 和stdio,则会在当前运行的terminal中把linux启动信息打印出来
qemu-system-i386 -kernel $LINUX/arch/i386/boot/bzImage -initrd rootfs.img.gz -append "root=/dev/ram rdinit=sbin/init console=ttyS0" -nographic
c. qemu的快捷键 
C-a h    print this help
C-a x    exit emulator
C-a s    save disk data back to file (if -snapshot)
C-a t    toggle console timestamps
C-a b    send break (magic sysrq)
C-a c    switch between console and monitor
C-a C-a  sends C-a

二.qemu模拟ARM
 2.1 qemu-system-arm的安装
如果只是apt-get install qemu,不会安装qemu-system-arm
sun@ubuntu:/work/qemu$ sudo apt-get install qemu qemu-system qemu-utils
sun@ubuntu:/work/qemu$ qemu-system-arm  --version
QEMU emulator version 1.0.50 (Debian 1.0.50-2012.03-0ubuntu2.1), Copyright (c) 2003-2008 Fabrice Bellard
注意: 编译工具链可以不用apt-get install 来安装,试过6410自带的交叉编译工具链是完全可用的。
2.2 编译u-boot, kernel, busybox
这儿的编译跟x86的不同之处是:
不论是编译u-boot 还是 linux-3.0.1 还是busybox都需要个改Makefile中的ARCH与CROSS_COMPILE两个变量c
  1. ARCH ?= arm
  2. CROSS_COMPILE ?= /opt/6410/4.3.2/bin/arm-none-linux-gnueabi-
编译u-boot时是用的make ca9x4_ct_vxp_config
编译Linux-3.0.1时是用的 arch/arm/configs/vexpress_defconfig
内核编译命令: make vexpress_defconfig && make -j16
a.copy zImage
在arch/arm/Makefile中
  1. 278 zImage Image xipImage bootpImage uImage: vmlinux
  2. 279 $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
  3. 280 echo "$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@"
  4. 281 cp $(boot)/$@ ../
其中$(boot)/$@是zImage的路径
../ 是linux-3.01源码的上一层

2.3 用ext3系统启动
编译完成busybox, make install 后,用mkfs.sh脚本生成文件系统,只是生成,不用打包成其它格式
  1. #!/bin/sh
  2. KERNEL=$(pwd)
  3. BUSYBOX=$(find busybox* -maxdepth 0)
  4. LINUX=$(find linux* -maxdepth 0)
  5. #create filesystem
  6. cd $BUSYBOX
  7. mkdir -pv proc sys dev etc etc/init.//先创建系统目录
  8. cat << EOF > etc/init.d/rcS //生成rcS文件
  9. #!/bin/sh
  10. mount -t proc none /proc
  11. mount -t sysfs none /sys
  12. /sbin/mdev -s
  13. EOF
  14. chmod 777 ./etc/init.d/rcS //修改rcS权限
  15. cd -
用ext3.sh脚本创建ext3文件系统
  1. #!/bin/sh
  2. #创建一个32M的空文件
  3. dd if=/dev/zero of=a9rootfs.ext3 bs=1M count=32 

  4. #格式化为EXT3
  5. sudo mkfs.ext3 a9rootfs.ext3 

  6. # 挂载到a9rootdir目录
  7. mkdir -pv /tmp/a9rootdir
  8. sudo mount -t ext3 a9rootfs.ext3 /tmp/a9rootdir/ -loop

  9. #拷贝文件到该目录,相对于放到a9rootfs.ext3里面
  10. sudo cp /work/qemu/rootfs/* /tmp/a9rootdir/ -Rf

  11. sudo umount /tmp/a9rootdir
启动:
  1. qemu-system-arm -kernel zImage -M vexpress-a9 -append "root=/dev/mmcblk0 console=ttyAMA0 console=tty0" -sd a9rootfs.ext3 -serial stdio
2.4 用NFS启动
编译完成busybox, make install 后,用mkfs.sh脚本生成文件系统,只是生成,不用打包成其它格式
启动:
  1. qemu-system-arm -m 256 -kernel zImage -serial stdio -M vexpress-a9 -append root="/dev/nfs console=ttyAMA0 console=tty0 nfsroot=10.0.0.1:/work/qemu/rootfs rw ip=10.0.0.2:10.0.0.1:10.0.0.1:255.255.255.0 " -net nic,vlan=-net tap,vlan=0,ifname=tap0,script=qemu-ifup &
qemu-ifup脚本如下:
  1. #!/bin/sh
  2. echo "Executing /etc/qemu-ifup"
  3. sudo ifconfig $1 10.0.0.1
前提是主机上的nfs-server己配置好

三. qemu调试linux系统
3.1 启动调试模式下的qemu
   sun@ubuntu:/work/x86/kernel$ sh start.sh s
3.2 另起一个terminal
  1. sun@ubuntu:/work/x86/kernel/linux-3.0.1$ gdb vmlinux 
  2. Reading symbols from /work/x86/kernel/linux-3.0.1/vmlinux...done.
  3. (gdb) target remote localhost:1234
  4. Remote debugging using localhost:1234
  5. 0x0000fff0 in ?? ()
  6. (gdb) b kernel_init 
  7. Breakpoint 1 at 0xc15c7786: file init/main.c, line 781.
  8. (gdb) c 
  9. Continuing.

  10. Breakpoint 1, kernel_init (unused=0x0) at init/main.c:781
  11. 781    {
  12. (gdb) l
  13. 776        panic("No init found. Try passing init= option to kernel. "
  14. 777         "See Linux Documentation/init.txt for guidance.");
  15. 778    }
  16. 779    
  17. 780    static int __init kernel_init(void * unused)
  18. 781    {
  19. 782        /*
  20. 783         * Wait until kthreadd is all set-up.
  21. 784         */
  22. 785        wait_for_completion(&kthreadd_done);
  23. (gdb)
3.3 每次都这么操作比较麻烦,可以建立一个gdbinit脚本
sun@ubuntu:/work/x86/kernel/linux-3.0.1$ vi .gdbinit 
  1. target remote localhost:1234
  2. b kernel_init
  3. c
然后下次运行时就可以
sun@ubuntu:/work/x86/kernel/linux-3.0.1$ gdb vmlinux 
注意,如果用gdbinit脚本时出现以下问题:
  1. warning: File "/work/x86/kernel/linux-3.0.1/.gdbinit" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load".
  2. To enable execution of this file add
  3.     add-auto-load-safe-path /work/x86/kernel/linux-3.0.1/.gdbinit
  4. line to your configuration file "/home/sun/.gdbinit".
  5. To completely disable this security protection add
  6.     set auto-load safe-path /
  7. line to your configuration file "/home/sun/.gdbinit".
  8. For more information about this security protection see the
  9. "Auto-loading safe path" section in the GDB manual. E.g., run from the shell:
  10.     info "(gdb)Auto-loading safe path"
sun@ubuntu:/work/x86/kernel/linux-3.0.1$ vi ~/.gdbinit 
 set auto-load safe-path /
在~/.gdbini中加入上面这一行,取消掉

 [参]:
以QEMU模拟Linux,学习linux内核
http://www.cnblogs.com/senix/archive/2013/02/21/2921221.html
使用qemu调试linux内核
http://blog.csdn.net/aero_boy/article/details/6262609
使用qemu模拟Coretex-A9运行u-boot和Linux
http://www.linuxidc.com/Linux/2012-07/65478.htm
;