/* *---------------------------------------------------------------------- * T2EX Software Package * * Copyright 2012 by Ken Sakamura. * This software is distributed under the T-License 2.0. *---------------------------------------------------------------------- * * Released by T-Engine Forum(http://www.t-engine.org/) at 2012/12/12. * Modified by T-Engine Forum at 2015/2/27. * *---------------------------------------------------------------------- */ ============================================================================== T-Engineリファレンスボード用 T2EX実装仕様書 ============================================================================== ------------------------------------------------------------------------------ 1. 概要 ------------------------------------------------------------------------------ 本書は、T-Engine リファレンスボード上で動作する T-Kernel 2.0 Extension (T2EX) の実装に関する設定やリソースに関する詳細や制限事項を記述した仕様書である。 ------------------------------------------------------------------------------ 2. T-Kernel 2.0 リファレンス実装との差分 ------------------------------------------------------------------------------ T2EXの実装は T-Kernel 2.0 のリファレンス実装をベースとし、追加を行うことを 基本として作られているが、一部 T-Kernel 2.0 リファレンス実装に対して修正を 加えている。 具体的には、以下の点について T-Kernel 2.0 リファレンス実装に対する変更が行 われている。 - ディスパッチャ (${BD}/kernel/sysdepend_t2ex/cpu/em1d/cpu_support.S) プロセッサの排他的レジスタロード/ストア命令(ldrexおよびstrex)の 利用のために、ディスパッチ時に排他をクリア(clrex)する処理を追加。 - メモリ管理機能 (${BD}/kernel/extension/memory/t2ex) 詳細については第3節に示す。 ------------------------------------------------------------------------------ 3. メモリ保護機能 ------------------------------------------------------------------------------ 3.1 基本的な設定項目 T2EXのメモリ管理機能の基本的な設定は、ソースプログラム中の以下のファイルに 含まれる設定を書き換えることで行うことができる。 kernel/sysmain/build_t2ex/tef_em1d/Makefile 以下のようなパラメータを設定することが可能である。 - T2EX_MM 利用するメモリ管理機能名のサフィックス _t2ex : T2EX標準のメモリ保護機能を用いる (空) : T-Kernel 2.0標準のメモリ管理機能(メモリ保護なし)を用いる - T2EX_MM_USE_TASKEXCEPTION メモリ保護違反時の処理方法の指定 1 : TaskMemFaultHdr() を利用する標準構成を利用する 0 : TaskMemFaultHdr() を利用しない簡易構成を利用する - T2EX_MM_USE_DEFAULT_FAULT_HANDLER 保護違反処理例外ハンドラの定義位置の指定 1 : T2EXシステムコード内部で定義されたハンドラを利用する 0 : ユーザアプリケーション側で定義されたハンドラを利用する 3.2から3.6までの各節では、T2EX_MM を _t2ex とした場合の構成について述べる。 T2EX_MM を空とする場合、すなわちT2EXのメモリ保護機能を利用しない場合の設定に ついては、3.7節で述べる。 3.2 MMUの設定 以下のように設定されており、T-Kernel 2.0リファレンス実装と共通である。 この設定は、システム起動時に T-Monitor により設定され、以後変更されない (変更してはならない)。 (a) SCTLR.AFE [29] = 1 ページテーブルのアクセスフラグを有効にする。 (b) SCTLR.TRE [28] = 1 メモリ属性 TEX の再マップを有効にする。 (c) PRRR = 0x000a8aa4 (d) NMRR = 0x44e048e0 メモリ属性の再マップを、以下のように割り当てる。 TEX[0] C B メモリタイプ 内部キャッシュ 外部キャッシュ 0 0 0 Strongly-order None None 0 0 1 Device None None 0 1 0 Normal WT-NA WT-NA 0 1 1 Normal WB-NA WB-NA 1 0 0 Normal None None 1 0 1 Normal WT-NA WB-A 1 1 0 (未使用) 1 1 1 Normal WB-A WB-A WT-NA Write-through, no allocate on write WB-NA Write-back, no allocate on write WB-A Write-back, allocate on write 3.3 メモリマップ 以下の通りとなっており、T-Kernel 2.0リファレンス実装とおおむね共通である。 論理アドレス モード 0x00000000 +=======================+ -- |タスク固有空間 | | 仮想メモリ (予約) 0x10000000 +=======================+ -- |周辺デバイス | S D RW- |(未使用領域含む) | 0x30000000 +-----------------------+ -- |RAM (64MB) | | 保護メモリ領域 |(未使用領域含む) | 0x40000000 +-----------------------+ -- |周辺デバイス | S D RW- |(未使用領域含む) | 物理アドレス 0x70000000 +-----------------------+ -- 0x00000000 |ROM (32MB) | S C R-X | NOR Flash を写像(*1) 0x72000000 +-----------------------+ -- 0x02000000 |(予約) | 0x80000000 +=======================+ -- |プログラムマップ用 | ↑ 0x90000000 +-----------------------+ | 仮想メモリ (予約) |メモリマップ用 | ↓ 0xa0000000 +=======================+ -- |内蔵 SRAM (128KB) | S N RWX |(未使用領域含む) | 0xb0000000 +-----------------------+ |周辺デバイス | S D RW- |(未使用領域含む) | 0xd0000000 +=======================+ -- |共有メモリ空間 | | 仮想メモリ (予約) 0xf0000000 +=======================+ -- |内蔵 Boot ROM | S N R-- |(未使用領域含む) | 0xffffffff +-----------------------+ モード 保護レベル属性 S システムレベル (ユーザレベルからのアクセス不可) U ユーザレベル (システムレベル・ユーザレベルからアクセス可能) メモリタイプ/キャッシュ属性 C キャッシュ ON Normal memory / Write-back cache, Write allocate N キャッシュ OFF Normal memory / Non-cacheable D デバイス Device memory / Non-cacheable アクセス属性 ( - はその属性がオフ) R リード可 W ライト可 X プログラム実行可 ・各領域のドメインはすべて 0 である。 ・保護メモリ領域となっている領域はT2EXメモリ保護機能によって管理される 領域であり、ページ単位(4KB)でモードの指定が行われる。 保護メモリ領域以外の領域はいずれもセクション単位(1MB)でマッピング およびモードの指定が行われる。 ・仮想メモリとなっている領域は本実装では使用されず、予約されている。 未割り当て領域として設定されており、アクセス不可となっている。 ・保護メモリおよび仮想メモリ以外の領域は、論理アドレス=物理アドレスとして マッピングされ、マッピング・モードのいずれも動的に変化しない。 (*1) ただし、タスク固有空間に隠れてしまう NOR Flash の領域は、論理 アドレス=物理アドレスとはならず、上記メモリマップのように移動 してマッピングする。このマッピングは動的に変化しない。 本書中のアドレスは、特に記述がない限り論理アドレスで表記されている。 ・内蔵 SRAM および内蔵 Boot ROM は、システム起動時(ブート時)に使用される が、システム起動後は使用されず、OS による管理もされない。 システム起動後、内蔵 SRAM は、任意の用途に使用可能である。 ・保護メモリ領域のうち、tk_get_smb() や malloc() 等の動的メモリ割り当て APIコールや、システム内部の動的なメモリ割り当てに用いられる領域を動的 割り当て領域と呼ぶ。初期状態ではアクセス不可能なモードが指定されており、 割り当てが行われた状態で指定されたモードでアクセス可能となり、解放された 時点でアクセス不可能なモードに戻る。 ・動的割り当て領域以外のメモリは静的にモードが指定される領域であり、静的 割り当て領域と呼ばれる。動的メモリ領域と異なり、T2EXの初期化時に固定した モードが割り当てられる。T2EXの初期化処理を適切に変更することで、アプリケー ションに応じて適切なモードを割り当てる事が可能である。 3.4 静的割り当て領域 この節では、本実装における静的割り当て領域の実装の概要と、アプリケーション に応じた変更方法について示す。 3.4.1 初期化処理 静的割り当て領域の割り当てを行うために、本実装ではELFオブジェクトにおける セクション(以下、リンカセクション)を利用する。すなわち、同一のモードを持つ シンボルの属するメモリ領域に対してリンカセクションを対応付けることで、リン カセクションを通したメモリ領域の指定を行なっている。 静的割り当て領域の設定に関係するファイルは以下の通りである。 - kernel/sysmain/build_t2ex/tef_em1d/kernel_t2ex-rom.lnk - kernel/sysmain/build_t2ex/tef_em1d/kernel_t2ex-ram.lnk シンボルの所属するリンカセクションを指定する。 すなわち、シンボルの属するメモリ領域のモードを指定する。 - kernel/extension/memory/t2ex/sysdepend/em1d/space.c 各静的領域に対するモードの設定を行う。(InitLogicalSpace関数) - kernel/sysdepend_t2ex/device/tef_em1d/icrt0_t2ex.S または icrt0_t2ex_ram.S 静的領域を含むメモリ領域の内容に対する初期化を行う。 具体的な例を示すと、kernel_t2ex-rom.lnk では、ユーザレベル用のデータ領域に 対するリンカセクションである .data_usr および .bss_usr を以下のように定義 している。 このルールでは、*.uo のファイル名を持ったオブジェクトファイル内のデータ 領域が、.data_usr, .bss_usr の各セクションに含まれるように定義される。 これらの2つのセクションは連続して割り当てられれ、その先頭・終端には __data_usr_start, _end_usr のシンボルがそれぞれ定義される。 __data_usr_org = LOADADDR(.bss) + SIZEOF(.bss); .data_usr ALIGN(0x1000) : AT(__data_usr_org) { __data_usr_start = . ; *.uo(.data) *.uo(.data.*) *.uo(.data1) KEEP (*.uo(.eh_frame)) *.uo(.gcc_except_table) *.uo(.sdata) *.uo(.sdata.*) . = ALIGN(4); _edata_usr = .; PROVIDE (edata_usr = .); } .bss_usr ALIGN(4) : { __bss_usr_start = .; PROVIDE (__sbss_usr_start = .); PROVIDE (___sbss_usr_start = .); *.uo(.sbss) *.uo(.sbss.*) *.uo(.scommon) PROVIDE (__sbss_usr_end = .); PROVIDE (___sbss_usr_end = .); *.uo(.bss) *.uo(.bss.*) *.uo(COMMON) . = ALIGN(4); _end_usr = .; PROVIDE (end_usr = .); } space.c 内の InitLogicalSpace 関数では、この情報を用いて初期化が行われる。 具体的には、以下の部分によって __data_usr_start から _end までの領域が、 モード PTE_USR_RW (ユーザアクセス可能・読み書き可能)に初期化される。 (なお、この場所が実行される際に la = __data_usr_start となっている。) for ( ; (UW)la < (UW)&_end_usr; la = NextPage(la) ) { /* User data area (__data_usr_start ... _end_usr) */ pte.w = PTE_USR_RW; pte.a.pfa = LADRtoPFA(la); SetPTE(la, pte, FALSE); } icrt0_t2ex.S は、T-Kernel 2.0 標準実装の icrt0.S に相当するが、BSS領域が .bss, .bss_usr の2つに分割されることから、それぞれに対する初期化を分けて 行なうように変更されている。メモリ領域の変更によりもともととは異なる初期 化が必要となる場合には、このファイルを修正する必要がある。 3.4.2 リファレンス実装における静的設定 3.4.1 節に示す実装方法により、リファレンス実装では以下のような静的割り当て領域に 対する設定が行われている。ここで、[] 内に示した名前はそれぞれのシンボルが割り当て られるリンカセクション名である。 --------------------------------------------------------------------------------- 領域 特権レベル ユーザレベル ================================================================================= ユーザレベルのプログラム領域 [.text] R,EX R,EX 読込み専用データ領域 [.rodata] R,EX R,EX 特権レベルの読み書き可能データ領域 R,W - [.data, .bss] ユーザレベルの読み書き可能データ領域 R,W R,W [.data_usr, .bss_usr] --------------------------------------------------------------------------------- リファレンス実装におけるモード設定は、ユーザレベルからのシステムレベル領域に対する 書き込み権限の禁止を徹底しているほかは、全体的に簡易的かつ保守的な設定としている。 具体的には、プログラム領域・読込み専用可能データ領域については保護レベルの区別を 行なっていないため、たとえば以下の操作については許容され保護違反とはならない。 - ユーザレベルからの静的システムプログラムコードへのアクセス このような設定としている理由は、システム側とユーザプログラム側で共通に利用される コードおよび読込み専用データの共有にある。この設定では、たとえばSVCインタフェース ライブラリ(libsvc.a)のコードを共有することができるため、プログラムコードの 置かれるROMまたはRAMを節約することが可能となる。 3.4.3 データ領域の割り当て T2EXリファレンス実装の Makefile では、従来 SRC としていたものを SRC_SYS と SRC_USR の2つに分割し、前者をシステム領域用、後者をユーザ領域用としている。 すなわち、SRC_SYS, SRC_USR のどちらにソースファイルを指定するかによって、 カーネルにリンクされるオブジェクトの読み書き可能なデータ領域(.data, .bss)が 割り当てられる空間が以下のように異なっている。 - SRC_SYS: 特権レベルの読み書き可能データ領域(.data, .bss)に割り当てる - SRC_USR: ユーザレベルの読み書き可能データ領域(.data_usr, .bss_usr)に 割り当てる SRC_SYS, SRC_USR の指定は以下のいずれかのファイルを通して行うことが出来る。 kernel/sysmain/build_t2ex/tef_em1d/Makefile kernel/sysmain/build_t2ex/Makefile.common 3.5 保護違反例外 割り当てが行われていない動的領域へのアクセスや、モード指定に反するメモリアクセス 違反を行った場合にはメモリ保護違反となり、保護違反例外処理が行われる。 T2EX_MM_USE_DEFAULT_FAULT_HANDLER を 1 とした場合、保護違反処理例外ハンドラは 以下のT2EX内部のファイルで定義されており、以下のファイルに含まれる TaskMemFaultHdr() および RawMemFaultHdr() を適切に変更することで、必要な例外処理を行うことができる。 kernel/extension/memory/t2ex/sysdepend/em1d/exchdr.c 本実装においては、各ハンドラはサンプルとして以下のように実装されている。 - RawMemFaultHdr() デバッグ支援目的の実装であり、"*** OS SYSTEM DOWN ***" のメッセージを 出力し、T-Monitorに遷移する。 - TaskMemFaultHdr() 例外を発生させたタスクに対して、例外コード 0 のタスク例外を送信する。 タスク側はタスク例外ハンドラを定義し、例外処理を行うことで、タスク単位での 保護違反例外処理を行うことが出来る。 なお、タスク例外の送信が失敗した場合(対象のタスクがタスク例外ハンドラを 実装していない場合を含む)には、RawMemFaultHdr() と同様に "*** OS SYSTEM DOWN ***" のメッセージを出力し、T-Monitorに遷移する。 なお、T2EX_MM_USE_DEFAULT_FAULT_HANDLER を 0 とした場合には、上記のサンプル 実装はリンクされず、ユーザアプリケーション側でこれらの関数を定義する必要がある。 3.6 実装上の制限事項 以下の制限事項がある。 - セクション単位(1MB)で管理された静的領域に対して、モードの変更を行うことは できない。 3.7 T2EXメモリ保護機能を利用しない設定 T2EXのメモリ保護機能を利用しない設定とする場合、以下の設定を行う必要がある。 - kernel/sysmain/build_t2ex/tef_em1d/Makefile T2EX_MM を空に設定する(詳細は3.1節を参照) - kernel/sysdepend_t2ex/cpu/em1d/cpu_conf.h USE_MMU を 0 に設定する。(標準では1に設定されている) 上記の設定を行った場合の動作については、T-Kernel 2.0の実装仕様書を参照すること。 ------------------------------------------------------------------------------ 4. ファイル管理機能 ------------------------------------------------------------------------------ 4.1 特殊ファイルシステム ファイル管理機能では、「基本FATファイルシステム」以外に,以下の2つの特殊 なファイルシステムを内部的に使用する。 (1) ルートファイルシステム ファイルシステムを接続するルートディレクトリ "/" に対応した仮想的なファイ ルシステム。 ファイルシステム実装部名 "rootfs" 接続名 "/" (特別な名称) サブディレクトリ <接続したファイルシステムの接続名> ルートファイルシステムの切断や、実装部の登録の削除はできない。 (2) コンソールファイルシステム 標準入出力をファイルとして取り扱うための、コンソールデバイスに対応した仮 想的なファイルシステム。 ファイルシステム実装部名 "consolefs" 接続名 "console" ファイル "stdin", "stdout", "stderr" コンソールファイルシステムの切断や、実装部の登録の削除はできない。ファイ ルは上記の3つに固定され、削除や追加はできない。 コンソールファイルシステムでは、コンソールの操作のために、コンソールドラ イバの以下のAPIを使用する。 ConsoleIO() 初期化 console_conf() コンフィグレーション console_in() 入力 console_out() 出力 4.2 ファイル管理共通部 4.2.1 システム構成情報 FsMaxFile 同時にオープン可能なファイル数(システム全体) システム全体としてアプリケーションタスクから同時にオープンできるファイル の数を指定する。自動的にオープンされる標準入出力の stdin, stdout, stderr の3つのファイルは、この数に含まれない。 最低 2 以上を設定すること。 FsMaxFIMP 同時に登録可能なファイルシステム実装部数 システム全体として同時に登録可能なファイルシステム実装部の数を指定する。 自動的に登録されるルートファイルシステム実装部と、コンソールファイルシステ ム実装部は、この数に含まれないが、基本FATファイルシステム実装部は、この数 に含まれる。 最低 1 以上を設定すること。 FsMaxCON 同時に接続可能なファイルシステムの接続数 システム全体として同時に接続可能なファイルシステムの接続数を指定する。 自動的に接続されるルートファイルシステムと、コンソールファイルシステムは、 この数に含まれない。 最低 1 以上を設定すること。 ※ 上記の設定値は、動的なメモリの消費量に直接的に影響するため、必要最低限の 数値に設定することが望まれる。 4.2.2 カーネルオブジェクト 以下のカーネルオブジェクトを消費する。 ---------------------- 種別 個数 ====================== サブシステム 1 イベントフラグ 1 ---------------------- 4.2.3 動的なメモリ確保 以下のサイズのメモリを Kmalloc() / Kfree()により動的に確保/解放する。 ----------------------------------- 動的確保するメモリサイズ(バイト数) =================================== 初期化時: (終了するまで解放されない) 8 * ( TMaxTskId ) 4 * ( TMaxTskId ) 4 * ( FsMaxFile + 3 ) + 16 24 * ( FsMaxFile + 3 ) 76 * ( FsMaxFIMP + 2 ) 60 * ( FsMaxCON + 2 ) PATH_MAX( =1024 ) * 2 ----------------------------------- 一時的: PATH_MAX( =1024 ) ----------------------------------- 4.2.4 APIの実装方式 ファイル管理機能の API は、基本的に拡張 SVC として実装しているが、例外と して、以下の API はライブラリとして実装している。 (1) 可変引数の処理のため int fs_open(const char *path, int oflag, ... /* mode_t mode */ ); int fs_ioctl(int fd, int request, ... /* arg */ ); int fs_fcntl(int fd, int cmd, ... /* arg */ ); (2) 同等の API への置き換え int fs_creat(const char *pathname, mode_t mode); --> fs_open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode); (3) 戻り値の対応のため off_t fs_lseek(int fd, off_t offset, int whence); off64_t fs_lseek64(int fd, off64_t offset64, int whence); 4.2.5 カレントディレクトリの英大文字/小文字 カレントディレクトリはファイル管理機能(共通部)で管理しており、fs_chdir() で設定したパス名の文字列を、そのまま fs_getcwd() で戻す。 そのためFATファイルシステムのような英大文字と小文字の区別がないファイルシ ステムでは、パス名中の英大文字と小文字が実際のファイル名と一致しない場合 がある。 (例) ディレクトリ /FAT/local/bin/ に対して、 fs_chdir("/FAT/Local/BIN") を実行後の fs_getcwd() では、 "/FAT/Local/BIN" が戻り、 fs_chdir("/FAT/LOCAL/bin") を実行した後の fs_getcwd() では、 "/FAT/LOCAL/bin" が戻る。 fs_fchdir() で設定した場合は、ファイルシステム実装部の動作に依存する。 4.3 基本 FAT ファイルシステム実装部 4.3.1 システム構成情報 FsAccessTime 最終アクセス時刻の更新の可否 最終アクセス時刻を更新するかどうかを指定する。0 を指定した場合には、最終 アクセス時刻を更新しない。0 以外を指定した場合は、最終アクセス時刻を更新 するため、ファイルの生成や書き込みを一切行わない場合でも、ファイルシステ ムへの書き込みが発生する場合がある。( FAT ファイルシステムでの、アクセス 時刻は日単位のため、日が変わらないかぎり書き込みは発生しない ) FiFAT_TskPri タスク優先度 ファイルシステムに対する実際の処理を行うタスクの優先度を指定する。 他のタスクとの依存関係は特にないが、通常はアプリケーションタスクより高い 優先度に設定すること。 FiFAT_StkSz タスクスタックサイズ ファイルシステムに対する実際の処理を行うタスクのスタックサイズ。 標準の 2048 から特に変更する必要はない。 FiFAT_FCacheSz FATキャッシュサイズ(バイト数) FiFAT_FCacheNs FATキャッシュ単位セクタ数 FAT領域をアクセスするためのキャッシュサイズを指定する。 単位セクタ数は、ディスク入出力の単位となるページのセクタ数を指定する値で 1、または 2 の倍数を指定すること。 ページサイズ = 単位セクタ数 * ディスクセクタサイズ(通常は512バイト) 実際のキャッシュサイズ = (キャッシュサイズ / ページサイズ) * ページサイズ FiFAT_RCacheSz ルートディレクトリキャッシュサイズ(バイト数) FiFAT_RCacheNs ルートディレクトリキャッシュ単位セクタ数 FAT12/16 のルートディレクトリ領域をアクセスするためのキャッシュサイズを指 定する。FAT32 では使用しない。 単位セクタ数は、ディスク入出力の単位となるページのセクタ数を指定する値で 1、または 2 の倍数を指定すること。 ページサイズ = 単位セクタ数 * ディスクセクタサイズ(通常は512バイト) 実際のキャッシュサイズ = (キャッシュサイズ / ページサイズ) * ページサイズ FiFAT_DCacheSz データキャッシュサイズ(バイト数) FiFAT_DCacheNs データキャッシュ単位セクタ数 ファイル/ディレクトリのデータ領域(クラスタ領域)をアクセスするためのキャッ シュサイズを指定する。 単位セクタ数は、ディスク入出力の単位となるページのセクタ数を指定する値で 0、1、または 2 の倍数を指定すること。0 を指定した場合は、クラスタサイズと 同じとなる。 ページサイズ = 単位セクタ数 * ディスクセクタサイズ(通常は512バイト) または、クラスタサイズ(単位セクタ数 = 0 のとき) 実際のキャッシュサイズ = (キャッシュサイズ / ページサイズ) * ページサイズ 4.3.2 カーネルオブジェクト 接続するファイルシステムごとに、以下のカーネルオブジェクトを消費する。 ---------------------- 種別 個数 ====================== タスク 1 ランデブ 1 ---------------------- 接続された 1つのファイルシステムに対する実際の処理は、1つのタスクで順番に 処理され、そのタスクへの処理要求の送信、および処理結果の受信にランデブを 使用する。ランデブのメッセージサイズは 4 バイトである。 4.3.3 動的なメモリ確保 以下のサイズのメモリを Kmalloc() / Kfree()により動的に確保/解放する。 --------------------------------------------------------------- 動的確保するメモリサイズ(バイト数) =============================================================== ファイルシステム接続時: (切断まで解放されない) 2,596 44 * ( FiFAT_FCacheSz / ( FiFAT_FCacheNs * 512 ) ) 44 * ( FiFAT_RCacheSz / ( FiFAT_RCacheNs * 512 ) ) (*1) 44 * ( FiFAT_FCacheSz / ( FiFAT_FCacheNs * 512 ) ) (512 + 44) * 2 4 * ( FsMaxFile ) --------------------------------------------------------------- ファイルオープン時: (クローズするまで解放されない) 60 + 24 80 * N (*2) PATH_MAX(=1024) (*3) --------------------------------------------------------------- (*1) FAT12/16の場合のみ、FAT32では使用しない。 (*2) N はファイルを構成する連続クラスタの数 / 10。 構成するクラスタがすべて不連続に配置された場合、連続クラスタの数は ファイルサイズ/クラスタサイズとなる。 (*3) ディレクトリオープンのときのみ。 4.3.4 注意事項/制限事項 (1) FAT12, FAT16, FAT32 のファイルシステムに対応する。 (2) ショートファイル名(SFN)、および、ロングファイル名(LFN)に対応する。 ショートファイル名の文字コードは、MS漢字コード(CP932) である。 ファイル名として、ASCII 文字のみ使用する場合は、"FAT_ASCII_FN_ONLY" を定 義してビルドすることにより、コード変換テーブルが不要になり、コードサイズ を大幅に小さくすることができる。 (3) ディレクトリの再配置には対応しない。 ロングファイル名(LFN)のためには、連続した複数のディレクトリエントリが必要 になる。ファイル生成時に連続した複数のディレクトリエントリの空きが無かっ た場合は、ディレクトリエントリを再配置して連続した空きを作るのではなく新 たなクラスタを追加してディレクトリを拡大することで対応する。 しかしながら、FAT12, FAT16 のルートディレクトリは拡大できないため、ディレ クトリエントリの空きがあるにも関わらず、ファイルの生成エラーとなる場合が ある。 (4) ファイル通し番号は一意的な保証はない。 FATファイルシステムにはファイル通し番号は存在しないため、ファイル通し番号 として、そのファイルに対応したディレクトリエントリのディスク先頭からの位 置をファイル通し番号としている。 そのため、ファイル通し番号は 32ビットでは収まらず、64ビットとなるが、ファ イル管理機能の API は、32ビットであるため、64ビットの下位 32ビットをファ イル通し番号として戻している。そのため、異なるファイルが同じファイル通し 番号となる可能性がある。ただし、同一のディレクトリ内のファイルは全て異な るファイル通し番号となることは保証される。 (5) カレントディレクトリのパス名 fs_fchdir() で戻すカレントディレクトリのパス名の英大文字と小文字はファイ ル名の大文字と小文字を正確に反映するが、そのためにパスを辿る処理が必要に なる。 英大文字と小文字の区別が不要な場合は、"FAT_CURDIR_CASE_NOCARE" を定義して ビルドすることにより、fs_fchdir()の処理を高速化し、コードサイズも少し減ら すことができる。 ------------------------------------------------------------------------------ 5. ネットワーク通信機能 ------------------------------------------------------------------------------ 5.1 LANドライバ T2EXリファレンス実装のネットワーク通信機能は、T-Engineリファレンスボード (tef_em1d)のネットワーク・インタフェース・カード(NIC: Network Interface Card)用の T-Engine 標準デバイスドライバ仕様 LAN ドライバを用いる。この LAN ドライバは、T2EX リファレンス実装のソースコードと一緒に提供され、実機 (tef_em1d) と tef_em1d 用エミュレータ(QEMU-tef_em1d)に共通で利用可能なデ バイスドライバである。 ネットワーク通信機能におけるハードウェア依存部は LAN ドライバのみである。 T2EXリファレンス実装のネットワーク通信機能を tef_em1d とは異なるハードウェ アへ移植する場合、LAN ドライバを移植すればよい。 5.2 同時にオープン可能なソケットの最大数 同時にオープン可能なソケットの最大数はシステム構成情報の SoMaxSocket で設 定できる。この数は、so_socket() で生成されるソケットと so_accept() により 生成されるソケットの合計数である。 1 つのソケットの生成に必要なカーネルオブジェクトは、「5.7 カーネルオブジェ クト」を参照すること。 5.3 接続可能なデバイスドライバの最大数 so_ifattach() でネットワーク通信マネージャに接続可能なデバイスドライバの 数には制限がある。接続可能なデバイスドライバの最大数は以下のヘッダーファ イルの TKN_NIFDEV_MAX で定義されている。 ${BD}/t2ex/network/net/src/netmain/tkn_init.h #define TKN_NIFDEV_MAX 3 5.4 LANドライバに登録されるバッファ (1) 登録されるバッファ数 so_ifattach() でデバイスドライバを接続すると、受信に必要なバッファをその デバイスドライバに登録する。デバイスドライバに登録される受信バッファの個 数はシステム構成情報の SoDrvRxBufNum で設定する。 (2) バッファサイズ デバイスドライバに登録されるバッファサイズは、イーサネットの最大フレーム サイズである 1520 バイトである。この値は以下のヘッダーファイルの TKN_RXBUF_SIZE で定義されている。 ${BD}/t2ex/network/net/src/netmain/if_tkn.h #define TKN_RXBUF_SIZE 1520 5.5 ソケットの送受信キューのバッファサイズ ソケットの送受信キューのバッファサイズに関連するシステム構成情報のデフォ ルト値は以下の通りである。 -------------------------------------- システム構成情報 サイズ(バイト数) ====================================== SoTcpTxBufSz 32,768 SoTcpRxBufSz 32,768 SoUdpTxBufSz 9,216 SoUdpRxBufSz 41,600 SoRawIPTxBufSz 8,192 SoRawIPRxBufSz 8,192 SoRawTxBufSz 8,192 SoRawRxBufSz 8,192 -------------------------------------- TCP のフロー制御の最大ウィンドウサイズは、送信キューまたは受信キューのバッ ファサイズに依存する。システム構成情報の SoTcpDoAutoTx, SoTcpDoAutoRx に 1 を設定すると、送信キューまたは受信キューのバッファサイズは通信相手のウィ ンドウサイズに合わせて動的に変更される(自動リサイズ)。これらのシステム構 成情報のデフォルト値は 0 である。 自動リサイズに関連するシステム構成情報のデフォルト値は以下の通りである。 -------------------------------------- システム構成情報 サイズ(バイト数) ====================================== SoTcpIncAutoTx 16,384 SoTcpMaxAutoTx 262,144 SoTcpIncAutoRx 16,384 SoTcpMaxAutoRx 262,144 -------------------------------------- 5.6 動的なメモリ確保への変更 移植元となったソースコードにおいてスタック上に数KBのバッファを確保してい たものがあった。元の実装では組込み機器用として適当ではないので、malloc() 等で動的に確保するように改良した。 --------------------------------------------------------------- 関数名 ファイルパス =============================================================== res_queryN() net/src_bsdlib/libc/net/getaddrinfo.c getanswer() net/src_bsdlib/libc/net/getaddrinfo.c _gethtent() net/src_bsdlib/libc/net/getaddrinfo.c res_querydomainN() net/src_bsdlib/libc/net/getaddrinfo.c getanswer() net/src_bsdlib/libc/net/gethnamaddr.c res_nquery() net/src_bsdlib/libc/resolv/res_query.c res_nquerydomain() net/src_bsdlib/libc/resolv/res_query.c res_nameinquery() net/src_bsdlib/libc/resolv/res_send.c res_queriesmatch() net/src_bsdlib/libc/resolv/res_send.c --------------------------------------------------------------- (*) ファイルパスは「${BD}/t2ex/network/」を省略している。 動的に確保されるバッファのサイズは次のヘッダーファイルで定義されている。 ${BD}/t2ex/network/net/src_bsdlib/libc/include/port_before.h #define T2EX_NS_MAXPACKET (64*1024) #define T2EX_NS_HOSTBUFSZ (8*1024) #define T2EX_NS_MAXDNAME (1025) #define T2EX_NS_THRESHOLD (1024) T2EX_NS_MAXPACKET DNS パケットの送受信用バッファのサイズ - res_queryN() [getaddrinfo.c] T2EX_NS_HOSTBUFSZ DNS パケットの解析用バッファのサイズ - getanswer() [getaddrinfo.c] - _gethtent() [getaddrinfo.c] T2EX_NS_MAXDNAME DNS ホスト名の展開または圧縮に用いられるバッファのサイズ - getanswer() [getaddrinfo.c] - res_querydomainN() [getaddrinfo.c] - getanswer() [gethnamaddr.c] - res_nquerydomain() [res_query.c] - res_nameinquery() [res_send.c] - res_queriesmatch() [res_send.c] T2EX_NS_THRESHOLD DNS のクエリパケット用バッファのサイズ - res_nquery() [res_query.c] 5.7 カーネルオブジェクト (1) ネットワーク通信機能初期化時に消費されるカーネルオブジェクト so_main() によりネットワーク通信機能を初期化すると以下の数のカーネルオブ ジェクトが消費される。 ---------------------- 種別 個数 ====================== タスク 6 セマフォ 5 イベントフラグ 5 ミューテックス 1 ランデブ 1 周期ハンドラ 1 サブシステム 1 ---------------------- (2) デバイスドライバ接続時に消費されるカーネルオブジェクト so_ifattach() によりデバイスドライバを接続すると以下の数のカーネルオブジェ クトが消費される。 -------------------------- 種別 個数 ========================== タスク 1 メッセージバッファ 1 -------------------------- (3) ソケットの生成により消費されるカーネルオブジェクト so_socket() または so_accept() によりソケットを 1 つ生成すると以下の数の カーネルオブジェクトが消費される。 ------------------------------------------- 種別 個数 =========================================== イベントフラグ ceil(2/32) + ceil(4/32) ------------------------------------------- 表中の「2/32」「4/32」は、それぞれイベントフラグの「2 ビット分」「4 ビッ ト分」を意味している。また、ceil() は天井関数であり、ceil(x) は実数 x に 対して最小の整数を表す。 また、so_socket() と so_accept() により生成されるソケットの合計数が N 個 の場合、以下の個数のイベントフラグが必要になる。 ceil((2*N)/32) + ceil((4*N)/32) (計算例) N=9 の場合 ceil((2*9)/32) + ceil((4*9)/32) = ceil(18/32) + ceil(36/32) = 1 + 2 = 3 (4) ネットワーク通信機能で必要となるカーネルオブジェクト 接続されるデバイスドライバの最大数を D, 生成されるソケットの最大数を S (これはシステム構成情報の SoMaxSocket に等しい) とおくと、下表のようにま とめられる。 -------------------------------------------------------------------- 種別 個数 ==================================================================== タスク 6 + D セマフォ 5 イベントフラグ 1 + ceil((57 + 2*S)/32) + ceil((37 + 4*S)/32) ミューテックス 1 メッセージバッファ D ランデブ 1 周期ハンドラ 1 サブシステム 1 -------------------------------------------------------------------- イベントフラグの天井関数の中に表れる定数項(57と37)は、so_main() による初 期化時に消費されるイベントフラグのビット数である。 5.8 実行環境の設定 T-Engineリファレンスボード(tef_em1d)で動作を確認する場合、特に設定する項 目はない。LAN ケーブルが本体に接続されていることを確認してプログラムを実 行する。 ここでは、T-Engine リファレンスボード (tef_em1d) 用エミュレータ (QEMU-tef_em1d) で T2EX ネットワーク通信機能を使用するための実行環境の設 定方法を説明する。 QEMU-tef_em1d の説明書に記述されているように、起動時のパラメータ指定によ り QEMU-tef_em1d はホストOS上の仮想ネットワークデバイス(TAP)を使用できる。 また、QEMU-tef_em1d とホストOS間で通信を行うためには、ネットワークを適切 に構築する必要がある。本書では、ブリッジ接続を利用して QEMU-tef_em1d とホ ストOS間の通信、および、QEMU-tef_em1d から物理ネットワークに直接アクセス するネットワークを構築する。 (1) 前提条件 (a) ホストOS Windows 7, Windows Vista, Windows XP (QEMU-tef_em1d が動作するホスト OS に準ずる) 下記の作業を行うには、Windows の管理者権限が必要である。 (2) TAP デバイス (a) OpenVPN のインストール 以下の URL から OpenVPN のインストーラをダウンロードする。 http://openvpn.net/index.php/download/community-downloads.html (「Windows Installer」のリンクからダウンロードする) ダウンロードした「openvpn-2.2.2-install.msi」を実行し、画面の指示に従い OpenVPN をインストールする。 インストール中に下記のメッセージが表示されたら、「インストール(I)」を選択 する。 このデバイスソフトウェアをインストールしますか? 名前: TAP-Win32 Provider V9 ネットワークアダプター 発行元: OpenVPN Technologies, Inc. (b) TAP デバイスの名称変更 OpenVPN でインストールされた TAP デバイスの名前には、日本語が含まれている 可能性がある。名前に日本語が含まれていると QEMU-tef_em1d から利用できない ので、適切な名前に変更する必要がある。 以下の手順で「ネットワーク接続」を表示させる。 - Windows 7 の場合 1) スタートメニューから「コントロールパネル」を開く。 2) 「ネットワークの状態とタスクの表示」をクリックする。 3) 「アダプターの設定の変更」をクリックする。 - Windows Vista の場合 1) スタートメニューから「コントロールパネル」を開く。 2) 「ネットワークとインターネット」をクリックする。 3) 「ネットワークセンター」をクリックする。 4) 「ネットワーク接続の管理」をクリックする。 - Windows XP の場合 1) スタートメニューから「コントロールパネル」を開く。 2) 「ネットワークとインターネット接続」をクリックする。 3) 「ネットワーク接続」をクリックする。 「TAP-Win32 Adapter V9」という表記のあるアダプタが、OpenVPN でインストー ルされた TAP デバイスである。このアダプタを右クリックして「名前の変更」を 選択する。 変更する名前は何でも構わないが、スペースは使わずに ASCII 文字のみを用いる こと。以下、ここで名称を「MY-TAP」に変更した前提で説明を続ける。 (3) ブリッジ接続 「ネットワーク接続」を表示させる。((2)(b)参照) まず、ホストPCが利用しているネットワークアダプタを確認する。そのネットワー クアダプタと先程作成した TAP デバイスを、Ctrl キーを押しながら選択する。 選択されているいずれかのアダプタを右クリックし、「ブリッジ接続」をクリッ クする。 (4) QEMU-tef_em1d のパラメータ ${BD}/kernel/sysmain/src/network_sample/ に qemu-net.bat がある。 このファイルを QEMU-tef_em1d のインストールディレクトリ C:\qemu\bin\ に コピーする。ネットワーク通信機能を使用するプログラムを実行する場合は、qemu.bat の代わりに qemu-net.bat を使用する。 qemu-net.bat は qemu.bat に以下のオプションを追加している。環境に合わせて 適宜修正すること。 -net nic,macaddr=52:54:00:12:34:56 QEMU-tef_em1d の NIC の MAC アドレスを設定する。複数の QEMU-tef_em1d を 実行する場合は、それぞれ異なる MAC アドレスを設定する必要がある。なお、 移植元の QEMU の man ページには以下の MAC アドレスを使用しているサンプ ルが記述されている。 52:54:00:12:34:56, 52:54:00:12:34:57, 52:54:00:12:34:58 -net tap,ifname=MY-TAP TAP デバイスの名前を設定する。 5.9 ネットワークの動作確認 ここでは、サンプルプログラムを用いてネットワークの動作を確認するまでの手 順を説明する。 (1) ソースコードの修正 ${BD}/kernel/sysmain/src/appl_main.c の appl_main() を修正する。以下の 関数呼び出しで必要とされるヘッダーファイル net_test.h を次のようにインク ルードする。 #include "network_sample/net_test.h" appl_main() に以下の関数呼び出しを追加する。 net_test(); net_test() 関数は、DHCP を用いてアドレスを設定することを想定している。静 的にアドレスを設定する場合は、アドレス設定関連のマクロを設定し、以下のファ イルの net_test() 内のnet_conf() へ渡すパラメータを修正する。詳細は 「5.11 ネットワークユーティリティ (1) ネットワークインタフェースの設定」 を参照すること。 ${BD}/kernel/sysmain/src/network_sample/net_test.c (2) ネットワークのサンプルプログラムのビルド方法 サンプルプログラムのビルド用 Makefile.sample をインクルードするために、 ${BD}/kernel/sysmain/build_t2ex/tef_em1d/Makefile の最後に次の一行を追加する。 include ../../src/network_sample/Makefile.sample ビルドする場合は、通常のビルドと同様、以下のディレクトリで make を実行す る。 ${BD}/kernel/sysmain/build_t2ex/tef_em1d (3) ネットワークのサンプルプログラムの動作確認 実機上で実行する場合、通常と同様の手順でプログラムを転送して実行する。エ ミュレータ上で実行する場合、ビルドしたバイナリを 5.8(4) で設定した qemu-net.bat から実行する。 ネットワークインタフェースの設定結果とサンプルプログラムの動作結果が出力 される。 5.10 ネットワーク通信機能を利用するプログラム開発 ネットワーク通信機能が提供するソケットを用いて通信するためには、ネットワー ク通信機能を初期化してからネットワークインタフェースを適切に設定する必要 がある。 (1) ネットワーク通信機能の初期化 so_main(0, NULL); (2) ネットワークインタフェースの設定 サンプルプログラムの net_test() の中で呼ばれている net_conf() を呼ぶこと により、ネットワークインタフェース Neta に対して必要なアドレス設定を行う ことができる。 net_conf() およびその他のネットワークユーティリティについては「5.11 ネッ トワークユーティリティ」を参照すること。 ネットワークインタフェースの設定完了後は、ソケットを用いた通信を行える。 5.11 ネットワークユーティリティ ネットワークユーティリティのサンプルプログラムを提供する。 ネットワークユーティリティをビルドする場合は、 ${BD}/kernel/sysmain/build_t2ex/tef_em1d/Makefile の最後に次の一行を追加する。 include ../../src/network_sample/Makefile.sample 通常のビルドと同様、以下のディレクトリで make を実行する。 ${BD}/kernel/sysmain/build_t2ex/tef_em1d (1) ネットワークインタフェースの設定 #include "network_sample/util.h" int net_conf(int emu, int dhcp); パラメータ int emu エミュレータかどうか int dhcp アドレスの設定方法 説明 ネットワークインタフェース Neta を設定する。so_main() でネットワーク通 信機能を初期化してから呼ぶ。 - ループバックデバイスの設定 - ネットワークインタフェース Neta の設定 - デフォルトゲートウェイの設定 - DNS関連の設定 - ホスト名テーブルの設定 net_conf() は、T2EX API コールに加えて 5.11(3) 以降のネットワークユーティ リティ関数を内部的に利用している。 実機で実行する場合は emu に 0 を指定する。エミュレータで実行する場合は emu に 1 を指定する。emu 用に以下の定数が定義されている。 #define NET_CONF_MACHINE (0) #define NET_CONF_EMULATOR (1) DHCP でアドレスを設定する場合は dhcp に 1 を指定する。静的にアドレスを 設定する場合は dhcp に 0 を指定する。dhcp 用に以下の定数が定義されてい る。 #define NET_CONF_STATIC (0) #define NET_CONF_DHCP (1) なお、静的にアドレスを設定する場合、以下のファイルの先頭に定義されてい るマクロを直接編集する。 ${BD}/kernel/sysmain/src/network_sample/net_conf.c - IPADDR: IP アドレス - NETMASK: ネットマスク - GATEWAY: ゲートウェイ - DNSSERVER1: 1つ目のDNSサーバ (不要の場合はコメントアウトする) - DNSSERVER2: 2つ目のDNSサーバ (不要の場合はコメントアウトする) - DNSSERVER3: 3つ目のDNSサーバ (不要の場合はコメントアウトする) - DNSDOMAIN: DNSの検索ドメイン (不要の場合はコメントアウトする) 使用例 (実機で DHCP を使用する場合) net_conf(NET_CONF_MACHINE, NET_CONF_DHCP); 使用例 (エミュレータで静的にアドレスを設定する場合) net_conf(NET_CONF_EMULATOR, NET_CONF_STATIC); (*) net_conf.c の上記マクロを適切に設定しておくこと (2) ネットワークインタフェースの情報表示 #include "network_sample/util.h" void net_show(void); 解説 ネットワークインタフェースに関連する以下の情報を表示する。 - ネットワークインタフェースに設定されたアドレス情報 - DNS関連の設定 - ホスト名テーブル - 経路情報 (3) ネットワークインタフェースのアドレス設定 #include "network_sample/util.h" void set_ifaddr(const char* ifname, in_addr_t addr, in_addr_t mask) パラメータ const char* ifname インタフェース名 in_addr_t addr アドレス in_addr_t mask ネットワークマスク 解説 ifname で指定されたインタフェースにアドレス addr とネットワークマスク mask を設定する。 (4) ネットワークインタフェースの起動/停止 #include "network_sample/util.h" int if_updown(const char* ifname, int is_up) パラメータ const char* ifname インタフェース名 int is_up インタフェースの起動/停止 解説 ifname で指定されたインタフェースを起動または停止する。 インタフェースを起動する場合は is_up に 0 以外の値を指定する。インタ フェースを停止する場合は is_up に 0 を指定する。 (5) 経路の追加 #include "network_sample/route.h" void route_add(in_addr_t dest, in_addr_t gate, in_addr_t mask, int index, int direct); パラメータ in_addr_t dest 宛先アドレス in_addr_t gate ゲートウェイアドレス in_addr_t mask ネットワークマスク int index インタフェースのインデックス int direct 宛先アドレスに直接到達可能かどうかを示す値 解説 宛先アドレス dest、ゲートウェイアドレス gate、ネットワークマスク mask の経路情報をルーティングテーブルに追加する。 index にはインタフェースのインデックスを指定する。この値は、 so_ifnametoindex() などで取得することができる。 宛先アドレスに直接接続されている場合は direct に 0 以外の値を設定し、そ れ以外の場合は direct に 0 を設定する。direct に 0 を設定すると経路情報 のフラグに RTF_GATEWAY を設定し、direct に 0 以外の値を設定すると経路情 報のフラグに RTF_GATEWAY を設定せずに RTF_HOST を設定する。 デフォルトゲートウェイを指定する場合は dest, mask に INADDR_ANY を指定 する。 (6) 経路の削除 #include "network_sample/route.h" void route_delete(in_addr_t dest, in_addr_t mask, int index, int direct); パラメータ in_addr_t dest 宛先アドレス in_addr_t gate ゲートウェイアドレス in_addr_t mask ネットワークマスク 解説 宛先アドレス dest、ゲートウェイアドレス gate、ネットワークマスク mask の経路情報をルーティングテーブルから削除する。 デフォルトゲートウェイを指定する場合は dest, mask に INADDR_ANY を指定 する。 (7) 経路の一覧表示 #include "network_sample/route.h" void dump_rtlist(void); 解説 ルーティングテーブルのエントリを標準出力に表示する。 (8) ホスト名テーブルのエントリ追加 #include "network_sample/util.h" void add_hosttable(const char* hostname, in_addr_t addr); パラメータ const char* hostname ホスト名 in_addr_t addr アドレス 解説 ホスト名 hostname にアドレス addr を割り当てるエントリをホスト名テーブ ルに追加する。 (9) DHCP によるアドレス設定 #include "network_sample/dhclient.h" int dhclient(const char* ifname); パラメータ const char* ifname インタフェース名 解説 ifname で指定されたインタフェースに対して、DHCP を用いて以下の設定を行 う。 - ネットワークインタフェースのアドレス設定 - デフォルトゲートウェイの設定 - DNS関連の設定 5.12 実装上の制限事項 以下の制限事項がある。 - 元のソースコードではIPヘッダのIDフィールドにランダムな値を設定する機能 があるが、本実装ではメモリ使用量を削減するためにこの機能を提供しない。 ------------------------------------------------------------------------------ 6. カレンダ機能 ------------------------------------------------------------------------------ 以下の制限事項がある。 - time_t 型の引数または戻り値を持つAPIコールにおいて、SYSTIM, SYSTIM_U で 表現できない範囲の時刻を指定した場合、エラーとなる。 具体的には、1985年1月1日00:00:00以前の時刻を指定した場合、エラーとなる。 - dt_strptime() において %U, %W を指定した場合、文字列中の値は無視され tm に格納されない。 ------------------------------------------------------------------------------ 7. プログラムロード機能 ------------------------------------------------------------------------------ 7.1 プログラムモジュールの作成 本実装ではプログラムモジュールのフォーマットとしてELFオブジェクトをサポートする。 プログラムモジュールは ${BD}/module/etc/makerules に含まれるビルドルールを 用いることで作成できる。以下のディレクトリにシステムプログラムモジュールおよび 一般プログラムモジュールのサンプルが含まれているので、これらを参考にすること。 ${BD}/module/test-sys システムプログラムモジュールのサンプル ${BD}/module/test-usr 一般プログラムモジュールのサンプル 7.2 制限事項 以下の制限事項がある。 - 一般プログラムモジュールの初期化処理および終了処理は、pm_load() の実行時に ロード先の空間指定によらず常にシステムレベルで実行される。 ------------------------------------------------------------------------------ 8. 標準C互換ライブラリ ------------------------------------------------------------------------------ 標準C互換ライブラリは ${BD}/lib/libtk の一部と、${BD}/lib/libc で実装されている。 本実装において、標準C互換ライブラリのデータ領域はユーザレベル(.data_usrおよび .bss_usr)に配置される。 ------------------------------------------------------------------------------ ------------------------------------------------------------------------------