Linux内核移植和yaffs2根文件系统制作.docx
- 文档编号:8076876
- 上传时间:2023-01-28
- 格式:DOCX
- 页数:28
- 大小:36.29KB
Linux内核移植和yaffs2根文件系统制作.docx
《Linux内核移植和yaffs2根文件系统制作.docx》由会员分享,可在线阅读,更多相关《Linux内核移植和yaffs2根文件系统制作.docx(28页珍藏版)》请在冰豆网上搜索。
Linux内核移植和yaffs2根文件系统制作
Linux内核移植和yaffs2根文件系统制作V1.2
1.1Linux内核基础知识
在动手进行Linux内核移植之前,非常有必要对Linux内核进行一定的了解,下面从Linux内核的版本和分类说起。
1.1.1Linux版本
Linux内核的版本号可以从源代码的顶层目录下的Makefile中看到,比如2.6.29.1内核的Makefile中:
VERSION=2
PATCHLEVEL=6
SUBLEVEL=29
EXTRAVERSION=.1
其中的“VERSION”和“PATCHLEVEL”组成主版本号,比如2.4、2.5、2.6等,稳定版本的德主版本号用偶数表示(比如2.6的内核),开发中的版本号用奇数表示(比如2.5),它是下一个稳定版本内核的前身。
“SUBLEVEL”称为次版本号,它不分奇偶,顺序递增,每隔1~2个月发布一个稳定版本。
“EXTRAVERSION”称为扩展版本号,它不分奇偶,顺序递增,每周发布几次扩展本版号。
1.1.2什么是标准内核
按照资料上的习惯说法,标准内核(或称基础内核)就是指主要在http:
//www.kernel.org/维护和获取的内核,实际上它也有平台属性的。
这些linux内核并不总是适用于所有linux支持的体系结构。
实际上,这些内核版本很多时候并不是为一些流行的嵌入式linux系统开发的,也很少运行于这些嵌入式linux系统上,这个站点上的内核首先确保的是在IntelX86体系结构上可以正常运行,它是基于X86处理器的内核,如对linux-2.4.18.tar.bz2的配置makemenuconfig时就可以看到,Processortypeandfeatures--->中只有386、486、586/K5/5x86/6x86/6x86MX、Pentium-Classic、Pentium-MMX、Pentium-Pro/Celeron/Pentium-II、Pentium-III/Celeron(Coppermine)、Pentium-4、K6/K6-II/K6-III、Athlon/Duron/K7、Elan、Crusoe、Winchip-C6、Winchip-2、Winchip-2A/Winchip-3、CyrixIII/C3选项,而没有类似Samsun2410等其他芯片的选择。
如果需要用在其他特定的处理器平台上就需要对内核进行打补丁,形成不同的嵌入式内核。
实际上,不同处理器系统的内核下载站点中提供的也往往是补丁patch而已,故原x86平台上的内核变成了基础内核,也被称为标准内核了。
1.1.3Linux操作系统的分类
第一层次分类:
以主要功能差异和发行组织区分(基础linux系统/内核)。
1、标准linux
2、μClinux
无MMU支持的linux系统,运行在无MMU的CPU上。
3、Linux-RT
是最早在linux上实现硬实时支持的linux发行版本。
4、Linux/RTAI
支持硬实时的linux,于RT-linux最大的不同之处在于RTAI定义了RTHAL,它将RTAI需要在linux中修改的部分定义成一组API接口,RTAI只使用API管理员在2009年8月13日编辑了该文章文章。
-->1.2.1Bootloader启动过程
Bootloader在运行过程中虽然具有初始化系统和执行用户输入的命令等作用,但它最根本的功能就是为了启动Linux内核。
1、Bootloader的概念和作用
Bootloader是嵌入式系统的引导加载程序,它是系统上电后运行的第一段程序,其作用类似于PC机上的BIOS。
在完成对系统的初始化任务之后,它会将非易失性存储器(通常是Flash或DOC等)中的Linux内核拷贝到RAM中去,然后跳转到内核的第一条指令处继续执行,从而启动Linux内核。
由此可见,Bootloader和Linux内核有着密不可分的联系,要想清楚的了解Linux内核的启动过程,我们必须先得认识Bootloader的执行过程,这样才能对嵌入式系统的整个启动过程有清晰的掌握。
2、Bootloader的执行过程
不同的处理器上电或复位后执行的第一条指令地址并不相同,对于ARM处理器来说,该地址为0x00000000。
对于一般的嵌入式系统,通常把Flash等非易失性存储器映射到这个地址处,而Bootloader就位于该存储器的最前端,所以系统上电或复位后执行的第一段程序便是Bootloader。
而因为存储Bootloader的存储器不同,Bootloader的执行过程也并不相同,下面将具体分析。
嵌入式系统中广泛采用的非易失性存储器通常是Flash,而Flash又分为NorFlash和NandFlash两种。
它们之间的不同在于:
NorFlash支持芯片内执行(XIP,eXecuteInPlace),这样代码可以在Flash上直接执行而不必拷贝到RAM中去执行。
而NandFlash并不支持XIP,所以要想执行NandFlash上的代码,必须先将其拷贝到RAM中去,然后跳到RAM中去执行。
3、Bootloader的功能
实际应用中的Bootloader根据所需功能的不同可以设计得很复杂,除完成基本的初始化系统和调用Linux内核等基本任务外,还可以执行很多用户输入的命令,比如设置Linux启动参数,给Flash分区等;也可以设计得很简单,只完成最基本的功能。
但为了能达到启动Linux内核的目的,所有的Bootloader都必须具备以下功能:
(1)、初始化RAM
因为Linux内核一般都会在RAM中运行,所以在调用Linux内核之前bootloader必须设置和初始化RAM,为调用Linux内核做好准备。
初始化RAM的任务包括设置CPU的控制寄存器参数,以便能正常使用RAM以及检测RAM大小等。
(2)、初始化串口
串口在Linux的启动过程中有着非常重要的作用,它是Linux内核和用户交互的方式之一。
Linux在启动过程中可以将信息通过串口输出,这样便可清楚的了解Linux的启动过程。
虽然它并不是Bootloader必须要完成的工作,但是通过串口输出信息是调试Bootloader和Linux内核的强有力的工具,所以一般的Bootloader都会在执行过程中初始化一个串口做为调试端口。
(3)、检测处理器类型
Bootloader在调用Linux内核前必须检测系统的处理器类型,并将其保存到某个常量中提供给Linux内核。
Linux内核在启动过程中会根据该处理器类型调用相应的初始化程序。
(4)、设置Linux启动参数
Bootloader在执行过程中必须设置和初始化Linux的内核启动参数。
目前传递启动参数主要采用两种方式:
即通过structparam_struct和structtag(标记列表,taggedlist)两种结构传递。
structparam_struct是一种比较老的参数传递方式,在2.4版本以前的内核中使用较多。
从2.4版本以后Linux内核基本上采用标记列表的方式。
但为了保持和以前版本的兼容性,它仍支持structparam_struct参数传递方式,只不过在内核启动过程中它将被转换成标记列表方式。
标记列表方式是种比较新的参数传递方式,它必须以ATAG_CORE开始,并以ATAG_NONE结尾。
中间可以根据需要加入其他列表。
Linux内核在启动过程中会根据该启动参数进行相应的初始化工作。
(5)、调用Linux内核映像
Bootloader完成的最后一项工作便是调用Linux内核。
如果Linux内核存放在Flash中,并且可直接在上面运行(这里的Flash指NorFlash),那么可直接跳转到内核中去执行。
但由于在Flash中执行代码会有种种限制,而且速度也远不及RAM快,所以一般的嵌入式系统都是将Linux内核拷贝到RAM中,然后跳转到RAM中去执行。
不论哪种情况,在跳到Linux内核执行之前CPU的寄存器必须满足以下条件:
r0=0,r1=处理器类型,r2=标记列表在RAM中的地址。
1.2.2Linux启动过程
在Bootloader将Linux内核映像拷贝到RAM以后,可以通过下例代码启动Linux内核:
call_linux(0,machine_type,kernel_params_base)。
其中,machine_tpye是Bootloader检测出来的处理器类型,kernel_params_base是启动参数在RAM的地址。
通过这种方式将Linux启动需要的参数从bootloader传递到内核。
Linux内核有两种映像:
一种是非压缩内核,叫Image,另一种是它的压缩版本,叫zImage。
根据内核映像的不同,Linux内核的启动在开始阶段也有所不同。
zImage是Image经过压缩形成的,所以它的大小比Image小。
但为了能使用zImage,必须在它的开头加上解压缩的代码,将zImage解压缩之后才能执行,因此它的执行速度比Image要慢。
但考虑到嵌入式系统的存储空容量一般比较小,采用zImage可以占用较少的存储空间,因此牺牲一点性能上的代价也是值得的。
所以一般的嵌入式系统均采用压缩内核的方式。
对于ARM系列处理器来说,zImage的入口程序即为arch/arm/boot/compressed/head.S。
它依次完成以下工作:
开启MMU和Cache,调用decompress_kernel()解压内核,最后通过调用call_kernel()进入非压缩内核Image的启动。
下面将具体分析在此之后Linux内核的启动过程。
1、Linux内核入口
Linux非压缩内核的入口位于文件/arch/arm/kernel/head-armv.S中的stext段。
该段的基地址就是压缩内核解压后的跳转地址。
如果系统中加载的内核是非压缩的Image,那么bootloader将内核从Flash中拷贝到RAM后将直接跳到该地址处,从而启动Linux内核。
不同体系结构的Linux系统的入口文件是不同的,而且因为该文件与具体体系结构有关,所以一般均用汇编语言编写。
对基于ARM处理的Linux系统来说,该文件就是head-armv.S。
该程序通过查找处理器内核类型和处理器类型调用相应的初始化函数,再建立页表,最后跳转到start_kernel()函数开始内核的初始化工作。
检测处理器内核类型是在汇编子函数__lookup_processor_type中完成的。
通过以下代码可实现对它的调用:
bl__lookup_processor_type。
__lookup_processor_type调用结束返回原程序时,会将返回结果保存到寄存器中。
其中r8保存了页表的标志位,r9保存了处理器的ID号,r10保存了与处理器相关的struproc_info_list结构地址。
检测处理器类型是在汇编子函数__lookup_architecture_type中完成的。
与__lookup_processor_type类似,它通过代码:
“bl__lookup_processor_type”来实现对它的调用。
该函数返回时,会将返回结构保存在r5、r6和r7三个寄存器中。
其中r5保存了RAM的起始基地址,r6保存了I/O基地址,r7保存了I/O的页表偏移地址。
当检测处理器内核和处理器类型结束后,将调用__create_page_tables子函数来建立页表,它所要做的工作就是将RAM基地址开始的4M空间的物理地址映射到0xC0000000开始的虚拟地址处。
对笔者的S3C2410开发板而言,RAM连接到物理地址0x30000000处,当调用__create_page_tables结束后0x30000000~0x30400000物理地址将映射到0xC0000000~0xC0400000虚拟地址处。
当所有的初始化结束之后,使用如下代码来跳到C程序的入口函数start_kernel()处,开始之后的内核初始化工作:
bSYMBOL_NAME(start_kernel)
2、start_kernel函数
start_kernel是所有Linux平台进入系统内核初始化后的入口函数,它主要完成剩余的与硬件平台相关的初始化工作,在进行一系列与内核相关的初始化后,调用第一个用户进程-init进程并等待用户进程的执行,这样整个Linux内核便启动完毕。
该函数所做的具体工作有:
调用setup_arch()函数进行与体系结构相关的第一个初始化工作;对不同的体系结构来说该函数有不同的定义。
对于ARM平台而言,该函数定义在arch/arm/kernel/Setup.c。
它首先通过检测出来的处理器类型进行处理器内核的初始化,然后通过bootmem_init()函数根据系统定义的meminfo结构进行内存结构的初始化,最后调用paging_init()开启MMU,创建内核页表,映射所有的物理内存和IO空间。
创建异常向量表和初始化中断处理函数;初始化系统核心进程调度器和时钟中断处理机制;初始化串口控制台(serial-console);ARM-Linux在初始化过程中一般都会初始化一个串口做为内核的控制台,这样内核在启动过程中就可以通过串口输出信息以便开发者或用户了解系统的启动进程。
创建和初始化系统cache,为各种内存调用机制提供缓存,包括;动态内存分配,虚拟文件系统(VirtualFileSystem)及页缓存。
初始化内存管理,检测内存大小及被内核占用的内存情况;初始化系统的进程间通信机制(IPC);当以上所有的初始化工作结束后,start_kernel()函数会调用rest_init()函数来进行最后的初始化,包括创建系统的第一个进程-init进程来结束内核的启动。
init进程首先进行一系列的硬件初始化,然后通过命令行传递过来的参数挂载根文件系统。
最后init进程会执行用户传递过来的“init=”启动参数执行用户指定的命令,或者执行以下几个进程之一:
execve("/sbin/init",argv_init,envp_init)
execve("/etc/init",argv_init,envp_init)
execve("/bin/init",argv_init,envp_init)
execve("/bin/sh",argv_init,envp_init)
当所有的初始化工作结束后,cpu_idle()函数会被调用来使系统处于闲置(idle)状态并等待用户程序的执行。
至此,整个Linux内核启动完毕。
Linux内核是一个非常庞大的工程,经过十多年的发展,它已从从最初的几百KB大小发展到现在的几百兆。
清晰的了解它执行的每一个过程是件非常困难的事。
但是在嵌入式开发过程中,我们并不需要十分清楚Linux的内部工作机制,只要适当修改Linux内核中那些与硬件相关的部分,就可以将Linux移植到其它目标平台上。
通过对Linux的启动过程的分析,我们可以看出哪些是和硬件相关的,哪些是Linux内核内部已实现的功能,这样在移植Linux的过程中便有所针对。
而Linux内核的分层设计将使Linux的移植变得更加容易。
1.3Linux内核移植
1.3.1移植内核和根文件系统准备工作
移植内核前,保证你已经装上了Linux系统,建立好了交叉编译环境,我用的是虚拟机,装的Redhat9.0系统,交叉编译工具用的是友善之臂的arm-linux-gcc-4.3.2。
开始移植Linux内核了,下面是我我使用的内核和文件系统,以及所用到的工具及获取方法:
1、Linux系统
我是在虚拟机上安装的Redhat9.0。
XP系统下虚拟机设置的共享目录是D:
share,对应的Linux系统的目录是/mnt/hgfs/share。
我将下面准备的压缩包和文件都统一放到该目录下。
2、Linux内核
到www.kernel.org/主页,进入该网站中链接FTPftp:
//ftp.kernel.org/pub/,在里面进入文件夹“linux->kernel->v2.6”,会出现很多版本的内核压缩包和补丁,选中Linux-2.6.29.1.tar.bz2下载。
3、交叉编译工具链
使用友善之臂提供的arm-linux-4.3.2工具链,没有的到
4、yaffs2代码
进入http:
//www.aleph1.co.uk/cgi-bin/viewcvs.cgi/,点击“DownloadGNUtarball”,下载后出现cvs-root.tar.gz压缩包。
5、busybox-1.13.3
从busybox-1.13.3.tar.gz。
6、根文件系统制作工具
到友善之臂网站下载根文件系统制作工具mkyaffs2image.tgz。
7、友善之臂的根文件系统
在制作根文件系统时,需要用到链接库,为保证链接库能用直接用友善之臂的根文件系统root_qtopia中的链接库lib,到友善之臂网站下载root_qtopia.tgz。
这些文件都下载到D:
share中,通过虚拟机进入Redhat9.0系统,进入/mnt/hgfs/share目录便可访问这些与XP共享的文件。
8、硬件平台
友善之臂的mini2440
1.3.2修改Linux源码中参数
1、解压内核源码
mkdir/opt/studyarm
cd/mnt/hgfs/share
tar–jxvflinux-2.6.29.1.tar.bz2–C/opt/studyarm
2、进入内核目录,修改makefile,并对内核进行默认配置进行修改
193行,修改
ARCH?
=arm
CROSS_COMPILE?
=arm-linux-
3、修改平台输入时钟
找到内核源码arch/arm/mach-s3c2440/mach-smdk2440.c文件,在函数staticvoid__initsmdk2440_map_io(void)中,修改成s3c24xx_init_clocks(12000000)。
4、修改machine名称(可以不改)
修改文件arch/arm/mach-s3c2440/mach-smdk2440.c,在文件中找到MACHINE_START(),修改为MACHINE_START(S3C2440,“Study-S3C2440”)。
5、修改Nandflash分区信息
修改文件kernel.git/arch/arm/plat-s3c24xx/common-smdk.c。
第一,修改分区信息:
staticstructmtd_partitionsmdk_default_nand_part[]={
[0]={
.name="bootloader",
.offset=0x00000000,
.size=0x00030000,
},
[1]={
.name="kernel",
.offset=0x00050000,
.size=0x00200000,
},
[2]={
.name="root",
.offset=0x00250000,
.size=0x03dac000,
}
};
第二,再修改s3c2410_platform_nand_smdk_nand_infosmdk_nand_info={
…
.tacls=0,
.twrph0=30,
.twrph1=0,
…
};
6、修改LCD背光
修改文件/arch/arm/mach-s3c2440/mach-smdk2440.c,因为友善的3.5寸液晶的背光控制是由S3C2440的GPG4引脚来控制的,故下面的改动将开启背光。
staticvoid__initsmdk2440_machine_init(void)
{
s3c24xx_fb_set_platdata(&smdk2440_fb_info);
platform_add_devices();
s3c2410_gpio_cfgpin(S3C2410_GPG4,S3C2410_GPG4_OUTP);
s3c2410_gpio_setpin(S3C2410_GPG4,1);smdk_machine_init();
}
6、LCD参数修改
这里用的是NEC3.5英寸屏液晶屏,大小为320x240,需要修改修改文件arch/arm/mach-s3c2440/mach-smdk2440.c。
staticstructs3c2410fb_displaysmdk2440_lcd_cfg__initdata=
{
…
.right_margin=37,
.hsync_len=6,
.upper_margin=2,
.lower_margin=6,
.vsync_len=2,
};
staticstructs3c2410fb_mach_infosmdk2440_fb_info__initdata={
…
.default_display=0
.gpccon=0xaa955699,
.gpccon_mask=0xffc003cc,
.gpcup=0x0000ffff,
.gpcup_mask=0xffffffff,
.gpdcon=0xaa95aaa1,
.gpdcon_mask=0xffc0fff0,
.gpdup=0x0000faff,
.gpdup_mask=0xffffffff,
.lpcsel=0xf82,
};
7、给内核打yaffs2文件系统的补丁
cd/mnt/hgfs/share
tar–zxvf/mnt/hgfs/share/cvs-root.tar.gz–C/opt/studyarm
cd/opt/stdudyarm/cvs/yaffs2/
./patch-ker.shc/opt/studyarm/linux-2.6.29.1/
上面命令完成下面三件事情:
(1)修改内核fs/Kconfig
增加一行:
source"fs/yaffs2/Kconfig"
(2)修改内核fs/Kconfig
增加一行:
ojb-$(CONFIG_YAFFS_FS)+=yaffs2/
(3)在内核fs/目录下创建yaffs2目录
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Linux 内核 移植 yaffs2 文件系统 制作