요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
===================
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.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
Fallback mechanism 개요와 설정
1-21문서 제목은 `Fallback mechanisms`입니다.
Root filesystem에서 direct filesystem lookup이 실패하거나 실무적인 이유로 firmware를 root filesystem에 설치할 수 없을 때 이를 극복하도록 fallback mechanism을 지원합니다.
Firmware fallback mechanism과 관련된 kernel configuration option은 다음과 같습니다.
- `CONFIG_FW_LOADER_USER_HELPER`는 firmware fallback mechanism build를 활성화합니다. 현재 대부분의 distribution이 이 option을 켭니다. 이 option은 켜고 `CONFIG_FW_LOADER_USER_HELPER_FALLBACK`은 끄면 `request_firmware_nowait()` call에서 custom fallback mechanism만 사용할 수 있습니다.
- `CONFIG_FW_LOADER_USER_HELPER_FALLBACK`은 `request_firmware_direct()`를 제외한 모든 firmware API call에서 각 request가 kobject uevent fallback mechanism을 사용하도록 강제합니다. 현재 대부분의 distribution은 이 option을 끕니다.
- 이 kconfig option이 켜진 상태에서 `request_firmware_nowait()`의 두 번째 argument인 `uevent`를 false로 지정하면, custom fallback mechanism이 있고 firmware를 수동으로 load하겠다고 kernel에 알립니다.
설정 조합의 효과
22-30다음 설정에서는 kobject uevent fallback mechanism이 동작하지 않습니다.
CONFIG_FW_LOADER_USER_HELPER=y
CONFIG_FW_LOADER_USER_HELPER_FALLBACK=n
이 조합에서는 `request_firmware_nowait()`의 `uevent`를 true로 지정해도 kobject uevent fallback mechanism이 절대로 적용되지 않습니다.
Fallback mechanism이 필요한 이유
31-53Direct filesystem lookup은 여러 이유로 실패할 수 있습니다. Fallback mechanism의 필요성을 설명하는 알려진 이유는 다음과 같습니다.
- Boot 중 root filesystem에 접근하는 시점과의 race
- Suspend에서 resume할 때의 race. Firmware cache로 해결되지만, firmware cache는 uevent를 사용할 때만 지원되고 `request_firmware_into_buf()`에는 지원되지 않습니다.
- Firmware를 일반적인 방법으로 접근할 수 없는 경우. Root filesystem에 설치할 수 없거나, device unit별 local information으로 만든 고유한 data일 수 있습니다.
- Mobile device용 WiFi chipset calibration data처럼 unit마다 다른 firmware는 root filesystem이 아닌 별도 flash partition에 설치될 수 있습니다.
Fallback mechanism의 두 유형
54-64하나의 공통 sysfs interface를 loading facility로 사용하는 fallback mechanism은 실제로 두 종류입니다.
- Kobject uevent fallback mechanism
- Custom fallback mechanism
두 mechanism은 같은 sysfs loading facility를 사용하지만 userspace notification 방식이 다릅니다.
Firmware sysfs loading facility
65-98Device driver가 fallback mechanism으로 firmware를 upload하도록 돕기 위해 firmware infrastructure는 userspace가 firmware를 load하고 준비 완료를 알릴 수 있는 sysfs interface를 만듭니다.
Sysfs directory는 `fw_create_instance()`가 생성합니다. 이 call은 요청한 firmware 이름을 가진 새 `struct device`를 만들고, request에 사용된 device를 parent로 연결해 device hierarchy에 배치합니다.
Sysfs directory의 file attribute는 새 device의 class인 `firmware_class`와 group인 `fw_dev_attr_groups`를 통해 정의하고 제어합니다. 원래 사용할 수 있던 유일한 firmware loading mechanism이 지금의 fallback mechanism이었고 `struct class firmware_class`를 등록했기 때문에 `firmware_class`라는 module 이름이 생겼습니다.
노출 attribute가 module 이름의 일부이므로 오래된 userspace와 backward compatibility를 보장하기 위해 앞으로도 `firmware_class` module 이름을 바꿀 수 없습니다.
Sysfs interface는 loading indicator와 firmware upload file을 노출합니다.
- `/sys/$DEVPATH/loading`
- `/sys/$DEVPATH/data`
Firmware upload를 시작할 때 `loading` file에 1을 쓰고, 이어서 firmware를 `data` file에 기록한 뒤, 준비가 끝났음을 kernel에 알리도록 `loading` file에 0을 씁니다.
이 sysfs firmware device는 direct firmware loading이 실패하고 해당 request에 fallback mechanism이 활성화된 경우에만 생성됩니다. 이 설정은 `firmware_fallback_sysfs()`로 수행합니다. Direct filesystem lookup이 성공하면 device를 만들지 않습니다.
Direct lookup 실패 뒤 userspace가 loading 상태와 data를 전달하는 순서입니다.
Sysfs loading 세부 동작과 API
99-116다음 명령을 사용합니다.
echo 1 > /sys/$DEVPATH/loading
이 명령은 이전의 partial load를 즉시 정리하고 firmware API가 error를 반환하게 합니다. Firmware를 load하는 동안 `firmware_class`는 들어오는 image를 담도록 buffer를 `PAGE_SIZE` 단위로 늘립니다.
`firmware_data_read()`와 `firmware_loading_show()`는 test용 `test_firmware` driver를 위해서만 제공됩니다. 정상 사용에서는 호출하지 않으며 userspace가 정기적으로 사용할 것으로 기대하지도 않습니다.
`firmware_fallback_sysfs` 설명은 `drivers/base/firmware_loader/fallback.c`에서 해당 function의 kernel-doc을 가져옵니다.
.. kernel-doc:: drivers/base/firmware_loader/fallback.c
:functions: firmware_fallback_sysfs
Kobject uevent fallback mechanism
117-163Fallback loading용 sysfs interface를 위해 device가 생성되므로 userspace는 kobject uevent를 통해 device 추가 사실을 알 수 있습니다. Device hierarchy에 device가 추가되면 firmware loading fallback mechanism이 시작된 것입니다.
구현 세부 사항은 `fw_load_sysfs_fallback()`을 참고하며, 특히 `dev_set_uevent_suppress()`와 `kobject_uevent()` 사용을 확인해야 합니다.
Kernel의 kobject uevent mechanism은 `lib/kobject_uevent.c`에 구현되어 userspace로 uevent를 보냅니다. Distribution은 보조 수단으로 `CONFIG_UEVENT_HELPER_PATH`를 켜 core kernel usermode helper(UMH)가 kobject uevent용 userspace helper를 호출하게 할 수 있지만, 실제로 표준 distribution에서 이 option을 사용한 적은 없습니다.
`CONFIG_UEVENT_HELPER_PATH`가 켜지면 kernel에서 trigger되는 각 kobject uevent마다 `kobject_uevent_env()`가 호출될 때 해당 binary가 실행됩니다.
과거 firmware loading이 sysfs mechanism으로만 가능했을 때 userspace의 `hotplug`가 kobject event monitor 기능을 제공했습니다. 이후 systemd의 udev가 이를 대체했지만, systemd v217의 2014년 8월 commit `be2ea723b1d0`(`udev: remove userspace firmware loading support`)에서 udev의 firmware loading 지원이 제거됐습니다.
따라서 오늘날 대부분의 Linux distribution은 kobject uevent가 제공하는 firmware fallback mechanism을 사용하지 않습니다. 대부분이 `CONFIG_FW_LOADER_USER_HELPER_FALLBACK`도 끄기 때문에 이 상황이 더 뚜렷합니다.
Kobject event variable 설정은 `do_firmware_uevent()`를 참고합니다. `kobject add` event와 함께 userspace로 전달되는 변수는 다음과 같습니다.
Firmware fallback 시작을 알릴 때 userspace가 받는 환경변수입니다.
아래는 간단한 kobject uevent script 예입니다. `DEVPATH`와 `FIRMWARE`는 이미 environment에 제공됩니다.
# 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
Custom fallback mechanism
164-188`request_firmware_nowait()` 사용자는 sysfs fallback mechanism을 사용하되 userspace로 kobject uevent를 보내지 않도록 요청할 수 있습니다.
이 option의 원래 목적은 udev 이외의 utility가 `Direct filesystem lookup` 절의 목록 밖에 있는 비전통적인 path에서 firmware를 찾아야 하는 경우를 지원하는 것이었습니다. 다른 firmware API call은 uevent를 항상 강제하므로 이 option을 사용할 수 없습니다.
Uevent는 kernel에 fallback mechanism이 활성화된 경우에만 의미가 있습니다. 하지만 `request_firmware_nowait()`이 끌 수 있는 `uevent` flag는 firmware request의 firmware cache 설정에도 사용됩니다. 앞서 설명했듯 API call에 uevent가 켜진 경우에만 firmware cache를 구성합니다.
이 때문에 `request_firmware_nowait()`에서 firmware cache가 비활성화될 수 있지만, cache를 끄는 목적으로 이 API flag를 사용해서는 안 됩니다. 그것은 flag의 원래 목적이 아닙니다.
`uevent` flag를 설정하지 않는다는 것은 firmware fallback mechanism을 opt-in하면서 kobject uevent는 억제하겠다는 뜻입니다. 즉 별도 방식으로 device hierarchy의 device 추가를 monitor하고 custom path를 통해 firmware를 load하는 custom solution이 있다는 의미입니다.
Flag는 notification뿐 아니라 firmware cache 구성에도 영향을 줍니다.
Firmware fallback timeout
189-206Firmware fallback mechanism에는 timeout이 있습니다. Timeout 값 안에 sysfs interface로 firmware를 load하지 못하면 driver에 error를 보냅니다.
Uevent가 필요한 경우 기본 timeout은 60초입니다. Uevent를 사용하지 않으면 가능한 최대 timeout인 `MAX_JIFFY_OFFSET`을 사용합니다. Custom solution에는 firmware를 load하는 데 필요한 만큼 시간을 주려는 설계입니다.
원하는 timeout을 다음 file에 echo하여 값을 바꿀 수 있습니다.
- `/sys/class/firmware/timeout`
0을 쓰면 `MAX_JIFFY_OFFSET`을 사용한다는 뜻입니다. Timeout의 data type은 `int`입니다.
Uevent 사용 여부와 sysfs 설정값에 따른 timeout입니다.
EFI embedded firmware fallback
207-224일부 device에서는 system의 EFI code 또는 ROM에 integrated peripheral device용 firmware 사본이 내장되어 있고, 해당 peripheral의 Linux device driver가 이 firmware에 접근해야 합니다.
이런 firmware가 필요한 driver는 `firmware_request_platform()`을 사용할 수 있습니다. 이는 다른 fallback mechanism과 별개이며 sysfs interface를 사용하지 않습니다.
Device driver는 필요한 firmware를 `efi_embedded_fw_desc` struct로 기술합니다.
.. kernel-doc:: include/linux/efi_embedded_fw.h
:functions: efi_embedded_fw_desc
EFI firmware 검색과 driver 등록
225-250EFI embedded-fw code는 모든 `EFI_BOOT_SERVICES_CODE` memory segment를 scan해 `prefix`와 일치하는 8-byte sequence를 찾습니다. Prefix를 찾으면 `length` byte에 SHA-256을 계산하고, 값이 일치하면 `length` byte를 복사해 발견한 firmware 목록에 추가합니다.
모든 system에서 이 비교적 비싼 scan을 실행하지 않도록 DMI matching을 사용합니다. Driver는 `dmi_system_id` array를 export해야 하며 각 entry의 `driver_data`가 `efi_embedded_fw_desc`를 가리켜야 합니다.
이 array를 efi-embedded-fw code에 등록하려면 driver가 다음 작업을 해야 합니다.
- 항상 kernel built-in이거나 `dmi_system_id` array를 항상 built-in되는 별도 object file에 저장합니다.
- `include/linux/efi_embedded_fw.h`에 `dmi_system_id` array의 extern declaration을 추가합니다.
- `drivers/firmware/efi/embedded-firmware.c`의 `embedded_fw_table`에 array를 추가하고 driver가 built-in인지 검사하는 `#ifdef`로 감쌉니다.
- Kconfig entry에 `select EFI_EMBEDDED_FIRMWARE if EFI_STUB`을 추가합니다.
`firmware_request_platform()`은 항상 지정된 이름으로 disk에서 firmware를 먼저 직접 load합니다. 따라서 `/lib/firmware` 아래에 file을 두면 EFI embedded-fw를 언제든 override할 수 있습니다.
DMI match 뒤 EFI memory에서 firmware를 식별하고 보관하는 절차입니다.
EFI embedded-fw 제약
251-277EFI embedded firmware 사용 시 다음 사항에 유의해야 합니다.
- Scan code는 `start_kernel()` 끝부분에서 `rest_init()` 호출 직전에 실행됩니다. `subsys_initcall()`로 등록하는 일반 driver와 subsystem에는 문제가 없지만 그보다 먼저 실행되는 code는 EFI embedded-firmware를 사용할 수 없습니다.
- 현재 EFI embedded-fw code는 firmware가 항상 8-byte 배수 offset에서 시작한다고 가정합니다. 해당하지 않는 사례라면 이를 수정하는 patch가 필요합니다.
- 다른 architecture는 scan 전에 `EFI_BOOT_SERVICES_CODE`를 free하므로 현재 x86에서만 동작합니다.
- 현재의 `EFI_BOOT_SERVICES_CODE` brute-force scan은 ad-hoc solution입니다. UEFI Platform Initialization(PI) spec의 Firmware Volume(FV) protocol 사용도 논의됐지만 거부됐습니다.
- PI spec은 peripheral firmware를 정의하지 않고, PI spec의 internal interface는 backward compatibility를 보장하지 않습니다. FV implementation detail은 바뀌거나 system마다 다를 수 있어, 일부러 모호하게 정의된 FV Protocol을 지원하기 어렵습니다.
Embedded firmware 확인과 추출 예
278-308Silead touchscreen controller의 embedded firmware를 확인하고 추출하는 예는 다음과 같습니다.
- Kernel command line에 `efi=debug`를 지정해 system을 boot합니다.
- `/sys/kernel/debug/efi/boot_services_code?`를 home directory로 복사합니다.
- Hex editor로 `boot_services_code?` file을 열고 Silead firmware magic prefix `F0 00 00 00 02 00 00 00`을 찾습니다. 이 위치가 file 내부 firmware 시작 address입니다.
- Firmware는 8-byte page address로 시작하고, 일반적으로 첫 page는 위 prefix를 사용합니다. 그 뒤에는 32-bit word address와 32-bit value pair가 이어지며 word address는 page가 찰 때까지 pair마다 4 byte씩 증가합니다. 새 page address와 pair가 반복되는 뚜렷한 pattern이 멈추는 곳이 firmware 끝입니다.
다음 `dd` 명령으로 firmware를 추출합니다.
5. "dd if=boot_services_code? of=firmware bs=1 skip=<begin-addr> count=<len>"
Hex editor로 추출한 firmware file을 확인해 `dd` parameter가 올바른지 검증합니다.
- 테스트를 위해 예상 이름으로 `/lib/firmware`에 복사합니다.
- 추출한 firmware가 동작하면 발견한 정보를 `efi_embedded_fw_desc` struct에 채웁니다. `sha256sum firmware`를 실행해 `sha256` field에 넣을 SHA-256 값을 얻습니다.
Debug memory dump에서 firmware 경계를 찾고 검증·등록하는 순서입니다.
요약과 해설
fallback-mechanisms.rst:1-308Direct filesystem lookup이 실패하면 firmware loader는 공통 sysfs loading interface를 기반으로 kobject uevent 또는 custom fallback을 사용할 수 있습니다. Userspace는 `loading`과 `data` attribute로 firmware를 전달하며, kernel 설정과 `request_firmware_nowait()`의 `uevent` flag가 notification과 cache 동작을 좌우합니다.
별도의 EFI embedded firmware fallback은 sysfs를 사용하지 않습니다. DMI match와 EFI memory prefix·SHA-256 scan으로 firmware를 찾아 `firmware_request_platform()`에 제공하며, x86·실행 시점·정렬 같은 제약이 있습니다.