Подтвердить что ты не робот

Как Linux Kernel знает, где искать прошивку драйвера?

Я компилирую пользовательское ядро ​​под 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, однако это привело к той же ошибке. Эта прошивка не является GPL, предоставляемая Intel и упакованная Ubuntu. Я не верю, что у него есть реальная привязка к определенной версии ядра. cmp показывает, что версии в разных каталогах идентичны.

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

Обновление

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

Update2

Несколько исследований получили еще несколько ответов. До версии 92 udev программа firmware_helper была способом загрузки прошивки. Начиная с udev 93, эта программа была заменена на script с именем 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, имя пакета ядра добавляется к имени прошивки.

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

4b9b3361

Ответ 1

С точки зрения ядра см. /usr/src/linux/Документация/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

который точно соответствует формату ядра.


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

Ответ 2

Вау, это очень полезная информация, и это привело меня к решению моей проблемы при создании пользовательского модуля ядра 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 и остановки процесса загрузки прошивки
  • echo 0 to loading (сигнал ядра)
  • тогда конкретный модуль ядра получает данные и выталкивает их на устройство

Если вы посмотрите на страницу источника Lucid для udev, в udev-151/extras/firmware/firmware.c, источник для этой прошивки/библиотеки 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 (текстовые файлы, содержащие контрольную сумму и другие материалы) (wiki у меня нет репутации и нет возможности связывать). Программа ядра ihex2fw (вызванная из Makefile в kernel_source/lib/firmware на .HEX файлах) преобразует эти файлы HEX в произвольный двоичный формат, который ядро ​​Linux выбирает с помощью request_ihex_firmware, поскольку они думали, что чтение текстовых файлов в Ядро было глупым (это замедлит работу).

Ответ 3

В текущих системах Linux это обрабатывается через udev и firmware.agent.

Ответ 4

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

emerge ipw2200-firmware

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

make menucofig

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

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