我想知道在基于ARM的微控制器上编写SVC调用的正确方法。
到目前为止,我的理解是ARM有一个异常向量表,这意味着任何程序中的第一条指令都必须分支到适当的处理程序:
RESET ;Handles reset
UNDEFINED ;Undefined instructions
SVC BL SVC_Entry
PRE_ABORT ;Prefetch abort
DAT_ABORT ;Data abort
然后,每次运行SVC指令时,模式切换到管理程序,SVC提供的数字存储在R0中,程序将分支到适当的处理程序:
;== Handling SVC calls ========================================================
Max_SVC EQU 1
SVC_Entry CMP R0, #Max_SVC ;Check upper limit
BHI SVC_end ;Does nothing if unknown
ADD R0, PC, R0, LSL #2 ;Calculate table address
LDR PC, [R0, #0]
Jump_table DEFW SVC_0 ;Halt
DEFW SVC_1 ;Print string
;== SVC calls ================================================================
SVC_1 B SVC_end
SVC_end MOVS PC, LR ;Exiting
所以,如果我们有这些指示:
ADR R1, string ;R1 points to the string
SVC 1 ;SVC_1 handles the printing
程序必须切换到管理员模式,将数字“1”存储在R0中,然后按照跳转表分支到SVC_1,运行代码并切换回用户模式。
这是对的吗?我做得对吗?
到目前为止我遇到的问题是我的编译器对此行说“操作员期望”:
SVC BL SVC_Entry
在互联网上很难找到有关此主题的信息,我只想知道如何在ARM微控制器上正确使用SVC调用。
非常感谢。
编辑:底层处理器是ARM9,时钟频率约为240 MHz。住在这里 一个AT91微控制器。它所在的实验室板已经过修改,以满足我大学的需求。
通过串口使用定制程序将代码加载到电路板上。该程序还允许调试。
答案 0 :(得分:4)
如上所述,不要使用BL跳转到SVC条目,使用B.首先确定例行程序以确定SVC编号。 (我称之为SVC_dispatcher)。你在哪所大学?我会尝试彻底解释这一点,不要假设你做了多少或者不知道。我已经输入了正确的条款,因此如果我的评论不清楚或您想要更深入的话,您可以将其谷歌更多信息。我不确定结肠的标记方法,我已经习惯了较旧的指令集。
祝你好运SVC_dispatcher
PUSH {LR} ; always save your LR
LDR R14, [LR, #-4] ; its been stacked, so we can it (LR is R14)
; the link register is the line after the SVC instruction
; above, we load the instruction that is one before the
; link register (#-4 preindexed load) means instruction (SVC 1) into R14.
; Use bit clear to remove the mnemonic from the 32 bit instruction,
; leaving the data (1)
BIC R14, R14, #&FF000000
SVC_entry
CMP R14, #Max_SVC
BHI SVC_unknown
ADR R1, Jump_Table ; use this format, never add to the PC
LDR PC, [R1, R14, LSL #2]
; Beware: PC can be changed by IRQs **AT ANY TIME**
Jump_Table ; you know the drill here
DEFW SVC_0
DEFW SVC_1
SVC_0 B SVC_end
SVC_1 BL printString ; consider stacking registers that printString
B SVC_end ; will corrupt
SVC_end POP {LR} ; restore link register
MOV PC, LR
答案 1 :(得分:2)
只是补充Yoker的上述答案以澄清:
正如Yoker的答案所示,传统上SVC指令中的数字并未存储在R0中(如您在问题中所述),您应该从代码中检索它,直接读取直接值来自svc指令。
为此,您需要在返回地址之前获取指令指针,例如,如果您有这些说明:
._md-select-value {
height: 50px; /*Set height for select */
}
._md-select-value *:first-child {
height: 30px; /*Set height for selected value (including bar)
}
返回地址为LR = 0x800018,然后我们可以检索SVC指令LR-4 = 0x800014的地址,读取该地址内容(这是SVC 1指令)并只得到它的第一个字节(我们忽略svc操作码,只获得直接值。)
所以,在Yoker的例子中,我们可以看到以下说明:
0x800010: ADR R1, string ;R1 points to the string
0x800014: SVC 1 ;SVC_1 handles the printing
0x800018: ADD R1, R2 ;The next instruction after the SVC where LR will point to
这是另一个在皮质M0中使用C代码的例子(拇指指令):
LDR R14, [LR, #-4]
BIC R14, R14, #&FF000000