简单说明:从搭建环境,安装虚拟机开始移植4.9内核到jz2440开发板,目的是复习Linux交叉编译环境和系统构建的过程

环境搭建

安装ubuntu虚拟机18.04

  • 下载地址
https://www.ubuntu.com/download/desktop

注意虚拟机的网卡需要设置为桥接模式

下载linux内核4.9

  • 下载地址
www.kernel.org
  • 解压过程分为两步
xz -d linux-4.9.180.tar.xz
tar xvf linux-4.9.180.tar
  • 开启SSH服务
sudo apt-get install openssh-server 
/etc/init.d/ssh start (如果没启动,手动启动)

安装arm-linux-gcc工具链

  • 下载,解压,版本号:4.4.3
arm-linux-gcc-4.4.3.tar.gz
tar -zxvf arm-linux-gcc-4.4.3.tar.gz
  • 在/usr/local目录中新建文件夹,并解压
sudo mkdir /usr/local/arm
sudo cp * /usr/local/arm -rf
  • 设置环境变量
sudo vi /etc/environment
添加 /usr/local/arm/bin

内核的配置过程分析

在开始配置编译内核之前先来分析一下和内核编译息息相关的几个文件,Kconfig、.config、makefile,以及内核的编译过程

  • Linux内核配置有2中不同的方法,make menuconfig是最常用的方法,本文重点分析make menuconfig的过程,这三种方法殊途同归。
make .config / make xxx_defconfig
make menuconfig

makefile/Kconfig/.config之间的关系

Makefile :编译源文件的方法
Kconfig: 文本文件,内核的配置菜单,提供所有的配置选项
.config: 编译内核所依据的配置,菜单里选中的菜

Makefile:(drivers/Makefile)

/* 直接编译 */
obj-y				+= cdrom/
obj-y				+= auxdisplay/

/* 条件编译:根据.config的CONFIG_XXX来决定是否编译 */
/* CONFIG_XXX变量的取值是通过.config文件来集中赋值的 */
obj-$(CONFIG_PCCARD)		+= pcmcia/
obj-$(CONFIG_DIO)		+= dio/

/* 条件编译:只有make modules才会被编译 */
obj-m				+= cdrom/

Kconfig
— 决定make menuconfig时展示的菜单项

  • 示例(drivers/leds/Kconfig)
config LEDS_S3C24XX
tristate "LED Support for Samsung S3C24XX GPIO LEDs"
depends on LEDS_CLASS
depends on ARCH_S3C24XX
help
This option enables support for LEDs connected to GPIO lines
on Samsung S3C24XX series CPUs, such as the S3C2410 and S3C2440.

config : 关键字,表示一个配置选项的开始

tristate : 显示为< >,"LED Support for Samsung S3C24XX GPIO LEDs":make menuconfig 时显示的
		配置项名称,表示是否编译进内核,y/m/n

bool:显示为[],即无法配置成模块

dependon : 该选项依赖于另一个选项,只有依赖项被选中时,才能配置当前项

select : 反向依赖,该项选中时,同时选中select后面定义的那一项

help: 帮助信息

source:
source "arch/$SRCARCH/Kconfig" --- (顶层makefile) : 目录层次迭代,使各个
目录管理自己的配置内容。

.config

  • 内核编译参考文件,查看里面内容可以知道哪些驱动被编译进内核

  • Kconfig提供了编译选项,.config提供当前选中了哪些选项,在make menuconfig的时候修改的选项在保存后会同步到.config文件中

  • – 不建议直接修改.config

总结:三者之间的关系

  • makefile里面的条件编译的选项都是在.config里面集中定义的
  • Kconfig在make menuconfig的时候提供界面的选项,.config提供当前选中的选项,前者相当于菜单,后者相当于选中的菜,makefile就是炒这些菜的方法
  • make menuconfig 修改时会更新.config里面的配置项

make menuconfig过程分析

涉及到的文件:

1 Linux内核根目录下的scripts文件夹
2 arch/$ARCH/Kconfig文件、各层目录下的Kconfig文件
3 Linux内核根目录下的makefile文件、各层目录下的makefile文件
4 Linux内核根目录下的的.config文件、arm/$ARCH/下的config文件
5 Linux内核根目录下的 include/generated/autoconf.h文件

1 读取scripts文件夹中,存放的是make menuconfig 配置界面相关的文件

2 读取arch/$ARCH/Kconfig以及各子目录下的Kcondig ,生成配置条目

$ARCH 由根目录下的makefile决定:
	257 ARCH		?= arm
	258 CROSS_COMPILE	?= arm-linux-
Kconfig文件中为配置信息的宏定义,与我们在make menuconfig图形界面看到的信息一致

3 读取内核目录下的.config文件,生成配置选项:[*]编译进内核 [M]编译为模块 []不编译

arch/arm/configs : 存放了一些配置模板
可以通过cp /arch/arm/configs/xx_defconfig .config来使用这些配置模板 
通过图形界面变更配置选项会自动更新到.config文件中 
make disclean 会删除.config

4 编译过程根据.config生成 Linux内核根目录下的 include/config/auto.conf文件

CONFIG_EEPROM_93CX6=m 
CONFIG_DM9000=y 
根目录Makefile以及子目录的Makefile根据auto.conf生成编译条件 
obj-$(CONFIG_DM9000) += dm9000.o //obj-m += dm9000.o

5 编译过程根据.config生成Linux内核根目录下的 include/linux/autoconf.h文件

.config 或 auto.conf 中定义要编译为 m 模块的项,如: 
CONFIG_DEBUG_NX_TEST=m 
在 autoconf.h 中会被定义为: 
#define CONFIG_DEBUG_NX_TEST_MODULE 1 

.config或auto.conf 中定义为编译为 y 的选项,如: 
CONFIG_DM9000= y 
在 autoconf.h 中会被定义为: 
#define CONFIG_DM9000 1 

autoconf.h中是站在源码的角度,供源码使用的C语言宏定义。

总结

1 确定架构arch,读取arch目录的Kconfig中的配置,生成编译条目
				
2 读取内核根目录下的.config选项,将配置信息显示在图像界面上[*] [M] []

3 图像界面的改动会自动保存到.config文件中

4 编译过程根据.config形成auto.config,它决定了makefile中各个文件的编译类型
auto.config 相对于.config少了注释和增加了一些变量,顶层目录下的makefile包含auto.conf文件

5 编译时生成autoconfig.h,以C语言宏的形式表达个各个文件是否被编译,源码中
  会判断某文件是否被编译进行不同的处理。

配置编译内核

/*修改顶层makefile*/
257 ARCH		?= arm
258 CROSS_COMPILE	?= arm-linux-

/* 复制默认的配置文件到顶层文件目录下的.config文件 */
cd /work/sys/linux-4.9.180/arch/arm/configs
cp  s3c2410_defconfig  /work/sys/linux-4.9.180/.config

/* 安装缺少的库 */
sudo apt-get install libc6-dev
sudo apt-get install libncurses5-dev libncursesw5-dev

/* 配置,裁剪内核  */
make menuconfig
make uImage
出现错误 :/usr/local/arm/bin/arm-linux-gcc: 15: exec: /usr/local/arm/bin/.arm-none-linux-gnueabi-gcc: not found
原因:64位的系统缺少32位的库
根据错误提示安装32位的库:
sudo apt-get install lib32z1
sudo apt-get install lib32stdc++6
再次make uImage 

错误:arch/arm/boot/Makefile:79: recipe for target 'arch/arm/boot/uImage' failed
解决:sudo apt-get install u-boot-tools

再次make uImage ,即可编译通过
Image Name:   Linux-4.9.180
Created:      Sun Jun  9 23:09:38 2019
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    3150272 Bytes = 3076.44 KiB = 3.00 MiB
Load Address: 30108000
Entry Point:  30108000

下载内核到开发板上:
tftp 30000000 uImage
bootm 30000000
可以打印出内核信息,但是并不能正常启动内核,因此需要修改内核

修改内核

设置机器ID

Error: unrecognized/unsupported machine ID (r1 = 0x000000c1).

Available machine support:

ID (hex)        NAME
000002de        Simtec-Anubis
00000707        AT2440EVB
000007cf        MINI2440
000002a9        NexVision - Nexcoder 2440
0000034a        Simtec-OSIRIS
00000250        IPAQ-RX3715
0000016a        SMDK2440

设置:
上面是.config文件中配置成y的机器类型:因此set machid 选择单板和其中最相近的一个单板即可。
uboot设置机器ID参数  set machid 0x16a;save

修改时钟

linux-4.9.180/arch/arm/mach-s3c24xx$ vi mach-smdk2440.c
static void __init smdk2440_init_time(void)
{
		//s3c2440_init_clocks(16934400);
		s3c2440_init_clocks(12000000);
		samsung_timer_init();
}

修改MTD分区

与uboot里面设置的一样
arch\arm\mach-s3c24xx\common-smdk.c
static struct mtd_partition smdk_default_nand_part[] = {
	[0] = {
		.name	= "u-boot",
		.size	= SZ_256K,
		.offset	= 0,
	},
	[1] = {
		.name	= "params",
		.offset = MTDPART_OFS_APPEND,
		.size	= SZ_128K,
	},
	[2] = {
		.name	= "kernel",
		.offset = MTDPART_OFS_APPEND,
		.size	= SZ_4M,
	}
	[3] = {
		.name	= "rootfs",
		.offset = MTDPART_OFS_APPEND,
		.size	= MTDPART_SIZ_FULL,
	}
};

下载内核并启动,nandflash已经正确显示分区,看到内核panic信息:mount root 错误,没有挂接到正确的文件系统

VFS: Cannot open root device "mtdblock3" or unknown-block(0,0): error -6

原因可能是:

1 MTD分区和boot的分区对不上,找不到根文件系统
2 nand flash中对应的位置没有根文件系统
3 命令行参数设置的不对
4 内核中没有对应的文件系统

由于uboot设置的nandflash分区内核部分为2M,而4.9的内核大于2M,
因此需要修改uboot的nandflash分区

修改uboot2012:
1 修改分区 
	/include/configs/smdk2440.h
	#define MTDPARTS_DEFAULT        "mtdparts=jz2440-0:256k(u-boot),"       \
                                    "128k(params),"         \
                                    "4m(kernel),"   \
                                    "-(rootfs)"             \
重新 make

2 u-boot nandflash 操作方法介绍

烧写u-boot:
	tftp 30000000 u-boot.bin; protect off all; erase 0 0x3ffff; cp.b 30000000 0 40000

tftp烧写内核到nandflash:
	tftp 30000000 uImage
	nand erase.part kernel
	nand write 30000000 kernel

tftp烧写jffs文件系统:
	tftp 30000000 fs_mini_mdev.jffs2
	nand erase.part rootfs
	/                        目标地址  大小/
	nand write.jffs2 30000000 260000 5b89a8
	set boota rgs console=ttySAC0 root=/dev/mtdblock3 rootfstype=jffs2

tftp烧写yaffs文件系统:  
	tftp 30000000 fs_qtopia.yaffs2
	nand erase.part rootfs
	/                        目标地址  大小/
	nand write.yaffs 30000000 260000 889bc0

到此为止,内核和u-boot需要修改的部分以及修改完成,下一步制作最小根文件系统


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

通用Makefile 上一篇
从0移植4.9内核(2) 下一篇