当前位置: 首页 > Linux

【笨叔比特2】为什么ARM32架构中每个处理模式都有单独的栈?

时间:2023-04-06 04:06:24 Linux

》朋友们,我是笨叔。笨叔每天都想和大家分享一点点,可能是傻的,可能是傻的,可能是甜的,也可能是酸的小点点滴滴,记录下每一刻每一天的小感悟就像细雨滴,慢慢汇入江海!”上次提到LinuxCon大会,这种大会就像笨叔叔说的,“听你说的,胜过读十年书”。笨叔叔有幸拜访了北京Linux社区的一位老人,聆听了他鲜为人知的80、90年代CPU处理器架构和Linux操作系统的历史,以及他对生活和科技的感悟。.在聊天中,他提到为什么ARM32处理器需要7种处理器模式,而且每种处理器模式都需要一个独立的栈空间?比如irq模式,为什么ARM32设计需要一个独立的irq模式,而这个irq模式只是12字节?为什么不和SVC模式共用一个栈?比如x86等传统经典处理器架构中,irq是没有独立栈的thinking.这篇文章是一个介绍,希望有兴趣的小伙伴在文末留言发表你的看法01ARM32上的设计——来看看ARM32,如果发生irq中断,怎么处理ARM32处理器句柄呢?我们知道ARM32有很奇妙的7种工作模式:如上图所示,在ARMV6之前,ARM处理器有7种模式。普通内核运行在SVC模式,用户态app运行在User态,其他就是我们常说的IRQ中断,FIQ中断和几种异常模式。如果与x86相比,x86只有ring0~ring3四个特权级,内核运行在ring0,用户态运行在ring3,不区分SVC模式,IRQ模式等。我们正在看ARMv7的改进。不论安全模式,在非安全或正常世界中,ARMv7在继续使用7种模式的基础上区分了PL0模式、PL1和PL2模式。PL表示特权级别。简单的说:PL0模式:用户模式,相当于之前的USER模式PL1操作系统模式:包括之前的SVC模式,IRQ模式,FIQ模式PL2虚拟化模式:一种新的模式,有点类似于x86上的虚拟化扩展Root模式如果ARM32的设计是合理的,我们来看看ARMv8中的设计。ARMv8完全摒弃了ARMv7以前的做法,连名字都该换了。现在叫EL,也就是异常级别,每个EL级别的异常也变了。更名后,每个EL级别的管辖和权利都不同。是不是很像x86中的ring0~ring3?谁告诉你x86在PC和服务器上如此流行?所以,对于x86的优势,ARM当然要努力学习。除此之外,SVC、IRQ、FIQ等七种模式都被完全抛弃,这点与ARMv7有很大的不同。现在在ARMv8上,异常分为两种:同步异常:比如MMU的一些访问权限问题异步异常:就是常见的IRQ,FIQ,ERR还有一点,在ARMv8中,不再设置专用的exceptiontypeforeachexceptiontype例如IRQ没有单独的栈,当前栈只有每个EL一个栈。02ARM32中断栈—ARM32中断发生后,IRQ栈和SVC栈的情况如下:上图是Linux内核中的ARM32,当IRQ发生时,栈发生变化,可以看《奔跑吧Linux内核》第621~626页.一般来说,IRQ模式下的堆栈值保存的是中断发生处SPSR、LR、SP_IRQ这三个寄存器的内容。然后切换到SVC模式,将通用寄存器进一步保存到SVC的栈空间。所以在ARM32中,中断发生后,实际上使用了两种模式的栈,一种是IRQ模式栈,一种是SVC模式栈。这个SVC栈其实就是Linux内核中的内核栈。那么在X86中是怎样的呢?x86处理器中有一个TSS(TaskStateSegment)。当中断发生时,用户进程要么处于用户态(特权级3),要么处于内核态(特权级0)。如果是在用户态,就会发生栈。切换的问题,也就是会切换到内核态的栈,如果是内核态,那么就不存在栈切换的问题。但是x86处理器只有一个特权级0的ESP,也就是说中断发生后,只能使用一个栈,这个栈就是内核栈(kernelstack)。处理器的硬件逻辑会将被中断进程的下一条指令(CS、EIP)和EFLAG压入堆栈。当然,如果发生了从用户态栈到内核态栈的切换,处理器也会将用户态(SS,ESP)也压入栈中,此时使用的是内核栈。这种行为属于处理器的硬件逻辑范畴,不属于系统软件的行为。另一方面,Linux内核现在支持在x86或其他架构中分离内核栈和中断栈的方法。当然,这里所说的中断栈并不是本文所说的CPU内部的中断栈,而是类似于内核栈的栈,即在中断处理程序中,与SVC模式下使用的内核栈是分开的。这是内核设计的问题。总之,中断栈可以和内核栈共享,也可以重新分配一个独立的中断栈。但不利因素是,如果中断栈嵌套,可能会破坏内核栈中的部分数据。因为毕竟是共享的,栈空间有时难免会被拉长。所以在x86Linux中,一直采用独立的内核栈设计。系统中的每个进程都会有自己的内核栈,系统中的每个CPU都会准备两个独立的中断栈来进行中断处理,即hardirqstack和softirqstack。注意这是一个OS设计问题,不是我们今天要讨论的CPU硬件设计上的中断栈分离问题。下面是Linux内核中x86架构使用独立中断栈的补丁。https://git.kernel.org/pub/sc...为什么ARM32要为IRQ模式设置一个单独的12字节栈,而不是在SVC模式下多路复用栈?笨叔翻遍了ARM相关的技术文档,也没找到答案。我猜可能是因为一个重要的原因是ARM32架构是在1990年代设计的。那个时代的ARM处理器相当慢。单个IRQ栈可以提高中断的响应速度,尤其是早期ARM处理器的主要应用场景是嵌入式系统,支持中断嵌套。从上面x86的分离中断栈的patch来看,分离中断栈确实有很多优点,至少可以保证SVC模式下的栈不会溢出。那么究竟是ARM32的设计先进,还是ARMv8、x86的设计理念先进?是进步还是倒退?我有点糊涂了!笨叔抛砖引玉,希望有兴趣的同学稍后留言,一起探讨。