当前位置: 主页 > Linux安装教程 > 系统设置 >

【连载】Linux内核开发工具介绍(续二)

时间:2018-10-12 07:06来源:网络整理 作者:Linux先生 举报 点击:
Linux内核开发过程中,只有对内核进行正确配置后,才能进行编译。配置不当的内核,很有可能编译出错,或者不能正确运行。下面我们具体介绍一下如何正确进行内核

Linux内核开发过程中,只有对内核进行正确配置后,才能进行编译。配置不当的内核,很有可能编译出错,或者不能正确运行。下面我们具体介绍一下如何正确进行内核配置。

一、快速配置内核

进入Linux内核源码数顶层目录,输入make menuconfig命令,可进入如图1所示的基于Ncurses的Linux内核配置主界面(注意:主机须安装ncurses相关库才能正确运行该命令并出现配置界面)。如果没有在Makefile中指定ARCH,则须在命令行中指定:

$ make ARCH=arm menuconfig

【连载】Linux内核开发工具介绍(续二)

图1 基于Ncurses的Linux内核配置主界面

基于Ncurses的Linux内核配置界面不支持鼠标操作,必须用键盘操作。基本操作方法:

通过键盘的方向键移动光标,选中的子菜单或者菜单项高亮;

按TAB键实现光标在菜单区和功能区切换;

子菜单或者选项高亮,将光标移功能区选中<Select>回车:

如果是子菜单,按回车进入子菜单;

如果是菜单选项,按空格可以改变选项的值:

对于bool型选项,[*]表示选中,[ ]表示未选中;

对于tristate型选项,<*>表示静态编译,<M>表示编译为模块,<>表示未选中。

对于int、hex和string类型选项,按回车进入编辑菜单。

连按两次ESC或者选中<Exit>回车,将退回到上一级菜单;

按斜线(/)可启用搜索功能,填入关键字后可搜索全部菜单内容。

配置完毕,将光标移动到配置界面末尾,选中“Save an Alternate Configuration File”后回车,保存当前内核配置,默认配置文件名为.config,如图2所示。

【连载】Linux内核开发工具介绍(续二)

图2 保存内核配置为.config文件

保存完毕,选择<ESC>退出内核配置界面,回到终端命令行。

当然,也可以将配置文件命名为其它文件名,如config-bak等,但该配置不会被Makefile文件使用,Makefile默认使用文件名为.config的配置文件,所以重新命名配置文件通常在保留或者备份内核配置信息时使用。

也可以不用“Save an Alternate Configuration File”操作,连按ESC或选择<Exit>退出内核配置界面,将会出现如图3所示的保存配置提示信息,选择<Yes>后回车,内核配置将会被保存为.config文件。

【连载】Linux内核开发工具介绍(续二)

图3 保存内核配置提示信息

备份内核配置,在命令行下将.config文件复制为其它文件名来得更简单快捷:

$ cp .config config-bak

装载某个配置文件,可在配置界面选中“Load an Alternate Configuration File”,然后填入已存在的配置文件名称。也可在命令行下将配置文件复制为.config:

$ cp config-bak.config

在<arch/arm/configs/>目录下有很多*_defconfig文件,这些都是内核的预设配置文件,分别对应各种不同的参考板。如果要使用其中的配置文件作为内核编译配置,可用“make xxx_defconfig”命令来完成。对于已经设定好的内核配置,也可以命名为某个文件名,放到<arch/arm/configs/>目录下,在以后直接用make来调用该配置即可。例如将当前配置命名为m3352_defconfig并放到<arch/arm/configs/>目录下,后续只需执行下列命令即可使用当前配置:

$ make m3352_defconfig或者

$ make ARCH=arm CROSS_COMPILE=

arm-linux-gnueabihf-m3352_defconfig

二、内核配置详情

Linux内核配置菜单比较复杂,下面对一些比较重要的配置界面进行介绍,更多的详细配置,建议进行实际操作。另外,由于Linux内核版本差异,实际看到的内核配置界面可能与本节的介绍有所差异。

图1所示的内核配置主界面,实际包含了如表1所列的各项一级菜单。

表1 内核配置界面一级菜单

【连载】Linux内核开发工具介绍(续二)

【连载】Linux内核开发工具介绍(续二)

【连载】Linux内核开发工具介绍(续二)

一级菜单下的每一项几乎都有复杂的下级子菜单,各自的配置选项也很丰富,每项的意义也各不相同,如果逐一进行描述,将会是一件非常繁琐的事。而实际产品开发中,并不需要完全了解内核的每一个配置项,通常只需要了解其中一些相关项即可。

1、通用设置

进入General setup是内核通用设置菜单界面,菜单选项众多,通常可以关注表2所列选项。

表2 通用设置常见选项

【连载】Linux内核开发工具介绍(续二)

2、内核特性

Kernel Features是内核特性配置菜单,常用选项介绍如表3所列。

表3 内核特性常用选项说明

【连载】Linux内核开发工具介绍(续二)

3、启动选项

启动选项一般关心内核启动参数设置即可,可设置默认启动参数和内核参数类型。

默认启动参数通过“Default kernel command string”设置,例如:

(root=http://mt.sohu.com/dev/mmcblk0p2 rootwait console

=ttyO0,115200) Default kernel command string

内核参数类型通过Kernel command line type来设置,可选值:

( ) Use bootloader kernel arguments if available

( ) Extend bootloader kernel arguments

( ) Always use the default kernel command string

如果设置为“Always use the default kernel command string”则只能使用默认内核启动参数,通常会设置为“Use bootloader kernel arguments if available”,可接受Bootloader传递的参数启动。

4、网络支持

网络支持部分,包括了以太网、CAN、红外、蓝牙、无线等各种网络的支持配置选项。

网络选项配置。从Networking support Networking options,可进入网络选项配置界面,网络的配置很复杂,常用的一些配置选项和说明如表4所列。

表4 网络选项常用配置说明

【连载】Linux内核开发工具介绍(续二)

通常来说,使用Linux的系统都会用到网络,而使用网络又往往离不开TCP/TP,故建议在配置中选中TCP/IP选项,并选中下级全部选项,配置后的TCP/IP选项如程序清单1所示。

程序清单1 TCP/IP配置

[*] TCP/IP networking

[*] IP: multicasting

[*] IP: advanced router

[*] FIB TRIE statistics

[*] IP: policy routing

[*] IP: equal cost multipath

[*] IP: verbose route monitoring

[*] IP: kernel level autoconfiguration

[*] IP: DHCP support

[*] IP: BOOTP support

[*] IP: RARP support

<*> IP: tunneling

<*> IP: GRE demultiplexer

<*> IP: GRE tunnels over IP

[*] IP: broadcast GRE over IP

[*] IP: multicast routing

[*] IP: multicast policy routing

[*] IP: PIM-SM version 1 support

[*] IP: PIM-SM version 2 support

[*] IP: ARP daemon support

[*] IP: TCP syncookie support

<*> IP: AH transformation

<*> IP: ESP transformation

<*> IP: IPComp transformation

<*> IP: IPsec transport mode

<*> IP: IPsec tunnel mode

<*> IP: IPsec BEET mode

<*> Large Receive Offload (ipv4/tcp)

<*> INET: socket monitoring interface

[*] TCP: advanced congestion control --->

[*] TCP: MD5 Signature Option support (RFC2385) (EXPERIMENTAL)

<M> The IPv6 protocol --->

这些配置中,三态选项也可以配置为<M>,在需要的时候再插入模块。

对于IPv6,现在已经有不少应用需求,建议配置为<M>,并选中配置菜单中的全部选项,在需要的时候再插入模块。

特别说明一下CAN的配置选项。CAN-Bus相关协议支持以及CAN设备驱动配置项都在这里,并没有将CAN设备驱动放在drivers配置菜单中。CAN-Bus子系统配置界面如图4所示。

【连载】Linux内核开发工具介绍(续二)

图4 CAN-Bus子系统配置界面

其中的“CAN Device Drivers”子菜单下可选择具体的CAN设备,如图5所示。具体选择哪个CAN设备驱动,与具体的硬件平台相关。

【连载】Linux内核开发工具介绍(续二)

图5 CAN设备驱动配置界面

5、设备驱动

Linux内核支持众多外设,设备驱动程序很多,配置界面也很复杂,有众多配置项,如表5所列。

表5 设备驱动配置项

【连载】Linux内核开发工具介绍(续二)

【连载】Linux内核开发工具介绍(续二)

【连载】Linux内核开发工具介绍(续二)

【连载】Linux内核开发工具介绍(续二)

【连载】Linux内核开发工具介绍(续二)

【连载】Linux内核开发工具介绍(续二)

6、文件系统

进入File systems,是内核文件系统配置界面,可以看到很多文件系系统配置选项,如图6所示。

【连载】Linux内核开发工具介绍(续二)

图6 文件系统配置界面

一个完整的嵌入式LInux系统往往会支持多种文件系统,但绝非“File systems”菜单下的全部。这里仅对当前主流系统比较常用的一些文件系统配置项进行介绍,如表6所列。

表6 文件系统配置常用选项和说明

【连载】Linux内核开发工具介绍(续二)

【连载】Linux内核开发工具介绍(续二)

【连载】Linux内核开发工具介绍(续二)

三、编译内核

内核配置完成,输入make命令即可开始编译内核。如果没有修改Makefile文件并指定ARCH和CROSS_COMPILE参数,则须在命令行中指定:

$ make ARCH

=arm CROSS_COMPILE

=arm-none-linux-gnueabi-

目前大多数主机都是多核处理器,为了加快编译进度,可以开启多线程编译,在make的时候加上“-jN”即可,N的值为处理器核心数目的2倍。例如对于I7 4核处理器,可将N设置为8:

$ make ARCH

=arm CROSS_COMPILE

=arm-none-linux-gnueabi--j8

采用多线程编译的优点是能加快编译进度,缺点是如果内核中有错误,某个编译线程遇到错误终止了编译,而其它编译线程却还在继续,出错线程的错误提示通常会被其它编译线程的输出信息淹没,不利于排查。对于这种情况,则建议改为单线程编译,直到错误排除。

如果编译不出错,编译完成,会生成vmlinux、Image、zImage等文件,各文件说明如表7所列。

表7 内核编译生成文件说明

【连载】Linux内核开发工具介绍(续二)

1、zImage

zImage是通常情况下默认的压缩内核,可以直接加载到内存地址并开始执行。它从<arch/arm/boot/compressed/vmlinux>文件经过objcopy处理得到。在ARM Linux下最终生成zImage的各个参数记录在<arch/arm/boot/.zImage.cmd>文件中。AM3352内核生成zImage的实际参数为:

cmd_arch/arm/boot/zImage :=

/home/ctools/i686-arago-linux/usr/bin/arm-linux-gnueabihf-objcopy-O binary -R .comment -S

arch/arm/boot/compressed/vmlinux arch/arm/boot/zImage

说明1:路径信息与实际具体编译环境有关。

说明2:如果在64位ubuntu下编译Linux内核,在编译过程中很有可能出现“arm-fsl-linux-gnueabi/bin/as: error while loading shared libraries: libz.so.1: cannot open shared object file: No such file or directory”这样的错误,这是因为没有正确安装libz库所致,可“sudo apt-get install zlib1g:i386”命令安装解决。

2、uImage

对于ARM Linux系统,大多数采用U-Boot引导,很少直接使用zImage映像,实际上更多的是uImage。uImage是U-Boot默认采用的内核映像文件,它是在zImage内核映像之前加上了一个长度为64字节信息头的映像。这64字节信息头包括映像文件的类型、加载位置、生成时间、大小等信息(可参考U-Boot源码<include/image.h>文件的image_header_t数据结构定义)。进入<arch/arm/boot/>目录,用ls命令查看,uImage文件大小比zImage大64字节:

$ cd arch/arm/boot

$ ls -la Image zImage uImage

-rwxrwxr-x 1 chenxibing chenxibing 6460852 Jul 25 09:24 Image

-rw-rw-r-- 1 chenxibing chenxibing 3135544 Jul 25 09:24 uImage

-rwxrwxr-x 1 chenxibing chenxibing 3135480 Jul 25 09:24 zImage

在U-Boot下,通过bootm命令可以引导uImage映像文件启动。

3、mkimage工具

从zImage生成uImage需要用到mkimage工具。该工具可在编译U-Boot源码后从tools目录下获得,复制到系统/usr/bin目录即可;对于Ubuntu系统,还可用sudo apt-get install u-boot-tools命令安装得到。进入mkimage文件所在目录执行该文件,或者在安装mkimage工具后,直接在终端输入mkimage命令,可以得到mkimage工具的用法:

$ ./mkimage或者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

./mkimage -V ==> print version information and exit

使用mkimage工具根据zImage制作uImage映像文件的命令如下:

$ mkimage [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image

命令参数中需要指定体系结构、操作系统类型、压缩方式和入口地址等信息,各参数说明如表8所列。

表8 mkimage参数说明

【连载】Linux内核开发工具介绍(续二)

【连载】Linux内核开发工具介绍(续二)

对于EPC-28x处理器,内存起始地址为0x40000000,从zImage生成uImage映像文件的命令实际操作范例:

$ mkimage -A arm -O linux -T kernel -C none -a 0x40008000 -e 0x40008000 -n 'Linux-2.6.35' -d arch/arm/boot/zImage arch/arm/boot/uImage

说明:内存地址与处理器相关,在不同处理器上可能有差异。

mkimage除了可以制作uImage映像文件之外,还可以查看一个uImage映像文件的文件头信息,用法:

$ mkimage -l uImage_file

例如,用mkimage工具查看EPC-28x工控主板的uImage内核映像,可以得到如下信息:

$ mkimage -l uImage

Image Name:

Linux-2.6.35.3-571-gcca29a0-g191

Created:

Tue Nov 17 11:57:47 2015

Image Type:

ARM Linux Kernel Image (uncompressed)

Data Size:

2572336 Bytes = 2512.05 kB = 2.45 MB

Load Address: 40008000

Entry Point: 40008000

如果只有zImage内核映像文件,需要转换成uImage映像文件,则只能通过上述命令来实现。但是如果有内核源码,那生成uImage的方法就简单很多。实际上,Linux内核已经支持直接生成uImage格式映像文件,在<arch/arm/boot/Makefile>文件中给出了uImage的生成规则:

quiet_cmd_uimage = UIMAGE $@

cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE)

-A arm -O linux -T kernel

-C none -a $(LOADADDR) -e $(STARTADDR)

-n 'Linux-$(KERNELRELEASE)' -d $< $@

生成uImage的编译命令为make uImage:

$ make ARCH=arm CROSS_COMPILE

=arm-none-linux-gnueabi--j8uImage

在ARM Linux下最终生成uImage的各个参数记录在<arch/arm/boot/.uImage.cmd>文件中。对于在EPC-28x的Linux内核,实际参数为:

cmd_arch/arm/boot/uImage :=

/bin/bash /home/vmuser/prj/m28x/kernel/linux-2.6.35.3/s/mkuboot.sh -A arm -O linux -T kernel -C none -a 0x40008000 -e 0x40008000 -n 'Linux-2.6.35.3-571-gcca29a0-g1914ba0' -d

arch/arm/boot/zImage arch/arm/boot/uImage

说明:路径信息与实际具体编译环境有关。

4、编译内核模块

如果内核中有配置为<M>的模块或者驱动,需要在编译内核后再通过make modules命令编译这些模块或者驱动:

$ make ARCH=arm CROSS_COMPILE

=arm-none-linux-gnueabi-modules

编译得到的内核模块文件以“.ko”结尾,这些可以通过insmod命令插入到运行的内核中。

有的模块编译得到单一的“.ko”文件,且不依赖于其它模块,这样的模块可以直接用insmod命令插入系统而不会出现错误。

有的模块则可能编译后得到多个“.ko”文件,或者依赖于其它模块文件,且各文件插入还有顺序要求,这就是常说的模块依赖。对于这样的情况,用insmod命令手工尝试得到依赖关系,然后按顺序插入也是可以的,但不推荐这样做,毕竟很麻烦。

建议编译模块后,再通过make modules_install命令安装模块,可将编译得到的全部模块安装到某一目录下,并且还会生成模块的依赖关系文件。默认情况下会将内核模块安装到编译机器的“/”目录下,这一方面需要root权限,另一方面容易与主机文件混淆。建议通过INSTALL_MOD_PATH参数指定模块安装路径:

$ make ARCH=arm CROSS_COMPILE=

arm-none-linux-gnueabi

-INSTALL_MOD_PATH=

/home/chenxibing/work/rootfsmodules_install

安装后将在安装目录下生成“lib/modules/内核版本/”目录,该目录下通常有下列文件和目录:

build modules.alias modules.builtin modules.dep modules.devname

modules.softdep modules.symbols.binkernel/

modules.alias.bin modules.builtin.bin modules.dep.bin modules.order modules.symbols source

所有的内核模块都在kernel目录下,modules.dep是全部模块的依赖关系文件。将“lib/modules/内核版本/”复制到目标系统后根目录后,就可以用modprobe命令进行模块安装,而不用手工逐一加载各个模块。该文件内容多少与内核模块多少相关,现在摘取一个实例片段进行说明:

kernel/drivers/net/bonding/bonding.ko:(1)

kernel/drivers/usb/serial/usbserial.ko:(2)

kernel/drivers/usb/serial/ftdi_sio.ko: kernel/drivers/usb/serial/usbserial.ko(3)

每行开头至冒号(:)之前的表示一个内核模块,冒号之后的表示该模块所依赖的其它模块,必须先加载后面的模块才能加载该模块文件。冒号后面为空则表示该模块没有依赖关系。

第(1)行表示模块文件bonding.ko没有依赖关系,可以直接用insmod命令加载到内核中:

# insmod kernel/drivers/net/bonding/bonding.ko

用insmod加载模块,必须指明文件路径,否则不能加载。用modprobe命令加载则无需带路径:

# modprobe bonding

第(2)和(3)则共同说明了模块文件ftdi_sio.ko依赖于usbserial.ko文件,usbserial.ko没有依赖文件。用insmod命令用法如下:

# indmod kernel/drivers/usb/serial/usbserial.ko

# insmod kernel/drivers/usb/serial/ftdi_sio.ko

用modprobe命令就简单了:

# modprobe ftdi_sio

四、运行内核

得到uImage映像文件后,将uImage加载到内存地址ep-0x40处,通过bootm命令即可运行内核:

# tftp 40007fc0 uImage

# bootm 40007fc0

uImage启动会打印文件头信息并进行校验和计算,校验通过后开始内核自解压并运行:

## Booting kernel from Legacy Image at 40007fc0 ...

Image Name: Linux-2.6.35.3-571-gcca29a0-gd43

Image Type: ARM Linux Kernel Image (uncompressed)

Data Size: 2653928 Bytes = 2.5 MB

Load Address: 40008000

Entry Point: 40008000

Verifying Checksum ... OK

Loading Kernel Image ... OK

OK

Starting kernel ...

Uncompressing Linux... done, booting the kernel.

……

以下省略

后台回复关键字【Linux】,可查看嵌入式Linux开发教程。

【连载】Linux内核开发工具介绍(续二)

如果想和教程一起实践学习,可以使用致远电子IoT-3960L工控板。

------分隔线----------------------------
推荐内容