58.linux 内核 编译及调试
一.linux内核基本概念
1. linux 内核 和 linux 操作系统的区别
- linux 内核 : 通常指的是由官网下载下来的源码 编译出来的 uImage 或者 zImage 镜像
启动中包含的由 硬件抽象层、文件系统、进程调度、网络管理、驱动管理、内存管理(多任务)等功能。
- 通常我们使用的 linux 系统 是指: 像 Ubuntu 等操作系统。 包含linux 内核, 工具集,各种第三方库,
图形界面,应用程序的一个发布包(发行版)
2. linux 内核特性
- 免费开源
- 可移植性 支持广泛的硬件平台 //arm ppc mips x86...
- 扩展性
- 软硬件可裁剪
- 高可靠性、稳定性
- 网络功能强大
- 多任务、多用户系统
- 模块化设计
3. linux 内核版本
采用 A.B.C.D
A 主版本号
B 次版本号 为偶数表示 稳定版本 奇数为开发中版本
C 表示linux的发行版本号
D 表示更新版本号
4. linux 内核包含的五大功能:
- 进程管理
- 内存管理
- 文件系统
- 网络协议
- 设备驱动管理
linux 不会是一个真正的实时系统 (时间片轮转方式)
vxwork 是一个真正的实时(RTOS )系统 收费
5. linux 分层
应用程序
||
\/
系统调用
||
\/
linux 内核 分为 平台无关 和 平台相关码
||
\/
硬件平台
6.
linux 内核 下载地址 https://www.kernel.org/
linux 各个版本下载地址 https://www.kernel.org/pub/linux/kernel/
编译内核 make uImage
编译设备树 make dtbs
二 .内核的编译
1.注意要把 linux源码 拷贝到 Ubuntu中 解压, 不要在共享文件夹直接解压
因为 源码中会有一些软件链文件, 这些文件,windows文件系统 不能识别
2. 解压命令 tar -xvf ***.tar.xz
3. 配置交叉编译工具链:
方法一:export PATH=/自己的路径/gcc-4.6.4/bin:$PATH //临时有效
方法二:写到启动脚本中 /etc/profile 或者 .bashrc
4. 修改 源码顶层目录的 Makfile
ARCH ?= arm
CROSS_COMPILE ?= arm-none-linux-gnueabi-
5.
注:设备树: 用于描述硬件设备信息。 低版本内核的设硬件备信息,是存放在linux源码中的, 高版本是写到 设备树文件中
如果想启动内核,还需要配置一下网络 ,可以看前几节的内容。
三.内核目录结构
四.内核的启动过程
a. 自解压 decompess (arch/arm/boot/compressed/head.S) 汇编
b. 运行内核汇编部分 head.S 入口stext (arch/arm/kernel/head.S)
检测合法性(CPU 类型,机器类型)
c. 运行 C代码 start_kernel (init/main.c)
CPU,机器参数的安装 setup_arch
中断,定时,终端,内存等最基本的初始化
创建核心进程 kernel_init运行,启动多任务调度
d. 挂载 rootfs
e. . 运行第一个应用程序init (一般是 linuxrc)
五. 内核调试方法
1. 汇编阶段 点灯法
2. puts(内核解压前)
3. printascii (console 初始化前)
4. printk (内核解压后,信息输出显示到console初始化之后)
打印级别 /proc/sys/kernel/printk
#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_INFO “ \n INFO Level \n”);
通过proc在运行时查看和修改日志级别
cat /proc/sys/kernel/printk 显示 4 4 1 7
echo “7 4 1 7” > /proc/sys/kernel/printk 后
cat /proc/sys/kernel/printk 显示7 4 1 7
5.OOP内核异常信息
例:
1. 制造错误
修改drivers/char/fs4412_led_drv.c
在s5pv210_led_init函数中int ret=0;下增加下面语句: int *ptr = NULL; *ptr = 0xff;
2. 运行该内核报错
[ 1.165000] Unable to handle kernel NULL pointer dereference at virtual address 00000000
[ 1.170000] pgd = c0004000
[ 1.175000] [00000000] *pgd=00000000
[ 1.175000] Internal error: Oops: 805 [#1] PREEMPT SMP ARM
[ 1.180000] Modules linked in:
[ 1.185000] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.14.0 #25
[ 1.190000] task: ee8a0000 ti: ee8a4000 task.ti: ee8a4000
[ 1.195000] PC is at s5pv210_led_init+0x18/0x180
[ 1.200000] LR is at do_one_initcall+0x30/0x144
[ 1.205000] pc : [<c024225c>] lr : [<c00087b4>] psr: 60000153
[ 1.205000] sp : ee8a5ef8 ip : c059afac fp : 00000000
[ 1.215000] r10: c052d4fc r9 : c0564b80 r8 : c0242244
[ 1.220000] r7 : c05a3400 r6 : c055134c r5 : 00000000 r4 : ee8a4000
[ 1.230000] r3 : 00000055 r2 : c04c0430 r1 : 00000001 r0 : 1f400000
[ 1.235000] Flags: nZCv IRQs on FIQs off Mode SVC_32 ISA ARM Segment kernel
[ 1.245000] Control: 10c5387d Table: 4000404a DAC: 00000015
[ 1.250000] Process swapper/0 (pid: 1, stack limit = 0xee8a4240)
[ 1.255000] Stack: (0xee8a5ef8 to 0xee8a6000)
3. 找出错位置
根据PC is at s5pv210_led_init+0x18/0x180 知道出错的函数是s5pv210_led_init
根据pc : [<c024225c>] 知道出错的位置
#arm-none-linux-gnueabi-addr2line c024225c -e vmlinux -f 在源码中会显示具体出错的位置(利用小工具)