前言:来到这里,我们正式学习linux 的内核的配置和编译。
一、首先我们先来了解一下树莓派等芯片带操作系统的启动过程 1.1 X86、Intel、windows 等设备的启动过程 启动过程:电源- > BIOS -> windows 内核 -> C,D 盘的启动 -> 程序的启动(例如QQ 的启动)
1.2 嵌入式产品(树莓派、mini2440、mini6410、nanopi、海思、RK(瑞芯微) )的启动过程 启动过程:电源 -> BootLoader (引导操作系统启动) -> linux 内核 -> 文件系统(根据功能性来组织文件夹,带访问权限)-> 实实在在的嵌入式产品的启动(例如KTV 点歌机)
1.3 安卓操作系统的启动过程 启动过程:电源 -> fastBoot/Bootloader/ -> linux 内核 -> 文件系统 -> 虚拟机 -> HOME 应用程序 -> 点击某图标打开某app
1.4 C51 、STM32 (裸机,不带操作系统)的开发流程 不带操作系统的裸机开发是C语言直接操控底层寄存器实现相关业务。 业务流程型的裸机代码: 例如:遥控灯:while (1) 垃圾桶:WemosD1 LOOP (函数) 恩智浦智能车:stm32
以上内容虽然是偏向概念,但是在面试的时候也可以跟别人聊,可以增加你对嵌入式设备的了解
二、树莓派linux源码目录树的分析 linux内核源代码目录树结构详解
2.1 首先我们先来聊一下linux 内核 linux 内核大约由1.3w个C文件组成,1100w行代码左右 linux 是开源的,免费的,linux 开源社区由其工作者和爱好者共同进行维护
linux 是一个开源的,支持多架构多平台代码(可以说是非常的牛逼的) 可以执行是非常高的
但是linux 内核编译出来一般就是几M,一般是4M左右
因为是支持多平台多架构,所以在编译之前是需要进行配置的,配置成适合的目标平台来用
例如:ARM架构
海思,友善之臂,RK,树莓派,nanopi
X86架构
PowerPC
MIPS
三、树莓派linux源码的配置 首先我们先来了解一个问题:为什么要对linux内核进行配置呢? 答案:我们都知道驱动代码编写完后, 驱动代码的编译需要一个提前编译好的内核,那么进行内核的编译就必须要进行配置,配置的最终目标会生成.config 文件,该文件指导Makefile 去把有用的东西组织成内核。
3.0 交叉编译工具链的安装 由于我之前已经安装了交叉编译工具链所以省去了这一个步骤,如果没安装的参考前面交叉编译工具链的获得的博文
3.0.1 树莓派linux内核源码的下载 树莓派linux内核源码的下载网址 然后在下图黄色框内选择对应的版本下载,我的树莓派的版本是4.14.98-v7+ ,所以我选择的下载版本是4.14.y ,最好下载到windows跟linux的共享文件夹里,这样在虚拟机里直接从共享文件夹里拷贝出来即可,然后cp /mnt/hgfs/sharefromwindows/linux-rpi-4.14.y /home/lhb/SYSTEM ,然后将其解压
配置内核源码的三种方式
一般我们购买了芯片,厂家都会配linux 内核源码,比如说我们买了树莓派,厂家就会向我们提供树莓派linux 内核源码
配置config(以下的所有操作都是用到方式一这种cp厂家的config)
linux源码中有很多工程: 树莓派1的工程是bcmrpi_defconfig ; 树莓派2跟3的工程是bcm2709_defconfig ;
3.1 方式一 使用厂家提供的config 进行配置(即 cp 厂家.config .config )
查找厂家的config 指令:find -name *_defconfig 然后在终端执行以下指令
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make bcm2709_defconfig
这个命令的作用就是获取bcm2709_defconfig 的配置到config 中来
除了以上的方式,我们也可以用最传统的方式:cp arch/arm/configs/bcm2709_defconfig .config 然后去使用这个.config
ARCH=arm(指定当前要编译的是arm 架构,虽然树莓派是64位的,但这里仍然是选择arm ,而不是arm64 ) CROSS_COMPILE=arm-linux-gnueabihf- (指定编译器是树莓派,即交叉工具链,arm 交叉工具链的安装以及相关环境变量的设置在前面的博文有记录) KERNEL=kernel7 (指明kernel 类型,树莓派1设置为kernel ,树莓派2,3设置为kernel7 ) make bcm2709_defconfig(make 为配置命令)
以上黄色框内的说明就是已经将厂家的config获取到我们自己的config中来了
3.2 方式二 通过make menuconfig 一项项的来配置,通常都是基于厂家的config来进行配置 (如果没什么要改的话就没必要进行这一步)
在此之前,我们要先来安装一下等下要用到的库
安装必要的库:
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
3.2.1 对内核菜单进行配置 执行ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make menuconfig 之后会出现以下界面 选项讲解:
General setup —>(通用选项)
[ * ] Enable loadable module support —> 内核模块选项
[ * ]Enable the block layer —> 块设备逻辑层选项(大文件支持、分区、I/O调度)
System Type —>(平台选项)
Bus support —> 总线选项
Kernel Features —>内核特征
Boot options —> 引导选项
CPU Power Management —> CPU电源管理选项
Floating point emulation —> 浮点运算
Userspace binary formats —> 用户程序格式
Power management options —> 电源管理选项
[*] Networking support —> 网络协议选项
Device Drivers —> 设备驱动
Firmware Drivers ---- 驱动固件选项
File systems —> 文件系统选项
Kernel hacking —> 内核调试选项
Security options —> 安全模块选项
例如:我们要进行配置的是驱动部分
指令解释:使用空格可以切换[ ]里面的模式 [ * ]:编译进内核(*代表Y,编译进内核,zImage包含了驱动) [ M ]:编译成模块(以模块的方式生成驱动文件xxx.ko,系统启动后,通过命令inmosd xxx.ko来加载驱动) [ ]:表示不需要的部分
修改完毕后,保存退出
3.3 方式三 完全自己来进行(这种方式不太现实,需要比较高深的技术)
四、树莓派linux内核源码的编译 编译指令:
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make -j4 zImage modules dtbs
make -j4:指定用多少电脑资源进行编译(j4是四核的意思,我的虚拟机的核数设置成了1核,所以我使用的是j1,这个要每个人根据自己的电脑的配置以及虚拟机的设置的核数来决定)
zImage:生成内核镜像
modules:要生成驱动模块
dtbs:生成配置文件
编译的过程大概需要一个小时左右(这个主要看电脑的配置),验证是否成功的方法 4.1 首先观察在编译过程中是否有错误,如果跑了几分钟了还没有报错的话,那基本是不会出错的了
4.2 观察源码目录树下是否多了vmlinux ,有的话就成功了,失败无此文件
4.3 我们在路径/SYSTEM/linux-rpi-4.14.y/arch/arm/boot 底下查看次内核文件路径zImage (我们需要的目标镜像)
vmlinux是未压缩的linux,zImage是压缩好的linux(是ARM linux架构常用的一种压缩镜像文件)
经过以上所有的步骤,我们已经成功的把linux 内核编译好并生成相关的压缩镜像文件
4.4 把zImage 打包成树莓派可用的xxx.img 文件 指令:./scripts/mkknlimg arch/arm/boot/zImage ./kernel_new.img 在当前目录生成一个kernel_new.img 文件,这个就是树莓派新的镜像文件
4.5 完成以上步骤后,插入装有sd卡的U盘,并把U盘映射到虚拟机上面来 想要U盘映射成功,一定要确保以下黄框内的服务打开(按下win+r,然后输入services.msc ) 在确保以上服务打开后,如果还不行的话,就执行以下操作,重新选择一下虚拟机的USB 然后通过以下图中的操作进行连接U盘 然后在命令行模式下输入dmesg查看一下内核的一些信息 如果出现以上图中的sdb1 和 sdb2 那么说明U盘已经成功的映射到虚拟机上了
把U盘映射到虚拟机后,我们发现有sdb1和sdb2两个分区:
一个是fat分区,是boot相关的内容kernel的img文件就是在这个分区里;
一个是ext4分区,也就是系统的根目录分区
4.6 创建新目录并挂载U盘 4.6.1 在/home/lhb (即根目录)底下创建新目录 4.6.2 挂载U盘(这一步一定不能漏) 在路径/home/lhb 下输入以下两条指令即可
sudo mount /dev/sdb1 data1 挂载U盘的sdb1文件分区到当前路径下的data1文件夹 一个fat分区,是boot相关的内容,kernel的img
sudo mount /dev/sdb2 data2 挂载U盘的sdb2文件分区到当前路径下的data2文件夹 一个是ext4分区,也就是系统的根目录分区。
挂载成功后,分别查看data1 和data2 两个文件夹的内容
现在我们来明白一个问题,就是为什么要进行挂载? 比如mount /dev/sdb1 ~/Share/ ,把新硬盘的区sdb1挂载到工作目录的~ /Share/文件夹下,之后访问这个~/Share/文件夹就相当于访问这个硬盘的sdb1分区了,对/Share/的任何操作,都相当于对sdb1里文件的操作。所以Linux下,mount挂载的作用,就是将一个设备(通常是存储设备)挂接到一个已存在的目录上。访问这个目录就是访问该存储设备。
4.7 安装modules(设备驱动文件) 安装完modules之后 例如:hdmi接口、usb、wifi、io口等等的设备才能用,如果不安装设备驱动文件,内核也能安装成功,但是上面所列举的相关接口用不了就是了
指令: sudo ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make INSTALL_MOD_PATH=[ext4] modules_instal l
操作ext4分区需要root权限
[ext4]为第二分区(sdb2)虚拟机上挂载的地址(data2的位置),需要根据自己的地址更改
我的指令:
sudo ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make INSTALL_MOD_PATH=/home/lhb/data2 modules_install
在树莓派源码目录底下输入我的指令
4.8 安装更新 kernel.img 文件,注意镜像名字是kernel7.img 4.8.1 首先我们先把原本的镜像进行备份,以防新的镜像损坏或其他问题无法启动
cd /home/lhb/data1
cp kernel7.img kernel7old.img
4.8.2 接着把新编译生成的镜像拷贝到data1 即boot 分区底下,起名为kernel7.img (覆盖掉之前的kernel7.img即可) cp kernel_new.img /home/lhb/data1/kernel7.img
在这里,我来介绍两个小技巧
- 查看文件的大小指令
du xxx 这样是以kb 为单位查看文件的大小 du xxx -h 在文件的后加上-h 后,是以M 为单位查看文件的大小 - 查看文件在拷贝过程中是否有损坏
在文件拷贝的过程中有一个md5 的值,如果拷贝过程中文件没有损坏的话,md5 的值是不变的,如果拷贝失败或者是文件损坏的话,这个值就会改变 从上图中可以看出,在拷贝过程中文件的md5sum 的值是没改变的,所以拷贝成功了
4.9 拷贝相关配置文件
cp arch/arm/boot/dts/.*dtb* [fat]/
cp arch/arm/boot/dts/overlays/.*dtb* [fat]/overlays/
cp arch/arm/boot/dts/overlays/README [fat]/overlays/
操作fat 分区,需要root 权限。 [fat] 为第一分区(sdb1) 虚拟机上挂载的地址(data1 的位置),需要根据自己的地址更改
我的拷贝指令:
cp arch/arm/boot/dts/.*dtb* /home/lhb/data1
cp arch/arm/boot/dts/overlays/.*dtb* /home/lhb/data1/overlays/
cp arch/arm/boot/dts/overlays/README /home/lhb/data1/overlays/
断开挂载,把cmdline.txt更改成以下内容,用串口查看是否刷机成功
dwc_otg.lpm_enable=0 console=tty1 console=serial0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
温馨提示:其实不用改都行,如果之前树莓派连过自己wifi的话,更换内核后是不会消除自己的信息的,所以我用wifi远程连接树莓也是可行的
删除虚拟机里的data1 和data2
sudo umount data1
sudo umount data2
rm -r data1 data2
5. 启动树莓派 用串口或者远程登录树莓派后,用指令uname -r查看内核版本,发现内核信息已经是发生改变了 更换内核前: 更换内核后: 所以到此内核更换成功 本文参考博文
学习笔记,仅供参考
|