最近、読者の友人からSCPについて何か情報がないか聞かれたので、以前触れたばかりだったので、今日も勉強しに来ました。
この記事の内容は ARM の公式 Web サイトおよび上級記事から引用したもので、全体の内容は主に次のように分かれています。
- SCPとは
- システム制御プロセッサファームウェアの動作プロセス
- SCPのコードディレクトリ
時間が経ったので忘れている部分も多々あるのは事実ですが、間違いがあればご指摘ください!!!
さっそく始めましょう。
パート 1: 序文
1. SCPとは何ですか?
まずはSCPとは何なのか見てみましょう。
SCP-システム制御プロセッサーファームウェア-システム制御プロセッサーファームウェア-オープンソース電源およびシステム管理リファレンスファームウェア
業界では、アプリケーション プロセッサ (AP) からさまざまな電力やその他のシステム管理タスクを抽象化するために、システムにマイクロコントローラーを提供するという強い傾向があります。
電力制御システム アーキテクチャ (PCSA-DEN0050C) では、このアプローチに従ってシステムを構築する方法が説明されています。
PCSA は、アプリケーション プロセッサから電力およびシステム管理タスクを抽象化するために使用される専用プロセッサであるシステム制御プロセッサ (SCP) の概念を定義します。
SCP と同様に、管理性制御プロセッサ (MCP) も同じアプローチに従い、SoC ターゲット サーバーなどの管理性を必要とするシステム オン チップ (SoC) に管理エントリ ポイントを提供することを目的としています。
SCP ファームウェアは、いくつかの Arm コンピューティング サブシステムのシステム制御プロセッサ (SCP) および管理性制御プロセッサ (MCP) コンポーネントのソフトウェア リファレンス実装を提供します。
SCP ファームウェアは最近、GitHub でオープン ソース プロジェクトとして利用可能になり、BSD-3 条項ライセンスに基づいて利用可能です。
2. SCP は何ができますか?
- 一連の機能には次のものが含まれます。
- システムを初期化してアプリケーション コアのブートを有効にする
- ランタイムサービス:
- パワードメイン管理
- システム電源管理
- パフォーマンスドメイン管理 (動的な電圧と周波数のスケーリング)
- 時計管理
- センサー管理
- システム制御および管理インターフェイス (SCMI、プラットフォーム側)、Arm SCMI 仕様に基づく
- GNU Arm Embedded および Arm Compiler 6 ツールチェーンのサポート
- 複数の制御プロセッサを備えたプラットフォームのサポート
ここで簡単な理解ができたと仮定して、以下では多くを語らずに、SCP の学習を始めましょう。
パート 2:システム制御プロセッサーのファームウェア
1-SCPとは何ですか
- アプリケーション プロセッサ (AP) から電力およびシステム管理タスクを抽象化します。
- ARM システム制御および管理インターフェイス (SCMI) 仕様に準拠しています。
- 実行環境は固定ではありません。RTOS またはベアメタル環境で実行できます。
2- 基本的な構成要素
LayOut全体は3つのレイヤーに分かれています
-
モジュール:
- アーキテクチャに依存しない
- モジュールは、明確に定義された一連の操作を実行します。
-
フレーム:
- 初期化、イベント、通知、割り込み処理など、すべてのモジュールに共通のサービスを提供します。
- 実行環境に依存するアーキテクチャ層関連サービス
- アーキテクチャと実行環境に依存しない
- モジュール間の初期化、調整、対話を容易にします。
- 初期化、イベント、通知、割り込み処理など、すべてのモジュールに共通のサービスを提供します。
-
アーキテクチャ:
スレッド、割り込み、メモリ管理など、実行環境に依存する機能を提供します。
1-モジュール (struct fwk_module)
- モジュールの種類
- ハードウェア抽象化レイヤー:
- センサーなどのドライバーのクラスに共通のインターフェイス。
- 他のモジュールは HAL API を通じてプラットフォーム ドライバーを使用します
- 運転者:
- 特定のデバイスを制御します。
- HALモジュールで定義されたAPIを実装できます。
- ドライバーは HAL を使用しないことを選択できます。
- プロトコル:
- メッセージング チャネルの調停など、プロトコル固有のインターフェイスを他のモジュールに提供します。
- 仕える
- ハードウェア デバイスに関係のない作業または機能。
- 自己完結型であり、他のモジュールに API を公開しない場合があります
- ハードウェア抽象化レイヤー:
•产品由定义一个或多个固件目标的Product.mk文件组成。
•每个固件目标都是在构建产品时构建的二进制映像。
•固件目标完全由其模块集及其配置数据通过结构fwk_module_config定义。
- 組み合わせる
- バインディングにより、モジュールは別のモジュールの API セットを使用できるようになります。
- モジュールによって提供される API の各セットは一意に識別されます。
- モジュール要素は、同じ API セットの異なる実装を提供できます
2 要素とサブ要素
-
要素
- モジュールによって所有および管理されるリソース。
- デバイス、プロトコル、またはサービス インスタンスを参照する抽象化。
- たとえば、ドライバー タイプ モジュールの要素は、それが制御する各ハードウェア デバイスのインスタンスを表すことができます。
-
要素はオプションです。
-
コンポーネントの説明。
- コンポーネントごとに 1 つ。
- 要素構成データが含まれます。
-
要素は次のように定義されます。
- 名前文字列へのポインタを含む構造体
- 要素に関連付けられた子要素の数
- モジュール定義形式のデータへの void ポインター
-
子要素
- 要素によって所有および管理されるリソース。
- 記述子はありません。
例えば:
- センサーHALはモジュールです。
- PVT および熱センサー ドライバーは、センサー HAL を使用するモジュールです。
- PVT センサーと熱センサーはいくつかのグループに分類されます。各グループは、独自の構成を持つ要素です。
- グループ内の各センサーは子要素です。
3-SCP ファームウェアの実行手順
プレランフェーズ: 固定順序の 5 つのフェーズ
- モジュールの初期化: モジュールの構成データを使用してフレームワークによって呼び出されるモジュールの .init() 関数。
- • 要素の初期化: 要素構成データを使用してフレームワークによって呼び出されるモジュールの .Element_init() 関数。このフェーズは、モジュールに要素がある場合にのみ機能します。
- • 初期化後: フレームワークはモジュールの .Post_init() 関数を呼び出します。要素データがモジュールに提供された後の追加の初期化。オプションステージ。
- • フレームワークによって呼び出されるモジュールの Bind:.Bind() 関数。モジュールと要素は他のモジュールと要素にバインドされます。オプションステージ。
- • フレームワークはモジュールの Start:.Start() 関数を呼び出します。モジュールは他のモジュールのリソースを使用して初期化を完了できます。
オプションステージ。
- • 通常の実行フローは、主にモジュール間の対話によって導かれます。
- • 生成および処理されるイベント、通知、および応答。
4- モジュール間通信
イベントとお知らせ
イベント
イベント: リクエスト/レスポンスを通信するための抽象化。
• 呼び出し先のコンテキストで論理タスクを実装するメカニズム。
• モジュールは、イベント ターゲット モジュールが見つかったときにフレームワークによって呼び出される .procse_event() ハンドラーを提供します。
• 要求に関連付けられたタスクが完了すると、応答イベントが送信される場合があります。応答は、イベント処理の一部として、または後で送信できます。
– 遅延応答: 応答は、イベントの処理直後ではなく、後で送信
されます。 – 標準応答: フレームワークは、.Produce_event() が返されるとすぐに応答を生成します。
– 応答は、応答フラグが設定されたイベントです。ファームウェアはイベントと同じ方法でこれを処理します。
通知
通知: 通知フィールドが設定されたイベント。
• モジュールは他のモジュールからの通知をサブスクライブできます。
• 通知はフレームワークによってサブスクライブされたすべてのモジュールにブロードキャストされます。
• 依存関係チェーンの実装に使用できます。
– たとえば、システムの電源が移行する前に、クロックを変更したり、ウェイクアップ処理を設定したりする必要がある場合があります
。モジュールはシステム電源モジュールからの通知を使用できます。
•事件(fwk_event)
•需要响应
•延迟响应
•标准响应
•无需响应
•通知(fwk_event)
•需要响应
•延迟响应
•标准响应
•无需响应
5-イベント処理
イベントの作成 - put_event()
put_event_and_wait()
モジュールはパブリック/フレームワーク スレッドを使用しません。
• スレッドは、イベントが処理され、応答が生成されるまでブロックされます。
イベントを処理する
フレームワーク/共通スレッドまたはモジュール スレッドのコンテキストで処理されるイベント
6スレッド
ハイブリッド協調スケジューリング モデル - スケジューリングは、同じ優先度を持つスレッド間で協調的に行われます。
•无需锁
•使代码更简单,避免了死锁的情况。
•它消除了对执行上下文/RTOS的依赖,并防止了开销。
•事件在线程上下文中按顺序处理。
SCP スレッド モデルの特徴:
- • ソフトリアルタイムスケジューリング。
- • 同じ優先順位のスレッド (プリエンプションなし) を持つシングルスレッド環境とマルチスレッド環境をサポートします。
- • CMSIS 準拠の RTX RTOS などの協調スケジューリングをサポートします。
- • マルチプロセッサはサポートされていません。
- • フレームワークによって定義されたスレッド API は、直接の RTOS 呼び出しから独立しています。
- • これらの API は現在 CMSIS にマップされています。
CMSIS就是定义了一套芯片外设控制及编写规范的标准
1 - シングルスレッドモード
- • 最も単純な操作モード。ほぼすべての非 RTO ベースの実行環境に適しています。
- • スレッドのオーバーヘッドがありません。
- • BUILD_HAS_MULTITHREADING は未定義です。
- • フレーム スレッドは、すべてのイベントを処理する唯一のスレッドです。
- • モジュールには独自のスレッドがありません。
- • すべてのイベント、応答、通知に対応する単一のイベント キュー。
- • 割り込みが発生すると、割り込みが処理されます。
- • 割り込み処理の一部 (下半分) を延期する必要がある場合、イベントが ISR イベント キューに挿入されます。
- • イベント キューが空の場合、ISR イベント キューから 1 つのイベントが抽出され、イベント キューの最後尾にプッシュされます。
スケジュールモデル
実装方法
イベント駆動 - 優先順位なし
ついに終わった!!!
2- マルチスレッドモード
スケジュールモデル
- • すべてのスレッドが同じ優先度を持つ。
- • すべてのスレッドは、フレームワークによって提供される同じスレッド機能を持ちます。
- • スレッドは、別のスレッドからのシグナルがウェイクアップして、そのスレッドに向けられたイベントを処理するのを待ちます。
- RTOS ベースの環境に適しています。
- • BUILD_HAS_MULTITHREADING が定義されています。
- • メインスレッドを「コモンスレッド」といいます。
- • さらに、各モジュールは独自のスレッドを作成できます。
- • 共通スレッドは、独自のスレッドを持たないモジュールのすべてのイベントを処理します。
- • 各スレッドには独自の専用イベント キューがあります。
- • スレッドは、イベント処理用に別個のモジュール コンテキストを提供するために使用されます。
- • 任意のスレッド関数の実行は許可されません。
- • どの時点でも、実行するように通知されるスレッドは 1 つだけです。
イベント駆動 - 優先順位なし
• ソフトリアルタイム制約 (スレッド優先順位なし)
7- 新しいモジュール設計ガイドライン
新しいモジュールを自分で設計したい場合は、次の手順を参照してください。
-
共通モジュールは、シングルスレッド モードとマルチスレッド モードの両方をサポートする必要があります。
- • 製品固有のモジュールは、任意のスレッド モードをサポートするように選択できます。
-
モジュールは次のことを行ってはなりません:
- • タイムアウトなしのシングルスレッド モードでブロックします。
- • 呼び出し元のコンテキストで長時間実行タスクを実行します。イベントを生成し、そのイベントを介して長時間実行されるタスクをより小さなタスクに分割する必要があります。
- • ロックが必要な他のモジュールとコンテキストを共有する。
- • 後で使用されないメモリを割り当てます。ファームウェアにはメモリ「フリー」API がありません。ファームウェアをシンプルかつ効率的に保つために、動的なメモリ管理は実装されていません。
パート 3: コード ディレクトリ
この部分の内容については、前任者の論文の概要を抜粋させていただきましたが、詳細な内容については、参考資料の最後の部分でご確認いただければと思います。
安全性やシンプルさなどの機能を強調し、ARM の制御システム ファームウェアに適応するために、ARM は、M コアまたは R コア、さらには A コアの一部の特権システムでの作業に適したこの一般的なフレームワークを開発しました。オプティなど。
セキュリティの核となるのは分離であり、機能ごとにモジュールやドメインを形成し、モジュール間の不正なアクセスを禁止することを意味します。
1.モジュールの紹介
SCP の各機能は別個のモジュールとして実装されており、セキュリティ機能を確保するためにモジュール間の結合は可能な限り低く抑えられています。通常、ファームウェアに必要な全体的な機能はモジュール間の相互作用から得られるはずです。モジュール間の隔離は、上図の犬の噛み枠のようなもので、一度相互作用しようと手を伸ばすと予測不可能となるため、モジュール同士が相互作用できるように手すりを追加することで実現しています。 API 関数 システムの初期化で設定が無効になった場合は、モジュール間のバインドに関する次の章で説明します。
SCP のモジュールは 2 つの部分に分かれており、コードのルート ディレクトリのモジュール フォルダーの下に合計 77 個のパブリック モジュールがあり、さらに各製品の下にもモジュールがあり、100 個というと非常に多くなります。
ファームウェアには、Firmware.cmake で定義されているモジュールの一部のみが含まれており、gen_module_code.py スクリプトがソース コードを生成します。
これらのモジュールは、フレームワークの開始時に初期化され、実行を開始します。
パブリック モジュールはより多用途であり、製品独自のモジュールは通常ドライバーによって駆動され、カスタマイズする必要があります。
このプロトコル スタックは、SCP ソフトウェアと外部世界との間の対話のプロセスです。通常、メッセージはドライバー -> HAL 層を経由して送信され、その後の処理プロセスはサービス -> プロトコル -> HAL -> ドライバーとなり、ハードウェアが動作します。このインタラクションは終了したとみなされます。
2.フレームワークフレームワークプロセス
フレームワーク フレームワークは、システムの初期化、モジュールの初期化、割り込みサービスの提供、イベント サービスの提供など、ファームウェアの一般的なプロセスの実装を担当します。このようにして、モジュールは独自の機能と外部対話 API の実現に集中できます。SCP フレームワークの初期化のフローチャートは次のとおりです。
3.モジュール外部インターフェース
scp コードでは、すべての機能がモジュールによって提供されます。各モジュールは、モジュールの機能を API 列挙とその構造の形式で外部に提供し、モジュールの一般構造 fwk_module で提供します。
4. イベント イベント
モジュールはそれ自体または他のモジュールにイベントを送信できます。イベントのパラメーターは構造化メッセージ structfwk_event です。
5.動機通知
通知には 2 つのモジュール間の通信が含まれますが、イベントとの違いは次のとおりです。
-
•イベントはモジュールによって別のモジュールまたはそれ自体に送信されます。より確実です。
-
• 通知は、このモジュールにサブスクライブしているすべてのモジュールに送信されます。これはブロードキャストとみなされ、最初にサブスクライブする必要があります。
通知インターフェース:
-
•fwk_notification_subscribe//指定されたモジュールの指定された通知をサブスクライブします。
-
• fwk_notification_unsubscribe//通知の購読解除
-
•fwk_notification_notify//通知をサブスクライブするモジュールに通知を送信します。
実装に関しては、通知はイベントのメッセージ配信メカニズムを使用し、メッセージの送信および処理時に小さな変更のみを行います。
6. モジュールのバインディング
モジュールまたは要素は、モジュール内の別のモジュールまたは要素にバインドできます。目標は同じです。後続のステージで使用できる API へのポインターを取得します。(モジュール自体ではなく) モジュール内の要素にバインドしようとする場合、主な違いは、バインド要求を受信して処理するモジュールがターゲット要素に応じて動作を変更できることです。たとえば、バインディングを要求するモジュールが、その要求を処理するモジュール内の要素のサブセットにのみバインドできるようにすることができます。
アイデア: モジュール A はモジュール B と通信する必要があり、モジュール A のグローバル変数はモジュール B のコールバック関数を取得する必要があります。
モジュール A が初期化されると、モジュール A は独自のバインド関数を呼び出します。
APIを取得するためのモジュールBのbind–>fwk_module_bind–>process_bind_request()関数