加入收藏 | 设为首页 | 会员中心 | 我要投稿 应用网_丽江站长网 (http://www.0888zz.com/)- 科技、建站、数据工具、云上网络、机器学习!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

系统调用与软件中断SWI的达成

发布时间:2021-11-25 17:27:51 所属栏目:PHP教程 来源:互联网
导读:1 系统调用 操作系统的主要功能是为应用程序的运行创建良好的环境,保障每个程序都可以最大化利用硬件资源,防止非法程序破坏其它应用程序执行环境,为了达到这个目的,操作系统会将硬件的操作权限交给内核来管理,用户程序不能随意使用硬件,使用硬件(对硬

1   系统调用
操作系统的主要功能是为应用程序的运行创建良好的环境,保障每个程序都可以最大化利用硬件资源,防止非法程序破坏其它应用程序执行环境,为了达到这个目的,操作系统会将硬件的操作权限交给内核来管理,用户程序不能随意使用硬件,使用硬件(对硬件寄存器进行读写)时要先向操作系统发出请求,操作系统内核帮助用户程序实现其操作,也就是说用户程序不会直接操作硬件,而是提供给用户程序一些具备预定功能的内核函数,通过一组称为系统调用的(system call)的接口呈现给用户,系统调用把应用程序的请求传给内核,调用相应的内核函数完成所需的处理,将处理结果返回给应用程序。这好比我们去银行取款,用户自己的银行帐户不可能随意操作,必须要有一个安全的操作流程和规范,银行里的布局通常被分成两部分,中间用透明玻璃分隔开,只留一个小窗口,面向用户的是用户服务区,工作人员所在区域为内部业务操作区,取款时,将银行卡或存折通过小窗口交给业务员,并且告诉他要取多少钱,具体取钱的操作你是不会直接接触的,业务员会将银行帐户里减掉取款金额,将现金给你。上述操作流程可以很好保护银行系统,银行系统的操作全部由业务员来实现,用户只能向业务员提出自己的服务请求。银行里的小窗口就类似与操作系统的系统调用接口,是将用户请求传递给内核的接口。   
 
  
 
 
图3-16系统调用接口示意图
 
操作系统里将用户程序运行在用户模式下,并且为其分配可以使用内存空间,其它内存空间不能访问,内核态运行在特权模式下,对系统所有硬件进行统一管理和控制。从前面所学知识可以了解到,用户模式下没有权限进行模式切换,这也就意味着用户程序不可能直接通过切换模式去访问硬件寄存器,如果用户程序试图访问没有权限的硬件,会产生异常。这样用户程序被限制起来,如果用户程序想要使用硬件时怎么办呢?用户程序使用硬件时,必须调用操作系统提供的API接口才可以,而操作系统API接口通过软件中断方式切换到管理模式下,实现从用户模式下进入特权模式。
 
2   软件中断
软中断是利用硬件中断的概念,用软件方式进行模拟,实现从用户模式切换到特权模式并执行特权程序的机制。
 
硬件中断是由电平的物理特性决定,在电平变化时引发中断操作,而软中断是通过一条具体指令SWI,引发中断操作,也就是说用户程序里可以通过写入SWI指令来切换到特权模式,当CPU执行到SWI指令时会从用户模式切换到管理模式下,执行软件中断处理。由于SWI指令由操作系统提供的API封装起来,并且软件中断处理程序也是操作系统编写者提前写好的,因此用户程序调用API时就是将操作权限交给了操作系统,所以用户程序还是不能随意访问硬件。
 
先来了解下SWI指令。
 
SWI 软中断号immed_24
 
软中断指令相对比较简单,只有一个操作数:immed_24,SWI指令编码格式如图3-17所示。
 
 
 
 
图3-17 SWI指令编码格式
 
SWI指令编码中immed_24为24位任意有效立即数(范围0~2^24-1),当该指令被执行时系统产生软中断异常,切换到管理模式下。用户程序切换到管理模式下后,进入到软中断处理程序,通常软中断异常处理程序都是系统开发人员提前写好的,SWI切换到了特权模式,执行的是系统开发人员写好的异常���理程序,只要该处理程序没有问题,那么用户程序还是不能为所欲为的。
 
SWI指令后面的24立即数是干什么用的呢?用户程序通过SWI指令切换到特权模式,进入软中断处理程序,但是软中断处理程序不知道用户程序到底想要做什么?SWI指令后面的24位用来做用户程序和软中断处理程序之间的接头暗号。通过该软中断立即数来区分用户不同操作,执行不同内核函数。如果用户程序调用系统调用时传递参数,根据ATPCSC语言与汇编混合编程规则将参数放入R0~R4即可。下面的例子通过系统调用函数int led_on(int led_no)实现点亮第led_no 个LED灯,由于C语言里没有SWI 指令对应的语句,因此这儿要用到C语言与汇编混合编程,led_on函数里将参数led_no的值传递给R0,通过软中断SWI指令切换到软中断管理模式,同时R0 软中断方式点亮LED灯,用户通过SWI  #1指令可以点灯,具体点亮哪个灯,通过R0保存参数传递,如果亮灯成功返回对应LED号。
 
系统调用接口函数led_on:
 
#define __led_on_swi_no                          1                 // 软中断号1,调用管理模式下的do_led_on函数
 
int led_on(int led_no){
 
         int ret;                                              // 返回值
 
          __asm{                                            // 由于C程序中没有SWI对应表达式,所以使用混合编程
 
                   mov  r0, led_no                     // 根据ATPCS规则,r0存放第一个参数
 
                   swi    __led_on_swi_no         // 产生SWI软中断,中断号为__led_on_swi_no
 
                   mov  ret, r0                            // 软中断处理结束,取得中断处理返回值,传递给ret变量
 
         }
 
         return ret;                                                  // 将ret返回给调用led_on的语句
 
}
 
3   软中断处理
CPU执行到swi xxx执行后,产生软件中断,由异常处理部分知识可知,软中断产生后CPU将强制将PC的值置为异常向量表地址0x08,在异常向量表0x08处安放跳转指令b HandleSWI,这样CPU就跳往我们自己定义的HandleSWI处执行。
 
首先,软中断处理中通过STMFD  SP!, {R0-R12,  LR}      要保存程序执行现场,将R0~R12通用寄存器数据保存在管理模式下SP栈内,LR由硬件自动保存软中断指令下一条指令的地址(后面利用LR的地址取得SWI指令编码),该寄存器值也保存在SP栈内,将来处理完毕之后返回。由SWI指令编码知识可知, SWI指令低24位保存有软中断号,通过LDR R4, [LR, #-4]指令,取得SWI指令编码(LR为硬件自动保存SWI xxx指令的下一条指令地址,LR – 4就是SWI指令地址),将其保存在R4寄存器中。通过BIC      R4, R4, #0xFF000000指令将SWI指令高8位清除掉,只保留低24位立即数,再根据24位立即数中的软中断号判断用户程序的请求操作。如果24位立即数为1,表示led_on系统调用产生的软中断,则在管理模式下调用对应的亮灯操作do_led_on。如果24位立即数为2,表示led_off系统调用产生的软中断,则调用灭灯操作do_led_on,根据ATPCS调用规则,R0~R3做为参数传递寄存器,在软中断处理中没有使用这4个寄存器,而是使用R4作为操作寄存器的。执行完系统调用操作之后,返回到swi_return(在调用对应系统操作时,通过LDREQ    LR, =swi_return设置了返回地址),执行返回处理,通过LDMIA    SP!, {R0-R12, PC}^ 指令将用户寄存器数据恢复到R0~R12,将进入软中断处理时保存的返回地址LR的值恢复给PC,实现程序返回,同时还恢复了状态寄存器。切换回用户模式下程序中继续执行。
 
; 异常向量表开始
 
; 0x00: 复位Reset异常
 
         b       Reset
 
 
 
; 0x04: 未定义异常(未处理)
 
HandleUndef
 
           b       HandleUndef
 
 
 
; 0x08: 软件中断异常,跳往软件中断处���函数HandleSWI
 
    b         HandleSWI
 
… …
 
; 省略其它异常向量和对应处理
 
… …
 
;***********************************************************************
 
; 软中断处理
 
;***********************************************************************
 
IMPORT do_led_on
 
IMPORT do_led_off
 
HandleSWI
 
         STMFD     SP!, {R0-R12,  LR}            ; 保存程序执行现场
 
         LDR R4, [LR, #-4]                                   ; LR - 4 为指令" swi xxx" 的地址,低24位是软件中断号
 
         BIC   R4, R4, #0xFF000000                    ; 取得ARM指令24位立即数
 
          
 
         CMP          R4, #1                                    ; 判断24位立即数,如果为1,调用do_led_on系统调用
 
         LDREQ     LR, =swi_return                    ; 软中断处理返回地址
 
         LDREQ     PC, = do_led_on                    ; 软中断号1对应系统调用处理
 
          
 
         CMP          R4, #2                                    ; 判断24位立即数,如果为2,调用do_led_off系统调用
 
         LDREQ     LR, =swi_return                    ; 软中断处理返回地址
 
         LDREQ     PC, = do_led_off                            ; 软中断号2对应系统调用处理
 
          
 
         MOVNE    R0, #-1                                   ; 没有该软中断号对应函数,出错返回-1
 
swi_return
 
         LDMIA     SP!, {R0-R12, PC}^             ; 中断返回, ^表示将spsr的值复制到cpsr
 
1.1.4   led系统调用实验
本实验通过Led跑马灯效果来模拟系统调用,本程序提供了两个系统调用接口led_on和led_off,用户程序main.c通过引入头文件led.h使用系统调用接口,用户调用led_on和led_off时通过软中断指令切换到管理模式,在管理模式下调用内核led操作系统do_led_on和do_led_off,实现Led的亮灭。实验源码适用于QQ2440,TQ2440,MINI2440开发板。
 
head.s:
 
本程序文件主要用于安装异常向量表,Reset异常处理,软中断处理和必要硬件初始化。
 
;**********************************************************************
 
; 系统调用实验(QQ2440, MINI2440,TQ2440)
 
;**********************************************************************
 
GPBCON   EQU      0x56000010
 
GPBDAT    EQU      0x56000014   
 
SYS_STACK_BASE EQU    0x33000000    
 
EXPORT   SWI_LED
 
AREA        SWI_LED ,CODE,READONLY
 
ENTRY
 
;**********************************************************************      
 
; 设置中断向量,除Reset和HandleSWI外,其它异常都没有使用(如果不幸发生了,
 
; 将导致死机)
 
;**********************************************************************      
 
; 0x00: 复位Reset异常
 
b        Reset
 
 
 
; 0x04: 未定义异常(未处理)
 
HandleUndef
 
b        HandleUndef
 
 
 
; 0x08: 软件中断异常,跳往软件中断处理函数HandleSWI
 
b        HandleSWI
 
 
 
; 0x0c: 指令预取异常(未处理)
 
HandlePrefetchAbt
 
b        HandlePrefetchAbt
 
 
 
; 0x10: 数据访问中止异常(未处理)
 
HandleDataAbt
 
b        HandleDataAbt
 
 
 
; 0x14: 未使用异常(未处理)
 
HandleNotUsed
 
b        HandleNotUsed
 
 
 
; 0x18: 一般中断异常(未处理)
 
HandleIRQ
 
b        HandleIRQ
 
 
 
; 0x1c: 快速中断异常(未处理)
 
HandleFIQ
 
b        HandleFIQ
 
 
 
Reset                                                                          ; 复位异常处理入口
 
; 关闭看门狗
 
ldr  r0, = 0x53000000
 
mov  r1, #0
 
str  r1, [r0]
 
 
bl  initmem
 
 
 
ldr      sp,     =0x32000000                                           ; 设置管理模式栈指针
 
 
; LED灯初始化
 
ldr  r0, =GPBCON                                                   ; LED的GPIO接口配置寄存器
 
ldr  r1, =0x00015400                                                ; GPIO配置数据
 
str  r1, [r0]                                                              ; 设置GPIO
 
         
 
ldr  r0, =GPBDAT                                                              ; Led数据寄存器
 
ldr  r1, =0x1e0                                                          ; 熄灭所有Led
 
str  r1, [r0]
 
 
 
msr    cpsr_c,       #0xdf        
 
ldr      sp, =SYS_STACK_BASE
 
msr    cpsr_c,       #0x50                                   ; 开启系统中断,进入用户模式,该指令执行完
 
                                                                       ; 就进入用户空间,执行用户程序xmain
 
 
 
ldr      lr,      =halt_loop                                       ; 设置管理模式下返回地址
 
IMPORT xmain
 
ldr      pc,     =xmain                                            ; 跳入主函数main里执行
 
          
 
halt_loop
 
b   halt_loop
 
 
;***********************************************************************
 
; 软中断处理
 
;***********************************************************************
 
IMPORT do_led_on
 
IMPORT do_led_off
 
HandleSWI
 
STMFD      SP!, {R0-R12,  LR}   ; 保存程序执行现场
 
LDR   R4, [LR, #-4]                     ; LR - 4 为指令" swi xxx" 的地址,指令低24位软件中断号
 
BIC     R4, R4, #0xFF000000       ; 取得ARM指令24位立即数
 
         
 
CMP           R4, #1                           ; 判断24位立即数的值,如果为1,调用do_led_on系统调用
 
LDREQ      LR, =swi_return           ; 软中断处理返回地址
 
LDREQ      PC, = do_led_on          ; 软中断号1对应系统调用处理
 
         
 
CMP           R4, #2                           ; 判断24位立即数的值,如果为2,调用do_led_off系统调用
 
LDREQ      LR, =swi_return           ; 软中断处理返回地址
 
LDREQ      PC, = do_led_off                   ; 软中断号2对应系统调用处理
 
         
 
MOVNE    R0, #-1                         ; 没有该软中断号对应函数,出错返回-1
 
          
 
swi_return
 
LDMIA      SP!, {R0-R12, PC}^    ; 中断返回, ^表示将spsr的值复制到cpsr
 
          
 
initmem
 
ldr  r0, =0x48000000                     ; 内存控制寄存器起始地址
 
ldr  r1, =0x48000034                     ; 内存控制寄存器结束地址
 
adr  r2, memdata                                     ; 加载寄存器设置数据区首地址
 
initmemloop
 
ldr  r3, [r2], #4
 
str  r3, [r0], #4
 
teq  r0, r1
 
bne  initmemloop                                     ; 循环设置每一个寄存器
 
mov  pc, lr
 
 
 
memdata
 
DCD 0x22000000                ;BWSCON
 
DCD 0x00000700                 ;BANKCON0    
 
DCD 0x00000700                 ;BANKCON1    
 
DCD 0x00000700                 ;BANKCON2    
 
DCD 0x00000700               ;BANKCON3             
 
DCD 0x00000700                 ;BANKCON4    
 
DCD 0x00000700                 ;BANKCON5    
 
DCD 0x00018005                 ;BANKCON6    
 
DCD 0x00018005                 ;BANKCON7    
 
DCD 0x008e07a3                  ;REFRESH        
 
DCD 0x000000b1                 ;BANKSIZE      
 
DCD 0x00000030                 ;MRSRB6
 
DCD 0x00000030                 ;MRSRB7
 
 
END                                                ; 代码结束
 
main.c:
 
本程序文件是用户程序xmain,主要实现跑马灯效果,通过使用系统调用led_on,led_off实现Led控制。
 
#include "led.h"
 
 
 
/* 亮灯延时 */
 
void delay(int msec)
 
{
 
         int i, j;
 
         for(i = 1000; i > 0; i--)
 
                    for(j = msec*10; j > 0; j--)
 
                    /* do nothing */;
 
}
 
 
 
/* 主函数跑马灯效果 */
 
int xmain()
 
{
 
         while(1)
 
         {
 
              led_on(1);
 
              delay(5);              //delay
 
      
 
             led_on(2);
 
             delay(5);              //delay
 
      
 
             led_on(3);
 
             delay(5);              //delay
 
      
 
             led_on(4);
 
             delay(5);              //delay
 
      
 
             led_off(1);
 
             delay(5);              //delay
 
      
 
             led_off(2);
 
             delay(5);              //delay
 
      
 
             led_off(3);
 
             delay(5);              //delay
 
      
 
             led_off(4);
 
             delay(5);              //delay
 
    }
 
    return 0;
 
}
 
 
 
led_lib.c
 
本程序文件是系统调用函数led_on, led_off的具体实现,通过swi软中断提交硬件访问请求,将具体请求以软中断号的方式通过参数传递给内核空间。
 
#include "led.h"
 
 
 
#define __led_on_swi_no                1                 // 软中断号1,调用管理模式下的do_led_on函数
 
#define __led_off_swi_no                2                 // 软中断号2,调用管理模式下的do_led_off函数
 
 
 
int led_on(int led_no){
 
         int ret;                                                       // 返回值
 
          __asm{                                                     // 由于C程序中没有SWI对应表达式,所以使用混合编程
 
                   mov  r0, led_no                               // 根据ATPCS规则,r0存放第一个参数
 
                   swi    __led_on_swi_no                  // 产生SWI软中断,中断号为__led_on_swi_no
 
                   mov  ret, r0                                     // 软中断处理结束,取得中断处理返回值,传递给ret变量
 
         }
 
         return ret;                                                           // 将ret返回给调用led_on的语句
 
}
 
 
 
 
 
int led_off(int led_no){          
 
         int ret;                                                       // 返回值
 
          __asm{                                                     // 由于C程序中没有SWI对应表达式,所以使用混合编程
 
                   mov  r0, led_no                               // 根据ATPCS规则,r0存放第一个参数
 
                   swi    __led_off_swi_no                       // 产生SWI软中断,中断号为__led_off_swi_no
 
                   mov  ret, r0                                     // 软中断处理结束,取得中断处理返回值,传递给ret变量
 
         }                                                              
 
         return ret;                                                           // 将ret返回给调用led_off的语句
 
}
 
led.h:
 
Led系统调用头文件。
 
extern int led_on(int num);
 
extern int led_off(int num);
 
sys_call.c:
 
本程序文件主要是系统调用接口内核空间do_led_on,do_led_off函数的实现。
 
#include "register.h"
 
/* Led1~Led4初始化 */
 
#define LED1       (1<<5)                          //LED1 GPBDAT[5]
 
#define LED2       (1<<6)                          //LED2 GPBDAT[6]
 
#define LED3       (1<<7)                          //LED3 GPBDAT[7]
 
#define LED4       (1<<8)                          //LED4 GPBDAT[8]
 
 
 
/* 点亮对应num号Led */
 
extern int do_led_on (int num)
 
{
 
  switch(num)
 
  {
 
           case 1:
 
                    GPBDAT = GPBDAT & ~LED1; break;
 
           case 2:
 
                    GPBDAT = GPBDAT & ~LED2; break;
 
           case 3:
 
                    GPBDAT = GPBDAT & ~LED3; break;
 
           case 4:
 
                    GPBDAT = GPBDAT & ~LED4; break;
 
           default:
 
                    return 0;
 
  }
 
  return num;
 
}
 
 
 
/* 关闭对应num号Led */
 
extern int do_led_off(int num)
 
{
 
  switch(num)
 
  {
 
           case 1:
 
                    GPBDAT = GPBDAT | LED1; break;
 
           case 2:
 
                    GPBDAT = GPBDAT | LED2; break;
 
           case 3:
 
                    GPBDAT = GPBDAT | LED3; break;
 
           case 4:
 
                    GPBDAT = GPBDAT | LED4; break;
 
           default:
 
                    return 0;
 
  }
 
  return num;
 
}

(编辑:应用网_丽江站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读