現在の組み込みシステムは、たくさんのデバイスから構成されています。組み込みシステムに高い付加価値が求められる時流に伴い、ひとつの組み込みシステムには入出力デバイスはもとより、ネットワークデバイス、ストレージデバイス、セキュリティ管理デバイス、ユーザーから直接操作されることのない電源管理デバイスなど、様々な種類のデバイスが統合されています。これらのハードウェアを適切に運用するには、デバイスを製造したベンダーが定めた制御シーケンスに従い、ソフトウェアからデバイスを操作する必要があります。ここで活躍するソフトウェアモジュールが、デバイスドライバです。デバイスドライバは、デバイスベンダーが変わるたびにアプリケーションを再実装せずに済むよう、各デバイスの違いを吸収し、アプリケーションから使いやすいように機能を抽象化するソフトウェアです(図1)。
今回の初心者講座では、組み込みLinuxに同梱されているデバイスドライバの仕組みや特長について解説するとともに、デバイスドライバと密接な関係にあるカーネルモジュールについても解説。記事の後半では、Raspberry Pi 4実機上で利用できるカーネルモジュールの開発手順を紹介します。
8本すべて無料!組み込みLinuxウェビナー
組み込みLinuxの基礎知識から、Docker/コンテナ技術の開発方法、さらには起動シーケンスを理解し、実際のLinuxアプリ開発も学べる。開発デモはRaspberry Pi 4を使用しているので、受講後すぐにお試しいただくことで可能です。
視聴申込はこちらから
デバイスドライバとは
デバイスドライバは、制御対象のデバイスを適切にコントロールし、ハードウェアが提供する機能を運用。アプリケーションをはじめとする他のプログラムに対して、機能を実現するために不可欠なAPI内の実装を提供するソフトウェアです。
一例として、組み込みLinuxにおけるネットワークデバイスのデバイスドライバの役割を図2で紹介いたします。まず、アプリケーション視点でシステムを見ますと、ネットワークを使うアプリケーションは、OSのAPI(Application Program Interface)を利用してネットワークの確立、データの送受信、ネットワークの終了といった機能をLinuxカーネルへ依頼します(図中上段のControl)。逆に、デバイス視点でシステムをみてみますと、ベンダーの違いやモデルの違いにより、ソフトウェアからデバイスを制御する方法がそれぞれ異なります。パケットを送信するために、処理A、処理B、処理Cと3ステップを踏むネットワークデバイスもあれば、処理A以降は全自動で稼働し、パケットを送信するために処理Aのみ1ステップで完了するネットワークデバイスもあるでしょう(図中下段のControl Model X用、Control Model Y用)。ただし、いずれの場合もアプリケーションが真に期待するのは、データの送受信機能です(図中DATA)。
そこで、組み込みLinuxでは、アプリケーションとカーネル間のインタフェースの取り決めとしてAPIを定義し、API内で実行しなければならないデバイスごとの制御方式を定義するプログラムをデバイスドライバとして同梱します(図中、デバイスドライバ for X、デバイスドライバ for Y)。デバイスドライバの層を設けることにより、同じ実装のアプリケーションを、様々なネットワークデバイス上で運用することができます。
組み込みLinux入門に最適な1冊
「市場投入までの期間の短縮」「サポートとメンテナンスコストの削減」「コンプライアンス問題への対応」「クラウドネイティブアーキテクチャとコンテナ技術」など、気になるTopicsを網羅したeBookが無料でダウンロードできます。是非ご覧ください。 無料のeBookをダウンロード
Linuxデバイスドライバの仕組みと動き
それでは、組み込みLinuxに内蔵するデバイスドライバには、どのような機能が必要となるでしょうか。ネットワークデバイスを例とした場合における、デバイスドライバが提供する機能を図3に示します。
まず、デバイスドライバには対応デバイス検出機能が必要となります。デバイスドライバが制御できるハードウェアを検索し、デバイスドライバの制御下におく機能です。Linuxカーネルは新しいデバイスを発見する度に、全デバイスドライバの対応デバイス検出機能を使って、ハードウェアを制御してくれるデバイスドライバを検索します(図3-①)。
Linuxカーネルはデバイスに対応するデバイスドライバの発見に成功すると、デバイスドライバにハードウェアの初期化を依頼します。*_probe
という名前で実装される本機能は、アプリケーションが機能を利用する前に準備すべきバッファやリソースの確保、ハードウェアの初期化などを担当します(図3-②)。初期化完了後はデバイスが使える状態となりますので、APIとデバイスドライバの関数を結びつける*_register
処理を実行します(図3-③)。ネットワークデバイスの場合、データの送受信といった通信に使うインタフェースと、ネットワークデバイス状態を確認・変更するためのethtoolインタフェースを登録します。
*_register
処理が完了すると、Linuxの場合/dev
フォルダ内のファイルとしてデバイスが表示されます。これにより、アプリケーションはAPIを介して対象のデバイスを操作できるようになります。アプリケーションがAPIへアクセスすると、APIに対応したデバイス制御機能が呼び出され(図3-④)、デバイスドライバにより実際のハードウェアが操作され(図3-⑤)、通信処理が動作します(図3-⑥)。
Raspberry Pi 4のネットワークインタフェースに対応するデバイスドライバの概要
Raspberyr Pi 4のネットワークインターフェースはBroadcom社製のデバイスドライバ「genet」により制御されています。本節ではデバイスドライバの具体的なイメージを持っていただくために、実際に動作しているソースコードと図3の各処理の対応について解説いたします。
図3-①の対応デバイス検出機能はbcmgenet_matchで定義されており、bcmgenet_matchにヒットしたデバイスに対して図3-②初期化処理としてbcmgenet_probeが実行されます。図3-③の登録処理では、通信用にbcmgenet_netdev_opsを、ethtool用にbcmgenet_ethtool_opsの関数群が登録されます。以降は、アプリケーションからの操作(図3-④)に従いbcmgenet_netdev_ops内に定義された関数またはbcmgenet_ethtool_ops内に定義された関数が図3-⑤として開始され、ハードウェアが制御され通信が確立します(図3-⑥)
カーネルモジュールとは
続いては、組み込みLinuxのデバイスドライバと対で覚えておきたい機能「カーネルモジュール」を解説いたします。
カーネルモジュールは、Linuxカーネルの機能をファイルに分割し、システム動作中にLinuxカーネルに求められる機能を、動的に挿入、抜去できるようにする機能です。組み込みLinuxでは多くのデバイスドライバがカーネルモジュールの形で提供されています。機能をLinuxカーネルに直接同梱せず、ファイル化することにより、電源を投入したままの状態でデバイスドライバをアップデートできる他、Linuxカーネルをコンパクトにし起動時間やリソースの消費量を最適化することができます。
カーネルモジュールとなったLinuxカーネルの機能は、Linuxカーネル内には含まれず、ファイルシステムに含まれます。一般的には*.ko または *.ko.*という拡張子のファイルとなります。カーネルモジュールにLinuxカーネルへ挿入する「insmod」コマンドにファイルを指定して実行することにより、ファイルに内蔵された機能をLinuxカーネルへ追加することができます(図4-①、図4-②)。追加後、カーネルモジュールにデバイスドライバを内蔵していれば、ハードウェアの制御が開始され(図4-③)、アプリケーションから対象デバイスを利用できるようになります(図4-④)。
なお、機能をLinuxカーネルに同梱するか、カーネルモジュールとしてファイルシステム上に格納するかの選択は、Linuxカーネルのビルド時に指定可能です(図5)。
Kernel Configuration with menuconfig
カーネルモジュールの操作方法
カーネルモジュールの操作方法を図6にて解説いたします。カーネルモジュールの操作に使うコマンドは主に3つ「insmod または modprobe」「lsmod」「rmmod」です。
insmod/modprobe
insmodコマンドは、指定したカーネルモジュールファイル(*.ko)をシステムに挿入するコマンドです(図6-①)。実行するとカーネルモジュールがカーネルへロードされ、ソースコード中のmodule_initにて指定された関数が実行されます(図6-②)。
modprobeコマンドも指定したカーネルモジュールファイルをシステムに挿入するコマンドですが、insmodの替りにmodprobeを使うことにより指定したカーネルモジュールが依存している他のカーネルモジュールも自動的に挿入することができます。insmodは指定したカーネルモジュールのみを対象に動作するため、依存関係のあるカーネルモジュールがロードされていない場合、個々に挿入する必要があります。
lsmod
lsmodコマンドは、動作中のシステムにロードされているカーネルモジュールの一覧を表示する機能です(図6-③)。
rmmod
rmmodコマンドは、ロードされているカーネルモジュールを抜去するコマンドです。実行するとソースコード中のmodule_exitにて指定された関数が実行され(図6-④)、完了後にカーネルモジュールの機能がカーネルからアンロードされます(図6-⑤)。
はじめてのデバイスドライバ開発|最小構成のカーネルモジュールをビルドする
それでは、上記にて紹介したカーネルモジュールを、ゼロから開発する手順を紹介します。今回開発するカーネルモジュールは、挿入時、抜去時に文字列を出力するシンプルなプログラムです。文字列を出力している処理を、実際のハードウェア操作に替えることによりデバイスドライバを実現することができます。
Adding Kernel Development Support to the SDK
Wind River LinuxでLinuxディストリビューションとSDKをビルドする
まず、カーネルモジュールを実行するベースとなるLinuxディストリビューションと、そのLinuxディストリビューション用のプログラムを開発できるSDKを生成します。「conf/local.conf
」に「TOOLCHAIN_TARGET_TASK_append
」と「TOOLCHAIN_HOST_TASK_append
」を指定することによりLinuxカーネルの開発が可能となります。
Wind River Linuxの提供するSDKとは
# Wind Rivr Linux開発環境を入手する $ git clone --recursive https://github.com/WindRiver-Labs/wrlinux-x.git # Raspberry Pi 4用のBSPを取得する $ ./wrlinux-x/setup.sh --machines bcm-2xxx-rpi4 # プロジェクトを作成する $ . ./environment-setup-x86_64-wrlinuxsdk-linux $ . ./oe-init-build-env build # 生成するLinuxディストリビューションとSDKの構成を変更します $ vi conf/local.conf ## ネットワークからパッケージを自動的に収集する BB_NO_NETWORK = "0" ## カーネルモジュールをビルドできるSDKを生成する TOOLCHAIN_TARGET_TASK_append = " python-dev kernel-dev kernel-devsrc" TOOLCHAIN_HOST_TASK_append = " nativesdk-openssl-dev nativesdk-bison nativesdk-flex" # Wind River LinuxによるLinuディストリビューションとSDKのビルドを開始する $ bitbake wrlinux-image-glibc-std -c populate_sdk
カーネルモジュールのビルド準備をする
次に、カーネルモジュールを開発する準備として、SDKを開発用PCへインストールし、カーネルモジュールのビルドに必要となる各種ファイルを準備します。
# bitbake後、./tmp-glibcdeploy/sdkフォルダに含まれているSDKをシステムへインストールします $ sudo chmod 0777 /opt $ ./tmp-glibc/deploy/sdk/wrlinux-10.19.45.12-glibc-x86_64-bcm_2xxx_rpi4-wrlinux-image-glibc-std-sdk.sh ... # インストールされたフォルダへ移動します $ cd /opt/windriver/wrlinux/19.45/ # ビルド準備をするスクリプトを実行します $ . ./environment-setup-aarch64-wrs-linux # Linuxカーネルのソースコードが格納されているフォルダへ移動します $ cd sysroots/aarch64-wrs-linux/ # 確認用コマンド(作業ディレクトリはこちらになります) $ pwd /opt/windriver/wrlinux/19.45/sysroots/aarch64-wrs-linux $ cd ./usr/src/kernel # カーネルモジュールの開発準備を実行します $ make modules_prepare ... # exportコマンドを使ってカーネルモジュールのビルドに使うソースコードの先頭をSDKTARGETSYSROOT環境変数に登録します $ export SDKTARGETSYSROOT=/opt/windriver/wrlinux/19.45//sysroots/aarch64-wrs-linux
SDKを使って自作のカーネルモジュールをビルドする
それでは、自作のカーネルモジュールをウインドリバー社が配布しているソースコードを活用して開発してみましょう。まず任意のフォルダを作成し、hello.cとMakefileファイルを「Creating the Kernel Module Using the SDK」を参考に実装してください。
実装後、makeコマンドを実行すると、カーネルモジュール「hello.ko」が生成されます。
Raspberry Pi 4にLinuxカーネルをインストールする
Raspberry Pi 4起動用のmicro SDカードを準備する
Raspberry Pi 4用の起動用micro SDカードを準備します。Raspberry Pi 4向けmicro SDカードの初期化方法は「micro SDの初期化方法」をご参照ください。
Linuxディストリビューションをビルドし、micro SDカードへインストールする
コマンド「bitbake wrlinux-image-glibc-std」が完了すると、生成されたLinuxディストリビューションが「tmp-build/deoloy/image」フォルダへ格納されます。「micro SDへのイメージ書き込み」を参考に、LinuxディストリビューションをRaspberry Pi 4起動用micro SDカードへインストールしてください。
カーネルモジュールをmicro SDカードへ格納する
また、ビルドしたカーネルモジュールをmicro-SDカードに格納し、Raspberry Pi 4起動後にカーネルモジュールへアクセスできるようにします。
# micro-SDカードを開発用PCにマウントします $ sudo mount -t ext4 /dev/sdX2 /mnt # 生成したカーネルモジュールをmicro-SDカードの/rootにコピーします $ sudo cp hello.ko /mnt/root/hello.ko
実際にカーネルモジュールの追加と削除を試してみる
最後に、micro-SDカードを挿入したRaspberry Pi 4を起動すると、カーネルモジュールhello.koを/root
内にて確認することができます。カーネルモジュールに対してinsmod、lsmod、rmmodを実行するとカーネルモジュールの挿入・抜去の様子を見ることができます。なお、カーネルモジュールが出力したメッセージはdmesg
コマンドで確認することができます。
# /rootへ移動しカーネルモジュールを確認します $ cd /root $ ls hello.ko # カーネルモジュールを挿入します $ insmod hello.ko # ロード済みのカーネルモジュールの一覧を表示します $ lsmod ... hello ... # カーネルモジュールを抜去します $ rmmod hello # ロード済みのカーネルモジュールの一覧を表示します $ lsmod (hello.koは表示されない) $ dmesg (挿入・抜去時のメッセージを確認できる)
組み込みLinux入門に最適な1冊
「市場投入までの期間の短縮」「サポートとメンテナンスコストの削減」「コンプライアンス問題への対応」「クラウドネイティブアーキテクチャとコンテナ技術」など、気になるTopicsを網羅したeBookが無料でダウンロードできます。是非ご覧ください。 無料のeBookをダウンロード
まとめ
今回の初心者講座では、Linuxカーネル内で特に重要なデバイスドライバとカーネルモジュールについて解説いたしました。組み込みLinuxの開発では、限られたリソースの中で多数のデバイスを制御する必要があるため、デバイスドライバとカーネルモジュールの知識は役立つでしょう。是非今回の内容をお役立てください。
Wind River Linux Community版(無償版)のRaspberry Pi 4対応状況について
Wind River Linux Community版(無償版)は、Raspberry Pi 4のモデルのうち、Raspberry Pi 4 Model B メモリ4GB品のみに対応しています(※1)。操作をお手元に試される場合には対応製品をご準備ください。
※1:Raspberry Pi 4 Model B リビジョン1.4以降の機材では firmware等の変更も必要となります。
Wind River Linuxについて
Wind River Linux®は、商用組み込みLinuxマーケットシェアNo.1!※の業界最先端の組み込みLinux開発プラットフォームです。最大15年の長期サポートや継続的デリバリーにも対応し、信頼性の高いエッジデバイスの開発を支援します。
※出典:VDC Reserch The Global Market IoT & Embedded Operating Systems (2018)
Wind River Linux 製品ウエブサイト Wind River Linux 製品カタログ Wind River Linux ダウンロード
Wind River Linux インタビュー記事
Wind River Linuxが誕生して15年となる。Wind River Linux誕生の背景やこれまでの取り組み、採用事例などについて話を聞いた。
Wind River Linux インタビュー記事
- Linuxは、Linus Torvaldsの米国およびその他の国における商標または登録商標です。
- Raspberry PiはRaspberry Pi財団の登録商標です。
- Wind RiverおよびVxWorksはWind River Systems, Inc.の登録商標です。
- その他記載の会社名、製品名は、それぞれの会社の商標または登録商標です。