linux内核分析(ARMv8 Linux内核错误处理过程分析怎么解决)

:暂无数据 2025-08-23 14:40:01 0
各位老铁们好,相信很多人对linux内核分析都不是特别的了解,因此呢,今天就来为大家分享下关于linux内核分析以及ARMv8 Linux内核错误处理过程分析怎么解决的问题知识,还望可以帮助大家,解决大家的一些困惑,下面一起来看看吧!

本文目录

ARMv8 Linux内核错误处理过程分析怎么解决

1.1 Linux内核异常处理相关文件
Linux内核中,异常处理主要由两个文件完成,entry.S和traps.c,当然还有一些其它异常处理函数分布于fault.c, memory.c等等。entry.S包含异常的入口、进入异常处理C函数前的压栈、退出C函数前的出栈、一些fork函数相关的处理代码(暂不分析)、任务切换汇编处理过程(cpu_switch_to函数,暂不分析)。traps.c主要包含异常处理C函数。
本文主要分析entry.S,对于traps.c作简要介绍。
1.2 执行kernel_entry之前的栈
1.3 执行kernel_entry时的栈
1.4 执行kernel_exit 时的栈
1.5 entry.s代码分析
/*
* Low-level exception handling code
*
* Copyright (C) 2012 ARM Ltd.
* Authors:Catalin Marinas 《catalin.marinas@arm.com》
*Will Deacon 《will.deacon@arm.com》
*
* This program is **** software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
***隐藏网址***
*/
#include 《linux/init.h》
#include 《linux/linkage.h》
#include 《a**/assembler.h》
#include 《a**/a**-offsets.h》
#include 《a**/errno.h》
#include 《a**/thread_info.h》
#include 《a**/unistd.h》
#include 《a**/unistd32.h》
/*
* Bad Abort numbers
*-----------------
*/
#define BAD_SYNC0
#define BAD_IRQ1
#define BAD_FIQ2
#define BAD_ERROR3
//根据该结构体内容
/*
struct pt_regs {
union {
struct user_pt_regs user_regs;//结构体user_pt_regs和结构体pt_regs内容一样
struct {//共用体存储31个通用寄存器,外加sp,pc,pstate三个特殊寄存器
//该结构体用于异常处理的压栈弹栈操作
u64 regs;
u64 sp;
u64 pc;
u64 pstate;
};
};
u64 orig_x0;
u64 syscallno;
};
*/
//S_FRAME_SIZE定义在a**-offsets.c中,DEFINE(S_FRAME_SIZE,sizeof(struct pt_regs));
//即结构体pt_regs的大小,结构体pt_regs的定义见上面
//S_LR定义:DEFINE(S_LR,offsetof(struct pt_regs, regs));
//即31号寄存器在结构体pt_regs中的偏移量
//阅读以下内容请参考图1 和图2
.macrokernel_entry, el, regsize = 64
subsp, sp, #S_FRAME_SIZE - S_LR// room for LR, SP, SPSR, ELR,见图2中sp’指向的位置
.if\regsize == 32
movw0, w0// zero upper 32 bits of x0
.endif
/*
*.macropush, xreg1, xreg2//压栈两个寄存器
*stp\xreg1, \xreg2, !//注意!!!push指令也改变sp的值!!!
*.endm
*/
pushx28, x29//进行压栈操作,push也是一个宏定义,因为ARMv8没有push指令,用stp代替
pushx26, x27
pushx24, x25
pushx22, x23
pushx20, x21
pushx18, x19
pushx16, x17
pushx14, x15
pushx12, x13
pushx10, x11
pushx8, x9
pushx6, x7
pushx4, x5
pushx2, x3
pushx0, x1//此时sp指向位置见图2中sp’’
.if\el == 0//如果异常级是el0,把el0的sp栈指针给x21寄存器
mrsx21, sp_el0
.else
addx21, sp, #S_FRAME_SIZE//如果异常级不是el0,把sp指针指向的地方加上pt_regs大小后的地址放入x21,
//即指向没进入kernel_entry函数钱的sp指向的位置,见图2中x21指向的地址
.endif
mrsx22, elr_el1//把el1的lr寄存器给x22
mrsx23, spsr_el1//把spsr给x23
stplr, x21, //把lr,x21寄存器存入sp+S_LR指向的地方
stpx22, x23, //把lr,存入sp+s_PC指向的位置,用于异常返回
/*
* Set syscallno to -1 by default (overridden later if real syscall).
*/
.if\el == 0
mvnx21, xzr
strx21,
.endif
/*
* Registers that may be useful after this macro is invoked:
*
* x21 - aborted SP
* x22 - aborted PC
* x23 - aborted PSTATE
*/
.endm
.macrokernel_exit, el, ret = 0
//把此时sp(即图2中sp’’)+S_PC位置处开始的16字节内容分别给x21,x22
//即把栈中存的x21和x22内容取出来
ldpx21, x22, // load ELR, SPSR
.if\el == 0
ldrx23, // load return stack pointer,取出
.endif
.if\ret
ldrx1, // preserve x0 (syscall return),如果ret=1,则保存x0,用于系统调用,暂不分析
addsp, sp, S_X2
.else
popx0, x1//如果ret=0,弹出x0,x1
.endif
popx2, x3// load the rest of the registers
popx4, x5
popx6, x7
popx8, x9
msrelr_el1, x21// set up the return data,把前面弹出的x21,x22分别赋值给elr_el1,spsr_el1
msrspsr_el1, x22
.if\el == 0
msrsp_el0, x23
.endif
popx10, x11
popx12, x13
popx14, x15
popx16, x17
popx18, x19
popx20, x21
popx22, x23
popx24, x25
popx26, x27
popx28, x29
ldrlr, , #S_FRAME_SIZE - S_LR// load LR and restore SP,把lr弹出
eret// return to kernel,异常返回,该指令会把lr给pc,完成跳转
.endm
.macroget_thread_info, rd
mov\rd, sp
and\rd, \rd, #~((1 《《 13) - 1)// top of 8K stack
.endm
/*
* These are the registers used in the syscall handler, and allow us to
* have in theory up to 7 arguments to a function - x0 to x6.
*
* x7 is reserved for the system call number in 32-bit mode.
*/
sc_nr.reqx25// number of system calls
scno.reqx26// syscall number
stbl.reqx27// syscall table pointer
tsk.reqx28// current thread_info
/*
* Interrupt handling.
*/
.macroirq_handler
ldrx1, handle_arch_irq
movx0, sp
blrx1
.endm
.text
/*
* Exception vectors.
*/
.macroventrylabel//这里是2^7对齐,即对齐到内存地址的0x80
.align7
b\label
.endm
.align11

/* ENTRY也是一个宏,定义在include/linkage.h中
* #ifndef ENTRY
* #define ENTRY(name) \
* .globl name; \
* ALIGN; \
* name:
* #endif

Linux微内核(鸿蒙分析)

1、最近鸿蒙炒的火热,19年就说ipc是谷歌fuchsia的5倍,但他当时没有对比宏内核,正常宏内核的ipc效率肯定很高。

我自己觉得微内核确实是体积小了但是外面的那些驱动什么的又需要开发者去开发,这些开发者前期也就只有华为的开发人员去弄

鸿**立了跑到国外谷歌全家桶又是一个不可逾越的鸿沟,GMS用不了国外就没希望,何况fuchsia这个谷歌的备用还在那摆着,所以鸿蒙切入点在国内,以万物互联为主题是最佳发展方式。

个人比较喜欢鸿蒙的一些东西,也相信它一定会成功,或许3年或许更久,但是现在取代安卓是不可能的的,不过打破垄断全新开源,重新定义5G万物互联时代,作为一个学生还是开了眼的。

2、相对与安卓来说全场景、分布式是鸿蒙OS2.0的最大优势,鸿蒙OS2.0首先在分布式能力上经行了提升分布式软总线、分布式数据管理、并提升了分布式安全能力,(手表电视 汽车 中控外加美的九阳老板电器)、EMUI11借鉴了鸿蒙的分布式技术,多屏协同。

3、GPL:谷歌曾提出影响开源世界最大的障碍就是GPL,GPL规定要求代码使用者代码衍生出来的东西永远开源。谷歌为了隔离gpl的开源,提出了Apache(阿帕奇)协议,就是我开源你随便。

谷歌把一个魔改后的linux作为内核封装起来,中间加了一层类库,让其他所有部分对内核的调用,都像是两个软件之间的调用一样,然后把所有涉及到GPL授权的代码全部替换重写,开源并以Apache协议授权。

这就导致linux社区不满,因为它违反了Linux开源精神如果非强制会导致没人愿意开源,2012年安卓在linux分支树上被永远除名

话说回来要不是Apache哪里来的EMUI Flyme Coloros,要是GPL的话那不是给人打工吗。

4、安卓的linux内核包含了权限管理,CPU指令适配、设备驱动等等

微内核简单理解就是:裁剪了一下,更小了,手机平板手表通用,手机摄像头给手表用,内核一样,手机上有摄像头的设备驱动,不同于wifi、蓝牙华为可以通过分布式软总线来实现信息的传递,这一步5G起到了关键作用。关于分布式软总线的介绍在博客最后。

优势1:灵活的全场景适用,不同屏幕大小、功耗和性能要求的设备可以灵活选择,这样一个应用就有可能在多个设备或者华为所说的全设备上运行,这对于5G万物互联来说非常方便

优势2:安全,恶意代码只能在某个模块下运行,不再是宏内核整个root权限下随便运行

5、当前鸿蒙智慧屏上鸿蒙1.0是linux 鸿蒙 liteos三核并存,因为他生存初期必须要保证鸿蒙系统的可用性,他前期要兼容安卓,一点一点替换安卓的驱动等等,开源的世界有现成的就没人会去造轮子。

6、对于鸿蒙的分布式,也就是软硬件资源共享,其实是基于微内核的,宏内核要实现ipc通信就需要用户空间进程调度到内核空间内核空间再到另一个用户进程空间实现资源传递,宏内核的内核空间是共享的,所谓的新建一个进程可以说是只是说新建了自己独立的用户空间,这里面的ipc通信效率目前来说是要比微内核的效率要高的,而华为的分布式ipc是要通过软总线来实现的,如果借助tcp来实现安全可以保证,但是协议繁琐效率降低,这对于我们物联网的交互来说是不可采取的,所以软总线相当于一个魔改的tcp。

分布式软总线将原本计算机网络通讯协议七层结构中的 表示层、会话层、传输层和网络层等协议精简为一层 ,称为 分布式软总线的极简协议 ,能提升有效载荷。

通过报文简化、包头简化、交互简化,基于应用场景的缓冲机制等方式,提升有效的传输负荷、解决传统 TCP/IP 协议过于复杂的协议层次模型、层层增加包头和解包,充分发挥物理通信通道的最大效能。

通过对协议的优化,分布式软总线无线连接、高带宽、低时延、低功耗、安全接入的优点。分布式软总线实现小于20ms的低时延,端到端时延小于20ms,有效吞吐量达到1.2Gbps,抗丢包性达到25%, 高性能IPC将进程间的通信效率提升了5倍 。

简单理解可以把它想象成优化的tcp更快实现资源共享。

如何使用crash工具分析Linux内核崩溃转储文件

使用 crash 的先决条件
1. kernel 映像文件 vmlinux 在编译的时候必须指定了 -g 参数,即带有调试信息。
2. 需要有一个内存崩溃转储文件(例如 vmcore),或者可以通过 /dev/mem 或 /dev/crash 访问的实时系统内存。如果 crash 命令行没有指定转储文件,则 crash 默认使用实时系统内存,这时需要 root 权限。
3. crash 支持的平台处理器包括:x86, x86_64, ia64, ppc64, arm, s390, s390x ( 也有部分 crash 版本支持 Alpha 和 32-bit PowerPC,但是对于这两种平台的支持不保证长期维护 )。
4. crash 支持 2.2.5-15(含)以后的 Linux 内核版本。随着 Linux 内核的更新,crash 也在不断升级以适应新的内核。
crash 安装指南
要想使用 crash 调试内核转储文件,需要安装 crash 工具和内核调试信息包。
以 RHEL 为例,安装 crash 及内核调试信息包的步骤如下:
rpm -ivh crash-5.1.8-1.el6.ppc64.rpm
rpm -ivh kernel-debuginfo-common-ppc64-2.6.32-220.el6.ppc64.rpm
rpm -ivh kernel-debuginfo-2.6.32-220.el6.ppc64.rpm
启动 crash
以 RHEL 和 SLES 为例:
RHEL6.2:/usr/lib/debug/lib/modules/2.6.32-220.el6.ppc64/vmlinux
SLES11SP2:/usr/lib/debug/boot/vmlinux-3.0.13-0.27-ppc64.debug
使用 crash -h 或 man crash 可以查看 crash 支持的一系列选项,这里仅以常用的选项为例说明如下:
-h:打印帮助信息
-d:设置调试级别
-S:使用 /boot/System.map 作为默认的映射文件
-s:不显示版本、初始调试信息等,直接进入命令行
-i file:启动之后自动运行 file 中的命令,再接受用户输入

内存管理:一文读懂Linux内存组织结构及页面布局

1、内存是什么?

1) 内存又称主存,是 CPU 能直接寻址的存储空间,由半导体器件制成;

2) 内存的特点是存取速率快,断电一般不保存数据,非持久化设备;

2、内存的作用

1) 暂时存放 cpu 的运算数据

2) 硬盘等外部存储器交换的数据

3) 保障 cpu 计算机的稳定性和高性能

1、linux 内存地址空间 Linux 内存管理全貌

2、内存地址——用户态&内核态

3、内存地址——MMU 地址转换

4、内存地址——分段机制

1) 段选择符

更多Linux内核视频教程文档资料免费领取后台私信【 内核 】自行获取。

内核学习网站:

Linux内核源码/内存调优/文件系统/进程管理/设备驱动/网络协议栈-学习视频教程-腾讯课堂

2) 分段实现

5、内存地址——分页机制(32 位)

6、用户态地址空间

7、内核态地址空间

8、进程内存空间

内存管理算法 ——对讨厌自己管理内存的人来说是天赐的礼物

1、内存碎片

1) 基本原理

2) 如何避免内存碎片

2、伙伴系统算法——组织结构

1) 概念

2) 外部碎片

3、伙伴系统算法——申请和回收

1) 申请算法

2) 回收算法

3) 条件

4、如何分配 4M 以上内存?

1) 为何限制大块内存分配

2) 内核中获取 4M 以上大内存的方法

5、伙伴系统——反碎片机制

1) 不可移动页

2) 可回收页

6、slab 算法——基本原理

1) 基本概念

2) 内部碎片

7、slab 分配器的结构

详细参考:

经典|图解Linux内存性能优化核心思想

8、slab 高速缓存

1) 普通高速缓存

2) 专用高速缓存

9、内核态内存池

1) 基本原理

2) 内核 API

10、用户态内存池

1) C++ 实例

11、DMA 内存

1) 什么是 DMA

2) DMA 信号

out of memory 的时代过去了吗?no,内存再充足也不可任性使用。

1、内存的使用场景

2、用户态内存分配函数

a) 如果当前连续内存块足够 realloc 的话,只是将 p 所指向的空间扩大,并返回 p 的指针地址。这个时候 q 和 p 指向的地址是一样的

b) 如果当前连续内存块不够长度,再找一个足够长的地方,分配一块新的内存,q,并将 p 指向的内容 copy 到 q,返回 q。并将 p 所指向的内存空间删除

3、内核态内存分配函数

4、malloc 申请内存

5、缺页异常

6、用户进程访问内存分析

7、共享内存

1) 原理

2) shm 接口

1、C 内存泄露

2、C 野指针

3、C 资源访问冲突

4、STL 迭代器失效

错误示例:删除当前迭代器,迭代器会失效

正确示例:迭代器 erase 时,需保存下一个迭代器

5、C++ 11 智能指针

(1)原理分析:

(2)数据结构:

(3)使用方法:

6、C++ 11 更小更快更安全

六、 如何查看内存

可以通过 cat /proc/slabinfo 命令查看

可以通过 /proc/sys/vm/drop_caches来释放

如何linux内核报告问题

Linux Kernel BUG:soft lockup CPU#1 stuck分析
1.线上内核bug日志
kernel: Deltaway too big! 18428729675200069867 ts=18446743954022816244 write stamp =18014278822746377
kernel:------------------------
kernel:WARNING: at kernel/trace/ring_buffer.c:1988 rb_reserve_next_event+0x2ce/0x370()(Not tainted)
kernel:Hardware name: ProLiant DL360 G7
kernel:Modules linked in: fuse ipv6 power_meter bnx2 sg microcode serio_raw iTCO_wdtiTCO_vendor_support hpilo hpwdt i7core_edac edac_core shpchp ext4 mbcache jbd2sd_mod crc_t10dif hpsa radeon ttm drm_kms_helper drm i2c_algo_bit i2c_coredm_mirror dm_region_hash dm_log dm_mod
kernel: Pid:5483, comm: master Not tainted 2.6.32-220.el6.x86_64 #1
kernel: CallTrace:
kernel: ? warn_slowpath_common+0x87/0xc0
kernel: ? warn_slowpath_null+0x1a/0x20
kernel: ? rb_reserve_next_event+0x2ce/0x370
kernel: ? ring_buffer_lock_reserve+0xa2/0x160
kernel: ? trace_buffer_lock_reserve+0x2c/0x70
kernel: ? trace_current_buffer_lock_reserve+0x16/0x20
kernel: ? ftrace_raw_event_hrtimer_cancel+0x4e/0xb0
kernel: ? hrtimer_try_to_cancel+0xba/0xd0
kernel: ? do_setitimer+0xd4/0x220
kernel: ? alarm_setitimer+0x3a/0x60
kernel: ? sys_alarm+0xe/0x20
kernel: ? tracesys+0xd9/0xde
kernel: ------
abrt-dump-oops: Reported 1 kernel oopses to Abrt
kernel: BUG: softlockup - CPU#11 stuck for 4278190091s!
kernel:Modules linked in: fuse ipv6 power_meter bnx2 sg microcode serio_raw iTCO_wdtiTCO_vendor_support hpilo hpwdt i7core_edac edac_core shpchp ext4 mbcache jbd2sd_mod crc_t10dif hpsa radeon ttm drm_kms_helper drm i2c_algo_bit i2c_coredm_mirror dm_region_hash dm_log dm_mod
kernel: CPU 11
kernel:Modules linked in: fuse ipv6 power_meter bnx2 sg microcode serio_raw iTCO_wdtiTCO_vendor_support hpilo hpwdt i7core_edac edac_core shpchp ext4 mbcache jbd2sd_mod crc_t10dif hpsa radeon ttm drm_kms_helper drm i2c_algo_bit i2c_coredm_mirror dm_region_hash dm_log dm_mod
kernel:
kernel: Pid:5492, comm: qmgr Tainted: G W ---------------- 2.6.32-220.el6.x86_64 #1 HPProLiant DL360 G7
kernel: RIP:0010:do_setitimer+0x1d0/0x220
kernel: RSP:0018:ffff88080a661ef8 EFLAGS: 00000286
kernel: RAX:ffff88080b175a08 RBX: ffff88080a661f18 RCX: 0000000000000000
kernel: RDX:0000000000000000 RSI: 0000000000000082 RDI: ffff88080c8c4c40
kernel: RBP:ffffffff8100bc0e R08: 0000000000000000 R09: 0099d7270e01c3f1
kernel: R10:0000000000000000 R11: 0000000000000246 R12: ffffffff810ef9a3
kernel: R13:ffff88080a661e88 R14: 0000000000000000 R15: ffff88080a65a544
kernel: FS:00007f10b245f7c0(0000) GS:ffff88083c4a0000(0000) knlGS:0000000000000000
kernel: CS:0010 DS: 0000 ES: 0000 CR0: 000000008005003b
kernel: CR2:00007ff955977380 CR3: 000000100a80b000 CR4: 00000000000006e0
kernel: DR0:0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
kernel: DR3:0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
kernel:Process qmgr (pid: 5492, threadinfo ffff88080a660000, task ffff880809577500)
kernel: Stack:
kernel:00007f10b323def0 00007f10b248ead0 00007f10b26d0f78 00007f10b248ede0
kernel:《0》 ffff88080a661f68 ffffffff8106f88a 0000000000000000 0000000000000000
kernel:《0》 000000000000014c 00000000000f423d 0000000000000000 0000000000000000
kernel: CallTrace:
kernel: ? alarm_setitimer+0x3a/0x60
kernel: ? sys_alarm+0xe/0x20
kernel: ? tracesys+0xd9/0xde
kernel: Code:89 ef e8 74 66 02 00 83 3d 15 69 b5 00 00 75 37 49 8b 84 24 70 07 00 00 48 0508 08 00 00 66 ff 00 66 66 90 fb 66 0f 1f 44 00 00 《31》 c0 e9 64 fe ff ff49 8b 84 24 68 07 00 00 48 c7 80 d0 00 00
kernel: CallTrace:
kernel: ? do_setitimer+0x209/0x220
kernel: ? alarm_setitimer+0x3a/0x60
kernel: ? sys_alarm+0xe/0x20
kernel: ? tracesys+0xd9/0xde
abrt-dump-oops: Reported 1 kernel oopses to Abrt
2.内核软死锁(soft lockup)bug原因分析
Soft lockup名称解释:所谓,soft lockup就是说,这个bug没有让系统彻底死机,但是若干个进程(或者kernel thread)被锁死在了某个状态(一般在内核区域),很多情况下这个是由于内核锁的使用的问题。
Linux内核对于每一个cpu都有一个监控进程,在技术界这个叫做watchdog(看门狗)。通过ps –ef | grep watchdog能够看见,进程名称大概是watchdog/X(数字:cpu逻辑编号1/2/3/4之类的)。这个进程或者线程每一秒钟运行一次,否则会睡眠和待机。这个进程运行会收集每一个cpu运行时使用数据的时间并且存放到属于每个cpu自己的内核数据结构。在内核中有很多特定的中断函数。这些中断函数会调用soft lockup计数,他会使用当前的时间戳与特定(对应的)cpu的内核数据结构中保存的时间对比,如果发现当前的时间戳比对应cpu保存的时间大于设定的阀值,他就假设监测进程或看门狗线程在一个相当可观的时间还没有执。Cpu软锁为什么会产生,是怎么产生的?如果linux内核是经过精心设计安排的CPU调度访问,那么怎么会产生cpu软死锁?那么只能说由于用户开发的或者第三方软件引入,看我们服务器内核panic的原因就是qmgr进程引起。因为每一个无限的循环都会一直有一个cpu的执行流程(qmgr进程示一个后台邮件的消息队列服务进程),并且拥有一定的优先级。Cpu调度器调度一个驱动程序来运行,如果这个驱动程序有问题并且没有被检测到,那么这个驱动程序将会暂用cpu的很长时间。根据前面的描述,看门狗进程会抓住(catch)这一点并且抛出一个软死锁(soft lockup)错误。软死锁会挂起cpu使你的系统不可用。
如果是用户空间的进程或线程引起的问题backtrace是不会有内容的,如果内核线程那么在soft lockup消息中会显示出backtrace信息。
3.根据linux内核源码分析错误
根据我们第一部分内核抛出的错误信息和call trace(linux内核的跟踪子系统)来分析产生的具体原因。
首先根据我们的centos版本安装相应的linux内核源码,具体步骤如下:
(1)下载源码的rpm包kernel-2.6.32-220.17.1.el6.src.rpm
(2)安装相应的依赖库,命令:yuminstall rpm-build redhat-rpm-config asciidoc newt-devel
(3)安装源码包:rpm -ikernel-2.6.32-220.17.1.el6.src.rpm
(4)进入建立源码的目录:cd~/rpmbuild/SPECS
(5)建立生成源码目录:rpmbuild-bp --target=`uname -m` kernel.spec
下面开始真正的根据内核bug日志分析源码:
(1)第一阶段内核错误日志分析(时间在Dec 4 14:03:34这个阶段的日志输出代码分析,其实这部分代码不会导致cpu软死锁,主要是第二阶段错误日志显示导致cpu软死锁)
我们首先通过日志定位到相关源代码:看下面日志:Dec 4 14:03:34 BP-YZH-1-xxxx kernel: WARNING: atkernel/trace/ring_buffer.c:1988 rb_reserve_next_event+0x2ce/0x370() (Not tainted)
根据日志内容我们可以很容易的定位到kernel/trace/ring_buffer.c这个文件的1988行代码如下:WARN_ON(1)。
先简单解释一下WARN_ON的作用:WARN_ON只是打印出当前栈信息,不会panic。所以会看到后面有一大堆的栈信息。这个宏定义如下:
#ifndef WARN_ON
#defineWARN_ON(condition) ({ \
int __ret_warn_on = !!(condition); \
if (unlikely(__ret_warn_on)) \
__WARN(); \
unlikely(__ret_warn_on); \
})
#endif
这个宏很简单保证传递进来的条件值为0或者1(两次逻辑非操作的结果),然后使用分支预测技术(保证执行概率大的分支紧邻上面的指令)判断是否需要调用__WARN()宏定义。如果满足条件执行了__WARN()宏定义也接着执行一条空指令;。上面调用WARN_ON宏是传递的1,所以会执行__WARN()。下面继续看一下__WARN()宏定义如下:
#define __WARN() warn_slowpath_null(__FILE__,__LINE__)
从接下来的call trace信息中我们也确实发现调用了warn_slowpath_null这个函数。通过在linux内核源代码中搜索这个函数的实现,发现在panic.c(内核恐慌时的相关功能实现)中实现如下:
voidwarn_slowpath_null(c***t char *file, int line)
{
warn_slowpath_common(file, line,__builtin_return_address(0),
TAINT_WARN, NULL);
}
EXPORT_SYMBOL(warn_slowpath_null);//都出这个符号,让其他模块可以使用这个函数
同样的我们看到了warn_slowpath_common这个函数,而在call trace当中这个函数在warn_slowpath_null函数之前打印出来,再次印证了这个流程是正确的。同样在panic.c这个文件中我发现了warn_slowpath_common这个函数的实现如下:
static voidwarn_slowpath_common(c***t char *file, int line, void *caller,
unsigned taint, struct slowpath_args *args)
{
c***t char *board;
printk(KERN_WARNING "------------------------\n");
printk(KERN_WARNING "WARNING: at %s:%d %pS()(%s)\n",
file, line, caller, print_tainted());
board = dmi_get_system_info(DMI_PRODUCT_NAME);//得到dmi系统信息
if (board)
printk(KERN_WARNING "Hardware name:%s\n", board);//通过我们的日志信息可以发现我们硬件名称是ProLiant DL360 G7
if (args)
vprintk(args-》fmt, args-》args);
print_modules();//打印系统模块信息
dump_stack();//dump信息输出(call trace开始)
print_oops_end_marker();//打印oops结束
add_taint(taint);
}
分析这个函数的实现不难发现我们的很多日志信息从这里开始输出,包括打印一些系统信息,就不继续深入分析了(请看代码注释,里面调用相关函数打印对应信息,通过我分析这些函数的实现和我们的日志信息完全能够对应,其中dump_stack是与cpu体系结构相关的,我们的服务器应该是属于x86体系)。这里在继续分析一下dump_stack函数的实现,因为这个是与cpu体系结构相关的,而且这个函数直接反应出导致内核panic的相关进程。这个函数实现如下:
/*
* The architecture-independent dump_stackgenerator
*/
void dump_stack(void)
{
unsigned long stack;
printk("Pid: %d, comm: %.20s %s %s %.*s\n",
current-》pid, current-》comm,print_tainted(),
init_utsname()-》release,
(int

linux内核~~

用gcc编译一下,就成了内核镜像了
开机时要把镜像加载进内存
在加上些软件,就是一个比较完整的linux了
内核源码书:
linux内核完全注释(0.11/0.12内核)
linux内核源代码情景分析(2.4内核)
要弄明白内核结构,多研究研究Makefile文件

μClinux的μClinux操作系统的核心技术环节剖析

在GNU通用公共许可证的授权下,μClinux操作系统的用户可以使用几乎所有Linux的API函数,不会因为没有内存管理单元MMU而受到影响;而且,μClinux在标准的Linux基础上进行了适当的裁剪和优化,形成了一个高度优化的、代码紧凑的嵌入式Linux,体积小了,但是仍然保留了Linux的大多数的优点,比如稳定性好、强大的网络功能、良好的可移植性、完备的文件系统支持功能、以及标准丰富的应用程序接口API等,可以支持类似ARM7TDMI等类型多的小巧玲珑的中央处理器。下面对μClinux二此开法过程中涉及到的主要功能部件以及各部分的技术内涵,进行较为深入的分析和讨论,以便网络管理人员在应用μClinux进行系统功能扩展时参考:
(1)系统加载模块,该模块又称BootLoader。它是负责μClinux操作系统内核启动的基本功能模块。具体来说,该功能模块可以完成建立uCLinux内核运行环境和从闪存Flash中装载初始化内核镜象。
(2)系统内核初始化模块,该模块又称SystemInit。启动μClinux内核时,首先受到调用的功能函数是StartKernel()函数。该函数的主要任务是初始化内核的其他部分。具体包括:捕获终端请求IRQ、进程调度、设备驱动程序加载、标定延迟循环,进而调用fork的init进程,以启动任务管理环境。
(3)系统调用模块,该模块又称为SystemCall模块。在μClinux系统执行完init程序后,内核对程序流不再有直接的控制权,它此后的作用仅限于处理捕获到的中断请求事件(例如硬件中断),并为系统调用提供服务进程。
(4)设备驱动模块,又称为DeviceDriver模块。在几乎所有的操作系统中,设备驱动都占据大部分的系统空间,μClinux也不例外。同其他各类操作系统一样,μClinux的设备驱动程序,为系统连接和控制的硬件设备与操作系统之间提供通讯接口。同时,各设备发出的中断请求由系统调用模块负责安排响应时间,并提供服务程序的入口地址。
(5)文件系统,又称为FileManagement模块。任何一个操作系统,包括μClinux在内,它们最重要的任务之一就是对多种文件系统进行有效的管理。μClinux在文件管理方面具有很强的兼容性,很容易同其他操作系统共存、共享各类常用文件。特别值得推崇的是,μClinux可以透明地支持许多不同类型的文件系统,将各种安装的文件和文件系统以一个完整的虚拟文件系统的形式呈现给用户。同时,μClinux还带有一个完整的TCP/IP协议,可以支持各种流行的网络协议,方便用户使用系统访问网络资源,是一个功能丰富、简便易用的网络操作系统。

分析linux内核崩溃信息

分析kernel比较关键的就是看三点:
1) 内核会给出一个崩溃原因的猜测,这里是,CPU 0 Unable to handle kernel paging request at virtual address 00000000
2) 看pc指针的值,这里是epc == 00000000
3) 看调用栈Call Trace:[ //可惜后面没给出来
通常是根据指针加上偏移值跟反汇编代码对照,找到出问题的指令。
这个panic的原因比较明显,应该是引用了空指针,试图执行0x00000000出的代码。

Linux内核源码解析-list.h

开头就说明了这里的 list.h 文件来自 Linux Kernel ( */include/linux/list.h ),只是去除了列表项的硬件预加载部分。

进行宏替换后就是

Note: 没搞懂这里为什么加个 osn 前缀,原本是 list_add ,现在是 osn_list_add 。

可以看到就是个简单的链表节点删除过程,同时把删除节点的前后指针设为无法访问。

删除节点后初始化,前后指针都指向自己

从A链表删除后头插法插入B链表

从A链表删除后尾插法插入B链表

先对 list 判空,非空就把 list 链表除头节点外裁剪到 head 头节点在的链表中。函数不安全, list 节点可以继续访问其他节点。

多了一步 list 重新初始化的过程。

(unsigned long)(&((type *)0)-》member))) 将0x0地址强制转换为 type * 类型,然后取 type 中的成员 member 地址,因为起始地址为0,得到的 member 的地址就直接是该成员相对于 type 对象的偏移地址了。
所以该语句的功能是:得到 type 类型对象中 member 成员的地址偏移量。
先将 ptr 强制转换为 char * 类型(因为 char * 类型进行加减的话,加减量为 sizeof(char)*offset , char 占一个字节空间,这样指针加减的步长就是1个字节,实现加一减一。)
整句话的意思就是:得到指向 type 的指针,已知成员的地址,然后减去这个成员相对于整个结构对象的地址偏移量,得到这个数据对象的地址。

就是从前往后,从后往前的区别

Note: 从head节点开始(不包括head节点!)遍历它的每一个节点!它用n先将下一个要遍历的节点保存起来,防止删除本节点后,无法找到下一个节点,而出现错误!

已知指向某个结构体的指针pos,以及指向它中member成员的指针head,从下一个结构体开始向后遍历这个结构体链

Note: 同理,先保存下一个要遍历的节点!从head下一个节点向后遍历链表。

list.h使用说明
linux内核list.h分析(一)
linux内核list.h分析(二)
【Linux内核数据结构】最为经典的链表list

OK,关于linux内核分析和ARMv8 Linux内核错误处理过程分析怎么解决的内容到此结束了,希望对大家有所帮助。
本文编辑:admin

更多文章:


python怎么读入excel(python如何读取excel文件)

python怎么读入excel(python如何读取excel文件)

本篇文章给大家谈谈python怎么读入excel,以及python如何读取excel文件对应的知识点,文章可能有点长,但是希望大家可以阅读完,增长自己的知识,最重要的是希望对各位有所帮助,可以解决了您的问题,不要忘了收藏本站喔。

土耳其叙利亚(土耳其与叙利亚是一个人种吗)

土耳其叙利亚(土耳其与叙利亚是一个人种吗)

今天给各位分享土耳其与叙利亚是一个人种吗的知识,其中也会对土耳其与叙利亚是一个人种吗进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

java官方(java官方文档里接口方法都不写权限是public/private/protect/default)

java官方(java官方文档里接口方法都不写权限是public/private/protect/default)

大家好,java官方相信很多的网友都不是很明白,包括java官方文档里接口方法都不写权限是public/private/protect/default也是一样,不过没有关系,接下来就来为大家分享关于java官方和java官方文档里接口方法都

linux内核分析(ARMv8 Linux内核错误处理过程分析怎么解决)

linux内核分析(ARMv8 Linux内核错误处理过程分析怎么解决)

各位老铁们好,相信很多人对linux内核分析都不是特别的了解,因此呢,今天就来为大家分享下关于linux内核分析以及ARMv8 Linux内核错误处理过程分析怎么解决的问题知识,还望可以帮助大家,解决大家的一些困惑,下面一起来看看吧!

c语言switch语句输入字符(c语言编程,使用switch语句,输入A打印A,输入B打印B,输入C打印C,输入其他字符)

c语言switch语句输入字符(c语言编程,使用switch语句,输入A打印A,输入B打印B,输入C打印C,输入其他字符)

本篇文章给大家谈谈c语言switch语句输入字符,以及c语言编程,使用switch语句,输入A打印A,输入B打印B,输入C打印C,输入其他字符对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。

c语言返回数组(c语言如何返回一个数组)

c语言返回数组(c语言如何返回一个数组)

各位老铁们,大家好,今天由我来为大家分享c语言返回数组,以及c语言如何返回一个数组的相关问题知识,希望对大家有所帮助。如果可以帮助到大家,还望关注收藏下本站,您的支持是我们最大的动力,谢谢大家了哈,下面我们开始吧!

系统架构设计师可以直接考吗(软考能直接考高级系统架构师吗)

系统架构设计师可以直接考吗(软考能直接考高级系统架构师吗)

今天给各位分享软考能直接考高级系统架构师吗的知识,其中也会对软考能直接考高级系统架构师吗进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

java项目流程(一个项目的流程该怎么说,以java项目为例)

java项目流程(一个项目的流程该怎么说,以java项目为例)

本篇文章给大家谈谈java项目流程,以及一个项目的流程该怎么说,以java项目为例对应的知识点,文章可能有点长,但是希望大家可以阅读完,增长自己的知识,最重要的是希望对各位有所帮助,可以解决了您的问题,不要忘了收藏本站喔。

博客为什么没人用了(如今多人玩博客吗)

博客为什么没人用了(如今多人玩博客吗)

本篇文章给大家谈谈博客为什么没人用了,以及如今多人玩博客吗对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。

mysql查看数据库语句(mysql怎样查看数据库命令)

mysql查看数据库语句(mysql怎样查看数据库命令)

本篇文章给大家谈谈mysql查看数据库语句,以及mysql怎样查看数据库命令对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。

最近更新

python怎么读入excel(python如何读取excel文件)
2025-08-23 18:40:02 浏览:0
热门文章

口语100下载(口语100电脑版怎样下载)
2025-06-27 09:00:02 浏览:10
premiere pro怎么读(premiere怎么读)
2025-06-27 05:00:01 浏览:9
标签列表