第3章 メモリ保護機能
RI600PXは,マイコンに搭載されたMPU(Memory Protection Unit)を利用して,タスク・コンテキストからのメモリ・アクセスに関して,以下の保護機能を実現しています。なお,ハンドラは本機能に関係なく,すべてのアドレス空間にアクセスできます。
1 ) タスクおよびタスク例外処理ルーチンによる不正メモリ・アクセスの検出
タスクおよびタスク例外処理ルーチンは,アクセス許可された領域(メモリ・オブジェクト)のみにアクセスできます。許可されていない領域をアクセスすると,アクセス例外ハンドラが起動されます。
タスクおよびタスク例外処理ルーチンは,アクセス許可された領域(メモリ・オブジェクト)のみにアクセスできます。許可されていない領域をアクセスすると,アクセス例外ハンドラが起動されます。
2 ) ユーザ・スタック保護
各タスクのユーザ・スタックは,他のタスクからはアクセスできません。ユーザ・スタックがオーバフローしたり,タスクが他のタスクのユーザ・スタックをアクセスすると,アクセス例外ハンドラが起動されます。
各タスクのユーザ・スタックは,他のタスクからはアクセスできません。ユーザ・スタックがオーバフローしたり,タスクが他のタスクのユーザ・スタックをアクセスすると,アクセス例外ハンドラが起動されます。
3 ) RI600PXによる不正メモリ・アクセスの検出
いくつかのサービス・コールは,引数としてポインタを受け取ります。RI600PXは,サービス・コールを呼び出したタスクがポインタで指定された領域をアクセス可能かを検査します。アクセス許可がない場合には,サービス・コールはエラーE_MACV を返します。
また,いくつかのサービス・コールはユーザ・スタックにタスクのコンテキスト・レジスタを保存します。このときにユーザ・スタックがオーバフローする場合には,サービス・コールはエラーE_MACV を返します。
この機能は,タスク・コンテキストから呼び出されたサービス・コールでのみ行われます。
いくつかのサービス・コールは,引数としてポインタを受け取ります。RI600PXは,サービス・コールを呼び出したタスクがポインタで指定された領域をアクセス可能かを検査します。アクセス許可がない場合には,サービス・コールはエラーE_MACV を返します。
また,いくつかのサービス・コールはユーザ・スタックにタスクのコンテキスト・レジスタを保存します。このときにユーザ・スタックがオーバフローする場合には,サービス・コールはエラーE_MACV を返します。
この機能は,タスク・コンテキストから呼び出されたサービス・コールでのみ行われます。
「だれが」に相当するものが「ドメイン」です。タスクとそのタスク例外処理ルーチンは,必ずいずれかのドメインに所属します。ドメインは1~15 のドメインID で識別されます。ドメインは,システム・コンフィギュレーション・ファイルで静的に生成されます。
メモリ・オブジェクトは,通常はシステム・コンフィギュレーション・ファイルで静的に登録しますが,動的に登録(ata_mem サービス・コール),登録解除(det_mem サービス・コール)することもできます。メモリ・オブジェクトは,先頭アドレスが16 バイト境界で,かつサイズが16 バイトの整数倍でなければなりません。
タスクから,メモリ・オブジェクトに対して許可されていないアクセスをした場合,およびメモリ・オブジェクトでも自タスクのユーザ・スタックでもない領域をアクセスした場合,アクセス例外ハンドラが起動されます。
あるドメインにリード・アクセス,ライト・アクセス,実行アクセスの少なくともひとつのアクセスを許可されているメモリ・オブジェクトの数は,最大7つです。このことに留意して,メモリ・マップ設計を行ってください。ata_memまたは sac_memによってこの制約を満たさなくなる場合には,E_OACVエラーが検出されます。
RI600PXでは,このような悪意による不正メモリ・アクセスを防ぐために,「信頼されたドメイン」と呼ぶ機能をサポートしています。以下に示すソフトウエア構成に変更を与えるサービス・コールは,信頼されたドメインに所属するタスクからのみ呼出し可能となっています。これらのサービス・コールを信頼されていないドメインから呼び出した場合は,E_OACVエラーが検出されます。
1 ) ダウンロードする領域をメモリ・オブジェクトとして登録(ata_mem)する。その際,そのメモリ・オブジェクトに対し,ダウンロードを実行するタスクが所属するドメインAからのライトアクセスを許可する。その後,メモリ・オブジェクト領域にダウンロードを行う。
2 ) ダウンロード完了後,そのメモリ・オブジェクトをドメインBからアクセスできるように設定(sac_mem)する。そして,ダウンロードしたコードを,ドメインBに所属するタスクとして生成し,起動する。
また,タスクから呼び出されたサービス・コールでカーネルがユーザ・スタックを使用する場合,カーネルはスタック・ポインタがそのタスクのユーザ・スタック領域内にあるかどうかを検査します。範囲外の場合にはエラーE_MACVを返します。
共通ライブラリ関数など,複数のドメインから呼び出されるプログラムでは,メモリ・アクセスが可能かどうかを判定したい場合があります。このような場合は,vprb_memサービス・コールを利用してください。vprb_memサービス・コールは,指定したタスクが指定した領域に対して指定したアクセスが可能かを検査します。
タスクまたはタスク例外処理ルーチンが,許可されていないメモリにアクセスした時には,アクセス例外ハンドラが起動されます。アクセス例外ハンドラでは,アクセス違反の要因を取り除いて復帰するなどの処理を行うことができます。あるいは,デバッグ目的のみで使用しても構いません。
システム・コンフィギュレーション・ファイルで,静的API“memory_object[]”によってメモリ・オブジェクトを登録するとき,メモリ・オブジェクトのアドレスを絶対アドレスまたはセクション名で指定することができます。
セクション名指定では,メモリ・オブジェクトを構成する先頭のセクション名と最後のセクション名を指定します。この場合,リンク時に必ず想定通りのセクション配置となるように注意してください。たとえば,メモリ・オブジェクトの先頭は16バイト境界でなければならないので,メモリ・オブジェクトの先頭(memory_object[].start_address)に指定したセクションに対し,リンカの“aligned_section”オプションを指定してください。
また,メモリ・オブジェクトのサイズは16の整数倍,すなわちメモリ・オブジェクトの終端アドレスは16の整数倍+15でなければなりません。しかし,メモリ・オブジェクトの最後のセクション(memory_object[].end_address)がこの通りになるとは限りません。最後のセクションの終端が16の倍数+15でない場合には,終端+1から次の16の倍数+15までの範囲も,そのメモリ・オブジェクトの一部と扱われます。したがって,リンク時には終端セクションの終端+1から16の倍数+15の範囲には他のセクションを配置してはなりません。
- 例
memory_object[].end_addressに“CU_DOM1”を指定し,CU_DOM1セクションの終端アドレスが0xFFFF1003の場合,0xFFFF1004~0xFFFF100Fの範囲に他のセクションを配置してはなりません。リンク時に,CU_DOM1の後続のセクションに“aligned_section”オプションを指定することで,0xFFFF1004~0xFFFF100Fにはどのセクションも配置されなくなります。
memory_object[].end_addressに“CU_DOM1”を指定し,CU_DOM1セクションの終端アドレスが0xFFFF1003の場合,0xFFFF1004~0xFFFF100Fの範囲に他のセクションを配置してはなりません。リンク時に,CU_DOM1の後続のセクションに“aligned_section”オプションを指定することで,0xFFFF1004~0xFFFF100Fにはどのセクションも配置されなくなります。
1 ) タスクがアクセスする領域
タスクがアクセスできるのは,そのタスク自身のユーザ・スタックを除くと,アクセス許可が適切に設定されたメモリ・オブジェクトのみです。したがって,タスクがアクセスするプログラムセクション,定数セクション,初期化データ・セクション,未初期化データ・セクションは,メモリ・オブジェクト内に配置する必要があります。また,タスクでI/O領域をアクセスする場合には,その領域もメモリ・オブジェクトとする必要があります。
タスクがアクセスできるのは,そのタスク自身のユーザ・スタックを除くと,アクセス許可が適切に設定されたメモリ・オブジェクトのみです。したがって,タスクがアクセスするプログラムセクション,定数セクション,初期化データ・セクション,未初期化データ・セクションは,メモリ・オブジェクト内に配置する必要があります。また,タスクでI/O領域をアクセスする場合には,その領域もメモリ・オブジェクトとする必要があります。
2 ) メールボックスで扱うメッセージ
メッセージは,送受信双方のタスクからアクセス可能なメモリ・オブジェクト内に作成する必要があります。
ただし,メッセージ先頭には,カーネルの管理テーブルがあります。カーネル管理テーブルが破壊されると,システムの正常な動作は保証されません。この理由から,メッセージ通信には,データ・キューまたはメッセージ・バッファの使用を推奨します。
メッセージは,送受信双方のタスクからアクセス可能なメモリ・オブジェクト内に作成する必要があります。
ただし,メッセージ先頭には,カーネルの管理テーブルがあります。カーネル管理テーブルが破壊されると,システムの正常な動作は保証されません。この理由から,メッセージ通信には,データ・キューまたはメッセージ・バッファの使用を推奨します。
3 ) 固定長・可変長メモリ・プール領域
メモリ・プール領域は,メモリ・ブロックを使用するタスクからアクセス可能なメモリ・オブジェクト内とする必要があります。
ただし,RI600PXはメモリ・プール領域内に管理テーブルを生成します。カーネル管理テーブルが破壊されると,システムの正常な動作は保証されません。
メモリ・プール領域は,メモリ・ブロックを使用するタスクからアクセス可能なメモリ・オブジェクト内とする必要があります。
ただし,RI600PXはメモリ・プール領域内に管理テーブルを生成します。カーネル管理テーブルが破壊されると,システムの正常な動作は保証されません。
‐ システム・コンフィギュレーション・ファイルで固定長メモリ・プールを生成する場合
固定長メモリ・プール領域はmemorypool[].sectionで指定したセクションに生成されます。memorypool[].sectionを省略した場合,固定長メモリ・プール領域はBURI_HEAPセクションに生成されます。
固定長メモリ・プール領域はmemorypool[].sectionで指定したセクションに生成されます。memorypool[].sectionを省略した場合,固定長メモリ・プール領域はBURI_HEAPセクションに生成されます。
‐ システム・コンフィギュレーション・ファイルで可変長メモリ・プールを生成する場合
可変長メモリ・プール領域はvariable_memorypool[].mpl_sectionで指定したセクションに生成されます。variable_memorypool[].mpl_sectionを省略した場合,可変長メモリ・プール領域はBURI_HEAPセクションに生成されます。
可変長メモリ・プール領域はvariable_memorypool[].mpl_sectionで指定したセクションに生成されます。variable_memorypool[].mpl_sectionを省略した場合,可変長メモリ・プール領域はBURI_HEAPセクションに生成されます。
1 ) BURI_HEAP以外のRI600PXのセクション
BURI_HEAP以外のRI600PXのセクションはRI600PXのみがアクセスするため,メモリ・オブジェクトにしてはなりません。RI600PXのセクションについては,「2.6.4 セクション配置」を参照してください。
BURI_HEAP以外のRI600PXのセクションはRI600PXのみがアクセスするため,メモリ・オブジェクトにしてはなりません。RI600PXのセクションについては,「2.6.4 セクション配置」を参照してください。
2 ) タスクのユーザ・スタック領域
タスクのユーザ・スタック領域はメモリ・オブジェクト外でなければなりません。他のユーザ・スタックおよびメモリ・オブジェクトと重なっていた場合,システムの正常な動作は保証されません。
タスクのユーザ・スタック領域はメモリ・オブジェクト外でなければなりません。他のユーザ・スタックおよびメモリ・オブジェクトと重なっていた場合,システムの正常な動作は保証されません。
‐ システム・コンフィギュレーション・ファイルでタスクを生成する場合
ユーザ・スタック領域はtask[].stack_sectionで指定したセクションに生成されます。task[].stack_sectionを省略した場合,ユーザ・スタック領域はSURI_STACKセクションに生成されます。
ユーザ・スタック領域はtask[].stack_sectionで指定したセクションに生成されます。task[].stack_sectionを省略した場合,ユーザ・スタック領域はSURI_STACKセクションに生成されます。
4 ) メッセージ・バッファ領域
メッセージ・バッファ領域はメモリ・オブジェクト外でなければなりません。ユーザ・スタックおよびメモリ・オブジェクトと重なっていた場合,システムの正常な動作は保証されません。
メッセージ・バッファ領域はメモリ・オブジェクト外でなければなりません。ユーザ・スタックおよびメモリ・オブジェクトと重なっていた場合,システムの正常な動作は保証されません。