Linux 3.4.2内核移植到JZ2440开发板
0、开发环境
- 虚拟机:VMware workstation 16 pro
- 宿主机操作系统:Ubuntu 16.04
- 开发板:JZ2440
- 移植内核版本:Linux 3.4.2
1、内核下载及内核启动流程简述
1.1 点击上述链接,找到需要得内核版本(此文使用Linux3.4.2)
- 点击Linux内核下载地址获取内核源码
- 获取后放到Linux系统上解压:
tar -jxf linux-3.4.2.tar.bz2
Linux内核有3万多个文件,可以将v参数去掉,不显示解压信息。
1.2 内核启动大致流程
- bootloader
- 加载内核代码到内存中
- 设置tag参数
- 启动内核(R0 = 0, R1 = machid,R2 = tag参数地址)
- 内核
- 根据machid判断内核是否支持该机器(支持则启动,不支持则卡死)
- 解析tag参数
- 装载驱动(Flash、网卡。。。)
- 挂载根文件系统
- 应用程序
- 运行用户应用程序
2、配置并编译内核
2.1 配置架构和编译工具链
在根目录下的makefile中搜索ARCH,找到并按下图修改两项配置:
2.2 选择默认配置文件
进入arm架构的单板默认配置文件目录(arch/arm/configs/)查看内核支持的单板:
选择和我们单板最为接近的s3c2410进行编译。
回到根目录,执行命令make s3c2410_defconfig
,生成 s3c2410_defconfig
默认配置文件.config
。该文件中将支持的单板列表如下:
2.3 编译内核
执行命令make uImage
,生成内核镜像文件:
编译过程中的错误:
- recipe for target ‘kernel/timeconst.h’ failed
原因:因为在新版本的(Linux) 宿主机上编译老版本的内核版本出现的错误。
解决办法:将kernel/timeconst.pl
中第373行的宏判断defined()
去掉,去掉后如下:
- "mkimage" command not found - U-Boot images will not be built。
原因:Linux主机中制作uImage镜像依赖的一个包没安装。
解决办法:执行sudo apt-get install u-boot-tools
命令,安装依赖的包。
再次编译,编译成功。
3、设置machid(选择机器类型)
3.1 查看uboot中的machid
uboot启动内核的时候,如果环境变量未设置machid 的值,则会使用代码默认的宏定义。代码在文件u-boot-2012.04.01/arch/arm/lib/bootm.c
中的函数 boot_jump_linux 中:
uboot代码中默认的machid值为 gd->bd->bi_arch_number,全局搜索bi_arch_number(grep "bi_arch_number" * -nR
),在文件u-boot-2012.04.01/board/samsung/smdk2440/smdk2440.c
中:
再来查找宏定义MACH_TYPE_SMDK2410的值,在文件u-boot-2012.04.01/arch/arm/include/asm/mach-types.h
中:
所以,uboot默认传递的machid的值为193,即0xc1。
3.2 查看linux内核中的machid
查询当前Linux内核支持的machid有一种快速简洁的方法:因为uboot启动时会先去寻找环境变量中的值,如果不存在的话才会使用默认值,所以我们先随意设置一个machid的值,当该值不在支持的机器列表中时,在linux启动时就会列出目前所有支持的机器:
- 先直接在uboot命令行中执行
set machid 0xff0
(但不要执行saveenv
命令,其会将设置的machid保存进params分区中),用以设置一个machid的值。 - 设置成功后重新下载内核映像,启动内核:
在列出的支持列表中,可以看到SMDK2440的machid为0x16a。
这里有两种设置方法:
① 在uboot中修改赋值给bi_arch_number的宏为16a,然后重新编译,烧写uboot;
② 设置machid为16a,然后使用saveenv命令保存到环境中;
这里使用第二种方法修改machid并保存到环境变量中:
接着再次尝试启动内核,启动后内核输出乱码:
在内核源码中找到该machid对应的单板文件为arch\arm\mach-s3c24xx\mach-smdk2440.c
文件,在smdk2440_map_io 函数中可以看到晶振设置有问题,JZ2440板载的是12M晶振,所以修改如下:
重新配置编译内核,下载到开发板中启动,识别出的机器为SMDK2440:
4、修改内核中的mtd分区
在上一节Linux系统启动之后,打印出的分区表和实际对nand flash的分区表不一致,所以接下来要修改内核中的mtd分区表同uboot中的一致:
4.1 定位修改代码位置
通过linux启动后,打印出的分区表信息如下:
所以,内核的根目录下执行grep "\"Boot Agent\"" * -nR
搜索“Boot Agent”,结果如图:
判断在arch/arm/mach-s3c24xx/common-smdk.c:113:
处,进入该文件,果然分区表在这里:
修改为如下的分区表,其中三个宏定义的意思如下:
-
MTDPART_OFS_APPEND
:追加到上一个分区结束地址; -
MTDPART_SIZ_FULL
:剩下的所有空间;
重新编译,下载到开发板的内存中,然后启动内核,可以看到分区表已经被修改成功:
5、内核的裁剪
在前面的移植过程中,内核编译出来有 2414KB,而 Nand Flash 的 mtd 分区中指定了 kernel 分区为 2M=2048KB,所以需要对内核进行裁剪,去除不必要的内容。
5.1、选择s3c2410进行默认配置后,进入图形配置窗口
5.2、裁剪支持的机器
- 依次进入System Type->SAMSUNG S3C24XX SoCs Support,只需按下图勾选上*** S3C24XX SoCs *** 里的SAMSUNG S3C2440和*** S3C2440 Boards ***里的SMDK2440和SMDK2440 with S3C2440 CPU module选项,其余全部不选:
5.3、裁剪支持的文件系统
- 进入File systems,去除对Ext2和Ext3文件系统的支持:
- 进入 File systems -> CD-ROM/DVD Filesystems,去除对ISO9600 的支持:
- 进入 File systems -> DOS/FAT/NT Filesystems,去除对MSDOS和VFAT文件系统的支持:
- 进入 File systems -> Miscellaneous filesystems,去除对cramfs、ZLIB压缩型文件系统和ROM文件系统的支持:
5.4、裁剪支持的设备驱动
- 进入 Device Drivers -> SCSI device support,去除对SCSI设备和RAID传输类设备的支持:
- 进入 Device Drivers -> Input device support,去除对psaux、鼠标、键盘、游戏棒的支持:
- 进入 Device Drivers -> Network device support -> Ethernet driver support(只保留DM9000):
- 进入 Device Drivers -> Input device support -> Touchscreens,选上S3C2410 touchscreen input driver:
- 进入 Device Drivers -> Sound card support -> Advanced Linux Sound Architecture,去除USB声卡设备:
- 进入Device Drivers -> Multifunction device drivers,去除Silicon Motion SM501的支持:
- 进入Device Drivers -> USB support,去除对USB 文件系统、OHCI HCD、通用存储设备共享表(the shared table of common storage devices)、USB串口转换(USB serial converter)的支持:
- 进入Device Drivers -> MMC/SD/SDIO card support,去除对MMC block device驱动的支持:
5.5、配置EABI支持
- 进入Kernel Features ,选择勾选
Use the ARM EABI to compile the kernel
和Allow old ABI binaries to run with this kernel (EXPERIMENTAL)
。
如果内核不支持eabi,在启动时将会提示:
Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000004
。
6、移植DM9000网卡驱动,支持网络,支持NFS挂载,支持域名解析
6.1、移植DM9000网卡驱动
之前配置使用的SMDK2440开发板,默认不支持DM9000网卡驱动,但是其中的MINI2440开发板支持,所以要将MINI2440中的DM9000驱动移植到SMDK2440中。
进入内核源码目录里面,找到 arch/arm/mach-s3c24xx/
目录并进入,找到这两个文件:mach-smdk2440.c
和arch-mini2440.c
,并将 mach-mini2440.c 中关于网卡的配置代码,移植到 mach-smdk2440.c 中。
- 向mach-smdk2440.c文件中添加头文件:
#include <linux/dm9000.h>
- 向mach-smdk2440.c文件中移植并修改结构体
SMDK2440_dm9k_resource
- 移植并修改smdk2440_dm9k_pdata结构体
- 添加宏定义MACH_SMDK2440_DM9K_BASE
- 修改smdk2440_devices结构体
保持之前的配置不变,重新编译内核!
7、网络测试
7.1、局域网测试
- 设置网卡ip地址,启动网络连接
- ping测试
- 设置开机启动后自动配置ip地址
在开发板上使用vi编辑器编辑etc/init.d/rcS文件,添加一条配置命令即可:
重启测试:
7.2、外网测试
- 配置网关:
- 如果想开机后自动设置网关ip,仅需在开发板上使用vi编辑器编辑etc/init.d/rcS文件,添加一条配置命令即可:
- 重启之后ping外网测试:
7.3、域名解析测试
- 配置DNS域名解析服务器,在 /etc 目录下新建一个文件
resolv.conf
,然后编辑添加以下内容:
进行ping域名测试,成功:
8、挂接NFS文件系统
NFS是Network File System,网络文件系统,可以通过网络让不同机器、不同系统之间实现文件共享。通过NFS ,可以访问远程共享目录,就和访问本地磁盘一样。在嵌入式Linux开发中常用于开发板运行目标机上的程序。
8.1、linux主机建立NFS服务器端
- 安装NFS服务器
- 添加NFS共享目录
NFS共享目录:/home/leon/nfs_root/first_fs
其中,first_fs目录是一个最小文件系统,便于以后系统启动后直接通过NFS挂接,方便以后宿主机和开发板直接共享目录。
- 打开、编辑配置文件/etc/exports,在末尾添加指定NFS共享目录的语句
- 启动/重启 NFS服务
注:NFS服务在系统启动时会自动启动。
8.2 Linux主机建立NFS客户端自测
- 安装NFS客户端
- 挂载NFS共享目录到/mnt
提示错误:
**问题原因:**被拒绝的原因是因为使用了非法端口。因为如果端口号大于1024,则需要将 insecure 选项加入到配置文件(/etc/exports)相关选项中mount客户端才能正常工作。
secure 选项要求mount客户端请求源端口小于1024(然而在使用 NAT 网络地址转换时端口一般总是大于1024的),默认情况下是开启这个选项的,如果要禁止这个选项,则使用 insecure 标识。
详情可参考:NFS挂载问题 mount.nfs: access denied by server while mounting - 一本书的伤痕 -
**解决办法:**修改配置文件/etc/exports,加入 insecure 选项:
- 在NFS服务器端的共享文件夹/home/leon/nfs_root/first_fs新建测试文件
test
- 进入客户端挂载的文件夹
/mnt
查看是否有test文件,并尝试写入
8.3 开发板开机自动挂载NFS网络文件系统
- 重启开发板,进入uboot命令行,修改启动参数,保存后,重启:
192.168.1.100是宿主机ip地址;
192.168.1.50是开发板ip地址;
192.168.1.1是网关;
255.255.255.0是子网掩码;
eth0是网卡名称,可以在系统启动后,命令行输入
ifconfig -a
查看系统当前使用的网卡名称及其ip地址。
- 查看测试结果
如果设置正确,系统会在启动时直接远程挂接NFS服务器端的最小文件系统first_fs(共享目录),并自动启动sh命令行。
需要注意的是,挂接的最小文件系统必须匹配开发板内核版本,即编译内核和编译busybox的交叉编译器必须是同一个。尤其要注意最小文件系统中的/lib和/usr/lib中的so库文件必须是和交叉编译器使用的库文件一致。例如:我使用的arm-linux-gcc版本是4.3.2,它使用的库文件所在路径为: