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

发布网友 发布时间:2022-04-22 00:22

我来回答

1个回答

热心网友 时间:2023-12-22 10:10

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 free 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <linux/init.h>
#include <linux/linkage.h>

#include <asm/assembler.h>
#include <asm/asm-offsets.h>
#include <asm/errno.h>
#include <asm/thread_info.h>
#include <asm/unistd.h>
#include <asm/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三个特殊寄存器
//该结构体用于异常处理的压栈弹栈操作
u regs[31];
u sp;
u pc;
u pstate;
};
};
u orig_x0;
u syscallno;
};
*/

//S_FRAME_SIZE定义在asm-offsets.c中,DEFINE(S_FRAME_SIZE,sizeof(struct pt_regs));
//即结构体pt_regs的大小,结构体pt_regs的定义见上面
//S_LR定义:DEFINE(S_LR,offsetof(struct pt_regs, regs[30]));
//即31号寄存器在结构体pt_regs中的偏移量
//阅读以下内容请参考图1 和图2
.macrokernel_entry, el, regsize =
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, [sp, #-16]!//注意!!!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, [sp, #S_LR]//把lr,x21寄存器存入sp+S_LR指向的地方
stpx22, x23, [sp, #S_PC]//把lr,存入sp+s_PC指向的位置,用于异常返回

/*
* Set syscallno to -1 by default (overridden later if real syscall).
*/
.if\el == 0
mvnx21, xzr
strx21, [sp, #S_SYSCALLNO]
.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, [sp, #S_PC]// load ELR, SPSR
.if\el == 0
ldrx23, [sp, #S_SP]// load return stack pointer,取出
.endif
.if\ret
ldrx1, [sp, #S_X1]// 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, [sp], #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

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com