Linux内核移植
本次主要将linux-3.0的内核移植到S3C2440上:
移植目录:~/fl2440/kernel/linux-3.0
交叉编译器:buildroot-2012.08
bootloader:u-boot-2010.09
Target Board:FL2440
开发环境:linux服务器
一、建立交叉编译环境
**************************************************************************************************************
交叉编译介绍
**************************************************************************************************************
在一种计算机环境中运行的编译程序,能编译出在另外一种环境下运行的代码,我们就称这种编译器支持交叉编译。这个编译过程就叫交叉编译。简单地说,就是在一个平台上生成另一个平台上的可执行代码。这里需要注意的是所谓平台,实际上包含两个概念:体系结构(Architecture)、操作系统(Operating System)。同一个体系结构可以运行不同的操作系统;同样,同一个操作系统也可以在不同的体系结构上运行。举例来说,我们常说的x86 Linux平台实际上是Intel x86体系结构和Linux for x86操作系统的统称;而x86 WinNT平台实际上是Intel x86体系结构和Windows NT for x86操作系统的简称。
我们需要在linux环境中编译出能在ARM上运行的可执行文件,于是我们手动配置buildroot-2012.08.最后交叉编译器的路径为/opt/buildroot-2012.08/arm920t/usr/bin/;
二、源码包的获取及解压
本次主要移植linux-3.0的内核。
首先获取源码包地址:http://pan.baidu.com/s/1mgws9Eo,然后解压源码包linux-3.0.tar.bz2在自己指定的目录下生成linux-3.0;
[xiaokai@centos6 kernel]$ tar -xjf linux-3.0.tar.bz2
三、根目录下顶层Makefile的修改
/***************************************************************************************************************************
Makefile介绍及其作用
**************************************************************************************************************
一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。
于是我们需要通过修改Makefile来指定我们需要编译生成的文件供我们来使用。在这个文件中,我们需要修改的第一个地方是交叉编译器与平台的类型。
通过搜索CROSS_COMPILE,找到定义交叉编译器的环境变量,执行如下修改:
ARCH ?= arm
CROSS_COMPILE ?= /opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-
注意:如果我们编译内核的时候出现如下这样一个错误提示:
make: *** arm/kernel.git/arch/arm: Is a directory. Stop.
这个错误是由在Makefile的 ARCH ?= $(SUBARCH)这行的后面多了一个空格造成的;
如果出现如下这样一个错误提示:
make: /opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-: Command not found
CHK include/linux/version.h
CHK include/generated/utsrelease.h
make[1]: `include/generated/mach-types.h' is up to date.
CC kernel/bounds.s
/bin/sh: /opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-: No such file or directory
make[1]: *** [kernel/bounds.s] Error 1
这是因为/opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-后多了一个空格;
所以,在编辑Makefile时候,每行结尾,一定要确认没有空格,直接是换行。
/*************************************************************************************************************
mkimage介绍
**************************************************************************************************************
mkimage是在制作镜像文件时候, 在原来的image文件前增加一个0x40字节长度的头,增加的头结构描述如下:
/*
* Legacy format image header,
* all data in network byte order (aka natural aka bigendian).
*/
typedef struct image_header {
uint32_t ih_magic; /* Image Header Magic Number */
uint32_t ih_hcrc; /* Image Header CRC Checksum */
uint32_t ih_time; /* Image Creation Timestamp */
uint32_t ih_size; /* Image Data Size */
uint32_t ih_load; /* Data Load Address */
uint32_t ih_ep; /* Entry Point Address */
uint32_t ih_dcrc; /* Image Data CRC Checksum */
uint8_t ih_os; /* Operating System */
uint8_t ih_arch; /* CPU architecture */
uint8_t ih_type; /* Image Type */
uint8_t ih_comp; /* Compression Type */
uint8_t ih_name[IH_NMLEN]; /* Image Name */
} image_header_t;
Image Name占用了32字节,其他信息占用了32字节
为什么要增加呢?
通常,u-boot为kernel提供一些kernel无法知道的信息,比如ramdisk在RAM中的地址。Kernel也必须为U-boot提供必要的信息,如通过mkimage这个工具(在u-boot代码的tools目录中)可以给zImage添加一个header,也就是使得通常编译的内核zImage添加一个数据头,把添加头后的image通常叫uImage,uImage是可以被U-boot直接引导的内核镜像。
下面介绍一下mkimage的用法:
Usage: ./mkimage -l image
-l ==> list image header information
./mkimage [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image
-A ==> set architecture to 'arch'
-O ==> set operating system to 'os'
-T ==> set image type to 'type'
-C ==> set compression type 'comp'
-a ==> set load address to 'addr' (hex)
-e ==> set entry point to 'ep' (hex)
-n ==> set image name to 'name'
-d ==> use image data from 'datafile'
-x ==> set XIP (execute in place)
./mkimage [-D dtc_options] -f fit-image.its fit-image
-A 设定架构类型,可取值参照u-boot-2012.09/common/image.c
取值 表示的CPU体系结构
alpha Alpha
arm A RM
x86 Intel x86
ia64 IA64
mips MIPS
mips64 MIPS 64 Bit
ppc PowerPC
s390 IBM S390
sh SuperH
sparc SPARC
sparc64 SPARC 64 Bit
m68k MC68000
-O 设定操作系统类型,可取值参照u-boot-2012.09boot/common/image.c
可以取以下值:
openbsd、netbsd、freebsd、4_4bsd、linux、svr4、esix、solaris、irix、sco、dell、ncr、lynxos、vxworks、psos、qnx、u-boot、rtems、artos
-T image类型,可取值参照u-boot-2012.09/common/image.c
可以取以下值:
standalone、kernel、ramdisk、multi、firmware、script、filesystem
-a 指定image在内存中的加载地址
映象下载到内存中时,要按照用mkimage制作映象时,这个参数所指定的地址值来下载
-e 指定image运行的入口点地址
这个地址就是-a参数指定的值加上0x40(因为前面有个mkimage添加的0x40个字节的头)
-C 指定压缩方式,压缩方式参考u-boot-2012.09/common/image.c
可以取以下值:
none 不压缩
gzip 用gzip的压缩方式
bzip2 用bzip2的压缩方式
-n 指定映象名
-d data_file[:data_file...] 制作image的源文件
所以说这个工具可以用来制作各种压缩或不压缩的可启动映象文件。
于是我们下一步修改的地方应是添加mkimage工具。使系统在制作映象文件的时候,会在原来的可执行映象文件的前面加上一个0x40字节的头,记录参数所指定的信息。这样uboot才能识别这个映象是针对哪个CPU体系结构的,哪个OS的,哪种类型,加载内存中的哪个位置, 入口点在内存的那个位置以及映象名是什么。因而我们在559行下面添加如下:
cp arch/arm/boot/zImage . -f
mkimage -A arm -O linux -T kernel -C none -a 30008000 -e 30008040 -n "Linux Kernel" -d zImage linuxrom-s3c2440-xiao.bin
rm -f zImage
在Makefile中所有需要执行的命令都需要以tab键开头;
为了在make distclean中删除生成的bin文件,我们需要在1206行添加如下命令:
@rm -f linuxrom-*.bin
表示只有执行distclean时才会删除它。
四、拷贝mkimage
[xiaokai@centos6 linux-3.0]$ cp ../../bootloader/u-boot-2010.09/tools/mkimage .
将编译所需要的mkimage拷贝到当前目录下来;
五、修改时钟晶振频率(解决打印信息乱码,频率不同步现象)
S3C2440支持2种晶振频率:12MHZ和16MHZ。FL2440开发板使用的是12M的晶振,而内核源代码则采用的是16M频率,从而产生了错误的PCLK,因此导致内核向串口输出数据时使用了错误的波特率(通常我们串口输出的是115200),这样在secureCRT中看到的就是乱码。因此我们只需修改内核源代码中的晶振频率即可。
[xiaokai@centos6 linux-3.0]$ vim arch/arm/mach-s3c2440/mach-smdk2440.c
进入mach-smdk2440.c后,搜索smdk2410_map_io函数里面改时钟,此时需要知道我们之前uboot移植时定义过SBC2410X的输入时钟;
[xiaokai@centos6 linux-3.0]$ vim ../../bootloader/u-boot-2010.09/include/configs/sbc2410x.h
打开此文件之后,搜索52行可以看到
#define CONFIG_SYS_CLK_FREQ 12000000 /* the SBC2410X has 12MHz input clock */
说明我们需要将初始化,因而在180行
s3c24xx_init_clocks(16934400);
改为:
s3c24xx_init_clocks(12000000);
六、修改对uart控制器的配置,配置为普通串口
由于三星默认的串口名为ttySAC,而我们根文件系统中/etc/inittab文件中的串口名称需与内核中的串口名称一致。由于我的根文件系统中/etc/inittab中的串口名称为s3c2440_serial0,因此需要修改内核中的串口名称。现在我们需要内核移到S3C2440上,通过修改samsung.c可以将串口设备使能并加载到内核上;
[xiaokai@centos6 linux-3.0]$ vim drivers/tty/serial/samsung.c
在这个文件中我们将57行串口设备名改为如下:
#define S3C24XX_SERIAL_NAME "ttyS"即可保存;
七、机器码的修改
由于我uboot配置文件中是以mini2440为副本来移植的,在uboot移植工程中已将mini2440的ID号强制加载给Smdk2440。故此次Linux内核移植时为了以Smdk2440为模板来启动,而将mini2440本来的ID号1999改掉,如下:
-mini2440 MACH_MINI2440 MINI2440 999
+mini2440 MACH_MINI2440 MINI2440362
[xiaokai@centos6 linux-3.0]$ vim arch/arm/tools/mach-types
打开此文件后,在176行将看到MACHINE_START(S3C2440, "SMDK2440"),这里就是S3C2440的machine ID号。
八、拷贝.config文件
由于我们的开发板fl2440和mini2440的设计基本一样,所以我们以mini2440_defconfig为模板来生效我们需要执行或安装的一些功能模块;
[xiaokai@centos6 linux-3.0]$ cp arch/arm/configs/mini2440_defconfig .config
九、更改menuconfig配置对CPU的支持
[xiaokai@centos6 linux-3.0]$ export TERM=vt100
[xiaokai@centos6 linux-3.0]$ make menuconfig
System Type --->
S3C2440 and S3C2442 Machines --->
取消[ ]MINI2440 development board
选中[*]SMDK2440
点击退出保存即可。
十、make
即可生成我们需要的内核文件linuxrom-xiao.bin