最近有个读者朋友问我有没有关于SCP的资料可以分享一下,之前刚刚有接触过,于是今天来和大家再一起学习一下。
本文内容来自ARM官网以及一篇前辈的文章,全部内容主要分为:
因为时间,属实是很多东西都已经遗忘,如果有什么错误,欢迎指正!!!
话不多说,开始吧。
下面首先来看一下SCP是什么?
SCP-System Control Processor Firmware-系统控制处理器固件-开源电源和系统管理参考固件
行业中有一种强烈的趋势,即在系统中提供微控制器,以从应用处理器(AP)中提取各种电源或其他系统管理任务。
功率控制系统体系结构(PCSA-DEN0050C)描述了如何按照这种方法构建系统。
PCSA定义了系统控制处理器(SCP)的概念,SCP是一种专用处理器,用于将电源和系统管理任务从应用处理器中抽象出来。
与SCP类似,可管理性控制处理器(MCP)遵循相同的方法,目的是为需要可管理性的片上系统(SoC)提供管理入口点,例如在SoC目标服务器上。
SCP固件为几个Arm计算子系统中的系统控制处理器(SCP)和可管理性控制处理器(MCP)组件提供了软件参考实现。
SCP固件最近在GitHub上作为一个开源项目提供,它是根据BSD-3条款许可证提供的。
假设到这里你就有个简单的认识了,下面话不多说,开始SCP学习。
整个LayOut分为了三层
模块:
框架:
体系结构:
提供依赖于执行环境的功能,如线程、中断、内存管理等。
•产品由定义一个或多个固件目标的Product.mk文件组成。
•每个固件目标都是在构建产品时构建的二进制映像。
•固件目标完全由其模块集及其配置数据通过结构fwk_module_config定义。
元素
元件是可选的。
元件描述。
元素定义如下:
子元素
举个例子:
运行前阶段:按固定顺序排列的5个阶段
可选阶段。
Events & Notifications
事件:交流请求/响应的抽象。
•在被调用者上下文中实现逻辑任务的机制。
•模块提供了.procse_event()处理程序,当找到事件目标模块时,Framework会调用该处理程序。
•当与请求相关的任务完成时,可能会发送响应事件。响应可以作为事件处理的一部分发送,也可以稍后发送。
–延迟响应:稍后发送响应,而不是在处理事件后立即发送
–标准响应:一旦.produce_event()返回,Framework就会生成响应。
–响应是一个设置了响应标志的事件。固件以与事件相同的方式进行处理。
通知:设置了通知字段的事件。
•模块可以订阅来自其他模块的通知。
•通知由框架广播到所有订阅的模块。
•可用于实现依赖链。
–例如,如果在系统电源转换之前,我们可能需要更改时钟或设置一些
唤醒处理。模块可以使用来自系统电源模块的通知。
•事件(fwk_event)
•需要响应
•延迟响应
•标准响应
•无需响应
•通知(fwk_event)
•需要响应
•延迟响应
•标准响应
•无需响应
模块不使用公共/框架线程。
•线程阻塞,直到事件得到处理并生成响应。
混合协作调度模型-调度在具有相同优先级的线程之间是协作的。
•无需锁
•使代码更简单,避免了死锁的情况。
•它消除了对执行上下文/RTOS的依赖,并防止了开销。
•事件在线程上下文中按顺序处理。
SCP线程模型的特点:
CMSIS就是定义了一套芯片外设控制及编写规范的标准
执行方式
事件驱动-无优先级
终于执行完毕!!!
调度模型
如果你想自己设计一个新的模块可以参考下面的几个步骤。
通用模块必须同时支持单线程和多线程模式。
模块不应该:
这部分的内容我摘了前辈文章的大纲,详细的内容,在参考资料的最后部分可以去查看。
为了强调安全、简单等特性,适配ARM的控制系统固件,ARM又搞了这套通用的框架,适合在M核或者R核上工作,甚至A核的某些特权系统例如OPTEE中。
安全的核心就是隔离,隔离就是按功能形成module或者domain,模块之间禁止无权限的访问。
SCP的每个功能都实现为一个单独的module,module间耦合性尽量低,确保安全特性,通常固件所需的整体功能应来自模块之间的交互。module间隔离就像上图中的狗咬架,一旦伸手产生交互就祸福不能预测了,所以加上栏杆,规定好那些module间可以交互伸手,这都是通过API函数实现的,在系统初始化的时候设定死,下面模块间绑定章节会讲到。
SCP中的module分为两部分:在代码根目录module文件夹下,共77个公共模块,另外每个产品下面还有module,小100个可真不少。
一个固件只包含一部分module,在Firmware.cmake中定义,gen_module_code.py脚本生成源码
这些module在framework启动时候初始化启动运行。
公共的module比较有通用性,产品自己的module一般是驱动需要进行定制
这个协议栈就是SCP软件跟外界交互的流程,一般消息都是通过驱动->HAL层上来,然后处理的过程就是服务->协议->HAL->驱动再操作硬件做出反应,这次交互就算结束了。
framework框架负责固件的通用流程实现,包括系统初始化,module初始化,中断服务提供,event服务提供等。这样module就可以专注于自己功能和对外交互api的实现。SCP framework初始化流程图如下:
在scp代码中,所有的功能都由一个个模块提供。每个模块以api枚举及其结构体的方式对外提供该模块的功能,并在模块通用结构体fwk_module中提供。
模块可以给自己或者别的模块发送event事件,事件的参数是结构化消息structfwk_event。
notification涉及到两个模块的通信,跟event的区别是:
•event是一个模块发给另外一个模块或者发给自己,比较确定
•notification是发给订阅了这个模块的所有模块,算广播,需要先进行订阅
notification接口:
•fwk_notification_subscribe//订阅指定模块指定通知
•fwk_notification_unsubscribe//取消订阅通知
•fwk_notification_notify//向订阅该通知的模块发送通知
在实现上notification使用event的消息传递机制,只在发消息和处理消息的时候做微小改动。
一个模块或元素可以绑定到另一个模块或模块内的元素。目标是相同的 - 获取指向可在后续阶段使用的 API 的指针。当尝试绑定到模块内的元素(而不是模块本身)时,主要区别在于接收和处理绑定请求的模块能够根据目标元素更改其行为。例如,可以允许请求绑定的模块仅绑定到处理请求的模块内的元素子集。
思路:A模块要与B模块通信,A模块的全局变量要拿到B模块的回调函数。
A模块在初始化的时候,会调用自己的bind函数,
bind–>fwk_module_bind–>B模块的process_bind_request()函数,从而拿到api