我是靠谱客的博主 无心丝袜,最近开发中收集的这篇文章主要介绍linux过滤错误rzhi,《LINUX3.0内核源代码分析》第二章:中断和异常,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1.1.1.1退回用户态

从中断返回到用户态是由ret_to_user_from_irq进行处理的,在恢复寄存器现场前,需要处理抢占、检查信号等等。

/**

*从中断返回用户态,在软中断或者中断处理函数退出时,系统确保已经关闭了中断。

*/

ENTRY(ret_to_user_from_irq)

/**

*从任务的TI_FLAGS标志判断是否需要处理抢占或者信号。

*/

ldrr1, [tsk, #TI_FLAGS]

tstr1, #_TIF_WORK_MASK

/**

*处理抢占或者信号

*/

bnework_pending

/**

*运行到这里,说明没有抢占或者信号需要处理,或者已经处理完毕,开始退回用户态了。

*/

no_work_pending:

/**

*退回用户态时,必然会打开中断,因此这里记录下打开中断的事实,供调试用。

*/

#if defined(CONFIG_IRQSOFF_TRACER)

asm_trace_hardirqs_on

#endif

/* perform architecture specific actions before user return */

/**

*在返回用户态前,处理各个体系结构的钩子,对我们分析的单板来说,没有钩子需要处理。

*/

arch_ret_to_user r1, lr

/**

*恢复寄存器现场,并切回用户态。

*/

restore_user_regs fast = 0, offset = 0

ENDPROC(ret_to_user_from_irq)

在切换回用户态前,需要处理抢占和信号:

work_pending:

/**

*检查任务的_TIF_NEED_RESCHED,如果置位,则说明需要处理任务抢占,在这里调度到高优先级任务。

*/

tstr1, #_TIF_NEED_RESCHED

bnework_resched

/**

*接着处理信号。

*/

tstr1, #_TIF_SIGPENDING|_TIF_NOTIFY_RESUME

/**

*没有信号需要处理,则跳转到no_work_pending并退回用户态。

*/

beqno_work_pending

movr0, sp@ 'regs'

movr2, why@ 'syscall'

tstr1, #_TIF_SIGPENDING@ delivering a signal?

movnewhy, #0@ prevent further restarts

/**

*这里处理信号

*/

bldo_notify_resume

/**

*然后重新关中断并判断是否有更多任务需要处理。

*/

bret_slow_syscall@ Check work again

/**

*这里处理抢占,注意这里可以调用schedule,而不用调用preempt_schedule。这是有原因的。

*另外,这个标号也不能随意移到其他地方。因为调用schedule后,流程会转到ret_slow_syscall。

* ret_slow_syscall上会关中断,然后将中断、异常返回流程重新处理一次。

*需要关中断的原因,是schedule函数会强制将中断打开。

*/

work_resched:

blschedule

/*

* "slow" syscall return path."why" tells us if this was a real syscall.

*/

ENTRY(ret_to_user)

ret_slow_syscall:

disable_irq@ disable interrupts

1.1.1.2从svc32模式进入中断

当中断嵌套或者中断打断系统调用等异常时,中断会从svc32模式进入中断。在开始中断处理前,系统仍然需要保存寄存器现场。这是通过调用宏svc_entry来实现的。

/**

*当从svc模式进入中断处理程序时,使用本宏保存寄存器现场到堆栈中,并形成pt_regs结构传递给C函数。

*/

.macrosvc_entry, stack_hole=0

UNWIND(.fnstart)

UNWIND(.save {r0 - pc})

/**

*将当前指针向低地址移动,以保存寄存器现场。这里减去4是为了将sp指向pt_regs中r1的位置。

*/

subsp, sp, #(S_FRAME_SIZE + stack_hole - 4)

#ifdef CONFIG_THUMB2_KERNEL/*新内核支持将内核编译为THUMB-2,以节省代码空间,我们的系统不支持这个功能*/

SPFIX(strr0, [sp])@ temporarily saved

SPFIX(movr0, sp)

SPFIX(tstr0, #4)@ test original stack alignment

SPFIX(ldrr0, [sp])@ restored

#else

SPFIX(tstsp, #4)

#endif

SPFIX(subeqsp, sp, #4)

/**

*将r1-r12保存到堆栈中。

*/

stmiasp, {r1 - r12}

/**

* r0,sp,lr,spsr已经被汇编代码使用,因此需要根据r0从中断栈(我们目前正在使用的是svc栈)中取出

*/

ldmiar0, {r1 - r3}

/**

* r5指向pt_regs的ARM_sp即r13

*/

addr5, sp, #S_SP - 4@ here for interlock avoidance

movr4, #-1@""""""""

/**

*将r0调整到刚进入宏的位置

*/

addr0, sp, #(S_FRAME_SIZE + stack_hole - 4)

SPFIX(addeqr0, r0, #4)

/**

*保存r0,同时将sp向下调整4字节,现在sp指向pt_regs了。

*/

strr1, [sp, #-4]!@ save the "real" r0 copied

@ from the exception stack

movr1, lr

@

@ We are now ready to fill in the remaining blanks on the stack:

@

@r0 - sp_svc

@r1 - lr_svc

@r2 - lr_, already fixed up for correct return/restart

@r3 - spsr_

@r4 - orig_r0 (see pt_regs definition in ptrace.h)

@

stmiar5, {r0 - r4}/*将中断栈中的数据保存到pt_regs */

.endm

当不是从用户态进入中断时,中断处理代码要稍显复杂一点,主要是需要处理抢占:

/**

*从svc32模式进入中断的处理过程

*/

__irq_svc:

/**

*首先保存寄存器现场。

*/

svc_entry

/**

*进入中断后,系统自动将中断关闭,这里调用trace_hardirqs_off记录下中断被关闭的事实,用于跟踪调试。

*/

#ifdef CONFIG_TRACE_IRQFLAGS

bltrace_hardirqs_off

#endif

#ifdef CONFIG_PREEMPT

/**

*对可抢占内核来说,这里将任务的抢占计数加1,在整个中断处理过程中,进程都不能被抢占。

*/

get_thread_info tsk

ldrr8, [tsk, #TI_PREEMPT]@ get preempt count

addr7, r8, #1@ increment it

strr7, [tsk, #TI_PREEMPT]

#endif

irq_handler

#ifdef CONFIG_PREEMPT

/**

*恢复抢占计数。

*/

strr8, [tsk, #TI_PREEMPT]@ restore preempt count

/**

*将任务的TI_FLAGS标志加载到r0中,这样后面会根据r0判断_TIF_NEED_RESCHED,以处理任务抢占

*/

ldrr0, [tsk, #TI_FLAGS]@ get flags

/**

*如果在进入中断前,系统处于系统调用状态,那么抢占计数就可能为0.

*这里比较抢占计数是否为0,如果为0,则进行抢占处理。

*/

teqr8, #0@ if preempt count != 0

/**

*如果系统关抢占了,那么强制针r0清0,这样就不可能调用svc_preempt

*/

movner0, #0@ force flags to 0

/**

*如果系统没有关抢占,并且任务存在_TIF_NEED_RESCHED标志,则调用svc_preempt处理抢占。

*/

tstr0, #_TIF_NEED_RESCHED

blnesvc_preempt

#endif

/*在此中断处于关闭状态,从pt_regs中获得中断前的SPSR寄存器,接下来将会用这个寄存器恢复状态。*/

ldrr4, [sp, #S_PSR]@ irqs are already disabled

/*如果恢复状态后,将会打开中断,则调用trace_hardirqs_on进行跟踪*/

#ifdef CONFIG_TRACE_IRQFLAGS

tstr4, #PSR_I_BIT

bleqtrace_hardirqs_on

#endif

/**

*退回svc32模式

*/

svc_exit r4@ return from exception

UNWIND(.fnend)

ENDPROC(__irq_svc)

处理抢占的代码并不复杂,如下:

#ifdef CONFIG_PREEMPT

svc_preempt:

movr8, lr

/**

*这里调用preempt_schedule_irq处理抢占调度,今后在分析调度时,将会详细介绍这个函数。

*/

1:blpreempt_schedule_irq@ irq en/disable is done inside

/**

* preempt_schedule_irq返回时,会重新将中断关闭,这里加载TI_FLAGS标志是安全的。

*/

ldrr0, [tsk, #TI_FLAGS]@ get new tasks TI_FLAGS

tstr0, #_TIF_NEED_RESCHED

/**

*如果任务没有抢占标志,那么退回上层继续处理,恢复寄存器现场,返回上层中断。

*/

moveqpc, r8@ go again

/**

*否则表示任务再次被抢占,循环处理抢占。

*/

b1b

#endif

1.1.1.3退回svc32模式

从中断退出的代码如下:

#ifndef CONFIG_THUMB2_KERNEL

.macrosvc_exit, rpsr

msrspsr_cxsf, rpsr /*恢复rpsr */

#if defined(CONFIG_CPU_V6)

/**

*恢复r0寄存器

*/

ldrr0, [sp]

/**

*由于发生了中断,需要执行strex指令,这样上层中断中的spinlock会认为排它性装载失效,重启spinlock循环。

*在mips等体系结构中,这是由硬件完成的。可能ARM硬件不能完成这件事。

*/

strexr1, r2, [sp]@ clear the exclusive monitor

/**

*恢复所有寄存器,并恢复cpsr。将处理器状态切回中断前。

*/

ldmibsp, {r1 - pc}^@ load r1 - pc, cpsr

#elif defined(CONFIG_CPU_32v6K)

clrex@ clear the exclusive monitor

ldmiasp, {r0 - pc}^@ load r0 - pc, cpsr

#else

ldmiasp, {r0 - pc}^@ load r0 - pc, cpsr

#endif

.endm

最后

以上就是无心丝袜为你收集整理的linux过滤错误rzhi,《LINUX3.0内核源代码分析》第二章:中断和异常的全部内容,希望文章能够帮你解决linux过滤错误rzhi,《LINUX3.0内核源代码分析》第二章:中断和异常所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(68)

评论列表共有 0 条评论

立即
投稿
返回
顶部