单片机论坛

 找回密码
 立即注册

QQ登录

只需一步快速开始

搜索
查看: 918|回复: 0
打印 上一主题 下一主题
收起左侧

ARM SVC模式源码

[复制链接]
跳转到指定楼层
楼主
mitianshenyu 发表于 2019-3-9 12:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
采用svc模式可以将SDK(API)和Application分离 也可以省略很多重复的代码比如在bootload中用到了usb 然后在application中想复用的话可以用svc
原理: 类似软件中断中添加了一个软件中断源通过中断源表明调用的函数接口

源程序如下:
  1. #ifndef NRF_SVC__
  2. #define NRF_SVC__

  3. #ifdef SVCALL_AS_NORMAL_FUNCTION
  4. #define SVCALL(number, return_type, signature) return_type signature
  5. #else

  6. #ifndef SVCALL
  7. #if defined (__CC_ARM)
  8. #define SVCALL(number, return_type, signature) return_type __svc(number) signature
  9. #elif defined (__GNUC__)
  10. #define SVCALL(number, return_type, signature) \
  11.   _Pragma("GCC diagnostic ignored \"-Wunused-function\"") \
  12.   _Pragma("GCC diagnostic push") \
  13.   _Pragma("GCC diagnostic ignored \"-Wreturn-type\"") \
  14.   __attribute__((naked)) static return_type signature \
  15.   { \
  16.     __asm( \
  17.         "svc %0\n" \
  18.         "bx r14" : : "I" (number) : "r0" \
  19.     ); \
  20.   }    \
  21.   _Pragma("GCC diagnostic pop")
  22. #elif defined (__ICCARM__)
  23. #define PRAGMA(x) _Pragma(#x)
  24. #define SVCALL(number, return_type, signature) \
  25. PRAGMA(swi_number = number) \
  26. __swi return_type signature;
  27. #else
  28. #define SVCALL(number, return_type, signature) return_type signature  
  29. #endif
  30. #endif  // SVCALL

  31. #endif  // SVCALL_AS_NORMAL_FUNCTION
  32. #endif  // NRF_SVC__

  33. void C_SVC_Handler(uint8_t svc_num, uint32_t * p_svc_args)
  34. {
  35.     switch (svc_num)
  36.     {
  37.         case NRF_SEC_SVC_HASH:
  38.             p_svc_args[0] = nrf_sec_hash((nrf_sec_data_t *)     p_svc_args[0],
  39.                                          (uint8_t *)            p_svc_args[1],
  40.                                          (nrf_sec_hash_func_t)  p_svc_args[2]);
  41.             break;

  42.         case NRF_SEC_SVC_VERIFY:
  43.             p_svc_args[0] = nrf_sec_verify((nrf_sec_data_t *)           p_svc_args[0],
  44.                                            (nrf_sec_ecc_point_t *)      p_svc_args[1],
  45.                                            (nrf_sec_ecc_signature_t *)  p_svc_args[2],
  46.                                            (nrf_sec_algo_t)             p_svc_args[3]);
  47.             break;
  48.         
  49.         default:
  50.             p_svc_args[0] = NRF_ERROR_SVC_HANDLER_MISSING;
  51.             break;
  52.     }
  53. }

  54. #if defined ( __CC_ARM )
  55. __asm void SVC_Handler(void)
  56. {
  57. EXC_RETURN_CMD_PSP  EQU 0xFFFFFFFD  ; EXC_RETURN using PSP for ARM Cortex. If Link register contains this value it indicates the PSP was used before the SVC, otherwise the MSP was used.

  58.     IMPORT C_SVC_Handler
  59.     LDR   R0, =EXC_RETURN_CMD_PSP   ; Load the EXC_RETURN into R0 to be able to compare against LR to determine stack pointer used.
  60.     CMP   R0, LR                    ; Compare the link register with R0. If equal then PSP was used, otherwise MSP was used before SVC.
  61.     BNE   UseMSP                    ; Branch to code fetching SVC arguments using MSP.
  62.     MRS   R1, PSP                   ; Move PSP into R1.
  63.     B     Call_C_SVC_Handler        ; Branch to Call_C_SVC_Handler below.
  64. UseMSP
  65.     MRS   R1, MSP                   ; MSP was used, therefore Move MSP into R1.
  66. Call_C_SVC_Handler
  67.     LDR   R0, [R1, #24]             ; The arguments for the SVC was stacked. R1 contains Stack Pointer, the values stacked before SVC are R0, R1, R2, R3, R12, LR, PC (Return address), xPSR.
  68.                                     ; R1 contains current SP so the PC of the stacked frame is at SP + 6 words (24 bytes). We load the PC into R0.
  69.     SUBS  R0, #2                    ; The PC before the SVC is in R0. We subtract 2 to get the address prior to the instruction executed where the SVC number is located.
  70.     LDRB  R0, [R0]                  ; SVC instruction low octet: Load the byte at the address before the PC to fetch the SVC number.
  71.     LDR   R2, =C_SVC_Handler        ; Load address of C implementation of SVC handler.
  72.     BX    R2                        ; Branch to C implementation of SVC handler. R0 is now the SVC number, R1 is the StackPointer where the arguments (R0-R3) of the original SVC are located.
  73.     ALIGN
  74. }
  75. #elif defined ( __GNUC__ )
  76. void __attribute__ (( naked )) SVC_Handler(void)
  77. {
  78.     const uint32_t exc_return = 0xFFFFFFFD;      // EXC_RETURN using PSP for ARM Cortex. If Link register contains this value it indicates the PSP was used before the SVC, otherwise the MSP was used.
  79.    
  80.     __asm volatile(
  81.         "cmp   lr, %0\t\n"                       // Compare the link register with argument 0 (%0), which is exc_return. If equal then PSP was used, otherwise MSP was used before SVC.
  82.         "bne   UseMSP\t\n"                       // Branch to code fetching SVC arguments using MSP.
  83.         "mrs   r1, psp\t\n"                      // Move PSP into R1.
  84.         "b     Call_C_SVC_Handler\t\n"           // Branch to Call_C_SVC_Handler below.
  85.         "UseMSP:  \t\n"                          //
  86.         "mrs   r1, msp\t\n"                      // MSP was used, therefore Move MSP into R1.
  87.         "Call_C_SVC_Handler:  \t\n"              //
  88.         "ldr   r0, [r1, #24]\t\n"                // The arguments for the SVC was stacked. R1 contains Stack Pointer, the values stacked before SVC are R0, R1, R2, R3, R12, LR, PC (Return address), xPSR.
  89.                                                  // R1 contains current SP so the PC of the stacked frame is at SP + 6 words (24 bytes). We load the PC into R0.
  90.         "sub   r0, r0, #2\t\n"                   // The PC before the SVC is in R0. We subtract 2 to get the address prior to the instruction executed where the SVC number is located.
  91.         "ldrb  r0, [r0]\t\n"                     // SVC instruction low octet: Load the byte at the address before the PC to fetch the SVC number.
  92.         "bx    %1\t\n"                           // Branch to C implementation of SVC handler, argument 1 (%1). R0 is now the SVC number, R1 is the StackPointer where the arguments (R0-R3) of the original SVC are located.
  93.         ".align\t\n"
  94.         :: "r" (exc_return), "r" (C_SVC_Handler) // Argument list for the gcc assembly. exc_return is %0, C_SVC_Handler is %1.
  95.         : "r0", "r1"                             // List of register maintained manually.
  96.     );
  97. }
  98. #else
  99. #error Compiler not supported.
  100. #endif


  101. __asm void SVCHandler(void)
  102. {
  103.     IMPORT SVCHandler_main
  104.     TST lr, #4
  105.     ITE EQ
  106.     MRSEQ R0, MSP
  107.     MRSNE R0, PSP
  108.     B SVCHandler_main
  109. }
  110. void SVCHandler_main(unsigned int * svc_args)
  111. {
  112.     unsigned int svc_number;
  113.     /*
  114.     * Stack contains:
  115.     * R0, R1, R2, R3, R12, R14, the return address and xPSR
  116.     * First argument (R0) is svc_args[0]
  117.     */
  118.     svc_number = ((char *)svc_args[6])[-2];
  119.     switch(svc_number)
  120.     {
  121.         case SVC_00:
  122.             /* Handle SVC 00 */
  123.             break;
  124.         case SVC_01:
  125.             /* Handle SVC 01 */
  126.             break;
  127.         default:
  128.             /* Unknown SVC */
  129.             break;
  130.     }
  131. }

  132. #define SVC_00 0x00
  133. #define SVC_01 0x01
  134. void __svc(SVC_00) svc_zero(const char *string);
  135. void __svc(SVC_01) svc_one(const char *string);
  136. int call_system_func(void)
  137. {
  138.     svc_zero("String to pass to SVC handler zero");
  139.     svc_one("String to pass to a different OS function");
  140. }

  141. 在 ARM 状态时为 0

  142. ARM 和 Thumb 指令集均有 SVC 指令 在 Thumb 状态下调用 SVC 时必须考虑以下情况

  143. 指令的地址在 lrC2而不在 lrC4

  144. 该指令本身为 16 位因而需要半字加载请参阅Figure 6.3

  145. 在 ARM 状态下SVC 编号以 8 位存储而不是 24 位
  146. Example 6.8. SVC 处理程序
  147.     PRESERVE8
  148.     AREA SVC_Area, CODE, READONLY
  149.     EXPORT SVC_Handler    IMPORT C_SVC_Handler
  150. T_bit   EQU    0x20                    ; Thumb bit (5) of CPSR/SPSR.
  151. SVC_Handler
  152.     STMFD   sp!, {r0-r3, r12, lr}  ; Store registers
  153.     MOV     r1, sp                 ; Set pointer to parameters
  154.     MRS     r0, spsr               ; Get spsr
  155.     STMFD   sp!, {r0, r3}          ; Store spsr onto stack and another
  156.                                    ; register to maintain 8-byte-aligned stack
  157.     TST     r0, #T_bit             ; Occurred in Thumb state?
  158.     LDRNEH  r0, [lr,#-2]           ; Yes: Load halfword and...
  159.     BICNE   r0, r0, #0xFF00        ; ...extract comment field
  160.     LDREQ   r0, [lr,#-4]           ; No: Load word and...
  161.     BICEQ   r0, r0, #0xFF000000    ; ...extract comment field

  162.     ; r0 now contains SVC number
  163.     ; r1 now contains pointer to stacked registers

  164.     BL      C_SVC_Handler          ; Call main part of handler
  165.     LDMFD   sp!, {r0, r3}          ; Get spsr from stack
  166.     MSR     SPSR_cxsf, r0               ; Restore spsr
  167.     LDMFD   sp!, {r0-r3, r12, pc}^ ; Restore registers and return
  168.     END
复制代码

所有资料51hei提供下载:
ARM SVC.zip (3.58 KB, 下载问: 2)


评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 转播转播 分享分享 分享淘帖 顶 踩
回复

使用道具 举报

无效楼层该帖已经被删除
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|单片机论坛 |51Hei单片机16群 联系QQ:125739409;技术交流QQ群7344883

Powered by 单片机坛网

快速回复 返回顶部 返回列表
ձһhƬձƵ ձƵɫwww ձƵ:ɫ