内核编译与移植

fxzq fxzq     2023-04-20     460

关键词:

在嵌入式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内核在S3C2416上的移植。首先,Linux是开源软件,其内核源代码可以直接到网站https://www.kernel.org/上下载。但Linux内核的版本非常之... 查看详情

《基于armcortex-a9的嵌入式linux内核移植研究与实现》

[1]罗名驹.基于ARMCortex-A9的嵌入式Linux内核移植研究与实现[D].广东工业大学,2017.文章目录​​移植环境搭建​​​​设备树​​​​uboot​​​​内核移植​​​​根文件系统构建​​移植环境搭建1.ubuntu安装嵌入式开发通常是在... 查看详情

内核编译与移植

...是SMSC公司的网卡芯片,型号为LAN9220。此芯片在Linux-3.0.99内核中可以支持,因此修改进来就方便多了。先修改文件arch/arm/mach-s3c2416/mach-smdk2416.c,用vi打开它,先在包含头文件部分加入一句“#include<linux/smsc911x.h>”,把SMS... 查看详情

linux内核移植入门(代码片段)

文章目录基本概念内核源码目录结构内核配置主目录Makefile各子目录Makefile如何配置内核?1.配置仓库选取2.交叉编译器的修改3.体系结构体的选择4.修改配置文件内核编译编译结果:几种linux内核文件的区别开发板上U-Boot启动linux内核... 查看详情

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

摘要:将klsp移植到高版本内核中编译时,有可能会遇到一些编译报错。原因一部分是因为新版本的内核加入了更多的代码检测,或者是打开了更多的代码检测选项,将以前的warning视为了error,还有可能是因为... 查看详情

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

摘要:将klsp移植到高版本内核中编译时,有可能会遇到一些编译报错。原因一部分是因为新版本的内核加入了更多的代码检测,或者是打开了更多的代码检测选项,将以前的warning视为了error,还有可能是因为... 查看详情

关于linux内核(3.0.8)编译移植中出现的问题总结

在编译linux内核3.0.8当中出现的问题  交叉编译器版本4.4.61.Infileincludedfromdrivers/usb/host/ehci-hcd.c:124:drivers/usb/host/ehci.h:747:warning:functiondeclarationisn‘taprototypedrivers/usb/host/ehci-hcd.c:1290 查看详情

rk3399系统移植|移植linux原生5.4.32内核

更新时间更新内容2022-10-26初稿文章目录一、linux原生内核初试1.下载2.编译3.生成boot.img镜像3.启动测试二、移植到friendlyRK3399-SOM开发板1.新建单板2.新建设备树:3.编译4.测试三、rootfs挂载问题1.问题描述2.问题分析3.问题解决源码一... 查看详情

rk3399系统移植|移植linux主线5.4.32内核

更新时间更新内容2022-10-26初稿文章目录一、linux原生内核初试1.下载2.编译3.生成boot.img镜像3.启动测试二、移植到friendlyRK3399-SOM开发板1.新建单板2.新建设备树:3.编译4.测试三、rootfs挂载问题1.问题描述2.问题分析3.问题解决源码一... 查看详情

移植qt与tslib到x210开发板的体会

...如解压到了/root/xin_210/下@3:选择固定的交叉编译工具连,内核,tslib,QT源码都要用这一个编译,我用的是arm-2009q3.这个工具链中的arm-none-linux-gnueabi/libc 查看详情

linux系统移植:原厂kernel移植到开发板(代码片段)

...Linux系统移植:原厂Kernel移植到开发板一、获取原厂内核并编译二、内核启动测试三、添加自己板子文件3.1板子配置文件3.2板子设备树3.3编译四、重要配置修改4.1主频修改4.2EMMC驱动修改4.3网络驱动修改4.4保存修改后配置文件... 查看详情

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

/bin/sh:arm-linux-gcc:commandnotfoundmake[1]:***[kernel/bounds.s]Error127make:***[prepare0]Error2请问这是哪里出错了?错误原因是没有交叉编译器arm-linux-gcc。这个交叉编译器是基于gcc的,一般选用4.1版本的gcc,这个版本对于语法要求不是那么高,编... 查看详情

jz2440上内核和文件系统移植

...因为韦东山教程提供的工具链比较旧不能编译较新的linux内核,也可以自己使用crosstool-ng构建。ARM-LinuxGCC4.4.3(htt 查看详情

linux内核移植初探(代码片段)

内核移植的梯度:初级:根据芯片公司的参考配置,编译开发板内核并了解执行过程中极:添加内核驱动的方式方法高级:修改或添加BSP包linux内核特性:可移植性强、支持的硬件平台广泛;超强的网络功能;多任务多用户系统... 查看详情

内核的配置和移植

1.解压内核将linux-3.14.tar.xz拷贝到/home/linux下并解压2.修改Makefile修改Makefile中平台和交叉工具编译器将:ARCH?=$(SUBARCH)CROSS_COMPILE?=$(CONFIG_CROSS_COMPILE:"%"=%) 改为ARCH?=armCROSS_COMPILE?=arm-none-linux-gnueabi- 3. 查看详情

安卓rom移植到底是啥意思?

...成4.0的?,,,给你说明白点吧~~rom,,组成部分有,,内核,驱动,ui,,所谓的rom移植,,主要指的是移植内核与ui,,驱动移植了也没法用~~所以,,这里的rom移植主要指的是移植内核与ui,,但是,,由于移植要做的修改... 查看详情

第三方驱动移植——黑盒移植(代码片段)

...植的主要流程如下: 一、黑盒移植1、将驱动编译进内核  如果内核中已经有了已经支持的驱动,那直接在menu上选配即可。若没有,则需要第三方的驱动或者自己写一个驱动,移植进内核。  1)将第三方驱动放到linux源... 查看详情

linux系统移植的目录

参考技术A第1篇系统移植基础篇第1章linux内核介绍21.1系统调用接口21.1.1linux系统调用21.1.2用户编程接口21.1.3系统调用与服务例程的对应关系31.1.4系统调用过程31.1.5系统调用传递的参数41.2进程管理41.2.1进程41.2.2进程描述符51.2.3进程... 查看详情