分类: LINUX
2010-12-13 21:20:54
SWI 的例子有:
在以这种方式使用的时候,SWI 允许操作系统拥有一个模块结构,这意味着用来建立完整的操作系统的所需的代码可以被分割成许多小的部分(模块)和一个模块处理程序(handler)。
当 SWI 处理程序得到对特定的例程编号的一个请求的时候,它找到这个例程的位置并执行它,并传递(有关的)任何数据。
SWI &02或
SWI "OS_Write0"这些指令实际上是相同的,将被汇编成相同的指令。唯一的不同是第二个指令使用一个字符串来表示 SWI 编号 &02。在使用采用了字符串编号的程序的时候,在执行之前首先查找这个字符串。
在这里我们不想处理字符串,因为它不能给出它要进行什么的一个真实表示。它们通常用于增进一个程序的清晰程度,但不是实际执行的指令。
让我们再次看一下第一个指令:
SWI &02这是什么意思? 字面的意思是进入 SWI 处理程序并传递值 &02。在 RISC OS 中这意味着执行编号是 &02 的例程。
它是如何这么作的? 它如何传递 SWI 编号和进入 SWI 处理程序?
如果你查看内存的开始 32 字节(位于 0-&1C)并反汇编它们(查开实际的 ARM 指令)你将见到如下:
地址 内容 反汇编让我们仔细看一下。
00000000 : 0..å : E5000030 : STR R0,[R0,#-48]
00000004 : .óŸå : E59FF31C : LDR PC,&00000328
00000008 : .óŸå : E59FF31C : LDR PC,&0000032C
0000000C : .óŸå : E59FF31C : LDR PC,&00000330
00000010 : .óŸå : E59FF31C : LDR PC,&00000334
00000014 : .óŸå : E59FF31C : LDR PC,&00000338
00000018 : .óŸå : E59FF31C : LDR PC,&0000033C
0000001C : 2?ã : E3A0A632 : MOV R10,#&3200000
除了第一个和最后一个指令之外(它们是特殊情况)你见到的都是把一个新值装载到 PC (程序计数器)的指令,它们告诉计算机到哪里去执行下一个指令。还展示了这个值是从内存中的一个地址接受来的。(你可以在 !Zap 主菜单上使用“Read Memory”选项去自己查看一下。)
这看起来好象与 SWI 没多少关系,下面做进一步的说明。
一个 SWI 所做的一切就是把模式改变成超级用户并设置 PC 来执行在地址 &08 处的下一个指令! 把处理器转换到超级用户模式会切换掉两个寄存器 r13 和 r14 并用 r13_svc 和 r14_svc 替换它们。
在进入超级用户模式的时候,还把 r14_svc 设置为在这个 SWI 指令之后的地址。
这个实际上就象一个连接到地址 &08 的分支指令(BL &08),但带有用于一些数据(SWI 编号)的空间。
象我说过的那样,地址 &08 包含跳转到另一个地址的一个指令,就是实际的 SWI 程序的地址!
此时你可能会想“稍等一会! 还有 SWI 编号呢?”。实际上处理器忽略这个值本身。SWI 处理程序使用传递来的 r14_svc 的值来获取它。
下面是完成它的步骤(在存储寄存器 r0-r12 之后):
下面是一个例子,来自 ARM610 datasheet:
0x08 B Supervisor这就是 SWI 指令的基本处理步骤。
EntryTable
DCD ZeroRtn
DCD ReadCRtn
DCD WriteIRtn
...
Zero EQU 0
ReadC EQU 256
WriteI EQU 512
; SWI 包含需要的例程在位 8-23 中和数据(如果有的话)在位 0-7 中。
; 假定 R13_svc 指向了一个合适的栈
STMFD R13, {r0-r2 , R14}
; 保存工作寄存器和返回地址。
LDR R0,[R14,#-4]
; 得到 SWI 指令。
BIC R0,R0, #0xFF000000
; 清除高端的 8 位。
MOV R1, R0, LSR #8
; 得到例程偏移量。
ADR R2, EntryTable
; 得到入口表(EntryTable)的开始地址。
LDR R15,[R2,R1,LSL #2]
; 分支到正确的例程
WriteIRtn
; 写 R0 中的位 0 - 7 中的字符。
.............
LDMFD R13, {r0-r2 , R15}^
; 恢复工作空间,并返回、恢复处理器模式和标志。