编译linux内核
# 下载安装lzop库
sudo apt-get install lzop
# 解压linux压缩包
tar -vxjf xxxx.tar.bz2
# 在linux内核工程中加上shell文件,内容如下
#!/bin/sh
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v7_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
bear make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j4
编译完成以后就会在 arch/arm/boot
这个目录下生成一个叫做 zImage
的文件,zImage 就是
我们要用的 Linux
镜像文件。另外也会在 arch/arm/boot/dts
下生成很多.dtb
文件,这些.dtb
就是
设备树文件。
linux工程目录结构分析
目录结构详解
- arch目录
这个目录是和架构有关的目录,比如 arm、arm64、avr32、x86 等等架构。
arch/arm
中子目录用于控制系统引导、系统调用、动态调 频、主频设置等。arch/arm/configs
目录是不同平台的默认配置文件:xxx_defconfig
。
arch/arm/boot/dts
目录里面是对应开发平台的设备树文件。arch/arm/boot
目录下会保存编译出来的 Image 和 zImage
镜像文件,而 zImage
就是我们要 用的 linux 镜像文件
。arch/arm/mach-xxx
目录分别为相应平台的驱动和初始化文件,比如 mach-imx
目录里面就是 I.MX
系列 CPU
的驱动和初始化文件
- block目录
block
是 Linux 下块设备目录,像 SD 卡、EMMC、NAND、硬盘
等存储设备就属于块设备,
block
目录中存放着管理块设备的相关文件。
- crypto目录
crypto
目录里面存放着加密文件,比如常见的 crc、crc32、md4、md5、hash
等加密算法。
- Documentation 目录
此目录里面存放着 Linux
相关的文档,如果要想了解 Linux 某个功能模块或驱动架构的功能,就可以在 Documentation
目录中查找有没有对应的文档。
- drivers目录
驱动目录文件,此目录根据驱动类型的不同,分门别类进行整理,比如 drivers/i2c
就是 I2C
相关驱动目录,drivers/gpio
就是 GPIO
相关的驱动目录。
- firmware目录
存放固件。
- fs目录
此目录存放文件系统,比如 fs/ext2、fs/ext4、fs/f2fs 等,分别是 ext2、ext4 和 f2fs 等文件系统。
- include目录
头文件目录。
- init目录
存放 Linux 内核启动的时候初始化代码。
- ipc目录
IPC 为进程间通信,ipc 目录是进程间通信的具体实现代码。
- kernel目录
linux内核代码。
- lib目录
lib的意思就是库的意思,所以存放各种公用的库。
- mm目录
存放内存管理相关代码的目录。
- net目录
存放网络相关代码的目录。
- samples目录
存放一些示例代码的目录
- scripts目录
脚本目录,Linux 编译的时候会用到很多脚本文件,这些脚本文件就保存在此目录中。
- security目录
存放安全相关的代码。
- sound目录
存放音频相关驱动文件,音频驱动文件并没有存放到 drivers 目录中,而是单独的目录。
- tools目录
存放一些编译的时候使用到的工具。
- usr目录
存放与 initramfs 有关的代码。
initramfs是一个临时的文件系统,其中包含了必要的设备如硬盘、网卡、文件系统等的驱动以及加载驱动的工具及其运行环境,比如基本的C库,动态库的链接加载器等等。同时,那些处理根文件系统在RAID、网络设备上的程序也存放在initramfs中。由第三方程序(如Bootloader)负责将initramfs从硬盘装载进内存。
- virt目录
目录存放虚拟机相关文件。
- .config文件
跟 uboot 一样,.config 保存着 Linux 最终的配置信息,编译 Linux 的时候会读取此文件中的配置信息。最终根据配置信息来选择编译 Linux 哪些模块,哪些功能。
- Kbuild文件
有些Makefile文件会调用他。
- Kconfig文件
图形化配置界面的配置文件
- Makefile文件
编译,调用其他文件夹下面的Makefile,生成.config文件等等。顶层Makefile,需要好好的阅读一下。
- README文件
此文件详细讲解了如何编译 Linux 源码,以及 Linux 源码的目录信息。
VSCode 创建linux源码工程
先创建.vscode
目录并新建文件settings.json
。其中的内容是:
{
/*在收索的路径中去掉文件夹或者文件*/
"search.exclude": {
"**/node_modules": true,
"**/bower_components": true,
"**/*.o": true,
"**/*.su": true,
"**/*.cmd": true,
"Documentation": true,
".tmp*": true,
/* 屏蔽不用的架构相关的文件 */
"arch/alpha": true,
"arch/arc": true,
"arch/arm64": true,
"arch/avr32": true,
"arch/[b-z]*": true,
"arch/arm/plat*": true,
"arch/arm/mach-[a-h]*": true,
"arch/arm/mach-[n-z]*": true,
"arch/arm/mach-i[n-z]*": true,
"arch/arm/mach-m[e-v]*": true,
"arch/arm/mach-k*": true,
"arch/arm/mach-l*": true,
/* 屏蔽排除不用的配置文件 */
"arch/arm/configs/[a-h]*": true,
"arch/arm/configs/[j-z]*": true,
"arch/arm/configs/imo*": true,
"arch/arm/configs/in*": true,
"arch/arm/configs/io*": true,
"arch/arm/configs/ix*": true,
/* 屏蔽掉不用的 DTB 文件 */
"arch/arm/boot/dts/[a-h]*": true,
"arch/arm/boot/dts/[k-z]*": true,
"arch/arm/boot/dts/in*": true,
"arch/arm/boot/dts/imx1*": true,
"arch/arm/boot/dts/imx7*": true,
"arch/arm/boot/dts/imx2*": true,
"arch/arm/boot/dts/imx3*": true,
"arch/arm/boot/dts/imx5*": true,
"arch/arm/boot/dts/imx6d*": true,
"arch/arm/boot/dts/imx6q*": true,
"arch/arm/boot/dts/imx6s*": true,
"arch/arm/boot/dts/imx6ul-*": true,
"arch/arm/boot/dts/imx6ull-9x9*": true,
"arch/arm/boot/dts/imx6ull-14x14-ddr*": true,
"arch/arm/boot/dts/.[a-h]*": true,
"arch/arm/boot/dts/.[k-z]*": true,
"arch/arm/boot/dts/.in*": true,
"arch/arm/boot/dts/.imx1*": true,
"arch/arm/boot/dts/.imx7*": true,
"arch/arm/boot/dts/.imx2*": true,
"arch/arm/boot/dts/.imx3*": true,
"arch/arm/boot/dts/.imx5*": true,
"arch/arm/boot/dts/.imx6d*": true,
"arch/arm/boot/dts/.imx6q*": true,
"arch/arm/boot/dts/.imx6s*": true,
"arch/arm/boot/dts/.imx6ul-*": true,
"arch/arm/boot/dts/.imx6ul*": true,
"arch/arm/boot/dts/.imx6ull-9x9*": true,
"arch/arm/boot/dts/.imx6ull-14x14-ddr*": true
},
/*去掉显示的文件和文件夹*/
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"**/*.o": true,
"**/*.su": true,
"**/*.cmd": true,
"Documentation": true,
".tmp*": true,
/* 屏蔽不用的架构相关的文件 */
"arch/alpha": true,
"arch/arc": true,
"arch/arm64": true,
"arch/avr32": true,
"arch/[b-z]*": true,
"arch/arm/plat*": true,
"arch/arm/mach-[a-h]*": true,
"arch/arm/mach-[n-z]*": true,
"arch/arm/mach-i[n-z]*": true,
"arch/arm/mach-m[e-v]*": true,
"arch/arm/mach-k*": true,
"arch/arm/mach-l*": true,
/* 屏蔽排除不用的配置文件 */
"arch/arm/configs/[a-h]*": true,
"arch/arm/configs/[j-z]*": true,
"arch/arm/configs/imo*": true,
"arch/arm/configs/in*": true,
"arch/arm/configs/io*": true,
"arch/arm/configs/ix*": true,
/* 屏蔽掉不用的 DTB 文件 */
"arch/arm/boot/dts/[a-h]*": true,
"arch/arm/boot/dts/[k-z]*": true,
"arch/arm/boot/dts/in*": true,
"arch/arm/boot/dts/imx1*": true,
"arch/arm/boot/dts/imx7*": true,
"arch/arm/boot/dts/imx2*": true,
"arch/arm/boot/dts/imx3*": true,
"arch/arm/boot/dts/imx5*": true,
"arch/arm/boot/dts/imx6d*": true,
"arch/arm/boot/dts/imx6q*": true,
"arch/arm/boot/dts/imx6s*": true,
"arch/arm/boot/dts/imx6ul-*": true,
"arch/arm/boot/dts/imx6ull-9x9*": true,
"arch/arm/boot/dts/imx6ull-14x14-ddr*": true,
"arch/arm/boot/dts/.[a-h]*": true,
"arch/arm/boot/dts/.[k-z]*": true,
"arch/arm/boot/dts/.in*": true,
"arch/arm/boot/dts/.imx1*": true,
"arch/arm/boot/dts/.imx7*": true,
"arch/arm/boot/dts/.imx2*": true,
"arch/arm/boot/dts/.imx3*": true,
"arch/arm/boot/dts/.imx5*": true,
"arch/arm/boot/dts/.imx6d*": true,
"arch/arm/boot/dts/.imx6q*": true,
"arch/arm/boot/dts/.imx6s*": true,
"arch/arm/boot/dts/.imx6ul-*": true,
"arch/arm/boot/dts/.imx6ul*": true,
"arch/arm/boot/dts/.imx6ull-9x9*": true,
"arch/arm/boot/dts/.imx6ull-14x14-ddr*": true
}
}
顶层Makefile分析
基本和uboot的Makefile分析相似。
make zImage的过程
各个Image区别
vmlinux 是 ELF 格式的文件,但是在实际中我们不会使用 vmlinux,而是使用 zImage 或 uImage 这样的 Linux 内核镜像文件。
-
vmlinux 是编译出来的最原始的内核文件,是未压缩的。大小16M左右。
-
Image 是 Linux 内核镜像文件,但是 Image 仅包含可执行的二进制数据。Image 就是使用 objcopy 取消掉 vmlinux 中的一些其他信息,比如符号表什么的。但是 Image 是没有压缩过的,Image 保存
arch/arm/boot
目录下,其大小大概在 12MB 左右。 -
zImage 是经过 gzip 压缩后的 Image,经过压缩以后其大小大概在 6MB 左右。
-
uImage 是老版本 uboot 专用的镜像文件,uImag 是在 zImage 前面加了一个长度为 64字节的“头”,这个头信息描述了该镜像文件的类型、加载位置、生成时间、大小等信息。但是新的 uboot 已经支持了 zImage 启动!所以已经很少用到 uImage 了。
# 使用“make zImage”编译的 Linux 内核的话,首先肯定要先编译出 vmlinux
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
@ make -f ./scripts/Makefile.build obj=arch/arm/boot MACHINE=arch/arm/boot/zImage
# 使用 scripts/Makefile.build 文件来完成 vmlinux 到 zImage 的转换
linux内核移植
修改顶层Makefile
修改顶层 Makefile
,直接在顶层 Makefile
文件里面定义 ARCH
和 CROSS_COMPILE
这两个的变量值为 arm
和 arm-linux-gnueabihf-
。这样在编译的时候就不用输入很长的命令了。
配置并编译 Linux 内核
和 uboot
一样,在编译 Linux
内核之前要先配置 Linux
内核。每个板子都有其对应的默认配 置 文 件 , 这 些 默 认 配 置 文 件 保 存 在 arch/arm/configs
目录中。imx_v7_defconfig
和 imx_v7_mfg_defconfig
都可作为 I.MX6ULL EVK
开发板所使用的默认配置文件。但是这里建议使用 imx_v7_mfg_defconfig
这个默认配置文件,首先此配置文件默认支持 I.MX6UL
这款芯片,而且重要的一点就是此文件编译出来的 zImage
可以通过 NXP 官方提供的 MfgTool 工具烧写!!imx_v7_mfg_defconfig
中的“mfg”
的意思就是 MfgTool
make clean # 清理工程
make imx_v7_mfg_deconfig # 配置linux
make V=1 -j8 # 编译
Linux 内核编译完成以后会在 arch/arm/boot
目录下生成 zImage 镜像文件,如果使用设备树的话还会在 arch/arm/boot/dts
目录下开发板对应的.dtb(设备树)文件,比如 imx6ull-14x14-evk.dtb
就是 NXP 官方的 I.MX6ULL EVK 开发板对应的设备树文件
在linux中添加自己的开发板
添加开发板默认配置文件
将 arch/arm/configs
目录下的 imx_v7_mfg_defconfig
重新复制一份 ,命名为imx_dongfang_emmc_defconfig
cd arch/arm/configs/
cp imx_v7_mfg_defconfig imx_dongfang_emmc_defconfig
添加开发板对应的设备树文件
进入目录 arch/arm/boot/dts
中,复制一份 imx6ull-14x14-evk.dts
,然后将其重命名为 imx6ull-dongfang-emmc.dts
。
cd arch/arm/boot/dts
cp imx6ull-14x14-evk.dts imx6ull-dongfang-emmc.dts
.dts
是设备树源码文件,编译 Linux
的时候会将其编译为.dtb
文件。imx6ull-dongfang-emmc.dts
创 建 好 以 后 我 们 还 需 要 修 改 文 件 arch/arm/boot/dts/Makefile
, 找 到 “ dtb-$(CONFIG_SOC_IMX6ULL)
”配置项,在此配置项中加入“imx6ull-dongfang-emmc.dtb
”。
vi Makefile
/dtb-$(CONFIG_SOC_IMX6ULL) # 收索到该配置所在地方
# 在其中添加一样代码
# imx6ull-dongfang-emmc.dtb \
编译修改的自己的linux。添加mx6ull_dongfang_emmc.sh
文件
#!/bin/bash
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_dongfang_emmc_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
bear make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j8
CPU 主频和网络驱动修改
CPU 主频修改
进入根文件系统终端后,可以使用cat /proc/cpuinfo
查看CPU信息。
BogoMIPS 是 Linux 系统中衡量处理器运行速度的一个 “ 尺 子 ”, 处理器性能越强 , 主频越高 , BogoMIPS 值 就越大 。BogoMIPS 只是粗略的计算 CPU 性能,并不十分准确。但是我们可以通过 BogoMIPS 值来大致
的判断当前处理器的性能。
查看工作频率:进入到目录/sys/bus/cpu/devices/cpu0/cpufreq
中,此目录下会有很多文件。
- cpuinfo_cur_freq:当前 cpu 工作频率,从 CPU 寄存器读取到的工作频率。
- cpuinfo_max_freq:处理器所能运行的最高工作频率(单位: KHz)。
- cpuinfo_min_freq :处理器所能运行的最低工作频率(单位: KHz)。
- cpuinfo_transition_latency:处理器切换频率所需要的时间(单位:ns)。
- scaling_available_frequencies:处理器支持的主频率列表(单位: KHz)。
- scaling_available_governors:当前内核中支持的所有 governor(调频)类型。
- scaling_cur_freq:保存着 cpufreq 模块缓存的当前 CPU 频率,不会对 CPU 硬件寄存器进
行检查。 - scaling_driver:该文件保存当前 CPU 所使用的调频驱动。
- scaling_governor:governor(调频)策略,Linux 内核一共有 5 中调频策略,
①、Performance,最高性能,直接用最高频率,不考虑耗电。
②、Interactive,一开始直接用最高频率,然后根据 CPU 负载慢慢降低。
③、Powersave,省电模式,通常以最低频率运行,系统性能会受影响,一般不会用这个!
④、Userspace,可以在用户空间手动调节频率。
⑤、Ondemand,定时检查负载,然后根据负载来调节频率。负载低的时候降低 CPU 频率,这样省电,负载高的时候提高 CPU 频率,增加性能。 - scaling_max_freq:governor(调频)可以调节的最高频率。
- cpuinfo_min_freq:governor(调频)可以调节的最低频率。
- stats 目录下给出了 CPU 各种运行频率的统计情况,比如 CPU 在各频率下的运行时间以及
变频次数。
设置一直工作在做高频率
- 第一种方法:
# 在arch/arm/configs/imx_dongfang_emmc_defconfig文件中修改
# 注释掉第一下面的第一句,并添加最后一句上去
#CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
- 第二种方法
make menuconfig # 进入图形化配置
# 在下面的路径中修改为performance即可
CPU Power Management
-> CPU Frequency scaling
-> Default CPUFreq governor
设置超频
设置超频,修改一下设备树文件 arch/arm/boot/dts/imx6ull.dtsi
即可。
cpu0: cpu@0 {
compatible = "arm,cortex-a7";
device_type = "cpu";
reg = <0>;
clock-latency = <61036>; /* two CLK32 periods */
operating-points = <
/* kHz uV */
996000 1275000
792000 1225000
528000 1175000
396000 1025000
198000 950000
>;
fsl,soc-operating-points = <
/* KHz uV */
996000 1175000
792000 1175000
528000 1175000
396000 1175000
198000 1175000
>;
其中有一段代码,其中的数字就是该开发板所支持的频率。可以知道开发板支持996MHZ、792MHz、528MHz、
396MHz 和 198MHz。如果添加对696MHZ的支持,只需要修改部分。
operating-points = <
/* kHz uV */
996000 1275000
792000 1225000
696000 1225000
528000 1175000
396000 1025000
198000 950000
>;
fsl,soc-operating-points = <
/* KHz uV */
996000 1175000
792000 1175000
696000 1175000
528000 1175000
396000 1175000
198000 1175000
>;
编译设备树
make dtbs
使能 8 线 EMMC 驱动
Linux 内核驱动里面 EMMC 默认是 4 线模式的。硬件上使用8线制的速度更快,我们还要将emmc驱动修改为8线制的。修改设备树文件imx6ull_dongfang_emmc.dts
即可。在文件最后有:
&usdhc2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usdhc2>;
non-removable;
status = "okay";
};
将它修改为
&usdhc2 {
pinctrl-names = "default", "state_100mhz", "state_200mhz";
pinctrl-0 = <&pinctrl_usdhc2_8bit>;
pinctrl-1 = <&pinctrl_usdhc2_8bit_100mhz>;
pinctrl-2 = <&pinctrl_usdhc2_8bit_200mhz>;
bus-width = <8>;
non-removable;
status = "okay";
};
编译设备树make dtbs
,使用新的设备树启动即可。
修改网络驱动
修改为自己使用PHY的芯片驱动。
保存修改后的图形化配置文件
我们使用图形化配置后,会在.config
文件中添加相应的使能代码。但是如果我们使用make clean或者make distclean
命令清理工程的时候,那么.config
中的内容就会被删除掉。之前的所有的配置文件内容也就消失。所以我们在配置完图形界面以后经过测试没有问题,就必须要保存一下配置文件。保存配置的方法有两个。
- 直接另存为
.config
文件
直接将.config
文件另存为 imx_dongfang_emmc_defconfig
,然后其复制到 arch/arm/configs
目录下,替换以前的imx_dongfang_emmc_defconfig
。这样以后执行“make imx_dongfang_emmc_defconfig
”重新配置Linux 内核的时候就会使用新的配置文件。
- 通过图形界面保存配置文件
通过键盘的“→
”键,移动到“< Save >
”选项,然后按下回车键,打开文件名输入对话框。输入要保存的文件名,可以带路径,一般是相对路径。我们输入arch/arm/configs/imx_dongfang_emmc_defconfig
即可。设置好文件名以后选择下方的“< Ok >”按钮,保存文件并退出。