Linux内核移植入门

Posted cswhl

tags:

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

基本概念

linux内核特性:

1.可移植性,支持的硬件平台广泛
2.超强的网络功能
3.多任务多用户系统
4.模块化的设计

五大子系统:

1.进程管理子系统
2.内存管理子系统
3.文件系统子系统
4.网络协议子系统
5.设备管理子系统

获取linux内核:

1.内核官方发布点
2.芯片厂商提供

内核源码目录结构

内核配置

  1. Makefile 和 make

由主目录 Makefile 和 子目录 Makefile 共同指定内核的编译规则

2.通过 make menuconfig 及 Kconfig 修改内核的配置单,从而自动完成内核配置

选择哪些文件被编译进内核

主目录Makefile

Makefile文件位置: linux-3.0.8/Makefile

以下为Makefile文件中的部分代码,根据arch平台,配置包含子目录的头文件目录和子目录的Makefile

根据SUBARCH配置 SRCARCH,SUBARCH默认 X86

export KBUILD_BUILDHOST := $(SUBARCH)
ARCH            ?= $(SUBARCH)
CROSS_COMPILE   ?= $(CONFIG_CROSS_COMPILE:"%"=%) // 交叉编译器设置

# Architecture as present in compile.h
UTS_MACHINE     := $(ARCH)
SRCARCH         := $(ARCH)

# Additional ARCH settings for x86
ifeq ($(ARCH),i386)
        SRCARCH := x86
endif
ifeq ($(ARCH),x86_64)
        SRCARCH := x86
endif

包含子目录的头文件目录 arch/arm/include:

-I$(srctree)/arch/$(hdr-arch)/include 

包含子目录 arch/arm/Makefile 文件:

include $(srctree)/arch/$(SRCARCH)/Makefile

SRCARCH = arm
hdr-arch arm

各子目录Makefile

obj-y : 编译进内核
obj- : 不编译进去
obj-m : 以模块形式编译

如何配置内核?

1. 配置仓库选取

1、SUBARCH 默认就是X86的,内容默认配置安装X86
ARCH 这个变量改为 arm 单词

交叉编译 CROSS_COMPILE:在一种计算机环境中运行的编译程序,能编译出在另外一种环境下运行的代码

2、哪些文件会被编译?

这些文件是否被编译是由子目录中的Makfile文件中 CONFIG_xxx 变量是否被定义而决定(obj-y编译进内核,obj-m以模块形式编译)

主Makefile是如何将这些文件引入到我们的整个环境变量中?通过配置单 中定义的 CONFIG_xxx

3、配置单: 由芯片商提供BSP时会提供参考配置单,能够大大简化我们的配置过程

cs@cspc:/mnt/d/linux/linux-3.0.8/arch/arm$ ls # arm架构下的子目录
Kconfig        common   mach-at91      mach-dove        mach-gemini      mach-iop32x   mach-kirkwood  mach-mmp      mach-netx     mach-orion5x   mach-s3c2400  mach-s3c2443  mach-s5pv210   mach-spear6xx  mach-versatile  nwfpe         plat-omap     plat-samsung    vfp
Kconfig-nommu  configs  mach-bcmring   mach-ebsa110     mach-h720x       mach-iop33x   mach-ks8695    mach-msm      mach-nomadik  mach-pnx4008   mach-s3c2410  mach-s3c24a0  mach-sa1100    mach-tcc8k     mach-vexpress   oprofile      plat-orion    plat-spear
Kconfig.debug  include  mach-clps711x  mach-ep93xx      mach-imx        mach-ixp2000 mach-l7200     mach-mv78xx0  mach-nuc93x   mach-pxa       mach-s3c2412  mach-s3c64xx  mach-shark     mach-tegra     mach-vt8500     plat-iop      plat-pxa      plat-tcc
Makefile       kernel   mach-cns3xxx   mach-exynos4     mach-integrator  mach-ixp23xx  mach-loki      mach-mx5      mach-omap1    mach-realview  mach-s3c2416  mach-s5p64x0  mach-shmobile  mach-u300      mach-w90x900    plat-mxc      plat-s3c24xx  plat-versatile
boot           lib      mach-davinci   mach-footbridge  mach-iop13xx     mach-ixp4xx   mach-lpc32xx   mach-mxs      mach-omap2    mach-rpc       mach-s3c2440  mach-s5pc100  mach-spear3xx  mach-ux500     mm              plat-nomadik  plat-s5p      tools
cs@cspc:/mnt/d/linux/linux-3.0.8/arch/arm$ cd configs/
cs@cspc:/mnt/d/linux/linux-3.0.8/arch/arm/configs$ ls  # 配置单所在目录 configs
acs5k_defconfig        at91sam9260ek_defconfig  cerfcube_defconfig        cpu9g20_defconfig      exynos4_defconfig     h7202_defconfig       ixp4xx_defconfig      magician_defconfig   mx3_defconfig        nuc960_defconfig        pxa168_defconfig        s3c2410_defconfig     spear3xx_defconfig    usb-a9260_defconfig
acs5k_tiny_defconfig   at91sam9261_defconfig    cm_x2xx_defconfig         da8xx_omapl_defconfig  ezx_defconfig         hackkit_defconfig     jornada720_defconfig  mainstone_defconfig  mx51_defconfig       omap1_defconfig         pxa255-idp_defconfig    s3c6400_defconfig     spear6xx_defconfig    versatile_defconfig
afeb9260_defconfig     at91sam9263_defconfig    cm_x300_defconfig         davinci_all_defconfig  footbridge_defconfig  imote2_defconfig      kirkwood_defconfig    mini2440_defconfig   mxs_defconfig        omap2plus_defconfig     pxa3xx_defconfig        s5p64x0_defconfig     spitz_defconfig       vexpress_defconfig
ag5evm_defconfig       at91sam9g20ek_defconfig  cns3420vb_defconfig       dove_defconfig         fortunet_defconfig    integrator_defconfig  ks8695_defconfig      mmp2_defconfig       neponset_defconfig   orion5x_defconfig       pxa910_defconfig        s5pc100_defconfig     stamp9g20_defconfig   viper_defconfig
am200epdkit_defconfig  at91sam9rlek_defconfig   colibri_pxa270_defconfig  ebsa110_defconfig      g3evm_defconfig       iop13xx_defconfig     lart_defconfig        msm_defconfig        netwinder_defconfig  palmz72_defconfig       qil-a9260_defconfig     s5pv210_defconfig     tct_hammer_defconfig  xcep_defconfig
ap4evb_defconfig       at91x40_defconfig        colibri_pxa300_defconfig  edb7211_defconfig      g4evm_defconfig       iop32x_defconfig      loki_defconfig        mv78xx0_defconfig    netx_defconfig       pcm027_defconfig        raumfeld_defconfig      sam9_l9260_defconfig  tegra_defconfig       zeus_defconfig
assabet_defconfig      badge4_defconfig         collie_defconfig          em_x270_defconfig      h3600_defconfig       iop33x_defconfig      lpd270_defconfig      mx1_defconfig        nhk8815_defconfig    pcontrol_g20_defconfig  realview-smp_defconfig  shannon_defconfig     trizeps4_defconfig
at91cap9adk_defconfig  bcmring_defconfig        corgi_defconfig           ep93xx_defconfig       h5000_defconfig       ixp2000_defconfig     lubbock_defconfig     mx21_defconfig       nuc910_defconfig     pleb_defconfig          realview_defconfig      shark_defconfig       u300_defconfig
at91rm9200_defconfig   cam60_defconfig          cpu9260_defconfig         eseries_pxa_defconfig  h7201_defconfig       ixp23xx_defconfig     mackerel_defconfig    mx27_defconfig       nuc950_defconfig     pnx4008_defconfig       rpc_defconfig           simpad_defconfig      u8500_defconfig

配置单文件的后缀 “_defconfig” 表示默认配置,且每个配置单对应 arm 架构下的目录,如 “ixp2000_defconfig” 对应
“mach-ixp2000”

配置单内容如下(为y则代表其对应的文件会被编译进内核):

cs@cspc:/mnt/d/linux/linux-3.0.8/arch/arm/configs$ cat s5pv210_defconfig
CONFIG_EXPERIMENTAL=y
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_KALLSYMS_ALL=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
...

我们将将配置单导出到内核的主目录下 .config

4、修改defconfig 配置单变成适应于板子的文件

2.交叉编译器的修改

回到内核的主目录,修改Makefile

修改以下两行:

ARCH            ?= $(SUBARCH)  # 设置架构体系, 如直接设 arm;也可以在make中修改
CROSS_COMPILE   ?= $(CONFIG_CROSS_COMPILE:"%"=%)  # 设置交叉编译器

修改后的结果如:

ARCH            ?= arm   
CROSS_COMPILE   ?= /opt/FriendlyARM/toolschain/4.5.1/bin/arm-linux-
3.体系结构体的选择

将要移植的平台的参考配置单文件拷贝到主目录下:

cs@cspc:/mnt/d/linux/linux-3.0.8$ cp arch/arm/configs/s5pv210_defconfig .config
cs@cspc:/mnt/d/linux/linux-3.0.8$ ls -a
.  ..  .config  .gitignore  .mailmap  COPYING  CREDITS  Documentation  Kbuild  Kconfig  MAINTAINERS  Makefile  README  REPORTING-BUGS  arch  block  crypto  drivers  firmware  fs  include  init  ipc  kernel  lib  mm  net  samples  scripts  security  sound  tools  usr  virt
4.修改配置文件

可以使用 make menuconfig 以桌面窗口形式对.config 文件进行修改, 这比以文本方式修改.config更方便

关系: make menuconfig —解析Kconfig后修改—> .config —作用于—> Makefile
而且 make menuconfig中出现大量字符串,其来自解析的 Kconfig 文件

内核编译

  1. 将芯片厂商提供的配置单文件名更改为 .config
  2. 查看 Makefile中的交叉编译器是否设置正确
  3. make menuconfig 设置 .config

4.make编译文件
内核编译(make)之后会生成两个文件,一个Image,一个zImage,

其中Image为内核映像文件,而zImage为内核的一种映像压缩文件,Image大约为4M,而zImage不到2M

uImage又是什么的?

它是uboot专用的映像文件,它是在zImage之前加上一个长度为64字节的“头”,说明这个内核的版本、加载位置、生成时间、大小等信息;其0x40之后与zImage没区别。

生成uImage文件:

1.首先在uboot的/tools目录下寻找mkimage文件,把其copy到系统/usr/local/bin目录下,这样就完成制作工具
2.在内核目录下运行make uImage,如果成功,便可以在arch/arm/boot/目录下发现uImage文件,其大小比zImage多64个字节

有了uImage头部的描述, u-boot就知道对应Image的信息, 如果没有头部则需要自己手动去设置那些参数

vmlinum --> Image --> zImage --> uImage:

编译结果:几种linux内核文件的区别

1、vmlinux :编译出来后未压缩最原始的elf内核文件,该文件不能烧写到flash中

2、Image: vmlinux 经过 OBJCOPY 之后会产生的文件,比较大,但已经可以具备烧写到flash

2、zImage :Image经过gzip压缩后的文件。

3、bzImage:bz表示“big zImage”,不是用bzip2压缩的。两者的不同之处在于,zImage解压缩内核到低端内存(第一个640K),bzImage解压缩内核到高端内存(1M以上)。如果内核比较小,那么采用zImage或bzImage都行,如果比较大应该用bzImage。

4、uImage : U-boot专用的映像文件,它是在zImage之前加上一个长度为0x40的TAG。使得内核可以启动

5、vmlinuz: bzImage/zImage文件的拷贝或指向bzImage/zImage的链接。

6、initrd ,: “initial ramdisk”的简写。一般被用来临时的引导硬件到实际内核vmlinuz能够接管并继续引导的状态

一般情况下都在生成vmlinux后,再对内核进行压缩成为zImage,压缩的目录是kernel/arch/arm/boot。

下载到 flash 中的是压缩后的zImage文件,zImage是由压缩后的vmlinux和解压缩程序组成的。

开发板上U-Boot启动linux内核

查看 2440 的 datasheet , 发现内存映射的基址是 0x3000 0000 , 那么0x30008000 又是如何来的呢?

在内核文档kernel/Document/arm/Booting 文件中有:

Calling the kernel image

Existingboot loaders: MANDATORY New boot loaders: MANDATORY There are two options for calling the kernel zImage. If the zImage is stored inflash, and is linked correctly to be run from flash, then it is legal for the boot loader to call the zImage in flashdirectly. The zImage may also be placed in system RAM (at any location) and called there.Note that the kernel uses 16K of RAM below the image to store page tables. The recommended placement is 32KiBinto RAM.

看来在image下面用了32K(0x8000)的空间存放内核页表,0x30008000 就是 2440 的内核在 RAM 中的启动地址,这个地址就是这么来的

启动内核:

1、下载uImage.bin到SDRAM的0x30008000处,tftp是一个类似于ftp的下载软件,在uboot的shell下,输入:

tftp 0x30008000 uImage

2、启动内核,从0x30008000

bootm 0x30008000

内核Kconfig语法使用

1.make menuconfig 是如何找到 Kconfig?

make menuconfig界面选中(*代表选中)配置项时,.config配置单中的配置项也会更改为 “y”(对应的文件会被编译进内核)

make menuconfig --> Kconfig —> Makefile xxx.c 的过程 是如何组织的?

  1. make menuconfig中查找串口驱动的 宏CONFIG_SERIAL_SAMSUNG 配置项:




  1. 宏CONFIG_SERIAL_SAMSUNG 在对应的 Kconfig 中应该有这样的语法:

config SERIAL_SAMSUNG # make menuconfig运行时会在 .config 中自动生成 CONFIG_SERIAL_SAMSUNG 配置项

3.查找 Samsung SoC serial support 关键字,获得所在的Kconfig文件:

4.查看Kconfig文件获得 CONFIG_SERIAL_SAMSUNG 对应的 "config SERIAL_SAMSUNG"语法:

5.在Kconfig的同级目录下查看Makefile文件中的 “CONFIG_SERIAL_SAMSUNG” 配置项:

这里就将 samsung.c 文件编译进来了

2.Makefile 要编译一个 .o 文件是如何在Kconfig中配置的?

即: Makefile .o —> Kconfig, 则可以倒着查找

添加驱动到内核

概念

相比于裸机的驱动,内核驱动需要很多冗余的信息:

裸机的硬件发生改变则驱动也会改变; 而内核驱动则不会因为硬件改变而需要改变,因为其涉及一个复杂的驱动框架

如有驱动程序 myleddev.c 和应用程序 myledtest.c

添加步骤

1.将我们开发的驱动 myleddev.c 放到能自述其意的目录下,如 /drive/char/myled 目录
2.在myled 目录下增加并编辑 Makefile 文件,将 myleddev.c 和 Makefile 关联起来:
obj-$(CONFIG_MYLEDTEST) += myleddev.o  // 前缀必须为 "CONFIG_",如果$(CONFIG_MYLEDTEST)为y,即"obj-y"则指示编译器将myleddev.c被编译进内核

在myled目录的上级目录的Makefile中添加:

obj-y += myled/   # 内核会以myled目录作为下一个目标进入
或者
obj-$(CONFIG_MYLEDTEST) += myled/ # 需要将 CONFIG_MYLEDTEST 配置项设置为 "y"
3. 使用 make menuconfig

1.在myled目录下增加并编辑 Kconfig 文件:

menu "my char device"

config MYLEDTEST  
        bool "Support myled device driver"
        help
            Support led device driver for S5PV210
endmenu

2.在上级目录的 Kconfig 文件中包含子目录 myled 的 Kconfig文件:

source "drivers/char/myled/Kconfig"

3.使用make menuconfig将.config配置单中的 CONFIG_MYLEDTEST 配置为 y:



编译

使用 make uImage 将驱动编译进内核,目录下驱动对应的 .o 文件则代表驱动成功编译进内核:

执行应用程序

1.将编译后的内核下载到开发板上

2.确定内核是否运行了LED驱动

$ cat /proc/devices # devices文件记录了内核支持的设备信息

3.创建LED驱动程序与应用程序直接衔接的设备节点

# mknode /dev/led1 c 253 1 # 创建设备节点,名为 /dev/led1

4.测试

1.需要将应用程序放在开发板上运行,可以先将PC的目录挂载到开发板的 /mnt 下:

1.PC开启 ntf服务, netstat -tua | grep nfs: 检查ntf服务是否开启
2.exportfs 查看PC当前 NFS 共享的文件系统列表
3.将共享目录挂载到开发板的 /mnt 下(注意开发板要设置IP地址): mount -t nfs -o nolock 192.168.10.10:/work/ /mnt

2.将应用程序复制到共享目录下

3.PC上对应用程序进行交叉编译

arm-linux-gcc -o ledtest myledtest.c

4.开发板上执行应用程序

./ledtest

添加驱动到内核的过程:

参考资料

https://www.youtube.com/watch?v=qNeLmPCK7xE&list=PLljKjXpjNpgdY8fNIhHQG0ErUDldOCQxh&index=12

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

Linux内核裁剪移植学习分享

AM335x移植linux内核_转

Linux内核裁剪移植学习分享

RT-Thread快速入门-内核移植

内核裁剪--三星2410

Linux移植之内核启动过程引导阶段分析