TOPPERS/FMP3 リリースとの相違点

SOLID-OSにおけるカーネルでは以下の点がオリジナルのTOPPERS/FMP3と仕様または動作が異なります

対応予定の拡張機能

SOLID-OS の FMP3 カーネルでは、SOLID-OS の ASP3カーネル もしくは FMPカーネルでサポートしている 以下の拡張機能については、現時点では未サポートですが、今後のアップデートで対応予定です。

  • タスク起動要求キューイング数/タスク起床要求キューイング数の上限をコンフィグレーション可能

  • 各プロセッサアイドル時間取得機能

  • 実行中タスクのローテート(=同一優先度中で優先順位を最低にする) (xsm_imsbk_rtk())

  • 指定プロセッサについて実行中タスクの優先度を取得するAPI (imget_ppri())

  • 指定プロセッサについて実行中タスクのタスクIDを取得するAPI (imget_tid())

注釈

FMPでSOLID独自拡張としてサポートされている タイマーイベントハンドラ分散実行 についてはFMP3の標準仕様である ローカルタイマ方式 でサポートされています。

対応している拡張機能

SOLID-OSにおけるカーネルでは以下の点がオリジナルのTOPPERS/FMP3と仕様または動作が異なります


カーネル資源の静的な生成方法

SOLID-OSではタスクなどのカーネル資源を生成するために、カーネル起動時に読み込まれるパラメータをC言語のテーブルに記述しておくことで行います。


ミューテックスでの優先度継承プロトコルサポート

API仕様については μITRON4.0 仕様に準拠します


割込み及び例外の処理

SOLID-OSにおいてはCPUからの割込み及び例外の処理はCore Serviceの内部で行われます。

割込み処理については関連システムコールはオリジナル実装と同様に動作します。 ただし、kernel_cfg.c の中の設定テーブルに記述されていな割込みについては すべてカーネル管理外の割込みとして扱われます。

例外処理についてはすべてCore Serivceの内部で処理が完結します。 プロセッサ例外時でもカーネルに通知が行われないため、 def_exc()xns_dpn() は未実装か、オリジナルのカーネル仕様通りには機能しません。


割り込み優先度/割り込み優先マスクの扱いについて

割り込み優先度のレベル数は32段階固定 (TIPM_ENAALL (0), TMAX_INTPRI (-1), ..., TMIN_INTPRI (-31)) で定義され、 TMAX_INTPRI が割り込みコントローラの最も低い優先度に対応します(以降、TOPPERS優先度が-1するごとに優先度が1ずつ高くなります)

割り込みコントローラの割込み優先度レベル数が32未満の場合
  • 割込みハンドラの登録 (kernel_cfg.c)

    kernel_cfg.c で割込み初期化テーブルに設定された優先度が割り込みコントローラがサポートする最高優先度を超える場合、割り込みコントローラの最高優先度でハンドラの登録を行います。

  • chg_ipm() の動作

    パラメータ intpriに指定された優先度が割り込みコントローラがサポートする最高優先度を超える場合、割り込みコントローラの最高優先度でハンドラの登録を行います。

  • get_ipm() の動作

    get_ipm() は割り込みコントローラに実際に設定されている割込みマスク値に対応する範囲内で優先度を返します。 上述のchg_ipmの動作により、割り込みコントローラでサポートする優先度の範囲外の値を設定した場合には get_ipm() は割込みコントローラがサポートする最高の優先度に対応する値を返すため、 chg_ipm() の設定値とその後の get_ipm() の取得値は一致しません。

割り込みコントローラの割込み優先度レベル数が32を超える場合

  • get_ipm() の動作

    割込みコントローラか取得したマスク値がTOPPERS側の最高優先度 (TMIN_INTPRI) を超えている場合にはエラーとはせずに TMIN_INTPRI (-1) を値として返します。


静的資源カーネルにおいて以下のAPIにおけるパラメータ制限が緩和されています

それぞれ、CRE_DTQ での dtqmpCRE_PDQ での pdqmbCRE_MPF での mpfmb に NULL 以外を指定してもエラーになりません。(動的生成拡張サポートカーネルと同等)。

CRE_DTQ [ASPS0132]
CRE_PDQ [ASPS0142]
CRE_MPF [ASPS0166]

ミューテックスのロック解除順序

SOLID-OSでは unl_mtx() でミューテックス解除を行う場合にロックした順番と逆順となっていなくてもエラーとはなりません。(新世代カーネル仕様と同等の動作。第3世代カーネル仕様では E_OBJ エラー)


割り込み操作APIの対象割込み番号

次のAPIについてASP3.3.0以降のリリースではカーネルに登録された割込み(カーネル管理割込み)以外の割込み番号をパラメータに渡した場合にエラーとなりますが、SOLIDでは指定された割込みについて割り込みコントローラへの操作を試みます: dis_int(), ena_int(), clr_int(), ras_int(), prb_int()


タスク起動要求キューイング数/タスク起床要求キューイング数

タスクに対する起動要求 (act_tsk()) 及び起床要求 (wup_tsk()) のキューイング数がデフォルトで UINT32_MAX となっています。また、それぞれにカーネル起動時パラメータで0から UINT32_MAX の範囲で変更可能です。(0の場合はキューイングを行わない動作)

キューイング数を設定するにはアプリケーションの kernel_cfg.c 内で起動要求キューイング数/起床要求キューイング数の設定(optional)を参考に記述してください。


イベントフラグ待ち解除時のクリア方法指定

イベントフラグがセットされ、待ち状態にあったタスクの待ち状態が解除される際にフラグのビットパターンのビットをクリアする方法を以下の中から選択可能です。

  • 指定なし(クリアしない)

  • すべてのビットをクリア

  • 待ち対象のビットのみクリア

待ち対象のビットのみクリアする場合はイベントフラグ待ちAPI (wai_flg()/pol_flg()/twai_flg()) の待ちビットパターンパラメータ waiptn でセットされているビットがすべてクリアされます。それ以外のビットは変化しません。

クリア方法の指定は資源生成時の属性とイベントフラグ待ちAPI (wai_flg()/pol_flg()/twai_flg()) の待ちモードパラメータ wfmode の両方で指定可能です。両方とも指定されている場合には後者が優先されます。

資源生成時の属性

TA_CLR

全ビットクリア

TA_BITCLR

待ち対象ビットのみクリア(追加)

API (wai_flg()/pol_flg()/twai_flg()) の待ちモード (wfmode) [全て追加]

TWF_CLR

全ビットクリア

TWF_BITCLR

待ち対象ビットのみクリア

資源生成時の属性とAPIの待ちモードの組み合わせによる動作

生成時属性

API待ちモード

ビットクリア動作

(指定なし)

(指定なし)

ビットクリアしない

(指定なし)

TWF_CLR

ビットクリア

(指定なし)

TWF_BITCLR

待ち対象ビットのみクリア

TA_CLR

(指定なし)

全ビットクリア

TA_CLR

TWF_CLR

全ビットクリア

TA_CLR

TWF_BITCLR

待ち対象ビットのみクリア

TA_BITCLR

(指定なし)

待ち対象ビットのみクリア

TA_BITCLR

TWF_CLR

全ビットクリア

TA_BITCLR

TWF_BITCLR

待ち対象ビットのみクリア


Readers/Writerロックのサポート

  • 複数の読み手タスク(Readers)と単一の書き手タスク(Write)の間で排他処理を行うオブジェクト

  • ビルド方法、インクルードファイル(関数仕様)については以下のファイルを参照してください

    rtos/toppers_fmp3/fmp3/solid_extension/rwlock/Readme.md

  • [2020.2.27]デッドロック対策として同一タスクが多重にロックを取得しようとした場合の動作を以下の通りに変更しました。

    • すでに読み手ロックを取得したタスクが再度読み手ロックを取得 -> 成功 (ただしこの場合には取得した回数分だけアンロックを行う必要があります。)

    • すでに書き手ロックを取得したタスクが再度書き手ロックを取得 -> エラー (E_OBJ)

    • すでに書き手ロックを取得したタスクが読み手ロックを取得 -> エラー (E_OBJ)

  • [制限事項]

    以下の場合についてはAPIでエラーとはならずにデッドロックが発生する可能性があります。

    • 読み手ロックを取得したタスクが書き手ロックを取得


カーネル内の各資源について最大数を取得するAPI

  • 各資源について確保可能な最大数を取得することができます。

  • 静的に生成された資源に対しては ref_cfg(), 動的に生成される資源については aref_cfg() を呼び出します。

  • aref_cfg() は動的資源生成機能拡張が有効な場合のみ使用可能です。

#include <kernel.h>

typedef struct t_rcfg {
    uint_t    tskid_max;      /* タスクの最大数 */
    uint_t    semid_max;      /* セマフォの最大数 */
    uint_t    flgid_max;      /* イベントフラグの最大数 */
    uint_t    dtqid_max;      /* データキューの最大数 */
    uint_t    pdqid_max;      /* 優先度データキューの最大数 */
    uint_t    mtxid_max;      /* ミューテックスの最大数 */
    uint_t    mbfid_max;      /* メッセージバッファの最大数 */
    uint_t    mpfid_max;      /* 固定長メモリプールの最大数 */
    uint_t    cycid_max;      /* 周期通知の最大数 */
    uint_t    almid_max;      /* アラーム通知の最大数 */
    uint_t    spnid_max;      /* スピンロックの最大数 */
    uint_t    isrid_max;      /* ISRの最大数 */
} T_RCFG;

ER ref_cfg(T_RCFG *pk_rcfg);
/*
*     カーネル資源最大数の取得
*
*   <param>
*   T_RCFG   pk_rcfg    結果を格納するパケットのアドレス
*
*   <return value>
*   (戻り値)正常終了(E_OK)
*
*     各資源で定義されている最大数をpk_rcfgに書き込みます。
*     ここで書き込まれる数は静的生成資源と動的生成資源の合計となります。
*     動的資源生成機能拡張が無効な場合には静的資源の最大数と同一になります。
*     タスクコンテキスト/非タスクコンテキストのどちらからもで呼び出し可能です。
*
*   <errors>
*     (なし)
*
*/

#include <kernel.h>
ER aref_cfg(T_RCFG *pk_rcfg);
/*
*     カーネル資源最大数の取得(動的生成資源のみ)
*
*   <param>
*   T_RCFG   pk_rcfg    結果を格納するパケットのアドレス
*
*   <return value>
*   (戻り値)正常終了(E_OK)
*
*     各資源で定義されている動的資源の生成可能な最大数をpk_rcfgに書き込みます。
*     ここで書き込まれる数は動的生成資源のもののみとなります。
*     タスクコンテキスト/非タスクコンテキストのどちらからもで呼び出し可能です。
*
*   <errors>
*     (なし)
*
*/

カーネル内の生成済み動的生成資源の数を取得する

  • API関数呼び出し時点で動的に生成されているカーネル資源の数を取得することができます。

  • 動的資源生成機能拡張が有効な場合のみ使用可能です。

#include <kernel.h>

typedef struct t_rnid {
    uint_t    tskid_num;      /* タスクの生成済ID数 */
    uint_t    semid_num;      /* セマフォの生成済ID数 */
    uint_t    flgid_num;      /* イベントフラグの生成済ID数 */
    uint_t    dtqid_num;      /* データキューの生成済ID数 */
    uint_t    pdqid_num;      /* 優先度データキューの生成済ID数 */
    uint_t    mtxid_num;      /* ミューテックスの生成済ID数 */
    uint_t    mbfid_num;      /* メッセージバッファの生成済ID数 */
    uint_t    mpfid_num;      /* 固定長メモリプールの生成済ID数 */
    uint_t    cycid_num;      /* 周期通知の生成済ID数 */
    uint_t    almid_num;      /* アラーム通知の生成済ID数 */
    uint_t    spnid_num;      /* スピンロックの生成済ID数 */
    uint_t    isrid_num;      /* ISRの生成済ID数 */
} T_RNID;

ER aref_nid(T_RNID *pk_rnid);
/*
*     カーネル資源最大数の取得
*
*   <param>
*   T_RNID   pk_rnid    結果を格納するパケットのアドレス
*
*   <return value>
*   (戻り値)正常終了(E_OK)
*
*     呼び出し時点で生成されている動的資源の数をpk_rcfgに書き込みます。
*     タスクコンテキスト/非タスクコンテキストのどちらからもで呼び出し可能です。
*
*   <errors>
*     (なし)
*
*/

非タスクコンテキストからの clr_flg() を呼び出した場合の動作

SOLID-OSでは非タスクコンテキストから clr_flg() を呼び出した場合、タスクコンテキストから呼び出した場合と同等の動作をします。(第3世代カーネル仕様では E_CTX エラー)


CPUロック状態から呼び出すことが可能なサービスコール

TOPPERS標準仕様においてCPUロック状態で呼出可能なサービスコールに加えて、 以下のサービスコールについてもCPUロック状態から呼び出すことが可能です。 (E_CTXを返さずにCPUロック状態を維持したまま正常処理を行います。)

set_flg
  • これらのサービスコール内部で呼び出したプロセッサ上でタスク切替が必要となる様なタスク状態の変更が行われた場合には該当サービスコール終了後にユーザーが unl_cpu() または unl_spn() を呼び出すことによりCPUロック状態が解除(=割り込み許可)されるタイミングでタスクの遷移(ディスパッチ)が行われます。

警告

割り込みを許可するためにSOLID Core Serviceの SOLID_MUTEX_EnaInt() 関数を呼び出してもタスクの切替は行われません。CPUロック状態でサービスコールを呼び出した後の割り込み許可には必ず unl_cpu() (スピンロック保持中の場合は unl_spn() )を使用してください。

注釈

TOPPERS標準仕様においてCPUロック状態で呼出可能なサービスコールについてはTOPPERS第3世代カーネル(ITRON系)統合仕様書 の「2.5.5 CPUロック状態とCPUロック解除状態」を参照してください。


複数プロセッサをターゲットする割込みの指定が可能

  • カーネル起動時に読み込まれる割込みハンドラのパラメータテーブルでGICが通知するターゲットのCPUコアを複数指定することができます

  • 複数プロセッサをターゲットとする割込みの設定について

  • 同じ割込み番号(IRQNO)に対し、複数のプロセッサを指定可能となりました。

注釈

SGI/PPIの場合: あるIRQNOに対してプロセッサ毎に異なるハンドラを設定可能です。 SPIの場合: あるIRQNOに対して全プロセッサに共通な一つのハンドラのみ設定可能です。

  • 割り込み設定はマクロ CFG_DEF_INT/CFG_DEF_INT_MT を使用して kernel_cfg.c に記述します。

    割込み初期化設定ブロックの設定例 (kernel_cfg.c)

#define            INTNO_SGI_1               1             // SGI #1
#define            INTNO_SGI_2               2             // SGI #2
#define            INTNO_16_1                16            // 割込み番号16
#define            INTNO_17_2                17            // 割込み番号17
#define            INTNO_PPI_1               1             // PPI

extern void int_handler_int17(void);
extern void sgi_handler_p1(void);
extern void sgi_handler_p2(void);
extern void sgi_handler_p3(void);
extern void sgi_handler_p4(void);
extern void sgi_handler_common(void);
extern void spi_handler_common(void);

//
// 割込み初期化ブロック
//
const INTINIB _kernel_intinib_table[] = {

    // IRQ1 <- 最低優先度、ISRを使用, プロセッサ1のみ
    CFG_DEF_INT(INTNO_16_1, INTINI_USE_ISR, TA_NULL, (-1), 1),

    // IRQ2 <- 最高優先度、直接割込みハンドラ関数を登録, すべてのプロセッサに割込みを設定
    CFG_DEF_INT_MT(INTNO_17_2, int_handler_int17, TA_NULL, (-32), CFG_PROC_MASK_ANY),

    // SGIを複数コアをターゲットにしてプロセッサ毎に個別のハンドラを
    // 登録する例
    CFG_DEF_INT(INTNO_SGI_1, sgi_handler_p1, TA_ENAINT, (-2), 1),
    CFG_DEF_INT(INTNO_SGI_1, sgi_handler_p2, TA_ENAINT, (-2), 2),
    CFG_DEF_INT(INTNO_SGI_1, sgi_handler_p3, TA_NULL, (-2), 3),
    CFG_DEF_INT(INTNO_SGI_1, sgi_handler_p4, TA_ENAINT, (-2), 4),

    // SGIを複数コアをターゲットにしてプロセッサ毎に共通のハンドラを
    // 登録する例 (affinity_maskを使用して複数コア分を1行で登録)
    // 下記の例ではSGI発行でprc(1, 2, 3)で割り込み発生し、同じハンドラ関数が呼び出されます。
    CFG_DEF_INT_MT(INTNO_SGI_2, sgi_handler_common, TA_ENAINT, (-2), (CFG_PROC_MASK(1) | CFG_PROC_MASK(2) | CFG_PROC_MASK(3))),

    // SPIを複数コアをターゲットにしてプロセッサ毎に共通のハンドラを
    // 登録する例 (affinity_maskを使用して複数コア分を1行で登録)
    CFG_DEF_INT_MT(INTNO_PPI_1, spi_handler_common, TA_ENAINT, (-2), CFG_PROC_MASK_ANY),
};

警告

GICv3以降の環境でAffinity Routingを使用している場合など、GICのコンフィグレーションに よっては CFG_DEF_INT_MT による複数コアをターゲットにした登録が行えない場合があります。 この場合、 affinity_mask で最も下位のビットにあたるプロセッサ1個の身に対して 割込みがあがる様に設定を行います。(affinity_mask 中の他のプロセッサは対象外)


自タスクの終了と削除(exd_tsk()) [動的生成機能拡張パッケージ(ビルド時オプション)]

  • 自タスクの終了と削除を行います。( acre_tsk() で生成されたタスクのみ)

#include <kernel.h>
ER exd_tsk(void);
/*
*    自タスクの終了と削除
*
*   <param>
*   (なし)
*
*   <return value>
*   (戻り値)エラーコード(<errors>参照のこと)
*
*   呼び出したタスクを終了させ、さらにタスクの削除を行います。
*   具体的には以下の処理を行います。
*
*   - タスクの終了(タスクの状態を休止状態[DORMANT]に変更)
*   - システム状態をCPUロック解除状態,割込み優先度マスク全解除状態,
*      ディスパッチ許可状態に復旧
*   - 呼び出したタスクに対して起動要求がキューイングされている場合に
*      キューイングをクリア(タスク終了後の再起動は行わない)
*   - 呼び出したタスクがミューテックスをロックしていた場合、
*      全て解放
*   - 呼び出したタスクがloc_spnでスピンロックをロックしていた場合、
*      解放
*   - タスクの削除(タスク管理ブロック,スタック等の解放)
*
*   exd_tskが正常に処理された場合にはexd_tskからはリターンすることは
*   ありません。(非タスクコンテキストから呼び出された場合を除く)
*
*     [補足]
*     - 呼び出したタスクが静的に生成されたタスクであった場合には
*      タスクの削除は行わず、休止状態のままとなります。
*      静的生成タスクの場合でもexd_tskからはリターンせずに
*      次のタスク(またはアイドル状態)に遷移します。
*
*   <errors>
*     E_SYS    システムエラー
*                             ・カーネルの誤動作
*     E_CTX    コンテキストエラー
*                             ・非タスクコンテキストからの呼出し
*
*/
  • exd_tsk() を使用するためにはビルドするアプリケーションで以下のプロパティを設定し、動的生成機能拡張パッケージを有効にしてビルドしてください。

LibDynamicCreate <- 'true' (有効)

CPU0以外をマスタープロセッサコアに指定可能

  • SOLID-OS のマスタープロセッサコアを CPU0 以外に変更可能です

  • マスタープロセッサコアを指定する場合は、ビルドするアプリケーションで以下のプロパティを設定してください。

SOLID_BOOT_CPUID <- CPU ID を指定。省略時は "0" 指定として処理

マルチCPUクラスタに対応

  • マルチCPUクラスタの SoC にも対応しています

  • マルチCPUクラスタの SoC の場合には、以下のマクロを定義してください

SOLID_ARM_MULTICLUSTER <- =の後は、クラスタ0のCPU数を指定する(現状2, 4のみ対応)

ref_tsk() の機能拡張

  • ref_tsk() で取得可能なタスク情報に、スタック領域先頭、スタック領域サイズ、現スタックポインタを追加しました

  • この機能有効時の T_RTSK 型の定義は以下の通りです

typedef struct t_rtsk {
  STAT       tskstat;      /* タスク状態 */
  PRI    tskpri;       /* タスクの現在優先度 */
  PRI    tskbpri;      /* タスクのベース優先度 */
  uint_t subpri;       /* タスクのサブ優先度 */
  STAT   tskwait;      /* 待ち要因 */
  ID     wobjid;               /* 待ち対象のオブジェクトのID */
  TMO    lefttmo;      /* タイムアウトするまでの時間 */
  uint_t actcnt;               /* 起動要求キューイング数 */
  uint_t wupcnt;               /* 起床要求キューイング数 */
  bool_t raster;            /* タスク終了要求状態 */
  bool_t dister;            /* タスク終了禁止状態 */
  ID     prcid;             /* 割付けプロセッサのID */
  ID     actprc;            /* 次の起動時の割付けプロセッサのID */
  uint_t affinity_mask;     /* タスクの割付け可能プロセッサ */
#ifdef SOLID_ENABLE_KERNEL_EXT_REF_TSK_STACK_INFO
  SIZE   stksz;       /* スタック領域のサイズ(丸めた値) */
  void   *stk;        /* スタック領域の先頭番地 */
  void   *stkp;       /* 現スタックポインタ */
#endif /* SOLID_ENABLE_KERNEL_EXT_REF_TSK_STACK_INFO */
} T_RTSK;
  • ref_tsk() の機能拡張を使用するためにはビルドするアプリケーションで以下のプロパティを設定してください。

SOLID_EXTEND_REF_TSK <- '1' (有効) or '0' (無効)

eget_tid() API の追加

  • コンテキスト、CPUロック状態によらず当該CPUコアでのRUNNING 状態のタスクのタスクIDを返す

  • 呼び出し形式等は get_tid() と同じです。

  • eget_tid() の機能拡張を使用するためにはビルドするアプリケーションで以下のプロパティを設定してください。

SOLID_SUPPORT_EGET_TID <- '1' (有効) or '0' (無効)

制限事項

  • スピンロックの動的削除 (del_spn()) は機能せずエラーになる

  • スピンロックはエミュレート方式のみ対応しています。今後のリリースで対応予定です。