telnetd と ftpd のユーザ認証Telnet サーバと udevice.exe(2/2)

Telnet サーバと udevice.exe(1/2)

2012/08/27 koga

このタイトルをご覧になって、「おや?」と首をかしげた方が、いらっしゃるかも知れません。
「サービスの DLL をロードするホストプロセスは、servicesd.exe であって、udevice.exe じゃないはずだけれど。」そう思った方は、%_WINCEROOT%/public/COMMON/oak/files/common.bib をご覧になってみて下さい。何の事だか分からない、というあなたは、WEC/WinCE の User Mode Driver フレームワークについての今回と次回のエントリを、もしかしたら興味深く感じるかも知れません。

それから、「telnetd なら、普通は inetd とか xinted じゃないの?」と思った UNIX なあなたは、いわゆるネットワークデーモンの、WEC/WinCE での実現方式について、今回のエントリが参考になるかも知れません。

■スーパーサーバと servicesd.exe
Linux など UNIX 系の OS では、Telnet サーバ(telneted)などのサーバプログラムは、inetd や xinetd などのスーパーサーバによって起動されるのが一般的です。これに対し、WEC/WinCE では、servicesd.exe というプロセスが、その役割を果たします。servicesd.exe については、WEC/WinCE の次のリファレンスページで説明されています:

 Servicesd.exe (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee499183

 Services.exe Application Development (Windows Embedded CE 6.0)
 http://msdn.microsoft.com/en-US/library/ee500585(v=winembedded.60)

上の WinCE 6.0 のリファレンスページでは、servicesd.exe ではなく services.exe という名前になっていますが、これは、WinCE 6.0 R2 より前の版でのものです。WEC 7 の方のリファレンスページに書かれているように、WinCE 6.0 R2 からは、services.exe ではなく、servicesd.exe となっています。

servicesd.exe(および、R2 以前の WinCE 6.0 での services.exe)は、レジストリの [HKEY_LOCAL_MACHINE\Services] キー配下のキーで指定されたサーバ群を、[HKEY_LOCAL_MACHINE\Services\<サーバ名>\Accept\<ポート番号>] というキーで指定されたポート番号に対して、クライアンからの接続が起きた際に起動します。

servicesd.exe に対する、ポート番号とサーバ(service DLL)との関連付けについては、リファレンスの次のページで説明されています:

 Registering a Super Service Automatically (Windows Embedded CE 6.0)
 http://msdn.microsoft.com/en-US/library/ee498484(v=winembedded.60)

実際のレジストリ設定の内容は、
 %_WINCEROOT%/public/servers/oak/files/servers.reg
をご覧下さい。telnetd の他、httpd に対する設定も記載されています。

ところで、UNIX 系 OS の inetd や xinetd とは異なり、WEC/WinCE の servicesd.exe では、各サーバを独立したプロセスとして起動するのではなく、サーバ機能を実装した DLL を呼び出します。WEC/WinCE では、UNIX 系 OS で言うデーモンプログラムは、個々に独立したプロセスによって実行されるアプリケーションではなく、DLL として実装されているのです。より正確には、各サーバは、ユーザモードのデバイスドライバとして実装されており、servicesd.exe が、各サーバの DLL をロードして、IOCTL コードを用いてそれらを制御します。

WEC/WinCE は、組み込み機器向けの OS ですから、より少ないメモリで動作するための方策として、各サーバを個別のプロセスとして動かすのではなく、一つのプロセス(servicesd.exe)にロードされる DLL として実装して動かすようになっているのだと思います(注1)。そのための仕組みとして、ユーザモードのデバイスドライバの枠組みを利用している、というわけです。

注1:次回で述べますが、servicesd.exe は、実は複数起動することができ、サーバごとにプロセスを割り当てて動かすことも可能です。

■ユーザモードのデバイスドライバ
ここで、ユーザモードのデバイスドライバとは、カーネルではなく、ユーザプロセスにロードされて、ユーザ空間で動作するデバイスドライバのことです。WinCE 6.0 以降では、デバイスドライバは、カーネルにロードされてカーネル空間で動作するのが基本となっています。これは、伝統的な UNIX 系 OS と同じです。一方、純粋なマイクロカーネル構造だった WinCE 5.0 までは、独立したプロセスとして動作するデバイスマネージャが、デバイスドライバをロードして動かす仕組みになっていました。WinCE 5.0 から WinCE 6.0 への移行において、カーネルの仮想記憶機構に大幅な変更が加えられ、純粋なマイクロカーネル構造から、UNIX 系 OS に近い構造に変わった際に、デバイスマネージャにも変更が加えられました。つまり、独立して動作するプロセス(device.exe)から、カーネルにロードされる DLL(device.dll)となったのです。

WinCE 5.0 から WinCE 6.0 への移行の際の変更については、以前のエントリ(「レジストリ変更内容の永続化(2/2)」の末尾にある「おまけ」の項)でも紹介しました。

さて、Linx や Mac OS X など、UNIX 系 OS でも、ユーザモードのデバイスドライバに対する取り組みは、あります。プリンタドライバや、SVGAlib、および USB のクラスドライバなどが、典型的な例でしょう。

 Wikipedia 英語版の “Device driver” にある “Kernel-mode vs user-mode” の説明
 http://en.wikipedia.org/wiki/Device_driver#Kernel-mode_vs_user-mode

 Mac OS X の “User-Mode USB Device Arbitration”
 https://developer.apple.com/library/mac/#documentation/DeviceDrivers/Conceptual/ClassicUSBDeviceArb.html

ユーザモードのデバイスドライバの利点は、上の Wikipedia のページにも書かれているように、ドライバのバグによってカーネル全体が障害を起こすことを防ぎ、その結果システム全体の安定性を確保しやすくなる、ということだと思います。これは、Linux などの「モノリシックカーネル」に対して、純粋なマイクロカーネル構造の OS の利点としても、よく言われることです。純粋なマイクロカーネル構造の OS として、(WinCE 5.0 以外で)今でも現役で使われている QNX が、その一例です。

また、GUI の表示など、カーネルモードでは呼び出すことのできない API をデバイスドライバから利用したい場合に、デバイスドライバをカーネルモード部分とユーザモード部分に分割して実装し、ユーザモードのデバイスドライバで API を呼び出すようにする、といった方策での利用もあります。そのような場合には、カーネルモードのデバイスドライバとユーザモードのデバイスドライバが連携するための仕組みが必要です。WEC/WinCE では、そのための仕組みとして User Mode Driver フレームワークが提供されています。

■User Mode Driver フレームワーク
User Mode Driver フレームワークは、リファレンスの次のページで説明されています:

 User Mode Driver Framework (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee482294

 User Mode Driver Framework (Windows Embedded CE 6.0)
 http://msdn.microsoft.com/en-us/library/ee482294(v=WinEmbedded.60).aspx

大まかな構造は、WinCE 6.0 のリファレンスにある、アーキテクチャ図を見ると分かりやすいでしょう:

 User Mode Driver Framework Architecture (Windows Embedded CE 6.0)
 http://msdn.microsoft.com/en-US/library/ee486510(v=winembedded.60)

ユーザモードのデバイスドライバをロードするホストプロセス(User Mode Driver Host)が、カーネル内部のデバイスマネージャとの間の橋渡しを行う User Mode Driver Reflector とやり取りする様子が、上のページの図に描かれています。

User Mode Driver Reflector は、起動済みの User Mode Driver Host にドライバをロードさせたり、あるいは、新たに User Mode Driver Host を起動して、ドライバをロードさせます。ユーザモードのデバイスドライバは、User Mode Driver Host にロードされた後、DeviceIoConrol() や User Mode Driver フレームワークの関数を使って、カーネルモードのデバイスドライバを呼び出して連携動作します。カーネルモードのデバイスドライバやアプリケーションからの、ユーザモードのデバイスドライバの呼び出しは、デバイスマネージャが User Mode Driver Reflector を使って User Mode Driver Host へ呼び出し内容を転送(forward)して、User Mode Driver Host がドライバを呼び出すことによって処理されます。

UNIX 系 OS と同様、WinCE 6.0 以降では、ユーザモードのデバイスドライバは、物理メモリや周辺機器制御のレジスタなどをアクセスすることは、できません(この点が、WinCE 5.0 からの移行の際に大きく変わったことの一つです)。従って、ハードウェアを制御するためには、カーネルモードのデバイスドライバと連携する必要があります。

WEC 7/WinCE 6.0 に付属しているユーザモードのデバイスドライバとしては、ソフトウェア入力パネル(Software Input Panel; SIP)が、その一例です。また、GPS 中間ドライバ(GPS Indermediate Driver; GPSID)も、ユーザモードのデバイスドライバです。

なお、上で挙げた、User Mode Driver フレームワークの WEC 7 のリファレンスのトップページ、および、WinCE 6.0 のリファレンスの次のページにある、ユーザモードのデバイスドライバのサンプルの紹介は、間違いだと思います:

 User Mode Driver Framework Samples (Windows Embedded CE 6.0)
 http://msdn.microsoft.com/en-US/library/ee484423(v=winembedded.60)

これらのページには、
 %_WINCEROOT%\public\COMMON\oak\drivers\sdcard\SDClientDrivers\GPS
に、ユーザモードのデバイスドライバのサンプルがあると書かれてします。しかし、このディレクトリにソースコードが収録されているのは、実際にはカーネルモードのドライバである、SDIO の GPS モジュールのドライバ(GPSSDIO.dll)です。

上述した二つのユーザモードのデバイスドライバ(SIP と GPSID)の他に、何があるかは、
 %_WINCEROOT%/public/COMMON/oak/files/common.reg
で Flags キーの値に 0×10 ビット(DEVFLAGS_LOAD_AS_USERPROC)が設定されているドライバを見てみると分かります。また、WEC 7/WinCE 6.0 をカーネルデバッガ経由で動かして、プロセス一覧を表示し、udevice.exe にロードされている DLL の一覧を見るのもよいでしょう。

■servicesd.exe と udevice.exe
上で突然、udevice.exe のことを書きましたが、実は、udevice.exe が User Mode Driver Host なのです。そして、udevice.exe と、WEC/WinCE におけるスーパーサーバである servicesd.exe とは、深い関係があります。冒頭で、次のように書いたことを思い出して下さい:

このタイトルをご覧になって、「おや?」と首をかしげた方が、いらっしゃるかも知れません。
「サービスの DLL をロードするホストプロセスは、servicesd.exe であって、udevice.exe じゃないはずだけれど。」そう思った方は、%_WINCEROOT%/public/COMMON/oak/files/common.bib をご覧になってみて下さい。

common.bib を見ると、次の行があるはずです:

; @CESYSGEN IF CE_MODULES_DEVICE
   device.dll      $(_FLATRELEASEDIR)\device.dll               NK  SHMK
   udevice.exe     $(_FLATRELEASEDIR)\udevice.exe              NK  SHM      ★
   devmgr.dll      $(_FLATRELEASEDIR)\devmgr.dll               NK  SHMK
   regenum.dll     $(_FLATRELEASEDIR)\regenum.dll              NK  SHK
   busenum.dll     $(_FLATRELEASEDIR)\busenum.dll              NK  SHK
; @CESYSGEN IF DEVICE_PMIF
   pm.dll       $(_FLATRELEASEDIR)\pm.dll                      NK  SHMK
; @CESYSGEN ENDIF
; @CESYSGEN IF CE_MODULES_SERVICES
   servicesEnum.dll   $(_FLATRELEASEDIR)\servicesEnum.dll     NK  SHK
; Note - servicesd.exe is just renamed udevice.exe.  Services specific functionality via servicesFilter.dll
   servicesd.exe      $(_FLATRELEASEDIR)\udevice.exe          NK  SH        ★★
   servicesFilter.dll $(_FLATRELEASEDIR)\servicesFilter.dll   NK  SH
   services.exe       $(_FLATRELEASEDIR)\services.exe         NK  S
   servicesStart.exe  $(_FLATRELEASEDIR)\servicesstart.exe    NK  SH
; @CESYSGEN ENDIF


上で★★を付けた行を見ると、udevice.exe を servicesd.exe という名前で OS イメージへ格納する設定になっていることが分かります。★の行は、udevice.exe を OS イメージへ格納する設定の行です。つまり、udevice.exe と servicesd.exe の実体は、同じものなのです。

udevice.exe(そして、servicesd.exe も)のソースコードは、
 %_WINCEROOT%/private/winceos/COREOS/device/udevice/
に収録されています。カーネルデバッガを使ってソースコードを追ってみると、servicesd.exe として動作する場合、つまり、telned などのサーバ機能を実装した DLL のホストプロセスとして動作する場合には、スーパーサーバとして必要な動作を行うことが分かります。つまり、WSAStartup() を呼び出して winsock を初期化し、その後、DLL に対するレジストリで設定されたポートで接続待ちするスレッドを起動します。

udevice.exe と servicesd.exe は、実装上共通する部分が多いため、単一のプログラムとして実装し、OS イメージには異なる名前で配置する、という選択がなされたのでしょう。両者が同じ実体であるということは、リファレンスには明記されていませんから、もしかすると、将来は、異なるプログラムとして実装し直される可能性もあります。なお、servicesd.exe のスーパーサーバとしての機能は、
 %_WINCEROOT%/private/winceos/COREOS/device/udevice/
ではなく、
 %_WINCEROOT%/private/winceos/COREOS/device/services/filter/
に収録されたソースコードで実装されています。これは、udevice.exe(つまり、servicesd.exe)がリンクしている servicesFilter.dll という DLL のソースコードです。

Entry Filed under: OS の内部動作

Leave a Comment

Required

Required, hidden

Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Trackback this post  |  Subscribe to the comments via RSS Feed


Categories

Links

Posts by Authors

Recent Posts

Calendar

2012年8月
« 7月   12月 »
 1234
567891011
12131415161718
19202122232425
262728293031  

Posts by Month

Posts by Category

Meta