2009-06-04 7 views
44

Sto compilando un kernel personalizzato su Ubuntu e sto correndo il problema che il mio kernel non sembra sapere dove cercare il firmware. Sotto Ubuntu 8.04, il firmware è legato alla versione del kernel allo stesso modo dei moduli driver. Ad esempio, kernel 2.6.24-24-generic memorizza i propri moduli del kernel in:In che modo Linux Kernel sa dove cercare il firmware del driver?

/lib/modules/2.6.24-24-generic 

e il suo firmware:

/lib/firmware/2.6.24-24-generic 

Quando ho compilare il kernel di Ubuntu 2.6.24-24-generic secondo "Alternate Build Method: The Old-Fashioned Debian Way" Ricevo la directory dei moduli appropriata e tutti i miei dispositivi funzionano tranne quelli che richiedono firmware come la mia scheda wireless Intel (modulo ipw2200).

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 

numerr-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, dove ha il nome di mio kernel alla directory 2.6.24-24-generica, tuttavia questo ha provocato lo stesso errore. Questo firmware è non GPL, fornito da Intel e confezionato da Ubuntu. Non credo che abbia un legame reale con una particolare versione del kernel. cmp mostra che le versioni nelle varie directory sono identiche.

Quindi, come fa il kernel a sapere dove cercare il firmware?

Aggiornamento

ho trovato this solution 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

qualche ricerca più alzato alcuni più risposte. Fino alla versione 92 di udev, il programma firmware_helper era il modo in cui il firmware veniva caricato. A partire da udev 93 questo programma è stato sostituito con uno script denominato firmware.sh che fornisce funzionalità identiche per quanto posso dire. Entrambi questi hardcoded il percorso del firmware a /lib/firmware. Ubuntu sembra ancora utilizzare il binario /lib/udev/firmware_helper.

Il nome del file del firmware è passato al firmware_helper nella variabile d'ambiente $FIRMWARE che è concatenato al percorso /lib/firmware e utilizzato per caricare il firmware.

La richiesta effettiva per caricare il firmware è fatto da parte del 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 $FIRMWARE ambiente , il nome del pacchetto del kernel viene anteposto al nome del firmware.

Quindi chi lo fa?

+0

Qualcuno potrebbe aggiungere un commento per spiegare perché stanno votando per chiudere questa domanda? Apprezzerei il feedback. –

+2

Viene votato per la chiusura perché "appartiene a serverfault.com". Dal momento che la questione non riguarda la programmazione e piuttosto l'amministrazione, questo è in linea con le dichiarazioni di missione di entrambi i siti. – ephemient

+0

Grazie per il feedback. Ho considerato questa una domanda di programmazione poiché si è verificato un problema durante il tentativo di creare un kernel personalizzato. Mi piacerebbe sapere perché, in particolare, qualcuno considererebbe questo non correlato alla programmazione, anche se penso di aver qualche buona idea del perché. –

risposta

38

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. Semplicemente informa userspace, "Voglio un firmware con il nome di xxx", e aspetta che lo spazio utente ritorni al kernel l'immagine del firmware.

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" 

modo 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 leggete 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 questo:

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 di Ubuntu udev ha personalizzazioni che sembrano sempre in /lib/firmware/$(uname -r) prima. Questa politica viene gestita nello spazio utente.

+1

Risposta meravigliosa, grazie! Stavo guardando la sorgente di udev che mi tirava fuori i capelli cercando di capire da dove provenisse 'firmware_helper' di Ubuntu. Dovrebbe aver appena fatto un grep ricorsivo per il firmware nell'albero dei sorgenti udev. –

+0

In realtà è probabilmente dall'albero udev-extras, alcune parti delle quali Ubuntu ha deciso di modificare e raggruppare con il loro pacchetto udev. – ephemient

+0

'apt-get source' scarica e decomprime l'albero dei sorgenti Debian (o Ubuntu) per il pacchetto, che include una directory' debian' con informazioni sull'impacchettamento e setup specifico della distribuzione, che a volte include patch che non si trovano a monte. Questo è un caso. – ephemient

1

Su sistemi Linux correnti, questo viene gestito tramite udev e firmware.agent.

+0

Apparentemente Ubuntu 8.04 non ha firmware.agent in udev, ha qualcos'altro chiamato firmware_helper. In ogni caso, in che modo questo dice al kernel dove trovare il firmware? –

+0

Qualunque comando venga chiamato da udev, è responsabile del caricamento del firmware nel kernel. Dalla mia lettura del firmware.agent di Debian, scrive il firmware in un file speciale in/sys –

11

Wow questa è un'informazione molto utile e mi ha portato alla soluzione per il mio problema durante la creazione di un modulo del kernel USB personalizzato per un dispositivo che richiede il firmware.

Fondamentalmente, ogni Ubuntu porta un nuovo rehash di hal, sysfs, devfs, udev e così via ... e le cose cambiano. Infatti ho letto che hanno smesso di usare hal.

Quindi, eseguiamo di nuovo il reverse engineering in modo che sia pertinente agli ultimi sistemi [Ubuntu].

Su Ubuntu Lucid (l'ultimo al momento della scrittura), viene utilizzato /lib/udev/rules.d/50-firmware.rules. Questo file chiama il binario /lib/udev/firmware, dove avviene la magia.

Listing: /lib/udev/rules.d/50-firmware.regole

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

La magia deve essere qualcosa in questo senso (fonte: Linux Device Drivers, 3rd Ed., Ch. 14: The Linux Device Model):

  • eco 1-loading
  • firmware copia data
  • in caso di fallimento, eco -1 a loading e interrompere il processo di caricamento del firmware
  • echo da 0 a loading (segnalare il kernel)
  • poi, un modulo del kernel specifica riceve i dati e lo 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/firmware binario, è 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 ho nessuna reputazione e nessuna possibilità di collegamento). Il programma del kernel ihex2fw (chiamato da Makefile in kernel_source/lib/firmware su file .HEX) converte questi file HEX in un formato binario progettato in modo arbitrario che il kernel Linux preleva con request_ihex_firmware, perché pensavano che leggere i file di testo nel kernel fosse sciocco (rallenterebbe le cose).

+1

+1 Ora hai un rappresentante e puoi collegare. Se hai trovato utili le informazioni nell'OP o la risposta di un'altra persona, votarle. –

1

Linux 3.5.7 Gentoo, ho lo stesso problema. risolto:

emerge ipw2200-firmware 

Poi vai a/usr/src/linux

make menucofig 

il driver di periferica, rimuovere non necessari tutti i driver wirless, impostare Intell 2200 come modulo e ricompilare.

make 
make modules_install 
cp arch/x86/boot/bzImage /boot/kernel-yourdefault