Chinaunix首页 | 论坛 | 博客
  • 博客访问: 805315
  • 博文数量: 281
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2770
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-02 19:45
个人简介

邮箱:zhuimengcanyang@163.com 痴爱嵌入式技术的蜗牛

文章分类
文章存档

2020年(1)

2018年(1)

2017年(56)

2016年(72)

2015年(151)

分类: LINUX

2017-03-01 13:39:41

1.1 Linux 内核开发简介
    这里所说的“ Linux 内核开发”仅仅是指嵌入式 Linux 产品开发中内核和驱动相关开发
    工作,与 Linus 所领导的内核开发团队的内核开发有很大不同。
    产品开发中对内核进行二次开发, 需要开发人员具备如下一些基本技能和背景知识:
    a. 具备操作系统的基本知识,理解操作系统原理,最好了解 Linux 操作系统;
    b. 内核绝大部分都是 C 语言编写的, C 语言是必备技能;
    c. 内核是用 GNU C 编写的,尽管符合 ISO C89 标准,但还是使用了一些 GNU 扩展,
    所以对 GNU C 的一些扩展也必须有所了解;
    d. 对 Linux 内核源码基本分布有大致了解;
    e. 产品级的内核开发通常还包括一些内核驱动工作,对外设工作原理和驱动编写也必
    须有一定的了解。

1.2 Linux 源码阅读工具
1.2.1 Source Insight
    Source Insight 是 Windows 平台下一款流行度极高的源码阅读和编辑工具。不少 Linux
    开发人员还是习惯于在 Windows 下进行源码编辑,甚至查看和编辑 Linux 内核源码,依然
    在 Source Insight 中完成。

1.2.2 Eclipse
    Eclipse 是一个跨平台 IDE,既能运行于 Windows 平台,也能在 Linux 下运行。不少习
    惯于图形界面操作的开发人员,在 Linux 下则习惯于用 Eclipse 来查看和编辑 Linux 源码。
    如果仅仅是在 Eclipse 中查看 Linux 内核源码,则可以不必事先安装交叉编译器, 否则
    则须事先安装好交叉编译器。
    
1.2.3 vim+ctags+cscope
    Vi/Vim 是一个文本编辑器,在 Vim 中能高效的实现代码编辑。但 Vim 的功能不仅仅是
    一个文本编辑器,借助 ctags 和 cscope 的配合, Vim 能实现堪比图形 IDE 环境的源码编辑和
    阅读功能,在某种程度上甚至比图形 IDE 更方便。
    
1.2.4 LXR
    LXR 是 Linux Cross Referencer 的缩写,是一个比较流行的 Linux 源码查看工具,当然
    也不仅仅局限于查看 Linux 源码。 LXR 的下载地址为: ,参考该网站
    的安装说明,很容易在本机搭建一个本地 LXR 用于源码查看。
    
1.3 Linux 内核源码
1.3.1 目录树概览
    解压 Linux 内核源码压缩包,将得到内核源码。内核源码很复杂,包含多级目录,形成
    一个庞大的树状结构,通常称为 Linux 源码目录树。

1.3.2 快速确定主板关联代码
    拿到一份源码和一块评估板, 如何快速找到与这块板相关的源码,是很多研发人员都曾
    遇到过的问题。如果对内核源码结构有大概了解,要完成这些事情也不难,通常可按照基础
    代码、驱动代码和其它代码等方面来梳理。
    
    1. 基础代码
    Linux 移植通常分为体系结构级别移植(arm)、处理器级别移植(arm920t)和板级移植(smdk2440开发板)
    各级别移植难易程度差异很大,工作量和调试方式也各不相同。一般的产品开发人员所进行的内核移植,通
    常都是板级移植,这是几个级别中最简单的。
    从代码层面来看,通常把能让一个主板最小系统能运行的代码称为基础代码,这部分代
    码通常包含体系结构移植代码、处理器核心代码以及板级支持包的部分代码。理清了这部分
    代码,对于了解和掌握整个主板相关代码具有重要意义。
    
    确定主板名称和默认配置文件。
        例如,对于 EPC-28x 工控板,其对应的默认内核配置
        文件为。 通常来说,一个评估板的内核默认配置文
        件名称与评估板的名称相同或者有关联。确定了配置文件后,可用任何文本编辑器打开该配
        置文件,可以对配置的选项进行查看;或者进行 make menuconfig 配置,进入配置界面查看。
    
    确定对应的主板文件。
        在 ARM Linux 移植代码中,每个评估板通常都有一个对应的主
        板文件,在目录下。大多数主板文件都以“ board-”开头,采用
        “ board-xxx.c”这样的文件名,例如;也有以
        “ mach-”开头的,如。通常来说,一个评估板的主板
        文件名称与评估板的名称相同或者有关联。
        
    如果遇到名称特征不是很明显,不能确定的情况:
        则建议打开默认配置文件【就是.config文件】,找到
        “ CONFIG_MACH_XXX=y”这一行,确定主板对应的配置开关变量。然后打开
        文件,根据配置开关变量来确定主板文件。例如
        文件中有如下内容:
        # Intel/Marvell Dev Platforms
        obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
        obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o
        obj-$(CONFIG_MACH_ZYLONITE300) += zylonite.o zylonite_pxa300.o
        可以看到, 这几个主板文件命名都既不是以“ board-”开头,也不是以“ mach-”开头,
        对于这种情况,通过 Makefile 文件来确定一下是比较好的做法。特别是对于主板开关变量
        对应非单一文件的,更需要查看 Makefile 来确定关联文件,否则有可能遗漏某个文件,造
        成代码阅读理解上的障碍。如 CONFIG_MACH_ZYLONITE300 对应着 zylonite.c 和 zylonite
        _pxa300.c 两个 C 文件。
        
2. 驱动代码
    Linux 内核源码中接近一半的代码量是驱动,对某一个特定主板的系统而言,驱动也占
    据很大的比例,底层开发的很大一部分是驱动相关工作。掌握从众多驱动中找到正确的驱动
    源码文件,并根据产品的实际需求进行修改调整的方法,能有效促进产品开发的进度。
    Linux 内核源码树 drivers 目录很复杂,包含了各种外设的驱动。对嵌入式 Linux 开发而
    言,通常需要关注的目录如表 1.2 所列。
    
    表 1.2 常见驱动目录
    目录                           说明
    ------------------------------------------------------------------------------------------

    drivers/gpio          系统 GPIO 子系统和驱动目录,包括处理器内部 GPIO 以及外扩 GPIO 驱动。
                          遵循 GPIO 子系统的驱动,可通过/sys/class/gpio 进行访问
    drivers/hwmon         硬件监测相关驱动,如温度传感器、风扇监测等
    drivers/i2c           I2C子系统驱动。各 I2C 控制器的驱动在 i2c/busses 目录下
    drivers/input         输入子系统驱动目录
    
    drivers/input/keyboard        非HID键盘驱动,如GPIO键盘、矩阵键盘等
    drivers/input/touchscreen     触摸屏驱动,如处理器的触摸屏控制器驱动、外扩串行触摸屏控制器驱动、串口
                                  触摸屏控制器驱动等

    drivers/leds         LED 子系统和驱动,如 GPIO 驱动的 LED。遵循 LED 子系统的驱动 ,可通过/sys/class/leds 进行访问

    drivers/mfd          多功能器件驱动。如果一个器件能做多种用途,通常需要借助 MFD 来完成。例如 am3352 的 adc 接口,
                         可同时做 adc 和触摸屏控制器,所以需要实现 MFD 接口驱动

    drivers/misc         杂项驱动。特别需要关注目录,提供了i2c和spi接口的

                         EEPROM 驱动范例,所驱动的设备可通过/sys 系统访问
    drivers/mmc          sd/mmc卡驱动目录
    drivers/mtd          MTD子系统和驱动,包括NAND、oneNAND等。注意,UBI的实现也在MTD中
    drivers/mtd/nand     NAND FALSH的MTD驱动目录,包括NAND的基础驱动和控制器接口驱动
    drivers/net          网络设备驱动,包括MAC、PHY、CAN、USB网卡、无线、PPP协议等
    drivers/net/can      CAN设备驱动。 Linux 已经将 CAN 归类到网络中,采用 socket_CAN 接口
    drivers/net/ethernet    所支持的 MAC 驱动。常见厂家的 MAC 驱动都能找到,如 broadcom、 davicom、
                            marvell、 micrel、 smsc 等厂家的 MAC,处理器自带 MAC 的驱动也在该目录下
    drivers/net/phy         PHY 驱动,像 marvell、 micrel 和 smsc 的一些 PHY 驱动
    drivers/rtc             RTC 子系统和 RTC 芯片驱动
    drivers/spi SPI         子系统和 SPI 控制器驱动,含 GPIO 模拟 SPI 的驱动
    drivers/tty             TTY 驱动
    drivers/tty/serial      串口驱动,包括 8250 串口以及各处理器内部串口驱动实现
    drivers/uio             用户空间 IO 驱动
    drivers/usb             USB 驱动,包括 USB HOST、 Gadget、 USB 转串口以及 OTG 等支持
    drivers/video           Video 驱动,包括 Framebuffer 驱动、显示控制器驱动和背光驱动等。有的移植
                            代码会将液晶屏配置通放在显卡控制器驱动目录下,例如 omap2 系列的 LCD 配
                            置代码在目录下
    drivers/video/backlight     背光控制驱动
    drivers/video/logo          Linux 内核启动 LOGO 图片目录
    drivers/watchdog            看门狗驱动,包括软件看门狗和各种硬件看门狗驱动实现
    
    熟悉各类驱动在源码树中的大概位置,能帮助在开发过程中快速进行驱动源码查找和定
    位。一个系统到底用了哪些代码,与系统本身外设相关,也与主板配置文件相关。
    
3.其它代码
    还有一些代码是系统必须的代码,但在实际开发过程中通常很少需要进行关注,例如文
    件系统的实现代码、 网络子系统的实现代码等。对这部分代码和主板的关联性,建议根据配
    置文件来确认。
    
1.4 Linux 内核中的 Makefile 文件
    本节不对内核的 Makefile 文件进行深入展开,更多语法和说明请阅读:
     文件。
    
    1.4.1 顶层 Makefile
        源码目录树顶层 Makefile 是整个内核源码管理的入口,对整个内核的源码编译起着决
        定性作用。编译内核时,顶层 Makefile 会按规则递归历遍内核源码的所有子目录下的
        Makefile 文件,完成各子目录下内核模块的编译。
        
        1. 内核版本号
        打开顶层 Makefile,开头的几行记录了内核源码的版本号,通常如下所示:
            VERSION = 2
            PATCHLEVEL = 6
            SUBLEVEL = 35
            EXTRAVERSION =3
        说明代码版本为 2.6.35.3,编译得到的内核在目标板运行后,输入 uname -a 命令可以得到印证:
        # uname -a  (注意:这个是在目标板上运行的内核。)
            Linux boy 2.6.35.3-571-gcca29a0-gd431b3d-dirty #22 PREEMPT Tue Oct 27 20:12:33 CST 2015 armv5tejl
            GNU/Linux    
        
        2. 编译控制
        ( 1)体系结构
        Linux 是一个支持众多体系结构的操作系统,在编译过程中需指定体系结构,以与实际
        平台对应。在顶层 Makefile 中,通过变量 ARCH 来指定:
        ARCH ?= $(SUBARCH)
        如果没有在编译命令行中指定 ARCH 参数,系统将会进行本地编译,通过获取本机信
        息来自动指定:
            SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
            -e s/arm.*/arm/ -e s/sa110/arm/ \
            -e s/s390x/s390/ -e s/parisc64/parisc/ \
            -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
            -e s/sh[234].*/sh/ )
        如果进行 ARM 嵌入式 Linux 开发,则必须指定 ARCH 为 arm( 注意大小写,须与 arch/
        目录下的 arm 一致),如:
        $ make ARCH=arm
        当然,也可以修改 Makefile,将修改为 ARCH ?= $(SUBARCH)修改为 ARCH = arm,在
        命令行直接 make 即可。
        
        ( 2)编译器
        如果不是进行本地编译,则须指定交叉编译器,通过 CROSS_COMPILE来指定。Makefile
        中与交叉编译器的指定如下:
            CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%)
            ……
            AS = $(CROSS_COMPILE)as
            LD = $(CROSS_COMPILE)ld
            CC = $(CROSS_COMPILE)gcc
            CPP = $(CC) –E
            AR = $(CROSS_COMPILE)ar
            NM = $(CROSS_COMPILE)nm
            STRIP = $(CROSS_COMPILE)strip
            OBJCOPY = $(CROSS_COMPILE)objcopy
            OBJDUMP = $(CROSS_COMPILE)objdump
            
        CONFIG_CROSS_COMPILE 是一个配置选项,可在内核配置时候指定。如果在配置内
        核时候没有指定 CONFIG_CROSS_COMPILE,也没有在编译参数指定CROSS_COMPILE,
        则会采用本地编译器进行编译。
        
        进行 ARM 嵌入式 Linux 开发,必须指定交叉编译器,可以在内核配置通过 CONFIG
        _CROSS_COMPILE 指定交叉编译器,也可以通过 CROSS_COMPILE 指定。假定使用的交
        叉编译器是 arm-linux-gnueabihf-gcc,则指定 CROSS_COMPILE 为 arm-linux-gnueabihf-:
        $ make ARCH=arm CROSS_COMPILE= arm-linux-gnueabihf-

        或者在 Makefile 中,直接指定 CROSS_COMPILE 的值:
        CROSS_COMPILE = arm-linux-gnueabihf-
        
        注意:CROSS_COMPILE 指定的交叉编译器必须事先安装并正确设置系统环境变量;
        如果没有设置环境变量,则需使用绝对地址,例如:
        CROSS_COMPILE =/home/ctools/linux-devkit/bin/arm-linux-gnueabihf-
        如果同时指定了 ARCH 和 CROSS_COMPILE, 则在编译的时候, 只需简单的 make 就
        可以了。
        
    1.4.2 子目录的 Makefile
        在内核源码的子目录中,几乎每个子目录都有相应的 Makefile 文件,管理着对应目录
        下的代码。对该目录的文件或者子目录的编译控制,
        Makefile 中有两种表示方式,一种是默
认选择编译,用 obj-y 表示,如:
            obj-y += usb-host.o       # 默认编译 usb-host.c 文件
            obj-y += gpio/            # 默认编译 gpio 目录
            
        另一种表示则与内核配置选项相关联,编译与否以及编译方式取决于内核配置,例如:
            obj-$(CONFIG_WDT) += wdt.o         # wdt.c 编译控制
            obj-$(CONFIG_PCI) += pci/          # pci 目录编译控制
            
        是否编译 wdt.c 文件,或者以何种方式编译,取决于内核配置后的变量 CONFIG_WDT
        值:如果在配置中设置为[*],则静态编译到内核,如果配置为[M],则编译为 wdt.ko 模块,
        否则不编译。
        
        说明:受控目标是一个目录, obj-y 并不直接决定受控目录的文件以及子目录的文件,
        仅仅是与受控目录 Makefile 交互,实际编译控制在受控子目录的 Makefile 中。例如“ obj-y
        += gpio/”,最终 gpio 目录下哪些文件被编译,完全取决于 gpio 目录下的 Makefile。
        “ obj-$(CONFIG_PCI) += pci/” 的含义同理。
        
1.5 Linux 内核中的 Kconfig 文件
    本节不对内核的 Kconfig 文件进行深入展开,更多 Kconfig 语法和说明请阅读:
        

    内核源码树每个目录下都还包含一个 Kconfig 文件,用于描述所在目录源代码相关的内
    核配置菜单,各个目录的 Kconfig 文件构成了一个分布式的内核配置数据库。通过 make
    menuconfig( make xconfig 或者 make gconfig)命令配置内核的时候,从 Kconfig 文件读取菜
    单,配置完毕保存到文件名为.config 的内核配置文件中,供 Makefile 文件在编译内核时使
    用。
    
    具体的语法参考相关的书籍。    
        
       
阅读(3388) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~