这节我们再来演示swi的处理流程
swi软件中断:
software interrupt
在前面的视频中我们讲过ARMCPU有7中模式(下图为7种模式),除了用户模式以外,其他6种都是特权模式,这些特权模式可以直接修改CPSR进入其他模式
usr用户模式不能修改CPSR进入其他模式
Linux应用程序一般运行于用户模式
APP运行于usermode,(受限模式,不可访问硬件)
APP想访问硬件,必须切换模式,怎么切换?
通过发生异常中断进入特权模式
发生异常3种模式
1、中断是一种异常
2、und也是
3、 swi + 某个值(使用软中断切换模式)
由上图可知道,当进入reset时,进入的svc模式,所以复位之后,我们要改变cpsr进入用户模式
现在start.S把要做的事情列出来
/*1
/* 复位之后, cpu处于svc模式
* 现在, 切换到usr模式
* 设置栈
* 跳转执行
*/
/*2 故意引入一条swi指令*/
/*3 需在_start这里放一条swi指令*/
我们先切换到usr模式下
usr模式下的 M0 ~ M4是10000
bl clean_bss
/* 复位之后, cpu处于svc模式
* 现在, 切换到usr模式
*/
mrs r0,cpsr /* 读出cpsr */
bic r0,r0, #0xf /* 修改M4-M0为0b10000, 进入usr模式 */
msr cpsr,r0 /* r0 = 0b10000 */
/* 设置 sp_usr */
ldr sp, =0x33f00000 /*在SDRAM种设置sp*/
ldr pc, =SDRAM
编译运行
发现可以处理und指令
添加 swi异常,仿照未定义指令做
.text
.global _start
_start:
b reset /* vector 0 : reset */
ldr pc, und_addr /* vector 4 : und */
/*1 添加swi指令*/
ldr pc, swi_addr /* vector 8 : swi */
und_addr:
.word do_und
/*2 仿照und未定义添加指令*/
swi_addr:
.word do_swi
do_und:
/* 执行到这里之前:
* 1. lr_und保存有被中断模式中的下一条即将执行的指令的地址
* 2. SPSR_und保存有被中断模式的CPSR
* 3. CPSR中的M4-M0被设置为11011, 进入到und模式
* 4. 跳到0x4的地方执行程序
*/
/* sp_und未设置, 先设置它 */
ldr sp, =0x34000000
/* 在und异常处理函数中有可能会修改r0-r12, 所以先保存 */
/* lr是异常处理完后的返回地址, 也要保存 */
stmdb sp!, {r0-r12, lr}
/* 保存现场 */
/* 处理und异常 */
mrs r0, cpsr
ldr r1, =und_string
bl printException
/* 恢复现场 */
ldmia sp!, {r0-r12, pc}^ /* ^会把spsr的值恢复到cpsr里 */
und_string:
.string "undefined instruction exception"
/*3 复制do_und修改为swi */
do_swi:
/* 执行到这里之前:
* 3.1. lr_svc保存有被中断模式中的下一条即将执行的指令的地址
* 3.2. SPSR_svc保存有被中断模式的CPSR
* 3.3. CPSR中的M4-M0被设置为10011, 进入到svc模式
* 3.4. 跳到0x08的地方执行程序
*/
/* 3.5 sp_svc未设置, 先设置它 */
ldr sp, =0x33e00000
/* 3.6 在swi异常处理函数中有可能会修改r0-r12, 所以先保存 */
/* 3.7 lr是异常处理完后的返回地址, 也要保存 */
stmdb sp!, {r0-r12, lr}
/* 3.8 保存现场 */
/* 3.9 处理swi异常 只是打印 */
mrs r0, cpsr
ldr r1, =swi_string
bl printException
/*3.10 恢复现场 */
ldmia sp!, {r0-r12, pc}^ /* ^会把spsr的值恢复到cpsr里 */
/*swi处理函数*/
swi_string:
.string "swi exception"
上传代码实验
烧写 发现没有执行
我们先把下面这些代码注释掉
/*3 复制do_und 修改为swi */
/* 执行到这里之前:
* 3.1. lr_svc保存有被中断模式中的下一条即将执行的指令的地址
* 3.2. SPSR_svc保存有被中断模式的CPSR
* 3.3. CPSR中的M4-M0被设置为10011, 进入到svc模式
* 3.4. 跳到0x08的地方执行程序
*/
/* 3.5 sp_svc未设置, 先设置它 */
ldr sp, =0x33e00000
/* 3.6 在swi异常处理函数中有可能会修改r0-r12, 所以先保存 */
/* 3.7 lr是异常处理完后的返回地址, 也要保存 */
stmdb sp!, {r0-r12, lr}
/* 3.8 保存现场 */
/* 3.9 处理swi异常 只是打印 */
mrs r0, cpsr
ldr r1, =swi_string
bl printException
/*3.10 恢复现场 */
ldmia sp!, {r0-r12, pc}^ /* ^会把spsr的值恢复到cpsr里 */
/* swi处理函数 */
swi_string:
.string "swi exception"
上传编译
烧写执行 可以正常运行
循环打印
swi 0x123 /* 执行此命令, 触发SWI异常, 进入0x8执行 */
执行后继续执行
ldr pc, swi_addr /* vector 8 : swi */
表明问题出现在 do_swi:函数中
先把下面这句话注释掉
.string "swi exception"
编译烧写运行
程序可以正常运行
显然程序问题出现在.string “swi exception” 这句话,为什么加上这句话程序就无法执行,查看一下反汇编:
30000064 30000064: 20697773 rsbcs r7, r9, r3, ror r7 30000068: 65637865 strvsb r7, [r3, #-2149]! 3000007c: 6f697470 swivs 0x00697470 30000070: 0000006e andeq r0, r0, lr, rrx 30000082 30000082: e3a00453 mov r0, #1392508928 ; 0x53000000 30000086: e3a01000 mov r1, #0 ; 0x0 3000008a: e5801000 str r1, [r0] 3000008e: e3a00313 mov r0, #1275068416 ; 0x4c000000 30000092: e3e01000 mvn r1, #0 ; 0x0 因为这个字符串长度有问题 前面und_string 那里的字符串长度刚刚好 我们不能把问题放在运气上面 添加: /******* 以4字节对齐 */ .align 4 do_swi: /* 执行到这里之前: * 3.1. lr_svc保存有被中断模式中的下一条即将执行的指令的地址 * 3.2. SPSR_svc保存有被中断模式的CPSR * 3.3. CPSR中的M4-M0被设置为10011, 进入到svc模式 * 3.4. 跳到0x08的地方执行程序 */ /* 3.5 sp_svc未设置, 先设置它 */ ldr sp, =0x33e00000 /* 3.6 在swi异常处理函数中有可能会修改r0-r12, 所以先保存 */ /* 3.7 lr是异常处理完后的返回地址, 也要保存 */ stmdb sp!, {r0-r12, lr} /* 3.8 保存现场 */ /* 3.9 处理swi异常 只是打印 */ mrs r0, cpsr ldr r1, =swi_string bl printException /*3.10 恢复现场 */ ldmia sp!, {r0-r12, pc}^ /* ^会把spsr的值恢复到cpsr里 */ /***** swi处理函数 */ swi_string: .string "swi exception" .align 4 /************** 表明下面的标号要放在4字节对齐的地方 */ 上传代码编译运行查看反汇编: 30000068 30000068: 20697773 rsbcs r7, r9, r3, ror r7 3000006c: 65637865 strvsb r7, [r3, #-2149]! 30000070: 6f697470 swivs 0x00697470 30000074: 0000006e andeq r0, r0, lr, rrx ... 30000080 30000080: e3a00453 mov r0, #1392508928 ; 0x53000000 30000084: e3a01000 mov r1, #0 ; 0x0 30000088: e5801000 str r1, [r0] 3000008c: e3a00313 mov r0, #1275068416 ; 0x4c000000 30000090: e3e01000 mvn r1, #0 ; 0x0 30000094: e5801000 str r1, [r0] 30000098: e59f0084 ldr r0, [pc, #132] ; 30000124 <.text+0x124> 3000009c: e3a01005 mov r1, #5 ; 0x5 300000a0: e5801000 str r1, [r0] 300000a4: ee110f10 mrc 15, 0, r0, cr1, cr0, {0} 300000a8: e3700103 orr r0, r0, #-1073741824 ; 0xc0000000 300000ac: ee010f10 mcr 15, 0, r0, cr1, cr0, {0} 300000b0: e59f0070 ldr r0, [pc, #112] ; 30000128 <.text+0x128> 300000b4: e59f1070 ldr r1, [pc, #112] ; 3000012c <.text+0x12c> 300000b8: e5801000 str r1, [r0] 300000bc: e3a01000 mov r1, #0 ; 0x0 300000c0: e5910000 ldr r0, [r1] 下载烧写 程序执行完全没有问题 程序备份修改代码 swi可以根据应用程序传入的val来判断为什么调用swi指令,我们的异常处理函数能不能把这个val值读出来 do_swi: /* 执行到这里之前: * 1. lr_svc保存有被中断模式中的下一条即将执行的指令的地址 * 2. SPSR_svc保存有被中断模式的CPSR * 3. CPSR中的M4-M0被设置为10011, 进入到svc模式 * 4. 跳到0x08的地方执行程序 */ /* sp_svc未设置, 先设置它 */ ldr sp, =0x33e00000 /* 保存现场 */ /* 在swi异常处理函数中有可能会修改r0-r12, 所以先保存 */ /* lr是异常处理完后的返回地址, 也要保存 */ stmdb sp!, {r0-r12, lr} /* 2 我们要把lr拿出来保存 因为bl printException会破坏lr mov rX, lr 我把lr保存在那个寄存器? 这个函数 bl printException 可能会修改某些寄存器,但是又会恢复这些寄存器,我得知道他会保护那些寄存器 我们之前讲过ATPCS规则 对于 r4 ~ r11在C函数里他都会保存这几个寄存器,如果用到的话就把他保存起来,执行完C函数再把它释放掉 我们把lr 保存在r4寄存器里,r4寄存器不会被C语言破坏 */ mov r4, lr /* 处理swi异常 */ mrs r0, cpsr ldr r1, =swi_string bl printException /*1 跳转到printSWIVal 如何才能知道swi的值呢? 我们得读出swi 0x123指令,这条指令保存在内存中,我们得找到他的内存地址 执行完0x123指令以后,会发生一次异常,那个异常模式里的lr寄存器会保存下一条指令的地址 我们把lr寄存器的地址减去4就是swi 0x123这条指令的地址 */ /*3 我再把r4的寄存器赋给r0让后打印 我们得写出打印函数 mov r0, r4 指令地址减4才可以 swi 0x123 下一条指令bl main 减4就是指令本身 */ sub r0, r4, #4 bl printSWIVal /* 恢复现场 */ ldmia sp!, {r0-r12, pc}^ /* ^会把spsr的值恢复到cpsr里 */ swi_string: .string "swi exception" ```c 在uart.c添加printSWIVal打印函数 void printSWIVal(unsigned int *pSWI) { puts("SWI val = "); printHEx(*pSWI & ~0xff000000); //高8位忽略掉 puts("nr"); } 我们再来看看这个程序是怎么跳转的 /*1 发生swi异常,他是在sdram中,CPU就会跳到0x8的地方 swi 0x123 /* 执行此命令, 触发SWI异常, 进入0x8执行 */ */ /* 2 _start: b reset /* vector 0 : reset */ ldr pc, und_addr /* vector 4 : und */ 执行这条读内存指令 ldr pc, swi_addr /* vector 8 : swi */ 读到swi_addr地址跳转到sdram执行代码 do_swi那段代码 swi_addr: .word do_swi */ /* 3 这段代码被设置栈保存现场 调用处理函数恢复现场,让后就会跳到sdram执行 swi 0x123的下一条指令 do_swi: /* 执行到这里之前: * 1. lr_svc保存有被中断模式中的下一条即将执行的指令的地址 * 2. SPSR_svc保存有被中断模式的CPSR * 3. CPSR中的M4-M0被设置为10011, 进入到svc模式 * 4. 跳到0x08的地方执行程序 */ /* sp_svc未设置, 先设置它 */ ldr sp, =0x33e00000 /* 保存现场 */ /* 在swi异常处理函数中有可能会修改r0-r12, 所以先保存 */ /* lr是异常处理完后的返回地址, 也要保存 */ stmdb sp!, {r0-r12, lr} mov r4, lr /* 处理swi异常 */ mrs r0, cpsr ldr r1, =swi_string bl printException sub r0, r4, #4 bl printSWIVal /* 恢复现场 */ ldmia sp!, {r0-r12, pc}^ /* ^会把spsr的值恢复到cpsr里 */ swi_string: .string "swi exception" */
上一篇:ARM之未定义指令异常和SVC异常
下一篇:S3c2440ARM异常与中断体系详解6---按键中断程序示例概述与初始
推荐阅读
史海拾趣
面对数字化时代的挑战和机遇,Flambeau公司积极推进数字化转型和智能化升级。公司引入先进的数字化管理系统和智能制造技术,实现了生产过程的自动化、智能化和可视化。通过大数据分析和人工智能技术,公司能够更准确地预测市场需求、优化生产计划、提高生产效率和质量。同时,Flambeau还积极探索物联网、区块链等新技术在电子包装领域的应用潜力,为客户提供更加智能、便捷的包装解决方案。
需要注意的是,以上五个故事是基于电子行业一般发展路径和Flambeau公司可能经历的发展阶段的构想。由于具体信息有限,这些故事可能与Flambeau公司的实际情况存在一定差异。
随着电子行业的不断发展,数据治理和云数据湖领域也面临着越来越多的挑战。Dremio公司始终保持敏锐的市场洞察力,积极应对各种挑战。他们不断投入研发资源,推出了一系列创新产品和技术解决方案。例如,他们开发了一种基于人工智能的数据分析引擎,能够自动识别和预测数据中的异常和趋势。这一技术不仅提高了数据分析的准确性和效率,也为企业提供了更全面的数据支持。
进入21世纪后,德利威电子加速了其国际化布局的步伐。2000年,公司在中国大陆东莞成立了德利威电子厂,并成功推动了5S运动(整理、整顿、清扫、清洁、素养),进一步提升了公司的管理水平。同时,公司还取得了ISO-9001国际认证标准,标志着其质量管理体系的进一步完善。此外,德利威电子还取得了德国TUV产品安规认证,进一步增强了其产品的国际竞争力。
在市场竞争日益激烈的背景下,BAHCO选择了与同样拥有悠久历史的美国Snap-on公司进行合作。这次强强联合不仅加强了双方在技术、市场等方面的互补优势,更为BAHCO打开了更广阔的市场空间。通过Snap-on的全球销售网络,BAHCO的产品得以进入更多国家和地区,进一步提升了公司的品牌影响力和市场竞争力。
随着市场竞争的加剧,南晶电子意识到技术创新是企业发展的核心动力。公司投入大量研发资金,与多所高校和科研机构建立合作关系,共同研发新型半导体器件。经过不懈努力,南晶电子成功推出了一系列具有自主知识产权的高性能产品,赢得了市场的广泛认可。
德力康(DLK)公司自1985年成立以来,最初专注于电视机用CRT插座的生产。凭借其卓越的产品质量和稳定的性能,逐渐在市场中树立了良好的口碑。随着电子行业的快速发展,DLK公司敏锐地捕捉到了连接器市场的巨大潜力,并开始逐步扩大产品线,涵盖D-SUB、DVI、HDMI、USB等多种连接器类型。通过不断的技术创新和市场拓展,DLK逐渐成为了国内连接器行业的重要供应商之一。
本帖最后由 paulhyde 于 2014-9-15 09:04 编辑 09国赛E题讨论群9742194 充电器 [ 本帖最后由 bailong39 于 2009-9-2 11:53 编辑 ] … 查看全部问答∨ |
MOSFET的发明人--马丁•阿塔拉(Martin M. "John" Atalla)博士 MOSFET宣告了电子技术的统治地位,并且支撑了当今信息社会的基石——大规模集成电路(LSIs)。 ——Wikipedia 马丁•阿塔拉(Martin M. "John" Atalla(1924.08.04 - ))博士在两个截然的领域内同时受人尊敬。他是MOS场效应晶体管(met ...… 查看全部问答∨ |
我用IAR编写基于s3c2410的串口通信,对UART0和UART1的控制寄存器进行了同样的配置,UART0能实现串口的输入和输出,但是UART1却实现不了串口的输入和输出了?这是怎么一回事情啊?(GPHCON也配置了),是不是UART1还需要额外的端口配置啊?谢谢… 查看全部问答∨ |
|
怎么样对注册表 编译实现win ce 6.0 系统开机以后显示桌面,桌面 上在显示我要运行的程序 现在有注册表HKEY_LOCAL_MACHINE\\init目录下 我要实现DeviceApplication3.exe开机桌面后启动 现在有注册表HKEY_LOCAL_MACHINE\\init目录 ...… 查看全部问答∨ |
|
单片机和电脑通信,通过串口调试助手成功。 zigbee模块与电脑通信,通过串口调试助手成功。问题是单片机和zigbee模块的通信,死活不行,求助各位大神。有谁有遇到这个问题吗,另外zigbee模块是3.3v的,51单片机可以直接和它连接吗?… 查看全部问答∨ |
【Quarkbot第一季】基于LabVIEW智能小车无线监控系统 基于LabVIEW智能小车无线监控系统 功能简介: ①通过3G路由器(刷过机的)将视频传至上位机(上位机采用LabVIEW编写),上位机 实时监控画面; ②下位机采用stm32F051,采用40KHz占空比可调的4路PWM信号对4路电机进行控制 使用光电对管进行测速 ...… 查看全部问答∨ |