Что такое firmware в linux
Работаем с модулями ядра в Linux
Ядро — это та часть операционной системы, работа которой полностью скрыта от пользователя, т. к. пользователь с ним не работает напрямую: пользователь работает с программами. Но, тем не менее, без ядра невозможна работа ни одной программы, т.е. они без ядра бесполезны. Этот механизм чем-то напоминает отношения официанта и клиента: работа хорошего официанта должна быть практически незаметна для клиента, но без официанта клиент не сможет передать заказ повару, и этот заказ не будет доставлен.
В Linux ядро монолитное, т.е. все его драйвера и подсистемы работают в своем адресном пространстве, отделенном от пользовательского. Сам термин «монолит» говорит о том, что в ядре сконцентрировано всё, и, по логике, ничего не может в него добавляться или удаляться. В случае с ядром Linux — это правда лишь отчасти: ядро Linux может работать в таком режиме, однако, в подавляющем большинстве сборок возможна модификация части кода ядра без его перекомпиляции, и даже без его выгрузки. Это достигается путем загрузки и выгрузки некоторых частей ядра, которые называются модулями. Чаще всего в процессе работы необходимо подключать модули драйверов устройств, поддержки криптографических алгоритмов, сетевых средств, и, чтобы уметь это правильно делать, нужно разбираться в строении ядра и уметь правильно работать с его модулями. Об этом и пойдет речь в этой статье.
В современных ядрах при подключении оборудования модули подключаются автоматически, а это событие обрабатывается демоном udev, который создает соответствующий файл устройства в каталоге «/dev». Все это выполняется в том случае, если соответствующий модуль корректно установлен в дерево модулей. В случае с файловыми системами ситуация та же: при попытке монтирования файловой системы ядро подгружает необходимый модуль автоматически, и выполняет монтирование.
Если необходимость в модуле не на столько очевидна, ядро его не загружает самостоятельно. Например, для поддержки функции шифрования на loop устройстве нужно вручную подгрузить модуль «cryptoloop», а для непосредственного шифрования — модуль алгоритма шифрования, например «blowfish».
Поиск необходимого модуля
Модули хранятся в каталоге «/lib/modules/ » в виде файлов с расширением «ko». Для получения списка всех модулей из дерева можно выполнить команду поиска всех файлов с расширением «ko» в каталоге с модулями текущего ядра:
filename: /lib/modules/2.6.38-gentoo-r1/kernel/drivers/net/wireless/rt2x00/rt73usb.ko
license: GPL
firmware: rt73.bin
description: Ralink RT73 USB Wireless LAN driver.
version: 2.3.0
author: rt2x00.serialmonkey.com
depends: rt2x00lib,rt2x00usb,crc-itu-t
vermagic: 2.6.38-gentoo-r1 SMP preempt mod_unload modversions CORE2
parm: nohwcrypt:Disable hardware encryption. (bool)
Поле «firmware» указывает на то, что этот модуль сам по себе не работает, ему нужна бинарная микропрограмма устройства в специальном файле «rt73.bin». Необходимость в файле микропрограммы появилась в связи с тем, что интерфейс взаимодействия с устройством закрыт, и эти функции возложены на файл прошивки (firmware). Взять firmware можно с сайта разработчика, установочного диска, поставляемого вместе с устройством, или где-нибудь в репозиториях дистрибутива, затем нужно его скопировать в каталог «/lib/firmware», при чем имя файла должно совпадать с тем, что указано в модуле.
Следующее поле, на которое нужно обратить внимание — это поле «depends». Здесь перечислены модули, от которых зависит данный. Логично предположить, что модули друг от друга зависят, например модуль поддержки USB накопителей зависит от модуля поддержки USB контроллера. Эти зависимости просчитываются автоматически, и будут описаны ниже.
Последнее важное поле — «param». Здесь описаны все параметры, которые может принимать модуль при загрузке, и их описания. В данном случае возможен только один: «nohwcrypt», который, судя по описанию, отключает аппаратное шифрование. В скобках указан тип значения параметра.
Более подробную информацию о модуле можно прочитать в документации к исходным кодам ядра (каталог Documentation) в дереве исходных кодов. Например, найти код нужного видеорежима драйвера «vesafb» можно в файле документации «Documentation/fb/vesafb.txt» относительно корня дерева исходных кодов.
Загрузка и выгрузка модулей
Загрузить модуль в ядро можно при помощи двух команд: «insmod» и «modprobe», отличающихся друг от друга возможностью просчета и удовлетворения зависимостей. Команда «insmod» загружает конкретный файл с расширением «ko», при этом, если модуль зависит от других модулей, еще не загруженных в ядро, команда выдаст ошибку, и не загрузит модуль. Команда «modprobe» работает только с деревом модулей, и возможна загрузка только оттуда по имени модуля, а не по имени файла. Отсюда следует область применения этих команд: при помощи «insmod» подгружается файл модуля из произвольного места файловой системы (например, пользователь скомпилировал модули и перед переносом в дерево ядра решил проверить его работоспособность), а «modprobe» — для подгрузки уже готовых модулей, включенных в дерево модулей текущей версии ядра. Например, для загрузки модуля ядра «rt73usb» из дерева ядра, включая все зависимости, и отключив аппаратное шифрование, нужно выполнить команду:
# modprobe rt73usb nohwcrypt=0
Загрузка этого модуля командой «insmod» произойдет следующим образом:
# insmod /lib/modules/2.6.38-gentoo-r1/kernel/drivers/net/wireless/rt2x00/rt73usb.ko nohwcrypt=0
Но нужно помнить, что при использовании «insmod» все зависимости придется подгружать вручную. Поэтому эта команда постепенно вытесняется командой «modprobe».
После загрузки модуля можно проверить его наличие в списке загруженных в ядро модулей при помощи команды «lsmod»:
# lsmod | grep rt73usb
Module | Size | Used by | |
rt73usb | 17305 | 0 | |
crc_itu_t | 999 | 1 | rt73usb |
rt2x00usb | 5749 | 1 | rt73usb |
rt2x00lib | 19484 | 2 | rt73usb,rt2x00usb |
Из вывода команды ясно, что модуль подгружен, а так же в своей работе использует другие модули.
Чтобы его выгрузить, можно воспользоваться командой «rmmod» или той же командой «modprobe» с ключем «-r». В качестве параметра обоим командам нужно передать только имя модуля. Если модуль не используется, то он будет выгружен, а если используется — будет выдана ошибка, и придется выгружать все модули, которые от него зависят:
# rmmod rt2x00usb
ERROR: Module rt2x00usb is in use by rt73usb
# rmmod rt73usb
# rmmod rt2x00usb
После выгрузки модуля все возможности, которые он предоставлял, будут удалены из таблицы ядра.
Для автоматической загрузки модулей в разных дистрибутивах предусмотрены разные механизмы. Я не буду вдаваться здесь в подробности, они для каждого дистрибутива свои, но один метод загрузки всегда действенен и удобен: при помощи стартовых скриптов. В тех же RedHat системах можно записать команды загрузки модуля прямо в «/etc/rc.d/rc.local» со всеми опциями.
Файлы конфигурация модулей находится в каталоге «/etc/modprobe.d/» и имеют расширение «conf». В этих файлах преимущественно перечисляются альтернативные имена модулей, их параметры, применяемые при их загрузке, а так же черные списки, запрещенные для загрузки. Например, чтобы вышеупомянутый модуль сразу загружался с опцией «nohwcrypt=1» нужно создать файл, в котором записать строку:
options rt73usb nohwcrypt=1
Черный список модулей хранится преимущественно в файле «/etc/modules.d/blacklist.conf» в формате «blacklist ». Используется эта функция для запрета загрузки глючных или конфликтных модулей.
Сборка модуля и добавление его в дерево
Иногда нужного драйвера в ядре нет, поэтому приходится его компилировать вручную. Это так же тот случай, если дополнительное ПО требует добавление своего модуля в ядро, типа vmware, virtualbox или пакет поддержки карт Nvidia. Сам процесс компиляции не отличается от процесса сборки программы, но определенные требования все же есть.
Во первых, нужен компилятор. Обычно установка «gcc» устанавливает все, что нужно для сборки модуля. Если чего-то не хватает — программа сборки об этом скажет, и нужно будет доустановить недостающие пакеты.
Во вторых, нужны заголовочные файлы ядра. Дело в том, что модули ядра всегда собираются вместе с ядром, используя его заголовочные файлы, т.к. любое отклонение и несоответствие версий модуля и загруженного ядра ведет к невозможности загрузить этот модуль в ядро.
Если система работает на базе ядра дистрибутива, то нужно установить пакеты с заголовочными файлами ядра. В большинстве дистрибутивов это пакеты «kernel-headers» и/или «kernel-devel». Для сборки модулей этого будет достаточно. Если ядро собиралось вручную, то эти пакеты не нужны: достаточно сделать символическую ссылку «/usr/src/linux», ссылающуюся на дерево сконфигурированных исходных кодов текущего ядра.
После компиляции модуля на выходе будет получен один или несколько файлов с расширением «ko». Можно попробовать их загрузить при помощи команды «insmod» и протестировать их работу.
Если модули загрузились и работают (или лень вручную подгружать зависимости), нужно их скопировать в дерево модулей текущего ядра, после чего обязательно обновить зависимости модулей командой «depmod». Она пройдется рекурсивно по дереву модулей и запишет все зависимости в файл «modules.dep», который, в последствие, будет анализироваться командой «modprobe». Теперь модули готовы к загрузке командой modprobe и могут загружаться по имени со всеми зависимостями.
Стоит отметить, что при обновлении ядра этот модуль работать не будет. Нужны будут новые заголовочные файлы и потребуется заново пересобрать модуль.
«Слушаем» что говорит ядро
При появлении малейших неполадок с модулем, нужно смотреть сообщения ядра. Они выводятся по команде «dmesg» и, в зависимости от настроек syslog, в файл «/var/log/messages». Сообщения ядра могут быть информативными или отладочными, что поможет определить проблему в процессе работы модуля, а могут сообщать об ошибке работы с модулем, например недостаточности символов и зависимостей, некорректных переданных параметрах. Например, выше рассмотренный модуль «rt73usb» требует параметр типа bool, что говорит о том, что параметр может принимать либо «0», либо «1». Если попробовать передать «2», то система выдаст ошибку:
# modprobe rt73usb nohwcrypt=2
FATAL: Error inserting rt73usb (/lib/modules/2.6.38-gentoo-r1/kernel/drivers/net/wireless/rt2x00/rt73usb.ko): Invalid argument
Ошибка «Invalid argument» может говорить о чем угодно, саму ошибку ядро на консоль написать не может, только при помощи функции «printk» записать в системный лог. Посмотрев логи можно уже узнать в чем ошибка:
В этом примере выведена только последняя строка с ошибкой, чтобы не загромаждать статью. Модуль может написать и несколько строк, поэтому лучше выводить полный лог, или хотя бы последние строк десять.
Ошибку уже легко найти: значение «2» неприемлемо для параметра «nohwcrypt». После исправления, модуль корректно загрузится в ядро.
Из всего сказанного можно сделать один вывод: ядро Linux играет по своим правилам и занимается серьезными вещами. Тем не менее — это всего лишь программа, оно, по сути, не сильно отличается от других обычных программ. Понимание того, что ядро не так уж страшно, как кажется, может стать первым шагом к пониманию внутреннего устройства системы и, как результат, поможет быстро и эффективно решать задачи, с которыми сталкивается любой администратор Linux в повседневной работе.
Ubuntu Wiki
Firmware
What is Firmware?
Many devices have two essential software pieces that make them function in your operating system. The first is a working driver, which is the software that lets your system talk to the hardware. The second is firmware, which is usually a small piece of code that is uploaded directly to the device for it to function correctly. You can think of the firmware as a way of programming the hardware inside the device. In fact, in almost all cases firmware is treated like hardware in that it’s a black box; there’s no accompanying source code that is freely distributed with it.
Where Do You Get Firmware?
The firmware is usually maintained by the company that develops the hardware device. In Windows land, firmware is usually a part of the driver you install. It’s often not seen by the user. In Linux, firmware may be distributed from a number of sources. Some firmware comes from the Linux kernel sources. Others that have redistribution licenses come from upstream. Some firmware unfortunately do not have licenses allowing free redistribution.
Note that the linux-firmware-nonfree package is not installed by default.
The firmware files are placed into /lib/firmware. If you look inside there on your Ubuntu installation you will see hundreds of firmware files that have been installed by these packages.
How is Firmware Used?
If everything goes well you should see something like the following in your /var/log/syslog:
If there’s an issue, you may see something like the following:
Debugging Firmware Loading
Luckily, the firmware loading process is not too difficult to watch in action. Using the following debugging steps we can pin point what step in the process is failing.
Initial Step
First, ensure that the firmware file is present. If you are missing the firmware file, try searching on the web for a copy of it. If you find it, consider filing a bug against linux-firmware if the firmware has a redistribution license or against linux-firmware-nonfree otherwise.
The size of the file is the number listed after the user and group owners («root» and «root» in this case). It should be non-zero. At this point, you may want to search the web for an md5sum hash of the file and compare it to this file, but it’s not likely that the file is corrupted. If the firmware is corrupted, you will likely see an error message from the driver stating that the firmware was invalid or failed to upload anyways.
At this point we’ve verified that the firmware file exists, but wasn’t uploaded. We need to figure out which of steps 2-4 mentioned above are failing. Let’s start with step 2.
Kernel Event Sent to Udev
The second step involves the kernel sending an event to the udev subsystem. Luckily, there’s a handy tool we can use for monitoring these event messages: udevadm. Start with your driver unloaded. Then execute:
Now load your driver. Sometimes loading the driver alone will cause a firmware request. Other times, as with the e100 driver, you will need to do something to initiate a firmware request. In the case of the e100 driver, the firmware is requested after the user tries to bring up the ethernet interface by running ‘ip link set eth0 up’.
Once you have initiated a firmware request you should see a udev event that looks like the following:
FIRMWARE= : This is the filename of the firmware requested by the driver.
If you do not see an event with these three items, then the kernel request is not being propagated to udev. You should file a bug at this point against the udev package. If you do see this event, continue to the next step.
Udev Sends Firmware to Kernel
Now that udev has seen the firmware request, it has to decide how to process it. There should be a «rules» file in /lib/udev/rules.d/50-firmware.rules with a single udev rule:
9.10 (Karmic Koala) and earlier:
10.04 (Lucid Lynx) and later:
This rule tells udev to run the firmware program, which may be found in /lib/udev/, whenever it sees an event with both ACTION=add and SUBSYSTEM=firmware. In 9.10 and earlier, the firmware program will be passed the rest of the udev event information as environment variables. In 10.04 and later, the firmware filename and device path will be passed as parameters.
We can watch udev process the event by turning on extra logging:
When you initiate a firmware request, udev will log what it does with the event to /var/log/syslog. For example, you should see something like:
If you do not see firmware.sh get run, then you likely have an issue with your udev rules. Check for any custome udev rules you have in /etc/udev/rules.d. Any files in this directory will override files with the same name under /lib/udev/rules.d. Rules in /etc/udev/rules.d may also prevent the firmware rule from executing properly. If you have any issues at this step you should seek help from the community. If you believe you have found an issue in udev, feel free to open a bug.
After you have debugged udev execution, you should return the logging output to the normal level:
Kernel Reads the Firmware
If the firmware.sh script has been executed by udev, any errors it encounters should show up in your /var/log/syslog file. If you see any errors here they may be caused by the firmware.sh script (which is part of udev), or by the kernel. If you see the following error:
you should open a kernel bug. If you see any other error, you should open a bug against udev.
Kernel Gives Firmware to Driver
If the firmware loading process properly runs firmware.sh without an error, but the driver complains about the firmware, one of two things may be wrong. First, the firmware file may be incorrect or corrupted. You can try to reinstall the firmware or get the firmware from another source. Second, there may be an issue with the driver itself. If you have tried all the firmware versions you could find, you should open a kernel bug.
Kernel/Firmware (последним исправлял пользователь khadgaray 2013-12-11 08:01:04)
Только самое нужное. Избавляем Linux от багажа прошивок для оборудования
Содержание статьи
С железом нередко бывает так, что одного драйвера в пространстве ядра ОС для его работы недостаточно. Нужна также прошивка (firmware), которая загружается в само устройство. Точный формат и назначения прошивки зачастую известны только производителю: иногда это программа для микроконтроллера или FPGA, а иногда просто набор данных. Пользователю это не важно, главное, что устройство не работает, если ОС не загрузит в него прошивку.
В свободных операционных системах прошивки нередко вызывают споры. Многие из них распространяются под несвободными лицензиями и без исходного кода. Авторы OpenBSD и ряда дистрибутивов GNU/Linux считают это проблемой и со свободой, и с безопасностью и принципиально не включают такие прошивки в установочный образ.
Если у тебя есть устройство, которое требует прошивки, и тебе нужно, чтобы оно работало, вопрос лицензии прошивки становится чисто академическим — от необходимости иметь ее в системе и загружать ты никуда не уйдешь.
Полный набор из linux-firmware занимает более 500 Мбайт в распакованном виде. При этом каждой отдельно взятой системе требуется только небольшая часть этих файлов, остальное — мертвый груз.
Даже в современном мире с дисками на несколько терабайт еще много случаев, когда размер имеет значение: встраиваемые системы, образы для загрузки через PXE и подобное. Хорошо, если о board support package позаботился кто-то другой, но это не всегда так.
Если ты точно знаешь полный список нужного железа, можно извлечь файлы вручную. Впрочем, даже в этом случае найти нужные файлы может быть непросто — linux-firmware представляет собой не очень структурированную кучу файлов, и списка соответствия файлов именам модулей ядра там нет. А если ты хочешь дать пользователям возможность легко собрать свой образ, тут и вовсе нет выбора — нужно автоматическое решение.
В этой статье я расскажу о своем способе автоматической сборки. Он неидеален, но автоматизирует большую часть работы, что уже неплохо. Писать скрипт будем на Python 3.
Примеры кода в статье упрощенные. Готовый и работающий скрипт ты можешь найти на GitHub.
Основы
Поиск по вызовам request_firmware() тоже не очень перспективен. Некоторые модули поддерживают несколько разных прошивок, да и имя файла часто хранится в переменной. В качестве примера можно посмотреть на фрагмент кода из драйвера сетевой карты Intel e100.
Здесь и далее будем считать, что все ненужные модули отключены в конфиге сборки ядра (Kconfig). Если мы собираем образ для конкретной системы или ограниченного набора систем, это вполне логичное предположение.
Ищем исходники модулей
Чтобы собрать список имен файлов прошивок, мы сначала составим список всех файлов исходного кода ядра, где они используются. Затем мы прогоним эти файлы через препроцессор из GCC, чтобы раскрыть все макросы, и извлечем собственно имена нужных файлов.
Находим все включенные в конфиге модули
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Linux firmware
Linux firmware is a package distributed alongside the Linux kernel that contains firmware binary blobs necessary for partial or full functionality of certain hardware devices. These binary blobs are usually proprietary because some hardware manufacturers do not release source code necessary to build the firmware itself.
Modern graphics cards from AMD and NVIDIA almost certainly require binary blobs to be loaded for the hardware to operate correctly.
Starting at Broxton (a Skylake-based micro-architecture) Intel CPUs require binary blobs for additional low-power idle states (DMC), graphics workload scheduling on the various graphics parallel engines (GuC), and offloading some media functions from the CPU to GPU (HuC). [1]
Additionally, modern Intel Wi-Fi chipsets almost always require blobs. [2]
Contents
Installation
For security reasons, hotloading firmware into a running kernel has been shunned upon. Modern init systems such as systemd have strongly discouraged loading firmware from userspace.
Kernel
A few kernel options are important to consider when building in firmware support for certain devices in the Linux kernel:
For kernels before 4.18:
CONFIG_FIRMWARE_IN_KERNEL (DEPRECATED) Note this option has been removed as of versions v4.16 and above. [3] Enabling this option was previously necessary to build each required firmware blob specified by EXTRA_FIRMWARE into the kernel directly, where the request_firmware() function will find them without having to make a call out to userspace. On older kernels, it is necessary to enable it.
For kernels beginning with 4.18:
Firmware loading facility ( CONFIG_FW_LOADER ) This option is provided for the case where none of the in-tree modules require userspace firmware loading support, but a module built out-of-tree does. Build named firmware blobs into the kernel binary ( CONFIG_EXTRA_FIRMWARE ) This option is a string and takes the (space-separated) names of firmware files to be built into the kernel. These files will then be accessible to the kernel at runtime.
Firmware refers to embedded software which controls electronic devices. Well-defined boundaries between firmware and software do not exist, as both terms cover some of the same code. Typically, the term firmware deals with low-level operations in a device, without which the device would be completely non-functional (read more on Wikipedia).
Devices/Drivers Firmware
Many devices require firmware to operate. Historically, firmware would be built into the device’s ROM or Flash memory, but more and more often, a firmware image has to be loaded into the device RAM by a device driver during device initialisation.
A few firmware images are Free Software and Open Source but almost all of them are non-free, which means that you need to add the non-free and contrib components to your APT sources.
Firmware during the installation
In some cases the installer detects the need for non-free firmware and prompts the user to make the firmware available to the installer to complete the installation. This can happen, for example, with wireless network cards which often require non-free firmware to function (see ipw2200 for an example).
Installation images with firmware
An easy method is to use an installer image that includes all non-free firmware packages directly. See https://cdimage.debian.org/cdimage/unofficial/non-free/cd-including-firmware/
Firmware on removable media
You can also download the firmware archive for your platform and unpack it into a directory named firmware in the root of a removable storage device (USB/CD drive). You can find firmware downloads for your Debian version at https://cdimage.debian.org/cdimage/unofficial/non-free/firmware/. When the installer starts, it will automatically find the firmware files in the directory on the removable storage and, if needed, install the required firmware.
In some cases, firmware supplied on removable media may not be detected automatically (e.g. 740503). In these situations, drop to the console ( Ctrl+alt+F2) and manually mount(8) your removable storage on a temporary directory (e.g. /media).
Firmware on removable media and preseeding
It is also possible to bypass the installer’s searching and installation process by preseeding and providing the firmware files directly to the kernel:
The needed firmware files are assumed to be in a directory named firmware on a FAT partition formatted with mkfs.vfat and labelled FIRMWARE.
The following addition is made to the installer’s kernel command line. It is a single command but has been broken here for readability. Press TAB when the installation choice is highlighted to make the command line visible. A variation on this technique is presented elsewhere.
Once the network is configured, Debian-Installer can fetch firmware from Debian repositories.
Location of firmware files
Debian 8 «Jessie» and newer
udev used in Debian Jessie and later, only checks one directory for firmware files: /lib/firmware. See 729252 for details.
Debian 7 «Wheezy», Debian 6.0 «Squeeze»
Firmware is sourced from the following places (see udev’s /lib/udev/hotplug.functions and /lib/udev/firmware.agent)
List of firmware in Linux kernel
To find which package provides a given firmware file, you can use this search page:
https://www.debian.org/distrib/packages#search_contents
Firmware/List lists all firmware distributed along Debian Linux kernel images.
Computer Firmware
also known as OpenBoot, Found on Sun SPARC systems, IBM Power, PowerPC-based Apple Macintosh, IEEE 1275-1994. (wikipedia)
Coreboot (LinuxBIOS)
Found on the Lemote Yeeloong and embedded devices
Updating firmware
Firmware can be updated using various methods.
Open firmware
There are a number of projects creating various kinds of open firmware, including for booting, WiFi and audio.