Linux设备驱动开发之linux内核的编译和加载

linux内核的编译

对于设备驱动开发过程中,进行内核的编译是无法避免的。常用的编译步骤:

1.打开linux内核ide配置

make menuconfig

这个步骤是为了打开内核的图形化配置,主要是配置一些驱动模块和其他辅助模块。选择是否加入这些模块进入到内核映象中。下图为打开的配置界面:
Linux设备驱动开发之linux内核的编译和加载_第1张图片

这个配置界面里我们进行勾选模块的加入与否。等到我们配置完成后,选择保存退出。
然后进行编译内核和编译模块:

make zIamge  # 编译内核
make modules  # 编译模块

编译完成后生成的zIamge文件在arch/arm/boot目录下。我们把这个文件拷贝到目标板子上使用boot引导加载方式就可以成功运行刚刚编译好的内核了。
那么我们怎么配置这个图形界面呢?这个图形界面又是根据哪些文件中的信息获取的呢?

Kconfig

人们在编译内核之前会对内核模块进行一些裁剪,查缺补漏。每次查缺补漏时我们都要更改涉及模块木下的Makefile,这样很容易把Makefile搞坏掉,而且更改Makefile很麻烦。所以为了方便,便引入了Kconfig配置文件,我们直接在Kconfig文件上选择是否要哪个模块,不用再更改Makefile了。

应用实例:在内核代码中新增驱动代码目录和子目录

现在假设我们要在内核源代码中drivers目录下为ARM体系结构新增如下用于test driver的树形目录:

test
├── cpu
│   └── cpu.c
├── test.c
├── test_client.c
├── test_ioctl.c
├── test_proc.c
└── test_queue.c

现在我们的目标是把test里面的文件可以有选择的加入到内核的编译中。如何添加呢?
自然我们就想到了使用Makefile文件。没错,我们可以现在cpu文件夹中新建一个Makefile文件。现在Makefile文件有了,那么我们该怎么写这个文件呢?我们可以查看下Makefile的使用文档:

// Documentation/kbuild/makefiles.txt
 Example:
 133                 obj-y += foo.o
 134 
 135         This tells kbuild that there is one object in that directory,      named
 136         foo.o. foo.o will be built from foo.c or foo.S.
 137 
 138         If foo.o shall be built as a module, the variable obj-m is us     ed.
 139         Therefore the following pattern is often used:
 140 
 141         Example:
 142                 obj-$(CONFIG_FOO) += foo.o
 143 
 144         $(CONFIG_FOO) evaluates to either y (for built-in) or m (for      module).
 145         If CONFIG_FOO is neither y nor m, then the file will not be c     ompiled
 146         nor linked.

从上面截取的例子看,我们可以仿照例子的写法来添加Makefile文件内容。

  1 # drivers/test/cpu/Makefile
  2 #  
  3 # Makefile for test cpu
  4 #
  5 
  6 obj-$(CONFIG_TEST_CPU) += cpu.o

那么同理,我们继续在test目录下添加Makefile内容。在添加这个内容之前我们再看一个例子:

// Documentation/kbuild/makefiles.txt
 271         Example:
 272                 #fs/Makefile
 273                 obj-$(CONFIG_EXT2_FS) += ext2/
 274 
 275         If CONFIG_EXT2_FS is set to either 'y' (built-in) or 'm' (mod     ular)
 276         the corresponding obj- variable will be set, and kbuild will      descend
 277         down in the ext2 directory.

上述例子表明该层目录下的Makefile中如果想包含其子目录的文件,需要添加文件夹路径。
现在我们再写test目录下的Makefile。

  1 # drivers/test/Makefile
  2 #
  3 # Makefile for the TEST.
  4 #
  5 
  6 obj-$(CONFIG_TEST) += test.o test_queue.o test_client.o
  7 obj-$(CONFIG_TEST_USER) += test_ioctl.o
  8 obj-$(CONFIG_PROC_FS) += test_proc.o
  9 obj-$(CONFIG_TEST_CPU) += cpu/

好了,到现在为止我们已经添加完test目录及其子目录中Makefile的内容了。但是由于我们是按照例子写的,引用了一些符号(我理解为宏),这些符号的创建就要在另一个文件写了,是的,那就是Kconfig文件,接下来我们要在这个文件创建这些符号。
那么问题来了,我们该怎样在Kconfig文件中创建这些符号呢?依然老方法,看Kconfig的使用文档。

// Documentation/kbuild/kconfig-language.txt
206 Menu structure
207 --------------
208 
209 The position of a menu entry in the tree is determined in two ways. First
210 it can be specified explicitly:
211 
212 menu "Network device support"
213         depends on NET
214 
215 config NETDEVICES
216         ...
217 
218 endmenu
219 
220 All entries within the "menu" ... "endmenu" block become a submenu of
221 "Network device support". All subentries inherit the dependencies from
222 the menu entry, e.g. this means the dependency "NET" is added to the
223 dependency list of the config option NETDEVICES.

从这段文档我们可以发现,写这个Kconfig文件我们可以按照"menu" … "endmenu"这样一种书写格式来为内核图像配置界面提供一个菜单。然后在菜单的内部我们再创建上述Makefile中的还未定义的符号。

  1 # drivers/test/Kconfig
  2 #
  3 # TEST driver configuration
  4 #
  5 menu "TEST Driver"
  6 comment " TEST Driver"
  7 config CONFIG_TEST  # create a select option
  8         bool "TEST support "  # the type is "bool"  'y' or 'n'
  9 config CONFIG_TEST_USER  # create a select option
 10         tristate "TEST user-space interface"  # the type is "tristate"  'y' or 'n' or 'm'
 11         depends on CONFIG_TEST  # visible if the CONFIG_TEST is also visible. 
 12 config CONFIG_PROC_FS
 13         bool "TEST support proc fs "
 14         depends on CONFIG_TEST
 15 config CONFIG_TEST_CPU
 16         bool "TEST support cpu "
 17         depends on CONFIG_TEST
 18 endmenu

上面的代码就是Kconfig的配置代码。怎样解释这段代码呢?首先"menu" … "endmenu"结构我们前面提过了,是建立一个菜单的功能。然后“comment”…表示的是对这个菜单的注释说明的意思。剩下的解释在配置代码中就有说明了。
到现在为止,test目录下的Kconfig和Makefile都配置好了,test目录树如下:

test
├── cpu
│   ├── cpu.c
│   └── Makefile
├── Kconfig
├── Makefile
├── test.c
├── test_client.c
├── test_ioctl.c
├── test_proc.c
└── test_queue.c

现在呢我们再想一下,test目录下的文件最终都是要被编译的,所以为了找到这个路径下的文件,需要在test目录的上一层Makefile中添加test目录的路径:
在这里插入图片描述
最后呢我们再想一下,test目录下的Kconfig文件如何被识别呢?不知道的话依然老方法,查看使用文档:

// Documentation/kbuild/kconfig-language.txt
330 source:
331 
332         "source" <prompt>
333 
334 This reads the specified configuration file. This file is always parsed.

从上面的文档我们可以猜测,应该有一个更上层的Kconfig配置文件,在其里面通过source关键字来读取test目录下的Kconfig配置文件。这样的话test目录下的Kconfig文件才可以被识别,被加载到内核配置菜单中。
那么这个更上层的Kconfig在哪里呢?

// Documentation/kbuild/kconfig-language.txt
358 An example is the generic IOMAP functionality.
359 
360 We would in lib/Kconfig see:
361 
362 # Generic IOMAP is used to ...
363 config HAVE_GENERIC_IOMAP
364 
365 config GENERIC_IOMAP
366         depends on HAVE_GENERIC_IOMAP && FOO
367 
368 And in lib/Makefile we would see:
369 obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
370 
371 For each architecture using the generic IOMAP functionality we would s    ee:
372 
373 config X86
374         select ...
375         select HAVE_GENERIC_IOMAP
376         select ...

从这里的介绍我们可以看出一般放在arch目录下面。
这里我们以arm为例,选择arm目录下的Kconfig,打开这个文件,然后添加test目录路径代码:
Linux设备驱动开发之linux内核的编译和加载_第2张图片到现在为止,test目录下的文件可以完整的选择是否添加到内核中了。

linux内核的引导

引导Linux系统的过程包括很多阶段,这里将以引导ARM Linux为例来进行讲解。一般的SoC内嵌入了bootrom,上电时bootrom运行。对于CPU0而言,bootrom会去引导bootloader,而其他CPU则判断自己是不是CPU0,进入WFI的状态等待CPU0来唤醒它。CPU0引导bootloader,bootloader引导Linux内核,在内核启动阶段,CPU0会发中断唤醒CPU1,之后CPU0和CPU1都投入运行。CPU0导致用户空间的init程序被调用,init程序再派生其他进程,派生出来的进程再派生其他进程。CPU0和CPU1共担这些负载,进行负载均衡。
Linux设备驱动开发之linux内核的编译和加载_第3张图片

你可能感兴趣的:(linux设备驱动开发)