Linux系统移植学习笔记【2】linux内核移植

Linux系统移植学习笔记2

  • 二、linux内核的移植
      • 1.linux内核的特点
      • 2.linux内核源码的获取
      • 3.linux内核的版本命名方式
      • 4.linux内核版本的选择
      • 5.linux内核的配置和编译
      • 6.对内核源码进行配置和编译
      • 7.make fs6818_defconfig执行过程详解
      • 8.make menuconfig执行过程详解
      • 9. .config Kconfig Makefile三个文件之间的关系?
      • 10. 练习1:添加自己的菜单和菜单选项
      • 11. 练习2:采用模块化的方式编译内核、添加自己的菜单和菜单选项
      • 12. linux内核启动过程主要做了那些事儿?

二、linux内核的移植

1.linux内核的特点

1. linux内核是开源的,作者:linus  (git : 版本管理工具)
2. 源码由C语言和汇编实现
3. linux内核支持多种硬件架构平台
4. linux内核采用模块化方式编写,分层思想 
5. linux内核使用C和汇编代码实现,在内核中最好不要使用C++ 
6. linux内核具有很好的移植和裁剪特性,通过图形化界面的配置方式就可以完成裁剪

2.linux内核源码的获取

1. linux官方获取
	https://mirrors.edge.kernel.org/pub/linux/kernel/
2. 芯片厂家获取
3. 开发板厂家获取
4. 公司主管获取
本次一直练习使用:kernel-3.4.39-ok.tar.bz2

3.linux内核的版本命名方式

主版本号.次版本号.修订版本号

主版本号:内核源码有较大的改动才会更新主版本号
次版本号:修订版本号用完升级次版本号
	     偶数:稳定版
	     奇数:测试版
修订版本号:内核代码只要有更新就会修改修订版本号

4.linux内核版本的选择

1. 不选太新
2. 不选太旧
3. 选择稳定版本

5.linux内核的配置和编译

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配置文件

6.对内核源码进行配置和编译

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 

7.make fs6818_defconfig执行过程详解

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配置文件。

8.make menuconfig执行过程详解

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 

9. .config Kconfig Makefile三个文件之间的关系?

	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文件。

10. 练习1:添加自己的菜单和菜单选项

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 

11. 练习2:采用模块化的方式编译内核、添加自己的菜单和菜单选项

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> 增强排错的能力

12. linux内核启动过程主要做了那些事儿?

	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系统启动成功

你可能感兴趣的:(系统移植,linux,内核,linux)