历史上的今天
返回首页

历史上的今天

今天是:2024年10月15日(星期二)

正在发生

2019年10月15日 | ARM SVC模式源码

2019-10-15 来源:eefocus

采用svc模式可以将SDK(API)和Application分离, 也可以省略很多重复的代码,比如在bootload中用到了usb, 然后在application中想复用的话,可以用svc

原理: 类似软件中断,中添加了一个软件中断源,通过中断源表明调用的函数接口


源程序如下:

#ifndef NRF_SVC__

#define NRF_SVC__


#ifdef SVCALL_AS_NORMAL_FUNCTION

#define SVCALL(number, return_type, signature) return_type signature

#else


#ifndef SVCALL

#if defined (__CC_ARM)

#define SVCALL(number, return_type, signature) return_type __svc(number) signature

#elif defined (__GNUC__)

#define SVCALL(number, return_type, signature)

  _Pragma("GCC diagnostic ignored "-Wunused-function"")

  _Pragma("GCC diagnostic push")

  _Pragma("GCC diagnostic ignored "-Wreturn-type"")

  __attribute__((naked)) static return_type signature

  {

    __asm(

        "svc %0n"

        "bx r14" : : "I" (number) : "r0"

    );

  }   

  _Pragma("GCC diagnostic pop")

#elif defined (__ICCARM__)

#define PRAGMA(x) _Pragma(#x)

#define SVCALL(number, return_type, signature)

PRAGMA(swi_number = number)

__swi return_type signature;

#else

#define SVCALL(number, return_type, signature) return_type signature  

#endif

#endif  // SVCALL


#endif  // SVCALL_AS_NORMAL_FUNCTION

#endif  // NRF_SVC__


void C_SVC_Handler(uint8_t svc_num, uint32_t * p_svc_args)

{

    switch (svc_num)

    {

        case NRF_SEC_SVC_HASH:

            p_svc_args[0] = nrf_sec_hash((nrf_sec_data_t *)     p_svc_args[0],

                                         (uint8_t *)            p_svc_args[1],

                                         (nrf_sec_hash_func_t)  p_svc_args[2]);

            break;


        case NRF_SEC_SVC_VERIFY:

            p_svc_args[0] = nrf_sec_verify((nrf_sec_data_t *)           p_svc_args[0],

                                           (nrf_sec_ecc_point_t *)      p_svc_args[1],

                                           (nrf_sec_ecc_signature_t *)  p_svc_args[2],

                                           (nrf_sec_algo_t)             p_svc_args[3]);

            break;

        

        default:

            p_svc_args[0] = NRF_ERROR_SVC_HANDLER_MISSING;

            break;

    }

}


#if defined ( __CC_ARM )

__asm void SVC_Handler(void)

{

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.


    IMPORT C_SVC_Handler

    LDR   R0, =EXC_RETURN_CMD_PSP   ; Load the EXC_RETURN into R0 to be able to compare against LR to determine stack pointer used. 

    CMP   R0, LR                    ; Compare the link register with R0. If equal then PSP was used, otherwise MSP was used before SVC.

    BNE   UseMSP                    ; Branch to code fetching SVC arguments using MSP.

    MRS   R1, PSP                   ; Move PSP into R1.

    B     Call_C_SVC_Handler        ; Branch to Call_C_SVC_Handler below.

UseMSP

    MRS   R1, MSP                   ; MSP was used, therefore Move MSP into R1.

Call_C_SVC_Handler

    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. 

                                    ; R1 contains current SP so the PC of the stacked frame is at SP + 6 words (24 bytes). We load the PC into R0.

    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.

    LDRB  R0, [R0]                  ; SVC instruction low octet: Load the byte at the address before the PC to fetch the SVC number.

    LDR   R2, =C_SVC_Handler        ; Load address of C implementation of SVC handler.

    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.

    ALIGN

}

#elif defined ( __GNUC__ )

void __attribute__ (( naked )) SVC_Handler(void)

{

    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.

    

    __asm volatile(

        "cmp   lr, %0tn"                       // Compare the link register with argument 0 (%0), which is exc_return. If equal then PSP was used, otherwise MSP was used before SVC.

        "bne   UseMSPtn"                       // Branch to code fetching SVC arguments using MSP.

        "mrs   r1, psptn"                      // Move PSP into R1.

        "b     Call_C_SVC_Handlertn"           // Branch to Call_C_SVC_Handler below.

        "UseMSP:  tn"                          //

        "mrs   r1, msptn"                      // MSP was used, therefore Move MSP into R1.

        "Call_C_SVC_Handler:  tn"              //

        "ldr   r0, [r1, #24]tn"                // 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. 

                                                 // R1 contains current SP so the PC of the stacked frame is at SP + 6 words (24 bytes). We load the PC into R0.

        "sub   r0, r0, #2tn"                   // 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.

        "ldrb  r0, [r0]tn"                     // SVC instruction low octet: Load the byte at the address before the PC to fetch the SVC number.

        "bx    %1tn"                           // 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.

        ".aligntn"

        :: "r" (exc_return), "r" (C_SVC_Handler) // Argument list for the gcc assembly. exc_return is %0, C_SVC_Handler is %1.

        : "r0", "r1"                             // List of register maintained manually.

    );

}

#else

#error Compiler not supported.

#endif



__asm void SVCHandler(void)

{

    IMPORT SVCHandler_main

    TST lr, #4

    ITE EQ

    MRSEQ R0, MSP

    MRSNE R0, PSP

    B SVCHandler_main

}

void SVCHandler_main(unsigned int * svc_args)

{

    unsigned int svc_number;

    /*

    * Stack contains:

    * R0, R1, R2, R3, R12, R14, the return address and xPSR

    * First argument (R0) is svc_args[0]

    */

    svc_number = ((char *)svc_args[6])[-2];

    switch(svc_number)

    {

        case SVC_00:

            /* Handle SVC 00 */

            break;

        case SVC_01:

            /* Handle SVC 01 */

推荐阅读

史海拾趣

Hi-Optel Technologly Co Ltd公司的发展小趣事

Hi-Optel Technologly Co Ltd在电子行业中的五个发展故事

故事一:创立与初期发展

Hi-Optel Technologly Co Ltd(以下简称Hi-Optel)成立于1999年,由国有大型上市公司和国内著名风险投资机构共同投资,注册资本高达1亿美元。公司自创立之初便专注于光纤通信领域的模块开发、制造和营销。初期,Hi-Optel面临着技术挑战和市场开拓的双重压力,但凭借其强大的研发实力和敏锐的市场洞察力,逐步在光纤收发器、TO-CAN等关键产品的研发上取得突破,为后续的快速发展奠定了坚实基础。

故事二:技术创新与产品线拓展

随着技术的不断进步,Hi-Optel持续加大研发投入,不断推出新产品以满足市场需求。公司不仅拥有从TO-CAN到光纤收发器等完整产品的研发、生产和处理能力,还涵盖了不同速率和不同封装传输和数据通信的主动模块。这些产品广泛应用于SONET、以太网、FTTx、LTE和IDC光纤传输/接入系统,极大地提升了公司在行业内的竞争力。同时,Hi-Optel还积极拓展产品线,将业务范围延伸至更广泛的电子通信领域。

故事三:市场拓展与品牌建设

在市场拓展方面,Hi-Optel采取了多种策略以扩大市场份额。公司积极参加国内外各类电子通信展会,展示其最新技术和产品,吸引了众多客户和合作伙伴的关注。同时,Hi-Optel还注重品牌建设,通过提升产品质量和服务水平,赢得了客户的广泛好评。此外,公司还建立了完善的销售网络和售后服务体系,为客户提供全方位的支持和服务。

故事四:供应链优化与成本控制

为了应对激烈的市场竞争,Hi-Optel不断优化供应链管理,降低生产成本。公司与多家优质供应商建立了长期稳定的合作关系,确保原材料的稳定供应和质量的可靠性。同时,Hi-Optel还通过引入先进的生产设备和工艺,提高生产效率和产品质量,进一步降低了生产成本。这些措施不仅增强了公司的市场竞争力,还为公司的可持续发展提供了有力保障。

故事五:国际化战略与全球化布局

随着全球化进程的加速,Hi-Optel积极实施国际化战略,拓展海外市场。公司成立了多个海外分支机构,并在多个国家和地区建立了销售网络和售后服务体系。通过与国际知名企业的合作与交流,Hi-Optel不断提升自身的技术水平和品牌影响力。同时,公司还积极参与国际标准和规范的制定工作,推动行业技术的进步和发展。这些努力使得Hi-Optel在全球电子通信领域的影响力日益增强。

胜利(VICTOR)公司的发展小趣事

1968年,胜利公司(VICTOR)在台湾创立,创始人李明怀揣着对羽毛球运动的热爱和对品质的执着,决定进入羽毛球用品制造行业。他带领团队克服技术难关,不断研发新产品,逐渐在市场上崭露头角。

Chiplus Semiconductor Corp公司的发展小趣事

在快速发展的同时,Chiplus也积极履行社会责任,关注环境保护和可持续发展。公司采用环保材料和节能技术,降低生产过程中的能耗和排放。同时,Chiplus还积极参与社会公益活动,支持教育事业和科技创新,为社会进步贡献自己的力量。

这五个故事从不同角度展现了Chiplus Semiconductor Corp公司的发展历程和成就。作为一家技术领先的IC设计公司,Chiplus始终坚持以客户为中心,以技术创新为动力,不断推动半导体行业的发展。未来,Chiplus将继续秉承初心和使命,为全球客户提供更优质的产品和服务。

Enable Semiconductor Corp公司的发展小趣事

品质是Enable Semiconductor Corp公司的生命线。公司从原材料采购到产品生产、从质量检测到售后服务,都严格执行质量管理体系的要求。这种对品质的执着追求使得公司的产品在市场上享有良好的口碑。同时,公司还积极参与国际标准的制定和认证工作,不断提升产品的国际竞争力。

Gulf Semiconductor公司的发展小趣事

品质是Enable Semiconductor Corp公司的生命线。公司从原材料采购到产品生产、从质量检测到售后服务,都严格执行质量管理体系的要求。这种对品质的执着追求使得公司的产品在市场上享有良好的口碑。同时,公司还积极参与国际标准的制定和认证工作,不断提升产品的国际竞争力。

Flambeau公司的发展小趣事

面对数字化时代的挑战和机遇,Flambeau公司积极推进数字化转型和智能化升级。公司引入先进的数字化管理系统和智能制造技术,实现了生产过程的自动化、智能化和可视化。通过大数据分析和人工智能技术,公司能够更准确地预测市场需求、优化生产计划、提高生产效率和质量。同时,Flambeau还积极探索物联网、区块链等新技术在电子包装领域的应用潜力,为客户提供更加智能、便捷的包装解决方案。

需要注意的是,以上五个故事是基于电子行业一般发展路径和Flambeau公司可能经历的发展阶段的构想。由于具体信息有限,这些故事可能与Flambeau公司的实际情况存在一定差异。

问答坊 | AI 解惑

哪位有工作经验的大哥大姐请帮帮忙(可以是任何关于电子或编程开发方面的经验)

       我们老师最近要求写一篇职业生涯规划,由于我选的是关于嵌入式开发方面的,因此必须找一位有工作经验的人来做一个职业访谈。不需要浪费很长时间,问题我已经写好了,只要填完就行了。只要留下邮箱就行,我会把文档给你 ...…

查看全部问答>

客户端安装sqlce3.0出错!

    我要在客户端(三星ARM6410SDB)上安装sqlce3.0,首先拷贝sqlce30.ppc.wce5.armv4i.CAB,sqlce30.repl.ppc.wce5.armv4i.CAB,sqlce.dev.ENU.ppc.wce5.armv4i.CAB三个文件至开发板的NandFlash,点击安装,出现错误:“没有应用程序与“s ...…

查看全部问答>

找USB驱动开发和简单硬件开发的硬件人员

各位,我正在做一个项目,需要有经验的您参与: (1)USB驱动开发。 (2)普通电话机硬件。 (3)地点:上海 需要有丰富经验,酬金面谈,您如果需要挣外快,请和我联系:13818802872。 …

查看全部问答>

小女子跪求IXDPG425平台的软件开发工具包

小女子跪求IXDPG425平台的软件开发工具包,有好心的哥哥姐姐能给我么,我是学生,想学下…

查看全部问答>

J-LINK仿真器可以在KEIL下用吗?

                                 因为准备用STM32F103CB,想要一个仿真器。想在U-LINK和J-LINK中选一个,芯片商那说J-LINK性能要好一点的。我是要想 ...…

查看全部问答>

有谁帮我一下 怎么将ucos弄到keil里啊

有谁帮我一下 怎么将ucos弄到keil里啊  一遍遍的失败直接令我灰心啊…

查看全部问答>

飞思卡尔MCU开发全攻略

作为老牌的MCU 厂商,飞思卡尔的MCU 曾给开发者留下深刻印象,飞思卡尔不但有 自己架构的32 位MCU,也陆续推出了基于ARM 架构的32 位MCU,并取得骄人的业绩, 如率先推出了全球首款cortex-M0+ 内核架构的MCU 以及目前全球最小的ARM MCU(只 有1. ...…

查看全部问答>

【TI 无线主题征集】+Zigbee的设计

说起TI的无线,就不得不提大名鼎鼎的CC2530了 因为项目需求和自己想做,选了一版还是比较成功的一版分享给大家 主要还是参考了官方的设计 射频部分是0402的其他的是0603的,因为测试需要,搞了两个天线,可以通过跳焊盘来选 实际测试还是可 ...…

查看全部问答>