树莓派Linux内核开发

树莓派Linux内核开发

准备工作

注意:要选择树莓派相应的系统内核版本下载

uname -r //查看系统内核版本

image-20230522161827793

树莓派上的版本是6.1.21。

  • 下载相应的交叉编译工具链在ubuntu18.04上面。

  • 解压交叉编辑工具和树莓派系统内核源码

嵌入式设备的启动过程

x86架构的电脑

启动过程:电源->BIOS->window内核->C,D盘->启动应用程序(qq)

嵌入式产品:树莓怕,nanopi,海思

启动过程:电源->Bootloader(引导操作系统启动)->Linux内核->文件系统(根据功能性来组织文件夹,在根目录下面)->应用程序

安卓

启动过程:电源->fastBoot/Bootloader->Linux内核->文件系统->虚拟机->home应用程序(就是我们的手机页面)

linux内核源码树目录

一个Linux源码大约有1.3w个C文件,1100W行代码

Linux是一个开源,支持多架构多平台的代码,可执行性非常高,但是Linux内核编译出来一般就几M

因为支持多平台,多架构,所以编译之前要配置,配置成适合的目标平台来用

Linux内核源代码目录树结构。

Linux内核源代码目录树结构 - maxiongying - 博客园 (cnblogs.com)

arch:包含和硬件体系结构(架构)相关的代码,每种平台占一个相应的目录。从里面我们能看到arm、alpha、i386、mips、ia64这些文件夹,每种处理器架构都有不一样的硬件模块,这里就是要针对不同的架构进行不同的初始化。
 
block:部分块设备驱动程序。
 
crypto:常用加密和散列算法(如AES、SHA等),还有一些压缩和CRC校验算法。
 
Documentation:关于内核各部分的通用解释和注释。
 
drivers:设备驱动程序,每个不同的驱动占用一个子目录。
 
fs:各种支持的文件系统,如ext、fat、ntfs等。
 
include:头文件。其中,和系统相关的头文件被放置在linux子目录下。
 
init:内核初始化代码(注意不是系统引导代码)。
 
ipc:进程间通信的代码。
 
kernel:内核的最核心部分,包括进程调度、定时器等,和平台相关的一部分代码放在arch/*/kernel目录下。
 
lib:库文件代码。
 
mm:内存管理代码,和平台相关的一部分代码放在arch/*/mm目录下。
 
net:网络相关代码,实现了各种常见的网络协议。
 
scripts:用于配置内核文件的脚本文件。
 
security:主要是一个SELinux的模块。
 
sound:常用音频设备的驱动程序等。
 
usr:实现了一个cpio。

Linux内核配置

驱动代码的编写,驱动代码的编译需要一个提前编译好的内核,编译内核就需要配置。配置的最终目标会生成 .config文件,该文件指导Makefile去把有用东西组织成内核

第一种方法:

  • 1.厂家配linux内核源码,比如说买了树莓派,树莓派linux内核源码
  • cp 厂家.config .config (树莓派1的工程是bcmrpi_defconfig,树莓派2、3的工程是bcm2709_defconfig)
ARCH=arm  CROSS_COMPILE=arm-linux-gnueabihf-  KERNEL=kernel7  make bcm2709_defconfig
指定ARM架构         指定编译器                  树莓派内核             主要核心指令
  • ARCH=arm:指定为RAM架构
  • CROSS_COMPILE=arm-linux-gnueabihf- :指定交叉编译器
  • KERNEL=kernel7:指定内核版本

image-20230523162104758

第二种方法:

  • make menuconfig 一项项配置,通常是基于厂家的config来配置 (需要安装ncurse库,下面有介绍)
ARCH=arm       CROSS_COMPILE=arm-linux-gnueabihf-   KERNEL=kernel7     make menuconfig
#指定ARM架构         指定编译器                        树莓派内核           主要核心指令
  • ARCH=arm:指定为RAM架构
  • CROSS_COMPILE=arm-linux-gnueabihf- :指定编译器
  • KERNEL=kernel7:指定内核版本

执行上面的命令后,会进入一个配置页面,上面的命令需要安装ncurses库。

安装Ncurses库

sudo apt-get install bc
sudo apt-get install libncurses5-dev libncursesw5-dev
sudo apt-get install zlib1g:i386
sudo apt-get install libc6-i386 lib32stdc++6 lib32gcc1 lib32ncurses5

image-20230523162328937

  • 上下左右键进行操作
  • Enter进入下一个子菜单(末尾带箭头的会有子菜单)
  • " M " 模块方式生成驱动文件xxx.ko 系统启动后,通过命令inmosd xxx.ko 加载
  • " * " 编译进内核 zImage包含了驱动

开始编译Linux内核

ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make -j4 zImage modules dtbs
  • ARCH=arm:指定为RAM架构
  • CROSS_COMPILE=arm-linux-gnueabihf- :指定编译器
  • KERNEL=kernel7:指定内核版本
"kernel7"是指树莓派操作系统中针对ARMv7架构的内核版本。树莓派3B+属于ARMv7架构,因此在树莓派3B+上使用的内核版本通常被称为"kernel7"。这个命名约定帮助区分不同的内核版本,以适应不同的硬件架构和功能需求。

在树莓派上,"kernel7"代表ARMv7架构的内核,而"kernel8"则代表ARMv8架构(也称为ARM64或AArch64)。不同架构的内核版本在功能和优化方面可能有所差异,因此需要选择适合特定硬件架构的内核版本来确保最佳性能和兼容性。
  • -j4:四核处理器来编译(可根据虚拟机的硬件来更改)
  • zImage:生成内核镜像
  • modules:生成的驱动模块
  • dtbs:配置文件等等

大概要编译二十分钟左右!!!!

  • 查看是否编译成功:源码树目录下会生成" vmlinux " (没有压缩的Linux)

image-20230523171006650

  • 真正的生成的Linux内核在源码树目录下 arch/arm/boot 下生成的 " zImage "

image-20230523171101179

因为树莓配加载镜像需要.img文夹,所以需要将该目录下的zImage文夹打包为.img文件。

./scripts/mkknlimg arch/arm/boot/zImage ./kernel_new.img

如果使用的时6.16的内核源码,在scripts文件下面没有mkknlimg工具,这时候我们可以下载低版本的内核,把里面的mkknlimg复制过来用。

image-20230523202448053

可以看到已经生成了 kernel_new.img 文件

挂载树莓派内存卡

方法一:使用命令行操作(u盘插上虚拟机上,会有两个分区)

sudo mount /dev/sdb1 /home/xubozheng/data-fat    //存放的是 系统内核镜像
sudo mount /dev/sdb2 /home/xubozheng/data-ext4  //存放的是 系统的根目录

方式二:使用udev机制自动挂载

敲入命令 dmesg //打印内核信息

image-20230524222734785

可以看到,插入u盘的设备节点是 sdh1 和 sdh2

使用如下命令查看设备具体信息

 udevadm info --attribute-walk --name=/dev/sdh1

image-20230524223030566

在 /etc/udev/rule.d 下创建一个新的规则文件(必须是.rules结尾的文件

例如

ACTION=="add", SUBSYSTEMS=="sdh1", SUBSYSTEM=="block", RUN{program}+="/bin/mkdir  /media/%k" ,RUN{program}+="/usr/bin/systemd-mount --no-block --collect $devnode /media/%k"

内核的移植

1.首先将内核模块安装到SD中

sudo env PATH=$PATH make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=/home/xubozheng/data-ext4 modules_install

2.然后将旧的内核换成新的内核,最好备份一下

sudo cp /home/xubozheng/data-fat/$KERNEL.img /home/xubozheng/data-fat/$KERNEL-backup.img

3.开始更换

sudo cp arch/arm/boot/zImage /home/xubozheng/data-fat/$KERNEL.img

注意!!!!

$KERNEL.img 只是一个占位符,实际文件名可能会有所不同,$KERNEL.img是指操作系统内核的镜像文件

4.拷贝配置文件

sudo cp arch/arm/boot/dts/*.dtb /home/xubozheng/data-fat
sudo cp arch/arm/boot/dts/overlays/*.dtb* /home/xubozheng/data-fat/overlays/
sudo cp arch/arm/boot/dts/overlays/README /home/xubozheng/data-fat/overlays/

5.退出U盘

sudo umount /home/xubozheng/data-fat
sudo umount /home/xubozheng/data-ext4

遇到的问题

按照上述的流程确实可以更换内核,但是更换完内核之后,并不能链接网络,因为此时没有任何驱动加载进来

lsmod //此时输出为空

解决办法

https://github.com/raspberrypi 在该网址中找到firmware项目,下载该项目中的三个文件,把内存卡中boot中的三个同名文夹替换掉。

//三个文夹名字分别为
bootcode.bin
fixup.dat
start.elf

参考文献

https://mp.weixin.qq.com/s/05Hr5Z9hyTkAVekDvG6yeQ
posted @   徐博正  阅读(319)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示