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 firmware est lié à la version du noyau de la même manière que les modules du pilote. 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

Quand je compile le noyau Ubuntu 2.6.24-24-generic selon la " méthode de construction alternative: L'ancienne Debian Way " j'obtiens le répertoire de modules approprié et tous mes appareils fonctionnent sauf ceux nécessitant un firmware tel que ma carte sans fil Intel (module ipw2200).

Le Journal du noyau montre par exemple que lorsque ipw2200 tente 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 suit:

#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 2.6.24-24-generic, cependant cela a entraîné la même erreur. Ce firmware est non-GPL, fourni par Intel et emballé par Ubuntu. Je ne crois pas qu'il ait un lien réel avec une version particulière du noyau. cmp montre que les versions dans les différents répertoires sont identiques.

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

Mise à Jour

, j'ai trouvé cette solution exacte problème 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

D'autres recherches ont trouvé d'autres réponses. Jusqu'à la version 92 de udev, le programme firmware_helper a la manière du micrologiciel suis chargé. Commençant par udev 93 ce programme a été remplacé par un script nommé firmware.sh fournir des fonctionnalités identiques pour autant que je sache. Ces deux codent en dur le chemin du firmware vers /lib/firmware. Ubuntu semble toujours utiliser le binaire /lib/udev/firmware_helper.

Le nom du fichier firmware est passé à firmware_helper dans la variable d'environnement $FIRMWARE qui est concaténée au chemin /lib/firmware et utilisée 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 la variable d'environnement $FIRMWARE, le nom du paquet du noyau est obtenir ajouté au nom du firmware.

Alors qui le fait?

47
demandé sur wallyk 2009-06-04 16:04:35

4 réponses

Du point de vue du noyau, voir /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.

Le noyau ne Charge aucun firmware. Il informe simplement userspace ," je veux un firmware du nom de xxx ", et attend que userspace redirige l'image du firmware vers le noyau.

Maintenant, sur Ubuntu 8.04,

$ grep firmware /etc/udev/rules.d/80-program.rules
# Load firmware on demand
SUBSYSTEM=="firmware", ACTION=="add", RUN+="firmware_helper"

Donc, comme vous l'avez découvert, {[4] } est configuré pour exécuter firmware_helper lorsque le noyau le demande 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

Si vous lisez la source, vous constaterez Qu'Ubuntu a écrit un {[5] } qui est codé en dur pour rechercher d'abord /lib/modules/$(uname -r)/$FIRMWARE, puis /lib/modules/$FIRMWARE, et aucun autre emplacement. En le traduisant 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 paquet udev D'Ubuntu a des personnalisations qui regardent toujours /lib/firmware/$(uname -r) en premier. Cette stratégie est gérée dans l'espace utilisateur.

40
répondu ephemient 2009-06-04 22:15:23

Wow c'est une information très utile 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 un nouveau ressaisissement de hal, sysfs, devfs,udev, et ainsi de suite...et les choses changent. En fait, j'ai lu qu'ils ont cessé d'utiliser hal.

Alors, faisons de l'ingénierie inverse encore une fois, donc c'est pertinent pour les derniers systèmes [Ubuntu].

Sur Ubuntu Lucid (le dernier 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 se produit.

Liste:/lib/udev / règles.d / 50-firmware.règles

# 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: pilotes de périphériques Linux, 3e éd., Ch. 14: Le Modèle De Périphérique Linux):

  • echo 1 à loading
  • copier le micrologiciel vers data
  • en cas d'échec, echo -1 à loading et arrêter le processus de chargement du firmware
  • echo 0 à loading (signaler le noyau)
  • alors, un module de noyau spécifique reçoit les données et les pousse vers le 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 lucide, 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 textish contenant la somme de contrôle et d'autres choses) (wiki Je n'ai aucune réputation et aucune capacité à lier). Le programme du noyau ihex2fw (appelé à partir de Makefile dans kernel_source/lib / firmware sur .Fichiers hexadécimaux) convertit ces fichiers hexadécimaux en un format binaire de conception arbitraire que le noyau Linux récupère ensuite avec request_ihex_firmware, car ils pensaient que la lecture de fichiers texte dans le noyau était stupide (cela ralentirait les choses).

11
répondu Andy Matteson 2010-06-10 07:04:55

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

1
répondu David Schmitt 2009-06-04 12:12:18

Linux 3.5.7 Gentoo, j'ai le même problème. Résolu:

emerge ipw2200-firmware

Ensuite, allez dans /usr/src / linux

make menucofig

Sur le pilote de périphérique, supprimez tous les pilotes wirless qui ne sont pas nécessaires, définissez Intell 2200 comme module et recompilez.

make
make modules_install
cp arch/x86/boot/bzImage /boot/kernel-yourdefault
1
répondu MaxV 2013-02-26 10:54:56