【从零到一的Raspberry】数莓派踩坑实录(二) 内核编译配置和模块安装

2023-11-01

写在前面

  本次作业具有挑战性,不过不管哪一环节出错了,你都要知道如何把它还原到初始状态,这样你就不是在危险地操作,而有还原的保障.因此在第0节我会介绍一种还原数莓派系统的方法,这样你就可以在内核无法运行时还原到默认系统!
  后面从第一章开始,带序号的小节会指引你完成本次"内核裁剪"作业.加油!


  【声明】:本文章核心内容主要参考 数莓派官方网站 ,一切以官方网站上的指令为准,敬请访问

https://www.raspberrypi.com/documentation/computers/linux_kernel.html

  【NOTE】:如果你想要着手快速开始,请直接到序号索引的小节。没有序号的小节可以帮助你获取全方位的理解。
  【系统支持】:本篇暂时未支持Windows系统,请使用 Linux 系统,推荐使用双系统
  【硬件平台】:数莓派3或4系列,支持64位Linux系统,当然,非以上系列也可以用32位进行代替.只是对于本章而言,软件对于硬件具有较好的屏蔽性,数莓派3和4系列的操作代码完全一致.


项目内容

◼首先用默认配置重新编译已安装到开发板的内核,将新的内核替换现有内核,检查是否通过!
◼ 在原始版本基础上,重新配置Linux内核,构建一个较小的嵌入式Linux内核;在保留所需的基本功能前提下,内核越小越好;保留必要的模块加载,剩余部分(占多数)取消
◼ 编译安装重新配置后的内核、模块及设备树
◼ 用新的内核取代旧内核,在开发板上运行测试;
◼ 选择模块加载与卸载,检查是否加载卸载成功;
◼ 构建并安装两款不同于根文件系统(ext4)、用于应用开发的文件系统,基于所选文件系统特性说明其用途。


项目分工

◼<>首先用默认配置重新编译已安装到开发板的内核,将新的内核替换现有内核,检查是否通过!
◼<>内核裁剪流程探索与介绍
◼<2人>内核配置manuconfig详细选项阐述部分功能,并根据配置编译安装内核,查看内核大小,并观察是否启动成功
PPT整合
◼<1人>模块加载与卸载实验,基于原始配置来做,检查是否卸载成功,结合老师上课ppt
◼<2人>根文件系统探究,构建并安装不同的根文件系统,并说明其用途.结合老师上课ppt
报告整合

每个人做好自己的部分对应PPT和报告,最好做之前来找我演示一下,这样看文档会更容易理解.
大家有任何问题直接联系我,我和大家一起探究.



系统还原方法

  当我们配置内核,然后把配置好的内核移植到数莓派上时,可能无法工作,无法启动,无法连接等等.当你发现无法恢复需要重新配置时,请先把系统还原.以保证移植替换内核之前数莓派上运行着正常的系统.下面的方法,亲测有效一次,当然需要大量尝试来确保其在不同版本数莓派上的有效性.
  复位文件linux64_defconfig
在这里插入图片描述

  这个复位文件是什么呢?这个复位文件本质上是一个按照默认配置编译好的内核文件,我们只需要挂载TF卡然后进行安装就可以了,这也就可以使系统快速还原至一个正确的内核.

#64位内核名
KERNEL=kernel8
#挂载tf卡
sudo mount /dev/sdb1 mnt/fat32
sudo mount /dev/sdb2 mnt/ext4
#安装模块
sudo env PATH=$PATH make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- INSTALL_MOD_PATH=mnt/ext4 modules_install
#备份原镜像
sudo cp mnt/fat32/$KERNEL.img mnt/fat32/$KERNEL-backup.img
#移动编译好的镜像文件到boot中
sudo cp arch/arm64/boot/Image mnt/fat32/$KERNEL.img
sudo cp arch/arm64/boot/dts/broadcom/*.dtb mnt/fat32/
sudo cp arch/arm64/boot/dts/overlays/*.dtb* mnt/fat32/overlays/
sudo cp arch/arm64/boot/dts/overlays/README mnt/fat32/overlays/
#卸载tf卡
sudo umount mnt/fat32
sudo umount mnt/ext4

  这段代码我已经写成了recovery.sh,放入linux64_defconfig文件夹中.你要做的只是

0.lsblk查看tf卡在你的电脑上是不是sdb1,sdb2,如果是sdc的话,把recovery.sh文件中的sdb改成sdc
1.插上tf卡到电脑
2.解压linux64_defconfig文件
3.cd到linux64_defconfig文件夹中,输入sh recovery.sh等待一定时间,就可以恢复成功.
4.拔下tf卡,插到数莓派上,等待片刻,黄灯不闪,系统恢复成功.


  其中运行完脚本recovery.sh如下所示.
在这里插入图片描述

manuconfig配置内核

  配置内核总共有3方式,见本文:树莓派Linux内核源码配置、编译、挂载(boot/kernal/根文件)、开启新内核
  其中我们还原系统采用的是defconfig方法,即使用厂家提供的参考配置,而下面配置内核采用manuconfig方法
  下面仍然以64位系统为例,32位系统请参考开头给的官网参考来做

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- KERNEL=kernel8 menuconfig

  这里指明了make参数,分别是架构名,交叉编译工具链,内核镜像名(64位叫kernel8,32位较kernel7或者kernel7l)
  稍等几秒后弹出如下画面,就可以开始手动配置了.
在这里插入图片描述
  第一次我们首先按照manuconfig的默认配置来(Note:这里manuconfig的默认配置和之前所述的还原系统时用的厂家配置,这两者配置并不相同,编译的内核镜像大小是有区别的,但最后执行完毕都会生成 .config 文件,用来作为配置文件指导内核的编译)
  直接连续按下两次ESC,这时会有退出询问,询问是不是要保存配置
  点击确定
在这里插入图片描述
  然后可以看到提示信息告诉我们配置以及写入.config文件了
在这里插入图片描述

编译内核(Build with configs)

  无论你使用的是defconfig还是manuconfig,亦不论你的manuconfig配置如何,在上一步中你已经完成了 .config 文件的生成,这个文件将会指导我们这一节中的内核编译.

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- KERNEL=kernel8 Image modules dtbs -j 10

  指明架构,交叉编译工具链,内核镜像名,生成镜像,模块和dtb,注意64位生成Image而不是zImage(32位),同时使用-j 10为其开启多线程加速.j后面的数字最好是cpu核心的1.5倍为最好.
  根据电脑性能和配置内核大小不同,这一步将会花费数分钟到数十分钟不等的时间,耐心等待.
在这里插入图片描述
  编译结束,接下来将编译好的内核挂载到tf卡上

TF卡挂载新内核

  在当前编译好的文件夹下编写脚本文件loadkernel.sh,该shell脚本可以帮助自动化挂载新内核到TF卡.
在这里插入图片描述

  插入tf卡,运行脚本

sh loadkernel.sh

  运行完毕后拔下卡,插到数莓派上,发现绿灯很快就灭了,甚至都没有与网线成功连接(网线灯都没有亮).当然,我们其余的步骤都是没有问题的,因为defconfig就是按照如上步骤进行下来的,而manuconfig不行.因此这里推断是manuconfig中需要勾选一些重要启动项目才能让数莓派启动成功.那么下面就开始研究manuconfig配置.
  研究的过程在这里省略了,总之就是发现配置有某些数莓派官方提供的配置文件 bcm2711_defconfig 中的某些选项很重要.而我们使用 menuconfig启动的默认配置 和bcm2711_defconfig中的存在差距.默认配置编译完成是不能正常在数莓派上启动的.于是我考虑对比这两者的配置项的区别.


  1.对比两种配置生成的.config文件,由于每个文件各有数千行,使用python进行文件处理

import os
os.remove('diff.txt')
outf=open('diff.txt','w')
for line1 in open("bcm2711_defconfig.txt"):
    for line2 in open("defconfig.txt"):
        if(line1==line2):
            break
    else:#正常循环结束,表示没有匹配到line1
        outf.write(line1)
outf.close()

  但是输出的结果还是有数千行的差距.此方法行不通.


  2.使用manuconfig导入.config,在UI中进行查看,查看 bcm2711_defconfigmenuconfig启动的默认配置 其配置不同之处,发现其中配置项也有几千项,不能确定到底是什么配置对数莓派启动造成了关键影响.


  3.直接在 bcm2711_defconfig 的基础上进行删改,这被证明是切实有效的.这也是目前我认为最可行高效的方法之一.

  下面就详细阐释基于方法3如何来进行Linux内核配置,裁剪以及装载


1 工具链配置与内核下载

  本节主要参考了

https://www.raspberrypi.com/documentation/computers/linux_kernel.html#cross-compiling-the-kernel

  交叉编译的配置工具链和获取源码部分。我们以64位内核为例,以下语句分别完成了交叉编译链安装、linux内核获取

sudo apt install git bc bison flex libssl-dev make libc6-dev libncurses5-dev

sudo apt install crossbuild-essential-arm64

git clone --depth=1 https://github.com/raspberrypi/linux

  我们为linux文件集创建一份备份linux-bkp文件夹,可以留着防止编译配置出错时不用再git

2 内核配置

2.1 生成RP官方.config

  我们接下来先根据树莓派官方配置 bcm2711_defconfig 生成.config文件
  指明内核名称,架构,交叉工具链名还有官方的配置名

make KERNEL=kernel8 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcm2711_defconfig
2.2 导入RP官方.config进行修改,并覆盖(不是内核配置的组员跳过此步骤)

  导入.config需要使用manuconfig,于是我们编译manuconfig,在此之前,先安装manuconfig的依赖环境

 sudo apt install libncurses5-dev

  编译manuconfig

make KERNEL=kernel8 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig

  稍等片刻,会启动manuconfig的图形界面。我们使用方向键和回车选择LOAD按钮,加载的配置文件名即为我们前一步用官方配置bcm2711_defconfig生成的.config,因此这里按照默认的.config,然后点击确定就可以。
  这时候实质上就是基于树莓派官方提供的配置,在图形界面上进行新的删改配置了。这种配置的好处就是可以保证我们对内核的配置增删是基于能启动的基础上的,最大程度上保证了裁剪后内核的可靠性。
  在图形界面中适当修改一些选项以完成内核剪裁。
  这里需要详细介绍图形界面中具体的配置项,这占据了本次工作的主体内容!
  更改结束后,双击ESC,直到退出提示询问是否要保存配置文件,选择是。这时我们裁剪过的.config配置会覆盖之前bcm2711_defconfig生成的.config

3 内核编译

  已经配置完毕存在.config文件之后,我们编译时make就会按照 .config 文件所指示配置的进行编译

make KERNEL=kernel8 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image modules dtbs -j 12

  注意,j后面的参数推荐处理器数*1.5
  根据配置的内核大小和电脑处理速度的关系,大概等待10~30分钟不等即可完成配置。

4 内核挂载与模块安装

  这里采用脚本的方法进行快速执行.
  首先将带有TF卡的读卡器插入到你的电脑上
  <注意:这一章节保持tf卡插在电脑上>
  输入

lsblk

  来查看该tf卡挂载到了哪里,一般来说可能是sdb,sdc等等.在我的电脑上如下图所示,
在这里插入图片描述
  你需要通过查看它有bootrootfs这两个分区来确定tf卡挂载的设备名,这里不一定是sdb,在你的电脑上也许是sdc或者其他名字,总之,记住这个tf卡挂载名.
  如果没有出现以上步骤的两个分区,比如说新的tf卡是没有分区的,需要对其先进行分区,具体方法这里不再介绍.你可以使用一些分区软件来完成.
  接着,cd到刚刚完成编译的文件夹,在这里用touch创建一个脚本 loadkernel.sh ,用于自动化地运行一系列命令,需要注意的是,shell脚本注释行是以 # 开头的,不是#开头的行都会被作为语句直接执行.

touch loadkernel.sh

  然后对其进行编辑,写入如下脚本,并保存
  <注意:脚本中这里用到的是sdb,实际情况根据前述tf卡挂载名进行修改>

#指定内核名称
KERNEL=kernel8
#创建挂载tf卡的文件夹
mkdir mnt
mkdir mnt/fat32
mkdir mnt/ext4
#将tf卡对应分区挂载到两个文件夹上
sudo mount /dev/sdb1 mnt/fat32
sudo mount /dev/sdb2 mnt/ext4
#安装模块至ext4分区
sudo env PATH=$PATH make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- INSTALL_MOD_PATH=mnt/ext4 modules_install
#备份原来的镜像
sudo cp mnt/fat32/$KERNEL.img mnt/fat32/$KERNEL-backup.img
#将编译生成的新的镜像放入FAT32分区
sudo cp arch/arm64/boot/Image mnt/fat32/$KERNEL.img
#将编译生成的dts文件放入FAT32分区
sudo cp arch/arm64/boot/dts/broadcom/*.dtb mnt/fat32/
sudo cp arch/arm64/boot/dts/overlays/*.dtb* mnt/fat32/overlays/
sudo cp arch/arm64/boot/dts/overlays/README mnt/fat32/overlays/
#取消tf卡的挂载
sudo umount mnt/fat32
sudo umount mnt/ext4

  注意,这里模块的安装,是把前面配置为M的模块都放在/lib/module/uname -r/,而启动系统后如果需要用到相关模块,就可以使用相关指令进行加载和卸载.如果我们对某个模块使用非常频繁或者非常重要,就可以在编译时将其选择Y编译进入内核,这也就会启动自加载,而不需要手动加载. [模块加载与卸载] 详细内容见第五节
  至此,完成了内核的编译裁剪安装全流程,我们进入boot文件夹,右键kernel8.img查看裁剪后内核的大小
在这里插入图片描述

  拔下TF卡,插入到数莓派上.等待数秒,绿灯不闪时,如果能够正常启动,我们就可以通过putty对其进行ssh连接.
  当然,内核的替换并不会修改我们之前配置的一些启动选项,比如说登录名pi和密码123456,同时,ext4中的一些用户文件也依然存在.
  登录后,输入uname -a就可以查看该内核的版本号信息
  这是替换内核之前的信息

在这里插入图片描述

  
  这是替换内核之后的信息

在这里插入图片描述

5 模块的加载与卸载

本节参考
http://t.zoukankan.com/jjzd-p-6438641.html
https://blog.csdn.net/weixin_44502943/article/details/121402205

  在上级节中,我们选择了把一些项目作为模块编译,并将其安装在了数莓派/lib/module/uname -r/文件夹下,当数莓派系统需要使用时,我们再通过一些指令把这些模块加载进来.当不需要时,我们通过特定指令对其进行卸载.
在这里插入图片描述
  如上图,这些.ko名称结尾的都是之前安装的模块.

  lsmod命令可以查看当前正在运行的模块.
在这里插入图片描述
  modinfo <modname> 查看模块的信息,包括描述,依赖关系,证书,版本等
在这里插入图片描述
  其中很多模块是依赖于其他模块的,模块的依赖关系都靠modules.dep文件指示,该文件位置如下图所示
  
在这里插入图片描述
  
  模块的加载有两种指令,分别是
  insmode <xxx/xxx/modulename.ko>
  modprobe <modulename>
  后者的好处是会自动处理依赖关系,加载示例如下
  
在这里插入图片描述
  
  rmmod <modname>进行模块卸载
  
在这里插入图片描述

   任务: 实现模块加载卸载,对比几个指令的区别.详细介绍模块究竟是什么,其运行详细机制.
   拓展:尝试自己编写一个简单模块,加载之.

  

6 根文件系统安装

   数莓派的启动流程可以参考

https://blog.csdn.net/qq_45172832/article/details/126040945

   boot分区创建用户配置文件可以参考下面文章第三节

https://blog.csdn.net/fanbinjiim/article/details/124529243

   从本质上来说,需要研究给你一张空的tf卡,如何为其分区,安装bootloader,了解数莓派启动全流程,安装根文件系统,再编译内核,再下载模块并启动这样的全流程太过繁杂,因此我想到的办法是可以在现有的基础上使用fdisk命令删除分区.
   本节重要参考

https://blog.csdn.net/yuhangfeng/article/details/124845483
https://blog.csdn.net/yuhangfeng/article/details/124888832?spm=1001.2014.3001.5502

   在之前我们以及构建好的数莓派系统的基础上,把tf卡插入到电脑上.然后用fdisk删除ext4分区,并创建一个新的分区代替ext4,比方说ext3或者别的,参考老师ppt.然后新建好分区后,在这个新的分区上使用busybox创建根文件系统,其中包括了shell命令和库的编译.最后安装模块.
   当然也可以使用数莓派镜像安装器来进行boot分区安装.

存在的问题:无法启动
1.交叉编译器正确安装
2.分区删除干净
3.内核配置时选择支持该种类的文件系统FS
4.内核配置的启动段配置Boot options
关于内核启动bootargs设置
https://blog.csdn.net/weixin_43793181/article/details/115461081

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【从零到一的Raspberry】数莓派踩坑实录(二) 内核编译配置和模块安装 的相关文章

随机推荐

  • matlab工作区显示的是什么,matlab工作区介绍

    Workspace 工作区窗口 Command History 指令历史记录窗口 Current Directory 当前目录选择窗口 主要内容 Matlab简介 数组和矩阵 Matlab绘图 Matlab Workspace 工作区窗口
  • Spring oauth2.0 刷新token后设置原token5分钟内继续可用

    默认情况下刷新token后原token会立马不可用 但是在某些情况下我们需要刷新token后原token在一定时间内继续可用 例如微信的刷新token 通过查看DefaultTokenServices中的刷新token方法refreshAc
  • 栈破坏检测

    在C C 语言中 由于代码书写人员能够直接通过指针来操作内存的内容 在通常的时候没有可靠的方法来防止对数组的越界访问读写操作 但是 我们可以在发生了越界访问的时候 在没有造成任何有害结果之前 尝试检测到他 栈保护机制是在栈帧中任何局部缓冲区
  • Maven之pom.xml文件中的Build配置

    Maven之pom xml文件中的Build配置 前言 在日常的开发中 我们经常使用maven来管理和构建我们的项目 即使现在使用了各种springboot等方便快捷的框架 jar包的引入也是通过maven来进行的 因此有必要了解pom x
  • Batch和Epoch之间的区别是什么?

    写在前面 快速理解 随机梯度下降 SGD 是一种迭代学习算法 它使用训练数据集来更新模型 Batch 批量 大小是梯度下降算法的超参数 在模型的内部参数更新之前控制训练样本的数量 一个周期内一次批量训练的样本数 Epoch数是梯度下降算法的
  • python 图片与二进制之间的转换

    一 PIL格式图片转成二进制 先读取为PIL格式 再转为二进制 import io import base64 from PIL import Image def image2byte image 图片转byte image 必须是PIL格
  • java代码分层 handle_java 代码分层

    JAVA代码层次 阿里推荐 开放接口层 可直接封装 Service 方法暴露成 RPC 接口 通过 Web 封装成 http 接口 进行 网关安全控制 流量控制等 终端显示层 各个端的模板渲染并执行显示的层 当前主要是 velocity 渲
  • PyTorch torch.optim.lr_scheduler 学习率设置 调参 -- CosineAnnealingLR

    lr scheduler 学习率 学习率的参数调整是深度学习中一个非常重要的一项 Andrew NG 吴恩达 认为一般如果想调参数 第一个一般就是学习率 作者初步学习者 有错误直接提出 热烈欢迎 共同学习 感谢Andrew ng的机器学习和
  • easyui tabs 一个窗口修改完成后刷新另一个窗口

    在一个tab中添加或删除数据后 要改变主页 相当于链接的另一个tab 的内容 1 在要刷新的窗口的初始化中添加 js 刷新方法 并保存到 window top 中 window top Refresh CloudHomePage Conte
  • 二、基础平滑、面积折线图与折线堆叠、面积堆叠《手把手教你 ECharts 数据可视化详解》

    注 本系列教程需要对应 JavaScript html css 基础 否则将会导致阅读时困难 本教程将会从 ECharts 的官方示例出发 详解每一个示例实现 从中学习 ECharts ECharts 官方示例 https echarts
  • Mybatis学习(二)--getMapper接口绑定方案和多参数传值

    在Mybatis的基础使用中 如果想向一个sql语句中传递多个参数 只能将parameterType设置为某个类或者Map 不能直接传入多个参数 接口绑定方案可以实现直接传入多个参数 Mybatis的接口绑定方案与基本的使用方法不同的地方在
  • unity 射线获取坐标

    射线 碰到障碍物就会断开 鼠标点击屏幕获得一个二维坐标 通过相机的射线转换为三维世界坐标 private Vector3 worldPos 鼠标点击的点所对应的世界里面的位置 点击鼠标右键 if Input GetMouseButton 1
  • ThinkPHP文件包含漏洞分析

    出品 长白山攻防实验室 ID A Tree 0x00 声明 以下内容 来自长白山攻防实验室的A Tree作者原创 由于传播 利用此文所提供的信息而造成的任何直接或间接的后果和损失 均由使用者本人负责 长白山攻防实验室以及文章作者不承担任何责
  • Vue3集成高德地图方法

    1 注册高德开发者账号 获取key和安全密钥 2 下载依赖 可参考高德官方文档 https lbs amap com api jsapi v2 guide webcli map vue1 npm i amap amap jsapi load
  • GD32f103 8M晶振改12M , 要修改的地方

    手里的单片机是gd32f103ret6 晶振和官方库默认的8M不一致 导致串口乱码 网上找了好久全是STM32的例子 不过还是有参考意义的 以下是gd32f10x 的设置方式 1 Keil中的Target设置 PS 这一项好像会自动设置 安
  • 7、变量进阶

    7 变量进阶 理解 目标 变量的引用 可变和不可变类型 局部变量和全局变量 01 变量的引用 变量 和 数据 都是保存在 内存 中的 在 Python 中 函数 的 参数传递 以及 返回值 都是靠 引用 传递的 1 1 引用的概念 在 Py
  • [论文阅读]《how to share a secret》

    how to share a secret Adi Shamir 文章主要讲了如何将数据D分为n份 任意k份可以重组成D 任意k 1份不会泄露任何关于D的信息 这种技术能为密码系统构建鲁棒的密钥管理机制 即使灾难破坏一半信息或者安全性被破坏
  • 浅谈C++

    引子 程序运行时产生的数据都属于临时数据 程序一旦运行结束都会被释放通过文件可以将数据持久化 C 中对文件操作需要包含头文件 lt fstream gt C 提供了丰富的文件操作功能 你可以使用标准库中的fstream库来进行文件的读取 写
  • 【接口测试】POST请求提交数据的三种方式及Postman实现

    1 什么是POST请求 POST请求是HTPP协议中一种常用的请求方法 它的使用场景是向客户端向服务器提交数据 比如登录 注册 添加等场景 另一种常用的请求方法是GET 它的使用场景是向服务器获取数据 2 POST请求提交数据的常见编码格式
  • 【从零到一的Raspberry】数莓派踩坑实录(二) 内核编译配置和模块安装

    写在前面 本次作业具有挑战性 不过不管哪一环节出错了 你都要知道如何把它还原到初始状态 这样你就不是在危险地操作 而有还原的保障 因此在第0节我会介绍一种还原数莓派系统的方法 这样你就可以在内核无法运行时还原到默认系统 后面从第一章开始 带