用户态切换到内核态的三种方式:系统调用,中断,异常
CPU上下文切换的分为几个不同的场景:进程上下文切换,线程上下文切换,中断上下文切换
进程上下文概念。
1.当一个进程在执行时,CPU的所有寄存器中的值、进程的状态以及堆栈中的内容被称为该进程的上下文。(第一种解释)
2.进程的上下文包括用户级上下文和系统级上下文。
用户级上下文:由用户的程序块、数据块、运行时的堆和用户栈(统称为用户堆栈)等组成的用户空间信息被称为用户级上下文。
系统级上下文:由进程标识信息、进程现场信息、进程控制信息(包含进程表、页表、打开文件表等)和系统内核栈等组成的内核空间信息被称为系统级上下文。
进程切换:
1.页表全目录 2.内核堆栈 3.硬件上下文 4.刷新TLB(TLB hit)5.系统调度
线程切换:
保存寄存器、栈等私有数据,线程的调度是需要内核级别的权限的(操作CPU和内存),也就是说线程的调度工作是在内核态完成的,因此会有一个从用户态到内核态的切换。
线程上下文的保存和恢复,用户态和内核态的转换,CPU上下文的切换。
线程切换和进程切换差不多,都是在等待队列的双向链表里找一个task_struct运行罢了。
中断上下文
一:根据异常向量表找到异常向量处理程序(此处是将中断处理程序和异常向量表中的irq绑定)
二:在irq handle中
保存现场:
1.设置IRQ栈 2.CPSR(自动),保存LR 3.保存r0-r12
IRQ handle:
1. ldr sp, =IRQ_STACK
2.中断返回的PC保存在LR中,CPSR(自动)保存在(IRQ模式下)SPSR下。 sub lr,lr,#4
3.保存r0-r12,lr到irq模式下的栈上
stmfd sp!, {r0-r12,lr}
bl irq_handler
//处理完中断返回
ldmfd sp!, {r0-r12,pc}^ ^就是cpsr返回
三:在irq handler中
根据中断源寄存器查找中断状态寄存器来找到中断编号,根据编号去isr数组中找到isr地址。
具体的:绑定异常向量表,初始化控制器的基本寄存器(禁止左右中断)
自己配置 1.gpio配置(gpio中断,触发方式),2.写isr 3.绑定isr(中断号)到中断控制器
iic控制器那边wait_event_timeout(交出cpu)
从机有了响应,中断处理处理程序被执行,isr中执行wake_up(&i2c->wait)
系统调用:文件管理、进程控制、内存管理
首先保存(read函数对应的)系统调用号到R7寄存器,调用svc指令触发软中断异常,修改CPU的工作模式由USR切换到SVC,将返回地址和CPU状态寄存器内容压栈。进入软中断的处理入口以后,从R7寄存器中取出系统调用号,以系统调用号为下标(索引)在系统调用表中找到对应的内核函数sys_read,调用完毕,原路返回到用户空间,至此应用程序的read函数调用完毕。
Linux2.5之前(具体哪个版本不太清楚)下用int 0x80触发所有的系统调用,那如何区分不同的调用呢?对于每个系统调用都有一个系统调用号,在触发中断之前,会将系统调用号放入到一个固定的寄存器,0x80对应的中断处理程序会读取该寄存器的值,然后决定执行哪个系统调用的代码。
操作系统一般是通过中断来从用户态切换到内核态的。软件中断指令(SVC)用于产生软中断,使用软件中断指令进入中断。软中断调用时将返回地址和CPU状态寄存器内容压栈,修改特权级,根据中断号查找中断向量表,找到ISR中断服务例程地址,跳转执行。
调用到C库的函数定义的地方后,将会做如下工作:
软中断调用时将返回地址和CPU状态寄存器内容压栈
2.1 首先保存(read函数对应的)系统调用号到R7寄存器
2.2 调用svc指令触发软中断异常
老ARM体系结构:swi
新ARM体系结构:svc
软中断:实现CPU的工作模式由USR切换到SVC
此时:用户程序由用户空间“陷入”内核空间
3.一旦触发异常,CPU跳转到异常向量表软中断的处理入口,至此进入内核空间
4.进入软中断的处理入口以后,将会做如下事情:
1.从R7寄存器中取出系统调用号
2.2.以系统调用号为下标(索引)在系统调用表中找到对应的内核函数sys_read
5.找到对应的内核函数以后,调用这个内核函数,调用完毕,原路返回到用户空间,至此应用程序的read函数调用完毕
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)