Linux内核配置编译及基本调试方法
一、Linux内核配置编译
1. 交叉编译设置:make ARCH=arm CROSS_COMPILE=arm-linux-
注:也可以直接修改顶层Makefile
ARCH ?= arm
CROSS_COMPILE ?= arm-linux-
2. 加载默认设置:make mini2440_defconfig
① make mini2440_config: 将arch/arm/configs目录下的mini2440_defconfig文件复制为.config
② make menuconfig: 对内核默认配置进行调整
3. 编译内核
① make zImage
② make modules
③ make uImage(uImage是在zImage基础上加了64Bytes的头信息)
④ make bzImage(内核最终镜像大于512KB)
4. 安装内核:
make install
make modules_install
5. 内核配置系统由以下3部分组成
① Makefile:
② Kconfig:
③ 配置工具:
注:使用make config、make menuconfig等命令后,内核顶层目录生成一个“.config‘’配置文件,该文件记录模块是否编译进内核、或者编译成模块
6. 运行make menuconfig时,配置工具首先分析与体系结构对应的arch/<arch>/Kconfig文件,该文件除本身包含一些与体系结构相关的配置项和配置菜单外,还通过sourse语句引入下一层的Kconfig文件
7. 在make menuconfig界面中选择“config ARCH_S3C2410”选项后内核会在配置文件".config"中添加
CONFIG_ARCH_S3C2440=y
同时在include/config目录中生成由.config得来的配置文件auto.conf,以及在include/linux目录中以C语言头文件给出的配置文件autoconf.h
8. 执行make zImage等生成内核镜像命令时,首先执行顶层Makefile,顶层Makefile又通过include指令导入特定体系架构或子目录中的Makefile
① 顶层Makefile:
include $(srctree)/arch/$(SRCARCH)/Makefile
② arch/arm/Makefile:
machine-$(CONFIG_ARCH_S3C2410) := s3c2410 s3c2400 s3c2412 s3c2440 s3c2442 s3c2443
③ machine-y用于定义machdirs变量
machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y))
④ machdirs通过下面语句添加到core-y中(cory-y表示内核需要编译的核心文件)
cory-y += $(machdirs) $(platdirs)
9. 向内核中添加新的功能的步骤
① 将编写的源代码复制到Linux内核源代码相应目录
② 在目录的Kconfig文件中增加新源代码对应项目的编译配置选项
③ 在目录的Makefile文件中增加对新源代码的编译条目
10. 向内核中添加RTC驱动:
① 在drivers/rtc中包含S3C24XX处理器的RTC驱动源代码rtc-s3c.c
② 在drivers/rtc目录的Kconfig文件中包含RTC_DRV_S3C的配置项目
config RTC_DRV_S3C
tristate "Samsung S3C series SoC RTC"
depends on ARCH_S3C2410
help
RTC (Realtime Clock) driver for the clock inbuilt into the
Samsung S3C24XX series of SoCs. This can provide periodic
interrupt rates from 1Hz to 64Hz for user programs, and
wakeup from Alarm. The driver currently supports the common features on all the
S3C24XX range, such as the S3C2410, S3C2412, S3C2413, S3C2440
and S3C2442. This driver can also be build as a module. If so, the module
will be called rtc-s3c.
③ 在drivers/rtc目录的Makefile文件中添加关于RTC_DRV_S3C的条目
obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
11. 内核中的Makefile
① 目标定义:目标定义用来定义哪些内容要作为模块编译,哪些要编译进内核
obj-y += foo.o
更常见的做法是根据auto.conf文件的CONFIG_变量来决定文件的编译方式,例如
obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
② 多文件模块的定义:如果一个模块由多个文件组成,就应该采用模块名加-objs后缀或者-y后缀的形式来定义模块的组成文件。
obj-$(CONFIG_RTC_CLASS) += rtc-core.o
rtc-core-y := class.o interface.o
多文件模块定义也可以按照下面的格式,
obj-$(CONFIG_ISDN) += isdn.o
isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o
③ 目录层次迭代:当CONFIG_EXT3_FS的值为y或m时,内核构建系统会将ext3目录列入向下迭代的目标中
obj-$(CONFIG_EXT3_FS) += ext3/
12. 内核中的Kconfig
① Kconfig的语法比较丰富,按功能可分为配置选项描述语句和菜单结构描述语句
② 配置选项描述:
(1)“config”关键字定义新的配置选项,之后的几行定义该配置选项的属性
(2) 配置选项的属性包括类型、数据范围、输入提示、依赖关系、帮助信息和默认值
(3) 每个配置选项都必须指定类型,类型包括bool、tristate、string、hex和int。其中,tristate和string是两种基本类型,其他都是基于这两种基本类型。
(4) 输入提示的一般格式:
prompt <prompt> [if <expr>]
(5) 默认值的一般格式:
default <expr> [if <expr>]
(6) 依赖关系的格式:
depend on(requires) <expr>
(7) 选择(反向依赖)的格式:
select <symbol> [if <expr>]
(8) 数据范围的格式:
range <symbol> <symbol> [if <expr>]
(9) 帮助信息格式如下:
help(---help---)
(10) 一个简单的配置选项示例
config MODVERSIONS
bool
prompt "Set version infomation on all module sysbols"
help
Usually, modules have to be recompiled whenever you switch to a new kernel③
③ 菜单结构
(1)一般菜单结构由menu......endmenu描述
menu "Network device support"
depends on NET
config NETDEVICES
...
endmenu
注:所有处于“menu”和“endmenu”之间的菜单入口都会成为“Network device support”的子菜单,而且所有子菜单入口都会继承父菜单的依赖关系。
(2)通过分析依赖关系生成菜单结构
config MODULES
bool "Enable loadable module support" config MODVERSIONS
bool "Set version information on all module symbols"
depend on MODULES
(3)除此之外,Kconfig中还可能使用“choices...endchoices”、“comment”、“if...endif”这样的语法结构
二、Linux内核调试技术
1. 源码级别的调试接口
① BUG()和BUG_ON():当调用BUG()时,内核通过调用panic()引发OOPS,导致函数调用栈的回溯和打印错误信息。
#ifndef HAVE_ARCH_BUG
#define BUG() do { \
printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
panic("BUG!"); \
} while ()
#endif #ifndef HAVE_ARCH_BUG_ON
#define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while(0)
#endif
注:内核还提供了WARN()和WARN_ON()用于警告作用。
② dump_stack():打印寄存器上下文和函数的跟踪线索。
if (!consistent_pte[]) {
printk(KERN_ERR "%s: not initialised\n", __func__);
dump_stack();
return NULL;
}
③ printk()内核格式化打印函数。
(1)几乎在任何地方、任何时候内核都可以调用它(中断上下文、进程上下文、持有锁时、多处理器处理时等)。
(2)在系统启动过程中和终端初始化之前无法调用。可以用以下方法打印调试信息:
* 通过底层调试接口,将调试信息输出到串口等输出设备(Kernel low-level debugging functions)
* 使用early_printk()
④ printk_ratelimit():限制输出速率
(1)printk_ratelimit()的典型用法
if(printk_ratelimit())
printk(KERN_NOTICE "The printer if still on fire\n");
(2)printk_ratelimit()的返回值取决于两个因素,分别定义于以下两个文件
* /proc/sys/kernel/printk_ratelimit
* /proc/sys/kernel/printk_ratelimit_burst
例如:printk_ratelimit = 5、 printk_ratelimit_burst = 10表示每打印10次就会有5s不会向控制台输出。
2. 使用printk()打印调试信息
① 日志等级
(1)printk()和printf()一个主要区别就是前者可以指定一个日志等级
#define KERN_EMERG "<0>" /* system is unusable */
#define KERN_ALERT "<1>" /* action must be taken immediately */
#define KERN_CRIT "<2>" /* critical conditions */
#define KERN_ERR "<3>" /* error conditions */
#define KERN_WARNING "<4>" /* warning conditions */
#define KERN_NOTICE "<5>" /* normal but significant condition */
#define KERN_INFO "<6>" /* informational */
#define KERN_DEBUG "<7>" /* debug-level messages */
注:如果调用者未将日志等级提供给printk,系统就使用默认值:KERN_WARNING "<4>"
(2)/proc/sys/kernel/printk文件定义了当前使用的日志等级,4个数字分别表示控制台日志级别、默认消息日志级别、最小控制台日志级别和默认控制台日志级别。
/Test/TestOops # cat /proc/sys/kernel/printk
注:修改printk的值可以用如下命令
echo > /proc/sys/kernal/printk
② 日志缓冲区
(1)内核消息被保存在一个LOG_BUF_LEN大小的环形队列中。
(2)日志缓冲区的特点:
* 消息被读出到用户空间,此消息就从环形队列中删除
* 当消息缓冲区满时,再有printk()调用时,新消息将覆盖队列中的老消息
* 在读写环形队列时,同步问题很容易解决
③ syslogd/klogd
④ dmesg
⑤ 注意事项
(1)虽然printk()很健壮,但效率很低
(2)printk()的临时缓存printk_buf只有1KB,所以printk()函数一次只能记录小于1KB的信息到日志缓冲区,并且使用时注意是环形缓冲区。
3. 使用strace跟踪系统调用
① strace命令常用来跟踪进程执行时的系统调用和接受的信号
4. 使用OOPS调试系统故障
Linux内核配置编译及基本调试方法的更多相关文章
- Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装
原文:Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装 Linux内核分析(一) 从本篇博文开始我将对linux内核进行学习和分析,整个过程必将十分艰辛,但我会坚持到底 ...
- Linux内核@系统组成与内核配置编译
Linux系统由什么组成? 由用户空间(应用程序+GNU C标准库)和内核空间(系统调用接口+内核+内核架构代码)组成. Linux内核到底是什么?以及组成. ARM的七种操作级别? 内核网络协议栈( ...
- Linux 内核配置和编译
Linux 内核配置和编译 一.配置内核 (1). 为什么要配置内核 1. 硬件需求 2. 软件需求 选出需要的,去掉不要的 (2). 如何配置内核 1. make config 基于文本模式的交互 ...
- 【Linux内核】编译与配置内核(x86)
[Linux内核]编译与配置内核(x86) https://www.cnblogs.com/jamesharden/p/6414736.html
- linux内核空间与用户空间信息交互方法
linux内核空间与用户空间信息交互方法 本文作者: 康华:计算机硕士,主要从事Linux操作系统内核.Linux技术标准.计算机安全.软件测试等领域的研究与开发工作,现就职于信息产业部软件与 ...
- Linux内核配置浅析
1.Linux Kernel Kconfig系统的基本结构 Linux内核的配置系统由三个部分组成,分别是: 1>.Makefile:分布在 Linux 内核源代码根目录及各层目录中,定义 Li ...
- Linux内核配置机制(make menuconfig 、Kconfig、Makefile)讲解【转】
本文转载自:http://www.codexiu.cn/linux/blog/34801/ 前面我们介绍模块编程的时候介绍了驱动进入内核有两种方式:模块和直接编译进内核,并介绍了模块的一种编译方式—— ...
- 【转】 Linux内核中读写文件数据的方法--不错
原文网址:http://blog.csdn.net/tommy_wxie/article/details/8193954 Linux内核中读写文件数据的方法 有时候需要在Linuxkernel--大 ...
- Linux 内核配置机制(make menuconfig、Kconfig、makefile)讲解
前面我们介绍模块编程的时候介绍了驱动进入内核有两种方式:模块和直接编译进内核,并介绍了模块的一种编译方式--在一个独立的文件夹通过makefile配合内核源码路径完成 那么如何将驱动直接编译进内核呢? ...
随机推荐
- Postman学习宝典(二)
文章来源于:米阳MeYoung Postman 入门2 - Script.Runner 上次Postman 入门1 我们介绍全局变量和环境变量时已经使用过Tests 和 pre-request scr ...
- 学习Echarts:(二)异步加载更新
这部分比较简单,对图表的异步加载和更新,其实只是异步获取数据然后通过setOption传入数据和配置而已. $.get('data.json').done(function (data) { myCh ...
- SSH三大框架知识点
Hibernate ****************************************************************************************** ...
- Sql Server数据库导入Excel、txt数据详解,新人必看
转自个人原创 https://blog.csdn.net/qq_15170495/article/details/104591606 数据库的要想导入数据,列的映射很是关键,只有列名匹配好,系统才知道 ...
- 201771010128王玉兰《面向对象程序设计(Java)》第十三周学习总结
第一部分:基础理论知识 1.事件处理基础 事件源(event source):能够产生事件的对象都可 以成为事件源,如文本框.按钮等.一个事件源是一个 能够注册监听器并向监听器发送事件对象的对象. 事 ...
- UVALive3720
题目大意:见刘汝佳<算法竞赛入门经典——训练指南>P173. 解题思路: 问题可以转化为求共有多少条过点阵中的点的斜线.其中必定包含左斜线和右斜线,由于点阵式对称的,所以我们只需求出左右斜 ...
- python_Excel_xlwt
xlwt 创建excel,向excel写入数据,并保存数据 安装 推荐方法: 通过pip 安装,方便简洁,如下图所示: 导入 import xlrd 创建workbook(即excel) book = ...
- SpringBoot系列——状态机(附完整源码)
1. 简单介绍状态机 2. 状态机的本质 3. 状态机应用场景 1. 简单介绍状态机 状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调相关信号动作.完成特定 ...
- DQN(Deep Q-learning)入门教程(三)之蒙特卡罗法算法与Q-learning算法
蒙特卡罗法 在介绍Q-learing算法之前,我们还是对蒙特卡罗法(MC)进行一些介绍.MC方法是一种无模型(model-free)的强化学习方法,目标是得到最优的行为价值函数\(q_*\).在前面一 ...
- 5.List链表类型介绍和操作
数据类型List链表 (1)介绍 list类型其实就是一个双向链表.通过push,pop操作从链表的头部或者尾部添加删除元素.这使得list既可以用作栈,也可以用作队列. 该list链表类型应用场景: ...