Come fa Linux Kernel sa dove cercare firmware del driver?
-
09-09-2019 - |
Domanda
Sto compilando un kernel personalizzato sotto Ubuntu e sto correndo nel problema che il mio kernel sembra non sapere dove cercare per il firmware. In Ubuntu 8.04, il firmware è legata alla versione del kernel gli stessi moduli driver modo sono. Ad esempio, il kernel 2.6.24-24-generic negozi i suoi moduli del kernel in:
/lib/modules/2.6.24-24-generic
e il suo firmware:
/lib/firmware/2.6.24-24-generic
Quando compilo il kernel di Ubuntu 2.6.24-24-generic secondo la " Corporatura alternativo metodo: il Debian vecchia maniera " ho la directory dei moduli appropriata e tutti i miei dispositivi di lavoro ad eccezione di quelli che richiedono il firmware come la mia scheda wireless Intel (ipw2200 modulo)
.Il registro del kernel mostra per esempio che quando ipw2200 cerca di caricare il firmware del sottosistema kernel controlla il caricamento del firmware è in grado di individuarlo:
ipw2200: Detected Intel PRO/Wireless 2200BG Network Connection
ipw2200: ipw2200-bss.fw request_firmware failed: Reason -2
errno-base.h definisce come:
#define ENOENT 2 /* No such file or directory */
(La funzione che restituisce ENOENT mette un meno di fronte ad essa.)
Ho cercato di creare un link simbolico in / lib / firmware in cui il nome di mio kernel indicò la directory 2.6.24-24-generic, tuttavia questo ha provocato lo stesso errore. Questo firmware è non-GPL, fornito da Intel e imballato da Ubuntu. Non credo che abbia qualche legame effettivo ad una particolare versione del kernel. cmp
dimostra che le versioni nelle varie directory sono identici.
Quindi, come fa il kernel sa dove cercare il firmware?
Aggiorna
questa soluzione per l'esatto problema che sto avendo, tuttavia, non funziona più come Ubuntu ha eliminato /etc/hotplug.d
e non più memorizza il firmware in /usr/lib/hotplug/firmware
.
Update2
Alcuni ulteriori ricerche alzato alcuni più risposte. Fino fino alla versione 92 del udev
, il programma firmware_helper
è stato il modo in cui ha ottenuto il firmware caricato. A partire da 93 udev
questo programma è stato sostituito con uno script chiamato firmware.sh fornendo funzionalità identiche per quanto posso dire. Entrambi questi hardcode percorso firmware per /lib/firmware
. Ubuntu sembra essere ancora utilizzando il binario /lib/udev/firmware_helper
.
Il nome del file del firmware viene passato al firmware_helper
nel $FIRMWARE
variabile d'ambiente che viene concatenato alla /lib/firmware
percorso e utilizzato per caricare il firmware.
La richiesta effettiva per caricare il firmware è fatta dal conducente (ipw2200 nel mio caso) tramite la chiamata di sistema:
request_firmware(..., "ipw2200-bss.fw", ...);
Ora da qualche parte tra il driver chiamando request_firmware
e firmware_helper
guardando la variabile d'ambiente $FIRMWARE
, il nome del pacchetto del kernel è sempre anteposto al nome del firmware.
Quindi, chi lo sta facendo?
Soluzione
Dal punto di vista del kernel, vedere / 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.
Il kernel in realtà non caricare qualsiasi firmware a tutti. Si informa semplicemente userspace, "Voglio un firmware con il nome di xxx ", e attende userspace al tubo l'immagine del firmware di nuovo al kernel.
Ora, su Ubuntu 8.04,
$ grep firmware /etc/udev/rules.d/80-program.rules # Load firmware on demand SUBSYSTEM=="firmware", ACTION=="add", RUN+="firmware_helper"
in modo che hai scoperto, udev
è configurato per eseguire firmware_helper
quando il kernel richiede il firmware.
$ 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
Se avete letto la fonte, ci si accorge che Ubuntu ha scritto un firmware_helper
che è hard-coded al primo sguardo per /lib/modules/$(uname -r)/$FIRMWARE
, poi /lib/modules/$FIRMWARE
, e non altri luoghi. Tradurre per sh
, lo fa circa questa:
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
che è esattamente il formato del kernel si aspetta.
Per fare una lunga storia breve: il pacchetto udev
di Ubuntu ha personalizzazioni che sembrano sempre in /lib/firmware/$(uname -r)
prima. Questa politica viene gestita in userspace.
Altri suggerimenti
Wow questo è informazioni molto utili e mi ha portato alla soluzione per il mio problema quando si effettua un modulo del kernel USB personalizzata per un firmware che richiede dispositivo.
In sostanza, ogni Ubuntu porta un nuovo rimaneggiamento di HAL, sysfs, devfs, udev, e così via ... e le cose basta cambiare. In realtà ho letto hanno smesso di utilizzare Hal.
Quindi cerchiamo di decodificare questo, ancora una volta in modo che sia pertinente per gli ultimi [Ubuntu] sistemi.
Su Ubuntu Lucid (l'ultima al momento della scrittura), viene utilizzato /lib/udev/rules.d/50-firmware.rules
. Questo file chiama il /lib/udev/firmware
binario, dove la magia accade.
Quotazione: /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}"
La magia dovrebbe essere qualcosa in questo senso (fonte:. Linux driver di periferica, 3a ed, Ch . 14: il modello del dispositivo Linux ):
- echo 1 a
loading
- firmware copia
data
- sul fallimento, echo -1 a
loading
e processo firmware arresto loading - echo 0 a
loading
(segnalare il kernel) - poi, un modulo kernel specifico riceve i dati e spinge al dispositivo
Se si guarda alla pagina di origine di Lucid per udev, in udev-151/extras/firmware/firmware.c
, la fonte per questo firmware / lib / udev / binario del firmware, che è esattamente quello che succede.
Estratto: fonte 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");
Inoltre, molti dispositivi utilizzano un formato Intel HEX (file textish contengono checksum e altre cose) (Wiki non ho la reputazione e nessuna capacità di collegamento). Il programma di ihex2fw kernel (chiamato da Makefile in kernel_source / lib / firmware su file .HEX) converte i file HEX in un formato binario arbitrario-progettato che il kernel di Linux, allora prende con request_ihex_firmware
, perché pensavano leggere i file di testo nel kernel era sciocco (sarebbe rallentare le cose).
Su sistemi Linux attuali, questo viene gestito tramite udev
e il firmware.agent
.
Linux 3.5.7 Gentoo, io ho lo stesso problema. Risolto:
emerge ipw2200-firmware
Poi vai a / usr / src / linux
make menucofig
il driver di periferica, rimuovere tutti i driver wirless non necessari, impostare Intell 2200 come modulo e ricompilare.
make
make modules_install
cp arch/x86/boot/bzImage /boot/kernel-yourdefault