Introduce Platform Firmware Runtime Update and Telemetry drivers
Subsystems (4)
v2 cover Introduce Platform Firmware Runtime Update and Telemetry drivers
High Service Level Agreements (SLAs) requires that the system runs without service interruptions. Generally, system firmware provides runtime services such as RAS(Reliability, Availability and Serviceability) features, UEFI runtime services and ACPI services. Currently if there is any firmware code changes in these code area, the system firmware update and reboot is required. Example of bug fix could be wrong register size or location of the register. This means customer services are not available during the firmware upgrade, which could approach several minutes, resulting in not able to meet SLAs.
Intel provides a mechanism named Management Mode Runtime Update to help the users update the firmware without having to reboot[1].
This series provides the following facilities.
1. Perform a runtime firmware driver update and activate.
2. Ability to inject firmware code at runtime, for dynamic instrumentation.
3. Facility to retrieve logs from runtime firmware update and activate telemetry. (The telemetry is based on runtime firmware update: it records the logs during runtime update(code injection and driver update).
The Management Mode Runtime Update OS Interface Specification[1] provides two ACPI device objects to interface with system firmware to perform these updates. This patch series introduces the drivers for those ACPI devices.
[1] https://uefi.org/sites/default/files/resources/Intel_MM_OS_Interface_Spec_Rev100.pdf
Chen Yu (5):
Documentation: Introduce Platform Firmware Runtime Update
documentation
efi: Introduce EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and
corresponding structures
drivers/acpi: Introduce Platform Firmware Runtime Update device driver drivers/acpi: Introduce Platform Firmware Runtime Update Telemetry selftests/pfru: add test for Platform Firmware Runtime Update and
Telemetry
.../userspace-api/ioctl/ioctl-number.rst | 1 + Documentation/x86/index.rst | 1 + Documentation/x86/pfru.rst | 100 +++ drivers/acpi/Kconfig | 1 + drivers/acpi/Makefile | 1 + drivers/acpi/pfru/Kconfig | 29 + drivers/acpi/pfru/Makefile | 3 + drivers/acpi/pfru/pfru_telemetry.c | 412 +++++++++++++ drivers/acpi/pfru/pfru_update.c | 567 ++++++++++++++++++ include/linux/efi.h | 50 ++ include/uapi/linux/pfru.h | 151 +++++ tools/testing/selftests/Makefile | 1 + tools/testing/selftests/pfru/Makefile | 7 + tools/testing/selftests/pfru/config | 2 + tools/testing/selftests/pfru/pfru_test.c | 329 ++++++++++ 15 files changed, 1655 insertions(+) create mode 100644 Documentation/x86/pfru.rst create mode 100644 drivers/acpi/pfru/Kconfig create mode 100644 drivers/acpi/pfru/Makefile create mode 100644 drivers/acpi/pfru/pfru_telemetry.c create mode 100644 drivers/acpi/pfru/pfru_update.c create mode 100644 include/uapi/linux/pfru.h create mode 100644 tools/testing/selftests/pfru/Makefile create mode 100644 tools/testing/selftests/pfru/config create mode 100644 tools/testing/selftests/pfru/pfru_test.c
Signature · 1 line
2.25.1
PATCH v2 1/5 Documentation: Introduce Platform Firmware Runtime Update documentation
Add the Platform Firmware Runtime Update/Telemetry documentation.
---
v2: Add a spot in index.rst so it becomes part of the docs build
(Jonathan Corbet).
Sticking to the 80-column limit(Jonathan Corbet). Underline lengths should match the title text(Jonathan Corbet). Use literal blocks for the code samples(Jonathan Corbet).
--- Documentation/x86/index.rst | 1 + Documentation/x86/pfru.rst | 100 ++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 Documentation/x86/pfru.rst
Documentation/x86/index.rst +1 -0
@@ -37,3 +37,4 @@ x86-specific Documentation sgx features elf_auxvec + pfru
Documentation/x86/pfru.rst new file +100 -0
100 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v2 2/5 efi: Introduce EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and corresponding structures
In reply to Chen YuPlatform Firmware Runtime Update image starts with UEFI headers, and the headers are defined in UEFI specification, but some of them have not been defined in the kernel yet.
For example, the header layout of a capsule file looks like this:
EFI_CAPSULE_HEADEREFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADEREFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADEREFI_FIRMWARE_IMAGE_AUTHENTICATION
These structures would be used by the Platform Firmware Runtime Update driver to parse the format of capsule file to verify if the corresponding version number is valid. The EFI_CAPSULE_HEADER has been defined in the kernel, however the rest are not, thus introduce corresponding UEFI structures accordingly.
The reason why efi_manage_capsule_header_t and efi_manage_capsule_image_header_t are packedi might be that:
According to the uefi spec,
[Figure 23-6 Firmware Management and Firmware Image Management headers] EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER is located at the lowest offset within the body of the capsule. And this structure is designed to be unaligned to save space, because in this way the adjacent drivers and binary payload elements could start on byte boundary with no padding. And the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is at the head of each payload, so packing this structure also makes room for more data.
--- include/linux/efi.h | 50 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+)
include/linux/efi.h +50 -0
@@ -148,6 +148,56 @@ typedef struct {u32 imagesize; } efi_capsule_header_t; +#pragma pack(1) + +/* EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER */ +typedef struct { +u32 ver; +u16 emb_drv_cnt; +u16 payload_cnt; +/* +* Variable array indicated by number of +* (emb_drv_cnt + payload_cnt) +*/ +u64 offset_list[]; +}efi_manage_capsule_header_t ; + +/* EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER */ +typedef struct { +u32 ver; +guid_t image_type_id; +u8 image_index; +u8 reserved_bytes[3 ]; +u32 image_size; +u32 vendor_code_size; +/* ver = 2. */ +u64 hw_ins; +/* ver = v3. */ +u64 capsule_support; +}efi_manage_capsule_image_header_t ; + +#pragma pack() + +/* WIN_CERTIFICATE */ +typedef struct { +u32 len; +u16 rev; +u16 cert_type; +}win_cert_t ; + +/* WIN_CERTIFICATE_UEFI_GUID */ +typedef struct { +win_cert_t hdr; +guid_t cert_type; +u8 cert_data[]; +}win_cert_uefi_guid_t ; + +/* EFI_FIRMWARE_IMAGE_AUTHENTICATIO */ +typedef struct { +u64 mon_count; +win_cert_uefi_guid_t auth_info; +}efi_image_auth_t ; +/* * EFI capsule flags */
Signature · 1 line
2.25.1
PATCH v2 3/5 drivers/acpi: Introduce Platform Firmware Runtime Update device driver
In reply to Chen YuIntroduce the pfru_update driver which can be used for Platform Firmware Runtime code injection and driver update. The user is expected to provide the update firmware in the form of capsule file, and pass it to the driver via ioctl. Then the driver would hand this capsule file to the Platform Firmware Runtime Update via the ACPI device _DSM method. At last the low level Management Mode would do the firmware update.
---
v2: Add sanity check for duplicated instance of ACPI device.
Update the driver to work with allocated pfru_device objects. (Mike Rapoport)
For each switch case pair, get rid of the magic case numbers and add a default clause with the error handling.
(Mike Rapoport)
Move the obj->type checks outside the switch to reduce redundancy. (Mike Rapoport)
Parse the code_inj_id and drv_update_id at driver initialization time to reduce the re-parsing at runtime.
(Mike Rapoport)
Explain in detail how the size needs to be adjusted when doing version check.
(Mike Rapoport)
Rename parse_update_result() to dump_update_result() (Mike Rapoport)
Remove redundant return.
(Mike Rapoport)
Do not expose struct capsulate_buf_info to uapi, since it is not needed in userspace.
(Mike Rapoport)
--- .../userspace-api/ioctl/ioctl-number.rst | 1 + drivers/acpi/Kconfig | 1 + drivers/acpi/Makefile | 1 + drivers/acpi/pfru/Kconfig | 15 + drivers/acpi/pfru/Makefile | 2 + drivers/acpi/pfru/pfru_update.c | 567 ++++++++++++++++++ include/uapi/linux/pfru.h | 101 ++++ 7 files changed, 688 insertions(+) create mode 100644 drivers/acpi/pfru/Kconfig create mode 100644 drivers/acpi/pfru/Makefile create mode 100644 drivers/acpi/pfru/pfru_update.c create mode 100644 include/uapi/linux/pfru.h
Documentation/userspace-api/ioctl/ioctl-number.rst +1 -0
@@ -365,6 +365,7 @@ Code Seq# Include File Comments <mailto:[email protected]> 0xE5 00-3F linux/fuse.h 0xEC 00-01 drivers/platform/chrome/cros_ec_dev.h ChromeOS EC driver +0xEE 00-1F uapi/linux/pfru.h Platform Firmware Runtime Update and Telemetry 0xF3 00-3F drivers/usb/misc/sisusbvga/sisusb.h sisfb (in development) <mailto:[email protected]> 0xF6 all LTTng Linux Trace Toolkit Next Generation
drivers/acpi/Kconfig +1 -0
@@ -482,6 +482,7 @@ source "drivers/acpi/nfit/Kconfig" source "drivers/acpi/numa/Kconfig" source "drivers/acpi/apei/Kconfig" source "drivers/acpi/dptf/Kconfig" +source "drivers/acpi/pfru/Kconfig" config ACPI_WATCHDOG bool
drivers/acpi/Makefile +1 -0
@@ -102,6 +102,7 @@ obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o obj-$(CONFIG_ACPI_SPCR_TABLE) += spcr.o obj-$(CONFIG_ACPI_DEBUGGER_USER) += acpi_dbg.o obj-$(CONFIG_ACPI_PPTT) += pptt.o +obj-$(CONFIG_ACPI_PFRU) += pfru/ # processor has its own "processor." module_param namespace processor-y := processor_driver.o
drivers/acpi/pfru/Kconfig new file +15 -0
@@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0 +config ACPI_PFRU + tristate "ACPI Platform Firmware Runtime Update (PFRU)" + depends on 64BIT + help + In order to reduce the system reboot times and update the platform firmware + in time, Platform Firmware Runtime Update is leveraged to patch the system + without reboot. This driver supports Platform Firmware Runtime Update, + which is composed of two parts: code injection and driver update. + + For more information, see: + <file:Documentation/x86/pfru_update.rst> + + To compile this driver as a module, choose M here: + the module will be called pfru_update.
drivers/acpi/pfru/Makefile new file +2 -0
@@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_ACPI_PFRU) += pfru_update.o
drivers/acpi/pfru/pfru_update.c new file +567 -0
567 lines not on this page · raw message
include/uapi/linux/pfru.h new file +101 -0
101 lines not on this page · raw message
Signature · 1 line
2.25.1
Re: [PATCH v2 3/5] drivers/acpi: Introduce Platform Firmware Runtime Update device driver
Quoted 22 lines · Chen Yu
include/uapi/linux/pfru.h new file +22
-0+enum start_action { +START_STAGE , +START_ACTIVATE , +START_STAGE_ACTIVATE , +}; + +enum dsm_status { +DSM_SUCCEED , +DSM_FUNC_NOT_SUPPORT , +DSM_INVAL_INPUT , +DSM_HARDWARE_ERR , +DSM_RETRY_SUGGESTED , +DSM_UNKNOWN , +DSM_FUNC_SPEC_ERR , +}; + +struct update_cap_info { +enum dsm_status status; +int update_cap; + +uuid_t code_type; +int fw_version;
include/uapi/linux/pfru.h line 81
Quoted 10 lines
include/uapi/linux/pfru.h new file +10
-0+int code_rt_version; + +uuid_t drv_type; +int drv_rt_version; +int drv_svn; + +uuid_t platform_id; +uuid_t oem_id; + +char oem_info[];
Please use valid types for structures that cross the user/kernel boundry.
include/uapi/linux/pfru.h line 90
Quoted 9 lines
include/uapi/linux/pfru.h new file +9
-0+}; + +struct com_buf_info { +enum dsm_status status; +enum dsm_status ext_status; +unsigned long addr_lo; +unsigned long addr_hi; +int buf_size; +};
Same here.
include/uapi/linux/pfru.h line 98
Quoted 8 lines
include/uapi/linux/pfru.h new file +8
-0+ +struct updated_result { +enum dsm_status status; +enum dsm_status ext_status; +unsigned long low_auth_time; +unsigned long high_auth_time; +unsigned long low_exec_time; +unsigned long high_exec_time;
And same here.
And these are very odd structure names that you are adding to the "global" namespace. Please make them have a prefix for your driver so that people know what they belong to. "updated_result" is way too generic.
thanks,
greg k-h
Re: [PATCH v2 3/5] drivers/acpi: Introduce Platform Firmware Runtime Update device driver
Hi Greg,
thank you very much for your comments,
Quoted 28 lines · Greg Kroah-Hartman
Quoted 27 lines · Chen Yu
include/uapi/linux/pfru.h new file +27
-0+enum start_action { +START_STAGE , +START_ACTIVATE , +START_STAGE_ACTIVATE , +}; + +enum dsm_status { +DSM_SUCCEED , +DSM_FUNC_NOT_SUPPORT , +DSM_INVAL_INPUT , +DSM_HARDWARE_ERR , +DSM_RETRY_SUGGESTED , +DSM_UNKNOWN , +DSM_FUNC_SPEC_ERR , +}; + +struct update_cap_info { +enum dsm_status status; +int update_cap; + +uuid_t code_type; +int fw_version; +int code_rt_version; + +uuid_t drv_type; +int drv_rt_version; +int drv_svn;
Quoted 9 lines
include/uapi/linux/pfru.h line 81
Quoted 5 lines
include/uapi/linux/pfru.h new file +5
-0+ +uuid_t platform_id; +uuid_t oem_id; + +char oem_info[];Please use valid types for structures that cross the user/kernel boundry.
Okay, I'll switch them into __u prefixed one.
Quoted 12 lines
include/uapi/linux/pfru.h line 90
Quoted 9 lines
include/uapi/linux/pfru.h new file +9
-0+}; + +struct com_buf_info { +enum dsm_status status; +enum dsm_status ext_status; +unsigned long addr_lo; +unsigned long addr_hi; +int buf_size; +};Same here.
Okay, I'll fix them.
Quoted 11 lines
include/uapi/linux/pfru.h line 98
Quoted 8 lines
include/uapi/linux/pfru.h new file +8
-0+ +struct updated_result { +enum dsm_status status; +enum dsm_status ext_status; +unsigned long low_auth_time; +unsigned long high_auth_time; +unsigned long low_exec_time; +unsigned long high_exec_time;And same here.
Quoted 5 lines
And these are very odd structure names that you are adding to the "global" namespace. Please make them have a prefix for your driver so that people know what they belong to. "
updated_result" is way too generic.
Okay, added the driver name prefix in next version.
thanks,
Chenyu
PATCH v2 4/5 drivers/acpi: Introduce Platform Firmware Runtime Update Telemetry
In reply to Chen YuPlatform Firmware Runtime Update(PFRU) Telemetry Service is part of RoT (Root of Trust), which allows PFRU handler and other PFRU drivers to produce telemetry data to upper layer OS consumer at runtime.
The linux provides interfaces for the user to query the parameters of telemetry data, and the user could read out the telemetry data accordingly.
Typical log looks like:
[SmmRuntimeUpdateHandler.ProcessSmmRuntimeUpdate] ProcessSmmRuntimeUpdate = START, Action = 2 [SmmRuntimeUpdateHandler.ProcessSmmRuntimeUpdate]
FwVersion = 0, CodeInjectionVersion = 1 [ShadowSmmRuntimeUpdateImage]
Image = 0x74D9B000, ImageSize = 0x1172 [ProcessSmmRuntimeUpdate]
ShadowSmmRuntimeUpdateImage.Status = Success [ValidateSmmRuntimeUpdateImage]
CapsuleHeader.CapsuleGuid = 6DCBD5ED-E82D-4C44-BDA1-7194199AD92A [ValidateSmmRuntimeUpdateImage]
FmpCapHeader.Version = 1
[ValidateSmmRuntimeUpdateImage] FmpCapImageHeader.UpdateImageTypeId = B2F84B79-7B6E-4E45-885F-3FB9BB185402 [ValidateSmmRuntimeUpdateImage] SmmRuntimeUpdateVerifyImageWithDenylist.Status = Success [ValidateSmmRuntimeUpdateImage] SmmRuntimeUpdateVerifyImageWithAllowlist.Status = Success [SmmCodeInjectionVerifyPayloadHeader]
PayloadHeader.Signature = 0x31494353 [SmmCodeInjectionVerifyPayloadHeader]
PayloadHeader.PlatformId = 63462139-A8B1-AA4E-9024-F2BB53EA4723 [SmmCodeInjectionVerifyPayloadHeader] PayloadHeader.SupportedSmmFirmwareVersion = 0, PayloadHeader.SmmCodeInjectionRuntimeVersion = 1 [ProcessSmmRuntimeUpdate]
ValidateSmmRuntimeUpdateImage.Status = Success
CPU CSR[0B102D28] Before = 7FBF830E
CPU CSR[0B102D28] After = 7FBF8310
[ProcessSmmRuntimeUpdate] ProcessSmmCodeInjection.Status = Success [SmmRuntimeUpdateHandler.ProcessSmmRuntimeUpdate] ProcessSmmRuntimeUpdate = End, Status = Success
---
v2: Do similar clean up as pfru_update driver:
Add sanity check for duplicated instance of ACPI device. Update the driver to work with allocated telem_device objects. (Mike Rapoport)
For each switch case pair, get rid of the magic case numbers and add a default clause with the error handling. (Mike Rapoport)
--- drivers/acpi/pfru/Kconfig | 14 + drivers/acpi/pfru/Makefile | 1 + drivers/acpi/pfru/pfru_telemetry.c | 412 +++++++++++++++++++++++++++++ include/uapi/linux/pfru.h | 46 ++++ 4 files changed, 473 insertions(+) create mode 100644 drivers/acpi/pfru/pfru_telemetry.c
drivers/acpi/pfru/Kconfig +14 -0
@@ -13,3 +13,17 @@ config ACPI_PFRU To compile this driver as a module, choose M here: the module will be called pfru_update. + +config ACPI_PFRU_TELEMETRY + tristate "ACPI Platform Firmware Runtime Update Telemetry Service" + depends on ACPI_PFRU + help + PFRU(Platform Firmware Runtime Update) Telemetry Service is part of + RoT(Root of Trust), which allows Platform Firmware Runtime Update handler + and other PFRU drivers to produce telemetry data to upper layer OS consumer + at runtime. + + For more information, see: + <file:Documentation/x86/pfru_update.rst> + + If unsure, please say N.
drivers/acpi/pfru/Makefile +1 -0
@@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_ACPI_PFRU) += pfru_update.o +obj-$(CONFIG_ACPI_PFRU_TELEMETRY) += pfru_telemetry.o
drivers/acpi/pfru/pfru_telemetry.c new file +412 -0
412 lines not on this page · raw message
include/uapi/linux/pfru.h +46 -0
50 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v2 5/5 selftests/pfru: add test for Platform Firmware Runtime Update and Telemetry
In reply to Chen YuIntroduce a simple test for Platform Firmware Runtime Update and Telemetry drivers. It is based on ioctl to either update firmware driver or code injection, and read corresponding PFRU Telemetry log into user space.
For example:
./pfru_test -h
usage: pfru_test [OPTIONS]
code injection:
-l, --load
-s, --stage
-a, --activate
-u, --update [stage and activate]
-q, --query
-d, --revid update
telemetry:
-G, --getloginfo
-T, --type(0:execution, 1:history)
-L, --level(0, 1, 2, 4)
-R, --read
-D, --revid log
./pfru_test -G
log_level:4
log_type:0
log_revid:2
max_data_size:65536
chunk1_size:0
chunk2_size:1401
rollover_cnt:0
reset_cnt:4
./pfru_test -q
code injection image type:794bf8b2-6e7b-454e-885f-3fb9bb185402 fw_version:0
code_rt_version:1
driver update image type:0e5f0b14-f849-7945-ad81-bc7b6d2bb245 drv_rt_version:0
drv_svn:0
platform id:39214663-b1a8-4eaa-9024-f2bb53ea4723
oem id:a36db54f-ea2a-e14e-b7c4-b5780e51ba3d
launch the update:
./pfru_test -l yours.cap -u -T 1 -L 4
---
v2: Do not allow non-root user to run this test.
(Shuah Khan)
Test runs on platform without pfru_telemetry should skip instead of reporting failure/error.
(Shuah Khan)
Reuse uapi/linux/pfru.h instead of copying it into the test directory.
(Mike Rapoport)
--- include/uapi/linux/pfru.h | 4 + tools/testing/selftests/Makefile | 1 + tools/testing/selftests/pfru/Makefile | 7 + tools/testing/selftests/pfru/config | 2 + tools/testing/selftests/pfru/pfru_test.c | 329 +++++++++++++++++++++++ 5 files changed, 343 insertions(+) create mode 100644 tools/testing/selftests/pfru/Makefile create mode 100644 tools/testing/selftests/pfru/config create mode 100644 tools/testing/selftests/pfru/pfru_test.c
include/uapi/linux/pfru.h +4 -0
@@ -8,7 +8,11 @@#define __PFRU_H__#include <linux/ioctl.h> +#ifdef __KERNEL__#include <linux/uuid.h> +#else +#include <uuid/uuid.h> +#endif #define PFRU_UUID "ECF9533B-4A3C-4E89-939E-C77112601C6D"#define PFRU_CODE_INJ_UUID "B2F84B79-7B6E-4E45-885F-3FB9BB185402"
tools/testing/selftests/Makefile +1 -0
@@ -58,6 +58,7 @@ TARGETS += seccomp TARGETS += sgx TARGETS += sigaltstack TARGETS += size +TARGETS += pfru TARGETS += sparc64 TARGETS += splice TARGETS += static_keys
tools/testing/selftests/pfru/Makefile new file +7 -0
@@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0+ + +CFLAGS += -Wall -O2 +LDLIBS := -luuid + +TEST_GEN_PROGS := pfru_test +include ../lib.mk
tools/testing/selftests/pfru/config new file +2 -0
@@ -0,0 +1,2 @@ +CONFIG_ACPI_PFRU=m +CONFIG_ACPI_PFRU_TELEMETRY=m
tools/testing/selftests/pfru/pfru_test.c new file +329 -0
329 lines not on this page · raw message
Signature · 1 line
2.25.1