(4.3)uboot详解——异常和异常向量

(4.3)uboot详解——异常和异常向量

中断是一个较难掌握知识,因为它是一个过程,而不是一个结果,其中的步骤都建立在理论的层面上,需要理解。比如按下按键1会使led1亮,这个“起因-结果”的操作我想小孩子也能掌握,因为它是一个现象,但是要掌握“起因-过程-结果”却需要花一些功夫,因为这个过程需要理解。如果你认真的了解了前面两节的内容,那么现在就该到了实现“过程”的时候了。

前面两节分析了外部中断和内部中断相关的内容,这篇文章将对处理器的异常情况作一个总结。

可以参考第二片文章(处理器工作模式),ARM处理器有七种工作模式,除了用户模式和系统模式以外,其他5中模式都是异常模式。

人会生病,生病时我们可以依靠我们的免疫系统来恢复,计算机也会“生病”,它“生病”的时候就会进入异常工作模式,依靠异常处理程序让cpu恢复过来,那么计算机在哪些情况下会“生病”呢?

(1)复位异常:当cpu重新上电或者接收到reset信号的时候,处理器就会识别到有复位异常发生了,它就要进入管理模式,执行对应的异常处理函数,直到恢复正常为止。比如重启按钮被按下,或者cpu复位引脚电平发生变化,或者软件设置复位寄存器的相应位。

(2)一般中断/快速中断请求:cpu和外围设备是分别独立运行的硬件执行单元,cpu对全部设备进行管理和资源调度处理,cpu要想知道外围设备的运行状态,要么cpu定时的去查看外围设备的特定寄存器,要么外围设备自己告诉cpu发生了什么,第二种方式就是我们常说的中断请求操作,中断请求分为一般中断请求和快速中断请求,快速中断请求有最高的优先级和最小的中断延迟(看前面文章的中断处理过程就知道了),通常用于处理高速数据传输及通道中的数据恢复处理,如DMA等,但是绝大部分外设使用的是一般中断请求。所以当有中断请求的时候,处理器将进入中断模式,执行中断处理程序,直到恢复正常。

(3)预取指令中止异常:这个异常发生在cpu流水线的取指阶段,如果目标指令地址是非法地址,处理器就会进入中止模式,执行中止异常处理程序。比如使用bl指令跳转到某个地址读取指令,但是这个地址是不可读的,或者这个地址不存在。

(4)数据中止访问异常:这个异常发生在要访问的数据地址不存在或者非法地址时,这种情况,cpu也会进入中止模式,执行对应的处理程序。比如mov r0, A ; A中存放的地址是不存在的或者不可访问的

(5)未定义指令异常:这个异常发生在流水线技术的译码阶段,如果当前指令不能识别为有效指令,就会产生未定义指令异常,cpu就会进入未定义指令终止模式,执行异常处理程序。比如mov r0,#1的下一条指令是abc,这是一条非法指令。

(6)软件中断指令异常:把这个异常放到最后,是因为这个异常的产生原因比较特殊,他是应用程序自己产生的,用于用户程序申请访问硬件资源时,通过操作系统内核代码来访问外设硬件资源的一种方式。比如应用程序需要将数据打印到屏幕上,就需要使用显示器这个硬件资源,但是应用程序是没有权限使用外设硬件的,外设都是有内核进行管理的,那么怎么办呢?那么只能使用软件中断指令切换到内核态,通过操作系统内核代码来访问外设硬件,内核态是工作在特权模式下的,操作系统在特权模式下完成将用户数据打印到屏幕,所以软件中断的异常时在管理模式下进行处理的。

上面分析了处理器在哪些情况下会进入异常模式(注:这些模式都是cpu硬件层面的),第1,2,6种异常对于我们往往是有用的,工作中经常会使用这三种异常来实现我们想要的功能,但是第3,4,5种异常我们一般是不想看到的,这往往表示我们写了不规范的代码,或者执行了错误的操作。

从上面的分析可以发现,中断其实只是cpu异常的一种,中断处理有一个过程,其实它也是异常处理过程的一个子集。下面将对异常的处理过程进行分析:

(1)保护执行状态:当cpu发生异常的时候,硬件首先会将当前的工作模式记录下来,以便后面异常处理完成后可以恢复回来,异常发生时,会将当前CPSR的内容复制到发生的异常模式下的SPSR中,比如在用户模式时发生了未定义指令异常,则会将当前的CPSR保存在SPSR_und中。

(2)模式切换:硬件自动根据当前的异常类型,将异常码写入CPSR里的M[4:0]模式位,这样cpu就进入了对应的模式下,同时cpu会关闭中断IRQ(CPSR的I位置1),防止中断进入,如果当前异常是快速中断,则关闭快速中断。

(3)保存返回地址:当前程序被异常打断,切换到异常处理程序里,异常处理程序处理完成后,需要返回到当前模式的对应位置继续执行,所以必须保存当前执行指令的下一条指令的地址到LR_excep(后缀用于区分,无实际意义)中,至于保存的到底是什么值,是pc-4,pc-8还是pc,请参考这篇文章关于ARM的PC指针(什么时候PC+8,PC+4,PC-4,PC-8)

(4)跳入异常向量表:该操作是cpu硬件自动完成的,当异常发生时,cpu强制将pc的值修改为一个固定内存地址,这块固定地址称作异常向量。

后面我们将分析每一种异常的异常处理程序是怎么将cpu“治”好的,但是在这之前,需要弄明白,当cpu进入异常模式时,它是怎么确定要执行哪一种异常处理程序的?是谁指引它去“寻医问药”的呢?这个指示器就是异常向量。

上面这张图片就是一个异常向量表,从图中可以看到,每种ARM异常对应一个字长空间,正好是一条32位指令长度,比如bl指令在一个字长中的存放如下图:

当异常发生的时候,cpu强制将pc值设置为当前异常对应的固定内存地址,比如当运行0x345678地址处的指令时,发生一般中断异常,cpu就会将当前的pc值强制设置为0x00000018,并把0x345678保存到lr寄存器中,然后下一条指令将会从0x00000018处取指,如果0x00000018处的指令是bl
HandleIRQ, 那么cpu将会跳转到HandleIRQ处执行一般中断处理函数,这个函数是由我们编写的,记得中断处理函数完成时,要跳回0x34567d处继续执行原来的程序。

分析到这来,也许你会有意外,为什么异常向量表的存放地址可以是SDRAM的前4k呢?那里不是存放uboot的地方吗?如果这里存放了异常向量表,那么uboot不就被破坏掉了吗?

我们再看看第一篇文章((1)uboot详解——板子刚上电时都干了些什么)中介绍的这张内存映射图,当板子从norflash启动的时候,内存映射图如左半部分,这时没有存放uboot,uboot放在norflash中,所以存放异常向量表是没有影响的;然而当从nandflash启动的时候,内存映射图如右半部分,内存的前4k在刚上电的时候是会存放uboot的,如果再存放异常向量,必然会破坏uboot的数据!但是即使如此,为什么我们的板子能够正常运行呢?这个就涉及到了代码重定向的内容(将再后面重点讲解),因为在uboot初始化异常向量表的时候,cpu已经将uboot拷贝到SDRAM中执行了,也就是说uboot已经在0x30000000地址处了,即使在初始化中断向量时有破坏uboot,对板子的正常启动是没有影响的。

从中断向量表中可以看出,复位异常的向量指向0x0000000处,开发板的启动地址也是0x0000000处,这样要巧妙的设计是为了处理这种异常时,不用再写异常处理函数了,因为收到reset信号的时候,硬件会自动将uboot从nandflash中拷贝到stepping stone中,这样,uboot则成了复位异常的处理函数。至于norflash启动,其实过程也一样,请参考第一篇文章描述。

不仅如此,因为快速中断的中断向量地址是0x0000001c,它是最后一个向量,后面的空间可以被使用,所以可以将快速中断的处理函数直接以这个地址为开始进行编写了,而不用像其他异常处理函数一样,需要bl跳转到其他地址进行实现,这样可以节省一个bl指令的执行时间,也就是一个时钟周期(为什么是一个时钟周期?请参考arm指令流水线技术)。

下面是通常异常向量表中存放的指令:

bl reset

bl HandleUndef

bl HandleSWI

bl HandlePrefetchAbt

bl HandleDataAbt

bl HandleNoUsed

bl HandleIRQ

bl HandleFIQ

这些Handle则是存放着异常处理函数的入口地址

(5)通常找到异常向量表以后,异常向量表就会指引cpu去哪里执行异常处理程序,下面就来分析一下异常处理函数的实现过程。

异常处理函数一般都是有程序员写的,也往往是处理异常时最有发挥空间的地方,因为有了能够给我们编写异常处理函数的余地,才能让我们实现多种多样的功能,让我们的键盘能够快速的输入,我们的鼠标能自由的晃动,让各种传感器高速的捕捉信号,cpu也能及时的高效的处理这些请求。

A. 保存执行现场

异常处理程序最开始,要保存被打断程序的执行现场,程序的执行无非就是保存当前操作寄存器里的数据,可以通过下面的栈操作指令实现现场保存现场:

STMFD SP_excep!, {r0 - r12, LR_excep}

注:LR_abt,SP_excep分别对应异常模式下LR和SP

需要注意的是,在跳转到异常处理程序入口时,已经切换到对应异常模式下了,因此这里的SP是异常模式下的SP_excep了,所以被打断程序现场(寄存器数据)是保存在异常模式下的栈里,上述指令将r0~r12全部都保存到了异常模式栈,最后将修改完的被打断程序返回地址入栈保存;之所以保存该返回地址就是将来可以通过mov
pc,lr 的指令返回用户程序继续执行。

B. 异常处理过程

这个是异常处理的核心部分,具体问题需要具体分析和解决,将在实例中分析。但是编写时应该注意一下几点:

ISR不能有返回值;ISR不能传递参数;ISR应该是短而高效的,在ISR中做浮点运算是不明智的;ISR中不应该有重入和性能上的问题,因此不应该使用pintf()函数。

C.异常处理返回

异常处理完成之后,返回被打断程序继续执行,具体操作如下:

l 恢复被打断程序运行时寄存器数据

l 恢复程序运行时状态CPSR

l 通过进入异常时保存的返回地址,返回到被打断程序继续执行

异常发生后,进入异常处理程序时,将用户程序寄存器R0~R12里的数据保存在了异常模式下栈里面,异常处理完返回时,要将栈里保存的的数据再恢复回原先R0~R12里,毫无疑问在异常处理过程中必须要保证异常处理入口和出口时栈指针SP_excep要一样,否则恢复到R0~R12里的数据不正确,返回被打断程序时执行现场不一致,出现问题,虽然将执行现场恢复了,但是此时还是在异常模式下,CPSR里的状态是异常模式下状态,因此要恢复SPSR_excep里的保存状态到CPSR里,SPSR_excep是被打断程序执行时的状态,在恢复SPSR_excep到CPSR的同时,CPU的模式和状态从异常模式切换回了被打断程序执行时的模式和状态。此刻程序现场恢复了,状态也恢复了,但PC里的值仍然指向异常模式下的地址空间,我们要让CPU继续执行被打断程序,因此要再手动改变PC的值为进入异常时的返回地址,该地址在异常处理入口时已经计算好,直接将PC
= LR_excep即可。

上述操作可以一步一步实现,但是通常我们可以通过一条指令实现上述全部操作:

LDMFD SP_excp!,  {r0-r12,  pc}^

注:SP_excep为对应异常模式下SP,^符号表示恢复SPSR_excep到CPSR

中断异常处理操作可以用下图来描述:

下面将通过一个小小的项目来总结第4章1,2,3节所分析的内容,主要功能包括:

a. 开机时将cpu模式设置为管理模式

b.关闭看门狗

c.关闭中断

d.开启中断,并初始化中断向量表,设置栈

e.初始化按键中断,按下不同的按钮,点亮不同的led灯

代码较多,不方便贴出来,请到这里下载

总结:这里用了三节内容分析了中断和异常的相关内容,包括中断的产生,中断的处理过程和中断的配置等,由于这些知识不仅是重点也是难点,后面将会在分析uboot源代码的时候继续讲解。

经历一段小艰难后,我们将了解一下较轻快的话题——时钟分频。

时间: 2024-10-10 01:54:21

(4.3)uboot详解——异常和异常向量的相关文章

(5.2)uboot详解——省电模式(番外)

(5.2)uboot详解--省电模式(番外) 这篇文章将对uboot的省电模式进行分析,这里介绍的内容与uboot的启动其实关系不大,如果关心uboot的启动过程,可以跳过这节以及后面的小节,直接到第6章. 省电模式和cpu的工作模式(异常)其实关系也不大,省电模式主要是依靠时钟来分类的,因为外设的工作必须要时钟,当停止给外设提供时钟的时候,相应的外设也会停止工作,所以省电管理就是根据控制是否给相应的设备提供时钟或电源来达到节电的目的. ARM有四中节电模式: 普通模式:这种模式下,会给所有的外

linux移植u-boot(一)——U-Boot详解+自定义命令实战

linux移植u-boot(一)--U-Boot详解+自定义命令实战 2015-02-07 一.Bootloader ????简单地说:Bootloader主要功能就是 在系统上电时开始执行,初始化硬件和设备,准备好软件环境,最后调用操作系统. ????具体的包含:关闭你看门狗WATCHDOG,改变系统时钟,初始化存储控制器 ,将操作系统内核代码复制到内存中去运行. ????为了开发方便,可以增加网络功能,从PC上通过串口或者网络下载文件,烧写文件,将flash上的内核代码解压后运行等. Boo

(3)uboot详解——饿了么,我们来喂“狗”吧

(3)uboot详解--饿了么,我们来喂"狗"吧 uboot启动时,当将cpu运行模式设置为管理模式后,就要关闭看门狗了,那么看门狗是干什么的呢? 狗狗是我们的好朋友,有时候,一条好狗狗能够救主人的性命,"看门狗"是cpu的"好朋友",它也能够在cpu出状况的时候把它救活. 看门狗其实就是一个可以在一定时间内被复位的计数器,当看门狗启动后,计数器开始自动计数,经过一定时间,cpu就会将这个计数器复位,如果没有被复位,计数器溢出就会对CPU产生一个

详解Java基础--异常

经常写程序的人对try...catch...finally语句肯定是不陌生的了.但是好多人总对异常搞不太清楚,不知道这个异常什么意思,不知道为什么用这个异常处理,这篇博客为大家从本质上剖析一下java中的异常处理的工作原理. 一.定义 在<java编程思想>中这样定义异常:阻止当前方法或作用域继续执行的问题. 这是书面上的语言,翻译成我们自己的语言其实就是程序运行出现了问题.具体一点说就是程序运行出现了问题,可能会导致程序运行机制.所以就要通过抛出异常的方式告诉开发者哪里出现了问题. 二.异常

Linux中Uboot详解

在专用的嵌入式板子运行 GNU/Linux 系统已经变得越来越流行.一个嵌入式 Linux 系统从软件的角度看通常可以分为四个层次: 1. 引导加载程序.包括固化在固件(firmware)中的 boot 代码(可选),和 Boot Loader 两大部分. 2. Linux 内核.特定于嵌入式板子的定制内核以及内核的启动参数. 3. 文件系统.包括根文件系统和建立于 Flash 内存设备之上文件系统.通常用 ram disk 来作为 root fs. 4. 用户应用程序.特定于用户的应用程序.有

(1)uboot详解——板子刚上电时都干了些什么

电子产品如果没有了电,就跟废品没什么区别,是电赋予了他们生命,然而程序则是他们的灵魂. 小时候一直很好奇,一个个死板的电子产品为什么一上电以后就能够工作了呢?为什么一个小小芯片就能够运行我们编写的程序呢?一个开发板从刚上电到整个操作系统能够运行起来是怎么办到的呢?这些东西困扰了好久,参考了好多资料现在才慢慢弄明白其中一些原理. 我们现在接触的大多数电子产品都是使用数字电路设计出来的,数字电路的精髓就是两个数字:0和1,这两个数字千变万化的组合创造了计算机世界的缤纷多彩,不管是cpu.内存还是其他

uboot——详解各目录下的文件作用

uboot下载地址:http://ftp.denx.de/pub/u-boot/ 1.目录分布 2.目录结构变化: u-boot-2010.03及以前版本 ├── api                存放uboot提供的接口函数 ├── board              根据不同开发板定制的代码,代码也不少 ├── common             通用的代码,涵盖各个方面,已命令行处理为主 ├── cpu                与体系结构相关的代码,uboot的重头戏 ├──

异常处理与MiniDump详解(4) MiniDump

http://blog.csdn.net/vagrxie/article/details/4398721 异常处理与MiniDump详解(4) MiniDump 分类:             [Windows]              2009-07-31 23:18     23631人阅读     评论(12)     收藏     举报 exceptionpointersmicrosoftfunwindowsnull 目录(?)[+] 一   综述 二   基本应用 怎么感知到程序的崩

SVM-支持向量机原理详解与实践之一

目录(?)[+] 前言 SVM机器学习与深度学习 人工智能领域 机器学习与深度学习 SVM简介 SVM原理分析 快速理解SVM原理 线性可分和线性不可分 函数间隔和几何间隔 超平面分析与几何间隔详解 二次最优化 SVM-支持向量机原理详解与实践 前言 去年由于工作项目的需要实际运用到了SVM和ANN算法,也就是支持向量机和人工神经网络算法,主要是实现项目中的实时采集图片(工业高速摄像头采集)的图像识别的这一部分功能,虽然几经波折,但是还好最终还算顺利完成了项目的任务,忙碌一年,趁着放假有时间好好