开发环境内核版本:

thorn@ubuntu:~$ cat /proc/version
Linux version 4.4.0-63-generic (buildd@lcy01-31) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4) ) #84-Ubuntu SMP Wed Feb 1 17:20:32 UTC 2017
thorn@ubuntu:~$ uname -a
Linux ubuntu 4.4.0-63-generic #84-Ubuntu SMP Wed Feb 1 17:20:32 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
thorn@ubuntu:~$

gcc版本:

thorn@ubuntu:~$ arm-linux-gnueabi-gcc -v
Using built-in specs.
COLLECT_GCC=arm-linux-gnueabi-gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc-cross/arm-linux-gnueabi/4.9/lto-wrapper
Target: arm-linux-gnueabi
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.9.3-13ubuntu2' --with-bugurl=file:///usr/share/doc/gcc-4.9/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.9 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/arm-linux-gnueabi/include/c++/4.9.3 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libitm --disable-libquadmath --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.9-armel-cross/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.9-armel-cross --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.9-armel-cross --with-arch-directory=arm --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libgcj --enable-objc-gc --enable-multiarch --enable-multilib --disable-sjlj-exceptions --with-arch=armv5t --with-float=soft --disable-werror --enable-multilib --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=arm-linux-gnueabi --program-prefix=arm-linux-gnueabi- --includedir=/usr/arm-linux-gnueabi/include
Thread model: posix
gcc version 4.9.3 (Ubuntu/Linaro 4.9.3-13ubuntu2)

qemu版本:

git clone git://git.qemu-project.org/qemu.git
cd qemu
git checkout remotes/origin/stable-2.4 -b stable-2.4

linux源码内核版本:

wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.16.tar.xz

作为一个希望在嵌入式方向发展的同学,目前还没有真正的接触过嵌入式linux开发,很是惭愧,那么从模拟器开始吧。

总共花了2个多小时的时间,包括下载代码。由于对其中的某些过程还不是很理解,一路很是曲折。即便搭建起来了环境,还需要自己慢慢品味才行。

1. 首先下载Linux内核,以流行的3.16为例的原因是,作为一个初学者,希望有更多的参考资料。

两种方法:

  • 使用git
    git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
  • 直接下载3.16源代码包
    wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.16.tar.xz

    与大多数的搭建过程不同,我选择了直接下载源码,原因有2:

  • 以源码为基础,与大多数时候的开发环境相符,且更有成就感
  • 因为是压缩包,源码的下载速度更快
  • 内核下载完毕之后,解压。这些基本的操作大家都不会陌生。紧接下来的,安装arm的交叉编译链工具,这一步特别关键。很多参考资料直接给出了这样的命令行sudo apt-get install gcc-arm-linux-gnueabi,这是不严谨的,因为,随着gcc的更新,相关的工具链会做更新。
    然而内核的编译过程却还是依赖着比较老的gcc工具链,这会导致编译过程中出现很多莫名其妙的问题,而这些问题,对于新手的成长弊大于利。
    我在这个问题上面花了太多的时间,因为在编译的过程中总会出现莫名其妙的错误,改了一个,又出现另一个,如:

  • fatal error: linux/compiler-gcc5.h: No such file or directory
  • Makefile:901: recipe for target 'init' failed
  • scripts/Makefile.build:390: recipe for target 'init/mounts.o' failed
  • multiple definition of `return_address
  • 可能要开始怀疑人生了。

    对于每一个版本的内核,官方都会有推荐的工具链,版本不一定越高越好,匹配才行。
    比如3.16的内核,gcc用4.9的是ok的,那么可能需要自己手动安装。
    thorn@ubuntu:/usr/bin$ ls -l
    找到下面我们需要的关键信息,即一个软链接文件。
    lrwxrwxrwx 1 root root 34 Feb 27 21:56 arm-linux-gnueabi-gcc -> /usr/bin/arm-linux-gnueabi-gcc-5
    这个文件表明我们使用的arm-linux-gnueabi-gcc 实际上是arm-linux-gnueabi-gcc-5,那么就需要自己手动安装:
    sudo apt-get install gcc-4.9-arm-linux-gnueabi
    sudo apt-get install gcc-4.9-arm-linux-gnueabi-base
    由于不知道有何区别,索性都安装了下。

    并不需要卸载老版本的gcc,安装之后,只需要自己手动更改默认的gcc版本:

  • 删除arm-linux-gnueabi-gcc,它只是个到/usr/bin/arm-linux-gnueabi-gcc-5的软链接
    thorn@ubuntu:/usr/bin$ sudo rm /usr/bin/arm-linux-gnueabi-gcc

  • 重新建立我们需要的软链接
    thorn@ubuntu:~/linux-3.16$ sudo ln -s /usr/bin/arm-linux-gnueabi-gcc-4.9 /usr/bin/arm-linux-gnueabi-gcc

  • 做过了这一步再编译,云开见日,以前莫名其妙的错误都消失了。

  • 那么thorn@ubuntu:/usr/bin$ ls -l后可以看到,gcc已经指向正确:
    lrwxrwxrwx 1 root root 34 Feb 27 21:56 arm-linux-gnueabi-gcc -> /usr/bin/arm-linux-gnueabi-gcc-4.9

  • 编译linux内核:
    生成vexpress开发板的config文件

  • make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm O=./out_vexpress_3_16 vexpress_defconfig

    网上资料有如下步骤,据说是如果不做这个步骤,后面qemu会起不来。按照这个步骤,结果没有问题:

    执行如下命令:
    make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm O=./out_vexpress_3_16 menuconfig
    将System Type -->的Enable the L2x0 outer cache controller 取消

    git clone git://git.qemu-project.org/qemu.git
    cd qemu
    git checkout remotes/origin/stable-2.4 -b stable-2.4

    配置以前需要安装若干个软件包,惭愧的是自己并不知道这几个软件包的作用

    sudo apt-get install zlib1g-dev libglib2.0-0 libglib2.0-dev libtool libtool libsdl1.2-dev autoconf

    配置qemu,为了使qemu代码干净,中间文件都生成到build目录下

    thorn@ubuntu:~/qemu$ mkdir build
    thorn@ubuntu:~/qemu$ cd build/
    thorn@ubuntu:~/qemu/build$ ../configure --target-list=arm-softmmu --audio-drv-list=
    

    编译,安装

    sudo make install

    如果不是在root权限下,一定要加上sudo,比如我之前不知,就出现了如下的错误:

    install -d -m 0755 "/usr/local/share/qemu"
    cannot change permissions of ‘/usr/local/share/qemu’: No such file or directory

    感谢google,我找到了这个error的解决办法。

    测试qemu和内核能否运行成功
    qemu已经安装好了,内核也编译成功了,到这里测试一下,编译出来的内核是否OK,或者qemu对vexpress单板支持是否够友好。
    命令如下:

    thorn@ubuntu:~/linux-3.16/out_vexpress_3_16$ qemu-system-arm -M vexpress-a9 -m 512M -kernel /home/thorn/linux-3.16/out_vexpress_3_16/arch/arm/boot/zImage -nographic -append "console=ttyAMA0"
    

    如果看到内核启动过程中的打印,说明前的搭建是成功的。

    -M vexpress-a9 模拟vexpress-a9单板,你可以使用-M ?参数来获取该qemu版本支持的所有单板
    -m 512M 单板运行物理内存512M
    -kernel /home/ivan/kernel_git/linux/arch/arm/boot/zImage 告诉qemu单板运行内核镜像路径
    -nographic 不使用图形化界面,只使用串口
    -append "console=ttyAMA0" 内核启动参数,这里告诉内核vexpress单板运行,串口设备是哪个tty。

    以下命令杀死qemu-system-arm这个进程:

    ps -A | grep qemu-system-arm | awk '{print $1}' | xargs sudo kill -9

    以上就是本人arm运行环境的搭建过程,如有问题,欢迎评论,参考如下:

  • 从零使用qemu模拟器搭建arm运行环境
  • 用Qemu模拟vexpress-a9 (一) --- 搭建Linux kernel调试环境
  • Google
  • 3. 制作根文件系统

    你会注意到,有panic,我们还没有制作根文件系统

    Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)

  • 下载、编译和安装busybox
  • wget http://www.busybox.NET/downloads/busybox-1.20.2.tar.bz2

    thorn@ubuntu:~/busybox-1.20.2$ make defconfig
    thorn@ubuntu:~/busybox-1.20.2$ make CROSS_COMPILE=arm-linux-gnueabi-
    thorn@ubuntu:~/busybox-1.20.2$ make install CROSS_COMPILE=arm-linux-gnueabi-
    

    安装完成后,会在busybox目录下生成_install目录,该目录下的程序就是单板运行所需要的命令。

  • 形成根目录结构
    先在Ubuntu主机环境下,形成目录结构,里面存放的文件和目录与单板上运行所需要的目录结构完全一样,然后再打包成镜像(在开发板看来就是SD卡),这个临时的目录结构称为根目录。
  • 可以写一个脚本mkrootfs.sh完成这个任务

    #!/bin/bash
    sudo rm -rf rootfs
    sudo rm -rf tmpfs
    sudo rm -f a9rootfs.ext3
    sudo mkdir rootfs
    sudo cp ~/busybox-1.20.2/_install/*  rootfs/ -raf
    sudo mkdir -p rootfs/proc/
    sudo mkdir -p rootfs/sys/
    sudo mkdir -p rootfs/tmp/
    sudo mkdir -p rootfs/root/
    sudo mkdir -p rootfs/var/
    sudo mkdir -p rootfs/mnt/
    sudo cp ~/etc rootfs/ -arf
    sudo cp -arf /usr/arm-linux-gnueabi/lib rootfs/
    sudo rm rootfs/lib/*.a
    sudo arm-linux-gnueabi-strip rootfs/lib/*
    sudo mkdir -p rootfs/dev/
    sudo mknod rootfs/dev/tty1 c 4 1
    sudo mknod rootfs/dev/tty2 c 4 2
    sudo mknod rootfs/dev/tty3 c 4 3
    sudo mknod rootfs/dev/tty4 c 4 4
    sudo mknod rootfs/dev/console c 5 1
    sudo mknod rootfs/dev/null c 1 3
    sudo dd if=/dev/zero of=a9rootfs.ext3 bs=1M count=32
    sudo mkfs.ext3 a9rootfs.ext3
    sudo mkdir -p tmpfs
    sudo mount -t ext3 a9rootfs.ext3 tmpfs/ -o loop
    sudo cp -r rootfs/*  tmpfs/
    sudo umount tmpfs
    

    thorn@ubuntu:/$ sudo ./mkrootfs.sh由于在根目录下执行这个sh文件,故需要加上sudo。

    接下来,就可以启动qemu来模拟vexpress开发板了,命令参数如下:

    sudo qemu-system-arm \
        -M vexpress-a9 \
        -m 512M \
        -kernel /home/thorn/linux-3.16/out_vexpress_3_16/arch/arm/boot/zImage \
        -nographic \
        -append "root=/dev/mmcblk0  console=ttyAMA0" \
        -sd a9rootfs.ext3
    

    由于要读写根目录下的文件,故,执行qemu时要加上sudo。

    其中要注意的是,-sd a9rootfs.ext3,这个指的是绝对路径,由于我是在根目录下做这个的,所以,-sd后面直接是a9rootfs.ext3。

    执行结果如下:

    -serial stdio \ -m 512M \ -kernel /home/thorn/linux-3.16/out_vexpress_3_16/arch/arm/boot/zImage \ -append "root=/dev/mmcblk0 console=ttyAMA0 console=tty0" \ -sd a9rootfs.ext3

    执行结果如下: