Linux内核移植与启动
Targetborad:FL2440
Bootloader:U-boot-.09
交叉编译器:buildroot-.08
1.linux内核基础知识
首先,磨刀不误砍柴工。在动手进行linux内核移植之前,我们有必要对linux内核进行一定的了解。
1.1Linux内核启动过程概述
一个嵌入式Linux系统从软件角度看可以分为四个部分:
引导加载程序(Bootloader),Linux内核,文件系统,应用程序。
其中Bootloader是系统启动或复位以后执行的第一段代码,它主要用来初始化处理器及外设,然后调用Linux内核,linux内核在完成系统的初始化之后需要挂载某个文件系统作为根文件系统(rootfs),根文件系统是linux系统的核心组成部分,也是内核启动时首先要挂载的就是根文件系统。它可以作为linux系统中文件和数据的存储区域,通常它还包括系统配置文件和运行应用程序需要的库,保证了人和内核的信息交互。应用程序则是嵌入式系统所要达到的目标,一切的准备都是为了实现程序。若是没有应用程序,硬件上再精良嵌入式系统都没有实用意义。
Bootloader:在嵌入式操作系统中,BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。Bootloader在它完成CPU和相关硬件的初始化之后,再将操作系统映像或固化的嵌入式应用程序装在到内存中然后跳转到操作系统所在的空间,启动操作系统运行。它最根本的功能就是为了启动linux内核.为了启动内核Bootloader要依次完成
初始化RAM—初始化串口—检测处理器类型—设置Linux启动参数(bootargs)—调用Linux内核镜像。
文件系统:Linux文件系统中的文件是数据的集合,文件系统不仅包含着文件中的数据而且还有文件系统的结构,所有Linux用户和程序看到的文件、目录、软连接及文件保护信息等都存储在其中。
1.2编译环境交叉编译器的制作
交叉编译器本节不过多介绍。但我们必须知道若要实现人,虚拟机,开发板之间的信息传递就必须首先制作交叉编译器来帮助我们编译。在做好交叉编译器准备好编译环境之后我们就可以开始进行纯内核移植了。(在此使用的交叉编译器为buildroot-.08)
2.Linux内核移植与启动
2.1下载并解压缩linux-3.0.tar.bz2源代码
首先到LinuxKernel官方网站下载得到linux-3.0-rc4.tar.bz2文件,把它放到一个你有权限读写的文件夹,运行下面命令解压缩并进入解压后的文件夹:
$tar-xjflinux-3.0.tar.bz2
$cdlinux-3.0
2.2配置内核编译参数
1.首先修改顶层目录的Makefile文件
$vimMakefile
这里首要便是交叉编译器环境变量和选择开发平台类型
然后要将生成的zimage拷贝到当前目录,再手动增加mkimage工具来自动把Zimage生成可执行的.bin文。
注:内核编译之后会生成两个文件。一个Image,一个Zimage。image为内核映像文件,而Zimage为内核映像压缩文件。Image大约为4M,而Zimage不到2M。
===============================================================================
@@-192,8+192,8@@
#DefaultvalueforCROSS_COMPILEisnottoprefixexecutables
#Note:SomearchitecturesassignCROSS_COMPILEintheirarch/*/Makefile
exportKBUILD_BUILDHOST:=$(SUBARCH)
-ARCH?=$(SUBARCH)
-CROSS_COMPILE?=$(CONFIG_CROSS_COMPILE:"%"=%)
+ARCH?=arm
+CROSS_COMPILE?=/opt/buildroot-.08.packet/buildroot-.08/arm920t/usr/bin/arm-linux-
#Architectureaspresentincompile.h
UTS_MACHINE:=$(ARCH)
@@-557,6+557,9@@
#Thisallowausertoissueonly'make'tobuildakernelincludingmodules
#Defaultstovmlinux,butthearchmakefileusuallyaddsfurthertargets
all:vmlinux
+cparch/arm/boot/zImage.-f
+mkimage-Aarm-Olinux-Tkernel-Cnone-a30008040-n"LinuxKernel"-dzImage\linuxrom-s3c2440.bin
+rm-fzImage
ifdefCONFIG_CC_OPTIMIZE_FOR_SIZE
KBUILD_CFLAGS+=-Os
@@-1201,6+1204,7@@
-o-name'.*.rej'-o-size0\
-o-name'*%'-o-name'.*.cmd'-o-name'core'\)\
-typef-print|xargsrm-f
+@rm-flinuxrom-s3c2440.bin
2.修改晶振频率
因为我使用的是FL2440的开发板,根据datesheet可知晶振频率为12M。所以下一步修改晶振频率。
$vimarch/arm/mach-s3c2440/mach-smdk2440.c
============================================================================
@@-160,7+160,7@@
staticvoid__initsmdk2440_map_io(void)
{
s3c24xx_init_io(smdk2440_iodesc,ARRAY_SIZE(smdk2440_iodesc));
--s3c24xx_init_clocks(16934400);
+s3c24xx_init_clocks(12000000);
s3c24xx_init_uarts(smdk2440_uartcfgs,ARRAY_SIZE(smdk2440_uartcfgs));
}
3.修改驱动的串口
vimdrivers/tty/serial/samsung.c
===========================================================================
@@-54,7+54,7@@
/*UARTnameanddevicedefinitions*/
--#defineS3C24XX_SERIAL_NAME"ttySAC"
+#defineS3C24XX_SERIAL_NAME"ttyS"
#defineS3C24XX_SERIAL_MAJOR204
#defineS3C24XX_SERIAL_MINOR64
参考mini2440的.config文件作为我们的默认.config文件。改好之后再
$Makemenuconfig
打开文本窗口来选定即将要编译的模块,保存后会将里面的信息保存到同时生成的.config配置文件中。
另外:makemenuconfig时出来的文本窗口中的信息是通过读取在内核源代码目录下的Kconfig文件来配置的。根据Makefile文件来编译,而Makefile文件中的变量则通过.config来进行赋值操作。仅仅在Kconfig中添加选项。
4.修改MACHINEID设备编号
同样因为是做FL2440的内核,所以我们选择三星SMDK2440这个开发板。因为我U-boot中使用的machineid为1999,而且我使用的是s3c2440这个板子。
将mini2440和和s3c2440的machineID对调。
$vimarch/arm/tools/mach-types
配置就绪之后
Make
显示成功
此时已经会生成一个linux-s3c2440.bin的可执行二进制文件。
5.对nandflash进行分区
=========================================================================================================
@@-106,49+106,39@@
},
};
-/*NANDparititonfrom2.4.18-swl5*/
+/*NANDparititonfrom2.4.18-swl5,modifybyHandy.11.30*/
staticstructmtd_partitionsmdk_default_nand_part[]={
[0]={
-.name="BootAgent",
-.size=SZ_16K,
+.name="bootloader",
+.size=SZ_1M,
.offset=0,
},
[1]={
-.name="S3C2410flashpartition1",
-.offset=0,
-.size=SZ_2M,
+.name="linux",
+.offset=MTDPART_OFS_NXTBLK,
+.size=SZ_1M*15,
},
[2]={
-.name="S3C2410flashpartition2",
-.offset=SZ_4M,
-.size=SZ_4M,
+.name="rootfs",
+.offset=MTDPART_OFS_NXTBLK,
+.size=SZ_1M*40,
},
[3]={
-.name="S3C2410flashpartition3",
-.offset=SZ_8M,
-.size=SZ_2M,
+.name="apps",
+.offset=MTDPART_OFS_NXTBLK,
+.size=SZ_1M*50,
},
[4]={
-.name="S3C2410flashpartition4",
-.offset=SZ_1M*10,
-.size=SZ_4M,
+.name="data",
+.offset=MTDPART_OFS_NXTBLK,
+.size=SZ_1M*50,
},
[5]={
-.name="S3C2410flashpartition5",
-.offset=SZ_1M*14,
-.size=SZ_1M*10,
-},
-[6]={
-.name="S3C2410flashpartition6",
-.offset=SZ_1M*24,
-.size=SZ_1M*24,
-},
-[7]={
-.name="S3C2410flashpartition7",
-.offset=SZ_1M*48,
+.name="backup",
+.offset=SZ_1M*100,
.size=MTDPART_SIZ_FULL,
-}
+},
};
板子上nandflash是256M,给bootloader1M用来启动,内核15M以及40M的根文件系统。其他自由分配。
注意:此时若要再进行分区就要选择相应的文件系统。Nandflash比较常用的有yaffs2,ubifs,cramfs以及initramfs等等。
$make
此时能编译成功,但是生成的linux-s3c2440.bin文件依旧不能在板子上跑起来。
因为内核启动时首先挂载的是根文件系统,我们还没有做根文件系统给予内核支持,系统会出错而退出启动。
3.添加根文件系统支持
1、根文件系统简介
文件系统是对一个存储设备上的数据和元数据进行组织的机制。这种机制有利于用户和操作系统的交互。而根文件系统则是所有文件系统的根,我理解的是所有文件系统都是由根文件系统扩展开来的。而若是没有根文件系统则谈不上其他的文件系统。根文件系统它包含系统引导以及其他文件系统所能挂载的必要文件。
什么是根文件系统?首先是一种文件系统,但是相对于普通的文件系统,它的特殊之处在于,它是内核
启动时所mount的第一个文件系统。
而Linux又支持多种文件系统,包括ext2、ext3、vfat、ntfs、iso9660、jffs、romfs和nfs等,为了对各类文件系统进行统一管理,Linux引入了虚拟文件系统VFS(VirtualFileSystem),为各类文件系统提供一个统一的操作界面和应用编程接口。Linux启动时,第一个必须挂载的是根文件系统;若系统不能从指定设备上挂载根文件系统,则系统会出错而退出启动。之后可以自动或手动挂载其他的文件系统。因此,一个系统中可以同时存在不同的文件系统。
不同的文件系统类型有不同的特点,因而根据存储设备的硬件特性、系统需求等有不同的应用场合。在嵌入式Linux应用中,主要的存储设备为RAM(DRAM,SDRAM)和ROM(常采用FLASH存储器),常用的基于存储设备的文件系统类型包括:jffs2,yaffs,cramfs,romfs,ramdisk,ramfs/tmpfs等。
2、根文件系统支持
本文主要写内核的移植与启动,所以选择了制作很简单的initramfs文件系统作为根文件系统,它能伴随内核编译时同时与内核生成一个镜像而能与之一起启动。
$Makemenuconfig
进去选择Generalsetup编译模块
在下面选择InitialRAMfilesystem.....即initramfs文件系统,然后选择支持initramfs的源文件系统包所处位置。这里为../../rootfs/rootfs_tree/
在选择保存后即可连接开发板。重新编译内核后下载到板子上便可以启动了!