基于3代树莓派的内核编译、覆盖以及运行

原创首发于CSDN,转载请注明出处,谢谢!https://blog.csdn.net/weixin_46959681/article/details/116456664



为什么要对内核源码进行编译?

  • 驱 动 开 发 。 驱动开发。 一个提前编译并适配的内核环境是设备驱动开发的基础环境。
  • 多 平 台 , 多 架 构 。 多平台,多架构。 Linux操作系统就2.6.xx版本而言含有一万四千多个C文件,代码总量达到了惊人的一千一百多万行,现如今已经更新迭代到5.xx.xx了。之所以会有如此巨量的代码,是因为Linux一个开源的、支持多平台、多架构的类UNIX操作系统。诸如Arm、x86、PowerPC、MIPS,Linux操作系统都可以在上面运行,可移植性非常强。
  • 内 核 裁 剪 。 内核裁剪。 相比于“巨无霸”般的操作系统,其编译出来的内核只有若干兆大小,比如这次编译出的新的树莓派内核。内核如此精巧的原因在于编译出的内核终究是要落实到一个操作平台、一个目标架构上,其中绝大多数代码根本不参与编译过程。(开发使用的板子也只能是一种架构。)

树莓派内核的源码配置引导

在上一节中已讨论过,驱动代码编译的前提环境是一个已经编译好的内核。 若要进行内核的编译,你必须要对内核做出相应配置。内核配置的方式有以下三种:

  1. 使用硬件生产厂家提供的内核源码以及引导文件 bcm2709_defconfig,该引导文件只适配树莓派2代、3代; (引导文件会引导 Makefile 组织选取必要的文件生成内核)defconfig
树莓派内核引导文件 bcm2709_defconfig
  1. 根据厂家的引导文件如 bcm2709_defconfig ,自己手动一项项配置 make menuconfig ;
  2. 把上述的一切东西都抛掉,完全自己来。(直接在芯片厂家工作的高级工程师,我等小菜鸟望尘莫及……)

|引导文件.config配置实战

  • 方法一:使用内核中自带的引导文件 bcm2709_defconfig。在树莓派Linux源码目录底下 /home/xxx/xxx/linux-rpi-4.14.y 输入指令:

  • ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make bcm2709_defconfig
    bcm2709_defconfig

  • 方法二: 手动配置 make menuconfig。同样在源码目录树底输入指令:

  • ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make menuconfig

  • 【这里需要系统里已经配置好 ncurses图形库。】

  • [] 里能看到有 M、* 字样的字符,这两者表示驱动的加载方式。M 表示以模块化的方式生成驱动文件 xxx.ko 。系统启动后,通过命令 inmosd 加载驱动文件 xxx.ko 。* 表示将文件编译进内核,之后在目录 /arm/boot 内生成的内核文件 zImage 就含该记号标记的文件。 menuconfig


树莓派内核编译实战

在上述的引导文件配置完成以后,我们直接开始关于内核的实战编译,在源码目录底下/home/xxx/xxx/linux-rpi-4.14.y 输入指令:

ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make -j4 zImage modules dtbs

【“j4”表示使用4个核进行编译工作,“zImage”为生成的内核文件名,“modules”表示生成的驱动模块,“dtbs”表示配置文件。】

输入指令后就是漫长的文件配置时间,笔者个人笔记本屏幕上不停地闪过配置文件,这一过程大概要二十多分钟。
内核编译

|错误判断

注意,如果内核编译出现错误基本会在编译的前十几秒内终止进程。原因多半在于 交叉编译工具链的部署环境变量的设置 出现了问题,这个时候你去修改内核引导文件的配置是无济于事的。那么该如何判断内核的编译成功了呢?

  1. 内核编译在前二十多秒内的时间里没有报错;
  2. 在源码目录树文件 /home/xxx/xxx/linux-rpi-4.14.y 底下生成两个文件 vmlinux、vmlinux.o 以及在 /home/xxx/xxxi/linux-rpi-4.14.y/arch/arm/boot 下生成内核文件 zImage 。在这里插入图片描述

|内核文件 zImage 打包成镜像文件 kernel_new.img

利用linux源码包里脚本文件 scripts 里的工具 mkknlimg 将内核文件zImage 打包成镜像文件 kernel_new.img,输入指令:./scripts/mkknlimg arch/arm/boot/zImage ./kernel_new.img

kernel_new.img

|sdb分区奇妙二三事

将树莓派的SD卡插入读卡器接入电脑(这里有一点小折腾需要自己摸排),接入成功后使用指令 d m e s g dmesg dmesg 查看底层的硬件数据。从截图可以看到这里已经成功接入,但是可以看到提示:Volume was not properly umounted. Some data may be corrupt. Please run fsck.

在这里插入图片描述

碎 碎 念 : 碎碎念:

  • 在6号夜晚,笔者当时看到关于 sdb1 分区的提示,特意上网搜索了一遍,读到说是因为拨插不规范导致分区文件无法读取或者读取文件异常。当时内心就异常忐忑,因为这一步会直接影响后续分区挂载映射以及内核镜像文件 kernel_new.img 的读取覆盖。中间的过程还是有些离奇的,在后续的 cp 覆盖时乌班图系统提示无法找此文件,那时笔者也无法确认是挂载映射出现了问题,还是因SD卡文件损坏导致操作异常,又或者是别的什么奇怪的原因。只是那时已经到了最后几步,偏偏卡死在内核覆盖这一步,整个人都气到爆炸……😡。但是在第二天早上不死心的重新试了一下,居然又神奇的成功了。奇怪的是分区名从 sdb1 sdb2 变成了 sdc1 sdc2……不论怎么样,后面的挂载又可以做了。

|SD卡挂载映射以及新内核的覆盖

树莓派的SD卡有两个分区 FAT、ext4 ,因此也需要在主机目录底下创建两个文件:

  • data1 —— 对应 FAT 分区,涉及Boot相关的文件,内核镜像文件也放在此处;
  • data2 —— 对应 ext4 分区,涉及Linux系统根目录文件。

内 存 挂 载 : 内存挂载:

  • sudo mount /dev/sdb1 data1
  • sudo mount /dev/sdb2 data2

安 装 m o d u l e s : 安装 modules: modules (驱动模块文件安装在 ext4 分区内)

  • sudo ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make INSTALL_MOD_PATH=/hoem/xxx/xxx/data2 modules_install
    【界面会显示正在安装一堆的 .ko 文件,大致有 crypto、fs、net、sound以及驱动文件 drivers,如果少了这一步,则树莓派对应的显示器接口 hdmi、Wi-Fi、usb接口等都将无法使用。】

|更新覆盖Boot分区里的内核文件

第一篇参考博文内覆盖更新内核写到了修改 config.txt 文件指定用于覆盖的文件,我们这里直接进行 cp 覆盖,输入指令:cp kernel_new.img /home/xxx/xxx/kernel7.img

复制完成后最好使用 md5sum 分别查看拷贝目标 kernel_new.img 和粘贴文件 kernel7.img 两者的文件编码号是否一致。该编码号是唯一的,如果在拷贝中文件损坏或者失败,文件编码号就会改变。

在第一节 “为什么要对内核源码进行编译?” 中笔者就提到过相比于庞大的Linux系统,裁剪出来的内核是十分精巧的,这次裁剪出来的树莓派内核才只有 4.8M 。树莓派内核

注 意 : 注意:

  • 树莓派SD卡Boot 分区里的内核文件 kernel7.img ,该文件名是树莓派官方指定的特殊文件名。在覆盖内核文件之前,我们应该对其进行备份(将kernel7.img 备份成 kernel7OLD.img 文件,同样存放在 boot 分区即可),以免刷机失败导致后续树莓派无法启动。

|复制其他配置文件 dtbs

  • cp arch/arm/boot/dts/.* dtb * /home/xxx/xxx/data1/
  • cp arch/arm/boot/dts/overlays/.* dtb * /home/xxx/xxx/data1/overlays/
  • cp arch/arm/boot/dts/overlays/README /home/xxx/xxx/data1/overlays/

注意:

  • CSDN博客的两个星号会被渲染成斜体字母,读者复制的时候请自行删除空格。

树莓派上电启动查看新内核编号

树莓派上电启动,使用串口软件 minicomubuntu 系统进行数据交互(不排除其他人这一步出现错误),输入 uname -r 查看内核编号,可以看到新旧内核的编号完全不同,意味着树莓派内核的编译成功。

旧内核新内核
老版本内核新内核

不足或者加强学习的部分

在整个学习环节中,笔者进一步发现了自己在哪些地方需要继续深入:

  • 了解过Linux系统的根文件树目录结构‘/’,但对于Linux内核源码目录树结构确是一知半解;(概念性内容)
  • 对引导文件.config如何引导Makefile组织必要的文件编译内核有待深入学习?(原理性内容)
  • 内存的挂载映射如何实现的?(原理性内容)
  • 配置文件 xx.dtbs 又是怎么一回事?

阅读到这里请不要被吓到,笔者也只是初学者,能将上述问题全部解决的人无疑是在嵌入式领域深耕的高级工程师,笔者只是在此处引导出进一步学习性质的问题。


该篇博文的重心之处说明

该篇博文基于陈立臣老师的树莓派高阶开发课程和第一篇参考资料成文。学习的常态就是不断“制造”问题,又不断解决问题,哪怕是有了这么详尽的学习资料,但单就个人实操这一环节都会遇见摸不着头难的问题。

想必阅读到这里的读者已经能够发现,相比于参考资料中事无巨细的第一篇博文,笔者这一篇博文只涉及在ubuntu中做交叉编译并没有树莓派本地编译的内容,而且对于一些细节部分略有简洁,如树莓派的源码下载、交叉编译工具链的部署、交叉编译环境变量的配置、内核编译所必须要安装的库等等,笔者在整篇博文中全部都省略了(自己对着博客一步步操作下来自然会慢慢地配置齐全)。

之所以会如此,在于笔者只是想专注记录回顾个人在学习过程中遇到困难、个人的学习重心是哪些(源码的配置引导、内核的编译实战),外加在学习中引导自己对于 Linux 系统的学习还有哪些地方不足的。只有在这样的基础出发,从头到尾整理出来的博文才是一个阶段性学习的圆满,因为你已经带个下一个问题出发了。

上文中提到的缺失部分,笔者以后会单独整理出详尽的学习博客。


参考资料


文章更新记录

  • “内核文件 zImage 打包成镜像文件 kernel_new.img” 一节完成。 「2021.5.7 22:07」
  • “sdb分区奇妙二三事”一节完成。「2021.5.7 22:27」
  • 修饰了昨日完成的部分文章的局部文字。 「2021.5.8 10:43」
  • “树莓派上电启动查看新内核编号” 一节完成。 「2021.5.8 12:52」
  • 文章初次竣工。 「2021.5.8 21:31」
  • 版式和错别字略微修改。 「2021.5.24 14:53」

P.S.1 文章写完“sdb分区奇妙二三事”一节笔者已经夜晚爆肝三个多小时了,最近心率似乎有点失衡,嘴唇也有点紫……太晚了,更新就此暂停,剩余的内容放在明天上午吧。 「2021.5.7 22:30」

P.S.2 Linux内核的庞大世界等着我慢慢探索。无奈个人二十有几才开始编程,以前活得实在是过于封闭了。 「2021.5.8 21:33」

P.S.3 转移到二级专栏。 「20210.6.2 19:17」

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值