Woher weiß Linux Kernel, wo er nach Treiberfirmware suchen soll?
-
09-09-2019 - |
Frage
Ich kompile einen benutzerdefinierten Kernel unter Ubuntu und stieß auf das Problem zu, dass mein Kernel nicht weiß, wo ich nach Firmware suchen soll. Unter Ubuntu 8.04 ist die Firmware an die Kernelversion gebunden wie Treibermodule. Zum Beispiel speichert Kernel 2.6.24-24-Generic seine Kernel-Module in:
/lib/modules/2.6.24-24-generic
und seine Firmware in:
/lib/firmware/2.6.24-24-generic
Wenn ich den Ubuntu-Kern der 2,6.24-24-generischen Ubuntu nach dem "zusammenstellen" zusammenstelle "Alternative Build-Methode: Der altmodische Debian-Weg"Ich erhalte das entsprechende Modulverzeichnis und alle meine Geräte funktionieren außer denen, die Firmware wie meine Intel Wireless Card (IPW2200 -Modul) benötigen.
Das Kernel -Protokoll zeigt beispielsweise, dass das Kernel -Subsystem, das das Laden der Firmware steuert, nicht in der Lage ist, die Firmware zu laden, wenn IPW2200 versucht, die Firmware zu laden.
ipw2200: Detected Intel PRO/Wireless 2200BG Network Connection
ipw2200: ipw2200-bss.fw request_firmware failed: Reason -2
errno-base.h definiert dies als:
#define ENOENT 2 /* No such file or directory */
(Die Funktion, die den Enoent zurückgibt, stellt einen Minus vor sich.)
Ich habe versucht, einen Symlink in /lib /firmware zu erstellen, in dem der Name meines Kernels auf das Gener-Verzeichnis 2.6.24-24 hinwies. Dies führte jedoch zu demselben Fehler. Diese Firmware ist nicht GPL, von Intel bereitgestellt und von Ubuntu gepackt. Ich glaube nicht, dass es eine tatsächliche Verbindung zu einer bestimmten Kernelversion hat. cmp
zeigt, dass die Versionen in den verschiedenen Verzeichnissen identisch sind.
Woher weiß der Kernel, wo er nach Firmware suchen soll?
Aktualisieren
ich fand diese Lösung Zu dem genauen Problem, das ich habe, funktioniert es jedoch nicht mehr, wie Ubuntu beseitigt hat /etc/hotplug.d
und speichert seine Firmware nicht mehr in /usr/lib/hotplug/firmware
.
Update2
Einige weitere Forschungen haben weitere Antworten ausgeführt. Bis zu Version 92 von udev
, das Programm firmware_helper
War die Art und Weise, wie Firmware geladen wurde. Beginnen mit udev
93 Dieses Programm wurde durch ein Skript namens Firmware ersetzt. Beide hardcode den Firmware -Pfad zu /lib/firmware
. Ubuntu scheint immer noch die zu verwenden /lib/udev/firmware_helper
binär.
Der Name der Firmware -Datei wird an übergeben firmware_helper
in der Umgebungsvariablen $FIRMWARE
das wird mit dem Weg verkettet /lib/firmware
und verwendet, um die Firmware zu laden.
Die tatsächliche Anfrage zum Laden der Firmware wird vom Treiber (in meinem Fall IPW2200) über den Systemanruf erfolgen:
request_firmware(..., "ipw2200-bss.fw", ...);
Jetzt irgendwo zwischen dem Fahrer anruft request_firmware
und firmware_helper
Mit Blick auf die $FIRMWARE
Umgebungsvariable, der Kernel -Paketname wird auf den Firmware -Namen vorbereitet.
Also, wer macht das?
Lösung
Aus der Sicht des Kernels siehe /usr/src/linux/documentation/firmware_class/readme:
kernel(driver): calls request_firmware(&fw_entry, $FIRMWARE, device) userspace: - /sys/class/firmware/xxx/{loading,data} appear. - hotplug gets called with a firmware identifier in $FIRMWARE and the usual hotplug environment. - hotplug: echo 1 > /sys/class/firmware/xxx/loading kernel: Discard any previous partial load. userspace: - hotplug: cat appropriate_firmware_image > \ /sys/class/firmware/xxx/data kernel: grows a buffer in PAGE_SIZE increments to hold the image as it comes in. userspace: - hotplug: echo 0 > /sys/class/firmware/xxx/loading kernel: request_firmware() returns and the driver has the firmware image in fw_entry->{data,size}. If something went wrong request_firmware() returns non-zero and fw_entry is set to NULL. kernel(driver): Driver code calls release_firmware(fw_entry) releasing the firmware image and any related resource.
Der Kernel lädt keine Firmware. Es informiert UserSpace einfach: "Ich möchte eine Firmware namens der Namen von xxx", und wartet darauf, dass Benutzerspace das Firmware -Image zurück zum Kernel leitet.
Jetzt auf Ubuntu 8.04,
$ grep firmware /etc/udev/rules.d/80-program.rules # Load firmware on demand SUBSYSTEM=="firmware", ACTION=="add", RUN+="firmware_helper"
Also, wie Sie entdeckt haben, udev
ist zum Ausführen konfiguriert firmware_helper
Wenn der Kernel nach Firmware fragt.
$ apt-get source udev Reading package lists... Done Building dependency tree Reading state information... Done Need to get 312kB of source archives. 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] Fetched 312kB in 1s (223kB/s) gpg: Signature made Tue 14 Apr 2009 05:31:34 PM EDT using DSA key ID 17063E6D gpg: Can't check signature: public key not found dpkg-source: extracting udev in udev-117 dpkg-source: unpacking udev_117.orig.tar.gz dpkg-source: applying ./udev_117-8ubuntu0.2.diff.gz $ cd udev-117/ $ cat debian/patches/80-extras-firmware.patch
Wenn Sie die Quelle lesen, werden Sie feststellen, dass Ubuntu a geschrieben hat firmware_helper
das ist hart codiert, um zuerst zu suchen /lib/modules/$(uname -r)/$FIRMWARE
, dann /lib/modules/$FIRMWARE
, und keine anderen Orte. Übersetzen in sh
, Es macht ungefähr das:
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
Das ist genau das Format, das der Kernel erwartet.
Um eine lange Geschichte kurz zu machen: Ubuntu's udev
Paket hat Anpassungen, die immer einsehen /lib/firmware/$(uname -r)
Erste. Diese Richtlinie wird im Userspace behandelt.
Andere Tipps
Wow, das sind sehr nützliche Informationen und es führte mich zu der Lösung für mein Problem, wenn ich ein benutzerdefiniertes USB -Kernelmodul für ein Gerät erstellte, das Firmware erfordert.
Grundsätzlich bringt jeder Ubuntu eine neue Wiederholung von Hal, Sysfs, Devfs, Udev usw. und so weiter ... und die Dinge ändern sich einfach. Tatsächlich habe ich gelesen, dass sie aufgehört haben, Hal zu verwenden.
Lassen Sie uns dies also erneut umkehren, damit es für die neuesten [Ubuntu] -Systeme relevant ist.
Auf Ubuntu Lucid (die neueste zum Zeitpunkt des Schreibens), /lib/udev/rules.d/50-firmware.rules
wird genutzt. Diese Datei ruft die Binärdatei auf /lib/udev/firmware
, wo Magie passiert.
Listing: /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}"
Die Magie sollte etwas in dieser Richtung sein (Quelle: Linux -Geräte -Treiber, 3. Aufl., Ch. 14: Das Linux -Gerätemodell):
- Echo 1 bis
loading
- Kopieren Sie die Firmware an
data
- beim Versagen echo -1 bis
loading
und den Firmware -Ladeprozess stoppen - echo 0 bis
loading
(Signal des Kernels) - Anschließend empfängt ein bestimmtes Kernel -Modul die Daten und drückt sie auf das Gerät
Wenn Sie sich die Quellseite von Lucid für Udev ansehen, in udev-151/extras/firmware/firmware.c
, Die Quelle für diese Firmware/Lib/Udev/Firmware Binary ist genau das, was los ist.
Auszug: Lucid Source, 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");
Darüber hinaus verwenden viele Geräte ein Intel -Hex -Format (Textish -Dateien, die Prüfsumme und andere Dinge enthalten) (Wiki Es habe keinen Ruf und keine Verknüpfungsfähigkeit). Das Kernel-Programm IHEX2FW (von Makefile in Kernel_Source/lib/firmware auf .hex-Dateien genannt) konvertiert diese HEX-Dateien in ein beliebig entworfenes binäres Format, mit dem der Linux-Kernel dann aufnimmt request_ihex_firmware
, weil sie dachten, dass das Lesen von Textdateien im Kernel albern war (es würde die Dinge verlangsamen).
Auf aktuellen Linux -Systemen wird dies über behandelt udev
und die firmware.agent
.
Linux 3.5.7 Gentoo, ich habe das gleiche Problem. Gelöst:
emerge ipw2200-firmware
Gehen Sie dann zu/usr/src/Linux
make menucofig
Entfernen Sie auf dem Gerätetreiber alle nicht benötigten drahlosen Treiber, setzen Sie den Intelligenz in 2200 als Modul und kompilieren Sie sie neu.
make
make modules_install
cp arch/x86/boot/bzImage /boot/kernel-yourdefault