【Linux驱动开发(一)】编译内核,构建根文件系统并使用QEMU搭建Vexpress-A9开发板虚拟开发环境_qemu vxworks xilinx-zynq-a9 映像文件-程序员宅基地

技术标签: 【Linux驱动开发】基于QEUM的实操笔记  linux  嵌入式硬件  驱动开发  单片机  

安装Linux系统和QEMU

工欲善其事必先利其器,搭建一个良好的开发环境是进行开发的基础,可以少出很多bug

  1. 需要准备一个Linux系统的环境,可以用虚拟机搭建,网上有很多文章讲这个,就不赘述了。正点原子提供了开源的虚拟机和系统镜像的资料和搭建教程,完全开源的,请自取:正点原子资料
  2. 本文使用笔记本电脑装的Linux双系统作为开发环境,读者如果要安装双系统,可以查找自己电脑型号对应的双系统安装教程,也比较繁杂,但是之后就是在真正的Linux里搞开发,不存在虚拟机里莫名其妙的问题。

在实践过程中发现用虚拟机会出现挺多问题,比如虚拟机网络问题导致不能安装一些库、虚拟机导致电脑蓝屏、虚拟机卡慢等等问题

平台信息:

Ubuntu版本:22.04
gcc版本: 11.4.0
主机linux内核版本: 6.5.0-15-generic
所构建的Linux内核版本:6.6.16

Linux系统安装好了之后安装qemu,在命令行输入:

sudo apt-get install qemu
sudo apt-get install qemu-system

编译Linux内核

首先编译Linux内核,我们构建Linux内核需要编译后产生的内核镜像zImage和对应的设备树文件

  • 内核下载地址如下,官方网站可能下载比较慢,下载6.6.16版本的内核:
    内核下载官方网站
    内核下载镜像网站

  • 下载后解压,进入cd进入内核文件夹linux-6.6.16

  • 配置内核,输入一下命令:

    export ARCH=arm
    export CROSS_COMPILE=arm-linux-gnueabi-
    make vexpress_defconfig
    make menuconfig
    

    弹出的界面不设置,按两次esc退出,

    1. Uboot和Linux内核移植需要根据你的板卡选择相应的默认配置信息/boot/configs,我们选择Vexpress-A9开发板的配置信息。
    2. export命令:用于显示或设置环境变量,但是效果仅限于当前登录的终端,这样我们不用每次make都指定参数了
    3. vexpress_defconfig:是ARM Versatile Express开发板的内核默认配置文件,文件夹里有很多厂家板子的默认配置文件,放在arch/arm/configs
  • 接下来,我们编译内核镜像文件和设备树文件,时间有一点久,耐心等待:

    make bzImage
    make dtbs
    

    编译结果注意zImage的地址和设备树的地址,后续会用到

    make bzImage 的结果如下:
    0BJCopy arch/arm/boot/zImage
    Kernel: arch/arm/boot/zImage is ready
    make dtbs 的结果如下:
    DTC		arch/arm/boot/dts/arm/vexpress-v2p-ca5s.dtb
    DTC		arch/arm/boot/dts/arm/vexpress-v2p-ca9.dtb
    DTC		arch/arm/boot/dts/arm/vexpress-v2p-ca15-tc1.dtb
    DTC		arch/arm/boot/dts/arm/vexpress-v2p-ca15 a7.dtb
    

    可以看到,Linux内核镜像文件zInage保存在arch/arm/boot/zImage,设备树文件:vexpress-v2p-ca9.dtb(在arch/arm/boot/dts/文件夹下)

  • 在内核文件夹里,运行qemu:

    qemu-system-arm -M vexpress-a9 -smp 4 -m 256M -kernel arch/arm/boot/zImage -append "console=ttyAMA0" -dtb arch/arm/boot/dts/arm/vexpress-v2p-ca9.dtb -nographic
    

    输出信息出现Booting Linux on physical CPU 0x0,说明成功进入内核了,我们编译的内核和设备树没问题,但是我们没有构建和指定根文件系统,所以内核会崩溃显示---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0) ]---

  • QEMU中,输入ctrl+a再输入x,退出QEMU,准备构建根文件系统

构建根文件系统(BusyBox)

使用BusyBox来构建根文件系统,根文件系统的根目录和子目录中会有很多Linux 运行所必须的文件,比如库、常用的软件和命令、设备文件、配置文件等等,BusyBox 就集成了这些大量的 Linux 命令和工具

  • 博主下载的版本是1.36.1,下载网站:busybox下载
  • 解压,cd进入busybox,对busybox进行配置,使用默认配置defconfig
    make defconfig
    make menuconfig
    
    跳出的界面里配置静态编译:Setting->Build static binary,点空格把它选上,然后Esc退出
  • 编译根文件系统:
    mkdir /home/rootfs
    make
    make install CONFIG_PREFIX=/home/rootfs 
    

    设置CONFIG_PREFIX参数,将编译结果指定存放在根文件系统目录下

  • 接下来需要完善根文件系统
    • 创建etc,dev,mnt,sys,tmp,proc,root,lib等目录,安装动态链接库

      mkdir etc,dev,mnt,sys,tmp,proc,root
      sudo cp -d /usr/arm-linux-gnueabi/lib/*.so* ./lib
      
    • 创建设备节点

      cd dev/
      sudo mknod -m 666 console c 5 1
      sudo mknod -m 666 null c 1 3
      sudo mknod -m 666 dev/tty1 c 4 1
      sudo mknod -m 666 dev/tty2 c 4 2
      sudo mknod -m 666 dev/tty3 c 4 3
      sudo mknod -m 666 dev/tty4 c 4 4
      
    • 创建并写入三个配置文件/etc/init.d/rcS/etc/fstab/etc/inittab,其内容分别为:

      1. /etc/init.d/rcS: shell 脚本, 规定Linux 内核启动以后启动哪些文件的脚本,该文件一定要给与可执行权限!!!
      2. /etc/fstab:Linux 开机以后自动配置哪些需要自动挂载的分区
      3. /etc/inittab:内核初始化的init 程序会读取/etc/inittab这个文件,inittab 由若干条指令组成
        三个文件的写法以及环境变量配置参考这篇文章:WSL2下Ubuntu22.04使用Qemu搭建虚拟Vexpress-A9开发板(三)——挂载根文件系统

      /etc/init.d/rcS:

      #!/bin/sh
      PATH=/bin:/sbin:/usr/bin:/usr/sbin
      export LD_LIBRARY_PATH=/lib:/usr/lib
      /bin/mount -n -t ramfs ramfs /var
      /bin/mount -n -t ramfs ramfs /tmp
      /bin/mount -n -t sysfs none /sys
      /bin/mount -n -t ramfs none /dev
      /bin/mkdir /var/tmp
      /bin/mkdir /var/modules
      /bin/mkdir /var/run
      /bin/mkdir /var/log
      /bin/mkdir -p /dev/pts
      /bin/mkdir -p /dev/shm
      /sbin/mdev -s
      /bin/mount -a
      echo "-----------------------------------"
      echo "*****welcome to vexpress board*****"
      echo "-----------------------------------"
      

      /etc/fstab:

      proc    /proc           proc    defaults        0       0
      none    /dev/pts        devpts  mode=0622       0       0
      mdev    /dev            ramfs   defaults        0       0
      sysfs   /sys            sysfs   defaults        0       0
      tmpfs   /dev/shm        tmpfs   defaults        0       0
      tmpfs   /dev            tmpfs   defaults        0       0
      tmpfs   /mnt            tmpfs   defaults        0       0
      var     /dev            tmpfs   defaults        0       0
      ramfs   /dev            ramfs   defaults        0       0
      

      /etc/inittab:

      ::sysinit:/etc/init.d/rcS 
      ::askfirst:-/bin/sh
      ::restart:/sbin/init 
      ::ctrlaltdel:/sbin/reboot
      ::shutdown:/bin/umount -a -r
      

    写了shell脚本自动完成本节完善根文件系统的工作,自取,切换到/home/rootfs目录下执行:完善根文件系统的shell脚本

创建根文件系统镜像,SD挂载

  • 在根文件系统目录下执行下列命令,创建根文件系统镜像

    cd /home
    sudo qemu-img create -f raw linux.img 256M
    sudo mkfs -t ext4 ./linux.img
    
    sudo mkdir tmpfs
    sudo mount -o loop ./linux.img tmpfs/
    sudo cp -r rootfs/* tmpfs/
    sudo umount tmpfs 
    sudo rm -r tmpfs
    file linux.img
    

    根文件系统镜像创建成功显示:linux.img: Linux rev 1.0 ext4 filesystem data, UUID=c0f6a2f3-b70e-480f-8726-3c2d66ce9120 (extents) (64bit) (large files) (huge files)

  • 把编译出的内核镜像zImage和设备树文件拷贝到/home,运行QEMU:

    sudo qemu-system-arm \
    		-M vexpress-a9 \
            -m 256M \
            -kernel ./zImage \
            -dtb ./vexpress-v2p-ca9.dtb \
            -nographic \
            -append "root=/dev/mmcblk0 rw console=ttyAMA0" \
            -sd linux.img
    

    注意:-append选项的参数,我们从sd卡启动,root所指定的位置是/dev/mmcblk0 就是sd卡设备挂载的目录, rw 表示根文件系统是可以读写的,console 用来设置 linux 终端,表示通过什么设备来和 Linux 交互,设置 console = ttyAMA0,因为 linux启动以后板卡的串口 1 挂载在 linux 下的设备文件就是/dev/ttyAMA0

  • 构建内核成功!可以在QEMU模拟的arm开发板中输入linux指令了
    在这里插入图片描述

总结

  1. 编译内核的时候要注意选择对应板卡的内核配置信息
  2. Linux内核的构建需要三个文件,编译Linux内核得到的内核镜像文件zImage和设备树文件以及根文件系统镜像文件
  3. Linux启动还需要设置一些参数,比如root,console等等,qemu用-append选项设置
  4. 对真实板卡构建Linux内核先要构建uboot,这个实验没有构建uboot也能运行内核是因为使用qemu直接将内核镜像装载在了内存里
  5. 直接用qemu运行内核跟利用uboot运行内核的不同之处:
    1. 在uboot中,Linux启动需要配置的参数(root, console…)是通过设置bootargs环境变量配置的,
    2. 利用uboot构建内核的时候涉及nfs或者tftp网络的使用,利用网络将zImage和设备树文件传到uboot,然后通过网络挂载根文件系统。
  6. uboot构建过程跟Linux内核的构建差不多
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_43916093/article/details/136190036

智能推荐

c# 调用c++ lib静态库_c#调用lib-程序员宅基地

文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib

deepin/ubuntu安装苹方字体-程序员宅基地

文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang

html表单常见操作汇总_html表单的处理程序有那些-程序员宅基地

文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些

PHP设置谷歌验证器(Google Authenticator)实现操作二步验证_php otp 验证器-程序员宅基地

文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器

【Python】matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距-程序员宅基地

文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距

docker — 容器存储_docker 保存容器-程序员宅基地

文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器

随便推点

网络拓扑结构_网络拓扑csdn-程序员宅基地

文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn

JS重写Date函数,兼容IOS系统_date.prototype 将所有 ios-程序员宅基地

文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios

如何将EXCEL表导入plsql数据库中-程序员宅基地

文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql

Git常用命令速查手册-程序员宅基地

文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...

分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120-程序员宅基地

文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120

【C++缺省函数】 空类默认产生的6个类成员函数_空类默认产生哪些类成员函数-程序员宅基地

文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数

推荐文章

热门文章

相关标签