linux用户栈作用,linux内核栈和用户栈(二)

linux内核栈和用户栈(二)

一.中断向量

ARM执行的时候,有时会产生中断,根据中断的来源不同,执行不同的中断向量:

中断向量地址

异常中断类型

异常中断模式

优先级(6最低)

0x0

复位

SVC

1

0x4

未定义的指令

Undef

6

0x8

软件中断(SWI)

SVC

6

0x0c

指令预取中止

中止模式

5

0x10

数据访问中止

中止模式

2

0x14

保留

未使用

未使用

0x18

IRQ

IRQ

4

0x1c

FIQ

FIQ

3

Linux由于具有内核态和用户态,与ARM的不同运行模式对应,内核态运行于SVC模式,用户态运行于USR模式,当linux运行时由于产生中断,或者软中断时,会根据上表的中断向量,进入不同的运行流程。

__vectors_start:

W(b)vector_rst

W(b)vector_und

W(ldr)pc, __vectors_start + 0x1000

W(b)vector_pabt

W(b)vector_dabt

W(b)vector_addrexcptn

W(b)vector_irq

W(b)vector_fiq

二.外部中断的产生(IRQ)

2.1外部中断产生的预处理

.macrovector_stub, name, mode, correction=0

.align5

vector_\name:

.if \correction

sublr, lr, #\correction

.endif

@

@ Save r0, lr_ (parent PC) and spsr_

@ (parent CPSR)

@

stmiasp, {r0, lr}@ save r0, lr

mrslr, spsr

strlr, [sp, #8]@ save spsr

@

@ Prepare for SVC32 mode. IRQs remain disabled.

@

mrsr0, cpsr

eorr0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)

msrspsr_cxsf, r0

@

@ the branch table must immediately follow this code

@

andlr, lr, #0x0f

THUMB(adrr0, 1f)

THUMB(ldrlr, [r0, lr, lsl #2])

movr0, sp

ARM(ldrlr, [pc, lr, lsl #2])

movspc, lr@ branch to handler in SVC mode

ENDPROC(vector_\name)

当产生IRQ中断后,系统即进入向量0x18的IRQ模式,在该模式中,保存r0, lr, spsr到栈中,然后再更改CPSR切换ARM模式为SVC模式。在IRQ中断产生之前,系统可以运行在USR模式,即用户态,在这种情况下,ARM运行模式从USR模式,切换到IRQ模式,又在IRQ中断处理中,将系统切换到SVC状态,即内核态,用户态的寄存器被保存到SVC的堆栈中了。同样,在IRQ中断产生之前,系统运行在SVC模式下,即内核态,在这种情况下,ARM运行模式切到IRQ模式后,又被切换回SVC模式了,溜了一圈。对于IRQ具体的中断函数处理时都在SVC模式下,这样处理也同样有利于中断嵌套运行。

2.2外部中断的处理

/*

* Interrupt dispatcher

*/

vector_stubirq, IRQ_MODE, 4

.long__irq_usr@ 0 (USR_26 / USR_32)

.long__irq_invalid@ 1 (FIQ_26 / FIQ_32)

.long__irq_invalid@ 2 (IRQ_26 / IRQ_32)

.long__irq_svc@ 3 (SVC_26 / SVC_32)

.long__irq_invalid@ 4

.long__irq_invalid@ 5

.long__irq_invalid@ 6

.long__irq_invalid@ 7

.long__irq_invalid@ 8

.long__irq_invalid@ 9

.long__irq_invalid@ a

.long__irq_invalid@ b

.long__irq_invalid@ c

.long__irq_invalid@ d

.long__irq_invalid@ e

.long__irq_invalid@ f

Linux系统运行在用户态发生中断时,执行__irq_usr分支;当运行在内核态发生中断时,执行__irq_svc分支,

这两个流程的处理都已经在SVC模式了。

2.3 __irq_usr处理流程

.align5

__irq_usr:

usr_entry

kuser_cmpxchg_check

irq_handler

get_thread_info tsk

movwhy, #0

bret_to_user_from_irq

UNWIND(.fnend)

ENDPROC(__irq_usr)

.macrousr_entry, trace=1

UNWIND(.fnstart)

UNWIND(.cantunwind)@ don't unwind the user space

subsp, sp, #S_FRAME_SIZE

ARM(stmibsp, {r1 - r12})

THUMB(stmiasp, {r0 - r12})

ATRAP(mrcp15, 0, r7, c1, c0, 0)

ATRAP(ldrr8, .LCcralign)

ldmiar0, {r3 - r5}

addr0, sp, #S_PC@ here for interlock avoidance

movr6, #-1@ "" "" "" ""

strr3, [sp]@ save the "real" r0 copied

@ from the exception stack

ATRAP(ldrr8, [r8, #0])

@

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

@

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

@ r5 - spsr_

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

@

@ Also, separately save sp_usr and lr_usr

@

stmiar0, {r4 - r6}

ARM(stmdbr0, {sp, lr}^)

THUMB(store_user_sp_lr r0, r1, S_SP - S_PC)

@ Enable the alignment trap while in kernel mode

ATRAP(teqr8, r7)

ATRAP( mcrnep15, 0, r8, c1, c0, 0)

@

@ Clear FP to mark the first stack frame

@

zero_fp

.if\trace

#ifdef CONFIG_IRQSOFF_TRACER

bltrace_hardirqs_off

#endif

ct_user_exit save = 0

.endif

.endm

ENTRY(ret_to_user_from_irq)

ldrr1, [tsk, #TI_FLAGS]

tstr1, #_TIF_WORK_MASK

bnework_pending

no_work_pending:

asm_trace_hardirqs_on

/* perform architecture specific actions before user return */

arch_ret_to_user r1, lr

ct_user_enter save = 0

restore_user_regs fast = 0, offset = 0

ENDPROC(ret_to_user_from_irq)

.macrorestore_user_regs, fast = 0, offset = 0

movr2, sp

ldrr1, [r2, #\offset + S_PSR]@ get calling cpsr

ldrlr, [r2, #\offset + S_PC]!@ get pc

msrspsr_cxsf, r1@ save in spsr_svc

#if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_32v6K)

@ We must avoid clrex due to Cortex-A15 erratum #830321

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

#endif

.if\fast

ldmdbr2, {r1 - lr}^@ get calling r1 - lr

.else

ldmdbr2, {r0 - lr}^@ get calling r0 - lr,

.endif

movr0, r0@ ARMv5T and earlier require a nop

@ after ldm {}^

addsp, sp, #\offset + S_FRAME_SIZE

movspc, lr@ return & move spsr_svc into cpsr

.endm

2.4__irq_svc处理流程

.align5

__irq_svc:

svc_entry

irq_handler

#ifdef CONFIG_PREEMPT

get_thread_info tsk

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

ldrr0, [tsk, #TI_FLAGS]@ get flags

teqr8, #0@ if preempt count != 0

movner0, #0@ force flags to 0

tstr0, #_TIF_NEED_RESCHED

blnesvc_preempt

#endif

svc_exit r5, irq = 1@ return from exception

UNWIND(.fnend)

ENDPROC(__irq_svc)

三.内核栈的取得

.macroget_thread_info, rd

ARM(mov\rd, sp, lsr #THREAD_SIZE_ORDER + PAGE_SHIFT)

THUMB(mov\rd, sp)

THUMB(lsr\rd, \rd, #THREAD_SIZE_ORDER + PAGE_SHIFT)

mov\rd, \rd, lsl #THREAD_SIZE_ORDER + PAGE_SHIFT

.endm

#define THREAD_SIZE_ORDER 1

#define PAGE_SHIFT 12

struct thread_info {……},该结构大小是8K, 即低13位对齐,当前的SP右移13位,再左移13位即得到当前进程的thread_info, 从这也可以推出task_struct{}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值