s3c2440裸机-异常中断3-swi软中断

发布者:SereneSoul55最新更新时间:2024-07-05 来源: elecfans关键字:异常中断 手机看文章 扫描二维码
随时随地手机看文章

swi(软中断)

我们知道arm有7中工作模式,除了usr模式,其他6种都是特权模式。我们知道usr模式无法修改CPSR直接进入其他特权模式,但linux应用程序一般运行在usr模式,既然usr模式权限非常低,是无法直接访问硬件寄存器的,那么它是如何访问硬件的呢?


linux应用程序是通过系统调用,从而进入内核态,运行驱动程序来访问的硬件,那么系统调用又是如何实现的呢,就是通过软中断swi指令来进入svc模式,进入到svc模式后当然就能访问硬件啦。

所以我们的应用程序在usr模式想访问硬件,必须切换模式,怎么切换?


有以下两种方式:


1.发生异常或中断(被动的)


2.swi + 某个值(主动的)


现在介绍如何进入软中断swi:


我们知道cpu一上电会跳到0地址(reset复位)执行代码,此时CPU处于svc模式,2440异常向量表如下图所示:


为了验证usr模式能够主动的通过swi软中断指令来进入svc模式, 我们先将模式切换到usr模式,那么这个时候就不能访问硬件了,也不能直接修改cpsr直接进入其他模式。




从上图我们设置CPSR让M4-M0处在10000,这样就进入了usr模式, 然后我们修改。修改start.s如下:


.global _start


    _start:

        b reset  

            ldr pc, und_addr 

            ldr pc, swi_addr

            ...

        und_addr:

            .word do_und

        swi_addr:

            .word do_swi


    reset:

        /*

        看门狗

        时钟

        set SP

        sdram_init

        重定位

        bl uart0_init

        */



        /*先进入usr模式*/

        mrs r0, cpsr      /* 读出cpsr 读到r0 */

        /*使用bic命令 bitclean 把低4位清零*/

        bic r0, r0, #0xf  /* 修改M4-M0为0b10000, 进入usr模式 */

        msr cpsr, r0     /* 写入cpsr */


        /* 设置usr模式下的栈sp_usr */

        ldr sp, =0x33f00000

        swi 0x123  /* 执行此命令, 触发SWI异常, 进入0x8执行 */

        ldr pc, =main  /* 绝对跳转, 跳到SDRAM */


    halt:

        b halt

那么当执行到swi 0x123,就会触发SWI异常, 进入0x8的向量去执行,调用do_swi,我们参考上一节do_und实现我们的软中断服务程序do_swi。


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}


/* 处理swi异常 */

mrs r0, cpsr

ldr r1, =swi_string /*这里r0, r1只是为了给printException传参*/

bl printException


/* 恢复现场 */

ldmia sp!, {r0-r12, pc}^  /* ^会把spsr的值恢复到cpsr里 */


swi_string:

    .string 'swi exception'

完整的代码如下:




展开代码




.global _start

        b reset  

        ldr pc, und_addr 

        ldr pc, swi_addr

        ...

    und_addr:

        .word do_und

    swi_addr:

        .word do_swi


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}


/* 处理swi异常 */

mrs r0, cpsr

ldr r1, =swi_string /*这里r0, r1只是为了给printException传参*/

bl printException


/* 恢复现场 */

ldmia sp!, {r0-r12, pc}^  /* ^会把spsr的值恢复到cpsr里 */


swi_string:

    .string 'swi exception'


.align 4


reset:

    /*

    看门狗

    时钟

    set SP

    sdram_init

    重定位

    bl uart0_init

    */


    /*先进入usr模式*/

    mrs r0, cpsr      /* 读出cpsr 读到r0 */

    /*使用bic命令 bitclean 把低4位清零*/

    bic r0, r0, #0xf  /* 修改M4-M0为0b10000, 进入usr模式 */

    msr cpsr, r0     /* 写入cpsr */


    /* 设置usr模式下的栈sp_usr */

    ldr sp, =0x33f00000

    swi 0x123  /* 执行此命令, 触发SWI异常, 进入0x8执行 */

    ldr pc, =main  /* 绝对跳转, 跳到SDRAM */


halt:

    b halt

测试结果如下:


打印出了软中断异常的字符串和svc模式。


如何打印出swi软中断号 如何才能知道swi的值呢?


我们要读出swi 0x123指令,我们知道当执行完swi 0x123指令以后,会发生swi异常,lr_svc = PC + offset. 从下图看出offset是4.


我们知道lr_svc保存着被中断模式的下一条指令的地址,那么我们把lr寄存器的地址减去4就是当前pc的值,即为swi 0x123这条指令的地址。


do_swi代码修改如下:


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}

我们要把lr拿出来保存,因为bl printException会破坏lr,那么把lr保存在哪个个寄存器比较好呢?


我们知道当调用‘bl printException’可能会修改某些寄存器,但是又会恢复这些寄存器,那么得知道它会保护哪些些寄存器。 我们来看下ATPCS规则:

在子程序中,使用R4~R11来保存局部变量,子程序进入时必须保存这些寄存器的值,在返回前必须恢复这些寄存器的值。所以对于 r4 ~ r11在C函数里会保存这几个寄存器,执行完C函数再把它释放掉并且恢复原来的值。我们把lr 保存在r4寄存器里,r4寄存器不会被C语言破坏。


mov r4, lr


    /* 处理swi异常 */

    mrs r0, cpsr

    ldr r1, =swi_string

    bl printException

当执行完‘swi 0x123’指令后,会发生一次异常,那个异常模式里的lr寄存器会保存下一条指令的地址(即'ldr pc, =main'),我们把lr寄存器的地址减去4就是'swi 0x123'这条指令的地址。


把r4的寄存器赋给r0让后打印我们得写出打印函数


mov r0, r4


sub r0, r4, #4  //得到swi指令的地址

bl printSWIVal


    /* 恢复现场 */

    ldmia sp!, {r0-r12, pc}^  /* ^会把spsr的值恢复到cpsr里 */


swi_string:

.string 'swi exception'

在uart.c添加printSWIVal打印函数:


void printSWIVal(unsigned int *pSWI)

{

    puts('SWI val = ');

    printHEx(*pSWI & ~0xff000000); //高8位忽略掉  

    puts('nr');

}


关键字:异常中断 引用地址:s3c2440裸机-异常中断3-swi软中断

上一篇:s3c2440裸机-异常中断4-irq外部中断
下一篇:s3c2440裸机-异常中断2-und未定义指令异常

推荐阅读最新更新时间:2026-03-13 20:23

s3c2440裸机-异常中断(三. swi中断
#swi(软中断) 我们知道arm有7中工作模式,除了usr模式,其他6种都是特权模式。我们知道usr模式无法修改CPSR直接进入其他特权模式,但linux应用程序一般运行在usr模式,既然usr模式权限非常低,是无法直接访问硬件寄存器的,那么它是如何访问硬件的呢? linux应用程序是通过系统调用,从而进入内核态,运行驱动程序来访问的硬件,那么系统调用又是如何实现的呢,就是通过软中断swi指令来进入svc模式,进入到svc模式后当然就能访问硬件啦。 所以我们的应用程序在usr模式想访问硬件,必须切换模式,怎么切换? 有以下两种方式: 1.发生异常或中断(被动的) 2.swi + 某个值(主动的) 现在介绍如何进入软中断s
[单片机]
<font color='red'>s3c2440</font><font color='red'>裸机</font>-<font color='red'>异常中断</font>(三. <font color='red'>swi</font><font color='red'>软</font><font color='red'>中断</font>)
s3c2440裸机-异常中断1-异常中断的原理与流程
1.异常中断概述 在arm架构的处理器中,cpu有7中工作模式,2中工作状态。 1.CPU模式(Mode): 7种Mode: 除了usr/sys,其他5种都是异常模式。我们知道中断属于异常的2中,中断有irq,fiq。 usr sys undefined(und) Supervisor(svc) Abort(abt) irq fiq 用户模式 系统模式 未定义指令异常模 svc管理模式 终止模式(1.指令预取终止(读写某条错误的指令导致终止运行);2.数据访问终止(读写某个非法地址程序终止)) irq中断 快中断 除了usr模式,其他6中为特权模式。 CPU无法从usr模式直接进入特权模式。不能直接进入特权模式,那么怎
[单片机]
基于ARM7内核的SWI中断功能设计方案详解
笔者在设计一项目时采用LPC2458。此CPU为ARM7内核,带512K字节的片内FLASH,98k字节的片内RAM,支持片外LOCAL BUS总线,可从片外NOR FLASH启动CPU.由于代码量较大,程序放在片外的NOR FLASH中。且存在片外NOR FLASH在运行程序时,需对片外的NOR FLASH擦写的需求。 图1存储部分原理框图 在设计中,片外NOR FLASH的大小为16M字节。其中2M规划为存放运行程序,剩余的空间用于产品运行日志,告警灯存储空间。因此存在着在程序运行时对片外NOR FLASH擦写的需求。如果程序正在正常运行的片外FLASH中去擦写FLASH,会存在总线冲突的问题,无法实现此功能。我们采用A
[单片机]
基于ARM7内核的<font color='red'>SWI</font><font color='red'>软</font><font color='red'>中断</font>功能设计方案详解
十四、s3c2440裸机中断控制器
14.1 中断体系 ARM 体系的CPU 有 7 种工作模式 用户模式(usr):ARM 处理器正常的程序执行状态 快速中断模式(fiq):用于高速数据传输或通道处理 中断模式(irq):用户通用的中断处理   管理模式(svc):操作系统使用的保护模式 数据访问终止模式(abt):当数据或指令预取终止时进入该模式,可用于虚拟存储及存储保护 系统模式(sys):运行具有特权的操作系统任务 未定义指令中止模式(und):当未定义的指令执行时进入该模式,可用于支持硬件协处理器的软件仿真   可通过软件来进行模式切换,或者发生各类中断、异常时CPU自动进入相应的模式。除用户模式外,其他6种工作模式都属于特权模式,
[单片机]
十四、<font color='red'>s3c2440</font><font color='red'>裸机</font>—<font color='red'>中断</font>控制器
s3c2440裸机开发调试环境(MDK4.72,Jlink v8,mini2440)
我的开发环境:windows 7 32位,J-linkv8,mini2440开发板一块。最后选择了:MDK4.72版本,J-ink v8的当前最新版本J-linkARM v4.94。 1)打开Keil uVision4新建一个工程: 2)新建一个目录用于存放我们的工程文件,这样我用新建一个test目录:并且取工程名为test并保存: 3)接下来选择CUP database:我们选择samsung的S3C2440A,点击OK;之后会出现第二个图问你是否拷贝'S3C2440.s'到工程文件夹并加入到工程里,S3C2440.s是启动代码我们选择YES 4)然后我们需要对S3C2440.s进行一些
[单片机]
<font color='red'>s3c2440</font><font color='red'>裸机</font>开发调试环境(MDK4.72,Jlink v8,mini2440)
S3C2440 裸机程序之音频
/**************************************************************** NAME: u2440mon.c DESC: u2440mon entry point,menu,download HISTORY: Mar.25.2002:purnnamu: S3C2400X profile.c is ported for S3C2410X. Mar.27.2002:purnnamu: DMA is enabled. Apr.01.2002:purnnamu: isDownloadReady flag is added. Apr.10.2002:purnnamu: - Select
[单片机]
s3c2440裸机-时钟编程-2-配置时钟寄存器
1.2440时钟时序 下图是2440时钟配置时序: 1.上电后,nRESET复位信号拉低,此时cpu还无法取指令工作。 2.nRESET复位信号结束后变为高电平,此时cpu开始工作。此时cpu主频FCLK=osc。 3.此时可以配置PLL,经过lock time后,FCLK倍频成新的时钟。 2.如何配置时钟 在参考手册的特性里介绍了S3C2440的工作频率,Fclk最高400MHz,Hclk最高136MHz,Pclk最高68MHz。那么 我们干脆配置FCLK:HCLK:PCLK= 400:100:50 (MHz). 1,先配置lock time 我们取芯片手册上的推荐值。
[单片机]
s3c2440裸机-UART编程1-UART硬件介绍及传输原理
1.uart硬件介绍 UART的全称是Universal Asynchronous Receiver and Transmitter(异步收发器)。 uart主要用于: 1.打印调试 2.数据传输 串口通过三根线即可,发送、接收、地线。 pc的TxD - arm的RxD (UART write) arm的TxD - pc的RxD (UART read) 2.uart的参数和格式 波特率:表示每秒传输多少bit,bits per second(bps).一般波特率都会有9600,19200,115200等选项。 格式: 起始位: 先发出一个逻辑”0”的信号,表示传输数据的开始。 数据位:可以是5~8位逻辑”0”或”1”。
[单片机]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved