Как Linux Kernel знает, где искать прошивку драйвера? - PullRequest
50 голосов
/ 04 июня 2009

Я собираю собственное ядро ​​под Ubuntu и сталкиваюсь с проблемой, что мое ядро, похоже, не знает, где искать прошивку. В Ubuntu 8.04 прошивка привязана к версии ядра так же, как и модули драйверов. Например, ядро ​​2.6.24-24-generic хранит свои модули ядра в:

/lib/modules/2.6.24-24-generic

и его прошивка в:

/lib/firmware/2.6.24-24-generic

Когда я компилирую универсальное ядро ​​Ubuntu 2.6.24-24 в соответствии с « Альтернативным методом сборки: старомодный путь Debian », я получаю соответствующий каталог модулей, и все мои устройства работают, кроме тех, которые требуют прошивка, например, моя беспроводная карта Intel (модуль ipw2200).

Журнал ядра показывает, например, что когда ipw2200 пытается загрузить прошивку, подсистема ядра, контролирующая загрузку прошивки, не может найти его:

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

errno-base.h определяет это как:

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

(Функция, возвращающая ENOENT, ставит перед ней минус.)

Я попытался создать символическую ссылку в / lib / firmware, где имя моего ядра указывало на каталог 2.6.24-24-generic, однако это привело к той же ошибке. Эта прошивка не-GPL, предоставлена ​​Intel и упакована Ubuntu. Я не верю, что это имеет какое-либо отношение к конкретной версии ядра. cmp показывает, что версии в разных каталогах идентичны.

Так как ядро ​​узнает, где искать прошивку?

Обновление

Я нашел это решение для точной проблемы, с которой я столкнулся, однако оно больше не работает, поскольку Ubuntu устранило /etc/hotplug.d и больше не сохраняет свою прошивку в /usr/lib/hotplug/firmware.

Update2

Еще одно исследование выявило еще несколько ответов. До версии 92 udev программа firmware_helper была способом загрузки прошивки. Начиная с udev 93, эта программа была заменена на скрипт с именем firmware.sh, обеспечивающий идентичные функции, насколько я могу судить. Оба из них жестко кодируют путь прошивки к /lib/firmware. Ubuntu по-прежнему использует двоичный файл /lib/udev/firmware_helper.

Имя файла прошивки передается в firmware_helper в переменной среды $FIRMWARE, которая соединяется с путем /lib/firmware и используется для загрузки прошивки.

Фактический запрос на загрузку прошивки осуществляется драйвером (в моем случае ipw2200) через системный вызов:

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

Теперь где-то посередине между драйвером, вызывающим request_firmware и firmware_helper, глядя на переменную окружения $FIRMWARE, имя пакета ядра добавляется к имени прошивки.

Так, кто это делает?

Ответы [ 4 ]

41 голосов
/ 05 июня 2009

С точки зрения ядра, смотрите / 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.

Ядро вообще не загружает никакие прошивки. Он просто информирует пространство пользователя «Я хочу прошивку с именем xxx » и ждет, пока пространство пользователя отправит образ прошивки обратно в ядро.

Теперь в Ubuntu 8.04,

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

так как вы обнаружили, udev настроен для запуска firmware_helper, когда ядро ​​запрашивает прошивку.

$ 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

Если вы прочитаете источник, вы обнаружите, что Ubuntu написал firmware_helper, который жестко запрограммирован для поиска сначала /lib/modules/$(uname -r)/$FIRMWARE, затем /lib/modules/$FIRMWARE, и никаких других местоположений. Переводя его на sh, он делает примерно так:

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

- это именно тот формат, который ожидает ядро.


Короче говоря: пакет udev в Ubuntu имеет настройки, которые всегда сначала выглядят в /lib/firmware/$(uname -r). Эта политика обрабатывается в пользовательском пространстве.

12 голосов
/ 10 июня 2010

Ого, это очень полезная информация, и она привела меня к решению моей проблемы при создании пользовательского модуля ядра USB для устройства, требующего прошивки.

По сути, каждая Ubuntu приносит новую перефразировку hal, sysfs, devfs, udev и так далее ... и все просто меняется. На самом деле я читал, что они перестали использовать hal.

Итак, давайте еще раз проанализируем это, чтобы оно соответствовало новейшим системам [Ubuntu].

В Ubuntu Lucid (последний на момент написания) используется /lib/udev/rules.d/50-firmware.rules. Этот файл вызывает двоичный файл /lib/udev/firmware, где происходит волшебство.

Листинг: /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}"

Волшебство должно быть чем-то вроде этого (источник: Драйверы устройств Linux, 3-е изд., Гл. 14: Модель устройства Linux ):

  • эхо 1 до loading
  • скопировать прошивку в data
  • при сбое, эхо-сигнал от -1 до loading и остановка процесса загрузки прошивки
  • эхо от 0 до loading (сигнал ядра)
  • затем конкретный модуль ядра получает данные и отправляет их на устройство

Если вы посмотрите на исходную страницу Lucid для udev, в udev-151/extras/firmware/firmware.c, источнике этого двоичного файла firmware / lib / udev / firmware, это именно то, что происходит.

Отрывок: источник 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");

Кроме того, многие устройства используют формат Intel HEX (текстовые файлы, содержащие контрольную сумму и прочее) (вики это у меня нет репутации и нет возможности ссылаться). Программа ядра ihex2fw (вызывается из Makefile в kernel_source / lib / firmware для файлов .HEX) преобразует эти HEX-файлы в произвольно разработанный двоичный формат, который ядро ​​Linux затем берет с помощью request_ihex_firmware, поскольку они думали, что читают текстовые файлы в ядро было глупо (это могло бы замедлить ход событий).

1 голос
/ 26 февраля 2013

Linux 3.5.7 Gentoo, у меня та же проблема. РЕШИТЬ:

emerge ipw2200-firmware

Затем перейдите в / usr / src / linux

make menucofig

в драйвере устройства, удалите все ненужные драйверы, установите Intell 2200 в качестве модуля и перекомпилируйте.

make
make modules_install
cp arch/x86/boot/bzImage /boot/kernel-yourdefault
1 голос
/ 04 июня 2009

В современных системах Linux это обрабатывается с помощью udev и firmware.agent.

...