linux运行模式

来源:互联网 发布:软件文档编写指南 编辑:程序博客网 时间:2024/06/14 21:25
据说linux kernel只用到了arm的usr和svc两种模式;用户态位于usr,内核态位于svc。如果发生中断呢?难道不是处于irq模式?在中断异常的用户入口__irq_usr处加了打印,发现此时的mode是3,不是应该处于irq mode吗?怎么是svc呢?怎么切过去的?这还要从中断异常的入口说起。还记得中断向量表吗?
/** 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

vector_stub这是一个宏,是个很关键的宏。

.macrovector_stub, name, mode, correction=0.align5vector_\name:.if \correction@修正返回地址,为什么要修正?进入异常模式时lr中保存的是当前PC,异常返回后,需要执行的是当前状态的下一条指令,根据arm spec需要-4或者-8sublr, lr, #\correction.endif@@ Save r0, lr_<exception> (parent PC) and spsr_<exception>@ (parent CPSR)@stmiasp, {r0, lr} @ save r0, lr,到sp栈顶指针指定的内存mrslr, spsr @spsr读到lr,这是异常之前的状态,spsr_irqstrlr, [sp, #8] @ save spsr到sp+8的内存中@@ Prepare for SVC32 mode. IRQs remain disabled.@mrsr0, cpsr @cpsr读到r0,这是异常之后的eorr0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)@改mode了,异或特点:异或0不变,异或1取反;之前是0的bit都会置1,是1的bit不变。#define PSR_ISETSTATEPSR_T_BIT //thumb#define PSR_ISETSTATE0 //armmsrspsr_cxsf, r0 @r0保存到spsr_cxsf格式:MSR{<条件码>CPSR_f|SPSR_f,<#ommed_8r>MSR{<条件码>CPSR_<field>|SPSR_<field>,Rm其中:<field>字段可以是以下之一或多种:(位从右到左)C:控制域屏蔽字段(PSR中的第0位到第7位);X:扩展域屏蔽字段(PSR中的第8位到第15位);S:状态域屏蔽字段(PSR中的第16位到第32位);F:标志域屏蔽字段(PSR中的第24位到第31位)。注意了这里只是改了spsr_irq的mode,还没有开始切换呢。@@ the branch table must immediately follow this code@andlr, lr, #0x0f @lr保存的是spsr,低4bit,是modeTHUMB(adrr0, 1f )THUMB(ldrlr, [r0, lr, lsl #2])movr0, sp @将irq的栈顶地址给r0,就可以通过r0读irq的栈了ARM(ldrlr, [pc, lr, lsl #2])@pc = lr<<2;lr = pc+lr,有左移还是因为long对齐,__irq_usr位于0偏移处,__irq_svc位于3*4偏移处。movspc, lr @ branch to handler in SVC mode跳转的同时,做模式切换,s表示同时将spsr赋给cpsr,这里就切换过来了;切换到svc mode,spsr_svc应该保存的是切换之前的cpsr,应该是irq mode为2啊;可为什么读回来是0呢?在异常发生后,ARM内核会自动做以下工作,确实是由CPU自动处理的:1 保存执行状态:将CPSR复制到发生的异常模式下SPSR中;2 模式切换:将CPSR模式位强制设置为与异常类型相对应的值,同时处理器进入到ARM执行模式,禁止所有IRQ中断,当进入FIQ快速中断模式时禁止FIQ中断;3 保存返回地址:将下一条指令的地址(被打断程序)保存在LR(异常模式下LR_excep)中。4 跳入异常向量表:强制设置PC的值为相应异常向量地址,跳转到异常处理程序中。如果直接模式切换了,cpsr就不会copy了?所以spsr_svc中保存的还是上一次异常user to irq时的user mode?ENDPROC(vector_\name).align2@ handler addresses follow this label1:.endm

为什么要切换svc呢?应该是中断嵌套的要求,中断嵌套可能导致链接寄存器r14_irq被破坏,就找不到返回点了。

1 arm体系下pt_regs结构struct pt_regs {long uregs[18];};uregs[0] - uregs[17]分别对应,r0 - r15,cpsr,ORIG_r0

#define ARM_cpsruregs[16]#define ARM_pc uregs[15]#define ARM_lr uregs[14]#define ARM_sp uregs[13]#define ARM_ip uregs[12]#define ARM_fp uregs[11]#define ARM_r10 uregs[10]#define ARM_r9 uregs[9]#define ARM_r8 uregs[8]#define ARM_r7 uregs[7]#define ARM_r6 uregs[6]#define ARM_r5 uregs[5]#define ARM_r4 uregs[4]#define ARM_r3 uregs[3]#define ARM_r2 uregs[2]#define ARM_r1 uregs[1]#define ARM_r0 uregs[0]#define ARM_ORIG_r0uregs[17]

2 irq中断时堆栈的变化

--------

spsr

--------

lr ,中断返回地址,修正后的

--------

r0

-------- <-进入irq_svc或irq_usr之前,sp的值,也是r0的值

pt_regs

--------- <-进入svc_entry或usr_entry后,sp的值