• 2、内核基本学习


    一、Linux内核源代码的目录结构学习

        Linux 内核的目录,变化是比较的小,以Linux 2.6 的版本进行分析。

    1

        arch : 架构体系相关的代码,不同平台都在 arch 里面有相应的一个目录,比如 arm、powerpc、mips。在 arch 目录,存放的是各个平台以及各个平台的芯片对 Linux 内核进程调度、内存管理、中断等代码。

        block : 块设备驱动程序的 I/O 调度、

        crypto : 一些加密实现算法

        document : 内核各个部分帮助的文档,比如内核编写代码的风格、等等。

        fs : 文件系统。部分 NTFS、JFFS2

        include : 头文件,与系统习惯的头文件,是被放在 include/linux 里面

        init :  内核的初始化代码

        ipc : 进程通信的代码

        kernel : 内核最核心的部分,进程调度、定时器,等等,与平台相关的代码则在 arch/xxx/kernel 里面

        lib : 库文件

        mm : 内存管理代码,与平台相关的代码 在 arch/xxx/mm 目录里面

        net : 网络相关的代码

        scripts : 脚本,内核 执行 make menuconfig 的时候,这些脚本就会被运行,去查找 目录里面的 kconfig 文件,

        security : 安全的模块

        sound : ALSA 音频驱动核心代码,以及常用取用核心代码。

        usr : 实现打包、压缩 等

    二、内核的编译以及加载

    2.1、Linux内核的编译

        编译内核的时候,一般是需要对内核进行配置,一般的指令有:

    make config    // 基于文本,最古董级别的方式
    make menuconfig   // 文本菜单,还有图形界面
    make xconfig    // 基于 QT
    make  gconfig   // 基于 GTK

        所以, xconfig 和 gconfig 是依赖 QT 或者 GTK 实现的,所以一般是使用 make menocinfig

        当执行 make menuconfig 之后,内核的脚本(scripts) 就会去内核的目录,根获取Kconfig 文件 里面的配置信息, 多个层级目录的 kconfig 文件就组成了:

    image

         可以,通过  space 去选择,是否编译进内核,还是编译为模块、更或者是不编译。

        当执行完 make menuconfig 的时候,就会在顶层生成 .config(隐藏文件),它 是整个 Linux 所有的配置信息(记录了那些驱动要编译进内核,还是模块),

        编译的: make  zImage ,的时候,顶层的 MakeFile 就会更具 .config 记录的信息,去编译。 注意到  Linux 顶层 还有 Kbuild 文件,因为  Linux 是借助 Kbuild 完成这个系统的编译,这个知识点以后学习。

    2.1.1、Kconfig 学习

         Kconfig 文件,记录了make menuconfig 时候,用来配置内核,当前目录下的配置信息,就全记载在当前的 Kconfig 文件里面,以后自己添加驱动的时候,就要修改这一些。

        Kconfig 学习: 可以参考内核提供的参考资料,“Documentation/kbuild/kconfig-language.txt”,

    (1)基本菜单的实现

    menu "S3C2440 Machines"
    config SMDK2440_CPU2440
        bool "SMDK2440 with S3C2440 CPU module"
        depends on ARCH_S3C2440    
        select    XXXXXX
        default y if ARCH_S3C2440    
        select CPU_S3C2440
    config MACH_MINI2440
        bool "MINI2440 development board"
        select CPU_S3C2440
        select EEPROM_AT24
        select LEDS_TRIGGER_BACKLIGHT
        select SND_S3C24XX_SOC_S3C24XX_UDA134X
        help
          Say Y here to select support for the MINI2440. Is a 10cm x 10cm board available via various sources. It can come with a  3.5" or 7" touch LCD.
    
    endmenu

        menn xxxxxxxx endmenu  : 实现菜单定制的功能,make menuconfig 显示的菜单,就是使用者这样的命令实现的

        config SMDK2440_CPU2440 : config 是关键字,表示一个配置选项,其实是默认缺少了 CONFIG_, 全文的配置是 CONFIG_SMDK2440_CPU2440,

        bool "SMDK2440 with S3C2440 CPU module" : 

                 bool ,是类型,一般是 Y 和 N,

                 tristate变量的值:y、n和m

                  string变量的值:  字符串

        也就是实现将当前的模块(SMDK2440 with S3C2440 CPU module) 编译进内核,还是以模块的形式存在,"SMDK2440 with S3C2440 CPU module" 表示 配置界面显示的信息(显示的菜单),可以在当前行 按住 空格键,进行选取,其实也是可以通过 prompt 实现 :

    bool
    prompt  “SMDK2440 with S3C2440 CPU module”

        depends on ARCH_S3C2440 : depends on 是关键字,也就是 当前的配置,是依赖于 ARCH_S3C2440 ,只有当 ARCH_S3C2440 被选中的时候,当前才会显示配置信息。

        default y if ARCH_S3C2440 : default 和 if 是关键字,也就是默认的状况下是 “y”,也就是选中,编译进内核;同时,需要 ARCH_S3C2440  被选中,其实这个 if 条件,也是可以没有的。

        select CPU_S3C2440 : select ,反依赖,也就是当当前的配置信息被选上的时候,那么这个反依赖 CPU_S3C2440 ,也会被选上,

        help : 关键字,帮助信息,

    (2)依赖菜单的实现

        依赖菜单的实现,是如果后面的菜单依赖于前面的菜单的话,那么后面的就是前面菜单的子菜单,如果 父菜单设置为 y 的话,那么后续的子菜单就都是可见的;当父菜单是 n 的时候,,子菜单就是被隐藏。

    config    parent-caidan
        bool    “ enable load XXX”
    
    
    config   child-caidan
        depends on parent-caidan

        只有当 parent-caidan 被选上的时候,child-caidan 菜单选项才会被显示出来,以供选择。

    (3)choice 条目

        以多个条目的方式显示出来,以供用户的选择。

    choice
    xxxxx
    xxxx
    xxxx
    endchoice

    例子:

    choice
    prompt “choice list”
    config   aaaaaa
        bool
        prompt “xxxxxxxxx” 
        help “xxxxx”
    
    config    bbbbb
        bool
        prompt  “xxxxx”
        help “xxxxxx”
    endchoice

        当 光标选中 “choice list” 菜单之后,enter 之后,就会出现 aaa 和 bbb 的两个菜单,以供选择使用。

    (4)引入下级目录的 Kconfig

    source   ” /绝对路径/Kconfig“

      这样就引入了新的 Kconfig文件

      

    2.1.2、MakeFile 学习

       主要介绍了子目录下的kbuild MakeFile进行基本的介绍,因为子目录的 MakeFile 和kconfig 才需要程序要去改动。

    (1)单个目标编译

        将指定的目标文件编译进去内核,或者是模块的形式,文件是 test.c

    obj-y += test.o
    
    obj-m +=test.o

    (2)多文件模块

        一个模块 qqq,由多个文件,比如 test1.c、test2.c、test3、c

    obj-$(CONFIG_QQQ) += qqq.o
    qqq-y := test1.o test2.o test3.o

        编译模块 QQQ,是在 Kconfig 里面被配置过的话,当配置菜单设置为 y 的时候,那么,就会将 qqq.o 编译进内核,而模块包含了 test 三个文件,所以会江北test0.o、test1.o、test2.o v 编译进去 qqq 模块。

    (3)目录层次的问题

        当 MakeFile 文件需要编译下层的文件的时候,那么

    obj-$(CONFIG_QQQ) += qqq/

        当 CONFIG_QQQ 在菜单被设置为 y 或者 m 的时候,kbuild 就会把 qqq 目录列入到向下迭代的目标当中,也就是后续会继续进行 MakeFile。

    2.1.3、自己添加驱动代码目录和子目录

        假如要遭 /driver 目录为 arm 添加 test 驱动,添加的目录如下:

    2

        test 目录是在 /driver 目录下,添加新的目录和子目录,因此都需要添加 MakeFile和 Kconfig 文件。而 test 目录下新增的了 MakeFile 和 Kconfig 了,它的父目录必须做一些修改,使得后续添加的 Kconfig 和  MakeFile 能被引用。

    (1)新增 test 目录下的 Kconfig:

    menu "TEST DRIVER"
    
    config TEST
        bool "test support"
        defatly n
    config TEST_FOR_USER
        bool "test for user interface"
        depends on CONFIG_TEST
    
    endmenu

        创建 TEST_DRIVER 菜单,菜单里面有 test support 和 test for user interface 两个菜单选项,等待用户的选择,当 test support 被选为 y 的时候,test for user interface 才会显示出来。

    (2)修改 arch/arm/Kconfig

        为了使得这个 Kconfig 能起作用,就要 修改 arch/arm/Kconfig 文件,对 arch/arm/Kconfig 增加:

    source "drivers/test/Kconfig"

        也就是说,这个 source 使用新的 Kconfig 可以被引用。这样,自己定义的 Kconfig 文件,正式生效。、

    (3)test 目录下增加 MakeFile 文件

         test 目录下的 MakeFile文件,实现对当前目录文件的指导编译,和下一个目录下的文件编译:

    # /driver/test/Makefile
    
    obj-$(CONFIG_TEST)  +=  test.o test_client.o test_queue.o 
    obj-$(CONFIG_TEST_USER)  +=  test_ioctl.o
    
    obj-$(CONFIG_TEST_CPU)  += cpu/

        当在菜单选中 CONFIG_TEST 为 y 或者 为 m 的时候,就会编译后面指定的文件,后面的也是一样。因为砸他 test 目录下,是还有 CPU 子目录的,我们设定的时候,这个是为 arch/arm 下设定的平台驱动,所以假定 CONFIG_TEST_CPU 在其他地方被设置之后,就会编译 CPU 这个子目录。

    (4)cpu 子目录也是需要添加 MakeFile 文件

        只需要添加 MakeFile 指导编译文件就可以,不用添加 KCconfig 文件,因为这个选项是假定 arm 下面的结构CONFIG_TEST_CPU 被选中之后,就会跳转到 CPU 目录下进行编译;而不是通过 menuconfig 界面,指定编译。

    MakeFile 文件如下,

    # /driver/test/CPU/Makefile
    
    obj-$(CONFIG_TEST_CPU)  += cpu.o

    (5)test 的父母的 MakeFile 添加脚本

        test 下添加了 MakeFile文件,问了使这个MakeFile 文件生效,所以需要在 test 的父目录,也就是 driver 目录下的 MakeFile 文件,添加脚本。

    # /driver/MakeFile
    
    obj-$(CONFIG_TEST) += test/

        通过在父母路添加的这句脚本,使得父目录的 MakeFile 遍历 MakeFile 的时候,就会走进 test 进行编译,使得 test MakeFile 生效。

        因此,全新的生成的文件目录结果是:

    3

    三、内核的编码风格

        Linux 的编码风格 ,和一般的 window 风格不一样,这些风格是在 document /CodingStyle 文件里面,有比较详细的描述。

    3.1、命名风格的差异

        在window 中,一般是这样方式命名宏、变量和函数

    #define PI 3.1415926
    int minValue, maxValue;
    void SendData();

          宏代码上,使用全部大写的方式;而变量,第一个单词是全部小写,后面单词的第一个字母是大写;函数则所有的单词第一个字母,都是大写。

        在 Linux 中,则是这样命名:

    #define PI 3.1415926
    int min_value, max_value;
    int send_data();

        可见,在宏命令是是一样的,都是大写。但是在变量和函数命名上,下划线是大行其道,而且,也不再用字母的大写。

    3.2、括号

        缩进使用的是 TAB ,而 {} 使用的原则如下,

    (1)对于结构体、if、for、while、switch,{ 不另起一行,比如

    struct var_data {
        int data;
            char data[10];
    }
    
    if (a  ==  b){
        a = c;
        d = a;
    }  // 当 if 后面之后一行的时候,就不要爱括号了
    
    for (i = 0; i < 10; i++ ){
        XXXX;
        XXXX
    }    //  for 西面只有一行代码的时候,就不要括号了

        显然,在 if、for、while、switch 后面,是马上接的空格。

        同时,else 是不另起一行的,

    if (){
        XXX
        XXX
    }  else  {
        XXXXX
        }

        但是,函数的括号,一直都是另起一行的,

    int  add(int a,  int b)
    {
        XXX
        XXX
    }

    (2)switch 与 case 对于

    switch (*buf) {
    case 0 :
        XXXX;
        break;
    case 1;
        xxxx
        brea;
    
    default :
        break;
    }

    (3)代码的检查

       为符合Linux 内核对编码的风格,内核的 scripts/checkpatch.pl 提供了检查代码风格的脚本,

    chmod a+x  checkpatch.pl
    
    ./checkpatch.pl --no-tree -file /路径/1.c

        这里需要注意两个命令,一个是 –no-tree 和 - file,

    -file  :  指定文件,
    --no-tree : 修改路径,因为 checkpatch.pl 默认都是从顶层的目录开始,当使用这个命令的时候,就可以从任意的目录,进行代码风格的校验

       所以,针对下面代码进行校验:

    for(i = 0; i< 10; i++)
    {
        i++;
        i++;
    }
    
    执行命令:
    ./checkpatch.pl --no-tree -file /work/nfs_root/1.c 
    结果为:
    
    #12: FILE: 1.c:12:
    +    for(i = 0; i< 10; i++)
    +    {
    
    ERROR: spaces required around that '<' (ctx:VxW)
    #12: FILE: 1.c:12:
    +    for(i = 0; i< 10; i++)
                     ^
    
    ERROR: space required before the open parenthesis '('
    #12: FILE: 1.c:12:
    +    for(i = 0; i< 10; i++)
    
    total: 3 errors, 0 warnings, 20 lines checked
    
    1.c has style problems, please review.  If any of these errors
    are false positives report them to the maintainer, see
    CHECKPATCH in MAINTAINERS.
    可见,将上面的错误的代码风格都找了出来。
  • 相关阅读:
    浴谷夏令营2017.8.1数论的整理
    BZOJ1483: [HNOI2009]梦幻布丁
    NOIP2014-11-3模拟赛
    BZOJ3884: 上帝与集合的正确用法
    BZOJ4869: [Shoi2017]相逢是问候
    计蒜客NOIP2017提高组模拟赛(三)day1
    NOIP2014-9-6模拟赛
    NOIP2014-7-7模拟赛
    zoj Little Keng(快速幂)
    多校Key Set (快速幂)
  • 原文地址:https://www.cnblogs.com/qxj511/p/5452398.html
Copyright © 2020-2023  润新知