web-dev-qa-db-ja.com

Linux Kernelは、ドライバーファームウェアを探す場所をどのように知っていますか?

Ubuntuでカスタムカーネルをコンパイルしているときに、ファームウェアがどこにあるのかわからないという問題に直面しています。 Ubuntu 8.04では、ファームウェアはドライバーモジュールと同じようにカーネルバージョンに関連付けられています。たとえば、カーネル2.6.24-24-genericは、カーネルモジュールを次の場所に保存します。

_/lib/modules/2.6.24-24-generic
_

およびそのファームウェア:

_/lib/firmware/2.6.24-24-generic
_

2.6.24-24-generic Ubuntuカーネルを「 Alternate Build Method:The Old-Fashioned Debian Way 」に従ってコンパイルすると、適切なモジュールディレクトリが取得され、ファームウェアを必要とするデバイスを除くすべてのデバイスが動作しますIntelワイヤレスカード(ipw2200モジュール)として。

カーネルログは、たとえば、ipw2200がファームウェアをロードしようとすると、ファームウェアのロードを制御するカーネルサブシステムがそれを見つけることができないことを示します。

_ipw2200: Detected Intel PRO/Wireless 2200BG Network Connection
ipw2200: ipw2200-bss.fw request_firmware failed: Reason -2
_

errno-base.hはこれを次のように定義します。

_#define ENOENT       2  /* No such file or directory */
_

(ENOENTを返す関数は、その前にマイナスを置きます。)

/ lib/firmwareに、カーネルの名前が2.6.24-24-genericディレクトリを指すシンボリックリンクを作成しようとしましたが、同じエラーが発生しました。このファームウェアは、Intelから提供され、Ubuntuでパッケージ化された非GPLです。特定のカーネルバージョンと実際に関係があるとは思わない。 cmpは、さまざまなディレクトリのバージョンが同一であることを示しています。

それでは、カーネルはファームウェアを探す場所をどのようにして知るのでしょうか?

更新

この解決策 私が抱えている正確な問題を見つけましたが、Ubuntuが_/etc/hotplug.d_を排除し、ファームウェアを_/usr/lib/hotplug/firmware_に保存しなくなったため、機能しなくなりました。

Update2

さらなる研究により、さらにいくつかの答えが見つかりました。 udevのバージョン92までは、プログラム _firmware_helper_ がファームウェアのロード方法でした。 udev 93以降、このプログラムはfirmware.shという名前のスクリプトに置き換えられ、私が知る限り同一の機能を提供します。これらは両方とも、ファームウェアパスを_/lib/firmware_にハードコードします。 Ubuntuはまだ_/lib/udev/firmware_helper_バイナリを使用しているようです。

ファームウェアファイルの名前は、環境変数_firmware_helper_の_$FIRMWARE_に渡され、パス_/lib/firmware_に連結され、ファームウェアのロードに使用されます。

ファームウェアをロードする実際の要求は、システムコールを介してドライバー(私の場合はipw2200)によって行われます。

_request_firmware(..., "ipw2200-bss.fw", ...);
_

これで、ドライバーが_request_firmware_と_firmware_helper_を呼び出している間で、_$FIRMWARE_環境変数を見て、ファームウェア名の前にカーネルパッケージ名が追加されます。

だから誰がそれをやっているの?

50

カーネルの観点からは、 / usr/src/linux/Documentation/firmware_class/README を参照してください。

 kernel(driver):request_firmware(&fw_entry、$ FIRMWARE、device)
 
 userspace:
-/ sys/class/firmware/xxx/{loading、 
-ホットプラグは、$ FIRMWARE 
のファームウェア識別子と通常のホットプラグ環境で呼び出されます。
-hotplug:echo 1>/sys/class/firmware/xxx /loading

 kernel:以前の部分ロードを破棄します。
 
 userspace:
-hotplug:cat適切な_firmware_image>\
/sys/class/firmware/xxx/data 
 
カーネル:PAGE_SIZE単位でバッファーを増やして、イメージを保持するために
が入ってくると、
 
ユーザースペース:
-hotplug:echo 0> /sys/class/firmware/xxx/loading

 kernel:request_firmware()が戻り、ドライバーにファームウェアがあります
 fw_entry-> {data、size}の画像。何かがうまくいかなかった場合
 request_firmware()はゼロ以外を返し、fw_entryは
 NULLに設定されます。
 
 kernel(driver):ドライバーコードはrelease_firmware(fw_entry)を呼び出しますファームウェアイメージと関連するリソースを解放
します。

カーネルは実際にはファームウェアをまったくロードしません。 「xxxという名前のファームウェアが欲しい」というユーザースペースに通知し、ユーザースペースがファームウェアイメージをカーネルにパイプするのを待ちます。

さて、Ubuntu 8.04では、

 $ grep firmware /etc/udev/rules.d/80-program.rules
#オンデマンドでファームウェアをロード
 SUBSYSTEM == "firmware"、ACTION == "add" 、RUN + = "firmware_helper" 

あなたが発見したように、udevはカーネルがファームウェアを要求するときに_firmware_helper_を実行するように設定されています。

 $ apt-get source udev 
パッケージリストを読み込んでいます...完了
依存関係ツリーを構築しています
状態情報を読み込んでいます...完了
必要312kBのソースアーカイブを取得します。
 Get:1 http://us.archive.ubuntu.com hardy-security/main udev 117-8ubuntu0.2(dsc)[716B] 
 Get:2 http://us.archive.ubuntu.com hardy-security/main udev 117-8ubuntu0.2(tar)[245kB] 
 Get:3 http://us.archive.ubuntu.com hardy-security/main udev 117-8ubuntu0.2(diff)[65.7kB] 
 312kBを1秒でフェッチ(223kB/s)
 gpg:署名の作成2009年4月14日火曜日05:31:34 PM DSAキーID 17063E6D 
 gpgを使用したEDT:署名を確認できません:公開キーが見つかりません
 dpkg-source:udev-117 
でudevを抽出しています) dpkg-source:udev_117.orig.tar.gz 
 dpkg-source:./udev_117-8ubuntu0.2.diff.gz
$ cd udev-117 /
$の適用cat debian/patches/80-extras-firmware.patch 

ソースを読むと、Ubuntuが最初に/lib/modules/$(uname -r)/$FIRMWAREを探し、次に_firmware_helper_を探すようにハードコードされた_/lib/modules/$FIRMWARE_を書いたことがわかります。他の場所はありません。それをshに変換すると、およそ次のようになります。

_echo -n 1 > /sys/$DEVPATH/loading
cat /lib/firmware/$(uname -r)/$FIRMWARE > /sys/$DEVPATH/data \
    || cat /lib/firmware/$FIRMWARE      > /sys/$DEVPATH/data
if [ $? = 0 ]; then
    echo -n  1 > /sys/$DEVPATH/loading
    echo -n -1 > /sys/$DEVPATH/loading
fi
_

これは、カーネルが予期する形式です。


簡単に言うと、Ubuntuのudevパッケージには、最初に/lib/firmware/$(uname -r)で常に見えるカスタマイズがあります。このポリシーはユーザースペースで処理されています。

41
ephemient

うわー、これは非常に有用な情報であり、ファームウェアを必要とするデバイス用のカスタムUSBカーネルモジュールを作成する際の問題の解決につながりました。

基本的に、すべてのUbuntuはhal、sysfs、devfs、udevなどの新しいリハッシュをもたらします...そして状況は変わります。実際、私は彼らがhalの使用をやめたと読みました。

それで、これを再びリバースエンジニアリングして、最新の[Ubuntu]システムに関連するようにします。

Ubuntu Lucid(執筆時点で最新のもの)では、/lib/udev/rules.d/50-firmware.rules 使用されている。このファイルは、バイナリ/lib/udev/firmware、ここで魔法が発生します。

リスト:/lib/udev/rules.d/50-firmware.rules

# firmware-class requests, copies files into the kernel
SUBSYSTEM=="firmware", ACTION=="add", RUN+="firmware --firmware=$env{FIRMWARE} --devpath=$env{DEVPATH}"

魔法はこれらの線に沿ったものでなければなりません(ソース: Linux Device Drivers、3rd Ed。、Ch。14:The Linux Device Model ):

  • エコー1からloading
  • ファームウェアをdataにコピー
  • 失敗時には、-1からloadingにエコーし、ファームウェアのロードプロセスを停止します
  • echo 0 to loading(カーネルに信号を送る)
  • 次に、特定のカーネルモジュールがデータを受信し、デバイスにプッシュします

udevのLucidのソースページを見ると、udev-151/extras/firmware/firmware.c、そのファームウェア/ lib/udev/firmwareバイナリのソース、それがまさに続くことです。

抜粋:Lucidソース、udev-151/extras/firmware/firmware.c

    util_strscpyl(datapath, sizeof(datapath), udev_get_sys_path(udev), devpath, "/data", NULL);
    if (!copy_firmware(udev, fwpath, datapath, statbuf.st_size)) {
            err(udev, "error sending firmware '%s' to device\n", firmware);
            set_loading(udev, loadpath, "-1");
            rc = 4;
            goto exit;
    };

    set_loading(udev, loadpath, "0");

さらに、多くのデバイスはIntel HEX形式(チェックサムやその他のものを含むテキストファイル)を使用しています(wikiには評判もリンクもありません)。カーネルプログラムihex2fw(.HEXファイルのkernel_source/lib/firmwareのMakefileから呼び出されます)は、これらのHEXファイルを任意の設計のバイナリ形式に変換し、Linuxカーネルがrequest_ihex_firmware、彼らはカーネルでテキストファイルを読むことはばかげていると思ったので(それは物事を遅くするだろう)。

12
Andy Matteson

Linux 3.5.7 Gentoo、私は同じ問題を抱えています。解決済み:

emerge ipw2200-firmware

次に/ usr/src/linuxに移動します

make menucofig

デバイスドライバーで、不要なすべてのワイヤレスドライバーを削除し、Intell 2200をモジュールとして設定して再コンパイルします。

make
make modules_install
cp Arch/x86/boot/bzImage /boot/kernel-yourdefault
1
MaxV

現在のLinuxシステムでは、これはudevおよびfirmware.agent

1
David Schmitt