内核编译与移植

Posted fxzq

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内核编译与移植相关的知识,希望对你有一定的参考价值。

在嵌入式Linux系统中,内核移植非常关键,没有Linux内核一切都是空谈,下面我们就来讨论一下Linux内核在S3C2416上的移植。
首先,Linux是开源软件,其内核源代码可以直接到网站https://www.kernel.org/上下载。但Linux内核的版本非常之多,而且各个版本之间都存在有很多差异,那下载哪一个版本好呢?其实这个问题很难有统一的答案,但作为嵌入式系统开发本身来说,坚持两个原则是没错的:一是够用就好,不要去追求“高大尚”;二是能够维护好一套内核就行,不要一昧的去追新。如果你已经有了一套维护好的成熟内核,那就一直用它吧,除非万不得已不要更换,否则带来的工作量将是巨大的,花时间去研究不说,关键是可能新内核还没有你原来的稳定,再有就是内核变了可能你原来的驱动全部都要重写,无异于全部重新学习,想想都怕。嵌入式系统一般是定制于某项应用功能的(手机除外^_^),所以没有必要去追求新版本,因为无论内核如何变换,其实现的应用功能是不变的。
那么做为初学者应该如何选取内核呢?其实,针对初学者建议直接使用官方提供的BSP(板级支持包),在购买嵌入式开发板的时候,厂家都会配套为你提供已经移植好的内核,以方便使用。然而,在很多爱好者学习了一段时间的嵌入式系统之后,或者在学校嵌入式系统开发的课程中,往往会想要自己动手去移植一个内核,那么这里给出两种方法提供借鉴:一是使用一个完全与你的BSP一样版本的内核源码来实验(比如都是Linux-2.6.39.4);二是使用更新的版本来实验。推荐先做第一种,在成功之后可尝试着做第二种。
对于第一种方法,其实就是依葫芦画瓢,很快就能上手了。
首先下载内核源码(这里假设BSP提供的源码版本为Linux-2.6.39.4,所以下载的内核源码文件为linux-2.6.39.4.tar.bz2 ),完成后将文件拷贝到虚拟机中,然后把它解压到根目录下,执行命令“tar -jxvf linux-2.6.39.4.tar.bz2 -C /”,完成后到根目录下确认一下,然后把目录名称更改一下,执行“mv linux-2.6.39.4 linux-2.6.39.4.raw”,这样做的目的主要是为了后面好区分下载的源码与BSP的源码。完成后以同样的方式把BSP提供的内核源码也解压到根目录,目录名称就为linux-2.6.39.4。
接下来要找出BSP的源码更改了哪些地方,在根目录下执行命令“diff -r linux-2.6.39.4.raw linux-2.6.39.4 > diff”,该命令执行会需要一些时间,完成后在根目录下会生成一个文本文件diff,查看该文件就可看到两个目录文件的区别,它不仅能告诉你多了哪些文件,还会告诉你哪些文件的内容被更改过,改成了什么内容等等。
接下来根据diff文件显示的不同,把它们一一找出来。在diff文件(建议打印出来看)中,以Only开头的那行是指明该文件只在该目录下存在(即BSP中新加入的文件,源码中没有),以diff开头的那行是指明哪个文件有区别,其区别写在该行以下,其中,以“<”符号开头的说明该句只在linux-2.6.39.4.raw目录下的文件中存在,同理,以“>”符号开头的说明该句只在linux-2.6.39.4目录下的文件中存在。(其实“<”代表命令“diff -r linux-2.6.39.4.raw linux-2.6.39.4 > diff中要比较的左边的那个目录,即linux-2.6.39.4.raw目录,“>”则代表右边的那个目录,即linux-2.6.39.4目录。)其中还会有些诸如“26c27、102a103”等之类的提示,前面的数字表示行号,c表示清除,a表示追加等等,要详细了解可查一查diff命令,这里就不赘述了。
找出区别后就好办了,接下来你就可以按照区别来改,先把BSP中新增的文件拷贝到源码中相同目录下,再把有区别的文件进行替换操作(当然你也可以自己对照着来修改源文件),完成之后还要记得利用BSP中的配置文件进行系统配置,这有两种方法,一是直接拷贝linux-2.6.39.4目录下的配置文件过来(如果有的话),二是先在linux-2.6.39.4目录下执行内核配置命令,以生成“.config”文件(当然如果有“.config”文件就省事了),然后把该拷贝到linux-2.6.39.4.raw目录下就可以了。具体的配置将会在后面第二种方法中再作详细讨论。
最后执行内核编译命令“make zImage”或“make -j4 zImage”(仅当电脑是四核且虚拟机也配置为四核时),如果一切顺利,编译结束后就可以得到内核映像文件zImage了(默认在arch/arm/boot目录下),把该内核下载到开发板中,就能够启动开发板了。虽然是与原BSP内核一样的版本,但毕竟是自己做出来的第一个可用内核,这样做可以提高学习效率,增加成就感,减小挫折。先跑起来,其后再慢慢来分析修改部分的内容,进一步了解其原理,不失为一种快速入门的办法。
对于第二种方法,实际上是从零开始移植内核,这就需要从头说起,这种方法不太适合初学者。
这里以Linux-3.0.99为例进行讨论,这个版本其实是2.6.XX的最后一个版本,3.1.XX以后的版本与它们的差别就太大了,不仅引入了DTS(设备树)的概念,而且很多以前的API函数都发生了变化,甚至有的函数已经没有了。所以,在此处选用市场上已大量使用过的2.6.XX内核的最后一个版本3.0.99,也算作是个纪念吧。嵌入式开发板仍然以杭州硕数公司的S3C2416核心板为例进行移植实验。
在移植Linux之前有必要先讨论一下所用的开发板。在Linux内核源码中,不仅提供了对CPU架构的支持,还专门针对一些开发板提供了板级的支持,这种Linux板级支持的开发板,会由相应的CPU产商提供了一个基本的Demo,即提供一个“公板”,其它开发板供应商则是在这个公板的基础上进行适当的修改,以形成有自己特色的开发板。当然,有的做的比较有名的开发板,也会被Linux组织收录进板级支持(比如国内知名的mini2440)。这些板级支持的目录一般位于内核目录的arch/arm/configs目录下,因为该目录是内核的板级配置目录,所以文件名都以“XXXX_defconfig”的形式呈现(比如mini2440_defconfig)。但如果你使用的开发板没有板级支持,那么也可以使用“公板”的配置文件“s3c2410_defconfig”来进行修改。我们接下来就是以这个基本的配置文件来配置硕数公司的S3C2416核心板的。
与第一种方法一样,把从网上下下来的内核文件linux-3.0.99.tar.bz2拷贝到虚拟机中,并解压到根目录下,然后执行“cd /linux-3.0.99”进入该目录。由于编译的是arm架构的内核,所以先要改更交叉编译条件,执行“vim Makefile”打开顶层的Makefile文件,然后输入一个冒号进入底行模式,在冒号后面输入“/CROSS_COMPILE”(不包含双引号,后同),回车后就找到形如“CORSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:”%”=%)”的这样一句所在的位置,把它改为“CORSS_COMPILE ?= arm-linux-”(注:-后不能有空格),并把紧跟着它的上一句也改成“ARCH ?= arm”。然后存盘退出,这样交叉编译条件就改好了。
接下来进行内核配置,在源码的根目录下先执行命令“make s3c2410_defconfig”,完成后再执行菜单配置命令“make menuconfig”,过一会儿后会出现一个文本模式下的菜单,如下图所示。

技术图片 

在上图的对话框中,可利用键盘的上下光标键移动选择条,“Y”键勾选,“N”键取消,"M"键设置为模块,空格键翻转,回车键进入下一级设置,Tab键在项目间跳转,左右光标键选择按钮。
作为一个基础的配置,你也可以不更改任何内容,直接选择“Exit”按钮退出配置程序。在退出时会询问你是否把配置保存成“.config”文件,直接选“yes”即可。
配置完成后,执行内核编译命令,先执行“make clean”命令清理一下内核,然后输入“make zImage”并回车(也可用多线程模式)开始编译工作。编译的时间较长,一般需要二十分钟左右,如果中途没有出错的话,则编译完成后会在源码的“arch/arm/boot”目录下生成一个zImage映像文件。假如在这步就出错的话,那么很不幸,不仅得不到zImage文件,你还得根据出错的提示去解决问题。在编译内核时出错是件非常令人心烦的事情,不仅因为编译一次需要的时间较长,更麻烦的是出错的情况五花八门,特别对于初学者来说,你可能都不知道怎么去改。所以内核移植不当是技术活,更多的时候是取决于经验。
回到正题,如果编译内核出错了,由于我们使用的是默认配置,且什么文件都还没改,所以出错的问题不会太大,无非有下面几种可能:1.内核没有“.config”配置文件;2.没有在内核源码根目录(即源码的最顶层目录)下执行编译;3.没有Makefile文件提供编译规则;4.没有指定交叉编译工具;5.交叉编译工具链的版本与内核版本不匹配;6.交叉编译工具链配置不正确。只要细心对照以上几条进行检查,总是可以排除问题,编译成功的。
内核编译好后,把zImage文件下载到开发板上(推荐使用NFS方式下载到地址为32000000的地方),然后启动内核(在Bootloader下执行bootm命令),正常来说应该可以启动Linux系统了,但最终会停止在如下的界面上。

技术图片

这是因为内核还没有集成NandFlash的驱动,没有具体的分区以及没有文件系统读写支持所至,所以进入不了命令行(console端口)是正常的,但至少内核在S3C2416芯片上启动起来了,这也是值得高兴的。解决驱动、分区及文件系统支持的事我们后面再详细讨论,这里先来看一下,假如内核并没有在开发板上跑起来,而是停在了如下图所示的地方,是什么原因又如何解决呢?

技术图片

这个问题有可能会很常见,虽然产生的具体原因可能很多,但从现象上来看,应该是和Bootloader与内核之间传递的信息不正确有关。所以,解决此问题应从两方面来考虑,一是内核配置的问题,但我们仅使用了默认配置,应该与此无关;二是Bootloader传递过来的参数与内核某些参数不匹配。
现在重点来看第二种情况。在Bootloader加载内核之前,会给内核传递一些参数,以通知内核从哪里启动,如何启动等等信息。在传递的参数中,有一项叫做“MACH_TYPE”,它用于确定要启动哪类目标平台,如果该值与内核的不匹配,就会造成内核不能启动。这种情况要修改内核文件“arch/arm/mach-s3c2416/mach-smdk2416.c”,打开该文件,找到MACHINE_START(SMDK2416, "SMDK2416")函数,该函数其中的第一个参数SMDK2416即为“MACH_TYPE”,它要与Bootloader中的一致,该名称在U-boot中的定义位于U-boot源码文件“include/asm-arm/mach-types.h”中。由于硕数公司的S3C2416核心板上的U-boot中所传递过来的名称即为SMDK2416,所以此处不用更改就能启动。另外,刚才讨论的MACHINE_START(SMDK2416, "SMDK2416")中,第二个参数用于对内核的描述,一般厂商会把这些字符串换成自己的品牌名称,比如MINI2440的开发板就换成了“FriendlyARM Mini2440 development board”。这些信息在内核启动完成后,可通过执行命令“cat /proc/cpuinfo”来查看。
此外还有一种情况是内核可以启动,但显示乱码,这种现象也较为见。从现象分析,串口终端显示乱码,肯定与波特率设置不当有关。如果Bootloader显示正常,内核启动时显示乱码,则是内核的晶振时钟设置不对,同样打开上述“mach-smdk2416.c”文件,找到static void __init smdk2416_map_io(void)函数,并找到其中的s3c24xx_init_clocks(12000000);一句,把晶振频率改了与你的开发板一致,默认为12000000(即12MHz)。完成后重新编译内核,再下载到开发板就能正常显示启动过程了。硕数公司的S3C2416核心板的晶振就是12MHz,所以此处不用修改。

以上是关于内核编译与移植的主要内容,如果未能解决你的问题,请参考以下文章

Linux系统移植:内核获取和编译

Linux系统移植:内核获取和编译

内核编译与移植

linux内核移植编译时遇到的问题

问题排查低版本内核驱动移植到高版本内核中编译报错,部分编译异常记录及解决

问题排查低版本内核驱动移植到高版本内核中编译报错,部分编译异常记录及解决