首页 > 其他分享 >【单片机/嵌入式】复位中断服务函数与main函数

【单片机/嵌入式】复位中断服务函数与main函数

时间:2022-11-10 23:33:51浏览次数:64  
标签:CONTROL 函数 中断 特权 模式 单片机 寄存器 堆栈 main

一、复位中断服务函数调用main函数

在GD32F450ZGT6的启动文件startuup_gd32f450_470.s中可以发现,复位中断服务函数调用了main函数。

【疑问】为什么复位中断服务程序里面直接调用的main函数,难道所有程序都在复位中断里面执行的?
由于我们的main函数一般包含了while(1)的死循环,所以不会有如下图中执行到exit退出函数。

与GD32相同,STM32也是Cortex M系列内核。以STM32进入MDK(Keil)5的调试模式,当程序运行至复位中断服务函数时中可以发现,处理器操作模式竟然是Thread mode(线程模式),而进入中断服务函数后处理器本应处于Handler mode(处理模式)的。
通过查看官方文档【https://developer.arm.com/documentation/dui0552/a/the-cortex-m3-processor/exception-model/exception-types】即可发现问题所在:

最后一句:Execution restarts as privileged execution in Thread mode ,意为:异常重新作为特权级线程模式执行。也就是说上电复位或者手动复位,此时的复位中断服务器程序就是作为普通程序来执行的,已经不再是中断式的处理机制,就是简单的函数跳转到了main函数里面。

二、处理器的操作模式与特权级别

2.1两种操作模式

Cortex-M3/M4支持两种操作模式,两种操作模式分别是:
Handler mode 中断模式(处理模式),简单的说就是指异常服务程序是处在中断模式。
Thread mode 线程模式,简单的说就是异常服务程序以外的程序都是处在线程模式。
引入两个模式的本意,是用于区别普通应用程序的代码和异常服务程序的代码——包括中断服务程序的代码

2.2两种特权操作级别

两级特权操作分别为:特权级和非特权级(用户级)。
Unprivileged 非特权级(用户级):起到保护用户任务的作用,防止用户可以在任意任务中访问和修改系统寄存器,操作不当会造成系统崩溃。
Privileged 特权级:这种模式下用户可以在任意任务中对系统控制寄存器的访问和修改。
这可以提供一种存储器访问的保护机制,使得普通的用户程序代码不能意外地,甚至是恶意地执行涉及到要害的操作。处理器支持两种特权级,这也是一个基本的安全模型

(1)主应用程序(Thread mode线程模式),既可以使用特权级,也可以使用非特权级(用户级)
(2)异常(中断)服务程序(Handler mode处理模式)必须在特权级下执行。
(3)处理器复位后在线程模式+特权级模式下运行

在特权级下的代码可以通过置位CONTROL[0]来进入用户级。而不管是任何原因产生了任何异常,处理器都将以特权级来运行其服务例程,异常返回后,系统将回到产生异常时所处的级别。(在特权级模式下可以通过修改CONTROL寄存器进入用户级代码。)
用户级下的代码不能再试图修改CONTROL[0]来回到特权级。它必须通过一个异常handler,由那个异常handler来修改CONTROL[0],才能在返回到线程模式后拿到特权级。(用户级代码只能通过SVC中断,触发SVC异常才能重新进入特权级。)

控制寄存器(CONTROL)

CONTROL[0]=1,用户级的线程模式
CONTROL[0]=0,特权级的线程模式
CONTROL[1]=1,选择使用PSP
CONTROL[1]=0,选择使用MSP

复位后,处理器默认进入线程模式,特权极访问 ( 使用 MSP 作为堆栈指针 )

EXC_RETURN Description
0xFFFFFFF1 Return to Handler mode. Exception return gets state from the main stack. Execution uses MSP after return.
0xFFFFFFF9 Return to Thread mode. Exception Return get state from the main stack. Execution uses MSP after return.
0xFFFFFFFD Return to Thread mode. Exception return gets state from the process stack. Execution uses PSP after return.

在特权级模式下,用户可以访问和配置系统控制寄存器,比如NVIC中断控制器。然而,如果是在非特权级(用户级)模式下,系统控制寄存器是不允许访问的,一旦访问将导致硬件异常。
通过引入特权级和非特权级(用户级),就能够在硬件水平上限制某些不受信任的或者还没有调试好的程序,不让它们随便地配置涉及要害的寄存器,因而系统的可靠性得到了提高。
一般情况下特权级模式会配合MPU一起使用,通过MPU设定只有特权级才能访问的存储空间。
NVIC的中断控制/状态寄存器都只能在特权级下访问。不过有一个例外——软件触发中断寄存器可以在用户级下访问以产生软件中断。软件触发中断寄存器允许设置的前提,是设置中断控制寄存器STIR
对于Cortex-M3或者M4内核来说,所有的 核心外设寄存器 都是 只能在特权级 下才可以访问。核心外设主要是MPUNVICSCBSTK四个单元。 除了核心外设寄存器以外,M3/M4内核的特殊功能寄存器也是不能在非特权级下访问的,特殊功能寄存器主要包括以下寄存器:
1. 程序状态寄存器组(PSRs或曰xPSR)
2. 中断屏蔽寄存器组(PRIMASK, FAULTMASK,以及BASEPRI)
3. 控制寄存器(CONTROL)
对于参考手册上面所说的SPI,USART,USB等所有外设寄存器都是可以在非特权级下进行访问的。
在用户级下,不能访问系统控制空间(SCS,包含配置寄存器及调试组件的寄存器),且禁止使用MSR访问特殊功能寄存器(APSR除外),如果访问,则产生fault。
基于以上原因,从特权级转到非特权级后,不能直接通过写“控制寄存器”——因为不支持在非特权级下访问;因此只能通过特殊方式触发异常,从而进入特权级。
主要有以下两种方法访问核心外设:
1. 使用SVC(Supervisor Call)软中断。
2.在初始化和开启多任务 操作系统 前做核心外设的初始化。

2.3 Cortex-M3/M4中的特殊功能寄存器

1. 程序状态寄存器组(PSRs或曰xPSR)
2. 中断屏蔽寄存器组(PRIMASK, FAULTMASK,以及BASEPRI)
3. 控制寄存器(CONTROL)
其中控制寄存器CONTROL是用来设置特权级和非特权级切换的,CONTROL寄存器定义如下:
CONTROL[0]:仅当在特权级下操作时才允许写该位。一旦进入了用户级,唯一返回特权级的途径,就是触发一个软中断,再由服务例程改写该位。
CONTROL寄存器也是通过MRS和MSR指令来操作的:
MRS R0, CONTROL
MSR CONTROL, R0

2.4中断和异常的区别

在ARM编程领域中,凡是打断程序顺序执行的事件,都被称为异常(exception)
除了外部中断外,当有指令执行了“非法操作”,或者访问被禁的内存区间因各种错误产生的 fault,以及不可屏蔽中断发生时,都会打断程序的执行,这些情况统称为异常。在不严格的上下文中,异常与中断也可以混用。
另外,程序代码也可以主动请求进入异常状态的(常用于系统调用)。

2.5特权级作用范围及可操作的指令

MRS MSR 指令只可以在特权级模式下使用。需要通过MRS MSR访问的特殊功能寄存器,除了APSR可以在用户级访问。

2.6特权级与用户级使用的栈指针

特权级可以使用MSP和PSP指针。
用户级可以使用PSP,能不能使用MSP不太清楚。
在异常处理函数中只能使用MSP。
为了避免系统堆栈因应用程序的错误使用而毁坏,我们可以给应用程序专门配一个堆栈,不让它共享操作系统内核的堆栈。在这个管理制度下,运行在线程模式的用户代码使用PSP,而异常服务例程则使用MSP。这两个堆栈指针的切换是智能全自动的,就在异常服务的始末由硬件处理。
MSP和PSP 的含义是Main_Stack_Pointer 和 Process_Stack_Pointer,在逻辑地址上他们都是R13。Cortex-M3内核有两个堆栈指针:MSP-主堆栈指针和PSP-进程堆栈指针,在任何一个时刻只能有一个堆栈指针起作用。
MSP(Main_Stack_Pointer)主堆栈指针:当程序复位后(开始运行后),一直到第一次任务切换完成前,使用的都是MSP,即:main函数运行时用的是MSP,运行OSStartHighRdy,运行PendSV程序,用的都是MSP。当main函数开始运行前,启动文件会给这个函数分配一个堆栈空间,像ucos给任务分配堆栈空间一样,用于保存main函数运行过程中变量的保存。此时MSP就指向了该堆栈的首地址。
PSP(Process_Stack_Pointer)进程堆栈指针:切换任务之后PendSV服务程序中有ORR LR, LR, #0x04这句,意思就是PendSV中断返回后使用的PSP指针,此时PSP已经指向了所运行任务的堆栈,所以返回后就可以就接着该任务继续运行下去了。
由于任何一个时刻都只能使用一个堆栈指针(SP),所以,如果在某一个时刻,需要读取或者改变另外一个堆栈指针的内容就得使用特定的指令: MSR 和 MRS.
相关文章:【汇编:MSR/MRS/BIC指令】https://www.cnblogs.com/cxl-93/p/11009447.html

三、引用文章

本文仅用于知识点学习与记录,感谢以下文章及其作者:

【为什么复位中断服务程序里面直接调用的main函数,难道所有程序都在复位中断里面执行的?】https://cloud.tencent.com/developer/article/2144988
【ARM:用户级 特权级 AND 线程模式 Handler模式】https://blog.csdn.net/woshidytgg/article/details/104008196
【cortex M3/M4内核 特权级与用户级详解】https://blog.csdn.net/jieliangzi/article/details/107646182#:~:text=%E7%89%B9%E6%9D%83%E7%BA%A7%E4%B8%8E%E7%94%A8%E6%88%B7%E7%BA%A7%E4%BD%9C%E7%94%A8%E7%9A%84%E8%8C%83%E5%9B%B4
【ARM Cortex-M3 操作模式和特权级别】https://www.cnblogs.com/shangdawei/archive/2013/04/05/3000869.html

 

标签:CONTROL,函数,中断,特权,模式,单片机,寄存器,堆栈,main
From: https://www.cnblogs.com/steven913/p/16879214.html

相关文章

  • 通过调用函数判断一个数是否为质数
    /*//1.书写判断某个数是否为质数的方法,将这个方法封装在一个函数里    functionodd(a){      count=0      for(vari=1;i<......
  • C语言学习笔记---sizeof关键字和strlen函数
    sizeof和strlen在C语言中常用来计算字符大小和长度,在应用中却有着本质的区别。 sizeof是C语言中的关键字,其作用是返回一个对象或类型所占的内存字节数。使用方式为:int......
  • C++标准库<locale> :由islower() 函数 ----- 判断字符是否为小写字母 深入学习locale库
      C++标准库<locale>:声明:classlocale;接口:   ......
  • 数组为函数参数
    1、数组引用作为函数形参,链接1)输入必须为10个元素!2)可以将数组定义为类型voidprint(int(&arr)[10]){for(autoi:arr){cout<<i<<endl;}}......
  • excel表格-TRANSPOSE函数详解
    效果图将A1:D1的内容转置为A2:A5操作步骤1、选中要转置后的表格区域2、手动输入=TRANSPOSE(),在括号中输入被转置的区域A1:D1,=TRANSPOSE(A1:D1)3、同时按ctrl......
  • 函数与递归(day9)
    本章目的不是为了学会递归,而是通过递归学习函数在递归过程中在内存的储况以及递归函数的语句执行顺序。问题1:通过递归拆分数字实例​voidprint(intx){if(x>9){pr......
  • 腾讯云云函数实现小程序全局 access_token 刷新
    巧用云函数实现小程序全局access_token刷新​​#​​实现思路利用云函数请求微信服务器获取小程序全局唯一后台接口调用凭据并存入云数据库,配合云函数的触发器来实现定......
  • 腾讯云TCB云函数生成小程序码
    本文记录如何使用腾讯云云函数生成小程序码​​前言​​​​程序思路​​​​核心代码​​​​访问示例地址​​​​参考资料​​​​#​​前言之前写过一篇​​小程序......
  • 云函数扫盲
    记录一些云函数的基础知识,混个脸熟不少同学总是问关于云函数的问题,所以这里发个扫盲的文章吧。​​#​​云函数是啥?云函数作为无服务模式的一种实现(FaaS)已经有很多公司......
  • Java8新特性—四大内置函数式接口
    ......