2、内核基本学习

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

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

 

    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 文件就组成了:

     可以,通过  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 驱动,添加的目录如下:

 

    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 生效。

 

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

 

三、内核的编码风格

    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.

可见,将上面的错误的代码风格都找了出来。

时间: 2024-10-08 09:47:50

2、内核基本学习的相关文章

linux内核数据结构学习总结(undone)

本文旨在整理内核和应用层分别涉及到的数据结构,从基础数据结构的角度来为内核研究作准备,会在今后的研究中不断补充 目录 1. 进程相关数据结构 1) struct task_struct 2. 内核中的队列/链表对象 3. 内核模块相关数据结构 2) struct module 1. 进程相关数据结构 0x1: task_struct 我们知道,在windows中使用PCB(进程控制块)来对进程的运行状态进行描述,对应的,在linux中使用task_struct结构体存储相关的进程信息,task_

Linux 内核list_head 学习

Linux 内核list_head 学习(一) http://www.cnblogs.com/zhuyp1015/archive/2012/06/02/2532240.html 在Linux内核中,提供了一个用来创建双向循环链表的结构 list_head.虽然linux内核是用C语言写的,但是list_head的引入,使得内核数据结构也可以拥有面向对象的特性,通过使用操作list_head 的通用接口很容易实现代码的重用,有点类似于C++的继承机制(希望有机会写篇文章研究一下C语言的面向对象机制

【转】linux 用户线程、LWP、内核线程学习笔记

[好文转发---linux 用户线程.LWP.内核线程学习笔记] 在现代操作系统中,进程支持多线程.进程是资源管理的最小单元:而线程是程序执行的最小单元.一个进程的组成实体可以分为两大部分:线程集合资源集.进程中的线程是动态的对象:代表了进程指令的执行.资源,包括地址空间.打开的文件.用户信息等等,由进程内的线程共享. 线程有自己的私有数据:程序计数器,栈空间以及寄存器. Why Thread?(传统单线程进程的缺点) 1. 现实中有很多需要并发处理的任务,如数据库的服务器端.网络服务器.大容量

Linux内核驱动学习(二)----根文件系统的构成 (root filesystem)

1.建立根文件系统目录和文件 1.1创建目录 1.2创建设备文件(命令mknod):必须创建设备文件---consle\null 1.3创建配置文件---复制已有的/etc目录下的文件 1.4添加内核模块 进入Linux内核目录下,(注意,应该先编译内核,即命令make uImage ARCH=arm  CROSS_COMPILE=arm-linux-) 1.4.1.编译内核模块---命令 make modules ARCH=arm CROSS_COMPILE=arm-linux- 1.4.2.

内核编程学习小结

The road to success was trial and error development, recompilation, and lots of crashes. 寒假过去一个月,计划很多时候也没法跟上.不过总体上来说,还是学习和收获了一些东西的.过去的事情不能改变,所以也不必过于纠结和懊悔.假期的前期还计划对英语进行系统性的学习,我个人任务是画错时间,用错力了,看专业英语的时间完全可以用开翻译与内核编程有关的开发文档,这样更有意义一些,在发现问题后也没办法放下,这是很不好的一个缺

linux内核驱动学习(八)----驱动分类 | 学习方法 | 硬件访问

驱动分类: 对于驱动,我们一般按两种方法进行分类:常规分类法和总线分类法. 按照常规分类法,可以分为以下三类: 1.字符设备: 以字节为最小访问单位的设备.一般通过字符设备文件来访问字符设备驱动程序.字符驱动程序则负责驱动字符设备, ,这样的驱动通常支持open.close.read.write系统调用,应用程序可以通过设备文件(比如/dev/ttySAC0等)来访问字符设备(串口).例如:串口\led\按键 2.块设备: 以块(一般512字节)为最 小传输单位的设备.大多数UNIX系统中,块设

linux内核驱动学习指南

目录: 1.参考链接 1. 参考链接 小白的博客 ONE_Tech 你为什么看不懂Linux内核驱动源码? 求教怎么学习linux内核驱动 原文地址:https://www.cnblogs.com/agui125/p/10071452.html

Linux内核驱动学习(三)----内核模块基础 | 设计 | 可选项

内核模块基础--特点及其命令使用 1.模块本身并不被编译进内核文件(zImage或bzImage) 2.可以根据需要在内核运行时动态加载.卸载---->进而达到节省空间的目的 命令详解(以下载驱动DNW为例): insmod 模块名称(注意有.ko后缀)--安装 insmod dnw_usb.ko lsmod-->查看安装的内核模块 rmmod 模块名称(注意没有.ko后缀)---->卸载内核模块 rmmod dnw_usb 内核模块设计--简单的模块编写 根据上图范例代码,比较应用程序

[linux内核]proc学习笔记(一)

1,在/proc文件系统下创建节点的APIhttp://www.cnblogs.com/ziziwu/archive/2011/10/20/2218975.html  struct proc_dir_entry *create_proc_entry (const char *name, mode_t mode, struct proc_dir_entry *parent);  其中参数分别是 /proc 文件名,掩码,父目录. [cpp] view plaincopy 32 struct pro