lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <tbflj3r6picnz7pzhiz77gzhrdnmfxlruhtas4rfrvm27dapss@3wqf4dd2lmsx>
Date: Mon, 8 Sep 2025 11:25:53 -0500
From: Lucas De Marchi <lucas.demarchi@...el.com>
To: Badal Nilawar <badal.nilawar@...el.com>
CC: <intel-xe@...ts.freedesktop.org>, <dri-devel@...ts.freedesktop.org>,
	<linux-kernel@...r.kernel.org>, <anshuman.gupta@...el.com>,
	<rodrigo.vivi@...el.com>, <alexander.usyskin@...el.com>,
	<gregkh@...uxfoundation.org>, <daniele.ceraolospurio@...el.com>,
	<mika.westerberg@...ux.intel.com>, <karthik.poosa@...el.com>
Subject: Re: [PATCH v9 2/9] mei: late_bind: add late binding component driver

On Fri, Sep 05, 2025 at 09:19:46PM +0530, Badal Nilawar wrote:
>From: Alexander Usyskin <alexander.usyskin@...el.com>
>
>Introduce a new MEI client driver to support Late Binding firmware
>upload/update for Intel discrete graphics platforms.
>
>Late Binding is a runtime firmware upload/update mechanism that allows
>payloads, such as fan control and voltage regulator, to be securely
>delivered and applied without requiring SPI flash updates or
>system reboots. This driver enables the Xe graphics driver and other
>user-space tools to push such firmware blobs to the authentication
>firmware via the MEI interface.
>
>The driver handles authentication, versioning, and communication
>with the authentication firmware, which in turn coordinates with
>the PUnit/PCODE to apply the payload.
>
>This is a foundational component for enabling dynamic, secure,
>and re-entrant configuration updates on platforms like Battlemage.
>
>Cc: Badal Nilawar <badal.nilawar@...el.com>
>Reviewed-by: Mika Westerberg <mika.westerberg@...ux.intel.com>
>Signed-off-by: Badal Nilawar <badal.nilawar@...el.com>
>Reviewed-by: Anshuman Gupta <anshuman.gupta@...el.com>
>Signed-off-by: Rodrigo Vivi <rodrigo.vivi@...el.com>
>Signed-off-by: Alexander Usyskin <alexander.usyskin@...el.com>
>---
> drivers/misc/mei/Kconfig                   |  13 +
> drivers/misc/mei/Makefile                  |   1 +
> drivers/misc/mei/mei_lb.c                  | 312 +++++++++++++++++++++
> include/drm/intel/i915_component.h         |   1 +
> include/drm/intel/intel_lb_mei_interface.h |  70 +++++
> 5 files changed, 397 insertions(+)
> create mode 100644 drivers/misc/mei/mei_lb.c
> create mode 100644 include/drm/intel/intel_lb_mei_interface.h
>
>diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig
>index 7575fee96cc6..f8b04e49e4ba 100644
>--- a/drivers/misc/mei/Kconfig
>+++ b/drivers/misc/mei/Kconfig
>@@ -81,6 +81,19 @@ config INTEL_MEI_VSC
> 	  This driver can also be built as a module. If so, the module
> 	  will be called mei-vsc.
>
>+config INTEL_MEI_LB
>+	tristate "Intel Late Binding (LB) support on ME Interface"
>+	depends on INTEL_MEI_ME
>+	depends on DRM_XE
>+	help
>+	  Enable support for Intel Late Binding (LB) via the MEI interface.
>+
>+	  Late Binding is a method for applying firmware updates at runtime,
>+	  allowing the Intel Xe driver to load firmware payloads such as
>+	  fan controller or voltage regulator. These firmware updates are
>+	  authenticated and versioned, and do not require firmware flashing
>+	  or system reboot.
>+
> source "drivers/misc/mei/hdcp/Kconfig"
> source "drivers/misc/mei/pxp/Kconfig"
> source "drivers/misc/mei/gsc_proxy/Kconfig"
>diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile
>index 6f9fdbf1a495..a203ed766b33 100644
>--- a/drivers/misc/mei/Makefile
>+++ b/drivers/misc/mei/Makefile
>@@ -31,6 +31,7 @@ CFLAGS_mei-trace.o = -I$(src)
> obj-$(CONFIG_INTEL_MEI_HDCP) += hdcp/
> obj-$(CONFIG_INTEL_MEI_PXP) += pxp/
> obj-$(CONFIG_INTEL_MEI_GSC_PROXY) += gsc_proxy/
>+obj-$(CONFIG_INTEL_MEI_LB) += mei_lb.o
>
> obj-$(CONFIG_INTEL_MEI_VSC_HW) += mei-vsc-hw.o
> mei-vsc-hw-y := vsc-tp.o
>diff --git a/drivers/misc/mei/mei_lb.c b/drivers/misc/mei/mei_lb.c
>new file mode 100644
>index 000000000000..77686b108d3c
>--- /dev/null
>+++ b/drivers/misc/mei/mei_lb.c
>@@ -0,0 +1,312 @@
>+// SPDX-License-Identifier: GPL-2.0
>+/*
>+ * Copyright (C) 2025 Intel Corporation
>+ */
>+
>+#include <linux/component.h>
>+#include <linux/mei_cl_bus.h>
>+#include <linux/module.h>
>+#include <linux/overflow.h>
>+#include <linux/pci.h>
>+#include <linux/slab.h>
>+#include <linux/uuid.h>
>+
>+#include <drm/intel/i915_component.h>
>+#include <drm/intel/intel_lb_mei_interface.h>
>+
>+#include "mkhi.h"
>+
>+/**
>+ * DOC: Late Binding Firmware Update/Upload
>+ *
>+ * Late Binding is a firmware update/upload mechanism that allows configuration
>+ * payloads to be securely delivered and applied at runtime, rather than
>+ * being embedded in the system firmware image (e.g., IFWI or SPI flash).
>+ *
>+ * This mechanism is used to update device-level configuration such as:
>+ * - Fan controller
>+ * - Voltage regulator (VR)
>+ *
>+ * Key Characteristics:
>+ * ---------------------
>+ * - Runtime Delivery:
>+ *   Firmware blobs are loaded by the host driver (e.g., Xe KMD)
>+ *   after the GPU or SoC has booted.
>+ *
>+ * - Secure and Authenticated:
>+ *   All payloads are signed and verified by the authentication firmware.
>+ *
>+ * - No Firmware Flashing Required:
>+ *   Updates are applied in volatile memory and do not require SPI flash
>+ *   modification or system reboot.
>+ *
>+ * - Re-entrant:
>+ *   Multiple updates of the same or different types can be applied
>+ *   sequentially within a single boot session.
>+ *
>+ * - Version Controlled:
>+ *   Each payload includes version and security version number (SVN)
>+ *   metadata to support anti-rollback enforcement.
>+ *
>+ * Upload Flow:
>+ * ------------
>+ * 1. Host driver (KMD or user-space tool) loads the late binding firmware.
>+ * 2. Firmware is passed to the MEI interface and forwarded to
>+ *    authentication firmware.
>+ * 3. Authentication firmware authenticates the payload and extracts
>+ *    command and data arrays.
>+ * 4. Authentication firmware delivers the configuration to PUnit/PCODE.
>+ * 5. Status is returned back to the host via MEI.
>+ */
>+
>+#define INTEL_LB_CMD	0x12
>+#define INTEL_LB_RSP	(INTEL_LB_CMD | 0x80)
>+
>+#define INTEL_LB_SEND_TIMEOUT_MSEC 3000
>+#define INTEL_LB_RECV_TIMEOUT_MSEC 3000
>+
>+/**
>+ * struct mei_lb_req - Late Binding request structure
>+ * @header: MKHI message header (see struct mkhi_msg_hdr)
>+ * @type: Type of the Late Binding payload
>+ * @flags: Flags to be passed to the authentication firmware (e.g. %INTEL_LB_FLAGS_IS_PERSISTENT)
>+ * @reserved: Reserved for future use by authentication firmware, must be set to 0
>+ * @payload_size: Size of the payload data in bytes
>+ * @payload: Payload data to be sent to the authentication firmware
>+ */
>+struct mei_lb_req {
>+	struct mkhi_msg_hdr header;
>+	__le32 type;
>+	__le32 flags;
>+	__le32 reserved[2];
>+	__le32 payload_size;
>+	u8 payload[] __counted_by(payload_size);
>+} __packed;
>+
>+/**
>+ * struct mei_lb_rsp - Late Binding response structure
>+ * @header: MKHI message header (see struct mkhi_msg_hdr)
>+ * @type: Type of the Late Binding payload
>+ * @reserved: Reserved for future use by authentication firmware, must be set to 0
>+ * @status: Status returned by authentication firmware (see &enum intel_lb_status)
>+ */
>+struct mei_lb_rsp {
>+	struct mkhi_msg_hdr header;
>+	__le32 type;
>+	__le32 reserved[2];
>+	__le32 status;
>+} __packed;
>+
>+static bool mei_lb_check_response(const struct device *dev, ssize_t bytes,
>+				  struct mei_lb_rsp *rsp)
>+{
>+	/*
>+	 * Received message size may be smaller than the full message size when
>+	 * reply contains only MKHI header with result field set to the error code.
>+	 * Check the header size and content first to output exact error, if needed,
>+	 * and then process to the whole message.
>+	 */
>+	if (bytes < sizeof(rsp->header)) {
>+		dev_err(dev, "Received less than header size from the firmware: %zd < %zu\n",
>+			bytes, sizeof(rsp->header));
>+		return false;
>+	}
>+	if (rsp->header.group_id != MKHI_GROUP_ID_GFX) {
>+		dev_err(dev, "Mismatch group id: 0x%x instead of 0x%x\n",
>+			rsp->header.group_id, MKHI_GROUP_ID_GFX);
>+		return false;
>+	}
>+	if (rsp->header.command != INTEL_LB_RSP) {
>+		dev_err(dev, "Mismatch command: 0x%x instead of 0x%x\n",
>+			rsp->header.command, INTEL_LB_RSP);
>+		return false;
>+	}
>+	if (rsp->header.result) {
>+		dev_err(dev, "Error in result: 0x%x\n", rsp->header.result);
>+		return false;
>+	}
>+	if (bytes < sizeof(*rsp)) {
>+		dev_err(dev, "Received less than message size from the firmware: %zd < %zu\n",
>+			bytes, sizeof(*rsp));
>+		return false;
>+	}
>+
>+	return true;
>+}
>+
>+static int mei_lb_push_payload(struct device *dev,
>+			       enum intel_lb_type type, u32 flags,
>+			       const void *payload, size_t payload_size)
>+{
>+	struct mei_cl_device *cldev;
>+	struct mei_lb_req *req = NULL;
>+	struct mei_lb_rsp rsp;
>+	size_t req_size;
>+	ssize_t bytes;
>+	int ret;
>+
>+	cldev = to_mei_cl_device(dev);
>+
>+	ret = mei_cldev_enable(cldev);
>+	if (ret) {
>+		dev_dbg(dev, "Failed to enable firmware client. %d\n", ret);
>+		return ret;
>+	}
>+
>+	req_size = struct_size(req, payload, payload_size);
>+	if (req_size > mei_cldev_mtu(cldev)) {
>+		dev_err(dev, "Payload is too big: %zu\n", payload_size);
>+		ret = -EMSGSIZE;
>+		goto end;
>+	}
>+
>+	req = kmalloc(req_size, GFP_KERNEL);
>+	if (!req) {
>+		ret = -ENOMEM;
>+		goto end;
>+	}
>+
>+	req->header.group_id = MKHI_GROUP_ID_GFX;
>+	req->header.command = INTEL_LB_CMD;
>+	req->type = cpu_to_le32(type);
>+	req->flags = cpu_to_le32(flags);
>+	req->reserved[0] = 0;
>+	req->reserved[1] = 0;
>+	req->payload_size = cpu_to_le32(payload_size);
>+	memcpy(req->payload, payload, payload_size);
>+
>+	bytes = mei_cldev_send_timeout(cldev, (u8 *)req, req_size,
>+				       INTEL_LB_SEND_TIMEOUT_MSEC);
>+	if (bytes < 0) {
>+		dev_err(dev, "Failed to send late binding request to firmware. %zd\n", bytes);
>+		ret = bytes;
>+		goto end;
>+	}
>+
>+	bytes = mei_cldev_recv_timeout(cldev, (u8 *)&rsp, sizeof(rsp),
>+				       INTEL_LB_RECV_TIMEOUT_MSEC);
>+	if (bytes < 0) {
>+		dev_err(dev, "Failed to receive late binding reply from MEI firmware. %zd\n",
>+			bytes);
>+		ret = bytes;
>+		goto end;
>+	}
>+	if (!mei_lb_check_response(dev, bytes, &rsp)) {
>+		dev_err(dev, "Bad response from the firmware. header: %02x %02x %02x %02x\n",
>+			rsp.header.group_id, rsp.header.command,
>+			rsp.header.reserved, rsp.header.result);
>+		ret = -EPROTO;
>+		goto end;
>+	}
>+
>+	dev_dbg(dev, "status = %u\n", le32_to_cpu(rsp.status));
>+	ret = (int)le32_to_cpu(rsp.status);
>+end:
>+	mei_cldev_disable(cldev);
>+	kfree(req);
>+	return ret;
>+}
>+
>+static const struct intel_lb_component_ops mei_lb_ops = {
>+	.push_payload = mei_lb_push_payload,
>+};
>+
>+static int mei_lb_component_master_bind(struct device *dev)
>+{
>+	return component_bind_all(dev, (void *)&mei_lb_ops);
>+}
>+
>+static void mei_lb_component_master_unbind(struct device *dev)
>+{
>+	component_unbind_all(dev, (void *)&mei_lb_ops);
>+}
>+
>+static const struct component_master_ops mei_lb_component_master_ops = {
>+	.bind = mei_lb_component_master_bind,
>+	.unbind = mei_lb_component_master_unbind,
>+};
>+
>+static int mei_lb_component_match(struct device *dev, int subcomponent,
>+				  void *data)
>+{
>+	/*
>+	 * This function checks if requester is Intel %PCI_CLASS_DISPLAY_VGA or
>+	 * %PCI_CLASS_DISPLAY_OTHER device, and checks if the requester is the
>+	 * grand parent of mei_if i.e. late bind MEI device
>+	 */
>+	struct device *base = data;
>+	struct pci_dev *pdev;
>+
>+	if (!dev)
>+		return 0;
>+
>+	if (!dev_is_pci(dev))
>+		return 0;
>+
>+	pdev = to_pci_dev(dev);
>+
>+	if (pdev->vendor != PCI_VENDOR_ID_INTEL)
>+		return 0;
>+
>+	if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8) &&
>+	    pdev->class != (PCI_CLASS_DISPLAY_OTHER << 8))

this doesn't seem right, we should allow other PCI classes. AFAICS this
check could just be removed and just leave the INTEL_COMPONENT_LB below
to protect for component match

Lucas De Marchi

>+		return 0;
>+
>+	if (subcomponent != INTEL_COMPONENT_LB)
>+		return 0;
>+
>+	base = base->parent;
>+	if (!base) /* mei device */
>+		return 0;
>+
>+	base = base->parent; /* pci device */
>+
>+	return !!base && dev == base;
>+}
>+
>+static int mei_lb_probe(struct mei_cl_device *cldev,
>+			const struct mei_cl_device_id *id)
>+{
>+	struct component_match *master_match = NULL;
>+	int ret;
>+
>+	component_match_add_typed(&cldev->dev, &master_match,
>+				  mei_lb_component_match, &cldev->dev);
>+	if (IS_ERR_OR_NULL(master_match))
>+		return -ENOMEM;
>+
>+	ret = component_master_add_with_match(&cldev->dev,
>+					      &mei_lb_component_master_ops,
>+					      master_match);
>+	if (ret < 0)
>+		dev_err(&cldev->dev, "Failed to add late binding master component. %d\n", ret);
>+
>+	return ret;
>+}
>+
>+static void mei_lb_remove(struct mei_cl_device *cldev)
>+{
>+	component_master_del(&cldev->dev, &mei_lb_component_master_ops);
>+}
>+
>+#define MEI_GUID_MKHI UUID_LE(0xe2c2afa2, 0x3817, 0x4d19, \
>+			      0x9d, 0x95, 0x6, 0xb1, 0x6b, 0x58, 0x8a, 0x5d)
>+
>+static const struct mei_cl_device_id mei_lb_tbl[] = {
>+	{ .uuid = MEI_GUID_MKHI, .version = MEI_CL_VERSION_ANY },
>+	{ }
>+};
>+MODULE_DEVICE_TABLE(mei, mei_lb_tbl);
>+
>+static struct mei_cl_driver mei_lb_driver = {
>+	.id_table = mei_lb_tbl,
>+	.name = "mei_lb",
>+	.probe = mei_lb_probe,
>+	.remove	= mei_lb_remove,
>+};
>+
>+module_mei_cl_driver(mei_lb_driver);
>+
>+MODULE_AUTHOR("Intel Corporation");
>+MODULE_LICENSE("GPL");
>+MODULE_DESCRIPTION("MEI Late Binding Firmware Update/Upload");
>diff --git a/include/drm/intel/i915_component.h b/include/drm/intel/i915_component.h
>index 4ea3b17aa143..8082db222e00 100644
>--- a/include/drm/intel/i915_component.h
>+++ b/include/drm/intel/i915_component.h
>@@ -31,6 +31,7 @@ enum i915_component_type {
> 	I915_COMPONENT_HDCP,
> 	I915_COMPONENT_PXP,
> 	I915_COMPONENT_GSC_PROXY,
>+	INTEL_COMPONENT_LB,
> };
>
> /* MAX_PORT is the number of port
>diff --git a/include/drm/intel/intel_lb_mei_interface.h b/include/drm/intel/intel_lb_mei_interface.h
>new file mode 100644
>index 000000000000..d65be2cba2ab
>--- /dev/null
>+++ b/include/drm/intel/intel_lb_mei_interface.h
>@@ -0,0 +1,70 @@
>+/* SPDX-License-Identifier: MIT */
>+/*
>+ * Copyright (c) 2025 Intel Corporation
>+ */
>+
>+#ifndef _INTEL_LB_MEI_INTERFACE_H_
>+#define _INTEL_LB_MEI_INTERFACE_H_
>+
>+#include <linux/types.h>
>+
>+struct device;
>+
>+/**
>+ * define INTEL_LB_FLAG_IS_PERSISTENT - Mark the payload as persistent
>+ *
>+ * This flag indicates that the late binding payload should be stored
>+ * persistently in flash across warm resets.
>+ */
>+#define INTEL_LB_FLAG_IS_PERSISTENT	BIT(0)
>+
>+/**
>+ * enum intel_lb_type - enum to determine late binding payload type
>+ * @INTEL_LB_TYPE_FAN_CONTROL: Fan controller configuration
>+ */
>+enum intel_lb_type {
>+	INTEL_LB_TYPE_FAN_CONTROL = 1,
>+};
>+
>+/**
>+ * enum intel_lb_status - Status codes returned on late binding transmissions
>+ * @INTEL_LB_STATUS_SUCCESS: Operation completed successfully
>+ * @INTEL_LB_STATUS_4ID_MISMATCH: Mismatch in the expected 4ID (firmware identity/token)
>+ * @INTEL_LB_STATUS_ARB_FAILURE: Arbitration failure (e.g. conflicting access or state)
>+ * @INTEL_LB_STATUS_GENERAL_ERROR: General firmware error not covered by other codes
>+ * @INTEL_LB_STATUS_INVALID_PARAMS: One or more input parameters are invalid
>+ * @INTEL_LB_STATUS_INVALID_SIGNATURE: Payload has an invalid or untrusted signature
>+ * @INTEL_LB_STATUS_INVALID_PAYLOAD: Payload contents are not accepted by firmware
>+ * @INTEL_LB_STATUS_TIMEOUT: Operation timed out before completion
>+ */
>+enum intel_lb_status {
>+	INTEL_LB_STATUS_SUCCESS           = 0,
>+	INTEL_LB_STATUS_4ID_MISMATCH      = 1,
>+	INTEL_LB_STATUS_ARB_FAILURE       = 2,
>+	INTEL_LB_STATUS_GENERAL_ERROR     = 3,
>+	INTEL_LB_STATUS_INVALID_PARAMS    = 4,
>+	INTEL_LB_STATUS_INVALID_SIGNATURE = 5,
>+	INTEL_LB_STATUS_INVALID_PAYLOAD   = 6,
>+	INTEL_LB_STATUS_TIMEOUT           = 7,
>+};
>+
>+/**
>+ * struct intel_lb_component_ops - Ops for late binding services
>+ */
>+struct intel_lb_component_ops {
>+	/**
>+	 * push_payload - Sends a payload to the authentication firmware
>+	 * @dev: Device struct corresponding to the mei device
>+	 * @type: Payload type (see &enum intel_lb_type)
>+	 * @flags: Payload flags bitmap (e.g. %INTEL_LB_FLAGS_IS_PERSISTENT)
>+	 * @payload: Pointer to payload buffer
>+	 * @payload_size: Payload buffer size in bytes
>+	 *
>+	 * Return: 0 success, negative errno value on transport failure,
>+	 *         positive status returned by firmware
>+	 */
>+	int (*push_payload)(struct device *dev, u32 type, u32 flags,
>+			    const void *payload, size_t payload_size);
>+};
>+
>+#endif /* _INTEL_LB_MEI_INTERFACE_H_ */
>-- 
>2.34.1
>

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ