Linux內核分析筆記:https://blog.csdn.net/weixin_39148042/article/details/82494809
Linux內核分析
1、基本概念
2、啓動分析
3、調試方法
Linux內核基本概念
Linux內核:
• 從技術上說 linux 是一個內核
• “內核”指的是一個提供硬件抽象層、磁盤及文件系統控制、多任務等功能的系統軟件。一個內核不是一套完整的操作系統。
• 通常我們使用的 linux 系統是一個集 linux 內核、工具集、各種庫、桌面管理器、應用程序等一體的一個發佈包 (發行版)
主流的 Linux 發行版:
Debian GNU/Linux
Red Hat Linux
Fedora Core
Ubuntu Linux
SUSE Linux
Gentoo Linux
Asianux
Slackware Linux
Turbo Linux
CentOS
Linux 內核的特性:
• 免費開源
• 可以移植,支持的硬件平臺廣泛
arm, i386, m68k, m32r,m68knommu, mips, ppc, s390, sh, sparc
• 高可擴展性
‐ 可剪裁、可擴展,可以運行在大型主機,也可以運行在個人計算機上
• 高可靠性、穩定性
‐ 穩定性是linux鮮明特點,安裝了linux系統的主機,
‐ 連續運行一年不宕機是很平常的事情
• 超強的網絡功能
• 真正的多任務,多用戶系統
• 模塊化設計
‐ 模塊可以動態加載,卸載,可以減少系統體積,同時可以用來解決衝突問題,模塊調試
Linux內核版本:
• 目前linux系統採用 A.B.C.D 的版本號管理方式
– A 表示linux的主版本號
– B 表示linux的次版本號,B 爲偶數表示穩定版本,奇數表示開發中的版本
– C 表示linux的發行版本號
– D 表示更新版本號
• 主版本(X.Y)
– 1.0 2.0 2.2 2.4 2.6 3.x
Linux內核子系統:
進程管理
內存管理
文件系統
網絡協議
設備管理
Linux內核模塊結構圖:
編譯內核(已移植好的):
• 編譯內核 make uImage
• 編譯設備樹 make dtbs
Linux內核代碼結構:
Linux系統源代碼目錄結構:
Linux內核啓動分析
嵌入式系統啓動信息分析:
• u-boot啓動階段
U-Boot 2013.01 (Aug 24 2014 - 12:01:19) for FS4412
CPU: Exynos4412@1000MHz
Board: FS4412
DRAM: 1 GiB
……Loading: *######################
Starting kernel ...
• linux內核啓動階段
Booting Linux on physical CPU 0xa00
Linux version 3.14.0 (david@ubuntu)
CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=10c5387d
Machine model: Insignal Origen evaluation board based on Exynos4412
IP-Config: Complete:
VFS: Mounted root (nfs filesystem) on device 0:10
• 根文件系統階段(可運行應用程序)
[root@farsight ]# ls
a.out dev lib mnt root sys usr
bin etc linuxrc proc sbin tmp va
嵌入式系統 啓動流程:
//階段一(彙編)
設置爲SVC模式,關閉中斷,MMU,看門狗
基本硬件設備初始化 //初始化時鐘,串口,flash,內存
自搬移到內存
設置好棧 跳轉到C階段
//階段二(C語言)
大部分硬件初始化
搬移內核到 內存
運行內核
內核啓動流程:
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)
Linux內核調試方法
內核調試方法 點燈法:
ldr r0, =0x11000c40 @GPK2_7 led2
ldr r1, [r0]
bic r1, r1, #0xf0000000
orr r1, r1, #0x10000000
str r1, [r0]
ldr r0, =0x11000c44
mov r1,#0xff
str r1, [r0]
內核調試方法 printk打印輸出信息:
puts (內核解壓前)
printascii (console初始化前)
printk (內核解壓後,信息輸出顯示是在 console 初始化之後)
通過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
– 打印級別:
#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”);
內核調試方法 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 在源碼中會顯示具體出錯的位置