为了保证kernel_exit时能恢复准确的现场,这里有必要对第一现场先做保存。 其次设置栈帧大小S_FRAM_SIZE,S_FRAM_SIZE根据pt_regs结构体大小而设定。 pt_regs结构体: 另外就是读取elr_el1和spsr_el1等寄存器值。总之,kernel_entry主要将CPU寄存器按照pt_regs结构体的定义将异常第一现场保存到栈上。 (2)判断异常...
为了保证kernel_exit时能恢复准确的现场,这里有必要对第一现场先做保存。 其次设置栈帧大小S_FRAM_SIZE,S_FRAM_SIZE根据pt_regs结构体大小而设定。 pt_regs结构体: 另外就是读取elr_el1和spsr_el1等寄存器值。总之,kernel_entry主要将CPU寄存器按照pt_regs结构体的定义将异常第一现场保存到栈上。 (2)判断异常...
这是由于注释中提到的PC指的是内核堆栈中的处理器状态,而不是硬件意义上的PC寄存器,这里的linux regs实际上是pt_regs这个struct。 所以此处的意图是通过更改pt_regs.pc来更改ELR中的内容,并在exception return时跳到ELR指定的地址,对应了单步调试状态机中 "Programs the ELR_ELx ..." 这一步。 但对于单步调试...
为了保证kernel_exit时能恢复准确的现场,这里有必要对第一现场先做保存。 其次设置栈帧大小S_FRAM_SIZE,S_FRAM_SIZE根据pt_regs结构体大小而设定。 pt_regs结构体: 另外就是读取elr_el1和spsr_el1等寄存器值。总之,kernel_entry主要将CPU寄存器按照pt_regs结构体的定义将异常第一现场保存到栈上。 (2)判断异常...
pt_regs结构体包含异常发生时栈上寄存器中保存的信息,其代码在openeuler/kernel/blob/kernel-4.19/arch/arm64/include/asm/ptrace.h文件中: /* * This struct defines the way the registers are stored on the stack during an * exception. Note that sizeof(struct pt_regs) has to be a multiple of 16...
保存通用寄存器x0~x29到栈框里pt_regs->x0~x29 */ stpx0,x1, [sp,#16*0] stpx2,x3, [sp,#16*1] stpx4,x5, [sp,#16*2] stpx6,x7, [sp,#16*3] stpx8,x9, [sp,#16*4] stpx10,x11, [sp,#16*5] stpx12,x13, [sp,#16*6] ...
此时sp的值为init_task.stack + THREAD_SIZE - sizeof(struct pt_regs)。主要工作如下: 将x29(FP)和x30(LR)分别保存到sp-16和sp-8的地址上,然后sp -= 16。 将sp的值写入到x29(FP) 这是实现了ARM64函数调用标准规定的栈布局,为后续函数调用的入栈出栈做好了准备。
structpt_regs { union { struct user_pt_regs user_regs;//结构体user_pt_regs和结构体pt_regs内容一样 struct { //共用体存储31个通用寄存器,外加sp,pc,pstate三个特殊寄存器 //该结构体用于异常处理的压栈弹栈操作 u64 regs[31]; u64 sp; ...
内核代码中的关键部分,如pt_regs结构体偏移量,get_thread_info宏通过sp寄存器找到thread_info地址,恢复现场时,restore_user_regs宏会根据调用者情况调整寄存器和sp值。程序编译后,会将代码加载到RAM,这影响了跳转指令的选择,需使用相对跳转而非绝对地址。中断向量表(__vectors_start至__vectors_end...
struct pt_regs *regs = task_pt_regs(current); return do_fork(SIGCHLD, regs->gprs[15], regs, 0, NULL, NULL); } SYSCALL_DEFINE2(dup2, unsigned int, oldfd, unsigned int, newfd) // asmlinkage long sys_dup2(unsigned int old fd,unsigned int newfd) ...