1. linux内核是开源的,作者:linus (git : 版本管理工具)
2. 源码由C语言和汇编实现
3. linux内核支持多种硬件架构平台
4. linux内核采用模块化方式编写,分层思想
5. linux内核使用C和汇编代码实现,在内核中最好不要使用C++
6. linux内核具有很好的移植和裁剪特性,通过图形化界面的配置方式就可以完成裁剪
1. linux官方获取
https://mirrors.edge.kernel.org/pub/linux/kernel/
2. 芯片厂家获取
3. 开发板厂家获取
4. 公司主管获取
本次一直练习使用:kernel-3.4.39-ok.tar.bz2
主版本号.次版本号.修订版本号
主版本号:内核源码有较大的改动才会更新主版本号
次版本号:修订版本号用完升级次版本号
偶数:稳定版
奇数:测试版
修订版本号:内核代码只要有更新就会修改修订版本号
1. 不选太新
2. 不选太旧
3. 选择稳定版本
1. 拷贝linux内核源码压缩包到ubuntu中
1)拷贝内核源码到ubuntu目录中
kernel-3.4.39.tar.bz2
2)解压缩内核源码
tar -vxf kernel-3.4.39.tar.bz2
3)进入内核源码目录
cd kernel-3.4.39
2. 分析内核源码的目录结构
平台相关代码:代码跟硬件相关
arch
平台无关代码:代码跟硬件无关
drivers
lib
include
net
fs
kernel
...
3. 获取配置和编译的命令
清除中间文件:
make clean
make distclean
配置linux内核:
make menuconfig 基于菜单选项的方式对内核进行配置
编译内核:
make modules 模块化编译内核
make uImage 编译生成uImage的内核镜像
make dtbs 编译生成设备树文件
make fs6818_defconfig 配置内核支持fs6818开发板
"make ${PLATFORM}_defconfig"
Create a ./.config file by using the default
symbol values from
arch/$ARCH/configs/${PLATFORM}_defconfig.
Use "make help" to get a list of all available
platforms of your architecture.
根据arm/arm/configs目录下提供的缺省文件,
在内核源码的顶层目录下生成一个.config配置文件
1. 配置交叉编译工具链
195 ARCH ?= arm
196 CROSS_COMPILE ?= arm-none-linux-gnueabi-
2. 执行make distclean清除中间文件
只需要执行一次,
3. 执行make fs6818_defconfig 配置内核源码支持fs6818平台
4. 执行make menuconfig 通过图形化界面对内核进行配置
问题1:make menuconfig
第一次使用make menuconfig 需要安装图形化界面的工具
配置之前需要安装图形图(make meuconfig):
sudo apt-get install libncurses5-dev
sudo apt-get install lib32z1 (64位)
问题2 :make menuconfig
scripts/kconfig/mconf Kconfig
Your display is too small to run Menuconfig!
It must be at least 19 lines by 80 columns.
make[1]: *** [menuconfig] Error 1
make: *** [menuconfig] Error 2
中断字体太大,缩小终端字体
Device Drivers --->
Character devices --->
[ ] FS6818 beep driver # 去掉*
FS6818 board device driver support --->
[ ] adc driver for farsight FS6818 all platform # 去掉*
[ ] pwm timer driver for farsight FS6818 # 去掉*
[ ] DS18B20 driver for farsight FS6818 # 去掉*
FS6818 extension device driver support --->
< > This is FS6818_LED! # 去掉*
[ ] zlg7290 driver support input device # 去掉*
5. 执行make uImage 生成uImage的内核镜像
问题3:make uImage
在编译的过程中可能出现如下错误:
"mkimage" command not found - U-Boot images will not be built
make[1]: *** [arch/arm/boot/uImage] Error 1
make: *** [uImage] Error 2
错误的原因:找不到mkimage命令,
根据提示分析出来mkimage应该存在uboot源码目录中
uboot源码必须进行编译之后才会有mkimage可执行程序
解决问题的方法:
将uboot源码的tools目录下的mkimage,
拷贝到到ubuntu的/usr/bin目录下:
sudo cp ~/uboot源码目录/tools/mkimage /usr/bin
uboot目录 ubuntu目录
再次make uImage重新编译内核即可。
打印以下信息表示编译成功:
Image Name: Linux-3.4.39-farsight
Created: Mon Jul 20 15:09:28 2020
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 5391608 Bytes = 5265.24 kB = 5.14 MB
Load Address: 40008000
Entry Point: 40008000
uImage内核镜像在以下目录中:
Image arch/arm/boot/uImage is ready
6. 测试uImage
将uImage拷贝到tftpboot目录下
使用tftp下载内核镜像,使用nfs挂载根文件系统。
驱动:机制--》 向上层提供接口
应用: 逻辑--》 调用驱动的接口,实现复杂的逻辑
fs6818_led.ko --> 模块化的驱动代码
led_test --> 应用层的led灯的测试代码
模块化的命令
insmod fs6818_led.ko 加载驱动到内核中
rmmod fs6818_led 从内核卸载驱动
lsmod 查看已经加载驱动
mknod /dev/led c 500 0
mknod : 创建驱动对应的设备文件
/dev/led : led灯驱动对应的设备文件
c : 字符设备 b : 块设备
500: 主设备号
0 : 次设备号
eg :
[root@farsight]#insmod fs6818_led.ko
[ 322.886000] Led init
[root@farsight]#lsmod
fs6818_led 3925 0 - Live 0xbf000000
[root@farsight]#./led_test
open: No such file or directory
[root@farsight]#mknod /dev/led c 500 0
[root@farsight]#./led_test
1. 打开内核源码顶层目录的Makefile,搜索config
491 %config: scripts_basic outputmakefile FORCE
492 $(Q)mkdir -p include/linux include/config
493 $(Q)$(MAKE) $(build)=scripts/kconfig $@
解析:
$(Q) : @
$@ : 目标
$^ : 所有的依赖
$< : 第一个依赖
去掉命令前的$(Q),重新make fs6818_defconfig,结果:
mkdir -p include/linux include/config
make -f scripts/Makefile.build obj=scripts/kconfig fs6818_defconfig
-f scripts/Makefile.build ----》
-f参数后边的文件作为Makefile使用
obj=scripts/kconfig : 变量的赋值
进入scripts/kconfig目录下执行make fs6818_defconfig
2. 打开scripts/kconfig目录下的Makefile,搜索defconfig
95 %_defconfig: $(obj)/conf
96 $< --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
去掉命令前的$(Q),重新make fs6818_defconfig,结果:
scripts/kconfig/conf --defconfig=arch/arm/configs/fs6818_defconfig Kconfig
使用file命令查看conf文件的属性,可知是一个elf文件
conf文件的作用:
conf文件根据arch/arm/configs/fs6818_defconfig文件,
和内核源码顶层目录下的Kconfig文件,在内核源码顶层目录下,
生成.config配置文件。
1. 打开内核源码顶层目录的Makefile,搜索config
491 %config: scripts_basic outputmakefile FORCE
492 $(Q)mkdir -p include/linux include/config
493 $(Q)$(MAKE) $(build)=scripts/kconfig $@
解析:
$(Q) : @
$@ : 目标
$^ : 所有的依赖
$< : 第一个依赖
去掉命令前的$(Q),重新make menuconfig,结果:
mkdir -p include/linux include/config
make -f scripts/Makefile.build obj=scripts/kconfig menuconfig
-f scripts/Makefile.build ----》
-f参数后边的文件作为Makefile使用
obj=scripts/kconfig : 变量的赋值
进入scripts/kconfig目录下执行make menuconfig
2. 打开scripts/kconfig目录下的Makefile,搜索menuconfig
20 menuconfig: $(obj)/mconf
21 $< $(Kconfig)
命令的结果
scripts/kconfig/mconf Kconfig
mconf文件的作用?
mconf文件根据内核源码顶层目录的Kconfig文件生成对应的
图形化菜单选项的配置界面。
3. 打开内核源码顶层目录的Kconfig
mainmenu "Linux/$ARCH $KERNELVERSION Kernel Configuration"
config SRCARCH
string
option env="SRCARCH"
source "arch/$SRCARCH/Kconfig"
通过对Kconfig分析,可知
1> mainmenu : 修饰的内容就是主菜单,
语法格式:
mainmenu "主菜单的名字"
2> source : 包含下一级子菜单
以研发中心的ADC的驱动为例进行分析。
Symbol: FS_ADC [=y]
Type : boolean
Prompt: adc driver for farsight FS6818 all platform
Defined at drivers/char/farsight/Kconfig:3
Location:
-> Device Drivers
-> Character devices
-> FS6818 board device driver support
此处采用倒退的方式,adc的驱动代码在
kernel-3.4.39/drivers/char/farsight目录下
1》打开drivers/char/farsight/Kconfig
menu "FS6818 board device driver support"
config FS_ADC
bool "adc driver for farsight FS6818 all platform"
default y
help
different sensor select different channel
endmenu
2》 打开drivers/char/Kconfig
menu "Character devices"
source "drivers/char/farsight/Kconfig"
endmenu
3》打开drivers/Kconfig
menu "Device Drivers"
source "drivers/char/Kconfig"
endmenu
4》打开arch/arm/目录下的Kconfig
source "drivers/Kconfig"
5》打开内核源码顶层目录的Kconfig
source "arch/$SRCARCH/Kconfig"
总结:内核源码的每个目录下应该都有一个Kconfig文件
3> menu...endmenu : 修饰子菜单
语法格式:
menu "子菜单的名字"
config
bool
default
help
endmenu
4> bool : 修饰菜单选项
语法格式:
bool "菜单选项的名字"
5> default : 菜单选项的默认值
default y : 菜单选项默认为*,对应的驱动被编译到内核镜像中
6> help : 帮助信息
7> config : 配置选项
语法格式:
config 配置选项的名字
最终修改的是.config中的配置信息。
[*] adc driver for farsight FS6818 all platform
.config文件中的信息:CONFIG_FS_ADC=y
看drivers/char/farsight目录下的Makefile文件:
obj-$(CONFIG_FS_ADC) += adc_driver.o
[ ] adc driver for farsight FS6818 all platform
.config文件中的信息:# CONFIG_FS_ADC is not set
Makefile: 进行工程管理,配置和编译内核
.config : 存放的默认的配置信息,本质:定义了很多的变量
给Makefile文件使用,Makefile文件根据
CONFIG_**** = y ,对应的驱动被编译到uImage中
# CONFIG_**** is not set,对应的驱动不被编译到uImage中
make fs6818_defconfig时根据arch/arm/configs/fs6818_defconfig
和Kconfig文件生成.config文件
make menuconfig时,根据菜单选项的配置
.config会被修改
Kconfig:生成图形化界面的菜单选项的配置文件
大多数目录下都有一个Kconfig文件和Makefile文件。
1.去掉研发中心添加的硬件驱动代码
Device Drivers --->
Character devices --->
[ ] FS6818 beep driver # 去掉*
FS6818 board device driver support --->
[ ] adc driver for farsight FS6818 all platform # 去掉*
[ ] pwm timer driver for farsight FS6818 # 去掉*
[ ] DS18B20 driver for farsight FS6818 # 去掉*
FS6818 extension device driver support --->
< > This is FS6818_LED! # 去掉*
[ ] zlg7290 driver support input device # 去掉*
2. 拷贝led灯的驱动代码到内核的drivers/char目录下
led灯驱动代码:led-driver
拷贝fs6818_led.c和fs6818_led.h到drivers/char目录下
3. 添加菜单选项
打开drivers/char目录下Kconfig文件,添加以下信息
4 menu "HQYJ2020 LED Driver"
5 config HQYJ_LED
6 bool "20071A20081 fs6818 led driver"
7 default y
8 help
9 hqyj 2020 led driver!
10 endmenu
make menuconfig查看效果:
按下“/”键 : 进入搜索界面,搜索CONFIG_后边的字符串
Symbol: HQYJ_LED [=y]
│ Type : boolean
│ Prompt: 20071A20081 fs6818 led driver
│ Defined at drivers/char/Kconfig:5
│ Location:
│ -> Device Drivers
│ -> HQYJ2020 LED Driver
4. 修改drivers/char目录下Makefile文件,添加以下信息:
5 obj-$(CONFIG_HQYJ_LED) += fs6818_led.o
5. 编译内核源码生成uImage的镜像
$ make uImage
CC drivers/char/fs6818_led.o
6. 测试uImage镜像
led灯驱动已经编译到uImage内核镜像中
1> 拷贝新生成的uImage镜像到tftpboot目录下
cp arch/arm/boot/uImage ~/tftpboot
2> 启动开发板 (开发阶段系统的启动方式)
使用tftp下载uImage到内存中
使用nfs服务挂载根文件系统
检查自己uboot中的bootcmd和bootargs环境变量。
3> 编译led灯的应用程序,并将可执行文件拷贝到根文件系统中。
$ arm-none-linux-gnueabi-gcc fs6818led_test.c -o led_test
$ cp led_test ~/nfs/rootfs
4> 开发板启动之后,运行led灯的应用程序,观察led灯的现象
# ./led_test
bool : [] 二态
[*] : 对应的驱动被编译到uImage的内核镜像中
[ ] : 对应的驱动不被编译到uImage的内核镜像中
tristate : <> 三态
<*> : 对应的驱动被编译到uImage的内核镜像中
< > : 对应的驱动不被编译到uImage的内核镜像中
: 对应的驱动以模块化的方式进行编译, 驱动文件***.c将被编译成模块化的驱动文件 ***.ko
使用make modules命令对内核编译,可以将需要使用模块化编译的驱动程序编译生成 ***.ko
需要使用驱动时,使用insmod命令加载驱动到内核中 insmod ***.ko
不需要使用驱动时,使用rmmod命令将驱动从内核中移除 rmmod ***
1.去掉研发中心添加的硬件驱动代码
Device Drivers --->
Character devices --->
[ ] FS6818 beep driver # 去掉*
FS6818 board device driver support --->
[ ] adc driver for farsight FS6818 all platform # 去掉*
[ ] pwm timer driver for farsight FS6818 # 去掉*
[ ] DS18B20 driver for farsight FS6818 # 去掉*
FS6818 extension device driver support --->
< > This is FS6818_LED! # 去掉*
[ ] zlg7290 driver support input device # 去掉*
2. 拷贝led灯的驱动代码到内核的drivers/char目录下
led灯驱动代码:led-driver
拷贝fs6818_led.c和fs6818_led.h到drivers/char目录下
3. 添加菜单选项
打开drivers/char目录下Kconfig文件,添加以下信息
4 menu "HQYJ2020 LED Driver"
5 config HQYJ_LED
6 tristate "20071-20081 fs6818 led driver"
7 default y
8 help
9 hqyj 2020 led driver!
10 endmenu
make menuconfig查看效果:
按下“/”键 : 进入搜索界面,搜索CONFIG_后边的字符串
Symbol: HQYJ_LED <=y>
│ Type : boolean
│ Prompt: 20041&20052 fs6818 led driver
│ Defined at drivers/char/Kconfig:5
│ Location:
│ -> Device Drivers
│ -> HQYJ2020 LED Driver
修改为M:
Device Drivers---->
HQYJ2020 LED Driver ---->
<M> 20071&20081 fs6818 led driver 修改
4. 修改drivers/char目录下Makefile文件,添加以下信息:
5 obj-$(CONFIG_HQYJ_LED) += fs6818_led.o
5. 编译内核源码生成uImage的镜像
$ make uImage # 去掉上一次编译内核镜像时的led灯驱动文件
6. 使用模块化的命令编译led灯驱动
$ make modules
编译结果出现以下信息:
LD [M] drivers/char/fs6818_led.ko
7. 测试驱动
1> 拷贝新生成的uImage镜像到tftpboot目录下
$ cp arch/arm/boot/uImage ~/tftpboot
2> 拷贝fs6818_led.ko到跟文件系统中
$ cp drivers/char/fs6818_led.ko ~/nfs/rootfs
3> 启动开发板 (开发阶段系统的启动方式)
4> 编译led灯的应用程序,并将可执行文件拷贝到根文件系统中。
$ arm-none-linux-gnueabi-gcc fs6818led_test.c -o led_test
$ cp led_test ~/nfs/rootfs
5> 加载驱动
# insmod fs6818_led.ko
# lsmod # 查看加载的驱动
6> 开发板启动之后,运行led灯的应用程序,观察led灯的现象
# ./led_test
7> 卸载led灯驱动程序
rmmod: can't change directory to '/lib/modules': No such file or directory
解决办法:在lib目录下创建modules文件夹
cd lib
mkdir modules
rmmod: can't change directory to '3.4.39-farsight': No such file or directory
解决办法:在lib/modules目录下创建3.4.39-farsight文件夹
cd lib/modules
mkdir 3.4.39-farsight
总结:模块化编译驱动代码的优点:
1> 可以缩短开发周期
2> 缩小uImage内核镜像的大小
3> 增强排错的能力
1> uboot通过tftp命令将uImage下载到内存中
2> uImage需要完成自解压
3> 获取cpu的ID号,创建页表,初始化MMU,完成物理地址到虚拟地址的映射
4> 清除BSS段
5> 完成绝大多数硬件的初始化,进一步对硬件初始化
内存,时钟,串口,EMMC,nfs客户端....
5> 从u-boot环境变量的内存分区获取bootargs参数,根据bootargs参数,决定从哪里挂载根文件系统。
6> 挂载根文件系统,
7> 执行根文件系统中的1号进程,linuxrc程序
8> 到此开发板的linux系统启动成功