web-dev-qa-db-fra.com

Comment le noyau Linux sait-il où chercher le firmware du pilote?

Je compile un noyau personnalisé sous Ubuntu et je rencontre le problème que mon noyau ne semble pas savoir où chercher le firmware. Sous Ubuntu 8.04, le micrologiciel est lié à la version du noyau de la même manière que les modules de pilotes. Par exemple, le noyau 2.6.24-24-generic stocke ses modules du noyau dans:

/lib/modules/2.6.24-24-generic

et son firmware dans:

/lib/firmware/2.6.24-24-generic

Lorsque je compile le noyau Ubuntu générique 2.6.24-24 selon la " méthode de construction alternative: l'ancienne méthode Debian " j'obtiens le répertoire de modules approprié et tous mes périphériques fonctionnent à l'exception de ceux nécessitant un firmware tel que comme ma carte sans fil Intel (module ipw2200).

Le journal du noyau montre par exemple que lorsque ipw2200 essaie de charger le firmware, le sous-système du noyau contrôlant le chargement du firmware est incapable de le localiser:

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

errno-base.h définit ceci comme:

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

(La fonction renvoyant ENOENT met un moins devant elle.)

J'ai essayé de créer un lien symbolique dans/lib/firmware où le nom de mon noyau pointait vers le répertoire générique 2.6.24-24, mais cela a entraîné la même erreur. Ce firmware n'est pas GPL, fourni par Intel et emballé par Ubuntu. Je ne pense pas qu'il ait un lien réel avec une version particulière du noyau. cmp montre que les versions des différents répertoires sont identiques.

Alors, comment le noyau sait-il où chercher le firmware?

Mise à jour

J'ai trouvé cette solution au problème exact que j'ai, mais cela ne fonctionne plus car Ubuntu a éliminé /etc/hotplug.d et ne stocke plus son firmware dans /usr/lib/hotplug/firmware.

Update2

Quelques recherches supplémentaires ont permis de trouver d'autres réponses. Jusqu'à la version 92 de udev, le programme firmware_helper était la façon dont le firmware était chargé. À partir de udev 93 ce programme a été remplacé par un script nommé firmware.sh fournissant des fonctionnalités identiques pour autant que je sache. Ces deux codent en dur le chemin du micrologiciel vers /lib/firmware. Ubuntu semble toujours utiliser le /lib/udev/firmware_helper binaire.

Le nom du fichier du firmware est transmis à firmware_helper dans la variable d'environnement $FIRMWARE qui est concaténé au chemin /lib/firmware et utilisé pour charger le firmware.

La demande réelle de chargement du firmware est faite par le pilote (ipw2200 dans mon cas) via l'appel système:

request_firmware(..., "ipw2200-bss.fw", ...);

Maintenant quelque part entre le pilote appelant request_firmware et firmware_helper En regardant le $FIRMWARE variable d'environnement, le nom du package du noyau est ajouté au nom du micrologiciel.

Alors qui le fait?

50
Robert S. Barnes

Du point de vue du noyau, voir / usr/src/linux/Documentation/firmware_class/README :

 noyau (pilote): appelle request_firmware (& fw_entry, $ FIRMWARE, périphérique) 
 
 espace utilisateur: 
 -/sys/class/firmware/xxx/{loading, data} apparaissent. 
 - hotplug est appelé avec un identifiant de firmware dans $ FIRMWARE 
 et l'environnement hotplug habituel. 
 - hotplug: echo 1>/sys/class/firmware/xxx /loading[.____.
 noyau: Jeter toute charge partielle précédente. 
 
 espace utilisateur: 
 - hotplug: cat appropri_firmware_image>\
/sys/class/firmware/xxx/data 
 
 noyau: agrandit un tampon par incréments de PAGE_SIZE pour contenir l'image à mesure que 
 entre. 
 
 espace utilisateur: 
 - hotplug: echo 0> /sys/class/firmware/xxx/loading[.____.
 noyau: request_firmware () renvoie et le pilote a le firmware 
 image dans fw_entry -> {data, size}. Si quelque chose s'est mal passé 
 Request_firmware () renvoie différent de zéro et fw_entry est défini sur 
 NULL. 
 
 Noyau (pilote): le code du pilote appelle release_firmware (fw_entry) libérer 
 l'image du micrologiciel et toute ressource connexe. 

Le noyau ne charge en fait aucun firmware. Il informe simplement l'espace utilisateur, "Je veux un firmware du nom de xxx ", et attend que l'espace utilisateur redirige l'image du firmware vers le noyau.

Maintenant, sur Ubuntu 8.04,

 $ grep firmware /etc/udev/rules.d/80-program.rules[.____.[# Charger le firmware sur demande 
 SUBSYSTEM == "firmware", ACTION == "add" , RUN + = "firmware_helper" 

comme vous l'avez découvert, udev est configuré pour exécuter firmware_helper lorsque le noyau demande un firmware.

 $ apt-get source udev 
 Lecture des listes de packages ... Terminé 
 Construction de l'arborescence des dépendances 
 Lecture des informations d'état ... Terminé 
 Besoin de obtenir 312 Ko d'archives sources. 
 Obtenir: 1 http://us.archive.ubuntu.com hardy-security/main udev 117-8ubuntu0.2 (dsc) [716B] 
 Obtenir: 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] 
 Récupéré 312kB en 1s (223kB/s) 
 gpg: Signature faite le mardi 14 avril 2009 05:31:34 PM EDT utilisant l'ID de clé DSA 17063E6D 
 Gpg: impossible de vérifier la signature: clé publique introuvable 
 Dpkg-source: extraction d'udev dans udev-117 
 dpkg-source: déballage de udev_117.orig.tar.gz 
 dpkg-source: application ./udev_117-8ubuntu0.2.diff.gz[.____.[$ cd udev-117 /[.____.ram$ cat debian/patches/80-extras-firmware.patch 

Si vous lisez la source, vous constaterez qu'Ubuntu a écrit un firmware_helper Qui est codé en dur pour rechercher d'abord /lib/modules/$(uname -r)/$FIRMWARE, puis /lib/modules/$FIRMWARE, Et aucun autre emplacement. Le traduire en sh, il fait approximativement ceci:

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

qui est exactement le format attendu par le noyau.


Pour faire court: le package udev d'Ubuntu a des personnalisations qui apparaissent toujours dans /lib/firmware/$(uname -r) en premier. Cette politique est gérée dans l'espace utilisateur.

41
ephemient

Wow, ce sont des informations très utiles et cela m'a conduit à la solution de mon problème lors de la création d'un module de noyau USB personnalisé pour un périphérique nécessitant un firmware.

Fondamentalement, chaque Ubuntu apporte une nouvelle refonte de hal, sysfs, devfs, udev, etc. ... et les choses changent simplement. En fait, j'ai lu qu'ils avaient cessé d'utiliser hal.

Donc, inversons encore une fois l'ingénierie afin qu'elle soit pertinente pour les derniers systèmes [Ubuntu].

Sur Ubuntu Lucid (la dernière au moment de la rédaction), /lib/udev/rules.d/50-firmware.rules est utilisé. Ce fichier appelle le binaire /lib/udev/firmware, où la magie opère.

Liste: /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 magie devrait être quelque chose dans ce sens (source: Linux Device Drivers, 3rd Ed., Ch. 14: The Linux Device Model ):

  • écho 1 à loading
  • copier le firmware dans data
  • en cas d'échec, écho -1 à loading et arrêt du processus de chargement du firmware
  • écho 0 à loading (signalez le noyau)
  • puis, un module noyau spécifique reçoit les données et les envoie au périphérique

Si vous regardez la page source de Lucid pour udev, dans udev-151/extras/firmware/firmware.c, la source de ce binaire firmware/lib/udev/firmware, c'est exactement ce qui se passe.

Extrait: source 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");

De plus, de nombreux appareils utilisent un format Intel HEX (fichiers textuels contenant une somme de contrôle et d'autres choses) (wiki, je n'ai aucune réputation et aucune capacité de lien). Le programme du noyau ihex2fw (appelé depuis Makefile dans kernel_source/lib/firmware sur les fichiers .HEX) convertit ces fichiers HEX en un format binaire de conception arbitraire que le noyau Linux récupère ensuite avec request_ihex_firmware, car ils pensaient que lire des fichiers texte dans le noyau était idiot (cela ralentirait les choses).

12
Andy Matteson

Linux 3.5.7 Gentoo, j'ai le même problème. RESOLU:

emerge ipw2200-firmware

Allez ensuite dans/usr/src/linux

make menucofig

sur le pilote de périphérique, supprimez tous les pilotes sans fil inutiles, définissez Intell 2200 comme module et recompilez.

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

Sur les systèmes Linux actuels, cela est géré via udev et le firmware.agent.

1
David Schmitt