123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- ===================
- Fallback mechanisms
- ===================
- A fallback mechanism is supported to allow to overcome failures to do a direct
- filesystem lookup on the root filesystem or when the firmware simply cannot be
- installed for practical reasons on the root filesystem. The kernel
- configuration options related to supporting the firmware fallback mechanism are:
- * CONFIG_FW_LOADER_USER_HELPER: enables building the firmware fallback
- mechanism. Most distributions enable this option today. If enabled but
- CONFIG_FW_LOADER_USER_HELPER_FALLBACK is disabled, only the custom fallback
- mechanism is available and for the request_firmware_nowait() call.
- * CONFIG_FW_LOADER_USER_HELPER_FALLBACK: force enables each request to
- enable the kobject uevent fallback mechanism on all firmware API calls
- except request_firmware_direct(). Most distributions disable this option
- today. The call request_firmware_nowait() allows for one alternative
- fallback mechanism: if this kconfig option is enabled and your second
- argument to request_firmware_nowait(), uevent, is set to false you are
- informing the kernel that you have a custom fallback mechanism and it will
- manually load the firmware. Read below for more details.
- Note that this means when having this configuration:
- CONFIG_FW_LOADER_USER_HELPER=y
- CONFIG_FW_LOADER_USER_HELPER_FALLBACK=n
- the kobject uevent fallback mechanism will never take effect even
- for request_firmware_nowait() when uevent is set to true.
- Justifying the firmware fallback mechanism
- ==========================================
- Direct filesystem lookups may fail for a variety of reasons. Known reasons for
- this are worth itemizing and documenting as it justifies the need for the
- fallback mechanism:
- * Race against access with the root filesystem upon bootup.
- * Races upon resume from suspend. This is resolved by the firmware cache, but
- the firmware cache is only supported if you use uevents, and its not
- supported for request_firmware_into_buf().
- * Firmware is not accessible through typical means:
- * It cannot be installed into the root filesystem
- * The firmware provides very unique device specific data tailored for
- the unit gathered with local information. An example is calibration
- data for WiFi chipsets for mobile devices. This calibration data is
- not common to all units, but tailored per unit. Such information may
- be installed on a separate flash partition other than where the root
- filesystem is provided.
- Types of fallback mechanisms
- ============================
- There are really two fallback mechanisms available using one shared sysfs
- interface as a loading facility:
- * Kobject uevent fallback mechanism
- * Custom fallback mechanism
- First lets document the shared sysfs loading facility.
- Firmware sysfs loading facility
- ===============================
- In order to help device drivers upload firmware using a fallback mechanism
- the firmware infrastructure creates a sysfs interface to enable userspace
- to load and indicate when firmware is ready. The sysfs directory is created
- via fw_create_instance(). This call creates a new struct device named after
- the firmware requested, and establishes it in the device hierarchy by
- associating the device used to make the request as the device's parent.
- The sysfs directory's file attributes are defined and controlled through
- the new device's class (firmware_class) and group (fw_dev_attr_groups).
- This is actually where the original firmware_class module name came from,
- given that originally the only firmware loading mechanism available was the
- mechanism we now use as a fallback mechanism, which registers a struct class
- firmware_class. Because the attributes exposed are part of the module name, the
- module name firmware_class cannot be renamed in the future, to ensure backward
- compatibility with old userspace.
- To load firmware using the sysfs interface we expose a loading indicator,
- and a file upload firmware into:
- * /sys/$DEVPATH/loading
- * /sys/$DEVPATH/data
- To upload firmware you will echo 1 onto the loading file to indicate
- you are loading firmware. You then write the firmware into the data file,
- and you notify the kernel the firmware is ready by echo'ing 0 onto
- the loading file.
- The firmware device used to help load firmware using sysfs is only created if
- direct firmware loading fails and if the fallback mechanism is enabled for your
- firmware request, this is set up with :c:func:`firmware_fallback_sysfs`. It is
- important to re-iterate that no device is created if a direct filesystem lookup
- succeeded.
- Using::
- echo 1 > /sys/$DEVPATH/loading
- Will clean any previous partial load at once and make the firmware API
- return an error. When loading firmware the firmware_class grows a buffer
- for the firmware in PAGE_SIZE increments to hold the image as it comes in.
- firmware_data_read() and firmware_loading_show() are just provided for the
- test_firmware driver for testing, they are not called in normal use or
- expected to be used regularly by userspace.
- firmware_fallback_sysfs
- -----------------------
- .. kernel-doc:: drivers/base/firmware_loader/fallback.c
- :functions: firmware_fallback_sysfs
- Firmware kobject uevent fallback mechanism
- ==========================================
- Since a device is created for the sysfs interface to help load firmware as a
- fallback mechanism userspace can be informed of the addition of the device by
- relying on kobject uevents. The addition of the device into the device
- hierarchy means the fallback mechanism for firmware loading has been initiated.
- For details of implementation refer to fw_load_sysfs_fallback(), in particular
- on the use of dev_set_uevent_suppress() and kobject_uevent().
- The kernel's kobject uevent mechanism is implemented in lib/kobject_uevent.c,
- it issues uevents to userspace. As a supplement to kobject uevents Linux
- distributions could also enable CONFIG_UEVENT_HELPER_PATH, which makes use of
- core kernel's usermode helper (UMH) functionality to call out to a userspace
- helper for kobject uevents. In practice though no standard distribution has
- ever used the CONFIG_UEVENT_HELPER_PATH. If CONFIG_UEVENT_HELPER_PATH is
- enabled this binary would be called each time kobject_uevent_env() gets called
- in the kernel for each kobject uevent triggered.
- Different implementations have been supported in userspace to take advantage of
- this fallback mechanism. When firmware loading was only possible using the
- sysfs mechanism the userspace component "hotplug" provided the functionality of
- monitoring for kobject events. Historically this was superseded be systemd's
- udev, however firmware loading support was removed from udev as of systemd
- commit be2ea723b1d0 ("udev: remove userspace firmware loading support")
- as of v217 on August, 2014. This means most Linux distributions today are
- not using or taking advantage of the firmware fallback mechanism provided
- by kobject uevents. This is specially exacerbated due to the fact that most
- distributions today disable CONFIG_FW_LOADER_USER_HELPER_FALLBACK.
- Refer to do_firmware_uevent() for details of the kobject event variables
- setup. The variables currently passed to userspace with a "kobject add"
- event are:
- * FIRMWARE=firmware name
- * TIMEOUT=timeout value
- * ASYNC=whether or not the API request was asynchronous
- By default DEVPATH is set by the internal kernel kobject infrastructure.
- Below is an example simple kobject uevent script::
- # Both $DEVPATH and $FIRMWARE are already provided in the environment.
- MY_FW_DIR=/lib/firmware/
- echo 1 > /sys/$DEVPATH/loading
- cat $MY_FW_DIR/$FIRMWARE > /sys/$DEVPATH/data
- echo 0 > /sys/$DEVPATH/loading
- Firmware custom fallback mechanism
- ==================================
- Users of the request_firmware_nowait() call have yet another option available
- at their disposal: rely on the sysfs fallback mechanism but request that no
- kobject uevents be issued to userspace. The original logic behind this
- was that utilities other than udev might be required to lookup firmware
- in non-traditional paths -- paths outside of the listing documented in the
- section 'Direct filesystem lookup'. This option is not available to any of
- the other API calls as uevents are always forced for them.
- Since uevents are only meaningful if the fallback mechanism is enabled
- in your kernel it would seem odd to enable uevents with kernels that do not
- have the fallback mechanism enabled in their kernels. Unfortunately we also
- rely on the uevent flag which can be disabled by request_firmware_nowait() to
- also setup the firmware cache for firmware requests. As documented above,
- the firmware cache is only set up if uevent is enabled for an API call.
- Although this can disable the firmware cache for request_firmware_nowait()
- calls, users of this API should not use it for the purposes of disabling
- the cache as that was not the original purpose of the flag. Not setting
- the uevent flag means you want to opt-in for the firmware fallback mechanism
- but you want to suppress kobject uevents, as you have a custom solution which
- will monitor for your device addition into the device hierarchy somehow and
- load firmware for you through a custom path.
- Firmware fallback timeout
- =========================
- The firmware fallback mechanism has a timeout. If firmware is not loaded
- onto the sysfs interface by the timeout value an error is sent to the
- driver. By default the timeout is set to 60 seconds if uevents are
- desirable, otherwise MAX_JIFFY_OFFSET is used (max timeout possible).
- The logic behind using MAX_JIFFY_OFFSET for non-uevents is that a custom
- solution will have as much time as it needs to load firmware.
- You can customize the firmware timeout by echo'ing your desired timeout into
- the following file:
- * /sys/class/firmware/timeout
- If you echo 0 into it means MAX_JIFFY_OFFSET will be used. The data type
- for the timeout is an int.
- EFI embedded firmware fallback mechanism
- ========================================
- On some devices the system's EFI code / ROM may contain an embedded copy
- of firmware for some of the system's integrated peripheral devices and
- the peripheral's Linux device-driver needs to access this firmware.
- Device drivers which need such firmware can use the
- firmware_request_platform() function for this, note that this is a
- separate fallback mechanism from the other fallback mechanisms and
- this does not use the sysfs interface.
- A device driver which needs this can describe the firmware it needs
- using an efi_embedded_fw_desc struct:
- .. kernel-doc:: include/linux/efi_embedded_fw.h
- :functions: efi_embedded_fw_desc
- The EFI embedded-fw code works by scanning all EFI_BOOT_SERVICES_CODE memory
- segments for an eight byte sequence matching prefix; if the prefix is found it
- then does a sha256 over length bytes and if that matches makes a copy of length
- bytes and adds that to its list with found firmwares.
- To avoid doing this somewhat expensive scan on all systems, dmi matching is
- used. Drivers are expected to export a dmi_system_id array, with each entries'
- driver_data pointing to an efi_embedded_fw_desc.
- To register this array with the efi-embedded-fw code, a driver needs to:
- 1. Always be builtin to the kernel or store the dmi_system_id array in a
- separate object file which always gets builtin.
- 2. Add an extern declaration for the dmi_system_id array to
- include/linux/efi_embedded_fw.h.
- 3. Add the dmi_system_id array to the embedded_fw_table in
- drivers/firmware/efi/embedded-firmware.c wrapped in a #ifdef testing that
- the driver is being builtin.
- 4. Add "select EFI_EMBEDDED_FIRMWARE if EFI_STUB" to its Kconfig entry.
- The firmware_request_platform() function will always first try to load firmware
- with the specified name directly from the disk, so the EFI embedded-fw can
- always be overridden by placing a file under /lib/firmware.
- Note that:
- 1. The code scanning for EFI embedded-firmware runs near the end
- of start_kernel(), just before calling rest_init(). For normal drivers and
- subsystems using subsys_initcall() to register themselves this does not
- matter. This means that code running earlier cannot use EFI
- embedded-firmware.
- 2. At the moment the EFI embedded-fw code assumes that firmwares always start at
- an offset which is a multiple of 8 bytes, if this is not true for your case
- send in a patch to fix this.
- 3. At the moment the EFI embedded-fw code only works on x86 because other archs
- free EFI_BOOT_SERVICES_CODE before the EFI embedded-fw code gets a chance to
- scan it.
- 4. The current brute-force scanning of EFI_BOOT_SERVICES_CODE is an ad-hoc
- brute-force solution. There has been discussion to use the UEFI Platform
- Initialization (PI) spec's Firmware Volume protocol. This has been rejected
- because the FV Protocol relies on *internal* interfaces of the PI spec, and:
- 1. The PI spec does not define peripheral firmware at all
- 2. The internal interfaces of the PI spec do not guarantee any backward
- compatibility. Any implementation details in FV may be subject to change,
- and may vary system to system. Supporting the FV Protocol would be
- difficult as it is purposely ambiguous.
- Example how to check for and extract embedded firmware
- ------------------------------------------------------
- To check for, for example Silead touchscreen controller embedded firmware,
- do the following:
- 1. Boot the system with efi=debug on the kernel commandline
- 2. cp /sys/kernel/debug/efi/boot_services_code? to your home dir
- 3. Open the boot_services_code? files in a hex-editor, search for the
- magic prefix for Silead firmware: F0 00 00 00 02 00 00 00, this gives you
- the beginning address of the firmware inside the boot_services_code? file.
- 4. The firmware has a specific pattern, it starts with a 8 byte page-address,
- typically F0 00 00 00 02 00 00 00 for the first page followed by 32-bit
- word-address + 32-bit value pairs. With the word-address incrementing 4
- bytes (1 word) for each pair until a page is complete. A complete page is
- followed by a new page-address, followed by more word + value pairs. This
- leads to a very distinct pattern. Scroll down until this pattern stops,
- this gives you the end of the firmware inside the boot_services_code? file.
- 5. "dd if=boot_services_code? of=firmware bs=1 skip=<begin-addr> count=<len>"
- will extract the firmware for you. Inspect the firmware file in a
- hexeditor to make sure you got the dd parameters correct.
- 6. Copy it to /lib/firmware under the expected name to test it.
- 7. If the extracted firmware works, you can use the found info to fill an
- efi_embedded_fw_desc struct to describe it, run "sha256sum firmware"
- to get the sha256sum to put in the sha256 field.
|