首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Linux内核的相关基础概念

Linux内核的相关基础概念

.linux设备驱动的作用
内核:用于管理软硬件资源,并提供运行环境。如分配4G虚拟空间等。
linux设备驱动:是连接硬件和内核之间的桥梁。

linux系统按个人理解可按下划分:

应用层:包括POSIX接口,LIBC,图形库等,用于给用户提供访问内核的接口。属于用户态,ARM运行在用户模式(usr)者系统模式(sys)下。
内核层:应用程序调用相关接口后,会通过系统调用,执行SWI令切换ARM的工作模式到超级用户(svc)模式下,根据用户函数的要求执行相应的操作。
硬件层:硬件设备,当用户需要操作硬件时,内核会根据驱动接口操作硬件设备

图结构如下:


举一个相对比较邪恶的类比:
在深圳的酒店经常会在门缝看到一些卡片,上面说可以通过打电话送货上门提供某中服务。


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

.内核代码树介绍

linux-2.6.29
|-arch        : 包含和硬件体系结构相关的代码
|-block       : 硬盘调度算法,不是驱动
|-firmware    : 固件,如BOIS
|-Documentation:标准官方文档
|-dirver      : linux设备驱动
|-fs          : 内核所支持的文件体系
|-include     :头文件。linux/module.hlinux/init.h 常用库。
|-init        :库文件代码,C库函数在内核中的实现。
                                 init/main.c->start_kernel->内核执行第一条代码
|-ipc         : 进程件通信
|-mm          :内存管理
|-kernel      : 内核核心部分,包括进程调度等
|-net         :网络协议
|-sound       : 所有音频相关


其中,跟设备驱动有关并且经常查阅的文件夹有:
init
include: linux, asm-arm
drivers:
arch:

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

.内核补丁:
补丁一般都是基于某个版本内核生成的,用于升级旧内核。
打补丁需要注意:
1.对应版本的补丁只能用于对应版本的内核。
2.如果在已打补丁的内核再打补丁,需要先卸载原来补丁。
打补丁的方法:
1.制作补丁:
diff-Nur linux-2.6.30/ linux-2.6.30.1/ > linux-2.6.30.1.patch
//N为新加的文件全部修改
//linux-2.6.30旧版本
//linux-2.6.30.1新版本
//目标补丁
2.打补丁:
cdlinux-2.6.30                                //!!注意在原文件夹的目录中打补丁
patch-p1 < ../linux-2.6.30.1.patch                //-p1是忽略一级目录
3.恢复:
cdlinux-2.6.30             //!!注意在原文件夹的目录中打补丁
patch-R < ../linux-2.6.30.1.patch                //撤销补丁

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

.内核中的Makefile
对于内核,Makefile分为5类:
Documentation/kbuild/makefiles.txt描述如下:
50 The Makefiles have five parts:
51
52     Makefile                          Makefile,控制内核的编译
53     .config                             内核配置文件,配置内核时生成,make menuconfig
54     arch/$(ARCH)/Makefile 对应体系结构的Makefile
55     scripts/Makefile.*           Makefile共用的规则
56     kbuild Makefiles             各子目录下的Makefile,被上层的Makefile调用。

简单来说,编译内核会执行以下两步骤,它们分别干了以下的事情。
1一般的,我们会拷贝一个对应体系结构的配置文件到主目录下并改名为.config,这样就在makemenuconfig生成的图形配置中已经有了一些默认的配置,减少用户的劳动量。不过这一步不做也没关系的。
2.makemenuconfig
2.1、由总Makefile决定编译的体系结构(ARCH).编译工具(CROSS_COMPILE),并知道需要进去哪些内核根下的哪些目录进行编译。
2.2、由arch/$(ARCH)/Makefile,决定arch/$(ARCH)下还有的哪些目录和文件需要编译。
2.3、知道了需要编译的目录后,递归的进入哪些目录下,读取每一个Kconfig的信息,生成了图形配置的界面。
2.4、通过我们在图形配置界面中选项为
  • [M]或者[]
    2.5、保存并退出配置,会根据配置生成一份新的配置文件.config,并在同时生成include/config/auto.conf(这是.config的去注释版)。文件里面保存着CONFIG_XXXX等变量应该取y还是取m
    3.make
    3.1、根据Makefile包含的目录和配置文件的要求,进去个子目录进行编译,最后会在各子目录下生成一个.o或者.a文件,然后总Makefile指定的连接脚本arch/$(ARCH)/kernel/vmlinux.lds生成vmlinux,并通过压缩编程bzImage,或者按要求在对应的子目录下编译成模块。。               

    但是,具体是怎么生成配置文件的呢?
    注:我使用的内核是2.6.29
    1.在总Makefile中,根据以下语句进入需要编译的目录
    470 # Objects we will link intovmlinux / subdirs we need to visit
    471 init-y          := init/
    472 drivers-y       := drivers/sound/ firmware/
    473 net-y           := net/
    474 libs-y          := lib/
    475 core-y          := usr/
    476 endif # KBUILD_EXTMOD
    639 core-y          += kernel/ mm/fs/ ipc/ security/ crypto/ block/
    上面说明了,根目录下的initdriversoundfirmwarenetlibusr等目录,在编译时都会进去读取目录下的Makefile并进行编译。

    2.在总Makefile中包含的目录还是不够的,内核还需要根据对应的CPU体系架构,
    决定还需要将哪些子目录将要编译进内核。在总Makefile中有一个语句:
    529 include$(srctree)/arch/$(SRCARCH)/Makefile             //在这里,我定义SRCARCH= arm
    可以看出,在总Makefile中进去读取相应体系结构的Makefile->arch/$(SRCARCH)/Makefile
           
    arch/$(SRCARCH)/Makefile中指定arch/$(SRCARCH)路径下的哪些子目录需要被编译。
    arch/arm/Makefile 下:
    95 head-y          :=arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o
    187 # If we have a machine-specificdirectory, then include it in the build.
    188 core-y                         += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
    189 core-y                         += $(machdirs) $(platdirs)
    190 core-$(CONFIG_FPE_NWFPE)       += arch/arm/nwfpe/
    191 core-$(CONFIG_FPE_FASTFPE)     += $(FASTFPE_OBJ)
    192 core-$(CONFIG_VFP)             += arch/arm/vfp/
    193
    194 drivers-$(CONFIG_OPROFILE)     += arch/arm/oprofile/
    195
    196 libs-y                         := arch/arm/lib/ $(libs-y)
    上面看到,指定需要进入arch/arm/kernel/arch/arm/mm/arch/arm/common/等目录编译,至于core-ycore-$(CONFIG_FPE_NWFPE)这些是什么东西呢?

    其中,y表示编译成模块,m表示编译进内核(上面没有,因为默认情况下ARM全部编译进内核),但$(CONFIG_OPROFILE)又是什么呢?这些是根据用户在makemenuconfig中设置后,生成的值赋给了CONFIG_OPROFILE

    3.makemenuconfig后的配置信息是怎么来的?
    这是由各子目录下的Kconfig提供选项功用户选择并配置。
    arch/arm/Kconfig所有的配置都是根据arch/$(ARCH)/Kconfig文件通过Kconfig的语法source读取各个包含的子目录Kconfig来生成一个配置界面。每个Makefile目录下都有一个对应的Kconfig文件,用于生成配置界面来给用户决定内核如何配置,配置后会确定一个。CONFIG_XXX的的值(如上面的CONFIG_OPROFILE),来决定编译进内核,还是编译成模块或者不编译。
    如在arch/arm/Kconfig下:
    595 source"arch/arm/mach-clps711x/Kconfig"
    596
    597 source"arch/arm/mach-ep93xx/Kconfig"
    598
    599 source"arch/arm/mach-footbridge/Kconfig"
    600
    601 source"arch/arm/mach-integrator/Kconfig"
    602
    603 source"arch/arm/mach-iop32x/Kconfig"
    604
    605 source"arch/arm/mach-iop33x/Kconfig"
    这些就是用来指定,需要读取以下目录下的Kconfig文件来生成一个使用makemenuconfig时的配置界面。
            至于子目录下的Kconfig是怎么样的,待会介绍。
    总结Kconfig的作用:
    3.1.makemenuconfig下可以配置选项;
    3.2..config中确定CONFIG_XXX的的值。

    4.只是读取以上的两个Makefile还是不够了,内核还会把包含的子目录一层一层的读取它里面的MakefileKconfig

    上面啰啰嗦嗦地讲了这么久,无非就是想说,内核的编译并不是一个Makefile搞定的,需要通过根目录下的总Makefile来包含一下子Makefile(不管是根目录下的子目录还是/arch/arm中的子目录)。而Kconfig,为用户提供一个交互界面来选择如何配置并生成配置选项。

    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

    五、子目录下的MakefileKconfig

    上面我一直介绍的都是两个比较大的Makefile——Makefilearch/$(ARCH)/Makefile。接下来看一下实例。

    一、makefile中,y表示编译进内核,m表示编译成模块,不写代表不编译。所以,配置最简单的方法就是,直接修改子目录的Makefile
    先看看arch/arm/Makefile
    /*arch/arm/mach-s3c2440/Makefile*/
    12 obj-$(CONFIG_CPU_S3C2440)   +=s3c2440.o dsc.o
    13obj-$(CONFIG_CPU_S3C2440)   += irq.o
    14obj-$(CONFIG_CPU_S3C2440)   += clock.o         //配置2440的时钟进入模块
    15obj-$(CONFIG_S3C2440_DMA)   += dma.o
    如果我要取消s3c2440的时钟(当然这是必须要开的,只是举例)可以直接修改arch/arm/mach-s3c2440/Makefileobj-$(CONFIG_CPU_S3C2440)   += clock.o改为
    obj-   += clock.o
    如果你想编译成模块也可以修改成:
    obj-m        += clock.o
    在这里CONFIG_CPU_S3C2440的值默认是y,所以内核是要将时钟编译进内核的。也许有人会问,那我直接修改CONFIG_CPU_S3C2440的值为m不就可以将时钟编译成模块了,何必修改Makefile这么麻烦呢?的确是这样,只要我们通过在”makemenuconfig”的界面中配置后就能够改变CONFIG_CPU_S3C2440的值。接下来看看如何实现。

    二、在一般的编译内核时,我们都是通过”makemenuconfig”进入图形界面面配置的,接下来我实现一下如何将一个选项加入到图形配置界面中。
    看看具体实现的步骤:
    以下的执行环境是在PC机上,我使用的内核是linux-2.6.29
    2.1.进入内核目录
    cd linux-2.6.29
    2.2. driver目录下模拟一个名为test1驱动的文件夹
    mkdir driver/test1       
    2.3.在目录下随便些一个C文件,只要不报错。
    vim test1.c              
    我的test1.c如下:
      1 void foo()
      2 {
      3        ;
      4}                           
    2.4vim Makefile                                        //在目录下编写一个简单的Makefile
    Makefile文件编写如下:
    obj-$(CONFIG_TEST1) += test1.o
    CONFIG_TEST1是决定test1是否编译进内核或者编译成模块的。这就是通过同一目录下的Kconfig来在配置界面中生成选项,由用户在makemenuconfig中选择。
    2.5所以还要同一目录下写一个Kconfig
    vim Kconfig                                       
    Kconfig修改如下:
    menu "test1 driver here"                      //这是在图形配置显示的
    config TEST1
    bool "xiaobai test1 driver"                          //这同样也是在图形配置显示的
    help
    This is test1                                          //这个也是在图形配置显示的。
    说白了,就是在图形配置的driver下多了一个配置选项,用户配置后将CONFIG_TEST1的值存放在.config中,Makefile通过读取.config的去注释版include/config/auto.conf读取到CONFIG_TEST的值,再进行编译。

    但是,以上几步还不能达到目的,因为虽然在总Makefile中已经包含了目录driver,但是driver目录的Makefile中并没有包含test目录。因此需要在driver/Makefile中添加:
    103 obj-$(CONFIG_PPC_PS3)       +=ps3/
    104 obj-$(CONFIG_OF)        += of/
    105 obj-$(CONFIG_SSB)       += ssb/
    106 obj-$(CONFIG_VIRTIO)        +=virtio/
    107 obj-$(CONFIG_STAGING)       +=staging/
    108 obj-y               +=platform/
    109obj-$(CONFIG_TEST1)     += test1/                        //这是我添加的
    虽然Makefile中已经包含了,但这样还是不行。因为当需要配置ARM时,ARM结构下的Kconfig并没有包含testKconfig这样的话就不会出现在图形配置界面中,因此在arch/arm/Kconfig中添加:
    1230 menu"Device Drivers"        //要在DeviceDrivers这个选项里面添加
    1231
    1232 source "drivers/base/Kconfig"
    1233
    1234 source"drivers/connector/Kconfig"
    。。。。。。。。
    1330 source"drivers/test/Kconfig"                //这是我添加的
    1331
    1332 endmenu

    大功告成!
    这样,makemenuconfig界面写的DriverDevices下就多了一个"test1friver here"的目录,里面有一个配置选项"xiaobaitest1 driver"



    Kconfig文件的语法在documentation/kbuild/kconfig-language.txt文件中有详细的讲解,上面我只是简单实现了一下,都是皮毛。

    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

    .内核和模块的编译

    编译内核很简单,只需要配置完毕后执行make命令,将指定的文件编译进内核
    bzImage或者编译成模块。
    make =make bzImage + make modules
    因此如果值编译内核,即只编译配置文件中-y选项,可以直接用命令
    makebzImage
    如果值编译模块,即只编译配置文件中的-m选项,可以之直接使用命令
    makemodules
    模块可以编译当然也可以清除,使用命令
    makemodules clean
    如果只想单独编译一个模块,可以使用命令
    makeM=drivers/test/ modules         //只单独编译drivers/test中的.ko
    makeM=drivers/test/ modules clean         //清除
    上面的是在内核目录下的操作,但当我写驱动时,我并不可能在内核目录下编
    写,但我编译时却要依赖内核中的规则和Makefile,所以就有了以下的方法,
    同时这也是一般的编写驱动时Makefile的格式。
    指定内核Makefile并单独编译
    make-C /root/linux-2.6.29 M=`pwd` module
    make-C /root/linux-2.6.29 M=`pwd` module clean
    //-C指定内核Makefile的路径,可以使用相对路径。
    //-M指定要编译的文件的路径,同样课使用相对路径。
    编译生成的模块可以指定存放的目录
    make-C /root/linux-2.6.29 M=`pwd` modules_installINSTALL_MOD_PATH=/nfsroot   

    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

    七、总结

    说了这么久估计都说糊涂了,其实我只是想表达一下内核编译时大体上究竟是怎么样的一个过程。
    我以编译S3C2440的内核为例再说一遍:
    1一般我们会想将一份S3C2440的默认配置拷贝到内核跟目录下并改名为.config
    2.makemenuconfig
    2.1、由总Makefile决定编译的体系结构(ARCH).编译工具(CROSS_COMPILE),并知道需要进去哪些内核根下的哪些目录进行编译。
    2.2、由arch/$(ARCH)/Makefile,决定arch/$(ARCH)下还有的哪些目录和文件需要编译。
    2.3、知道了需要编译的目录后,递归的进入哪些目录下,读取每一个Kconfig的信息,生成了图形配置的界面。
    2.4、通过我们在图形配置界面中选项为
  • [M]或者[]
    2.5、保存并退出配置,会根据配置生成一份新的配置文件.config,并在同时生成include/config/auto.conf(这是.config的去注释版)。文件里面保存着CONFIG_XXXX等变量应该取y还是取m
    3.make
    3.1、根据Makefile包含的目录和配置文件的要求,进去个子目录进行编译,最后会在各子目录下生成一个.o或者.a文件,然后总Makefile指定的连接脚本arch/$(ARCH)/kernel/vmlinux.lds生成vmlinux,并通过压缩编程bzImage,或者按要求在对应的子目录下编译成模块
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • 返回列表