linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/7] Intel FPGA Security Manager Class Driver
@ 2020-10-02 22:36 Russ Weight
  2020-10-02 22:36 ` [PATCH v2 1/7] fpga: sec-mgr: intel fpga security manager class driver Russ Weight
                   ` (7 more replies)
  0 siblings, 8 replies; 25+ messages in thread
From: Russ Weight @ 2020-10-02 22:36 UTC (permalink / raw)
  To: mdf, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, yilun.xu, hao.wu, matthew.gerlach, Russ Weight

The Intel FPGA Security Manager class driver provides a common
API for user-space tools to manage updates for secure Intel FPGA
devices. Device drivers that instantiate the Intel Security
Manager class driver will interact with a HW secure update
engine in order to transfer new FPGA and BMC images to FLASH so
that they will be automatically loaded when the FPGA card reboots.

A significant difference between the FPGA Manager and the Intel FPGA 
Security Manager is that the FPGA Manager does a live update (Partial
Reconfiguration) to a device whereas the Intel FPGA Security Manager
updates the FLASH images for the Static Region and the BMC so that
they will be loaded the next time the FPGA card boots. Security is
enforced by hardware and firmware. The security manager interacts
with the firmware to initiate an update, pass in the necessary data,
and collect status on the update.

The n3000bmc-secure driver is the first driver to use the Intel FPG
Security Manager. This driver was previously submittied in the same
patch set, but has been split out in to a separate patch set for V2.
Follow-on Intel devices will also make use of this common API for
secure updates.

In addition to managing secure updates of the FPGA and BMC images,
the Intel FPGA Security Manager update process may also used to
program root entry hashes and cancellation keys for the FPGA static
region, the FPGA partial reconfiguration region, and the BMC.

Secure updates make use of the request_firmware framework, which
requires that image files are accessible under /lib/firmware. A request
for a secure update returns immediately, while the update itself
proceeds in the context of a kernel worker thread. Sysfs files provide
a means for monitoring the progress of a secure update and for
retrieving error information in the event of a failure.

The API consists of sysfs nodes and supports the following functions:

(1) Instantiate and monitor a secure update
(2) Display security information including: Root Entry Hashes (REH),
    Cancelled Code Signing Keys (CSK), and flash update counts for
    both BMC and FPGA images.

Changelog v1 -> v2:
  - Separated out the MAX10 BMC Security Engine to be submitted in
    a separate patch-set.
  - Bumped documentation dates and versions
  - Split ifpga_sec_mgr_register() into create() and register() functions
  - Added devm_ifpga_sec_mgr_create()
  - Added Documentation/fpga/ifpga-sec-mgr.rst 
  - Changed progress state "read_file" to "reading"
  - Added sec_error() function (similar to sec_progress())
  - Removed references to bmc_flash_count & smbus_flash_count (not supported)
  - Removed typedefs for imgr ops
  - Removed explicit value assignments in enums
  - Other minor code cleanup per review comments 

Russ Weight (7):
  fpga: sec-mgr: intel fpga security manager class driver
  fpga: sec-mgr: enable secure updates
  fpga: sec-mgr: expose sec-mgr update status
  fpga: sec-mgr: expose sec-mgr update errors
  fpga: sec-mgr: expose sec-mgr update size
  fpga: sec-mgr: enable cancel of secure update
  fpga: sec-mgr: expose hardware error info

 .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 143 ++++
 Documentation/fpga/ifpga-sec-mgr.rst          |  50 ++
 Documentation/fpga/index.rst                  |   1 +
 MAINTAINERS                                   |   9 +
 drivers/fpga/Kconfig                          |   9 +
 drivers/fpga/Makefile                         |   3 +
 drivers/fpga/ifpga-sec-mgr.c                  | 781 ++++++++++++++++++
 include/linux/fpga/ifpga-sec-mgr.h            | 137 +++
 8 files changed, 1133 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
 create mode 100644 Documentation/fpga/ifpga-sec-mgr.rst
 create mode 100644 drivers/fpga/ifpga-sec-mgr.c
 create mode 100644 include/linux/fpga/ifpga-sec-mgr.h

-- 
2.17.1


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH v2 1/7] fpga: sec-mgr: intel fpga security manager class driver
  2020-10-02 22:36 [PATCH v2 0/7] Intel FPGA Security Manager Class Driver Russ Weight
@ 2020-10-02 22:36 ` Russ Weight
  2020-10-02 23:03   ` Russ Weight
                     ` (2 more replies)
  2020-10-02 22:36 ` [PATCH v2 2/7] fpga: sec-mgr: enable secure updates Russ Weight
                   ` (6 subsequent siblings)
  7 siblings, 3 replies; 25+ messages in thread
From: Russ Weight @ 2020-10-02 22:36 UTC (permalink / raw)
  To: mdf, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, yilun.xu, hao.wu, matthew.gerlach, Russ Weight

Create the Intel Security Manager class driver. The security
manager provides interfaces to manage secure updates for the
FPGA and BMC images that are stored in FLASH. The driver can
also be used to update root entry hashes and to cancel code
signing keys.

This patch creates the class driver and provides sysfs
interfaces for displaying root entry hashes, canceled code
signing keys and flash counts.

Signed-off-by: Russ Weight <russell.h.weight@intel.com>
Signed-off-by: Xu Yilun <yilun.xu@intel.com>
---
v2:
  - Bumped documentation dates and versions
  - Added Documentation/fpga/ifpga-sec-mgr.rst 
  - Removed references to bmc_flash_count & smbus_flash_count (not supported)
  - Split ifpga_sec_mgr_register() into create() and register() functions
  - Added devm_ifpga_sec_mgr_create()
  - Removed typedefs for imgr ops
---
 .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  67 +++
 Documentation/fpga/ifpga-sec-mgr.rst          |  50 ++
 Documentation/fpga/index.rst                  |   1 +
 MAINTAINERS                                   |   9 +
 drivers/fpga/Kconfig                          |   9 +
 drivers/fpga/Makefile                         |   3 +
 drivers/fpga/ifpga-sec-mgr.c                  | 432 ++++++++++++++++++
 include/linux/fpga/ifpga-sec-mgr.h            |  81 ++++
 8 files changed, 652 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
 create mode 100644 Documentation/fpga/ifpga-sec-mgr.rst
 create mode 100644 drivers/fpga/ifpga-sec-mgr.c
 create mode 100644 include/linux/fpga/ifpga-sec-mgr.h

diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
new file mode 100644
index 000000000000..707958971bcb
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
@@ -0,0 +1,67 @@
+What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/name
+Date:		Oct 2020
+KernelVersion:  5.11
+Contact:	Russ Weight <russell.h.weight@intel.com>
+Description:	Name of low level fpga security manager driver.
+
+What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/sr_root_entry_hash
+Date:		Oct 2020
+KernelVersion:  5.11
+Contact:	Russ Weight <russell.h.weight@intel.com>
+Description:	Read only. Returns the root entry hash for the static
+		region if one is programmed, else it returns the
+		string: "hash not programmed".  This file is only
+		visible if the underlying device supports it.
+		Format: "0x%x".
+
+What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/pr_root_entry_hash
+Date:		Oct 2020
+KernelVersion:  5.11
+Contact:	Russ Weight <russell.h.weight@intel.com>
+Description:	Read only. Returns the root entry hash for the partial
+		reconfiguration region if one is programmed, else it
+		returns the string: "hash not programmed".  This file
+		is only visible if the underlying device supports it.
+		Format: "0x%x".
+
+What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/bmc_root_entry_hash
+Date:		Oct 2020
+KernelVersion:  5.11
+Contact:	Russ Weight <russell.h.weight@intel.com>
+Description:	Read only. Returns the root entry hash for the BMC image
+		if one is programmed, else it returns the string:
+		"hash not programmed".  This file is only visible if the
+		underlying device supports it.
+		Format: "0x%x".
+
+What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/sr_canceled_csks
+Date:		Oct 2020
+KernelVersion:  5.11
+Contact:	Russ Weight <russell.h.weight@intel.com>
+Description:	Read only. Returns a list of indices for canceled code
+		signing keys for the static region. The standard bitmap
+		list format is used (e.g. "1,2-6,9").
+
+What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/pr_canceled_csks
+Date:		Oct 2020
+KernelVersion:  5.11
+Contact:	Russ Weight <russell.h.weight@intel.com>
+Description:	Read only. Returns a list of indices for canceled code
+		signing keys for the partial reconfiguration region. The
+		standard bitmap list format is used (e.g. "1,2-6,9").
+
+What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/bmc_canceled_csks
+Date:		Oct 2020
+KernelVersion:  5.11
+Contact:	Russ Weight <russell.h.weight@intel.com>
+Description:	Read only. Returns a list of indices for canceled code
+		signing keys for the BMC.  The standard bitmap list format
+		is used (e.g. "1,2-6,9").
+
+What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/user_flash_count
+Date:		Oct 2020
+KernelVersion:  5.11
+Contact:	Russ Weight <russell.h.weight@intel.com>
+Description:	Read only. Returns number of times the user image for the
+		static region has been flashed.
+		Format: "%u".
diff --git a/Documentation/fpga/ifpga-sec-mgr.rst b/Documentation/fpga/ifpga-sec-mgr.rst
new file mode 100644
index 000000000000..02f3f65b182b
--- /dev/null
+++ b/Documentation/fpga/ifpga-sec-mgr.rst
@@ -0,0 +1,50 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+========================================
+Intel FPGA Security Manager Class Driver
+========================================
+
+The Intel FPGA Security Manager class driver provides a common
+API for user-space tools to manage updates for secure Intel FPGA
+devices. Device drivers that instantiate the Intel Security
+Manager class driver will interact with a HW secure update
+engine in order to transfer new FPGA and BMC images to FLASH so
+that they will be automatically loaded when the FPGA card reboots.
+
+A significant difference between the FPGA Manager and the Intel FPGA
+Security Manager is that the FPGA Manager does a live update (Partial
+Reconfiguration) to a device, whereas the Intel FPGA Security Manager
+updates the FLASH images for the Static Region and the BMC so that
+they will be loaded the next time the FPGA card boots. Security is
+enforced by hardware and firmware. The security manager interacts
+with the firmware to initiate an update, pass in the necessary data,
+and collect status on the update.
+
+In addition to managing secure updates of the FPGA and BMC images,
+the Intel FPGA Security Manager update process may also used to
+program root entry hashes and cancellation keys for the FPGA static
+region, the FPGA partial reconfiguration region, and the BMC.
+
+Secure updates make use of the request_firmware framework, which
+requires that image files are accessible under /lib/firmware. A request
+for a secure update returns immediately, while the update itself
+proceeds in the context of a kernel worker thread. Sysfs files provide
+a means for monitoring the progress of a secure update and for
+retrieving error information in the event of a failure.
+
+Sysfs Attributes
+================
+
+The API consists of two groups of sysfs attributes as described below.
+
+1. Files in the *security* sub-directory can be used to read security
+   information including: Root Entry Hashes (REH), Cancelled Code
+   Signing Keys (CSK), and the flash update count for FPGA images.
+
+2. Files in the *update* sub-directory can be used to instantiate and
+   monitor a secure update.
+
+
+See `<../ABI/testing/sysfs-class-ifpga-sec-mgr>`__ for a full
+description of the sysfs attributes for the Intel FPGA Security
+Manager.
diff --git a/Documentation/fpga/index.rst b/Documentation/fpga/index.rst
index f80f95667ca2..ba9c6b1917bd 100644
--- a/Documentation/fpga/index.rst
+++ b/Documentation/fpga/index.rst
@@ -8,6 +8,7 @@ fpga
     :maxdepth: 1
 
     dfl
+    ifpga-sec-mgr
 
 .. only::  subproject and html
 
diff --git a/MAINTAINERS b/MAINTAINERS
index 6d1175bf8529..5ffc0e02d741 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6858,6 +6858,15 @@ F:	Documentation/fpga/
 F:	drivers/fpga/
 F:	include/linux/fpga/
 
+INTEL FPGA SECURITY MANAGER DRIVERS
+M:	Russ Weight <russell.h.weight@intel.com>
+L:	linux-fpga@vger.kernel.org
+S:	Maintained
+F:	Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
+F:	Documentation/fpga/ifpga-sec-mgr.rst
+F:	drivers/fpga/ifpga-sec-mgr.c
+F:	include/linux/fpga/ifpga-sec-mgr.h
+
 FPU EMULATOR
 M:	Bill Metzenthen <billm@melbpc.org.au>
 S:	Maintained
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index 7cd5a29fc437..bf566a625be7 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -215,4 +215,13 @@ config FPGA_MGR_ZYNQMP_FPGA
 	  to configure the programmable logic(PL) through PS
 	  on ZynqMP SoC.
 
+config IFPGA_SEC_MGR
+	tristate "Intel Security Manager for FPGA"
+	help
+	  The Intel Security Manager class driver presents a common
+	  user API for managing secure updates for Intel FPGA
+	  devices, including flash images for the FPGA static
+	  region and for the BMC. Select this option to enable
+	  updates for secure FPGA devices.
+
 endif # FPGA
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index d8e21dfc6778..2e1d29c3d915 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -21,6 +21,9 @@ obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
 obj-$(CONFIG_ALTERA_PR_IP_CORE)         += altera-pr-ip-core.o
 obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT)    += altera-pr-ip-core-plat.o
 
+# Intel FPGA Security Manager Framework
+obj-$(CONFIG_IFPGA_SEC_MGR)		+= ifpga-sec-mgr.o
+
 # FPGA Bridge Drivers
 obj-$(CONFIG_FPGA_BRIDGE)		+= fpga-bridge.o
 obj-$(CONFIG_SOCFPGA_FPGA_BRIDGE)	+= altera-hps2fpga.o altera-fpga2sdram.o
diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
new file mode 100644
index 000000000000..f1caa4602ab3
--- /dev/null
+++ b/drivers/fpga/ifpga-sec-mgr.c
@@ -0,0 +1,432 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel Security Manager for FPGA
+ *
+ * Copyright (C) 2019-2020 Intel Corporation, Inc.
+ */
+
+#include <linux/fpga/ifpga-sec-mgr.h>
+#include <linux/idr.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+static DEFINE_IDA(ifpga_sec_mgr_ida);
+static struct class *ifpga_sec_mgr_class;
+
+#define to_sec_mgr(d) container_of(d, struct ifpga_sec_mgr, dev)
+
+static ssize_t
+show_canceled_csk(struct ifpga_sec_mgr *imgr,
+		  int (*get_csk)(struct ifpga_sec_mgr *imgr,
+				 unsigned long *csk_map, unsigned int nbits),
+		  int (*get_csk_nbits)(struct ifpga_sec_mgr *imgr),
+		  char *buf)
+{
+	unsigned long *csk_map = NULL;
+	unsigned int nbits;
+	int ret;
+
+	ret = get_csk_nbits(imgr);
+	if (ret < 0)
+		return ret;
+
+	nbits = (unsigned int)ret;
+	csk_map = vmalloc(sizeof(unsigned long) * BITS_TO_LONGS(nbits));
+	if (!csk_map)
+		return -ENOMEM;
+
+	ret = get_csk(imgr, csk_map, nbits);
+	if (ret)
+		goto vfree_exit;
+
+	ret = bitmap_print_to_pagebuf(1, buf, csk_map, nbits);
+
+vfree_exit:
+	vfree(csk_map);
+	return ret;
+}
+
+static ssize_t
+show_root_entry_hash(struct ifpga_sec_mgr *imgr,
+		     int (*get_reh)(struct ifpga_sec_mgr *imgr, u8 *hash,
+				    unsigned int size),
+		     int (*get_reh_size)(struct ifpga_sec_mgr *imgr),
+		     char *buf)
+{
+	int size, i, cnt, ret;
+	u8 *hash;
+
+	ret = get_reh_size(imgr);
+	if (ret < 0)
+		return ret;
+	else if (!ret)
+		return sprintf(buf, "hash not programmed\n");
+
+	size = ret;
+	hash = vmalloc(size);
+	if (!hash)
+		return -ENOMEM;
+
+	ret = get_reh(imgr, hash, size);
+	if (ret)
+		goto vfree_exit;
+
+	cnt = sprintf(buf, "0x");
+	for (i = 0; i < size; i++)
+		cnt += sprintf(buf + cnt, "%02x", hash[i]);
+	cnt += sprintf(buf + cnt, "\n");
+
+vfree_exit:
+	vfree(hash);
+	return ret ? : cnt;
+}
+
+#define DEVICE_ATTR_SEC_CSK(_name) \
+static ssize_t _name##_canceled_csks_show(struct device *dev, \
+					  struct device_attribute *attr, \
+					  char *buf) \
+{ \
+	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev); \
+	return show_canceled_csk(imgr, \
+	       imgr->iops->_name##_canceled_csks, \
+	       imgr->iops->_name##_canceled_csk_nbits, buf); \
+} \
+static DEVICE_ATTR_RO(_name##_canceled_csks)
+
+#define DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(_name) \
+static ssize_t _name##_root_entry_hash_show(struct device *dev, \
+				     struct device_attribute *attr, \
+				     char *buf) \
+{ \
+	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev); \
+	return show_root_entry_hash(imgr, \
+	       imgr->iops->_name##_root_entry_hash, \
+	       imgr->iops->_name##_reh_size, buf); \
+} \
+static DEVICE_ATTR_RO(_name##_root_entry_hash)
+
+static ssize_t user_flash_count_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
+
+	int cnt = imgr->iops->user_flash_count(imgr);
+	return cnt < 0 ? cnt : sprintf(buf, "%u\n", cnt);
+}
+static DEVICE_ATTR_RO(user_flash_count);
+
+DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(sr);
+DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(pr);
+DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(bmc);
+DEVICE_ATTR_SEC_CSK(sr);
+DEVICE_ATTR_SEC_CSK(pr);
+DEVICE_ATTR_SEC_CSK(bmc);
+
+static struct attribute *sec_mgr_security_attrs[] = {
+	&dev_attr_user_flash_count.attr,
+	&dev_attr_bmc_root_entry_hash.attr,
+	&dev_attr_sr_root_entry_hash.attr,
+	&dev_attr_pr_root_entry_hash.attr,
+	&dev_attr_sr_canceled_csks.attr,
+	&dev_attr_pr_canceled_csks.attr,
+	&dev_attr_bmc_canceled_csks.attr,
+	NULL,
+};
+
+#define check_attr(attribute, _name) \
+	((attribute) == &dev_attr_##_name.attr && imgr->iops->_name)
+
+static umode_t sec_mgr_visible(struct kobject *kobj,
+			       struct attribute *attr, int n)
+{
+	struct ifpga_sec_mgr *imgr = to_sec_mgr(kobj_to_dev(kobj));
+
+	/*
+	 * Only display optional sysfs attributes if a
+	 * corresponding handler is provided
+	 */
+	if (check_attr(attr, user_flash_count) ||
+	    check_attr(attr, bmc_root_entry_hash) ||
+	    check_attr(attr, sr_root_entry_hash) ||
+	    check_attr(attr, pr_root_entry_hash) ||
+	    check_attr(attr, sr_canceled_csks) ||
+	    check_attr(attr, pr_canceled_csks) ||
+	    check_attr(attr, bmc_canceled_csks))
+		return attr->mode;
+
+	return 0;
+}
+
+static struct attribute_group sec_mgr_security_attr_group = {
+	.name = "security",
+	.attrs = sec_mgr_security_attrs,
+	.is_visible = sec_mgr_visible,
+};
+
+static ssize_t name_show(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
+
+	return sprintf(buf, "%s\n", imgr->name);
+}
+static DEVICE_ATTR_RO(name);
+
+static struct attribute *sec_mgr_attrs[] = {
+	&dev_attr_name.attr,
+	NULL,
+};
+
+static struct attribute_group sec_mgr_attr_group = {
+	.attrs = sec_mgr_attrs,
+};
+
+static const struct attribute_group *ifpga_sec_mgr_attr_groups[] = {
+	&sec_mgr_attr_group,
+	&sec_mgr_security_attr_group,
+	NULL,
+};
+
+static bool check_sysfs_handler(struct device *dev,
+				void *sysfs_handler, void *size_handler,
+				const char *sysfs_handler_name,
+				const char *size_handler_name)
+{
+	/*
+	 * sysfs_handler and size_handler must either both be
+	 * defined or both be NULL.
+	 */
+	if (sysfs_handler) {
+		if (!size_handler) {
+			dev_err(dev, "%s registered without %s\n",
+				sysfs_handler_name, size_handler_name);
+			return false;
+		}
+	} else if (size_handler) {
+		dev_err(dev, "%s registered without %s\n",
+			size_handler_name, sysfs_handler_name);
+		return false;
+	}
+	return true;
+}
+
+#define check_reh_handler(_dev, _iops, _name) \
+	check_sysfs_handler(_dev, (_iops)->_name##_root_entry_hash, \
+			    (_iops)->_name##_reh_size, \
+			    __stringify(_name##_root_entry_hash), \
+			    __stringify(_name##_reh_size))
+
+#define check_csk_handler(_dev, _iops, _name) \
+	check_sysfs_handler(_dev, (_iops)->_name##_canceled_csks, \
+			    (_iops)->_name##_canceled_csk_nbits, \
+			    __stringify(_name##_canceled_csks), \
+			    __stringify(_name##_canceled_csk_nbits))
+
+/**
+ * ifpga_sec_mgr_create - create and initialize an Intel FPGA
+ *			  security manager struct
+ *
+ * @dev:  Intel fpga security manager device from pdev
+ * @name: ifpga security manager name
+ * @iops: pointer to a structure of ifpga callback functions
+ * @priv: ifpga security manager private data
+ *
+ * The caller of this function is responsible for freeing the struct
+ * with ifpg_sec_mgr_free(). Using devm_ifpga_sec_mgr_create() instead
+ * is recommended.
+ *
+ * Return: pointer to struct ifpga_sec_mgr or NULL
+ */
+struct ifpga_sec_mgr *
+ifpga_sec_mgr_create(struct device *dev, const char *name,
+		     const struct ifpga_sec_mgr_ops *iops, void *priv)
+{
+	struct ifpga_sec_mgr *imgr;
+	int id, ret;
+
+	if (!check_reh_handler(dev, iops, bmc) ||
+	    !check_reh_handler(dev, iops, sr) ||
+	    !check_reh_handler(dev, iops, pr) ||
+	    !check_csk_handler(dev, iops, bmc) ||
+	    !check_csk_handler(dev, iops, sr) ||
+	    !check_csk_handler(dev, iops, pr)) {
+		return NULL;
+	}
+
+	if (!name || !strlen(name)) {
+		dev_err(dev, "Attempt to register with no name!\n");
+		return NULL;
+	}
+
+	imgr = kzalloc(sizeof(*imgr), GFP_KERNEL);
+	if (!imgr)
+		return NULL;
+
+	id = ida_simple_get(&ifpga_sec_mgr_ida, 0, 0, GFP_KERNEL);
+	if (id < 0)
+		goto error_kfree;
+
+	mutex_init(&imgr->lock);
+
+	imgr->name = name;
+	imgr->priv = priv;
+	imgr->iops = iops;
+
+	device_initialize(&imgr->dev);
+	imgr->dev.class = ifpga_sec_mgr_class;
+	imgr->dev.parent = dev;
+	imgr->dev.id = id;
+
+	ret = dev_set_name(&imgr->dev, "ifpga_sec%d", id);
+	if (ret) {
+		dev_err(dev, "Failed to set device name: ifpga_sec%d\n", id);
+		goto error_device;
+	}
+
+	return imgr;
+
+error_device:
+	ida_simple_remove(&ifpga_sec_mgr_ida, id);
+
+error_kfree:
+	kfree(imgr);
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(ifpga_sec_mgr_create);
+
+/**
+ * ifpga_sec_mgr_free - free an Intel FPGA security manager created
+ *			with ifpga_sec_mgr_create()
+ *
+ * @imgr:	Intel FPGA security manager structure
+ */
+void ifpga_sec_mgr_free(struct ifpga_sec_mgr *imgr)
+{
+	ida_simple_remove(&ifpga_sec_mgr_ida, imgr->dev.id);
+	kfree(imgr);
+}
+EXPORT_SYMBOL_GPL(ifpga_sec_mgr_free);
+
+static void devm_ifpga_sec_mgr_release(struct device *dev, void *res)
+{
+	struct ifpga_sec_mgr *imgr = *(struct ifpga_sec_mgr **)res;
+
+	ifpga_sec_mgr_free(imgr);
+}
+
+/**
+ * devm_ifpga_sec_mgr_create - create and initialize an Intel FPGA
+ *			       security manager struct
+ *
+ * @dev:  Intel fpga security manager device from pdev
+ * @name: ifpga security manager name
+ * @iops: pointer to a structure of ifpga callback functions
+ * @priv: ifpga security manager private data
+ *
+ * This function is intended for use in a Intel FPGA Security manager
+ * driver's probe function.  After the security manager driver creates
+ * the ifpga_sec_mgr struct with devm_fpga_mgr_create(), it should
+ * register it with ifpga_sec_mgr_register().  The security manager
+ * driver's remove function should call ifpga_sec_mgr_unregister().
+ * The ifpga_sec_mgr struct allocated with this function will be freed
+ * automatically on driver detach.  This includes the case of a probe
+ * function returning error before calling fpga_mgr_register(), the
+ * struct will still get cleaned up.
+ *
+ * Return: pointer to struct ifpga_sec_mgr or NULL
+ */
+struct ifpga_sec_mgr *
+devm_ifpga_sec_mgr_create(struct device *dev, const char *name,
+			  const struct ifpga_sec_mgr_ops *iops, void *priv)
+{
+	struct ifpga_sec_mgr **ptr, *imgr;
+
+	ptr = devres_alloc(devm_ifpga_sec_mgr_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return NULL;
+
+	imgr = ifpga_sec_mgr_create(dev, name, iops, priv);
+	if (!imgr) {
+		devres_free(ptr);
+	} else {
+		*ptr = imgr;
+		devres_add(dev, ptr);
+	}
+
+	return imgr;
+}
+EXPORT_SYMBOL_GPL(devm_ifpga_sec_mgr_create);
+
+/**
+ * ifpga_sec_mgr_register - register an Intel FPGA security manager
+ *
+ * @imgr: Intel fpga security manager struct
+ *
+ * Return: 0 on success, negative error code otherwise.
+ */
+int ifpga_sec_mgr_register(struct ifpga_sec_mgr *imgr)
+{
+	int ret;
+
+	ret = device_add(&imgr->dev);
+	if (ret)
+		goto error_device;
+
+	dev_info(&imgr->dev, "%s registered\n", imgr->name);
+
+	return 0;
+
+error_device:
+	ida_simple_remove(&ifpga_sec_mgr_ida, imgr->dev.id);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ifpga_sec_mgr_register);
+
+/**
+ * ifpga_sec_mgr_unregister - unregister an Intel FPGA security manager
+ *
+ * @mgr: fpga manager struct
+ *
+ * This function is intended for use in an Intel FPGA security manager
+ * driver's remove() function.
+ */
+void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr)
+{
+	dev_info(&imgr->dev, "%s %s\n", __func__, imgr->name);
+
+	device_unregister(&imgr->dev);
+}
+EXPORT_SYMBOL_GPL(ifpga_sec_mgr_unregister);
+
+static void ifpga_sec_mgr_dev_release(struct device *dev)
+{
+}
+
+static int __init ifpga_sec_mgr_class_init(void)
+{
+	pr_info("Intel FPGA Security Manager\n");
+
+	ifpga_sec_mgr_class = class_create(THIS_MODULE, "ifpga_sec_mgr");
+	if (IS_ERR(ifpga_sec_mgr_class))
+		return PTR_ERR(ifpga_sec_mgr_class);
+
+	ifpga_sec_mgr_class->dev_groups = ifpga_sec_mgr_attr_groups;
+	ifpga_sec_mgr_class->dev_release = ifpga_sec_mgr_dev_release;
+
+	return 0;
+}
+
+static void __exit ifpga_sec_mgr_class_exit(void)
+{
+	class_destroy(ifpga_sec_mgr_class);
+	ida_destroy(&ifpga_sec_mgr_ida);
+}
+
+MODULE_DESCRIPTION("Intel FPGA Security Manager Driver");
+MODULE_LICENSE("GPL v2");
+
+subsys_initcall(ifpga_sec_mgr_class_init);
+module_exit(ifpga_sec_mgr_class_exit)
diff --git a/include/linux/fpga/ifpga-sec-mgr.h b/include/linux/fpga/ifpga-sec-mgr.h
new file mode 100644
index 000000000000..ded62090e9b9
--- /dev/null
+++ b/include/linux/fpga/ifpga-sec-mgr.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Header file for Intel FPGA Security Manager
+ *
+ * Copyright (C) 2019-2020 Intel Corporation, Inc.
+ */
+#ifndef _LINUX_IFPGA_SEC_MGR_H
+#define _LINUX_IFPGA_SEC_MGR_H
+
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+struct ifpga_sec_mgr;
+
+/**
+ * struct ifpga_sec_mgr_ops - device specific operations
+ * @user_flash_count:	    Optional: Return sysfs string output for FPGA
+ *			    image flash count
+ * @sr_root_entry_hash:	    Optional: Return sysfs string output for static
+ *			    region root entry hash
+ * @pr_root_entry_hash:	    Optional: Return sysfs string output for partial
+ *			    reconfiguration root entry hash
+ * @bmc_root_entry_hash:    Optional: Return sysfs string output for BMC
+ *			    root entry hash
+ * @sr_canceled_csks:	    Optional: Return sysfs string output for static
+ *			    region canceled keys
+ * @pr_canceled_csks:	    Optional: Return sysfs string output for partial
+ *			    reconfiguration canceled keys
+ * @bmc_canceled_csks:	    Optional: Return sysfs string output for bmc
+ *			    canceled keys
+ * @bmc_canceled_csk_nbits: Optional: Return BMC canceled csk vector bit count
+ * @sr_canceled_csk_nbits:  Optional: Return SR canceled csk vector bit count
+ * @pr_canceled_csk_nbits:  Optional: Return PR canceled csk vector bit count
+ * @bmc_reh_size:	    Optional: Return byte size for BMC root entry hash
+ * @sr_reh_size:	    Optional: Return byte size for SR root entry hash
+ * @pr_reh_size:	    Optional: Return byte size for PR root entry hash
+ */
+struct ifpga_sec_mgr_ops {
+	int (*user_flash_count)(struct ifpga_sec_mgr *imgr);
+	int (*bmc_root_entry_hash)(struct ifpga_sec_mgr *imgr, u8 *hash,
+				   unsigned int size);
+	int (*sr_root_entry_hash)(struct ifpga_sec_mgr *imgr, u8 *hash,
+				  unsigned int size);
+	int (*pr_root_entry_hash)(struct ifpga_sec_mgr *imgr, u8 *hash,
+				  unsigned int size);
+	int (*bmc_canceled_csks)(struct ifpga_sec_mgr *imgr,
+				 unsigned long *csk_map, unsigned int nbits);
+	int (*sr_canceled_csks)(struct ifpga_sec_mgr *imgr,
+				unsigned long *csk_map, unsigned int nbits);
+	int (*pr_canceled_csks)(struct ifpga_sec_mgr *imgr,
+				unsigned long *csk_map, unsigned int nbits);
+	int (*bmc_reh_size)(struct ifpga_sec_mgr *imgr);
+	int (*sr_reh_size)(struct ifpga_sec_mgr *imgr);
+	int (*pr_reh_size)(struct ifpga_sec_mgr *imgr);
+	int (*bmc_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
+	int (*sr_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
+	int (*pr_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
+};
+
+struct ifpga_sec_mgr {
+	const char *name;
+	struct device dev;
+	const struct ifpga_sec_mgr_ops *iops;
+	struct mutex lock;		/* protect data structure contents */
+	void *priv;
+};
+
+struct ifpga_sec_mgr *
+ifpga_sec_mgr_create(struct device *dev, const char *name,
+		     const struct ifpga_sec_mgr_ops *iops, void *priv);
+
+struct ifpga_sec_mgr *
+devm_ifpga_sec_mgr_create(struct device *dev, const char *name,
+			  const struct ifpga_sec_mgr_ops *iops, void *priv);
+
+int ifpga_sec_mgr_register(struct ifpga_sec_mgr *imgr);
+void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr);
+void ifpga_sec_mgr_free(struct ifpga_sec_mgr *imgr);
+
+#endif
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 2/7] fpga: sec-mgr: enable secure updates
  2020-10-02 22:36 [PATCH v2 0/7] Intel FPGA Security Manager Class Driver Russ Weight
  2020-10-02 22:36 ` [PATCH v2 1/7] fpga: sec-mgr: intel fpga security manager class driver Russ Weight
@ 2020-10-02 22:36 ` Russ Weight
  2020-10-04 20:54   ` Tom Rix
  2020-10-05  8:19   ` Wu, Hao
  2020-10-02 22:36 ` [PATCH v2 3/7] fpga: sec-mgr: expose sec-mgr update status Russ Weight
                   ` (5 subsequent siblings)
  7 siblings, 2 replies; 25+ messages in thread
From: Russ Weight @ 2020-10-02 22:36 UTC (permalink / raw)
  To: mdf, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, yilun.xu, hao.wu, matthew.gerlach, Russ Weight

Extend the FPGA Intel Security Manager class driver to
include an update/filename sysfs node that can be used
to initiate a security update.  The filename of a secure
update file (BMC image, FPGA image, Root Entry Hash image,
or Code Signing Key cancellation image) can be written to
this sysfs entry to cause a secure update to occur.

The write of the filename will return immediately, and the
update will begin in the context of a kernel worker thread.
This tool utilizes the request_firmware framework, which
requires that the image file reside under /lib/firmware.

Signed-off-by: Russ Weight <russell.h.weight@intel.com>
---
v2:
  - Bumped documentation date and version
  - Removed explicit value assignments in enums
  - Other minor code cleanup per review comments 
---
 .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  13 ++
 drivers/fpga/ifpga-sec-mgr.c                  | 157 ++++++++++++++++++
 include/linux/fpga/ifpga-sec-mgr.h            |  49 ++++++
 3 files changed, 219 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
index 707958971bcb..4f375f132c34 100644
--- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
+++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
@@ -65,3 +65,16 @@ Contact:	Russ Weight <russell.h.weight@intel.com>
 Description:	Read only. Returns number of times the user image for the
 		static region has been flashed.
 		Format: "%u".
+
+What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/update/filename
+Date:		Oct 2020
+KernelVersion:  5.11
+Contact:	Russ Weight <russell.h.weight@intel.com>
+Description:	Write only. Write the filename of an Intel image
+		file to this sysfs file to initiate a secure
+		update. The file must have an appropriate header
+		which, among other things, identifies the target
+		for the update. This mechanism is used to update
+		BMC images, BMC firmware, Static Region images,
+		and Root Entry Hashes, and to cancel Code Signing
+		Keys (CSK).
diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
index f1caa4602ab3..7d5a4979554b 100644
--- a/drivers/fpga/ifpga-sec-mgr.c
+++ b/drivers/fpga/ifpga-sec-mgr.c
@@ -5,8 +5,11 @@
  * Copyright (C) 2019-2020 Intel Corporation, Inc.
  */
 
+#include <linux/delay.h>
+#include <linux/firmware.h>
 #include <linux/fpga/ifpga-sec-mgr.h>
 #include <linux/idr.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
@@ -14,6 +17,8 @@
 static DEFINE_IDA(ifpga_sec_mgr_ida);
 static struct class *ifpga_sec_mgr_class;
 
+#define WRITE_BLOCK_SIZE	0x4000
+
 #define to_sec_mgr(d) container_of(d, struct ifpga_sec_mgr, dev)
 
 static ssize_t
@@ -134,6 +139,96 @@ static struct attribute *sec_mgr_security_attrs[] = {
 	NULL,
 };
 
+static void ifpga_sec_dev_error(struct ifpga_sec_mgr *imgr,
+				enum ifpga_sec_err err_code)
+{
+	imgr->err_code = err_code;
+	imgr->iops->cancel(imgr);
+}
+
+static void progress_complete(struct ifpga_sec_mgr *imgr)
+{
+	mutex_lock(&imgr->lock);
+	imgr->progress = IFPGA_SEC_PROG_IDLE;
+	complete_all(&imgr->update_done);
+	mutex_unlock(&imgr->lock);
+}
+
+static void ifpga_sec_mgr_update(struct work_struct *work)
+{
+	u32 size, blk_size, offset = 0;
+	struct ifpga_sec_mgr *imgr;
+	const struct firmware *fw;
+	enum ifpga_sec_err ret;
+
+	imgr = container_of(work, struct ifpga_sec_mgr, work);
+
+	get_device(&imgr->dev);
+	if (request_firmware(&fw, imgr->filename, &imgr->dev)) {
+		imgr->err_code = IFPGA_SEC_ERR_FILE_READ;
+		goto idle_exit;
+	}
+
+	imgr->data = fw->data;
+	imgr->remaining_size = fw->size;
+
+	if (!try_module_get(imgr->dev.parent->driver->owner)) {
+		imgr->err_code = IFPGA_SEC_ERR_BUSY;
+		goto release_fw_exit;
+	}
+
+	imgr->progress = IFPGA_SEC_PROG_PREPARING;
+	ret = imgr->iops->prepare(imgr);
+	if (ret) {
+		ifpga_sec_dev_error(imgr, ret);
+		goto modput_exit;
+	}
+
+	imgr->progress = IFPGA_SEC_PROG_WRITING;
+	size = imgr->remaining_size;
+	while (size) {
+		blk_size = min_t(u32, size, WRITE_BLOCK_SIZE);
+		size -= blk_size;
+		ret = imgr->iops->write_blk(imgr, offset, blk_size);
+		if (ret) {
+			ifpga_sec_dev_error(imgr, ret);
+			goto done;
+		}
+
+		imgr->remaining_size = size;
+		offset += blk_size;
+	}
+
+	imgr->progress = IFPGA_SEC_PROG_PROGRAMMING;
+	ret = imgr->iops->poll_complete(imgr);
+	if (ret) {
+		ifpga_sec_dev_error(imgr, ret);
+		goto done;
+	}
+
+done:
+	if (imgr->iops->cleanup)
+		imgr->iops->cleanup(imgr);
+
+modput_exit:
+	module_put(imgr->dev.parent->driver->owner);
+
+release_fw_exit:
+	imgr->data = NULL;
+	release_firmware(fw);
+
+idle_exit:
+	/*
+	 * Note: imgr->remaining_size is left unmodified here to
+	 * provide additional information on errors. It will be
+	 * reinitialized when the next secure update begins.
+	 */
+	kfree(imgr->filename);
+	imgr->filename = NULL;
+	put_device(&imgr->dev);
+	progress_complete(imgr);
+}
+
 #define check_attr(attribute, _name) \
 	((attribute) == &dev_attr_##_name.attr && imgr->iops->_name)
 
@@ -164,6 +259,48 @@ static struct attribute_group sec_mgr_security_attr_group = {
 	.is_visible = sec_mgr_visible,
 };
 
+static ssize_t filename_store(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
+	int ret = count;
+
+	if (count == 0 || count >= PATH_MAX)
+		return -EINVAL;
+
+	mutex_lock(&imgr->lock);
+	if (imgr->driver_unload || imgr->progress != IFPGA_SEC_PROG_IDLE) {
+		ret = -EBUSY;
+		goto unlock_exit;
+	}
+
+	imgr->filename = kstrndup(buf, count - 1, GFP_KERNEL);
+	if (!imgr->filename) {
+		ret = -ENOMEM;
+		goto unlock_exit;
+	}
+
+	imgr->err_code = IFPGA_SEC_ERR_NONE;
+	imgr->progress = IFPGA_SEC_PROG_READING;
+	reinit_completion(&imgr->update_done);
+	schedule_work(&imgr->work);
+
+unlock_exit:
+	mutex_unlock(&imgr->lock);
+	return ret;
+}
+static DEVICE_ATTR_WO(filename);
+
+static struct attribute *sec_mgr_update_attrs[] = {
+	&dev_attr_filename.attr,
+	NULL,
+};
+
+static struct attribute_group sec_mgr_update_attr_group = {
+	.name = "update",
+	.attrs = sec_mgr_update_attrs,
+};
+
 static ssize_t name_show(struct device *dev,
 			 struct device_attribute *attr, char *buf)
 {
@@ -185,6 +322,7 @@ static struct attribute_group sec_mgr_attr_group = {
 static const struct attribute_group *ifpga_sec_mgr_attr_groups[] = {
 	&sec_mgr_attr_group,
 	&sec_mgr_security_attr_group,
+	&sec_mgr_update_attr_group,
 	NULL,
 };
 
@@ -245,6 +383,12 @@ ifpga_sec_mgr_create(struct device *dev, const char *name,
 	struct ifpga_sec_mgr *imgr;
 	int id, ret;
 
+	if (!iops || !iops->cancel || !iops->prepare ||
+	    !iops->write_blk || !iops->poll_complete) {
+		dev_err(dev, "Attempt to register without required ops\n");
+		return NULL;
+	}
+
 	if (!check_reh_handler(dev, iops, bmc) ||
 	    !check_reh_handler(dev, iops, sr) ||
 	    !check_reh_handler(dev, iops, pr) ||
@@ -272,6 +416,8 @@ ifpga_sec_mgr_create(struct device *dev, const char *name,
 	imgr->name = name;
 	imgr->priv = priv;
 	imgr->iops = iops;
+	init_completion(&imgr->update_done);
+	INIT_WORK(&imgr->work, ifpga_sec_mgr_update);
 
 	device_initialize(&imgr->dev);
 	imgr->dev.class = ifpga_sec_mgr_class;
@@ -397,6 +543,17 @@ void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr)
 {
 	dev_info(&imgr->dev, "%s %s\n", __func__, imgr->name);
 
+	mutex_lock(&imgr->lock);
+	imgr->driver_unload = true;
+	if (imgr->progress == IFPGA_SEC_PROG_IDLE) {
+		mutex_unlock(&imgr->lock);
+		goto unregister;
+	}
+
+	mutex_unlock(&imgr->lock);
+	wait_for_completion(&imgr->update_done);
+
+unregister:
 	device_unregister(&imgr->dev);
 }
 EXPORT_SYMBOL_GPL(ifpga_sec_mgr_unregister);
diff --git a/include/linux/fpga/ifpga-sec-mgr.h b/include/linux/fpga/ifpga-sec-mgr.h
index ded62090e9b9..27008abd8e75 100644
--- a/include/linux/fpga/ifpga-sec-mgr.h
+++ b/include/linux/fpga/ifpga-sec-mgr.h
@@ -7,12 +7,26 @@
 #ifndef _LINUX_IFPGA_SEC_MGR_H
 #define _LINUX_IFPGA_SEC_MGR_H
 
+#include <linux/completion.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
 #include <linux/types.h>
 
 struct ifpga_sec_mgr;
 
+enum ifpga_sec_err {
+	IFPGA_SEC_ERR_NONE,
+	IFPGA_SEC_ERR_HW_ERROR,
+	IFPGA_SEC_ERR_TIMEOUT,
+	IFPGA_SEC_ERR_CANCELED,
+	IFPGA_SEC_ERR_BUSY,
+	IFPGA_SEC_ERR_INVALID_SIZE,
+	IFPGA_SEC_ERR_RW_ERROR,
+	IFPGA_SEC_ERR_WEAROUT,
+	IFPGA_SEC_ERR_FILE_READ,
+	IFPGA_SEC_ERR_MAX
+};
+
 /**
  * struct ifpga_sec_mgr_ops - device specific operations
  * @user_flash_count:	    Optional: Return sysfs string output for FPGA
@@ -35,6 +49,17 @@ struct ifpga_sec_mgr;
  * @bmc_reh_size:	    Optional: Return byte size for BMC root entry hash
  * @sr_reh_size:	    Optional: Return byte size for SR root entry hash
  * @pr_reh_size:	    Optional: Return byte size for PR root entry hash
+ * @prepare:		    Required: Prepare secure update
+ * @write_blk:		    Required: Write a block of data
+ * @poll_complete:	    Required: Check for the completion of the
+ *			    HW authentication/programming process. This
+ *			    function should check for imgr->driver_unload
+ *			    and abort with IFPGA_SEC_ERR_CANCELED when true.
+ * @cancel:		    Required: Signal HW to cancel update
+ * @cleanup:		    Optional: Complements the prepare()
+ *			    function and is called at the completion
+ *			    of the update, whether success or failure,
+ *			    if the prepare function succeeded.
  */
 struct ifpga_sec_mgr_ops {
 	int (*user_flash_count)(struct ifpga_sec_mgr *imgr);
@@ -56,6 +81,22 @@ struct ifpga_sec_mgr_ops {
 	int (*bmc_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
 	int (*sr_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
 	int (*pr_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
+	enum ifpga_sec_err (*prepare)(struct ifpga_sec_mgr *imgr);
+	enum ifpga_sec_err (*write_blk)(struct ifpga_sec_mgr *imgr,
+					u32 offset, u32 size);
+	enum ifpga_sec_err (*poll_complete)(struct ifpga_sec_mgr *imgr);
+	void (*cleanup)(struct ifpga_sec_mgr *imgr);
+	enum ifpga_sec_err (*cancel)(struct ifpga_sec_mgr *imgr);
+};
+
+/* Update progress codes */
+enum ifpga_sec_prog {
+	IFPGA_SEC_PROG_IDLE,
+	IFPGA_SEC_PROG_READING,
+	IFPGA_SEC_PROG_PREPARING,
+	IFPGA_SEC_PROG_WRITING,
+	IFPGA_SEC_PROG_PROGRAMMING,
+	IFPGA_SEC_PROG_MAX
 };
 
 struct ifpga_sec_mgr {
@@ -63,6 +104,14 @@ struct ifpga_sec_mgr {
 	struct device dev;
 	const struct ifpga_sec_mgr_ops *iops;
 	struct mutex lock;		/* protect data structure contents */
+	struct work_struct work;
+	struct completion update_done;
+	char *filename;
+	const u8 *data;			/* pointer to update data */
+	u32 remaining_size;		/* size remaining to transfer */
+	enum ifpga_sec_prog progress;
+	enum ifpga_sec_err err_code;	/* security manager error code */
+	bool driver_unload;
 	void *priv;
 };
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 3/7] fpga: sec-mgr: expose sec-mgr update status
  2020-10-02 22:36 [PATCH v2 0/7] Intel FPGA Security Manager Class Driver Russ Weight
  2020-10-02 22:36 ` [PATCH v2 1/7] fpga: sec-mgr: intel fpga security manager class driver Russ Weight
  2020-10-02 22:36 ` [PATCH v2 2/7] fpga: sec-mgr: enable secure updates Russ Weight
@ 2020-10-02 22:36 ` Russ Weight
  2020-10-04 21:00   ` Tom Rix
  2020-10-05  8:41   ` Wu, Hao
  2020-10-02 22:36 ` [PATCH v2 4/7] fpga: sec-mgr: expose sec-mgr update errors Russ Weight
                   ` (4 subsequent siblings)
  7 siblings, 2 replies; 25+ messages in thread
From: Russ Weight @ 2020-10-02 22:36 UTC (permalink / raw)
  To: mdf, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, yilun.xu, hao.wu, matthew.gerlach, Russ Weight

Extend the Intel Security Manager class driver to
include an update/status sysfs node that can be polled
and read to monitor the progress of an ongoing secure
update. Sysfs_notify() is used to signal transitions
between different phases of the update process.

Signed-off-by: Russ Weight <russell.h.weight@intel.com>
---
v2:
  - Bumped documentation date and version
  - Changed progress state "read_file" to "reading"
---
 .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 11 +++++
 drivers/fpga/ifpga-sec-mgr.c                  | 40 +++++++++++++++++--
 2 files changed, 47 insertions(+), 4 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
index 4f375f132c34..73a5246fea1b 100644
--- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
+++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
@@ -78,3 +78,14 @@ Description:	Write only. Write the filename of an Intel image
 		BMC images, BMC firmware, Static Region images,
 		and Root Entry Hashes, and to cancel Code Signing
 		Keys (CSK).
+
+What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/update/status
+Date:		Oct 2020
+KernelVersion:  5.11
+Contact:	Russ Weight <russell.h.weight@intel.com>
+Description:	Read-only. Returns a string describing the current
+		status of an update. The string will be one of the
+		following: idle, reading, preparing, writing,
+		programming. Userspace code can poll on this file,
+		as it will be signaled by sysfs_notify() on each
+		state change.
diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
index 7d5a4979554b..ad918fb42dc2 100644
--- a/drivers/fpga/ifpga-sec-mgr.c
+++ b/drivers/fpga/ifpga-sec-mgr.c
@@ -139,6 +139,13 @@ static struct attribute *sec_mgr_security_attrs[] = {
 	NULL,
 };
 
+static void update_progress(struct ifpga_sec_mgr *imgr,
+			    enum ifpga_sec_prog new_progress)
+{
+	imgr->progress = new_progress;
+	sysfs_notify(&imgr->dev.kobj, "update", "status");
+}
+
 static void ifpga_sec_dev_error(struct ifpga_sec_mgr *imgr,
 				enum ifpga_sec_err err_code)
 {
@@ -149,7 +156,7 @@ static void ifpga_sec_dev_error(struct ifpga_sec_mgr *imgr,
 static void progress_complete(struct ifpga_sec_mgr *imgr)
 {
 	mutex_lock(&imgr->lock);
-	imgr->progress = IFPGA_SEC_PROG_IDLE;
+	update_progress(imgr, IFPGA_SEC_PROG_IDLE);
 	complete_all(&imgr->update_done);
 	mutex_unlock(&imgr->lock);
 }
@@ -177,14 +184,14 @@ static void ifpga_sec_mgr_update(struct work_struct *work)
 		goto release_fw_exit;
 	}
 
-	imgr->progress = IFPGA_SEC_PROG_PREPARING;
+	update_progress(imgr, IFPGA_SEC_PROG_PREPARING);
 	ret = imgr->iops->prepare(imgr);
 	if (ret) {
 		ifpga_sec_dev_error(imgr, ret);
 		goto modput_exit;
 	}
 
-	imgr->progress = IFPGA_SEC_PROG_WRITING;
+	update_progress(imgr, IFPGA_SEC_PROG_WRITING);
 	size = imgr->remaining_size;
 	while (size) {
 		blk_size = min_t(u32, size, WRITE_BLOCK_SIZE);
@@ -199,7 +206,7 @@ static void ifpga_sec_mgr_update(struct work_struct *work)
 		offset += blk_size;
 	}
 
-	imgr->progress = IFPGA_SEC_PROG_PROGRAMMING;
+	update_progress(imgr, IFPGA_SEC_PROG_PROGRAMMING);
 	ret = imgr->iops->poll_complete(imgr);
 	if (ret) {
 		ifpga_sec_dev_error(imgr, ret);
@@ -259,6 +266,30 @@ static struct attribute_group sec_mgr_security_attr_group = {
 	.is_visible = sec_mgr_visible,
 };
 
+static const char * const sec_mgr_prog_str[] = {
+	"idle",			/* IFPGA_SEC_PROG_IDLE */
+	"reading",		/* IFPGA_SEC_PROG_READING */
+	"preparing",		/* IFPGA_SEC_PROG_PREPARING */
+	"writing",		/* IFPGA_SEC_PROG_WRITING */
+	"programming"		/* IFPGA_SEC_PROG_PROGRAMMING */
+};
+
+static ssize_t
+status_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
+	const char *status = "unknown-status";
+
+	if (imgr->progress < IFPGA_SEC_PROG_MAX)
+		status = sec_mgr_prog_str[imgr->progress];
+	else
+		dev_warn(dev, "Invalid status during secure update: %d\n",
+			 imgr->progress);
+
+	return sprintf(buf, "%s\n", status);
+}
+static DEVICE_ATTR_RO(status);
+
 static ssize_t filename_store(struct device *dev, struct device_attribute *attr,
 			      const char *buf, size_t count)
 {
@@ -293,6 +324,7 @@ static DEVICE_ATTR_WO(filename);
 
 static struct attribute *sec_mgr_update_attrs[] = {
 	&dev_attr_filename.attr,
+	&dev_attr_status.attr,
 	NULL,
 };
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 4/7] fpga: sec-mgr: expose sec-mgr update errors
  2020-10-02 22:36 [PATCH v2 0/7] Intel FPGA Security Manager Class Driver Russ Weight
                   ` (2 preceding siblings ...)
  2020-10-02 22:36 ` [PATCH v2 3/7] fpga: sec-mgr: expose sec-mgr update status Russ Weight
@ 2020-10-02 22:36 ` Russ Weight
  2020-10-04 21:06   ` Tom Rix
  2020-10-05  8:55   ` Wu, Hao
  2020-10-02 22:36 ` [PATCH v2 5/7] fpga: sec-mgr: expose sec-mgr update size Russ Weight
                   ` (3 subsequent siblings)
  7 siblings, 2 replies; 25+ messages in thread
From: Russ Weight @ 2020-10-02 22:36 UTC (permalink / raw)
  To: mdf, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, yilun.xu, hao.wu, matthew.gerlach, Russ Weight

Extend Intel Security Manager class driver to include
an update/error sysfs node that can be read for error
information when a secure update fails.

Signed-off-by: Russ Weight <russell.h.weight@intel.com>
---
v2:
  - Bumped documentation date and version
  - Added warning to sec_progress() for invalid progress status
  - Added sec_error() function (similar to sec_progress())
---
 .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 17 ++++
 drivers/fpga/ifpga-sec-mgr.c                  | 81 ++++++++++++++++---
 include/linux/fpga/ifpga-sec-mgr.h            |  1 +
 3 files changed, 89 insertions(+), 10 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
index 73a5246fea1b..1f9f2c215e0c 100644
--- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
+++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
@@ -89,3 +89,20 @@ Description:	Read-only. Returns a string describing the current
 		programming. Userspace code can poll on this file,
 		as it will be signaled by sysfs_notify() on each
 		state change.
+
+What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/update/error
+Date:		Oct 2020
+KernelVersion:  5.11
+Contact:	Russ Weight <russell.h.weight@intel.com>
+Description:	Read-only. Returns a string describing the failure
+		of a secure update. This string will be in the form
+		of <STATUS>:<ERROR>, where <STATUS> will be one of
+		the status strings described for the status sysfs
+		file and <ERROR> will be one of the following:
+		hw-error, timeout, user-abort, device-busy,
+		invalid-file-size, read-write-error, flash-wearout,
+		file-read-error.  The error sysfs file is only
+		meaningful when the secure update engine is in the
+		idle state. If this file is read while a secure
+		update is in progress, then the read will fail with
+		EBUSY.
diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
index ad918fb42dc2..456ea0b71e3d 100644
--- a/drivers/fpga/ifpga-sec-mgr.c
+++ b/drivers/fpga/ifpga-sec-mgr.c
@@ -146,10 +146,16 @@ static void update_progress(struct ifpga_sec_mgr *imgr,
 	sysfs_notify(&imgr->dev.kobj, "update", "status");
 }
 
+static void set_error(struct ifpga_sec_mgr *imgr, enum ifpga_sec_err err_code)
+{
+	imgr->err_state = imgr->progress;
+	imgr->err_code = err_code;
+}
+
 static void ifpga_sec_dev_error(struct ifpga_sec_mgr *imgr,
 				enum ifpga_sec_err err_code)
 {
-	imgr->err_code = err_code;
+	set_error(imgr, err_code);
 	imgr->iops->cancel(imgr);
 }
 
@@ -172,7 +178,7 @@ static void ifpga_sec_mgr_update(struct work_struct *work)
 
 	get_device(&imgr->dev);
 	if (request_firmware(&fw, imgr->filename, &imgr->dev)) {
-		imgr->err_code = IFPGA_SEC_ERR_FILE_READ;
+		set_error(imgr, IFPGA_SEC_ERR_FILE_READ);
 		goto idle_exit;
 	}
 
@@ -180,7 +186,7 @@ static void ifpga_sec_mgr_update(struct work_struct *work)
 	imgr->remaining_size = fw->size;
 
 	if (!try_module_get(imgr->dev.parent->driver->owner)) {
-		imgr->err_code = IFPGA_SEC_ERR_BUSY;
+		set_error(imgr, IFPGA_SEC_ERR_BUSY);
 		goto release_fw_exit;
 	}
 
@@ -274,22 +280,76 @@ static const char * const sec_mgr_prog_str[] = {
 	"programming"		/* IFPGA_SEC_PROG_PROGRAMMING */
 };
 
-static ssize_t
-status_show(struct device *dev, struct device_attribute *attr, char *buf)
+static const char * const sec_mgr_err_str[] = {
+	"none",			/* IFPGA_SEC_ERR_NONE */
+	"hw-error",		/* IFPGA_SEC_ERR_HW_ERROR */
+	"timeout",		/* IFPGA_SEC_ERR_TIMEOUT */
+	"user-abort",		/* IFPGA_SEC_ERR_CANCELED */
+	"device-busy",		/* IFPGA_SEC_ERR_BUSY */
+	"invalid-file-size",	/* IFPGA_SEC_ERR_INVALID_SIZE */
+	"read-write-error",	/* IFPGA_SEC_ERR_RW_ERROR */
+	"flash-wearout",	/* IFPGA_SEC_ERR_WEAROUT */
+	"file-read-error"	/* IFPGA_SEC_ERR_FILE_READ */
+};
+
+static const char *sec_progress(struct device *dev, enum ifpga_sec_prog prog)
 {
-	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
 	const char *status = "unknown-status";
 
-	if (imgr->progress < IFPGA_SEC_PROG_MAX)
-		status = sec_mgr_prog_str[imgr->progress];
+	if (prog < IFPGA_SEC_PROG_MAX)
+		status = sec_mgr_prog_str[prog];
 	else
 		dev_warn(dev, "Invalid status during secure update: %d\n",
-			 imgr->progress);
+			 prog);
+
+	return status;
+}
+
+static const char *sec_error(struct device *dev, enum ifpga_sec_err err_code)
+{
+	const char *error = "unknown-error";
+
+	if (err_code < IFPGA_SEC_ERR_MAX)
+		error = sec_mgr_err_str[err_code];
+	else
+		dev_warn(dev, "Invalid error code during secure update: %d\n",
+			 err_code);
+
+	return error;
+}
+
+static ssize_t
+status_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
 
-	return sprintf(buf, "%s\n", status);
+	return sprintf(buf, "%s\n", sec_progress(dev, imgr->progress));
 }
 static DEVICE_ATTR_RO(status);
 
+static ssize_t
+error_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
+	int ret;
+
+	mutex_lock(&imgr->lock);
+
+	if (imgr->progress != IFPGA_SEC_PROG_IDLE)
+		ret = -EBUSY;
+	else if (!imgr->err_code)
+		ret = 0;
+	else
+		ret = sprintf(buf, "%s:%s\n",
+			      sec_progress(dev, imgr->err_state),
+			      sec_error(dev, imgr->err_code));
+
+	mutex_unlock(&imgr->lock);
+
+	return ret;
+}
+static DEVICE_ATTR_RO(error);
+
 static ssize_t filename_store(struct device *dev, struct device_attribute *attr,
 			      const char *buf, size_t count)
 {
@@ -325,6 +385,7 @@ static DEVICE_ATTR_WO(filename);
 static struct attribute *sec_mgr_update_attrs[] = {
 	&dev_attr_filename.attr,
 	&dev_attr_status.attr,
+	&dev_attr_error.attr,
 	NULL,
 };
 
diff --git a/include/linux/fpga/ifpga-sec-mgr.h b/include/linux/fpga/ifpga-sec-mgr.h
index 27008abd8e75..246e3d452c59 100644
--- a/include/linux/fpga/ifpga-sec-mgr.h
+++ b/include/linux/fpga/ifpga-sec-mgr.h
@@ -110,6 +110,7 @@ struct ifpga_sec_mgr {
 	const u8 *data;			/* pointer to update data */
 	u32 remaining_size;		/* size remaining to transfer */
 	enum ifpga_sec_prog progress;
+	enum ifpga_sec_prog err_state;	/* progress state at time of failure */
 	enum ifpga_sec_err err_code;	/* security manager error code */
 	bool driver_unload;
 	void *priv;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 5/7] fpga: sec-mgr: expose sec-mgr update size
  2020-10-02 22:36 [PATCH v2 0/7] Intel FPGA Security Manager Class Driver Russ Weight
                   ` (3 preceding siblings ...)
  2020-10-02 22:36 ` [PATCH v2 4/7] fpga: sec-mgr: expose sec-mgr update errors Russ Weight
@ 2020-10-02 22:36 ` Russ Weight
  2020-10-02 22:37 ` [PATCH v2 6/7] fpga: sec-mgr: enable cancel of secure update Russ Weight
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 25+ messages in thread
From: Russ Weight @ 2020-10-02 22:36 UTC (permalink / raw)
  To: mdf, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, yilun.xu, hao.wu, matthew.gerlach, Russ Weight

Extend the Intel Security Manager class driver to include
an update/remaining_size sysfs node that can be read to
determine how much data remains to be transferred to the
secure update engine. This file can be used to monitor
progress during the "writing" phase of an update.

Signed-off-by: Russ Weight <russell.h.weight@intel.com>
Reviewed-by: Tom Rix <trix@redhat.com>
---
v2:
  - Bumped documentation date and version
---
 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr | 11 +++++++++++
 drivers/fpga/ifpga-sec-mgr.c                        | 10 ++++++++++
 2 files changed, 21 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
index 1f9f2c215e0c..ec51135fcb6a 100644
--- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
+++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
@@ -90,6 +90,17 @@ Description:	Read-only. Returns a string describing the current
 		as it will be signaled by sysfs_notify() on each
 		state change.
 
+What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/update/remaining_size
+Date:		Oct 2020
+KernelVersion:  5.11
+Contact:	Russ Weight <russell.h.weight@intel.com>
+Description:	Read-only. Returns the size of data that remains to
+		be written to the secure update engine. The size
+		value is initialized to the full size of the file
+		image and the value is updated periodically during
+		the "writing" phase of the update.
+		Format: "%u".
+
 What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/update/error
 Date:		Oct 2020
 KernelVersion:  5.11
diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
index 456ea0b71e3d..d8ac863c1159 100644
--- a/drivers/fpga/ifpga-sec-mgr.c
+++ b/drivers/fpga/ifpga-sec-mgr.c
@@ -350,6 +350,15 @@ error_show(struct device *dev, struct device_attribute *attr, char *buf)
 }
 static DEVICE_ATTR_RO(error);
 
+static ssize_t remaining_size_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
+
+	return sprintf(buf, "%u\n", imgr->remaining_size);
+}
+static DEVICE_ATTR_RO(remaining_size);
+
 static ssize_t filename_store(struct device *dev, struct device_attribute *attr,
 			      const char *buf, size_t count)
 {
@@ -386,6 +395,7 @@ static struct attribute *sec_mgr_update_attrs[] = {
 	&dev_attr_filename.attr,
 	&dev_attr_status.attr,
 	&dev_attr_error.attr,
+	&dev_attr_remaining_size.attr,
 	NULL,
 };
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 6/7] fpga: sec-mgr: enable cancel of secure update
  2020-10-02 22:36 [PATCH v2 0/7] Intel FPGA Security Manager Class Driver Russ Weight
                   ` (4 preceding siblings ...)
  2020-10-02 22:36 ` [PATCH v2 5/7] fpga: sec-mgr: expose sec-mgr update size Russ Weight
@ 2020-10-02 22:37 ` Russ Weight
  2020-10-04 21:13   ` Tom Rix
  2020-10-02 22:37 ` [PATCH v2 7/7] fpga: sec-mgr: expose hardware error info Russ Weight
  2020-10-04 21:19 ` [PATCH v2 0/7] Intel FPGA Security Manager Class Driver Tom Rix
  7 siblings, 1 reply; 25+ messages in thread
From: Russ Weight @ 2020-10-02 22:37 UTC (permalink / raw)
  To: mdf, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, yilun.xu, hao.wu, matthew.gerlach, Russ Weight

Extend the Intel Security Manager class driver to include
an update/cancel sysfs file that can be written to request
that an update be canceled. The write may return EBUSY if
the update has progressed to the point that it cannot be
canceled by software or ENODEV if there is no update in
progress.

Signed-off-by: Russ Weight <russell.h.weight@intel.com>
---
v2:
  - Bumped documentation date and version
  - Minor code cleanup per review comments 
---
 .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 10 ++++
 drivers/fpga/ifpga-sec-mgr.c                  | 59 +++++++++++++++++--
 include/linux/fpga/ifpga-sec-mgr.h            |  1 +
 3 files changed, 66 insertions(+), 4 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
index ec51135fcb6a..caafe7eb7670 100644
--- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
+++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
@@ -79,6 +79,16 @@ Description:	Write only. Write the filename of an Intel image
 		and Root Entry Hashes, and to cancel Code Signing
 		Keys (CSK).
 
+What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/update/cancel
+Date:		Oct 2020
+KernelVersion:  5.11
+Contact:	Russ Weight <russell.h.weight@intel.com>
+Description:	Write-only. Write a "1" to this file to request
+		that a current update be canceled. This request
+		will be rejected (EBUSY) if the programming phase
+		has already started or (ENODEV) if there is no
+		update in progress.
+
 What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/update/status
 Date:		Oct 2020
 KernelVersion:  5.11
diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
index d8ac863c1159..6267ac3a0780 100644
--- a/drivers/fpga/ifpga-sec-mgr.c
+++ b/drivers/fpga/ifpga-sec-mgr.c
@@ -159,6 +159,23 @@ static void ifpga_sec_dev_error(struct ifpga_sec_mgr *imgr,
 	imgr->iops->cancel(imgr);
 }
 
+static int progress_transition(struct ifpga_sec_mgr *imgr,
+			       enum ifpga_sec_prog new_progress)
+{
+	int ret = 0;
+
+	mutex_lock(&imgr->lock);
+	if (imgr->request_cancel) {
+		set_error(imgr, IFPGA_SEC_ERR_CANCELED);
+		imgr->iops->cancel(imgr);
+		ret = -ECANCELED;
+	} else {
+		update_progress(imgr, new_progress);
+	}
+	mutex_unlock(&imgr->lock);
+	return ret;
+}
+
 static void progress_complete(struct ifpga_sec_mgr *imgr)
 {
 	mutex_lock(&imgr->lock);
@@ -190,16 +207,20 @@ static void ifpga_sec_mgr_update(struct work_struct *work)
 		goto release_fw_exit;
 	}
 
-	update_progress(imgr, IFPGA_SEC_PROG_PREPARING);
+	if (progress_transition(imgr, IFPGA_SEC_PROG_PREPARING))
+		goto modput_exit;
+
 	ret = imgr->iops->prepare(imgr);
 	if (ret) {
 		ifpga_sec_dev_error(imgr, ret);
 		goto modput_exit;
 	}
 
-	update_progress(imgr, IFPGA_SEC_PROG_WRITING);
+	if (progress_transition(imgr, IFPGA_SEC_PROG_WRITING))
+		goto done;
+
 	size = imgr->remaining_size;
-	while (size) {
+	while (size && !imgr->request_cancel) {
 		blk_size = min_t(u32, size, WRITE_BLOCK_SIZE);
 		size -= blk_size;
 		ret = imgr->iops->write_blk(imgr, offset, blk_size);
@@ -212,7 +233,9 @@ static void ifpga_sec_mgr_update(struct work_struct *work)
 		offset += blk_size;
 	}
 
-	update_progress(imgr, IFPGA_SEC_PROG_PROGRAMMING);
+	if (progress_transition(imgr, IFPGA_SEC_PROG_PROGRAMMING))
+		goto done;
+
 	ret = imgr->iops->poll_complete(imgr);
 	if (ret) {
 		ifpga_sec_dev_error(imgr, ret);
@@ -381,6 +404,7 @@ static ssize_t filename_store(struct device *dev, struct device_attribute *attr,
 	}
 
 	imgr->err_code = IFPGA_SEC_ERR_NONE;
+	imgr->request_cancel = false;
 	imgr->progress = IFPGA_SEC_PROG_READING;
 	reinit_completion(&imgr->update_done);
 	schedule_work(&imgr->work);
@@ -391,8 +415,32 @@ static ssize_t filename_store(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_WO(filename);
 
+static ssize_t cancel_store(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
+	bool cancel;
+	int ret = count;
+
+	if (kstrtobool(buf, &cancel) || !cancel)
+		return -EINVAL;
+
+	mutex_lock(&imgr->lock);
+	if (imgr->progress == IFPGA_SEC_PROG_PROGRAMMING)
+		ret = -EBUSY;
+	else if (imgr->progress == IFPGA_SEC_PROG_IDLE)
+		ret = -ENODEV;
+	else
+		imgr->request_cancel = true;
+	mutex_unlock(&imgr->lock);
+
+	return ret;
+}
+static DEVICE_ATTR_WO(cancel);
+
 static struct attribute *sec_mgr_update_attrs[] = {
 	&dev_attr_filename.attr,
+	&dev_attr_cancel.attr,
 	&dev_attr_status.attr,
 	&dev_attr_error.attr,
 	&dev_attr_remaining_size.attr,
@@ -653,6 +701,9 @@ void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr)
 		goto unregister;
 	}
 
+	if (imgr->progress != IFPGA_SEC_PROG_PROGRAMMING)
+		imgr->request_cancel = true;
+
 	mutex_unlock(&imgr->lock);
 	wait_for_completion(&imgr->update_done);
 
diff --git a/include/linux/fpga/ifpga-sec-mgr.h b/include/linux/fpga/ifpga-sec-mgr.h
index 246e3d452c59..890be0800b05 100644
--- a/include/linux/fpga/ifpga-sec-mgr.h
+++ b/include/linux/fpga/ifpga-sec-mgr.h
@@ -112,6 +112,7 @@ struct ifpga_sec_mgr {
 	enum ifpga_sec_prog progress;
 	enum ifpga_sec_prog err_state;	/* progress state at time of failure */
 	enum ifpga_sec_err err_code;	/* security manager error code */
+	bool request_cancel;
 	bool driver_unload;
 	void *priv;
 };
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 7/7] fpga: sec-mgr: expose hardware error info
  2020-10-02 22:36 [PATCH v2 0/7] Intel FPGA Security Manager Class Driver Russ Weight
                   ` (5 preceding siblings ...)
  2020-10-02 22:37 ` [PATCH v2 6/7] fpga: sec-mgr: enable cancel of secure update Russ Weight
@ 2020-10-02 22:37 ` Russ Weight
  2020-10-04 21:19 ` [PATCH v2 0/7] Intel FPGA Security Manager Class Driver Tom Rix
  7 siblings, 0 replies; 25+ messages in thread
From: Russ Weight @ 2020-10-02 22:37 UTC (permalink / raw)
  To: mdf, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, yilun.xu, hao.wu, matthew.gerlach, Russ Weight

Extend the Intel Security Manager class driver to include
an optional update/hw_errinfo sysfs node that can be used
to retrieve 64 bits of device specific error information
following a secure update failure.

The underlying driver must provide a get_hw_errinfo() callback
function to enable this feature. This data is treated as
opaque by the class driver. It is left to user-space software
or support personnel to interpret this data.

Signed-off-by: Russ Weight <russell.h.weight@intel.com>
Reviewed-by: Tom Rix <trix@redhat.com>
---
v2:
  - Bumped documentation date and version
---
 .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 14 +++++++
 drivers/fpga/ifpga-sec-mgr.c                  | 38 +++++++++++++++++++
 include/linux/fpga/ifpga-sec-mgr.h            |  5 +++
 3 files changed, 57 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
index caafe7eb7670..37a335ff4936 100644
--- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
+++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
@@ -127,3 +127,17 @@ Description:	Read-only. Returns a string describing the failure
 		idle state. If this file is read while a secure
 		update is in progress, then the read will fail with
 		EBUSY.
+
+What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/update/hw_errinfo
+Date:		Oct 2020
+KernelVersion:  5.11
+Contact:	Russ Weight <russell.h.weight@intel.com>
+Description:	Read-only. Returns a 64 bit error value providing
+		hardware specific information that may be useful in
+		debugging errors that occur during FPGA image updates.
+		This file is only visible if the underlying device
+		supports it. The hw_errinfo value is only accessible
+		when the secure update engine is in the idle state.
+		If this file is read while a secure update is in
+		progress, then the read will fail with EBUSY.
+		Format: "0x%llx".
diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
index 6267ac3a0780..eb306dff7d31 100644
--- a/drivers/fpga/ifpga-sec-mgr.c
+++ b/drivers/fpga/ifpga-sec-mgr.c
@@ -152,10 +152,17 @@ static void set_error(struct ifpga_sec_mgr *imgr, enum ifpga_sec_err err_code)
 	imgr->err_code = err_code;
 }
 
+static void set_hw_errinfo(struct ifpga_sec_mgr *imgr)
+{
+	if (imgr->iops->get_hw_errinfo)
+		imgr->hw_errinfo = imgr->iops->get_hw_errinfo(imgr);
+}
+
 static void ifpga_sec_dev_error(struct ifpga_sec_mgr *imgr,
 				enum ifpga_sec_err err_code)
 {
 	set_error(imgr, err_code);
+	set_hw_errinfo(imgr);
 	imgr->iops->cancel(imgr);
 }
 
@@ -373,6 +380,23 @@ error_show(struct device *dev, struct device_attribute *attr, char *buf)
 }
 static DEVICE_ATTR_RO(error);
 
+static ssize_t
+hw_errinfo_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
+	int ret;
+
+	mutex_lock(&imgr->lock);
+	if (imgr->progress != IFPGA_SEC_PROG_IDLE)
+		ret = -EBUSY;
+	else
+		ret = sprintf(buf, "0x%llx\n", imgr->hw_errinfo);
+	mutex_unlock(&imgr->lock);
+
+	return ret;
+}
+static DEVICE_ATTR_RO(hw_errinfo);
+
 static ssize_t remaining_size_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
@@ -404,6 +428,7 @@ static ssize_t filename_store(struct device *dev, struct device_attribute *attr,
 	}
 
 	imgr->err_code = IFPGA_SEC_ERR_NONE;
+	imgr->hw_errinfo = 0;
 	imgr->request_cancel = false;
 	imgr->progress = IFPGA_SEC_PROG_READING;
 	reinit_completion(&imgr->update_done);
@@ -438,18 +463,31 @@ static ssize_t cancel_store(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_WO(cancel);
 
+static umode_t
+sec_mgr_update_visible(struct kobject *kobj, struct attribute *attr, int n)
+{
+	struct ifpga_sec_mgr *imgr = to_sec_mgr(kobj_to_dev(kobj));
+
+	if (attr == &dev_attr_hw_errinfo.attr && !imgr->iops->get_hw_errinfo)
+		return 0;
+
+	return attr->mode;
+}
+
 static struct attribute *sec_mgr_update_attrs[] = {
 	&dev_attr_filename.attr,
 	&dev_attr_cancel.attr,
 	&dev_attr_status.attr,
 	&dev_attr_error.attr,
 	&dev_attr_remaining_size.attr,
+	&dev_attr_hw_errinfo.attr,
 	NULL,
 };
 
 static struct attribute_group sec_mgr_update_attr_group = {
 	.name = "update",
 	.attrs = sec_mgr_update_attrs,
+	.is_visible = sec_mgr_update_visible,
 };
 
 static ssize_t name_show(struct device *dev,
diff --git a/include/linux/fpga/ifpga-sec-mgr.h b/include/linux/fpga/ifpga-sec-mgr.h
index 890be0800b05..baf4fe876164 100644
--- a/include/linux/fpga/ifpga-sec-mgr.h
+++ b/include/linux/fpga/ifpga-sec-mgr.h
@@ -60,6 +60,9 @@ enum ifpga_sec_err {
  *			    function and is called at the completion
  *			    of the update, whether success or failure,
  *			    if the prepare function succeeded.
+ * @get_hw_errinfo:	    Optional: Return u64 hw specific error info.
+ *			    The software err_code may used to determine
+ *			    whether the hw error info is applicable.
  */
 struct ifpga_sec_mgr_ops {
 	int (*user_flash_count)(struct ifpga_sec_mgr *imgr);
@@ -87,6 +90,7 @@ struct ifpga_sec_mgr_ops {
 	enum ifpga_sec_err (*poll_complete)(struct ifpga_sec_mgr *imgr);
 	void (*cleanup)(struct ifpga_sec_mgr *imgr);
 	enum ifpga_sec_err (*cancel)(struct ifpga_sec_mgr *imgr);
+	u64 (*get_hw_errinfo)(struct ifpga_sec_mgr *imgr);
 };
 
 /* Update progress codes */
@@ -112,6 +116,7 @@ struct ifpga_sec_mgr {
 	enum ifpga_sec_prog progress;
 	enum ifpga_sec_prog err_state;	/* progress state at time of failure */
 	enum ifpga_sec_err err_code;	/* security manager error code */
+	u64 hw_errinfo;			/* 64 bits of HW specific error info */
 	bool request_cancel;
 	bool driver_unload;
 	void *priv;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 1/7] fpga: sec-mgr: intel fpga security manager class driver
  2020-10-02 22:36 ` [PATCH v2 1/7] fpga: sec-mgr: intel fpga security manager class driver Russ Weight
@ 2020-10-02 23:03   ` Russ Weight
  2020-10-03  1:02     ` Moritz Fischer
  2020-10-04 20:43   ` Tom Rix
  2020-10-05  7:38   ` Wu, Hao
  2 siblings, 1 reply; 25+ messages in thread
From: Russ Weight @ 2020-10-02 23:03 UTC (permalink / raw)
  To: mdf, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, yilun.xu, hao.wu, matthew.gerlach

Hi Moritz,

This patch aligns with FPGA Manager implementation as you requested by
splitting up the create() and register() functions and adding a devm_
version of the create() function. I have a question (below) regarding the
device_add() function call.


On 10/2/20 3:36 PM, Russ Weight wrote:
> Create the Intel Security Manager class driver. The security
> manager provides interfaces to manage secure updates for the
> FPGA and BMC images that are stored in FLASH. The driver can
> also be used to update root entry hashes and to cancel code
> signing keys.
>
> This patch creates the class driver and provides sysfs
> interfaces for displaying root entry hashes, canceled code
> signing keys and flash counts.
>
> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
> Signed-off-by: Xu Yilun <yilun.xu@intel.com>
> ---
> v2:
>   - Bumped documentation dates and versions
>   - Added Documentation/fpga/ifpga-sec-mgr.rst 
>   - Removed references to bmc_flash_count & smbus_flash_count (not supported)
>   - Split ifpga_sec_mgr_register() into create() and register() functions
>   - Added devm_ifpga_sec_mgr_create()
>   - Removed typedefs for imgr ops
> ---
>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  67 +++
>  Documentation/fpga/ifpga-sec-mgr.rst          |  50 ++
>  Documentation/fpga/index.rst                  |   1 +
>  MAINTAINERS                                   |   9 +
>  drivers/fpga/Kconfig                          |   9 +
>  drivers/fpga/Makefile                         |   3 +
>  drivers/fpga/ifpga-sec-mgr.c                  | 432 ++++++++++++++++++
>  include/linux/fpga/ifpga-sec-mgr.h            |  81 ++++
>  8 files changed, 652 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>  create mode 100644 Documentation/fpga/ifpga-sec-mgr.rst
>  create mode 100644 drivers/fpga/ifpga-sec-mgr.c
>  create mode 100644 include/linux/fpga/ifpga-sec-mgr.h
>
> diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> new file mode 100644
> index 000000000000..707958971bcb
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> @@ -0,0 +1,67 @@
> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/name
> +Date:		Oct 2020
> +KernelVersion:  5.11
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Name of low level fpga security manager driver.
> +
> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/sr_root_entry_hash
> +Date:		Oct 2020
> +KernelVersion:  5.11
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Read only. Returns the root entry hash for the static
> +		region if one is programmed, else it returns the
> +		string: "hash not programmed".  This file is only
> +		visible if the underlying device supports it.
> +		Format: "0x%x".
> +
> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/pr_root_entry_hash
> +Date:		Oct 2020
> +KernelVersion:  5.11
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Read only. Returns the root entry hash for the partial
> +		reconfiguration region if one is programmed, else it
> +		returns the string: "hash not programmed".  This file
> +		is only visible if the underlying device supports it.
> +		Format: "0x%x".
> +
> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/bmc_root_entry_hash
> +Date:		Oct 2020
> +KernelVersion:  5.11
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Read only. Returns the root entry hash for the BMC image
> +		if one is programmed, else it returns the string:
> +		"hash not programmed".  This file is only visible if the
> +		underlying device supports it.
> +		Format: "0x%x".
> +
> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/sr_canceled_csks
> +Date:		Oct 2020
> +KernelVersion:  5.11
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Read only. Returns a list of indices for canceled code
> +		signing keys for the static region. The standard bitmap
> +		list format is used (e.g. "1,2-6,9").
> +
> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/pr_canceled_csks
> +Date:		Oct 2020
> +KernelVersion:  5.11
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Read only. Returns a list of indices for canceled code
> +		signing keys for the partial reconfiguration region. The
> +		standard bitmap list format is used (e.g. "1,2-6,9").
> +
> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/bmc_canceled_csks
> +Date:		Oct 2020
> +KernelVersion:  5.11
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Read only. Returns a list of indices for canceled code
> +		signing keys for the BMC.  The standard bitmap list format
> +		is used (e.g. "1,2-6,9").
> +
> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/user_flash_count
> +Date:		Oct 2020
> +KernelVersion:  5.11
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Read only. Returns number of times the user image for the
> +		static region has been flashed.
> +		Format: "%u".
> diff --git a/Documentation/fpga/ifpga-sec-mgr.rst b/Documentation/fpga/ifpga-sec-mgr.rst
> new file mode 100644
> index 000000000000..02f3f65b182b
> --- /dev/null
> +++ b/Documentation/fpga/ifpga-sec-mgr.rst
> @@ -0,0 +1,50 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +========================================
> +Intel FPGA Security Manager Class Driver
> +========================================
> +
> +The Intel FPGA Security Manager class driver provides a common
> +API for user-space tools to manage updates for secure Intel FPGA
> +devices. Device drivers that instantiate the Intel Security
> +Manager class driver will interact with a HW secure update
> +engine in order to transfer new FPGA and BMC images to FLASH so
> +that they will be automatically loaded when the FPGA card reboots.
> +
> +A significant difference between the FPGA Manager and the Intel FPGA
> +Security Manager is that the FPGA Manager does a live update (Partial
> +Reconfiguration) to a device, whereas the Intel FPGA Security Manager
> +updates the FLASH images for the Static Region and the BMC so that
> +they will be loaded the next time the FPGA card boots. Security is
> +enforced by hardware and firmware. The security manager interacts
> +with the firmware to initiate an update, pass in the necessary data,
> +and collect status on the update.
> +
> +In addition to managing secure updates of the FPGA and BMC images,
> +the Intel FPGA Security Manager update process may also used to
> +program root entry hashes and cancellation keys for the FPGA static
> +region, the FPGA partial reconfiguration region, and the BMC.
> +
> +Secure updates make use of the request_firmware framework, which
> +requires that image files are accessible under /lib/firmware. A request
> +for a secure update returns immediately, while the update itself
> +proceeds in the context of a kernel worker thread. Sysfs files provide
> +a means for monitoring the progress of a secure update and for
> +retrieving error information in the event of a failure.
> +
> +Sysfs Attributes
> +================
> +
> +The API consists of two groups of sysfs attributes as described below.
> +
> +1. Files in the *security* sub-directory can be used to read security
> +   information including: Root Entry Hashes (REH), Cancelled Code
> +   Signing Keys (CSK), and the flash update count for FPGA images.
> +
> +2. Files in the *update* sub-directory can be used to instantiate and
> +   monitor a secure update.
> +
> +
> +See `<../ABI/testing/sysfs-class-ifpga-sec-mgr>`__ for a full
> +description of the sysfs attributes for the Intel FPGA Security
> +Manager.
> diff --git a/Documentation/fpga/index.rst b/Documentation/fpga/index.rst
> index f80f95667ca2..ba9c6b1917bd 100644
> --- a/Documentation/fpga/index.rst
> +++ b/Documentation/fpga/index.rst
> @@ -8,6 +8,7 @@ fpga
>      :maxdepth: 1
>  
>      dfl
> +    ifpga-sec-mgr
>  
>  .. only::  subproject and html
>  
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 6d1175bf8529..5ffc0e02d741 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -6858,6 +6858,15 @@ F:	Documentation/fpga/
>  F:	drivers/fpga/
>  F:	include/linux/fpga/
>  
> +INTEL FPGA SECURITY MANAGER DRIVERS
> +M:	Russ Weight <russell.h.weight@intel.com>
> +L:	linux-fpga@vger.kernel.org
> +S:	Maintained
> +F:	Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> +F:	Documentation/fpga/ifpga-sec-mgr.rst
> +F:	drivers/fpga/ifpga-sec-mgr.c
> +F:	include/linux/fpga/ifpga-sec-mgr.h
> +
>  FPU EMULATOR
>  M:	Bill Metzenthen <billm@melbpc.org.au>
>  S:	Maintained
> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> index 7cd5a29fc437..bf566a625be7 100644
> --- a/drivers/fpga/Kconfig
> +++ b/drivers/fpga/Kconfig
> @@ -215,4 +215,13 @@ config FPGA_MGR_ZYNQMP_FPGA
>  	  to configure the programmable logic(PL) through PS
>  	  on ZynqMP SoC.
>  
> +config IFPGA_SEC_MGR
> +	tristate "Intel Security Manager for FPGA"
> +	help
> +	  The Intel Security Manager class driver presents a common
> +	  user API for managing secure updates for Intel FPGA
> +	  devices, including flash images for the FPGA static
> +	  region and for the BMC. Select this option to enable
> +	  updates for secure FPGA devices.
> +
>  endif # FPGA
> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
> index d8e21dfc6778..2e1d29c3d915 100644
> --- a/drivers/fpga/Makefile
> +++ b/drivers/fpga/Makefile
> @@ -21,6 +21,9 @@ obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
>  obj-$(CONFIG_ALTERA_PR_IP_CORE)         += altera-pr-ip-core.o
>  obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT)    += altera-pr-ip-core-plat.o
>  
> +# Intel FPGA Security Manager Framework
> +obj-$(CONFIG_IFPGA_SEC_MGR)		+= ifpga-sec-mgr.o
> +
>  # FPGA Bridge Drivers
>  obj-$(CONFIG_FPGA_BRIDGE)		+= fpga-bridge.o
>  obj-$(CONFIG_SOCFPGA_FPGA_BRIDGE)	+= altera-hps2fpga.o altera-fpga2sdram.o
> diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
> new file mode 100644
> index 000000000000..f1caa4602ab3
> --- /dev/null
> +++ b/drivers/fpga/ifpga-sec-mgr.c
> @@ -0,0 +1,432 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Intel Security Manager for FPGA
> + *
> + * Copyright (C) 2019-2020 Intel Corporation, Inc.
> + */
> +
> +#include <linux/fpga/ifpga-sec-mgr.h>
> +#include <linux/idr.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/vmalloc.h>
> +
> +static DEFINE_IDA(ifpga_sec_mgr_ida);
> +static struct class *ifpga_sec_mgr_class;
> +
> +#define to_sec_mgr(d) container_of(d, struct ifpga_sec_mgr, dev)
> +
> +static ssize_t
> +show_canceled_csk(struct ifpga_sec_mgr *imgr,
> +		  int (*get_csk)(struct ifpga_sec_mgr *imgr,
> +				 unsigned long *csk_map, unsigned int nbits),
> +		  int (*get_csk_nbits)(struct ifpga_sec_mgr *imgr),
> +		  char *buf)
> +{
> +	unsigned long *csk_map = NULL;
> +	unsigned int nbits;
> +	int ret;
> +
> +	ret = get_csk_nbits(imgr);
> +	if (ret < 0)
> +		return ret;
> +
> +	nbits = (unsigned int)ret;
> +	csk_map = vmalloc(sizeof(unsigned long) * BITS_TO_LONGS(nbits));
> +	if (!csk_map)
> +		return -ENOMEM;
> +
> +	ret = get_csk(imgr, csk_map, nbits);
> +	if (ret)
> +		goto vfree_exit;
> +
> +	ret = bitmap_print_to_pagebuf(1, buf, csk_map, nbits);
> +
> +vfree_exit:
> +	vfree(csk_map);
> +	return ret;
> +}
> +
> +static ssize_t
> +show_root_entry_hash(struct ifpga_sec_mgr *imgr,
> +		     int (*get_reh)(struct ifpga_sec_mgr *imgr, u8 *hash,
> +				    unsigned int size),
> +		     int (*get_reh_size)(struct ifpga_sec_mgr *imgr),
> +		     char *buf)
> +{
> +	int size, i, cnt, ret;
> +	u8 *hash;
> +
> +	ret = get_reh_size(imgr);
> +	if (ret < 0)
> +		return ret;
> +	else if (!ret)
> +		return sprintf(buf, "hash not programmed\n");
> +
> +	size = ret;
> +	hash = vmalloc(size);
> +	if (!hash)
> +		return -ENOMEM;
> +
> +	ret = get_reh(imgr, hash, size);
> +	if (ret)
> +		goto vfree_exit;
> +
> +	cnt = sprintf(buf, "0x");
> +	for (i = 0; i < size; i++)
> +		cnt += sprintf(buf + cnt, "%02x", hash[i]);
> +	cnt += sprintf(buf + cnt, "\n");
> +
> +vfree_exit:
> +	vfree(hash);
> +	return ret ? : cnt;
> +}
> +
> +#define DEVICE_ATTR_SEC_CSK(_name) \
> +static ssize_t _name##_canceled_csks_show(struct device *dev, \
> +					  struct device_attribute *attr, \
> +					  char *buf) \
> +{ \
> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev); \
> +	return show_canceled_csk(imgr, \
> +	       imgr->iops->_name##_canceled_csks, \
> +	       imgr->iops->_name##_canceled_csk_nbits, buf); \
> +} \
> +static DEVICE_ATTR_RO(_name##_canceled_csks)
> +
> +#define DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(_name) \
> +static ssize_t _name##_root_entry_hash_show(struct device *dev, \
> +				     struct device_attribute *attr, \
> +				     char *buf) \
> +{ \
> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev); \
> +	return show_root_entry_hash(imgr, \
> +	       imgr->iops->_name##_root_entry_hash, \
> +	       imgr->iops->_name##_reh_size, buf); \
> +} \
> +static DEVICE_ATTR_RO(_name##_root_entry_hash)
> +
> +static ssize_t user_flash_count_show(struct device *dev,
> +				     struct device_attribute *attr, char *buf)
> +{
> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
> +
> +	int cnt = imgr->iops->user_flash_count(imgr);
> +	return cnt < 0 ? cnt : sprintf(buf, "%u\n", cnt);
> +}
> +static DEVICE_ATTR_RO(user_flash_count);
> +
> +DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(sr);
> +DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(pr);
> +DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(bmc);
> +DEVICE_ATTR_SEC_CSK(sr);
> +DEVICE_ATTR_SEC_CSK(pr);
> +DEVICE_ATTR_SEC_CSK(bmc);
> +
> +static struct attribute *sec_mgr_security_attrs[] = {
> +	&dev_attr_user_flash_count.attr,
> +	&dev_attr_bmc_root_entry_hash.attr,
> +	&dev_attr_sr_root_entry_hash.attr,
> +	&dev_attr_pr_root_entry_hash.attr,
> +	&dev_attr_sr_canceled_csks.attr,
> +	&dev_attr_pr_canceled_csks.attr,
> +	&dev_attr_bmc_canceled_csks.attr,
> +	NULL,
> +};
> +
> +#define check_attr(attribute, _name) \
> +	((attribute) == &dev_attr_##_name.attr && imgr->iops->_name)
> +
> +static umode_t sec_mgr_visible(struct kobject *kobj,
> +			       struct attribute *attr, int n)
> +{
> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(kobj_to_dev(kobj));
> +
> +	/*
> +	 * Only display optional sysfs attributes if a
> +	 * corresponding handler is provided
> +	 */
> +	if (check_attr(attr, user_flash_count) ||
> +	    check_attr(attr, bmc_root_entry_hash) ||
> +	    check_attr(attr, sr_root_entry_hash) ||
> +	    check_attr(attr, pr_root_entry_hash) ||
> +	    check_attr(attr, sr_canceled_csks) ||
> +	    check_attr(attr, pr_canceled_csks) ||
> +	    check_attr(attr, bmc_canceled_csks))
> +		return attr->mode;
> +
> +	return 0;
> +}
> +
> +static struct attribute_group sec_mgr_security_attr_group = {
> +	.name = "security",
> +	.attrs = sec_mgr_security_attrs,
> +	.is_visible = sec_mgr_visible,
> +};
> +
> +static ssize_t name_show(struct device *dev,
> +			 struct device_attribute *attr, char *buf)
> +{
> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
> +
> +	return sprintf(buf, "%s\n", imgr->name);
> +}
> +static DEVICE_ATTR_RO(name);
> +
> +static struct attribute *sec_mgr_attrs[] = {
> +	&dev_attr_name.attr,
> +	NULL,
> +};
> +
> +static struct attribute_group sec_mgr_attr_group = {
> +	.attrs = sec_mgr_attrs,
> +};
> +
> +static const struct attribute_group *ifpga_sec_mgr_attr_groups[] = {
> +	&sec_mgr_attr_group,
> +	&sec_mgr_security_attr_group,
> +	NULL,
> +};
> +
> +static bool check_sysfs_handler(struct device *dev,
> +				void *sysfs_handler, void *size_handler,
> +				const char *sysfs_handler_name,
> +				const char *size_handler_name)
> +{
> +	/*
> +	 * sysfs_handler and size_handler must either both be
> +	 * defined or both be NULL.
> +	 */
> +	if (sysfs_handler) {
> +		if (!size_handler) {
> +			dev_err(dev, "%s registered without %s\n",
> +				sysfs_handler_name, size_handler_name);
> +			return false;
> +		}
> +	} else if (size_handler) {
> +		dev_err(dev, "%s registered without %s\n",
> +			size_handler_name, sysfs_handler_name);
> +		return false;
> +	}
> +	return true;
> +}
> +
> +#define check_reh_handler(_dev, _iops, _name) \
> +	check_sysfs_handler(_dev, (_iops)->_name##_root_entry_hash, \
> +			    (_iops)->_name##_reh_size, \
> +			    __stringify(_name##_root_entry_hash), \
> +			    __stringify(_name##_reh_size))
> +
> +#define check_csk_handler(_dev, _iops, _name) \
> +	check_sysfs_handler(_dev, (_iops)->_name##_canceled_csks, \
> +			    (_iops)->_name##_canceled_csk_nbits, \
> +			    __stringify(_name##_canceled_csks), \
> +			    __stringify(_name##_canceled_csk_nbits))
> +
> +/**
> + * ifpga_sec_mgr_create - create and initialize an Intel FPGA
> + *			  security manager struct
> + *
> + * @dev:  Intel fpga security manager device from pdev
> + * @name: ifpga security manager name
> + * @iops: pointer to a structure of ifpga callback functions
> + * @priv: ifpga security manager private data
> + *
> + * The caller of this function is responsible for freeing the struct
> + * with ifpg_sec_mgr_free(). Using devm_ifpga_sec_mgr_create() instead
> + * is recommended.
> + *
> + * Return: pointer to struct ifpga_sec_mgr or NULL
> + */
> +struct ifpga_sec_mgr *
> +ifpga_sec_mgr_create(struct device *dev, const char *name,
> +		     const struct ifpga_sec_mgr_ops *iops, void *priv)
> +{
> +	struct ifpga_sec_mgr *imgr;
> +	int id, ret;
> +
> +	if (!check_reh_handler(dev, iops, bmc) ||
> +	    !check_reh_handler(dev, iops, sr) ||
> +	    !check_reh_handler(dev, iops, pr) ||
> +	    !check_csk_handler(dev, iops, bmc) ||
> +	    !check_csk_handler(dev, iops, sr) ||
> +	    !check_csk_handler(dev, iops, pr)) {
> +		return NULL;
> +	}
> +
> +	if (!name || !strlen(name)) {
> +		dev_err(dev, "Attempt to register with no name!\n");
> +		return NULL;
> +	}
> +
> +	imgr = kzalloc(sizeof(*imgr), GFP_KERNEL);
> +	if (!imgr)
> +		return NULL;
> +
> +	id = ida_simple_get(&ifpga_sec_mgr_ida, 0, 0, GFP_KERNEL);
> +	if (id < 0)
> +		goto error_kfree;
> +
> +	mutex_init(&imgr->lock);
> +
> +	imgr->name = name;
> +	imgr->priv = priv;
> +	imgr->iops = iops;
> +
> +	device_initialize(&imgr->dev);
> +	imgr->dev.class = ifpga_sec_mgr_class;
> +	imgr->dev.parent = dev;
> +	imgr->dev.id = id;
> +
> +	ret = dev_set_name(&imgr->dev, "ifpga_sec%d", id);
> +	if (ret) {
> +		dev_err(dev, "Failed to set device name: ifpga_sec%d\n", id);
> +		goto error_device;
> +	}
> +
> +	return imgr;
> +
> +error_device:
> +	ida_simple_remove(&ifpga_sec_mgr_ida, id);
> +
> +error_kfree:
> +	kfree(imgr);
> +
> +	return NULL;
> +}
> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_create);
> +
> +/**
> + * ifpga_sec_mgr_free - free an Intel FPGA security manager created
> + *			with ifpga_sec_mgr_create()
> + *
> + * @imgr:	Intel FPGA security manager structure
> + */
> +void ifpga_sec_mgr_free(struct ifpga_sec_mgr *imgr)
> +{
> +	ida_simple_remove(&ifpga_sec_mgr_ida, imgr->dev.id);
> +	kfree(imgr);
> +}
> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_free);
> +
> +static void devm_ifpga_sec_mgr_release(struct device *dev, void *res)
> +{
> +	struct ifpga_sec_mgr *imgr = *(struct ifpga_sec_mgr **)res;
> +
> +	ifpga_sec_mgr_free(imgr);
> +}
> +
> +/**
> + * devm_ifpga_sec_mgr_create - create and initialize an Intel FPGA
> + *			       security manager struct
> + *
> + * @dev:  Intel fpga security manager device from pdev
> + * @name: ifpga security manager name
> + * @iops: pointer to a structure of ifpga callback functions
> + * @priv: ifpga security manager private data
> + *
> + * This function is intended for use in a Intel FPGA Security manager
> + * driver's probe function.  After the security manager driver creates
> + * the ifpga_sec_mgr struct with devm_fpga_mgr_create(), it should
> + * register it with ifpga_sec_mgr_register().  The security manager
> + * driver's remove function should call ifpga_sec_mgr_unregister().
> + * The ifpga_sec_mgr struct allocated with this function will be freed
> + * automatically on driver detach.  This includes the case of a probe
> + * function returning error before calling fpga_mgr_register(), the
> + * struct will still get cleaned up.
> + *
> + * Return: pointer to struct ifpga_sec_mgr or NULL
> + */
> +struct ifpga_sec_mgr *
> +devm_ifpga_sec_mgr_create(struct device *dev, const char *name,
> +			  const struct ifpga_sec_mgr_ops *iops, void *priv)
> +{
> +	struct ifpga_sec_mgr **ptr, *imgr;
> +
> +	ptr = devres_alloc(devm_ifpga_sec_mgr_release, sizeof(*ptr), GFP_KERNEL);
> +	if (!ptr)
> +		return NULL;
> +
> +	imgr = ifpga_sec_mgr_create(dev, name, iops, priv);
> +	if (!imgr) {
> +		devres_free(ptr);
> +	} else {
> +		*ptr = imgr;
> +		devres_add(dev, ptr);
> +	}
> +
> +	return imgr;
> +}
> +EXPORT_SYMBOL_GPL(devm_ifpga_sec_mgr_create);
> +
> +/**
> + * ifpga_sec_mgr_register - register an Intel FPGA security manager
> + *
> + * @imgr: Intel fpga security manager struct
> + *
> + * Return: 0 on success, negative error code otherwise.
> + */
> +int ifpga_sec_mgr_register(struct ifpga_sec_mgr *imgr)
> +{
> +	int ret;
> +
> +	ret = device_add(&imgr->dev);
> +	if (ret)
> +		goto error_device;
The comment header for device_add() includes the following text:

 * NOTE: _Never_ directly free @dev after calling this function, even
 * if it returned an error! Always use put_device() to give up your
 * reference instead.
 *
 * Rule of thumb is: if device_add() succeeds, you should call
 * device_del() when you want to get rid of it. If device_add() has
 * *not* succeeded, use *only* put_device() to drop the reference
 * count.

This implementation of the security manager requires that the parent
driver (which implements the security manager) explicitly free the
ifpga_sec_mgr structure or implicitly free it as a managed resource
(of the parent device) using the devm_ version of the create() function.
The device structure that is passed to device_add() above is embedded
in the ifpga_sec_mgr structure.

Does this implementation conflict with the core driver functions?
Is it possible that we are deleting a device structure that is still
being tracked by the core driver code?

- Russ

> +
> +	dev_info(&imgr->dev, "%s registered\n", imgr->name);
> +
> +	return 0;
> +
> +error_device:
> +	ida_simple_remove(&ifpga_sec_mgr_ida, imgr->dev.id);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_register);
> +
> +/**
> + * ifpga_sec_mgr_unregister - unregister an Intel FPGA security manager
> + *
> + * @mgr: fpga manager struct
> + *
> + * This function is intended for use in an Intel FPGA security manager
> + * driver's remove() function.
> + */
> +void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr)
> +{
> +	dev_info(&imgr->dev, "%s %s\n", __func__, imgr->name);
> +
> +	device_unregister(&imgr->dev);
> +}
> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_unregister);
> +
> +static void ifpga_sec_mgr_dev_release(struct device *dev)
> +{
> +}
> +
> +static int __init ifpga_sec_mgr_class_init(void)
> +{
> +	pr_info("Intel FPGA Security Manager\n");
> +
> +	ifpga_sec_mgr_class = class_create(THIS_MODULE, "ifpga_sec_mgr");
> +	if (IS_ERR(ifpga_sec_mgr_class))
> +		return PTR_ERR(ifpga_sec_mgr_class);
> +
> +	ifpga_sec_mgr_class->dev_groups = ifpga_sec_mgr_attr_groups;
> +	ifpga_sec_mgr_class->dev_release = ifpga_sec_mgr_dev_release;
> +
> +	return 0;
> +}
> +
> +static void __exit ifpga_sec_mgr_class_exit(void)
> +{
> +	class_destroy(ifpga_sec_mgr_class);
> +	ida_destroy(&ifpga_sec_mgr_ida);
> +}
> +
> +MODULE_DESCRIPTION("Intel FPGA Security Manager Driver");
> +MODULE_LICENSE("GPL v2");
> +
> +subsys_initcall(ifpga_sec_mgr_class_init);
> +module_exit(ifpga_sec_mgr_class_exit)
> diff --git a/include/linux/fpga/ifpga-sec-mgr.h b/include/linux/fpga/ifpga-sec-mgr.h
> new file mode 100644
> index 000000000000..ded62090e9b9
> --- /dev/null
> +++ b/include/linux/fpga/ifpga-sec-mgr.h
> @@ -0,0 +1,81 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Header file for Intel FPGA Security Manager
> + *
> + * Copyright (C) 2019-2020 Intel Corporation, Inc.
> + */
> +#ifndef _LINUX_IFPGA_SEC_MGR_H
> +#define _LINUX_IFPGA_SEC_MGR_H
> +
> +#include <linux/device.h>
> +#include <linux/mutex.h>
> +#include <linux/types.h>
> +
> +struct ifpga_sec_mgr;
> +
> +/**
> + * struct ifpga_sec_mgr_ops - device specific operations
> + * @user_flash_count:	    Optional: Return sysfs string output for FPGA
> + *			    image flash count
> + * @sr_root_entry_hash:	    Optional: Return sysfs string output for static
> + *			    region root entry hash
> + * @pr_root_entry_hash:	    Optional: Return sysfs string output for partial
> + *			    reconfiguration root entry hash
> + * @bmc_root_entry_hash:    Optional: Return sysfs string output for BMC
> + *			    root entry hash
> + * @sr_canceled_csks:	    Optional: Return sysfs string output for static
> + *			    region canceled keys
> + * @pr_canceled_csks:	    Optional: Return sysfs string output for partial
> + *			    reconfiguration canceled keys
> + * @bmc_canceled_csks:	    Optional: Return sysfs string output for bmc
> + *			    canceled keys
> + * @bmc_canceled_csk_nbits: Optional: Return BMC canceled csk vector bit count
> + * @sr_canceled_csk_nbits:  Optional: Return SR canceled csk vector bit count
> + * @pr_canceled_csk_nbits:  Optional: Return PR canceled csk vector bit count
> + * @bmc_reh_size:	    Optional: Return byte size for BMC root entry hash
> + * @sr_reh_size:	    Optional: Return byte size for SR root entry hash
> + * @pr_reh_size:	    Optional: Return byte size for PR root entry hash
> + */
> +struct ifpga_sec_mgr_ops {
> +	int (*user_flash_count)(struct ifpga_sec_mgr *imgr);
> +	int (*bmc_root_entry_hash)(struct ifpga_sec_mgr *imgr, u8 *hash,
> +				   unsigned int size);
> +	int (*sr_root_entry_hash)(struct ifpga_sec_mgr *imgr, u8 *hash,
> +				  unsigned int size);
> +	int (*pr_root_entry_hash)(struct ifpga_sec_mgr *imgr, u8 *hash,
> +				  unsigned int size);
> +	int (*bmc_canceled_csks)(struct ifpga_sec_mgr *imgr,
> +				 unsigned long *csk_map, unsigned int nbits);
> +	int (*sr_canceled_csks)(struct ifpga_sec_mgr *imgr,
> +				unsigned long *csk_map, unsigned int nbits);
> +	int (*pr_canceled_csks)(struct ifpga_sec_mgr *imgr,
> +				unsigned long *csk_map, unsigned int nbits);
> +	int (*bmc_reh_size)(struct ifpga_sec_mgr *imgr);
> +	int (*sr_reh_size)(struct ifpga_sec_mgr *imgr);
> +	int (*pr_reh_size)(struct ifpga_sec_mgr *imgr);
> +	int (*bmc_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
> +	int (*sr_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
> +	int (*pr_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
> +};
> +
> +struct ifpga_sec_mgr {
> +	const char *name;
> +	struct device dev;
> +	const struct ifpga_sec_mgr_ops *iops;
> +	struct mutex lock;		/* protect data structure contents */
> +	void *priv;
> +};
> +
> +struct ifpga_sec_mgr *
> +ifpga_sec_mgr_create(struct device *dev, const char *name,
> +		     const struct ifpga_sec_mgr_ops *iops, void *priv);
> +
> +struct ifpga_sec_mgr *
> +devm_ifpga_sec_mgr_create(struct device *dev, const char *name,
> +			  const struct ifpga_sec_mgr_ops *iops, void *priv);
> +
> +int ifpga_sec_mgr_register(struct ifpga_sec_mgr *imgr);
> +void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr);
> +void ifpga_sec_mgr_free(struct ifpga_sec_mgr *imgr);
> +
> +#endif


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 1/7] fpga: sec-mgr: intel fpga security manager class driver
  2020-10-02 23:03   ` Russ Weight
@ 2020-10-03  1:02     ` Moritz Fischer
  0 siblings, 0 replies; 25+ messages in thread
From: Moritz Fischer @ 2020-10-03  1:02 UTC (permalink / raw)
  To: Russ Weight
  Cc: mdf, linux-fpga, linux-kernel, trix, lgoncalv, yilun.xu, hao.wu,
	matthew.gerlach

Hi Russ,

On Fri, Oct 02, 2020 at 04:03:59PM -0700, Russ Weight wrote:
> Hi Moritz,
> 
> This patch aligns with FPGA Manager implementation as you requested by
> splitting up the create() and register() functions and adding a devm_
> version of the create() function. I have a question (below) regarding the
> device_add() function call.
> 
> 
> On 10/2/20 3:36 PM, Russ Weight wrote:
> > Create the Intel Security Manager class driver. The security
> > manager provides interfaces to manage secure updates for the
> > FPGA and BMC images that are stored in FLASH. The driver can
> > also be used to update root entry hashes and to cancel code
> > signing keys.
> >
> > This patch creates the class driver and provides sysfs
> > interfaces for displaying root entry hashes, canceled code
> > signing keys and flash counts.
> >
> > Signed-off-by: Russ Weight <russell.h.weight@intel.com>
> > Signed-off-by: Xu Yilun <yilun.xu@intel.com>
> > ---
> > v2:
> >   - Bumped documentation dates and versions
> >   - Added Documentation/fpga/ifpga-sec-mgr.rst 
> >   - Removed references to bmc_flash_count & smbus_flash_count (not supported)
> >   - Split ifpga_sec_mgr_register() into create() and register() functions
> >   - Added devm_ifpga_sec_mgr_create()
> >   - Removed typedefs for imgr ops
> > ---
> >  .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  67 +++
> >  Documentation/fpga/ifpga-sec-mgr.rst          |  50 ++
> >  Documentation/fpga/index.rst                  |   1 +
> >  MAINTAINERS                                   |   9 +
> >  drivers/fpga/Kconfig                          |   9 +
> >  drivers/fpga/Makefile                         |   3 +
> >  drivers/fpga/ifpga-sec-mgr.c                  | 432 ++++++++++++++++++
> >  include/linux/fpga/ifpga-sec-mgr.h            |  81 ++++
> >  8 files changed, 652 insertions(+)
> >  create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> >  create mode 100644 Documentation/fpga/ifpga-sec-mgr.rst
> >  create mode 100644 drivers/fpga/ifpga-sec-mgr.c
> >  create mode 100644 include/linux/fpga/ifpga-sec-mgr.h
> >
> > diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> > new file mode 100644
> > index 000000000000..707958971bcb
> > --- /dev/null
> > +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> > @@ -0,0 +1,67 @@
> > +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/name
> > +Date:		Oct 2020
> > +KernelVersion:  5.11
> > +Contact:	Russ Weight <russell.h.weight@intel.com>
> > +Description:	Name of low level fpga security manager driver.
> > +
> > +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/sr_root_entry_hash
> > +Date:		Oct 2020
> > +KernelVersion:  5.11
> > +Contact:	Russ Weight <russell.h.weight@intel.com>
> > +Description:	Read only. Returns the root entry hash for the static
> > +		region if one is programmed, else it returns the
> > +		string: "hash not programmed".  This file is only
> > +		visible if the underlying device supports it.
> > +		Format: "0x%x".
> > +
> > +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/pr_root_entry_hash
> > +Date:		Oct 2020
> > +KernelVersion:  5.11
> > +Contact:	Russ Weight <russell.h.weight@intel.com>
> > +Description:	Read only. Returns the root entry hash for the partial
> > +		reconfiguration region if one is programmed, else it
> > +		returns the string: "hash not programmed".  This file
> > +		is only visible if the underlying device supports it.
> > +		Format: "0x%x".
> > +
> > +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/bmc_root_entry_hash
> > +Date:		Oct 2020
> > +KernelVersion:  5.11
> > +Contact:	Russ Weight <russell.h.weight@intel.com>
> > +Description:	Read only. Returns the root entry hash for the BMC image
> > +		if one is programmed, else it returns the string:
> > +		"hash not programmed".  This file is only visible if the
> > +		underlying device supports it.
> > +		Format: "0x%x".
> > +
> > +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/sr_canceled_csks
> > +Date:		Oct 2020
> > +KernelVersion:  5.11
> > +Contact:	Russ Weight <russell.h.weight@intel.com>
> > +Description:	Read only. Returns a list of indices for canceled code
> > +		signing keys for the static region. The standard bitmap
> > +		list format is used (e.g. "1,2-6,9").
> > +
> > +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/pr_canceled_csks
> > +Date:		Oct 2020
> > +KernelVersion:  5.11
> > +Contact:	Russ Weight <russell.h.weight@intel.com>
> > +Description:	Read only. Returns a list of indices for canceled code
> > +		signing keys for the partial reconfiguration region. The
> > +		standard bitmap list format is used (e.g. "1,2-6,9").
> > +
> > +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/bmc_canceled_csks
> > +Date:		Oct 2020
> > +KernelVersion:  5.11
> > +Contact:	Russ Weight <russell.h.weight@intel.com>
> > +Description:	Read only. Returns a list of indices for canceled code
> > +		signing keys for the BMC.  The standard bitmap list format
> > +		is used (e.g. "1,2-6,9").
> > +
> > +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/user_flash_count
> > +Date:		Oct 2020
> > +KernelVersion:  5.11
> > +Contact:	Russ Weight <russell.h.weight@intel.com>
> > +Description:	Read only. Returns number of times the user image for the
> > +		static region has been flashed.
> > +		Format: "%u".
> > diff --git a/Documentation/fpga/ifpga-sec-mgr.rst b/Documentation/fpga/ifpga-sec-mgr.rst
> > new file mode 100644
> > index 000000000000..02f3f65b182b
> > --- /dev/null
> > +++ b/Documentation/fpga/ifpga-sec-mgr.rst
> > @@ -0,0 +1,50 @@
> > +.. SPDX-License-Identifier: GPL-2.0
> > +
> > +========================================
> > +Intel FPGA Security Manager Class Driver
> > +========================================
> > +
> > +The Intel FPGA Security Manager class driver provides a common
> > +API for user-space tools to manage updates for secure Intel FPGA
> > +devices. Device drivers that instantiate the Intel Security
> > +Manager class driver will interact with a HW secure update
> > +engine in order to transfer new FPGA and BMC images to FLASH so
> > +that they will be automatically loaded when the FPGA card reboots.
> > +
> > +A significant difference between the FPGA Manager and the Intel FPGA
> > +Security Manager is that the FPGA Manager does a live update (Partial
> > +Reconfiguration) to a device, whereas the Intel FPGA Security Manager
> > +updates the FLASH images for the Static Region and the BMC so that
> > +they will be loaded the next time the FPGA card boots. Security is
> > +enforced by hardware and firmware. The security manager interacts
> > +with the firmware to initiate an update, pass in the necessary data,
> > +and collect status on the update.
> > +
> > +In addition to managing secure updates of the FPGA and BMC images,
> > +the Intel FPGA Security Manager update process may also used to
> > +program root entry hashes and cancellation keys for the FPGA static
> > +region, the FPGA partial reconfiguration region, and the BMC.
> > +
> > +Secure updates make use of the request_firmware framework, which
> > +requires that image files are accessible under /lib/firmware. A request
> > +for a secure update returns immediately, while the update itself
> > +proceeds in the context of a kernel worker thread. Sysfs files provide
> > +a means for monitoring the progress of a secure update and for
> > +retrieving error information in the event of a failure.
> > +
> > +Sysfs Attributes
> > +================
> > +
> > +The API consists of two groups of sysfs attributes as described below.
> > +
> > +1. Files in the *security* sub-directory can be used to read security
> > +   information including: Root Entry Hashes (REH), Cancelled Code
> > +   Signing Keys (CSK), and the flash update count for FPGA images.
> > +
> > +2. Files in the *update* sub-directory can be used to instantiate and
> > +   monitor a secure update.
> > +
> > +
> > +See `<../ABI/testing/sysfs-class-ifpga-sec-mgr>`__ for a full
> > +description of the sysfs attributes for the Intel FPGA Security
> > +Manager.
> > diff --git a/Documentation/fpga/index.rst b/Documentation/fpga/index.rst
> > index f80f95667ca2..ba9c6b1917bd 100644
> > --- a/Documentation/fpga/index.rst
> > +++ b/Documentation/fpga/index.rst
> > @@ -8,6 +8,7 @@ fpga
> >      :maxdepth: 1
> >  
> >      dfl
> > +    ifpga-sec-mgr
> >  
> >  .. only::  subproject and html
> >  
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 6d1175bf8529..5ffc0e02d741 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -6858,6 +6858,15 @@ F:	Documentation/fpga/
> >  F:	drivers/fpga/
> >  F:	include/linux/fpga/
> >  
> > +INTEL FPGA SECURITY MANAGER DRIVERS
> > +M:	Russ Weight <russell.h.weight@intel.com>
> > +L:	linux-fpga@vger.kernel.org
> > +S:	Maintained
> > +F:	Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> > +F:	Documentation/fpga/ifpga-sec-mgr.rst
> > +F:	drivers/fpga/ifpga-sec-mgr.c
> > +F:	include/linux/fpga/ifpga-sec-mgr.h
> > +
> >  FPU EMULATOR
> >  M:	Bill Metzenthen <billm@melbpc.org.au>
> >  S:	Maintained
> > diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> > index 7cd5a29fc437..bf566a625be7 100644
> > --- a/drivers/fpga/Kconfig
> > +++ b/drivers/fpga/Kconfig
> > @@ -215,4 +215,13 @@ config FPGA_MGR_ZYNQMP_FPGA
> >  	  to configure the programmable logic(PL) through PS
> >  	  on ZynqMP SoC.
> >  
> > +config IFPGA_SEC_MGR
> > +	tristate "Intel Security Manager for FPGA"
> > +	help
> > +	  The Intel Security Manager class driver presents a common
> > +	  user API for managing secure updates for Intel FPGA
> > +	  devices, including flash images for the FPGA static
> > +	  region and for the BMC. Select this option to enable
> > +	  updates for secure FPGA devices.
> > +
> >  endif # FPGA
> > diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
> > index d8e21dfc6778..2e1d29c3d915 100644
> > --- a/drivers/fpga/Makefile
> > +++ b/drivers/fpga/Makefile
> > @@ -21,6 +21,9 @@ obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
> >  obj-$(CONFIG_ALTERA_PR_IP_CORE)         += altera-pr-ip-core.o
> >  obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT)    += altera-pr-ip-core-plat.o
> >  
> > +# Intel FPGA Security Manager Framework
> > +obj-$(CONFIG_IFPGA_SEC_MGR)		+= ifpga-sec-mgr.o
> > +
> >  # FPGA Bridge Drivers
> >  obj-$(CONFIG_FPGA_BRIDGE)		+= fpga-bridge.o
> >  obj-$(CONFIG_SOCFPGA_FPGA_BRIDGE)	+= altera-hps2fpga.o altera-fpga2sdram.o
> > diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
> > new file mode 100644
> > index 000000000000..f1caa4602ab3
> > --- /dev/null
> > +++ b/drivers/fpga/ifpga-sec-mgr.c
> > @@ -0,0 +1,432 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Intel Security Manager for FPGA
> > + *
> > + * Copyright (C) 2019-2020 Intel Corporation, Inc.
> > + */
> > +
> > +#include <linux/fpga/ifpga-sec-mgr.h>
> > +#include <linux/idr.h>
> > +#include <linux/module.h>
> > +#include <linux/slab.h>
> > +#include <linux/vmalloc.h>
> > +
> > +static DEFINE_IDA(ifpga_sec_mgr_ida);
> > +static struct class *ifpga_sec_mgr_class;
> > +
> > +#define to_sec_mgr(d) container_of(d, struct ifpga_sec_mgr, dev)
> > +
> > +static ssize_t
> > +show_canceled_csk(struct ifpga_sec_mgr *imgr,
> > +		  int (*get_csk)(struct ifpga_sec_mgr *imgr,
> > +				 unsigned long *csk_map, unsigned int nbits),
> > +		  int (*get_csk_nbits)(struct ifpga_sec_mgr *imgr),
> > +		  char *buf)
> > +{
> > +	unsigned long *csk_map = NULL;
> > +	unsigned int nbits;
> > +	int ret;
> > +
> > +	ret = get_csk_nbits(imgr);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	nbits = (unsigned int)ret;
> > +	csk_map = vmalloc(sizeof(unsigned long) * BITS_TO_LONGS(nbits));
> > +	if (!csk_map)
> > +		return -ENOMEM;
> > +
> > +	ret = get_csk(imgr, csk_map, nbits);
> > +	if (ret)
> > +		goto vfree_exit;
> > +
> > +	ret = bitmap_print_to_pagebuf(1, buf, csk_map, nbits);
> > +
> > +vfree_exit:
> > +	vfree(csk_map);
> > +	return ret;
> > +}
> > +
> > +static ssize_t
> > +show_root_entry_hash(struct ifpga_sec_mgr *imgr,
> > +		     int (*get_reh)(struct ifpga_sec_mgr *imgr, u8 *hash,
> > +				    unsigned int size),
> > +		     int (*get_reh_size)(struct ifpga_sec_mgr *imgr),
> > +		     char *buf)
> > +{
> > +	int size, i, cnt, ret;
> > +	u8 *hash;
> > +
> > +	ret = get_reh_size(imgr);
> > +	if (ret < 0)
> > +		return ret;
> > +	else if (!ret)
> > +		return sprintf(buf, "hash not programmed\n");
> > +
> > +	size = ret;
> > +	hash = vmalloc(size);
> > +	if (!hash)
> > +		return -ENOMEM;
> > +
> > +	ret = get_reh(imgr, hash, size);
> > +	if (ret)
> > +		goto vfree_exit;
> > +
> > +	cnt = sprintf(buf, "0x");
> > +	for (i = 0; i < size; i++)
> > +		cnt += sprintf(buf + cnt, "%02x", hash[i]);
> > +	cnt += sprintf(buf + cnt, "\n");
> > +
> > +vfree_exit:
> > +	vfree(hash);
> > +	return ret ? : cnt;
> > +}
> > +
> > +#define DEVICE_ATTR_SEC_CSK(_name) \
> > +static ssize_t _name##_canceled_csks_show(struct device *dev, \
> > +					  struct device_attribute *attr, \
> > +					  char *buf) \
> > +{ \
> > +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev); \
> > +	return show_canceled_csk(imgr, \
> > +	       imgr->iops->_name##_canceled_csks, \
> > +	       imgr->iops->_name##_canceled_csk_nbits, buf); \
> > +} \
> > +static DEVICE_ATTR_RO(_name##_canceled_csks)
> > +
> > +#define DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(_name) \
> > +static ssize_t _name##_root_entry_hash_show(struct device *dev, \
> > +				     struct device_attribute *attr, \
> > +				     char *buf) \
> > +{ \
> > +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev); \
> > +	return show_root_entry_hash(imgr, \
> > +	       imgr->iops->_name##_root_entry_hash, \
> > +	       imgr->iops->_name##_reh_size, buf); \
> > +} \
> > +static DEVICE_ATTR_RO(_name##_root_entry_hash)
> > +
> > +static ssize_t user_flash_count_show(struct device *dev,
> > +				     struct device_attribute *attr, char *buf)
> > +{
> > +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
> > +
> > +	int cnt = imgr->iops->user_flash_count(imgr);
> > +	return cnt < 0 ? cnt : sprintf(buf, "%u\n", cnt);
> > +}
> > +static DEVICE_ATTR_RO(user_flash_count);
> > +
> > +DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(sr);
> > +DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(pr);
> > +DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(bmc);
> > +DEVICE_ATTR_SEC_CSK(sr);
> > +DEVICE_ATTR_SEC_CSK(pr);
> > +DEVICE_ATTR_SEC_CSK(bmc);
> > +
> > +static struct attribute *sec_mgr_security_attrs[] = {
> > +	&dev_attr_user_flash_count.attr,
> > +	&dev_attr_bmc_root_entry_hash.attr,
> > +	&dev_attr_sr_root_entry_hash.attr,
> > +	&dev_attr_pr_root_entry_hash.attr,
> > +	&dev_attr_sr_canceled_csks.attr,
> > +	&dev_attr_pr_canceled_csks.attr,
> > +	&dev_attr_bmc_canceled_csks.attr,
> > +	NULL,
> > +};
> > +
> > +#define check_attr(attribute, _name) \
> > +	((attribute) == &dev_attr_##_name.attr && imgr->iops->_name)
> > +
> > +static umode_t sec_mgr_visible(struct kobject *kobj,
> > +			       struct attribute *attr, int n)
> > +{
> > +	struct ifpga_sec_mgr *imgr = to_sec_mgr(kobj_to_dev(kobj));
> > +
> > +	/*
> > +	 * Only display optional sysfs attributes if a
> > +	 * corresponding handler is provided
> > +	 */
> > +	if (check_attr(attr, user_flash_count) ||
> > +	    check_attr(attr, bmc_root_entry_hash) ||
> > +	    check_attr(attr, sr_root_entry_hash) ||
> > +	    check_attr(attr, pr_root_entry_hash) ||
> > +	    check_attr(attr, sr_canceled_csks) ||
> > +	    check_attr(attr, pr_canceled_csks) ||
> > +	    check_attr(attr, bmc_canceled_csks))
> > +		return attr->mode;
> > +
> > +	return 0;
> > +}
> > +
> > +static struct attribute_group sec_mgr_security_attr_group = {
> > +	.name = "security",
> > +	.attrs = sec_mgr_security_attrs,
> > +	.is_visible = sec_mgr_visible,
> > +};
> > +
> > +static ssize_t name_show(struct device *dev,
> > +			 struct device_attribute *attr, char *buf)
> > +{
> > +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
> > +
> > +	return sprintf(buf, "%s\n", imgr->name);
> > +}
> > +static DEVICE_ATTR_RO(name);
> > +
> > +static struct attribute *sec_mgr_attrs[] = {
> > +	&dev_attr_name.attr,
> > +	NULL,
> > +};
> > +
> > +static struct attribute_group sec_mgr_attr_group = {
> > +	.attrs = sec_mgr_attrs,
> > +};
> > +
> > +static const struct attribute_group *ifpga_sec_mgr_attr_groups[] = {
> > +	&sec_mgr_attr_group,
> > +	&sec_mgr_security_attr_group,
> > +	NULL,
> > +};
> > +
> > +static bool check_sysfs_handler(struct device *dev,
> > +				void *sysfs_handler, void *size_handler,
> > +				const char *sysfs_handler_name,
> > +				const char *size_handler_name)
> > +{
> > +	/*
> > +	 * sysfs_handler and size_handler must either both be
> > +	 * defined or both be NULL.
> > +	 */
> > +	if (sysfs_handler) {
> > +		if (!size_handler) {
> > +			dev_err(dev, "%s registered without %s\n",
> > +				sysfs_handler_name, size_handler_name);
> > +			return false;
> > +		}
> > +	} else if (size_handler) {
> > +		dev_err(dev, "%s registered without %s\n",
> > +			size_handler_name, sysfs_handler_name);
> > +		return false;
> > +	}
> > +	return true;
> > +}
> > +
> > +#define check_reh_handler(_dev, _iops, _name) \
> > +	check_sysfs_handler(_dev, (_iops)->_name##_root_entry_hash, \
> > +			    (_iops)->_name##_reh_size, \
> > +			    __stringify(_name##_root_entry_hash), \
> > +			    __stringify(_name##_reh_size))
> > +
> > +#define check_csk_handler(_dev, _iops, _name) \
> > +	check_sysfs_handler(_dev, (_iops)->_name##_canceled_csks, \
> > +			    (_iops)->_name##_canceled_csk_nbits, \
> > +			    __stringify(_name##_canceled_csks), \
> > +			    __stringify(_name##_canceled_csk_nbits))
> > +
> > +/**
> > + * ifpga_sec_mgr_create - create and initialize an Intel FPGA
> > + *			  security manager struct
> > + *
> > + * @dev:  Intel fpga security manager device from pdev
> > + * @name: ifpga security manager name
> > + * @iops: pointer to a structure of ifpga callback functions
> > + * @priv: ifpga security manager private data
> > + *
> > + * The caller of this function is responsible for freeing the struct
> > + * with ifpg_sec_mgr_free(). Using devm_ifpga_sec_mgr_create() instead
> > + * is recommended.
> > + *
> > + * Return: pointer to struct ifpga_sec_mgr or NULL
> > + */
> > +struct ifpga_sec_mgr *
> > +ifpga_sec_mgr_create(struct device *dev, const char *name,
> > +		     const struct ifpga_sec_mgr_ops *iops, void *priv)
> > +{
> > +	struct ifpga_sec_mgr *imgr;
> > +	int id, ret;
> > +
> > +	if (!check_reh_handler(dev, iops, bmc) ||
> > +	    !check_reh_handler(dev, iops, sr) ||
> > +	    !check_reh_handler(dev, iops, pr) ||
> > +	    !check_csk_handler(dev, iops, bmc) ||
> > +	    !check_csk_handler(dev, iops, sr) ||
> > +	    !check_csk_handler(dev, iops, pr)) {
> > +		return NULL;
> > +	}
> > +
> > +	if (!name || !strlen(name)) {
> > +		dev_err(dev, "Attempt to register with no name!\n");
> > +		return NULL;
> > +	}
> > +
> > +	imgr = kzalloc(sizeof(*imgr), GFP_KERNEL);
> > +	if (!imgr)
> > +		return NULL;
> > +
> > +	id = ida_simple_get(&ifpga_sec_mgr_ida, 0, 0, GFP_KERNEL);
> > +	if (id < 0)
> > +		goto error_kfree;
> > +
> > +	mutex_init(&imgr->lock);
> > +
> > +	imgr->name = name;
> > +	imgr->priv = priv;
> > +	imgr->iops = iops;
> > +
> > +	device_initialize(&imgr->dev);
> > +	imgr->dev.class = ifpga_sec_mgr_class;
> > +	imgr->dev.parent = dev;
> > +	imgr->dev.id = id;
> > +
> > +	ret = dev_set_name(&imgr->dev, "ifpga_sec%d", id);
> > +	if (ret) {
> > +		dev_err(dev, "Failed to set device name: ifpga_sec%d\n", id);
> > +		goto error_device;
> > +	}
> > +
> > +	return imgr;
> > +
> > +error_device:
> > +	ida_simple_remove(&ifpga_sec_mgr_ida, id);
> > +
> > +error_kfree:
> > +	kfree(imgr);
> > +
> > +	return NULL;
> > +}
> > +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_create);
> > +
> > +/**
> > + * ifpga_sec_mgr_free - free an Intel FPGA security manager created
> > + *			with ifpga_sec_mgr_create()
> > + *
> > + * @imgr:	Intel FPGA security manager structure
> > + */
> > +void ifpga_sec_mgr_free(struct ifpga_sec_mgr *imgr)
> > +{
> > +	ida_simple_remove(&ifpga_sec_mgr_ida, imgr->dev.id);
> > +	kfree(imgr);
> > +}
> > +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_free);
> > +
> > +static void devm_ifpga_sec_mgr_release(struct device *dev, void *res)
> > +{
> > +	struct ifpga_sec_mgr *imgr = *(struct ifpga_sec_mgr **)res;
> > +
> > +	ifpga_sec_mgr_free(imgr);
> > +}
> > +
> > +/**
> > + * devm_ifpga_sec_mgr_create - create and initialize an Intel FPGA
> > + *			       security manager struct
> > + *
> > + * @dev:  Intel fpga security manager device from pdev
> > + * @name: ifpga security manager name
> > + * @iops: pointer to a structure of ifpga callback functions
> > + * @priv: ifpga security manager private data
> > + *
> > + * This function is intended for use in a Intel FPGA Security manager
> > + * driver's probe function.  After the security manager driver creates
> > + * the ifpga_sec_mgr struct with devm_fpga_mgr_create(), it should
> > + * register it with ifpga_sec_mgr_register().  The security manager
> > + * driver's remove function should call ifpga_sec_mgr_unregister().
> > + * The ifpga_sec_mgr struct allocated with this function will be freed
> > + * automatically on driver detach.  This includes the case of a probe
> > + * function returning error before calling fpga_mgr_register(), the
> > + * struct will still get cleaned up.
> > + *
> > + * Return: pointer to struct ifpga_sec_mgr or NULL
> > + */
> > +struct ifpga_sec_mgr *
> > +devm_ifpga_sec_mgr_create(struct device *dev, const char *name,
> > +			  const struct ifpga_sec_mgr_ops *iops, void *priv)
> > +{
> > +	struct ifpga_sec_mgr **ptr, *imgr;
> > +
> > +	ptr = devres_alloc(devm_ifpga_sec_mgr_release, sizeof(*ptr), GFP_KERNEL);
> > +	if (!ptr)
> > +		return NULL;
> > +
> > +	imgr = ifpga_sec_mgr_create(dev, name, iops, priv);
> > +	if (!imgr) {
> > +		devres_free(ptr);
> > +	} else {
> > +		*ptr = imgr;
> > +		devres_add(dev, ptr);
> > +	}
> > +
> > +	return imgr;
> > +}
> > +EXPORT_SYMBOL_GPL(devm_ifpga_sec_mgr_create);
> > +
> > +/**
> > + * ifpga_sec_mgr_register - register an Intel FPGA security manager
> > + *
> > + * @imgr: Intel fpga security manager struct
> > + *
> > + * Return: 0 on success, negative error code otherwise.
> > + */
> > +int ifpga_sec_mgr_register(struct ifpga_sec_mgr *imgr)
> > +{
> > +	int ret;
> > +
> > +	ret = device_add(&imgr->dev);
> > +	if (ret)
> > +		goto error_device;
> The comment header for device_add() includes the following text:
> 
>  * NOTE: _Never_ directly free @dev after calling this function, even
>  * if it returned an error! Always use put_device() to give up your
>  * reference instead.
>  *
>  * Rule of thumb is: if device_add() succeeds, you should call
>  * device_del() when you want to get rid of it. If device_add() has
>  * *not* succeeded, use *only* put_device() to drop the reference
>  * count.
> 
> This implementation of the security manager requires that the parent
> driver (which implements the security manager) explicitly free the
> ifpga_sec_mgr structure or implicitly free it as a managed resource
> (of the parent device) using the devm_ version of the create() function.
> The device structure that is passed to device_add() above is embedded
> in the ifpga_sec_mgr structure.

It is confusing I'll admit :) It's been a while since I looked at the
gory details, but you might be onto something here.

I'll definitely look into this some more this weekend. Appreciate the
question!
> 
> Does this implementation conflict with the core driver functions?
> Is it possible that we are deleting a device structure that is still
> being tracked by the core driver code?
> 
> - Russ
> 
> > +
> > +	dev_info(&imgr->dev, "%s registered\n", imgr->name);
> > +
> > +	return 0;
> > +
> > +error_device:
> > +	ida_simple_remove(&ifpga_sec_mgr_ida, imgr->dev.id);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_register);
> > +
> > +/**
> > + * ifpga_sec_mgr_unregister - unregister an Intel FPGA security manager
> > + *
> > + * @mgr: fpga manager struct
> > + *
> > + * This function is intended for use in an Intel FPGA security manager
> > + * driver's remove() function.
> > + */
> > +void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr)
> > +{
> > +	dev_info(&imgr->dev, "%s %s\n", __func__, imgr->name);
> > +
> > +	device_unregister(&imgr->dev);
> > +}
> > +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_unregister);
> > +
> > +static void ifpga_sec_mgr_dev_release(struct device *dev)
> > +{
> > +}
> > +
> > +static int __init ifpga_sec_mgr_class_init(void)
> > +{
> > +	pr_info("Intel FPGA Security Manager\n");
> > +
> > +	ifpga_sec_mgr_class = class_create(THIS_MODULE, "ifpga_sec_mgr");
> > +	if (IS_ERR(ifpga_sec_mgr_class))
> > +		return PTR_ERR(ifpga_sec_mgr_class);
> > +
> > +	ifpga_sec_mgr_class->dev_groups = ifpga_sec_mgr_attr_groups;
> > +	ifpga_sec_mgr_class->dev_release = ifpga_sec_mgr_dev_release;
> > +
> > +	return 0;
> > +}
> > +
> > +static void __exit ifpga_sec_mgr_class_exit(void)
> > +{
> > +	class_destroy(ifpga_sec_mgr_class);
> > +	ida_destroy(&ifpga_sec_mgr_ida);
> > +}
> > +
> > +MODULE_DESCRIPTION("Intel FPGA Security Manager Driver");
> > +MODULE_LICENSE("GPL v2");
> > +
> > +subsys_initcall(ifpga_sec_mgr_class_init);
> > +module_exit(ifpga_sec_mgr_class_exit)
> > diff --git a/include/linux/fpga/ifpga-sec-mgr.h b/include/linux/fpga/ifpga-sec-mgr.h
> > new file mode 100644
> > index 000000000000..ded62090e9b9
> > --- /dev/null
> > +++ b/include/linux/fpga/ifpga-sec-mgr.h
> > @@ -0,0 +1,81 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Header file for Intel FPGA Security Manager
> > + *
> > + * Copyright (C) 2019-2020 Intel Corporation, Inc.
> > + */
> > +#ifndef _LINUX_IFPGA_SEC_MGR_H
> > +#define _LINUX_IFPGA_SEC_MGR_H
> > +
> > +#include <linux/device.h>
> > +#include <linux/mutex.h>
> > +#include <linux/types.h>
> > +
> > +struct ifpga_sec_mgr;
> > +
> > +/**
> > + * struct ifpga_sec_mgr_ops - device specific operations
> > + * @user_flash_count:	    Optional: Return sysfs string output for FPGA
> > + *			    image flash count
> > + * @sr_root_entry_hash:	    Optional: Return sysfs string output for static
> > + *			    region root entry hash
> > + * @pr_root_entry_hash:	    Optional: Return sysfs string output for partial
> > + *			    reconfiguration root entry hash
> > + * @bmc_root_entry_hash:    Optional: Return sysfs string output for BMC
> > + *			    root entry hash
> > + * @sr_canceled_csks:	    Optional: Return sysfs string output for static
> > + *			    region canceled keys
> > + * @pr_canceled_csks:	    Optional: Return sysfs string output for partial
> > + *			    reconfiguration canceled keys
> > + * @bmc_canceled_csks:	    Optional: Return sysfs string output for bmc
> > + *			    canceled keys
> > + * @bmc_canceled_csk_nbits: Optional: Return BMC canceled csk vector bit count
> > + * @sr_canceled_csk_nbits:  Optional: Return SR canceled csk vector bit count
> > + * @pr_canceled_csk_nbits:  Optional: Return PR canceled csk vector bit count
> > + * @bmc_reh_size:	    Optional: Return byte size for BMC root entry hash
> > + * @sr_reh_size:	    Optional: Return byte size for SR root entry hash
> > + * @pr_reh_size:	    Optional: Return byte size for PR root entry hash
> > + */
> > +struct ifpga_sec_mgr_ops {
> > +	int (*user_flash_count)(struct ifpga_sec_mgr *imgr);
> > +	int (*bmc_root_entry_hash)(struct ifpga_sec_mgr *imgr, u8 *hash,
> > +				   unsigned int size);
> > +	int (*sr_root_entry_hash)(struct ifpga_sec_mgr *imgr, u8 *hash,
> > +				  unsigned int size);
> > +	int (*pr_root_entry_hash)(struct ifpga_sec_mgr *imgr, u8 *hash,
> > +				  unsigned int size);
> > +	int (*bmc_canceled_csks)(struct ifpga_sec_mgr *imgr,
> > +				 unsigned long *csk_map, unsigned int nbits);
> > +	int (*sr_canceled_csks)(struct ifpga_sec_mgr *imgr,
> > +				unsigned long *csk_map, unsigned int nbits);
> > +	int (*pr_canceled_csks)(struct ifpga_sec_mgr *imgr,
> > +				unsigned long *csk_map, unsigned int nbits);
> > +	int (*bmc_reh_size)(struct ifpga_sec_mgr *imgr);
> > +	int (*sr_reh_size)(struct ifpga_sec_mgr *imgr);
> > +	int (*pr_reh_size)(struct ifpga_sec_mgr *imgr);
> > +	int (*bmc_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
> > +	int (*sr_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
> > +	int (*pr_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
> > +};
> > +
> > +struct ifpga_sec_mgr {
> > +	const char *name;
> > +	struct device dev;
> > +	const struct ifpga_sec_mgr_ops *iops;
> > +	struct mutex lock;		/* protect data structure contents */
> > +	void *priv;
> > +};
> > +
> > +struct ifpga_sec_mgr *
> > +ifpga_sec_mgr_create(struct device *dev, const char *name,
> > +		     const struct ifpga_sec_mgr_ops *iops, void *priv);
> > +
> > +struct ifpga_sec_mgr *
> > +devm_ifpga_sec_mgr_create(struct device *dev, const char *name,
> > +			  const struct ifpga_sec_mgr_ops *iops, void *priv);
> > +
> > +int ifpga_sec_mgr_register(struct ifpga_sec_mgr *imgr);
> > +void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr);
> > +void ifpga_sec_mgr_free(struct ifpga_sec_mgr *imgr);
> > +
> > +#endif
> 
Cheers,
Moritz

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 1/7] fpga: sec-mgr: intel fpga security manager class driver
  2020-10-02 22:36 ` [PATCH v2 1/7] fpga: sec-mgr: intel fpga security manager class driver Russ Weight
  2020-10-02 23:03   ` Russ Weight
@ 2020-10-04 20:43   ` Tom Rix
  2020-10-05  7:38   ` Wu, Hao
  2 siblings, 0 replies; 25+ messages in thread
From: Tom Rix @ 2020-10-04 20:43 UTC (permalink / raw)
  To: Russ Weight, mdf, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 10/2/20 3:36 PM, Russ Weight wrote:
> Create the Intel Security Manager class driver. The security
> manager provides interfaces to manage secure updates for the
> FPGA and BMC images that are stored in FLASH. The driver can
> also be used to update root entry hashes and to cancel code
> signing keys.
>
> This patch creates the class driver and provides sysfs
> interfaces for displaying root entry hashes, canceled code
> signing keys and flash counts.
>
> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
> Signed-off-by: Xu Yilun <yilun.xu@intel.com>
> ---
> v2:
>   - Bumped documentation dates and versions
>   - Added Documentation/fpga/ifpga-sec-mgr.rst 
>   - Removed references to bmc_flash_count & smbus_flash_count (not supported)
>   - Split ifpga_sec_mgr_register() into create() and register() functions
>   - Added devm_ifpga_sec_mgr_create()
>   - Removed typedefs for imgr ops
> ---
>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  67 +++
>  Documentation/fpga/ifpga-sec-mgr.rst          |  50 ++
>  Documentation/fpga/index.rst                  |   1 +
>  MAINTAINERS                                   |   9 +
>  drivers/fpga/Kconfig                          |   9 +
>  drivers/fpga/Makefile                         |   3 +
>  drivers/fpga/ifpga-sec-mgr.c                  | 432 ++++++++++++++++++
>  include/linux/fpga/ifpga-sec-mgr.h            |  81 ++++
>  8 files changed, 652 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>  create mode 100644 Documentation/fpga/ifpga-sec-mgr.rst
>  create mode 100644 drivers/fpga/ifpga-sec-mgr.c
>  create mode 100644 include/linux/fpga/ifpga-sec-mgr.h

Thanks for the changes, looks good.

Reviewed-by: Tom Rix <trix@redhat.com>



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 2/7] fpga: sec-mgr: enable secure updates
  2020-10-02 22:36 ` [PATCH v2 2/7] fpga: sec-mgr: enable secure updates Russ Weight
@ 2020-10-04 20:54   ` Tom Rix
  2020-10-05  8:19   ` Wu, Hao
  1 sibling, 0 replies; 25+ messages in thread
From: Tom Rix @ 2020-10-04 20:54 UTC (permalink / raw)
  To: Russ Weight, mdf, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 10/2/20 3:36 PM, Russ Weight wrote:
> Extend the FPGA Intel Security Manager class driver to
> include an update/filename sysfs node that can be used
> to initiate a security update.  The filename of a secure
> update file (BMC image, FPGA image, Root Entry Hash image,
> or Code Signing Key cancellation image) can be written to
> this sysfs entry to cause a secure update to occur.
>
> The write of the filename will return immediately, and the
> update will begin in the context of a kernel worker thread.
> This tool utilizes the request_firmware framework, which
> requires that the image file reside under /lib/firmware.
>
> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
> ---
> v2:
>   - Bumped documentation date and version
>   - Removed explicit value assignments in enums
>   - Other minor code cleanup per review comments 
> ---
>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  13 ++
>  drivers/fpga/ifpga-sec-mgr.c                  | 157 ++++++++++++++++++
>  include/linux/fpga/ifpga-sec-mgr.h            |  49 ++++++
>  3 files changed, 219 insertions(+)

This was 05/12 in the old patchset.

Looks good.

Reviewed-by: Tom Rix <trix@redhat.com>



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 3/7] fpga: sec-mgr: expose sec-mgr update status
  2020-10-02 22:36 ` [PATCH v2 3/7] fpga: sec-mgr: expose sec-mgr update status Russ Weight
@ 2020-10-04 21:00   ` Tom Rix
  2020-10-05  8:41   ` Wu, Hao
  1 sibling, 0 replies; 25+ messages in thread
From: Tom Rix @ 2020-10-04 21:00 UTC (permalink / raw)
  To: Russ Weight, mdf, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 10/2/20 3:36 PM, Russ Weight wrote:
> Extend the Intel Security Manager class driver to
> include an update/status sysfs node that can be polled
> and read to monitor the progress of an ongoing secure
> update. Sysfs_notify() is used to signal transitions
> between different phases of the update process.
>
> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
> ---
> v2:
>   - Bumped documentation date and version
>   - Changed progress state "read_file" to "reading"
> ---
>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 11 +++++
>  drivers/fpga/ifpga-sec-mgr.c                  | 40 +++++++++++++++++--
>  2 files changed, 47 insertions(+), 4 deletions(-)

This was 07/12 in the old patchset.

Also looks fine.

Reviewed-by: Tom Rix <trix@redhat.com>



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 4/7] fpga: sec-mgr: expose sec-mgr update errors
  2020-10-02 22:36 ` [PATCH v2 4/7] fpga: sec-mgr: expose sec-mgr update errors Russ Weight
@ 2020-10-04 21:06   ` Tom Rix
  2020-10-05  8:55   ` Wu, Hao
  1 sibling, 0 replies; 25+ messages in thread
From: Tom Rix @ 2020-10-04 21:06 UTC (permalink / raw)
  To: Russ Weight, mdf, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 10/2/20 3:36 PM, Russ Weight wrote:
> Extend Intel Security Manager class driver to include
> an update/error sysfs node that can be read for error
> information when a secure update fails.
>
> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
> ---
> v2:
>   - Bumped documentation date and version
>   - Added warning to sec_progress() for invalid progress status
>   - Added sec_error() function (similar to sec_progress())
> ---
>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 17 ++++
>  drivers/fpga/ifpga-sec-mgr.c                  | 81 ++++++++++++++++---
>  include/linux/fpga/ifpga-sec-mgr.h            |  1 +
>  3 files changed, 89 insertions(+), 10 deletions(-)

This is 08/12 of the old patchset.

Also fine.

Reviewed-by: Tom Rix <trix@redhat.com>



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 6/7] fpga: sec-mgr: enable cancel of secure update
  2020-10-02 22:37 ` [PATCH v2 6/7] fpga: sec-mgr: enable cancel of secure update Russ Weight
@ 2020-10-04 21:13   ` Tom Rix
  0 siblings, 0 replies; 25+ messages in thread
From: Tom Rix @ 2020-10-04 21:13 UTC (permalink / raw)
  To: Russ Weight, mdf, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 10/2/20 3:37 PM, Russ Weight wrote:
> Extend the Intel Security Manager class driver to include
> an update/cancel sysfs file that can be written to request
> that an update be canceled. The write may return EBUSY if
> the update has progressed to the point that it cannot be
> canceled by software or ENODEV if there is no update in
> progress.
>
> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
> ---
> v2:
>   - Bumped documentation date and version
>   - Minor code cleanup per review comments 
> ---
>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 10 ++++
>  drivers/fpga/ifpga-sec-mgr.c                  | 59 +++++++++++++++++--
>  include/linux/fpga/ifpga-sec-mgr.h            |  1 +
>  3 files changed, 66 insertions(+), 4 deletions(-)

This is 10/12 of the original patch set.

Discussions covered most of my issues, the others are changed here.

Reviewed-by: Tom Rix <trix@redhat.com>



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 0/7] Intel FPGA Security Manager Class Driver
  2020-10-02 22:36 [PATCH v2 0/7] Intel FPGA Security Manager Class Driver Russ Weight
                   ` (6 preceding siblings ...)
  2020-10-02 22:37 ` [PATCH v2 7/7] fpga: sec-mgr: expose hardware error info Russ Weight
@ 2020-10-04 21:19 ` Tom Rix
  7 siblings, 0 replies; 25+ messages in thread
From: Tom Rix @ 2020-10-04 21:19 UTC (permalink / raw)
  To: Russ Weight, mdf, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 10/2/20 3:36 PM, Russ Weight wrote:
> The Intel FPGA Security Manager class driver provides a common
> API for user-space tools to manage updates for secure Intel FPGA
> devices. Device drivers that instantiate the Intel Security
> Manager class driver will interact with a HW secure update
> engine in order to transfer new FPGA and BMC images to FLASH so
> that they will be automatically loaded when the FPGA card reboots.
>
> A significant difference between the FPGA Manager and the Intel FPGA 
> Security Manager is that the FPGA Manager does a live update (Partial
> Reconfiguration) to a device whereas the Intel FPGA Security Manager
> updates the FLASH images for the Static Region and the BMC so that
> they will be loaded the next time the FPGA card boots. Security is
> enforced by hardware and firmware. The security manager interacts
> with the firmware to initiate an update, pass in the necessary data,
> and collect status on the update.
>
> The n3000bmc-secure driver is the first driver to use the Intel FPG
> Security Manager. This driver was previously submittied in the same
> patch set, but has been split out in to a separate patch set for V2.
> Follow-on Intel devices will also make use of this common API for
> secure updates.
>
> In addition to managing secure updates of the FPGA and BMC images,
> the Intel FPGA Security Manager update process may also used to
> program root entry hashes and cancellation keys for the FPGA static
> region, the FPGA partial reconfiguration region, and the BMC.
>
> Secure updates make use of the request_firmware framework, which
> requires that image files are accessible under /lib/firmware. A request
> for a secure update returns immediately, while the update itself
> proceeds in the context of a kernel worker thread. Sysfs files provide
> a means for monitoring the progress of a secure update and for
> retrieving error information in the event of a failure.
>
> The API consists of sysfs nodes and supports the following functions:
>
> (1) Instantiate and monitor a secure update
> (2) Display security information including: Root Entry Hashes (REH),
>     Cancelled Code Signing Keys (CSK), and flash update counts for
>     both BMC and FPGA images.
>
> Changelog v1 -> v2:
>   - Separated out the MAX10 BMC Security Engine to be submitted in
>     a separate patch-set.
>   - Bumped documentation dates and versions
>   - Split ifpga_sec_mgr_register() into create() and register() functions
>   - Added devm_ifpga_sec_mgr_create()
>   - Added Documentation/fpga/ifpga-sec-mgr.rst 
>   - Changed progress state "read_file" to "reading"
>   - Added sec_error() function (similar to sec_progress())
>   - Removed references to bmc_flash_count & smbus_flash_count (not supported)
>   - Removed typedefs for imgr ops
>   - Removed explicit value assignments in enums
>   - Other minor code cleanup per review comments 
>
> Russ Weight (7):
>   fpga: sec-mgr: intel fpga security manager class driver
>   fpga: sec-mgr: enable secure updates
>   fpga: sec-mgr: expose sec-mgr update status
>   fpga: sec-mgr: expose sec-mgr update errors
>   fpga: sec-mgr: expose sec-mgr update size
>   fpga: sec-mgr: enable cancel of secure update
>   fpga: sec-mgr: expose hardware error info
>
>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 143 ++++
>  Documentation/fpga/ifpga-sec-mgr.rst          |  50 ++
>  Documentation/fpga/index.rst                  |   1 +
>  MAINTAINERS                                   |   9 +
>  drivers/fpga/Kconfig                          |   9 +
>  drivers/fpga/Makefile                         |   3 +
>  drivers/fpga/ifpga-sec-mgr.c                  | 781 ++++++++++++++++++
>  include/linux/fpga/ifpga-sec-mgr.h            | 137 +++
>  8 files changed, 1133 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>  create mode 100644 Documentation/fpga/ifpga-sec-mgr.rst
>  create mode 100644 drivers/fpga/ifpga-sec-mgr.c
>  create mode 100644 include/linux/fpga/ifpga-sec-mgr.h

Russ,

This set has all the changes I was looking for.

Thanks,

Tom


^ permalink raw reply	[flat|nested] 25+ messages in thread

* RE: [PATCH v2 1/7] fpga: sec-mgr: intel fpga security manager class driver
  2020-10-02 22:36 ` [PATCH v2 1/7] fpga: sec-mgr: intel fpga security manager class driver Russ Weight
  2020-10-02 23:03   ` Russ Weight
  2020-10-04 20:43   ` Tom Rix
@ 2020-10-05  7:38   ` Wu, Hao
  2020-10-06  0:05     ` Russ Weight
  2 siblings, 1 reply; 25+ messages in thread
From: Wu, Hao @ 2020-10-05  7:38 UTC (permalink / raw)
  To: Weight, Russell H, mdf, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, Xu, Yilun, Gerlach, Matthew, Weight, Russell H

> Subject: [PATCH v2 1/7] fpga: sec-mgr: intel fpga security manager class
> driver
> 
> Create the Intel Security Manager class driver. The security
> manager provides interfaces to manage secure updates for the
> FPGA and BMC images that are stored in FLASH. The driver can
> also be used to update root entry hashes and to cancel code
> signing keys.
> 
> This patch creates the class driver and provides sysfs
> interfaces for displaying root entry hashes, canceled code
> signing keys and flash counts.
> 
> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
> Signed-off-by: Xu Yilun <yilun.xu@intel.com>
> ---
> v2:
>   - Bumped documentation dates and versions
>   - Added Documentation/fpga/ifpga-sec-mgr.rst
>   - Removed references to bmc_flash_count & smbus_flash_count (not
> supported)
>   - Split ifpga_sec_mgr_register() into create() and register() functions
>   - Added devm_ifpga_sec_mgr_create()
>   - Removed typedefs for imgr ops
> ---
>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  67 +++
>  Documentation/fpga/ifpga-sec-mgr.rst          |  50 ++
>  Documentation/fpga/index.rst                  |   1 +
>  MAINTAINERS                                   |   9 +
>  drivers/fpga/Kconfig                          |   9 +
>  drivers/fpga/Makefile                         |   3 +
>  drivers/fpga/ifpga-sec-mgr.c                  | 432 ++++++++++++++++++
>  include/linux/fpga/ifpga-sec-mgr.h            |  81 ++++
>  8 files changed, 652 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>  create mode 100644 Documentation/fpga/ifpga-sec-mgr.rst
>  create mode 100644 drivers/fpga/ifpga-sec-mgr.c
>  create mode 100644 include/linux/fpga/ifpga-sec-mgr.h
> 
> diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> new file mode 100644
> index 000000000000..707958971bcb
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> @@ -0,0 +1,67 @@
> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/name
> +Date:		Oct 2020
> +KernelVersion:  5.11
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Name of low level fpga security manager driver.
> +
> +What:
> 	/sys/class/ifpga_sec_mgr/ifpga_secX/security/sr_root_entry_hash
> +Date:		Oct 2020
> +KernelVersion:  5.11
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Read only. Returns the root entry hash for the static
> +		region if one is programmed, else it returns the
> +		string: "hash not programmed".  This file is only
> +		visible if the underlying device supports it.
> +		Format: "0x%x".
> +
> +What:
> 	/sys/class/ifpga_sec_mgr/ifpga_secX/security/pr_root_entry_hash
> +Date:		Oct 2020
> +KernelVersion:  5.11
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Read only. Returns the root entry hash for the partial
> +		reconfiguration region if one is programmed, else it
> +		returns the string: "hash not programmed".  This file
> +		is only visible if the underlying device supports it.
> +		Format: "0x%x".
> +
> +What:
> 	/sys/class/ifpga_sec_mgr/ifpga_secX/security/bmc_root_entry_hash
> +Date:		Oct 2020
> +KernelVersion:  5.11
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Read only. Returns the root entry hash for the BMC image
> +		if one is programmed, else it returns the string:
> +		"hash not programmed".  This file is only visible if the
> +		underlying device supports it.
> +		Format: "0x%x".
> +
> +What:
> 	/sys/class/ifpga_sec_mgr/ifpga_secX/security/sr_canceled_csks
> +Date:		Oct 2020
> +KernelVersion:  5.11
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Read only. Returns a list of indices for canceled code
> +		signing keys for the static region. The standard bitmap
> +		list format is used (e.g. "1,2-6,9").
> +
> +What:
> 	/sys/class/ifpga_sec_mgr/ifpga_secX/security/pr_canceled_csks
> +Date:		Oct 2020
> +KernelVersion:  5.11
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Read only. Returns a list of indices for canceled code
> +		signing keys for the partial reconfiguration region. The
> +		standard bitmap list format is used (e.g. "1,2-6,9").
> +
> +What:
> 	/sys/class/ifpga_sec_mgr/ifpga_secX/security/bmc_canceled_csks
> +Date:		Oct 2020
> +KernelVersion:  5.11
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Read only. Returns a list of indices for canceled code
> +		signing keys for the BMC.  The standard bitmap list format
> +		is used (e.g. "1,2-6,9").
> +
> +What:
> 	/sys/class/ifpga_sec_mgr/ifpga_secX/security/user_flash_count
> +Date:		Oct 2020
> +KernelVersion:  5.11
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Read only. Returns number of times the user image for the
> +		static region has been flashed.
> +		Format: "%u".
> diff --git a/Documentation/fpga/ifpga-sec-mgr.rst
> b/Documentation/fpga/ifpga-sec-mgr.rst
> new file mode 100644
> index 000000000000..02f3f65b182b
> --- /dev/null
> +++ b/Documentation/fpga/ifpga-sec-mgr.rst
> @@ -0,0 +1,50 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +========================================
> +Intel FPGA Security Manager Class Driver
> +========================================
> +
> +The Intel FPGA Security Manager class driver provides a common
> +API for user-space tools to manage updates for secure Intel FPGA
> +devices. Device drivers that instantiate the Intel Security
> +Manager class driver will interact with a HW secure update
> +engine in order to transfer new FPGA and BMC images to FLASH so
> +that they will be automatically loaded when the FPGA card reboots.
> +
> +A significant difference between the FPGA Manager and the Intel FPGA
> +Security Manager is that the FPGA Manager does a live update (Partial
> +Reconfiguration) to a device, whereas the Intel FPGA Security Manager
> +updates the FLASH images for the Static Region and the BMC so that
> +they will be loaded the next time the FPGA card boots. Security is
> +enforced by hardware and firmware. The security manager interacts
> +with the firmware to initiate an update, pass in the necessary data,
> +and collect status on the update.
> +
> +In addition to managing secure updates of the FPGA and BMC images,
> +the Intel FPGA Security Manager update process may also used to
> +program root entry hashes and cancellation keys for the FPGA static
> +region, the FPGA partial reconfiguration region, and the BMC.
> +
> +Secure updates make use of the request_firmware framework, which
> +requires that image files are accessible under /lib/firmware. A request
> +for a secure update returns immediately, while the update itself
> +proceeds in the context of a kernel worker thread. Sysfs files provide
> +a means for monitoring the progress of a secure update and for
> +retrieving error information in the event of a failure.
> +
> +Sysfs Attributes
> +================
> +
> +The API consists of two groups of sysfs attributes as described below.
> +
> +1. Files in the *security* sub-directory can be used to read security
> +   information including: Root Entry Hashes (REH), Cancelled Code
> +   Signing Keys (CSK), and the flash update count for FPGA images.
> +
> +2. Files in the *update* sub-directory can be used to instantiate and
> +   monitor a secure update.
> +
> +
> +See `<../ABI/testing/sysfs-class-ifpga-sec-mgr>`__ for a full
> +description of the sysfs attributes for the Intel FPGA Security
> +Manager.
> diff --git a/Documentation/fpga/index.rst b/Documentation/fpga/index.rst
> index f80f95667ca2..ba9c6b1917bd 100644
> --- a/Documentation/fpga/index.rst
> +++ b/Documentation/fpga/index.rst
> @@ -8,6 +8,7 @@ fpga
>      :maxdepth: 1
> 
>      dfl
> +    ifpga-sec-mgr
> 
>  .. only::  subproject and html
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 6d1175bf8529..5ffc0e02d741 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -6858,6 +6858,15 @@ F:	Documentation/fpga/
>  F:	drivers/fpga/
>  F:	include/linux/fpga/
> 
> +INTEL FPGA SECURITY MANAGER DRIVERS
> +M:	Russ Weight <russell.h.weight@intel.com>
> +L:	linux-fpga@vger.kernel.org
> +S:	Maintained
> +F:	Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> +F:	Documentation/fpga/ifpga-sec-mgr.rst
> +F:	drivers/fpga/ifpga-sec-mgr.c
> +F:	include/linux/fpga/ifpga-sec-mgr.h
> +
>  FPU EMULATOR
>  M:	Bill Metzenthen <billm@melbpc.org.au>
>  S:	Maintained
> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> index 7cd5a29fc437..bf566a625be7 100644
> --- a/drivers/fpga/Kconfig
> +++ b/drivers/fpga/Kconfig
> @@ -215,4 +215,13 @@ config FPGA_MGR_ZYNQMP_FPGA
>  	  to configure the programmable logic(PL) through PS
>  	  on ZynqMP SoC.
> 
> +config IFPGA_SEC_MGR
> +	tristate "Intel Security Manager for FPGA"
> +	help
> +	  The Intel Security Manager class driver presents a common
> +	  user API for managing secure updates for Intel FPGA
> +	  devices, including flash images for the FPGA static
> +	  region and for the BMC. Select this option to enable
> +	  updates for secure FPGA devices.
> +
>  endif # FPGA
> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
> index d8e21dfc6778..2e1d29c3d915 100644
> --- a/drivers/fpga/Makefile
> +++ b/drivers/fpga/Makefile
> @@ -21,6 +21,9 @@ obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+=
> zynqmp-fpga.o
>  obj-$(CONFIG_ALTERA_PR_IP_CORE)         += altera-pr-ip-core.o
>  obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT)    += altera-pr-ip-core-plat.o
> 
> +# Intel FPGA Security Manager Framework
> +obj-$(CONFIG_IFPGA_SEC_MGR)		+= ifpga-sec-mgr.o
> +
>  # FPGA Bridge Drivers
>  obj-$(CONFIG_FPGA_BRIDGE)		+= fpga-bridge.o
>  obj-$(CONFIG_SOCFPGA_FPGA_BRIDGE)	+= altera-hps2fpga.o altera-
> fpga2sdram.o
> diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
> new file mode 100644
> index 000000000000..f1caa4602ab3
> --- /dev/null
> +++ b/drivers/fpga/ifpga-sec-mgr.c
> @@ -0,0 +1,432 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Intel Security Manager for FPGA
> + *
> + * Copyright (C) 2019-2020 Intel Corporation, Inc.
> + */
> +
> +#include <linux/fpga/ifpga-sec-mgr.h>
> +#include <linux/idr.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/vmalloc.h>
> +
> +static DEFINE_IDA(ifpga_sec_mgr_ida);
> +static struct class *ifpga_sec_mgr_class;
> +
> +#define to_sec_mgr(d) container_of(d, struct ifpga_sec_mgr, dev)
> +
> +static ssize_t
> +show_canceled_csk(struct ifpga_sec_mgr *imgr,
> +		  int (*get_csk)(struct ifpga_sec_mgr *imgr,
> +				 unsigned long *csk_map, unsigned int nbits),
> +		  int (*get_csk_nbits)(struct ifpga_sec_mgr *imgr),
> +		  char *buf)
> +{
> +	unsigned long *csk_map = NULL;
> +	unsigned int nbits;
> +	int ret;
> +
> +	ret = get_csk_nbits(imgr);
> +	if (ret < 0)
> +		return ret;
> +
> +	nbits = (unsigned int)ret;
> +	csk_map = vmalloc(sizeof(unsigned long) * BITS_TO_LONGS(nbits));
> +	if (!csk_map)
> +		return -ENOMEM;
> +
> +	ret = get_csk(imgr, csk_map, nbits);
> +	if (ret)
> +		goto vfree_exit;
> +
> +	ret = bitmap_print_to_pagebuf(1, buf, csk_map, nbits);
> +
> +vfree_exit:
> +	vfree(csk_map);
> +	return ret;
> +}
> +
> +static ssize_t
> +show_root_entry_hash(struct ifpga_sec_mgr *imgr,
> +		     int (*get_reh)(struct ifpga_sec_mgr *imgr, u8 *hash,
> +				    unsigned int size),
> +		     int (*get_reh_size)(struct ifpga_sec_mgr *imgr),
> +		     char *buf)
> +{
> +	int size, i, cnt, ret;
> +	u8 *hash;
> +
> +	ret = get_reh_size(imgr);
> +	if (ret < 0)
> +		return ret;
> +	else if (!ret)
> +		return sprintf(buf, "hash not programmed\n");
> +
> +	size = ret;
> +	hash = vmalloc(size);
> +	if (!hash)
> +		return -ENOMEM;
> +
> +	ret = get_reh(imgr, hash, size);
> +	if (ret)
> +		goto vfree_exit;
> +
> +	cnt = sprintf(buf, "0x");
> +	for (i = 0; i < size; i++)
> +		cnt += sprintf(buf + cnt, "%02x", hash[i]);
> +	cnt += sprintf(buf + cnt, "\n");
> +
> +vfree_exit:
> +	vfree(hash);
> +	return ret ? : cnt;
> +}
> +
> +#define DEVICE_ATTR_SEC_CSK(_name) \
> +static ssize_t _name##_canceled_csks_show(struct device *dev, \
> +					  struct device_attribute *attr, \
> +					  char *buf) \
> +{ \
> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev); \
> +	return show_canceled_csk(imgr, \
> +	       imgr->iops->_name##_canceled_csks, \
> +	       imgr->iops->_name##_canceled_csk_nbits, buf); \
> +} \
> +static DEVICE_ATTR_RO(_name##_canceled_csks)
> +
> +#define DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(_name) \
> +static ssize_t _name##_root_entry_hash_show(struct device *dev, \
> +				     struct device_attribute *attr, \
> +				     char *buf) \
> +{ \
> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev); \
> +	return show_root_entry_hash(imgr, \
> +	       imgr->iops->_name##_root_entry_hash, \
> +	       imgr->iops->_name##_reh_size, buf); \
> +} \
> +static DEVICE_ATTR_RO(_name##_root_entry_hash)
> +
> +static ssize_t user_flash_count_show(struct device *dev,
> +				     struct device_attribute *attr, char *buf)
> +{
> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
> +
> +	int cnt = imgr->iops->user_flash_count(imgr);
> +	return cnt < 0 ? cnt : sprintf(buf, "%u\n", cnt);
> +}
> +static DEVICE_ATTR_RO(user_flash_count);
> +
> +DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(sr);
> +DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(pr);
> +DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(bmc);
> +DEVICE_ATTR_SEC_CSK(sr);
> +DEVICE_ATTR_SEC_CSK(pr);
> +DEVICE_ATTR_SEC_CSK(bmc);
> +
> +static struct attribute *sec_mgr_security_attrs[] = {
> +	&dev_attr_user_flash_count.attr,
> +	&dev_attr_bmc_root_entry_hash.attr,
> +	&dev_attr_sr_root_entry_hash.attr,
> +	&dev_attr_pr_root_entry_hash.attr,
> +	&dev_attr_sr_canceled_csks.attr,
> +	&dev_attr_pr_canceled_csks.attr,
> +	&dev_attr_bmc_canceled_csks.attr,
> +	NULL,
> +};
> +
> +#define check_attr(attribute, _name) \
> +	((attribute) == &dev_attr_##_name.attr && imgr->iops->_name)
> +
> +static umode_t sec_mgr_visible(struct kobject *kobj,
> +			       struct attribute *attr, int n)
> +{
> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(kobj_to_dev(kobj));
> +
> +	/*
> +	 * Only display optional sysfs attributes if a
> +	 * corresponding handler is provided
> +	 */
> +	if (check_attr(attr, user_flash_count) ||
> +	    check_attr(attr, bmc_root_entry_hash) ||
> +	    check_attr(attr, sr_root_entry_hash) ||
> +	    check_attr(attr, pr_root_entry_hash) ||
> +	    check_attr(attr, sr_canceled_csks) ||
> +	    check_attr(attr, pr_canceled_csks) ||
> +	    check_attr(attr, bmc_canceled_csks))
> +		return attr->mode;
> +
> +	return 0;
> +}
> +
> +static struct attribute_group sec_mgr_security_attr_group = {
> +	.name = "security",
> +	.attrs = sec_mgr_security_attrs,
> +	.is_visible = sec_mgr_visible,
> +};
> +
> +static ssize_t name_show(struct device *dev,
> +			 struct device_attribute *attr, char *buf)
> +{
> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
> +
> +	return sprintf(buf, "%s\n", imgr->name);
> +}
> +static DEVICE_ATTR_RO(name);
> +
> +static struct attribute *sec_mgr_attrs[] = {
> +	&dev_attr_name.attr,
> +	NULL,
> +};
> +
> +static struct attribute_group sec_mgr_attr_group = {
> +	.attrs = sec_mgr_attrs,
> +};
> +
> +static const struct attribute_group *ifpga_sec_mgr_attr_groups[] = {
> +	&sec_mgr_attr_group,
> +	&sec_mgr_security_attr_group,
> +	NULL,
> +};
> +
> +static bool check_sysfs_handler(struct device *dev,
> +				void *sysfs_handler, void *size_handler,
> +				const char *sysfs_handler_name,
> +				const char *size_handler_name)
> +{
> +	/*
> +	 * sysfs_handler and size_handler must either both be
> +	 * defined or both be NULL.
> +	 */
> +	if (sysfs_handler) {
> +		if (!size_handler) {
> +			dev_err(dev, "%s registered without %s\n",
> +				sysfs_handler_name, size_handler_name);
> +			return false;
> +		}
> +	} else if (size_handler) {
> +		dev_err(dev, "%s registered without %s\n",
> +			size_handler_name, sysfs_handler_name);
> +		return false;
> +	}

Optional:

	If (sysfs_handler && !size_handler) {

	} else if (!sysfs_handler && size_handler) {
	
	}

> +	return true;
> +}
> +
> +#define check_reh_handler(_dev, _iops, _name) \
> +	check_sysfs_handler(_dev, (_iops)->_name##_root_entry_hash, \
> +			    (_iops)->_name##_reh_size, \
> +			    __stringify(_name##_root_entry_hash), \
> +			    __stringify(_name##_reh_size))
> +
> +#define check_csk_handler(_dev, _iops, _name) \
> +	check_sysfs_handler(_dev, (_iops)->_name##_canceled_csks, \
> +			    (_iops)->_name##_canceled_csk_nbits, \
> +			    __stringify(_name##_canceled_csks), \
> +			    __stringify(_name##_canceled_csk_nbits))
> +
> +/**
> + * ifpga_sec_mgr_create - create and initialize an Intel FPGA
> + *			  security manager struct
> + *
> + * @dev:  Intel fpga security manager device from pdev
> + * @name: ifpga security manager name
> + * @iops: pointer to a structure of ifpga callback functions
> + * @priv: ifpga security manager private data
> + *
> + * The caller of this function is responsible for freeing the struct
> + * with ifpg_sec_mgr_free(). Using devm_ifpga_sec_mgr_create() instead
> + * is recommended.
> + *
> + * Return: pointer to struct ifpga_sec_mgr or NULL
> + */
> +struct ifpga_sec_mgr *
> +ifpga_sec_mgr_create(struct device *dev, const char *name,
> +		     const struct ifpga_sec_mgr_ops *iops, void *priv)
> +{
> +	struct ifpga_sec_mgr *imgr;
> +	int id, ret;
> +
> +	if (!check_reh_handler(dev, iops, bmc) ||
> +	    !check_reh_handler(dev, iops, sr) ||
> +	    !check_reh_handler(dev, iops, pr) ||
> +	    !check_csk_handler(dev, iops, bmc) ||
> +	    !check_csk_handler(dev, iops, sr) ||
> +	    !check_csk_handler(dev, iops, pr)) {
> +		return NULL;
> +	}
> +
> +	if (!name || !strlen(name)) {
> +		dev_err(dev, "Attempt to register with no name!\n");
> +		return NULL;
> +	}
> +
> +	imgr = kzalloc(sizeof(*imgr), GFP_KERNEL);
> +	if (!imgr)
> +		return NULL;
> +
> +	id = ida_simple_get(&ifpga_sec_mgr_ida, 0, 0, GFP_KERNEL);
> +	if (id < 0)
> +		goto error_kfree;
> +
> +	mutex_init(&imgr->lock);
> +
> +	imgr->name = name;
> +	imgr->priv = priv;
> +	imgr->iops = iops;
> +
> +	device_initialize(&imgr->dev);
> +	imgr->dev.class = ifpga_sec_mgr_class;
> +	imgr->dev.parent = dev;
> +	imgr->dev.id = id;
> +
> +	ret = dev_set_name(&imgr->dev, "ifpga_sec%d", id);
> +	if (ret) {
> +		dev_err(dev, "Failed to set device name: ifpga_sec%d\n", id);
> +		goto error_device;
> +	}
> +
> +	return imgr;
> +
> +error_device:
> +	ida_simple_remove(&ifpga_sec_mgr_ida, id);
> +
> +error_kfree:
> +	kfree(imgr);
> +
> +	return NULL;
> +}
> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_create);
> +
> +/**
> + * ifpga_sec_mgr_free - free an Intel FPGA security manager created
> + *			with ifpga_sec_mgr_create()
> + *
> + * @imgr:	Intel FPGA security manager structure
> + */
> +void ifpga_sec_mgr_free(struct ifpga_sec_mgr *imgr)
> +{
> +	ida_simple_remove(&ifpga_sec_mgr_ida, imgr->dev.id);
> +	kfree(imgr);
> +}
> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_free);
> +
> +static void devm_ifpga_sec_mgr_release(struct device *dev, void *res)
> +{
> +	struct ifpga_sec_mgr *imgr = *(struct ifpga_sec_mgr **)res;
> +
> +	ifpga_sec_mgr_free(imgr);
> +}
> +
> +/**
> + * devm_ifpga_sec_mgr_create - create and initialize an Intel FPGA
> + *			       security manager struct
> + *
> + * @dev:  Intel fpga security manager device from pdev
> + * @name: ifpga security manager name
> + * @iops: pointer to a structure of ifpga callback functions
> + * @priv: ifpga security manager private data
> + *
> + * This function is intended for use in a Intel FPGA Security manager
> + * driver's probe function.  After the security manager driver creates
> + * the ifpga_sec_mgr struct with devm_fpga_mgr_create(), it should
> + * register it with ifpga_sec_mgr_register().  The security manager
> + * driver's remove function should call ifpga_sec_mgr_unregister().
> + * The ifpga_sec_mgr struct allocated with this function will be freed
> + * automatically on driver detach.  This includes the case of a probe
> + * function returning error before calling fpga_mgr_register(), the
> + * struct will still get cleaned up.
> + *
> + * Return: pointer to struct ifpga_sec_mgr or NULL
> + */
> +struct ifpga_sec_mgr *
> +devm_ifpga_sec_mgr_create(struct device *dev, const char *name,
> +			  const struct ifpga_sec_mgr_ops *iops, void *priv)
> +{
> +	struct ifpga_sec_mgr **ptr, *imgr;
> +
> +	ptr = devres_alloc(devm_ifpga_sec_mgr_release, sizeof(*ptr),
> GFP_KERNEL);
> +	if (!ptr)
> +		return NULL;
> +
> +	imgr = ifpga_sec_mgr_create(dev, name, iops, priv);
> +	if (!imgr) {
> +		devres_free(ptr);
> +	} else {
> +		*ptr = imgr;
> +		devres_add(dev, ptr);
> +	}
> +
> +	return imgr;
> +}
> +EXPORT_SYMBOL_GPL(devm_ifpga_sec_mgr_create);
> +
> +/**
> + * ifpga_sec_mgr_register - register an Intel FPGA security manager
> + *
> + * @imgr: Intel fpga security manager struct
> + *
> + * Return: 0 on success, negative error code otherwise.
> + */
> +int ifpga_sec_mgr_register(struct ifpga_sec_mgr *imgr)
> +{
> +	int ret;
> +
> +	ret = device_add(&imgr->dev);
> +	if (ret)
> +		goto error_device;
> +
> +	dev_info(&imgr->dev, "%s registered\n", imgr->name);
> +
> +	return 0;
> +
> +error_device:
> +	ida_simple_remove(&ifpga_sec_mgr_ida, imgr->dev.id);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_register);
> +
> +/**
> + * ifpga_sec_mgr_unregister - unregister an Intel FPGA security manager
> + *
> + * @mgr: fpga manager struct
> + *
> + * This function is intended for use in an Intel FPGA security manager
> + * driver's remove() function.
> + */
> +void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr)
> +{
> +	dev_info(&imgr->dev, "%s %s\n", __func__, imgr->name);
> +
> +	device_unregister(&imgr->dev);
> +}
> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_unregister);
> +
> +static void ifpga_sec_mgr_dev_release(struct device *dev)
> +{
> +}
> +
> +static int __init ifpga_sec_mgr_class_init(void)
> +{
> +	pr_info("Intel FPGA Security Manager\n");
> +
> +	ifpga_sec_mgr_class = class_create(THIS_MODULE, "ifpga_sec_mgr");
> +	if (IS_ERR(ifpga_sec_mgr_class))
> +		return PTR_ERR(ifpga_sec_mgr_class);
> +
> +	ifpga_sec_mgr_class->dev_groups = ifpga_sec_mgr_attr_groups;
> +	ifpga_sec_mgr_class->dev_release = ifpga_sec_mgr_dev_release;
> +
> +	return 0;
> +}
> +
> +static void __exit ifpga_sec_mgr_class_exit(void)
> +{
> +	class_destroy(ifpga_sec_mgr_class);
> +	ida_destroy(&ifpga_sec_mgr_ida);
> +}
> +
> +MODULE_DESCRIPTION("Intel FPGA Security Manager Driver");
> +MODULE_LICENSE("GPL v2");
> +
> +subsys_initcall(ifpga_sec_mgr_class_init);
> +module_exit(ifpga_sec_mgr_class_exit)
> diff --git a/include/linux/fpga/ifpga-sec-mgr.h b/include/linux/fpga/ifpga-
> sec-mgr.h
> new file mode 100644
> index 000000000000..ded62090e9b9
> --- /dev/null
> +++ b/include/linux/fpga/ifpga-sec-mgr.h
> @@ -0,0 +1,81 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Header file for Intel FPGA Security Manager
> + *
> + * Copyright (C) 2019-2020 Intel Corporation, Inc.
> + */
> +#ifndef _LINUX_IFPGA_SEC_MGR_H
> +#define _LINUX_IFPGA_SEC_MGR_H
> +
> +#include <linux/device.h>
> +#include <linux/mutex.h>
> +#include <linux/types.h>
> +
> +struct ifpga_sec_mgr;
> +
> +/**
> + * struct ifpga_sec_mgr_ops - device specific operations
> + * @user_flash_count:	    Optional: Return sysfs string output for
> FPGA
> + *			    image flash count
> + * @sr_root_entry_hash:	    Optional: Return sysfs string output for
> static
> + *			    region root entry hash
> + * @pr_root_entry_hash:	    Optional: Return sysfs string output for
> partial
> + *			    reconfiguration root entry hash
> + * @bmc_root_entry_hash:    Optional: Return sysfs string output for BMC
> + *			    root entry hash
> + * @sr_canceled_csks:	    Optional: Return sysfs string output for static
> + *			    region canceled keys
> + * @pr_canceled_csks:	    Optional: Return sysfs string output for
> partial
> + *			    reconfiguration canceled keys
> + * @bmc_canceled_csks:	    Optional: Return sysfs string output for
> bmc
> + *			    canceled keys
> + * @bmc_canceled_csk_nbits: Optional: Return BMC canceled csk vector bit
> count
> + * @sr_canceled_csk_nbits:  Optional: Return SR canceled csk vector bit
> count
> + * @pr_canceled_csk_nbits:  Optional: Return PR canceled csk vector bit
> count
> + * @bmc_reh_size:	    Optional: Return byte size for BMC root entry hash
> + * @sr_reh_size:	    Optional: Return byte size for SR root entry hash
> + * @pr_reh_size:	    Optional: Return byte size for PR root entry hash
> + */
> +struct ifpga_sec_mgr_ops {
> +	int (*user_flash_count)(struct ifpga_sec_mgr *imgr);
> +	int (*bmc_root_entry_hash)(struct ifpga_sec_mgr *imgr, u8 *hash,
> +				   unsigned int size);
> +	int (*sr_root_entry_hash)(struct ifpga_sec_mgr *imgr, u8 *hash,
> +				  unsigned int size);
> +	int (*pr_root_entry_hash)(struct ifpga_sec_mgr *imgr, u8 *hash,
> +				  unsigned int size);
> +	int (*bmc_canceled_csks)(struct ifpga_sec_mgr *imgr,
> +				 unsigned long *csk_map, unsigned int nbits);
> +	int (*sr_canceled_csks)(struct ifpga_sec_mgr *imgr,
> +				unsigned long *csk_map, unsigned int nbits);
> +	int (*pr_canceled_csks)(struct ifpga_sec_mgr *imgr,
> +				unsigned long *csk_map, unsigned int nbits);
> +	int (*bmc_reh_size)(struct ifpga_sec_mgr *imgr);
> +	int (*sr_reh_size)(struct ifpga_sec_mgr *imgr);
> +	int (*pr_reh_size)(struct ifpga_sec_mgr *imgr);
> +	int (*bmc_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
> +	int (*sr_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
> +	int (*pr_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);

I am thinking that if these callbacks for size are really needed or not.
If these size values are not changed dynamically, which requires no
recalculation, then these size values can be stored in ifpga sec mgr
data structure directly. I think the checking logic could be simpler too.
Do you think if it is possible?

Thanks
Hao

> +};
> +
> +struct ifpga_sec_mgr {
> +	const char *name;
> +	struct device dev;
> +	const struct ifpga_sec_mgr_ops *iops;
> +	struct mutex lock;		/* protect data structure contents */
> +	void *priv;
> +};
> +
> +struct ifpga_sec_mgr *
> +ifpga_sec_mgr_create(struct device *dev, const char *name,
> +		     const struct ifpga_sec_mgr_ops *iops, void *priv);
> +
> +struct ifpga_sec_mgr *
> +devm_ifpga_sec_mgr_create(struct device *dev, const char *name,
> +			  const struct ifpga_sec_mgr_ops *iops, void *priv);
> +
> +int ifpga_sec_mgr_register(struct ifpga_sec_mgr *imgr);
> +void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr);
> +void ifpga_sec_mgr_free(struct ifpga_sec_mgr *imgr);
> +
> +#endif
> --
> 2.17.1


^ permalink raw reply	[flat|nested] 25+ messages in thread

* RE: [PATCH v2 2/7] fpga: sec-mgr: enable secure updates
  2020-10-02 22:36 ` [PATCH v2 2/7] fpga: sec-mgr: enable secure updates Russ Weight
  2020-10-04 20:54   ` Tom Rix
@ 2020-10-05  8:19   ` Wu, Hao
  2020-10-06 18:55     ` Russ Weight
  1 sibling, 1 reply; 25+ messages in thread
From: Wu, Hao @ 2020-10-05  8:19 UTC (permalink / raw)
  To: Weight, Russell H, mdf, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, Xu, Yilun, Gerlach, Matthew, Weight, Russell H

> -----Original Message-----
> From: Russ Weight <russell.h.weight@intel.com>
> Sent: Saturday, October 3, 2020 6:37 AM
> To: mdf@kernel.org; linux-fpga@vger.kernel.org; linux-
> kernel@vger.kernel.org
> Cc: trix@redhat.com; lgoncalv@redhat.com; Xu, Yilun <yilun.xu@intel.com>;
> Wu, Hao <hao.wu@intel.com>; Gerlach, Matthew
> <matthew.gerlach@intel.com>; Weight, Russell H
> <russell.h.weight@intel.com>
> Subject: [PATCH v2 2/7] fpga: sec-mgr: enable secure updates
> 
> Extend the FPGA Intel Security Manager class driver to
> include an update/filename sysfs node that can be used
> to initiate a security update.  The filename of a secure
> update file (BMC image, FPGA image, Root Entry Hash image,
> or Code Signing Key cancellation image) can be written to
> this sysfs entry to cause a secure update to occur.
> 
> The write of the filename will return immediately, and the
> update will begin in the context of a kernel worker thread.
> This tool utilizes the request_firmware framework, which
> requires that the image file reside under /lib/firmware.
> 
> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
> ---
> v2:
>   - Bumped documentation date and version
>   - Removed explicit value assignments in enums
>   - Other minor code cleanup per review comments
> ---
>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  13 ++
>  drivers/fpga/ifpga-sec-mgr.c                  | 157 ++++++++++++++++++
>  include/linux/fpga/ifpga-sec-mgr.h            |  49 ++++++
>  3 files changed, 219 insertions(+)
> 
> diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> index 707958971bcb..4f375f132c34 100644
> --- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> @@ -65,3 +65,16 @@ Contact:	Russ Weight <russell.h.weight@intel.com>
>  Description:	Read only. Returns number of times the user image for the
>  		static region has been flashed.
>  		Format: "%u".
> +
> +What:
> 	/sys/class/ifpga_sec_mgr/ifpga_secX/update/filename
> +Date:		Oct 2020
> +KernelVersion:  5.11
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Write only. Write the filename of an Intel image
> +		file to this sysfs file to initiate a secure
> +		update. The file must have an appropriate header
> +		which, among other things, identifies the target
> +		for the update. This mechanism is used to update
> +		BMC images, BMC firmware, Static Region images,
> +		and Root Entry Hashes, and to cancel Code Signing
> +		Keys (CSK).
> diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
> index f1caa4602ab3..7d5a4979554b 100644
> --- a/drivers/fpga/ifpga-sec-mgr.c
> +++ b/drivers/fpga/ifpga-sec-mgr.c
> @@ -5,8 +5,11 @@
>   * Copyright (C) 2019-2020 Intel Corporation, Inc.
>   */
> 
> +#include <linux/delay.h>
> +#include <linux/firmware.h>
>  #include <linux/fpga/ifpga-sec-mgr.h>
>  #include <linux/idr.h>
> +#include <linux/kernel.h>
>  #include <linux/module.h>
>  #include <linux/slab.h>
>  #include <linux/vmalloc.h>
> @@ -14,6 +17,8 @@
>  static DEFINE_IDA(ifpga_sec_mgr_ida);
>  static struct class *ifpga_sec_mgr_class;
> 
> +#define WRITE_BLOCK_SIZE	0x4000

Maybe some comments here for this value or should this be a parameter
of ifpga sec mgr, provided from low level driver during initialization?

> +
>  #define to_sec_mgr(d) container_of(d, struct ifpga_sec_mgr, dev)
> 
>  static ssize_t
> @@ -134,6 +139,96 @@ static struct attribute *sec_mgr_security_attrs[] = {
>  	NULL,
>  };
> 
> +static void ifpga_sec_dev_error(struct ifpga_sec_mgr *imgr,
> +				enum ifpga_sec_err err_code)
> +{
> +	imgr->err_code = err_code;
> +	imgr->iops->cancel(imgr);
> +}
> +
> +static void progress_complete(struct ifpga_sec_mgr *imgr)
> +{
> +	mutex_lock(&imgr->lock);
> +	imgr->progress = IFPGA_SEC_PROG_IDLE;
> +	complete_all(&imgr->update_done);
> +	mutex_unlock(&imgr->lock);
> +}
> +
> +static void ifpga_sec_mgr_update(struct work_struct *work)
> +{
> +	u32 size, blk_size, offset = 0;
> +	struct ifpga_sec_mgr *imgr;
> +	const struct firmware *fw;
> +	enum ifpga_sec_err ret;
> +
> +	imgr = container_of(work, struct ifpga_sec_mgr, work);
> +
> +	get_device(&imgr->dev);
> +	if (request_firmware(&fw, imgr->filename, &imgr->dev)) {
> +		imgr->err_code = IFPGA_SEC_ERR_FILE_READ;
> +		goto idle_exit;
> +	}
> +
> +	imgr->data = fw->data;
> +	imgr->remaining_size = fw->size;
> +
> +	if (!try_module_get(imgr->dev.parent->driver->owner)) {
> +		imgr->err_code = IFPGA_SEC_ERR_BUSY;
> +		goto release_fw_exit;
> +	}
> +
> +	imgr->progress = IFPGA_SEC_PROG_PREPARING;
> +	ret = imgr->iops->prepare(imgr);
> +	if (ret) {
> +		ifpga_sec_dev_error(imgr, ret);
> +		goto modput_exit;
> +	}
> +
> +	imgr->progress = IFPGA_SEC_PROG_WRITING;
> +	size = imgr->remaining_size;
> +	while (size) {
> +		blk_size = min_t(u32, size, WRITE_BLOCK_SIZE);
> +		size -= blk_size;
> +		ret = imgr->iops->write_blk(imgr, offset, blk_size);
> +		if (ret) {
> +			ifpga_sec_dev_error(imgr, ret);
> +			goto done;
> +		}
> +
> +		imgr->remaining_size = size;
> +		offset += blk_size;
> +	}

Looks like we can remove size and just use remaining_size here?

> +
> +	imgr->progress = IFPGA_SEC_PROG_PROGRAMMING;
> +	ret = imgr->iops->poll_complete(imgr);
> +	if (ret) {
> +		ifpga_sec_dev_error(imgr, ret);
> +		goto done;

Looks like no need for this goto done.

> +	}
> +
> +done:
> +	if (imgr->iops->cleanup)
> +		imgr->iops->cleanup(imgr);
> +
> +modput_exit:
> +	module_put(imgr->dev.parent->driver->owner);
> +
> +release_fw_exit:
> +	imgr->data = NULL;
> +	release_firmware(fw);
> +
> +idle_exit:
> +	/*
> +	 * Note: imgr->remaining_size is left unmodified here to
> +	 * provide additional information on errors. It will be
> +	 * reinitialized when the next secure update begins.
> +	 */
> +	kfree(imgr->filename);
> +	imgr->filename = NULL;
> +	put_device(&imgr->dev);
> +	progress_complete(imgr);

Should it call this function progress complete even in failure case?
A little confusing.

> +}
> +
>  #define check_attr(attribute, _name) \
>  	((attribute) == &dev_attr_##_name.attr && imgr->iops->_name)
> 
> @@ -164,6 +259,48 @@ static struct attribute_group
> sec_mgr_security_attr_group = {
>  	.is_visible = sec_mgr_visible,
>  };
> 
> +static ssize_t filename_store(struct device *dev, struct device_attribute *attr,
> +			      const char *buf, size_t count)
> +{
> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
> +	int ret = count;
> +
> +	if (count == 0 || count >= PATH_MAX)
> +		return -EINVAL;
> +
> +	mutex_lock(&imgr->lock);
> +	if (imgr->driver_unload || imgr->progress != IFPGA_SEC_PROG_IDLE)
> {
> +		ret = -EBUSY;
> +		goto unlock_exit;
> +	}
> +
> +	imgr->filename = kstrndup(buf, count - 1, GFP_KERNEL);
> +	if (!imgr->filename) {
> +		ret = -ENOMEM;
> +		goto unlock_exit;
> +	}
> +
> +	imgr->err_code = IFPGA_SEC_ERR_NONE;
> +	imgr->progress = IFPGA_SEC_PROG_READING;
> +	reinit_completion(&imgr->update_done);
> +	schedule_work(&imgr->work);
> +
> +unlock_exit:
> +	mutex_unlock(&imgr->lock);
> +	return ret;
> +}
> +static DEVICE_ATTR_WO(filename);
> +
> +static struct attribute *sec_mgr_update_attrs[] = {
> +	&dev_attr_filename.attr,
> +	NULL,
> +};
> +
> +static struct attribute_group sec_mgr_update_attr_group = {
> +	.name = "update",
> +	.attrs = sec_mgr_update_attrs,
> +};
> +
>  static ssize_t name_show(struct device *dev,
>  			 struct device_attribute *attr, char *buf)
>  {
> @@ -185,6 +322,7 @@ static struct attribute_group sec_mgr_attr_group = {
>  static const struct attribute_group *ifpga_sec_mgr_attr_groups[] = {
>  	&sec_mgr_attr_group,
>  	&sec_mgr_security_attr_group,
> +	&sec_mgr_update_attr_group,
>  	NULL,
>  };
> 
> @@ -245,6 +383,12 @@ ifpga_sec_mgr_create(struct device *dev, const char
> *name,
>  	struct ifpga_sec_mgr *imgr;
>  	int id, ret;
> 
> +	if (!iops || !iops->cancel || !iops->prepare ||
> +	    !iops->write_blk || !iops->poll_complete) {
> +		dev_err(dev, "Attempt to register without required ops\n");
> +		return NULL;
> +	}
> +
>  	if (!check_reh_handler(dev, iops, bmc) ||
>  	    !check_reh_handler(dev, iops, sr) ||
>  	    !check_reh_handler(dev, iops, pr) ||
> @@ -272,6 +416,8 @@ ifpga_sec_mgr_create(struct device *dev, const char
> *name,
>  	imgr->name = name;
>  	imgr->priv = priv;
>  	imgr->iops = iops;
> +	init_completion(&imgr->update_done);
> +	INIT_WORK(&imgr->work, ifpga_sec_mgr_update);
> 
>  	device_initialize(&imgr->dev);
>  	imgr->dev.class = ifpga_sec_mgr_class;
> @@ -397,6 +543,17 @@ void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr
> *imgr)
>  {
>  	dev_info(&imgr->dev, "%s %s\n", __func__, imgr->name);
> 
> +	mutex_lock(&imgr->lock);
> +	imgr->driver_unload = true;

May need some comments here, do you mean get module doesn't work here
to prevent unexpected driver unloading? Or you mean parent device maybe
hot unplug in some cases?

Thanks
Hao

> +	if (imgr->progress == IFPGA_SEC_PROG_IDLE) {
> +		mutex_unlock(&imgr->lock);
> +		goto unregister;
> +	}
> +
> +	mutex_unlock(&imgr->lock);
> +	wait_for_completion(&imgr->update_done);
> +
> +unregister:
>  	device_unregister(&imgr->dev);
>  }
>  EXPORT_SYMBOL_GPL(ifpga_sec_mgr_unregister);
> diff --git a/include/linux/fpga/ifpga-sec-mgr.h b/include/linux/fpga/ifpga-
> sec-mgr.h
> index ded62090e9b9..27008abd8e75 100644
> --- a/include/linux/fpga/ifpga-sec-mgr.h
> +++ b/include/linux/fpga/ifpga-sec-mgr.h
> @@ -7,12 +7,26 @@
>  #ifndef _LINUX_IFPGA_SEC_MGR_H
>  #define _LINUX_IFPGA_SEC_MGR_H
> 
> +#include <linux/completion.h>
>  #include <linux/device.h>
>  #include <linux/mutex.h>
>  #include <linux/types.h>
> 
>  struct ifpga_sec_mgr;
> 
> +enum ifpga_sec_err {
> +	IFPGA_SEC_ERR_NONE,
> +	IFPGA_SEC_ERR_HW_ERROR,
> +	IFPGA_SEC_ERR_TIMEOUT,
> +	IFPGA_SEC_ERR_CANCELED,
> +	IFPGA_SEC_ERR_BUSY,
> +	IFPGA_SEC_ERR_INVALID_SIZE,
> +	IFPGA_SEC_ERR_RW_ERROR,
> +	IFPGA_SEC_ERR_WEAROUT,
> +	IFPGA_SEC_ERR_FILE_READ,
> +	IFPGA_SEC_ERR_MAX
> +};
> +
>  /**
>   * struct ifpga_sec_mgr_ops - device specific operations
>   * @user_flash_count:	    Optional: Return sysfs string output for FPGA
> @@ -35,6 +49,17 @@ struct ifpga_sec_mgr;
>   * @bmc_reh_size:	    Optional: Return byte size for BMC root entry hash
>   * @sr_reh_size:	    Optional: Return byte size for SR root entry hash
>   * @pr_reh_size:	    Optional: Return byte size for PR root entry hash
> + * @prepare:		    Required: Prepare secure update
> + * @write_blk:		    Required: Write a block of data
> + * @poll_complete:	    Required: Check for the completion of the
> + *			    HW authentication/programming process. This
> + *			    function should check for imgr->driver_unload
> + *			    and abort with IFPGA_SEC_ERR_CANCELED when
> true.
> + * @cancel:		    Required: Signal HW to cancel update
> + * @cleanup:		    Optional: Complements the prepare()
> + *			    function and is called at the completion
> + *			    of the update, whether success or failure,
> + *			    if the prepare function succeeded.
>   */
>  struct ifpga_sec_mgr_ops {
>  	int (*user_flash_count)(struct ifpga_sec_mgr *imgr);
> @@ -56,6 +81,22 @@ struct ifpga_sec_mgr_ops {
>  	int (*bmc_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
>  	int (*sr_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
>  	int (*pr_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
> +	enum ifpga_sec_err (*prepare)(struct ifpga_sec_mgr *imgr);
> +	enum ifpga_sec_err (*write_blk)(struct ifpga_sec_mgr *imgr,
> +					u32 offset, u32 size);
> +	enum ifpga_sec_err (*poll_complete)(struct ifpga_sec_mgr *imgr);
> +	void (*cleanup)(struct ifpga_sec_mgr *imgr);
> +	enum ifpga_sec_err (*cancel)(struct ifpga_sec_mgr *imgr);
> +};
> +
> +/* Update progress codes */
> +enum ifpga_sec_prog {
> +	IFPGA_SEC_PROG_IDLE,
> +	IFPGA_SEC_PROG_READING,
> +	IFPGA_SEC_PROG_PREPARING,
> +	IFPGA_SEC_PROG_WRITING,
> +	IFPGA_SEC_PROG_PROGRAMMING,
> +	IFPGA_SEC_PROG_MAX
>  };
> 
>  struct ifpga_sec_mgr {
> @@ -63,6 +104,14 @@ struct ifpga_sec_mgr {
>  	struct device dev;
>  	const struct ifpga_sec_mgr_ops *iops;
>  	struct mutex lock;		/* protect data structure contents */
> +	struct work_struct work;
> +	struct completion update_done;
> +	char *filename;
> +	const u8 *data;			/* pointer to update data */
> +	u32 remaining_size;		/* size remaining to transfer */
> +	enum ifpga_sec_prog progress;
> +	enum ifpga_sec_err err_code;	/* security manager error code */
> +	bool driver_unload;
>  	void *priv;
>  };
> 
> --
> 2.17.1


^ permalink raw reply	[flat|nested] 25+ messages in thread

* RE: [PATCH v2 3/7] fpga: sec-mgr: expose sec-mgr update status
  2020-10-02 22:36 ` [PATCH v2 3/7] fpga: sec-mgr: expose sec-mgr update status Russ Weight
  2020-10-04 21:00   ` Tom Rix
@ 2020-10-05  8:41   ` Wu, Hao
  2020-10-06 19:46     ` Russ Weight
  1 sibling, 1 reply; 25+ messages in thread
From: Wu, Hao @ 2020-10-05  8:41 UTC (permalink / raw)
  To: Weight, Russell H, mdf, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, Xu, Yilun, Gerlach, Matthew, Weight, Russell H

> Subject: [PATCH v2 3/7] fpga: sec-mgr: expose sec-mgr update status
> 
> Extend the Intel Security Manager class driver to
> include an update/status sysfs node that can be polled
> and read to monitor the progress of an ongoing secure
> update. Sysfs_notify() is used to signal transitions
> between different phases of the update process.
> 
> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
> ---
> v2:
>   - Bumped documentation date and version
>   - Changed progress state "read_file" to "reading"
> ---
>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 11 +++++
>  drivers/fpga/ifpga-sec-mgr.c                  | 40 +++++++++++++++++--
>  2 files changed, 47 insertions(+), 4 deletions(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> index 4f375f132c34..73a5246fea1b 100644
> --- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> @@ -78,3 +78,14 @@ Description:	Write only. Write the filename of an
> Intel image
>  		BMC images, BMC firmware, Static Region images,
>  		and Root Entry Hashes, and to cancel Code Signing
>  		Keys (CSK).
> +
> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/update/status
> +Date:		Oct 2020
> +KernelVersion:  5.11
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Read-only. Returns a string describing the current
> +		status of an update. The string will be one of the
> +		following: idle, reading, preparing, writing,
> +		programming. Userspace code can poll on this file,
> +		as it will be signaled by sysfs_notify() on each
> +		state change.
> diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
> index 7d5a4979554b..ad918fb42dc2 100644
> --- a/drivers/fpga/ifpga-sec-mgr.c
> +++ b/drivers/fpga/ifpga-sec-mgr.c
> @@ -139,6 +139,13 @@ static struct attribute *sec_mgr_security_attrs[] = {
>  	NULL,
>  };
> 
> +static void update_progress(struct ifpga_sec_mgr *imgr,
> +			    enum ifpga_sec_prog new_progress)
> +{
> +	imgr->progress = new_progress;
> +	sysfs_notify(&imgr->dev.kobj, "update", "status");
> +}
> +
>  static void ifpga_sec_dev_error(struct ifpga_sec_mgr *imgr,
>  				enum ifpga_sec_err err_code)
>  {
> @@ -149,7 +156,7 @@ static void ifpga_sec_dev_error(struct ifpga_sec_mgr
> *imgr,
>  static void progress_complete(struct ifpga_sec_mgr *imgr)
>  {
>  	mutex_lock(&imgr->lock);
> -	imgr->progress = IFPGA_SEC_PROG_IDLE;
> +	update_progress(imgr, IFPGA_SEC_PROG_IDLE);
>  	complete_all(&imgr->update_done);
>  	mutex_unlock(&imgr->lock);
>  }
> @@ -177,14 +184,14 @@ static void ifpga_sec_mgr_update(struct
> work_struct *work)
>  		goto release_fw_exit;
>  	}
> 
> -	imgr->progress = IFPGA_SEC_PROG_PREPARING;
> +	update_progress(imgr, IFPGA_SEC_PROG_PREPARING);
>  	ret = imgr->iops->prepare(imgr);
>  	if (ret) {
>  		ifpga_sec_dev_error(imgr, ret);
>  		goto modput_exit;
>  	}
> 
> -	imgr->progress = IFPGA_SEC_PROG_WRITING;
> +	update_progress(imgr, IFPGA_SEC_PROG_WRITING);
>  	size = imgr->remaining_size;
>  	while (size) {
>  		blk_size = min_t(u32, size, WRITE_BLOCK_SIZE);
> @@ -199,7 +206,7 @@ static void ifpga_sec_mgr_update(struct work_struct
> *work)
>  		offset += blk_size;
>  	}
> 
> -	imgr->progress = IFPGA_SEC_PROG_PROGRAMMING;
> +	update_progress(imgr, IFPGA_SEC_PROG_PROGRAMMING);
>  	ret = imgr->iops->poll_complete(imgr);
>  	if (ret) {
>  		ifpga_sec_dev_error(imgr, ret);
> @@ -259,6 +266,30 @@ static struct attribute_group
> sec_mgr_security_attr_group = {
>  	.is_visible = sec_mgr_visible,
>  };
> 
> +static const char * const sec_mgr_prog_str[] = {
> +	"idle",			/* IFPGA_SEC_PROG_IDLE */
> +	"reading",		/* IFPGA_SEC_PROG_READING */
> +	"preparing",		/* IFPGA_SEC_PROG_PREPARING */
> +	"writing",		/* IFPGA_SEC_PROG_WRITING */
> +	"programming"		/* IFPGA_SEC_PROG_PROGRAMMING */
> +};
> +
> +static ssize_t
> +status_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
> +	const char *status = "unknown-status";
> +
> +	if (imgr->progress < IFPGA_SEC_PROG_MAX)
> +		status = sec_mgr_prog_str[imgr->progress];

I am not sure if this would be a problem that as there is no lock protection for
the progress value. If someone changes imgr->progress into a bad value just
after the first check imgr->progress < IFPGA_SEC_PROG_MAX passed.

> +	else
> +		dev_warn(dev, "Invalid status during secure update: %d\n",
> +			 imgr->progress);

One minor thing, dev_err or even WARN_ON should be better, and I think 
if it hits this, that will be a critical issue in the driver, isn't it?

Thanks
Hao

> +
> +	return sprintf(buf, "%s\n", status);
> +}
> +static DEVICE_ATTR_RO(status);
> +
>  static ssize_t filename_store(struct device *dev, struct device_attribute *attr,
>  			      const char *buf, size_t count)
>  {
> @@ -293,6 +324,7 @@ static DEVICE_ATTR_WO(filename);
> 
>  static struct attribute *sec_mgr_update_attrs[] = {
>  	&dev_attr_filename.attr,
> +	&dev_attr_status.attr,
>  	NULL,
>  };
> 
> --
> 2.17.1


^ permalink raw reply	[flat|nested] 25+ messages in thread

* RE: [PATCH v2 4/7] fpga: sec-mgr: expose sec-mgr update errors
  2020-10-02 22:36 ` [PATCH v2 4/7] fpga: sec-mgr: expose sec-mgr update errors Russ Weight
  2020-10-04 21:06   ` Tom Rix
@ 2020-10-05  8:55   ` Wu, Hao
  2020-10-06 20:00     ` Russ Weight
  1 sibling, 1 reply; 25+ messages in thread
From: Wu, Hao @ 2020-10-05  8:55 UTC (permalink / raw)
  To: Weight, Russell H, mdf, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, Xu, Yilun, Gerlach, Matthew, Weight, Russell H

> Subject: [PATCH v2 4/7] fpga: sec-mgr: expose sec-mgr update errors
> 
> Extend Intel Security Manager class driver to include
> an update/error sysfs node that can be read for error
> information when a secure update fails.
> 
> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
> ---
> v2:
>   - Bumped documentation date and version
>   - Added warning to sec_progress() for invalid progress status
>   - Added sec_error() function (similar to sec_progress())
> ---
>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 17 ++++
>  drivers/fpga/ifpga-sec-mgr.c                  | 81 ++++++++++++++++---
>  include/linux/fpga/ifpga-sec-mgr.h            |  1 +
>  3 files changed, 89 insertions(+), 10 deletions(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> index 73a5246fea1b..1f9f2c215e0c 100644
> --- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> @@ -89,3 +89,20 @@ Description:	Read-only. Returns a string describing
> the current
>  		programming. Userspace code can poll on this file,
>  		as it will be signaled by sysfs_notify() on each
>  		state change.
> +
> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/update/error
> +Date:		Oct 2020
> +KernelVersion:  5.11
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Read-only. Returns a string describing the failure
> +		of a secure update. This string will be in the form
> +		of <STATUS>:<ERROR>, where <STATUS> will be one of
> +		the status strings described for the status sysfs
> +		file and <ERROR> will be one of the following:
> +		hw-error, timeout, user-abort, device-busy,
> +		invalid-file-size, read-write-error, flash-wearout,
> +		file-read-error.  The error sysfs file is only
> +		meaningful when the secure update engine is in the
> +		idle state. If this file is read while a secure
> +		update is in progress, then the read will fail with
> +		EBUSY.
> diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
> index ad918fb42dc2..456ea0b71e3d 100644
> --- a/drivers/fpga/ifpga-sec-mgr.c
> +++ b/drivers/fpga/ifpga-sec-mgr.c
> @@ -146,10 +146,16 @@ static void update_progress(struct ifpga_sec_mgr
> *imgr,
>  	sysfs_notify(&imgr->dev.kobj, "update", "status");
>  }
> 
> +static void set_error(struct ifpga_sec_mgr *imgr, enum ifpga_sec_err
> err_code)
> +{
> +	imgr->err_state = imgr->progress;
> +	imgr->err_code = err_code;
> +}
> +
>  static void ifpga_sec_dev_error(struct ifpga_sec_mgr *imgr,
>  				enum ifpga_sec_err err_code)
>  {
> -	imgr->err_code = err_code;
> +	set_error(imgr, err_code);
>  	imgr->iops->cancel(imgr);
>  }
> 
> @@ -172,7 +178,7 @@ static void ifpga_sec_mgr_update(struct work_struct
> *work)
> 
>  	get_device(&imgr->dev);
>  	if (request_firmware(&fw, imgr->filename, &imgr->dev)) {
> -		imgr->err_code = IFPGA_SEC_ERR_FILE_READ;
> +		set_error(imgr, IFPGA_SEC_ERR_FILE_READ);
>  		goto idle_exit;
>  	}
> 
> @@ -180,7 +186,7 @@ static void ifpga_sec_mgr_update(struct work_struct
> *work)
>  	imgr->remaining_size = fw->size;
> 
>  	if (!try_module_get(imgr->dev.parent->driver->owner)) {
> -		imgr->err_code = IFPGA_SEC_ERR_BUSY;
> +		set_error(imgr, IFPGA_SEC_ERR_BUSY);
>  		goto release_fw_exit;
>  	}
> 
> @@ -274,22 +280,76 @@ static const char * const sec_mgr_prog_str[] = {
>  	"programming"		/* IFPGA_SEC_PROG_PROGRAMMING */
>  };
> 
> -static ssize_t
> -status_show(struct device *dev, struct device_attribute *attr, char *buf)
> +static const char * const sec_mgr_err_str[] = {
> +	"none",			/* IFPGA_SEC_ERR_NONE */
> +	"hw-error",		/* IFPGA_SEC_ERR_HW_ERROR */
> +	"timeout",		/* IFPGA_SEC_ERR_TIMEOUT */
> +	"user-abort",		/* IFPGA_SEC_ERR_CANCELED */
> +	"device-busy",		/* IFPGA_SEC_ERR_BUSY */
> +	"invalid-file-size",	/* IFPGA_SEC_ERR_INVALID_SIZE */
> +	"read-write-error",	/* IFPGA_SEC_ERR_RW_ERROR */
> +	"flash-wearout",	/* IFPGA_SEC_ERR_WEAROUT */
> +	"file-read-error"	/* IFPGA_SEC_ERR_FILE_READ */
> +};
> +
> +static const char *sec_progress(struct device *dev, enum ifpga_sec_prog
> prog)
>  {
> -	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
>  	const char *status = "unknown-status";
> 
> -	if (imgr->progress < IFPGA_SEC_PROG_MAX)
> -		status = sec_mgr_prog_str[imgr->progress];
> +	if (prog < IFPGA_SEC_PROG_MAX)
> +		status = sec_mgr_prog_str[prog];
>  	else
>  		dev_warn(dev, "Invalid status during secure update: %d\n",
> -			 imgr->progress);
> +			 prog);
> +
> +	return status;
> +}
> +
> +static const char *sec_error(struct device *dev, enum ifpga_sec_err
> err_code)
> +{
> +	const char *error = "unknown-error";
> +
> +	if (err_code < IFPGA_SEC_ERR_MAX)
> +		error = sec_mgr_err_str[err_code];
> +	else
> +		dev_warn(dev, "Invalid error code during secure
> update: %d\n",
> +			 err_code);
> +
> +	return error;
> +}
> +
> +static ssize_t
> +status_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
> 
> -	return sprintf(buf, "%s\n", status);
> +	return sprintf(buf, "%s\n", sec_progress(dev, imgr->progress));
>  }
>  static DEVICE_ATTR_RO(status);
> 
> +static ssize_t
> +error_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
> +	int ret;
> +
> +	mutex_lock(&imgr->lock);
> +
> +	if (imgr->progress != IFPGA_SEC_PROG_IDLE)
> +		ret = -EBUSY;
> +	else if (!imgr->err_code)
> +		ret = 0;
> +	else
> +		ret = sprintf(buf, "%s:%s\n",
> +			      sec_progress(dev, imgr->err_state),
> +			      sec_error(dev, imgr->err_code));

In scheduled work for update, there is no lock protection, would that be a 
real problem here? e.g. progress is changed, or err_state and err_code
are not matched.

Thanks
Hao

> +
> +	mutex_unlock(&imgr->lock);
> +
> +	return ret;
> +}
> +static DEVICE_ATTR_RO(error);
> +
>  static ssize_t filename_store(struct device *dev, struct device_attribute *attr,
>  			      const char *buf, size_t count)
>  {
> @@ -325,6 +385,7 @@ static DEVICE_ATTR_WO(filename);
>  static struct attribute *sec_mgr_update_attrs[] = {
>  	&dev_attr_filename.attr,
>  	&dev_attr_status.attr,
> +	&dev_attr_error.attr,
>  	NULL,
>  };
> 
> diff --git a/include/linux/fpga/ifpga-sec-mgr.h b/include/linux/fpga/ifpga-
> sec-mgr.h
> index 27008abd8e75..246e3d452c59 100644
> --- a/include/linux/fpga/ifpga-sec-mgr.h
> +++ b/include/linux/fpga/ifpga-sec-mgr.h
> @@ -110,6 +110,7 @@ struct ifpga_sec_mgr {
>  	const u8 *data;			/* pointer to update data */
>  	u32 remaining_size;		/* size remaining to transfer */
>  	enum ifpga_sec_prog progress;
> +	enum ifpga_sec_prog err_state;	/* progress state at time of
> failure */
>  	enum ifpga_sec_err err_code;	/* security manager error code */
>  	bool driver_unload;
>  	void *priv;
> --
> 2.17.1


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 1/7] fpga: sec-mgr: intel fpga security manager class driver
  2020-10-05  7:38   ` Wu, Hao
@ 2020-10-06  0:05     ` Russ Weight
  2020-10-06  1:01       ` Russ Weight
  0 siblings, 1 reply; 25+ messages in thread
From: Russ Weight @ 2020-10-06  0:05 UTC (permalink / raw)
  To: Wu, Hao, mdf, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, Xu, Yilun, Gerlach, Matthew



On 10/5/20 12:38 AM, Wu, Hao wrote:
>> Subject: [PATCH v2 1/7] fpga: sec-mgr: intel fpga security manager class
>> driver
>>
>> Create the Intel Security Manager class driver. The security
>> manager provides interfaces to manage secure updates for the
>> FPGA and BMC images that are stored in FLASH. The driver can
>> also be used to update root entry hashes and to cancel code
>> signing keys.
>>
>> This patch creates the class driver and provides sysfs
>> interfaces for displaying root entry hashes, canceled code
>> signing keys and flash counts.
>>
>> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
>> Signed-off-by: Xu Yilun <yilun.xu@intel.com>
>> ---
>> v2:
>>   - Bumped documentation dates and versions
>>   - Added Documentation/fpga/ifpga-sec-mgr.rst
>>   - Removed references to bmc_flash_count & smbus_flash_count (not
>> supported)
>>   - Split ifpga_sec_mgr_register() into create() and register() functions
>>   - Added devm_ifpga_sec_mgr_create()
>>   - Removed typedefs for imgr ops
>> ---
>>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  67 +++
>>  Documentation/fpga/ifpga-sec-mgr.rst          |  50 ++
>>  Documentation/fpga/index.rst                  |   1 +
>>  MAINTAINERS                                   |   9 +
>>  drivers/fpga/Kconfig                          |   9 +
>>  drivers/fpga/Makefile                         |   3 +
>>  drivers/fpga/ifpga-sec-mgr.c                  | 432 ++++++++++++++++++
>>  include/linux/fpga/ifpga-sec-mgr.h            |  81 ++++
>>  8 files changed, 652 insertions(+)
>>  create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>  create mode 100644 Documentation/fpga/ifpga-sec-mgr.rst
>>  create mode 100644 drivers/fpga/ifpga-sec-mgr.c
>>  create mode 100644 include/linux/fpga/ifpga-sec-mgr.h
>>
>> diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> new file mode 100644
>> index 000000000000..707958971bcb
>> --- /dev/null
>> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> @@ -0,0 +1,67 @@
>> +What: /sys/class/ifpga_sec_mgr/ifpga_secX/name
>> +Date:Oct 2020
>> +KernelVersion:  5.11
>> +Contact:Russ Weight <russell.h.weight@intel.com>
>> +Description:Name of low level fpga security manager driver.
>> +
>> +What:
>> /sys/class/ifpga_sec_mgr/ifpga_secX/security/sr_root_entry_hash
>> +Date:Oct 2020
>> +KernelVersion:  5.11
>> +Contact:Russ Weight <russell.h.weight@intel.com>
>> +Description:Read only. Returns the root entry hash for the static
>> +region if one is programmed, else it returns the
>> +string: "hash not programmed".  This file is only
>> +visible if the underlying device supports it.
>> +Format: "0x%x".
>> +
>> +What:
>> /sys/class/ifpga_sec_mgr/ifpga_secX/security/pr_root_entry_hash
>> +Date:Oct 2020
>> +KernelVersion:  5.11
>> +Contact:Russ Weight <russell.h.weight@intel.com>
>> +Description:Read only. Returns the root entry hash for the partial
>> +reconfiguration region if one is programmed, else it
>> +returns the string: "hash not programmed".  This file
>> +is only visible if the underlying device supports it.
>> +Format: "0x%x".
>> +
>> +What:
>> /sys/class/ifpga_sec_mgr/ifpga_secX/security/bmc_root_entry_hash
>> +Date:Oct 2020
>> +KernelVersion:  5.11
>> +Contact:Russ Weight <russell.h.weight@intel.com>
>> +Description:Read only. Returns the root entry hash for the BMC image
>> +if one is programmed, else it returns the string:
>> +"hash not programmed".  This file is only visible if the
>> +underlying device supports it.
>> +Format: "0x%x".
>> +
>> +What:
>> /sys/class/ifpga_sec_mgr/ifpga_secX/security/sr_canceled_csks
>> +Date:Oct 2020
>> +KernelVersion:  5.11
>> +Contact:Russ Weight <russell.h.weight@intel.com>
>> +Description:Read only. Returns a list of indices for canceled code
>> +signing keys for the static region. The standard bitmap
>> +list format is used (e.g. "1,2-6,9").
>> +
>> +What:
>> /sys/class/ifpga_sec_mgr/ifpga_secX/security/pr_canceled_csks
>> +Date:Oct 2020
>> +KernelVersion:  5.11
>> +Contact:Russ Weight <russell.h.weight@intel.com>
>> +Description:Read only. Returns a list of indices for canceled code
>> +signing keys for the partial reconfiguration region. The
>> +standard bitmap list format is used (e.g. "1,2-6,9").
>> +
>> +What:
>> /sys/class/ifpga_sec_mgr/ifpga_secX/security/bmc_canceled_csks
>> +Date:Oct 2020
>> +KernelVersion:  5.11
>> +Contact:Russ Weight <russell.h.weight@intel.com>
>> +Description:Read only. Returns a list of indices for canceled code
>> +signing keys for the BMC.  The standard bitmap list format
>> +is used (e.g. "1,2-6,9").
>> +
>> +What:
>> /sys/class/ifpga_sec_mgr/ifpga_secX/security/user_flash_count
>> +Date:Oct 2020
>> +KernelVersion:  5.11
>> +Contact:Russ Weight <russell.h.weight@intel.com>
>> +Description:Read only. Returns number of times the user image for the
>> +static region has been flashed.
>> +Format: "%u".
>> diff --git a/Documentation/fpga/ifpga-sec-mgr.rst
>> b/Documentation/fpga/ifpga-sec-mgr.rst
>> new file mode 100644
>> index 000000000000..02f3f65b182b
>> --- /dev/null
>> +++ b/Documentation/fpga/ifpga-sec-mgr.rst
>> @@ -0,0 +1,50 @@
>> +.. SPDX-License-Identifier: GPL-2.0
>> +
>> +========================================
>> +Intel FPGA Security Manager Class Driver
>> +========================================
>> +
>> +The Intel FPGA Security Manager class driver provides a common
>> +API for user-space tools to manage updates for secure Intel FPGA
>> +devices. Device drivers that instantiate the Intel Security
>> +Manager class driver will interact with a HW secure update
>> +engine in order to transfer new FPGA and BMC images to FLASH so
>> +that they will be automatically loaded when the FPGA card reboots.
>> +
>> +A significant difference between the FPGA Manager and the Intel FPGA
>> +Security Manager is that the FPGA Manager does a live update (Partial
>> +Reconfiguration) to a device, whereas the Intel FPGA Security Manager
>> +updates the FLASH images for the Static Region and the BMC so that
>> +they will be loaded the next time the FPGA card boots. Security is
>> +enforced by hardware and firmware. The security manager interacts
>> +with the firmware to initiate an update, pass in the necessary data,
>> +and collect status on the update.
>> +
>> +In addition to managing secure updates of the FPGA and BMC images,
>> +the Intel FPGA Security Manager update process may also used to
>> +program root entry hashes and cancellation keys for the FPGA static
>> +region, the FPGA partial reconfiguration region, and the BMC.
>> +
>> +Secure updates make use of the request_firmware framework, which
>> +requires that image files are accessible under /lib/firmware. A request
>> +for a secure update returns immediately, while the update itself
>> +proceeds in the context of a kernel worker thread. Sysfs files provide
>> +a means for monitoring the progress of a secure update and for
>> +retrieving error information in the event of a failure.
>> +
>> +Sysfs Attributes
>> +================
>> +
>> +The API consists of two groups of sysfs attributes as described below.
>> +
>> +1. Files in the *security* sub-directory can be used to read security
>> +   information including: Root Entry Hashes (REH), Cancelled Code
>> +   Signing Keys (CSK), and the flash update count for FPGA images.
>> +
>> +2. Files in the *update* sub-directory can be used to instantiate and
>> +   monitor a secure update.
>> +
>> +
>> +See `<../ABI/testing/sysfs-class-ifpga-sec-mgr>`__ for a full
>> +description of the sysfs attributes for the Intel FPGA Security
>> +Manager.
>> diff --git a/Documentation/fpga/index.rst b/Documentation/fpga/index.rst
>> index f80f95667ca2..ba9c6b1917bd 100644
>> --- a/Documentation/fpga/index.rst
>> +++ b/Documentation/fpga/index.rst
>> @@ -8,6 +8,7 @@ fpga
>>      :maxdepth: 1
>>
>>      dfl
>> +    ifpga-sec-mgr
>>
>>  .. only::  subproject and html
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 6d1175bf8529..5ffc0e02d741 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -6858,6 +6858,15 @@ F:Documentation/fpga/
>>  F:drivers/fpga/
>>  F:include/linux/fpga/
>>
>> +INTEL FPGA SECURITY MANAGER DRIVERS
>> +M:Russ Weight <russell.h.weight@intel.com>
>> +L:linux-fpga@vger.kernel.org
>> +S:Maintained
>> +F:Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> +F:Documentation/fpga/ifpga-sec-mgr.rst
>> +F:drivers/fpga/ifpga-sec-mgr.c
>> +F:include/linux/fpga/ifpga-sec-mgr.h
>> +
>>  FPU EMULATOR
>>  M:Bill Metzenthen <billm@melbpc.org.au>
>>  S:Maintained
>> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
>> index 7cd5a29fc437..bf566a625be7 100644
>> --- a/drivers/fpga/Kconfig
>> +++ b/drivers/fpga/Kconfig
>> @@ -215,4 +215,13 @@ config FPGA_MGR_ZYNQMP_FPGA
>>    to configure the programmable logic(PL) through PS
>>    on ZynqMP SoC.
>>
>> +config IFPGA_SEC_MGR
>> +tristate "Intel Security Manager for FPGA"
>> +help
>> +  The Intel Security Manager class driver presents a common
>> +  user API for managing secure updates for Intel FPGA
>> +  devices, including flash images for the FPGA static
>> +  region and for the BMC. Select this option to enable
>> +  updates for secure FPGA devices.
>> +
>>  endif # FPGA
>> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
>> index d8e21dfc6778..2e1d29c3d915 100644
>> --- a/drivers/fpga/Makefile
>> +++ b/drivers/fpga/Makefile
>> @@ -21,6 +21,9 @@ obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)+=
>> zynqmp-fpga.o
>>  obj-$(CONFIG_ALTERA_PR_IP_CORE)         += altera-pr-ip-core.o
>>  obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT)    += altera-pr-ip-core-plat.o
>>
>> +# Intel FPGA Security Manager Framework
>> +obj-$(CONFIG_IFPGA_SEC_MGR)+= ifpga-sec-mgr.o
>> +
>>  # FPGA Bridge Drivers
>>  obj-$(CONFIG_FPGA_BRIDGE)+= fpga-bridge.o
>>  obj-$(CONFIG_SOCFPGA_FPGA_BRIDGE)+= altera-hps2fpga.o altera-
>> fpga2sdram.o
>> diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
>> new file mode 100644
>> index 000000000000..f1caa4602ab3
>> --- /dev/null
>> +++ b/drivers/fpga/ifpga-sec-mgr.c
>> @@ -0,0 +1,432 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Intel Security Manager for FPGA
>> + *
>> + * Copyright (C) 2019-2020 Intel Corporation, Inc.
>> + */
>> +
>> +#include <linux/fpga/ifpga-sec-mgr.h>
>> +#include <linux/idr.h>
>> +#include <linux/module.h>
>> +#include <linux/slab.h>
>> +#include <linux/vmalloc.h>
>> +
>> +static DEFINE_IDA(ifpga_sec_mgr_ida);
>> +static struct class *ifpga_sec_mgr_class;
>> +
>> +#define to_sec_mgr(d) container_of(d, struct ifpga_sec_mgr, dev)
>> +
>> +static ssize_t
>> +show_canceled_csk(struct ifpga_sec_mgr *imgr,
>> +  int (*get_csk)(struct ifpga_sec_mgr *imgr,
>> + unsigned long *csk_map, unsigned int nbits),
>> +  int (*get_csk_nbits)(struct ifpga_sec_mgr *imgr),
>> +  char *buf)
>> +{
>> +unsigned long *csk_map = NULL;
>> +unsigned int nbits;
>> +int ret;
>> +
>> +ret = get_csk_nbits(imgr);
>> +if (ret < 0)
>> +return ret;
>> +
>> +nbits = (unsigned int)ret;
>> +csk_map = vmalloc(sizeof(unsigned long) * BITS_TO_LONGS(nbits));
>> +if (!csk_map)
>> +return -ENOMEM;
>> +
>> +ret = get_csk(imgr, csk_map, nbits);
>> +if (ret)
>> +goto vfree_exit;
>> +
>> +ret = bitmap_print_to_pagebuf(1, buf, csk_map, nbits);
>> +
>> +vfree_exit:
>> +vfree(csk_map);
>> +return ret;
>> +}
>> +
>> +static ssize_t
>> +show_root_entry_hash(struct ifpga_sec_mgr *imgr,
>> +     int (*get_reh)(struct ifpga_sec_mgr *imgr, u8 *hash,
>> +    unsigned int size),
>> +     int (*get_reh_size)(struct ifpga_sec_mgr *imgr),
>> +     char *buf)
>> +{
>> +int size, i, cnt, ret;
>> +u8 *hash;
>> +
>> +ret = get_reh_size(imgr);
>> +if (ret < 0)
>> +return ret;
>> +else if (!ret)
>> +return sprintf(buf, "hash not programmed\n");
>> +
>> +size = ret;
>> +hash = vmalloc(size);
>> +if (!hash)
>> +return -ENOMEM;
>> +
>> +ret = get_reh(imgr, hash, size);
>> +if (ret)
>> +goto vfree_exit;
>> +
>> +cnt = sprintf(buf, "0x");
>> +for (i = 0; i < size; i++)
>> +cnt += sprintf(buf + cnt, "%02x", hash[i]);
>> +cnt += sprintf(buf + cnt, "\n");
>> +
>> +vfree_exit:
>> +vfree(hash);
>> +return ret ? : cnt;
>> +}
>> +
>> +#define DEVICE_ATTR_SEC_CSK(_name) \
>> +static ssize_t _name##_canceled_csks_show(struct device *dev, \
>> +  struct device_attribute *attr, \
>> +  char *buf) \
>> +{ \
>> +struct ifpga_sec_mgr *imgr = to_sec_mgr(dev); \
>> +return show_canceled_csk(imgr, \
>> +       imgr->iops->_name##_canceled_csks, \
>> +       imgr->iops->_name##_canceled_csk_nbits, buf); \
>> +} \
>> +static DEVICE_ATTR_RO(_name##_canceled_csks)
>> +
>> +#define DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(_name) \
>> +static ssize_t _name##_root_entry_hash_show(struct device *dev, \
>> +     struct device_attribute *attr, \
>> +     char *buf) \
>> +{ \
>> +struct ifpga_sec_mgr *imgr = to_sec_mgr(dev); \
>> +return show_root_entry_hash(imgr, \
>> +       imgr->iops->_name##_root_entry_hash, \
>> +       imgr->iops->_name##_reh_size, buf); \
>> +} \
>> +static DEVICE_ATTR_RO(_name##_root_entry_hash)
>> +
>> +static ssize_t user_flash_count_show(struct device *dev,
>> +     struct device_attribute *attr, char *buf)
>> +{
>> +struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
>> +
>> +int cnt = imgr->iops->user_flash_count(imgr);
>> +return cnt < 0 ? cnt : sprintf(buf, "%u\n", cnt);
>> +}
>> +static DEVICE_ATTR_RO(user_flash_count);
>> +
>> +DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(sr);
>> +DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(pr);
>> +DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(bmc);
>> +DEVICE_ATTR_SEC_CSK(sr);
>> +DEVICE_ATTR_SEC_CSK(pr);
>> +DEVICE_ATTR_SEC_CSK(bmc);
>> +
>> +static struct attribute *sec_mgr_security_attrs[] = {
>> +&dev_attr_user_flash_count.attr,
>> +&dev_attr_bmc_root_entry_hash.attr,
>> +&dev_attr_sr_root_entry_hash.attr,
>> +&dev_attr_pr_root_entry_hash.attr,
>> +&dev_attr_sr_canceled_csks.attr,
>> +&dev_attr_pr_canceled_csks.attr,
>> +&dev_attr_bmc_canceled_csks.attr,
>> +NULL,
>> +};
>> +
>> +#define check_attr(attribute, _name) \
>> +((attribute) == &dev_attr_##_name.attr && imgr->iops->_name)
>> +
>> +static umode_t sec_mgr_visible(struct kobject *kobj,
>> +       struct attribute *attr, int n)
>> +{
>> +struct ifpga_sec_mgr *imgr = to_sec_mgr(kobj_to_dev(kobj));
>> +
>> +/*
>> + * Only display optional sysfs attributes if a
>> + * corresponding handler is provided
>> + */
>> +if (check_attr(attr, user_flash_count) ||
>> +    check_attr(attr, bmc_root_entry_hash) ||
>> +    check_attr(attr, sr_root_entry_hash) ||
>> +    check_attr(attr, pr_root_entry_hash) ||
>> +    check_attr(attr, sr_canceled_csks) ||
>> +    check_attr(attr, pr_canceled_csks) ||
>> +    check_attr(attr, bmc_canceled_csks))
>> +return attr->mode;
>> +
>> +return 0;
>> +}
>> +
>> +static struct attribute_group sec_mgr_security_attr_group = {
>> +.name = "security",
>> +.attrs = sec_mgr_security_attrs,
>> +.is_visible = sec_mgr_visible,
>> +};
>> +
>> +static ssize_t name_show(struct device *dev,
>> + struct device_attribute *attr, char *buf)
>> +{
>> +struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
>> +
>> +return sprintf(buf, "%s\n", imgr->name);
>> +}
>> +static DEVICE_ATTR_RO(name);
>> +
>> +static struct attribute *sec_mgr_attrs[] = {
>> +&dev_attr_name.attr,
>> +NULL,
>> +};
>> +
>> +static struct attribute_group sec_mgr_attr_group = {
>> +.attrs = sec_mgr_attrs,
>> +};
>> +
>> +static const struct attribute_group *ifpga_sec_mgr_attr_groups[] = {
>> +&sec_mgr_attr_group,
>> +&sec_mgr_security_attr_group,
>> +NULL,
>> +};
>> +
>> +static bool check_sysfs_handler(struct device *dev,
>> +void *sysfs_handler, void *size_handler,
>> +const char *sysfs_handler_name,
>> +const char *size_handler_name)
>> +{
>> +/*
>> + * sysfs_handler and size_handler must either both be
>> + * defined or both be NULL.
>> + */
>> +if (sysfs_handler) {
>> +if (!size_handler) {
>> +dev_err(dev, "%s registered without %s\n",
>> +sysfs_handler_name, size_handler_name);
>> +return false;
>> +}
>> +} else if (size_handler) {
>> +dev_err(dev, "%s registered without %s\n",
>> +size_handler_name, sysfs_handler_name);
>> +return false;
>> +}
> Optional:
>
> If (sysfs_handler && !size_handler) {
>
> } else if (!sysfs_handler && size_handler) {
>
> }
Yes, I can code it that way. It would be more readable.
>
>> +return true;
>> +}
>> +
>> +#define check_reh_handler(_dev, _iops, _name) \
>> +check_sysfs_handler(_dev, (_iops)->_name##_root_entry_hash, \
>> +    (_iops)->_name##_reh_size, \
>> +    __stringify(_name##_root_entry_hash), \
>> +    __stringify(_name##_reh_size))
>> +
>> +#define check_csk_handler(_dev, _iops, _name) \
>> +check_sysfs_handler(_dev, (_iops)->_name##_canceled_csks, \
>> +    (_iops)->_name##_canceled_csk_nbits, \
>> +    __stringify(_name##_canceled_csks), \
>> +    __stringify(_name##_canceled_csk_nbits))
>> +
>> +/**
>> + * ifpga_sec_mgr_create - create and initialize an Intel FPGA
>> + *  security manager struct
>> + *
>> + * @dev:  Intel fpga security manager device from pdev
>> + * @name: ifpga security manager name
>> + * @iops: pointer to a structure of ifpga callback functions
>> + * @priv: ifpga security manager private data
>> + *
>> + * The caller of this function is responsible for freeing the struct
>> + * with ifpg_sec_mgr_free(). Using devm_ifpga_sec_mgr_create() instead
>> + * is recommended.
>> + *
>> + * Return: pointer to struct ifpga_sec_mgr or NULL
>> + */
>> +struct ifpga_sec_mgr *
>> +ifpga_sec_mgr_create(struct device *dev, const char *name,
>> +     const struct ifpga_sec_mgr_ops *iops, void *priv)
>> +{
>> +struct ifpga_sec_mgr *imgr;
>> +int id, ret;
>> +
>> +if (!check_reh_handler(dev, iops, bmc) ||
>> +    !check_reh_handler(dev, iops, sr) ||
>> +    !check_reh_handler(dev, iops, pr) ||
>> +    !check_csk_handler(dev, iops, bmc) ||
>> +    !check_csk_handler(dev, iops, sr) ||
>> +    !check_csk_handler(dev, iops, pr)) {
>> +return NULL;
>> +}
>> +
>> +if (!name || !strlen(name)) {
>> +dev_err(dev, "Attempt to register with no name!\n");
>> +return NULL;
>> +}
>> +
>> +imgr = kzalloc(sizeof(*imgr), GFP_KERNEL);
>> +if (!imgr)
>> +return NULL;
>> +
>> +id = ida_simple_get(&ifpga_sec_mgr_ida, 0, 0, GFP_KERNEL);
>> +if (id < 0)
>> +goto error_kfree;
>> +
>> +mutex_init(&imgr->lock);
>> +
>> +imgr->name = name;
>> +imgr->priv = priv;
>> +imgr->iops = iops;
>> +
>> +device_initialize(&imgr->dev);
>> +imgr->dev.class = ifpga_sec_mgr_class;
>> +imgr->dev.parent = dev;
>> +imgr->dev.id = id;
>> +
>> +ret = dev_set_name(&imgr->dev, "ifpga_sec%d", id);
>> +if (ret) {
>> +dev_err(dev, "Failed to set device name: ifpga_sec%d\n", id);
>> +goto error_device;
>> +}
>> +
>> +return imgr;
>> +
>> +error_device:
>> +ida_simple_remove(&ifpga_sec_mgr_ida, id);
>> +
>> +error_kfree:
>> +kfree(imgr);
>> +
>> +return NULL;
>> +}
>> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_create);
>> +
>> +/**
>> + * ifpga_sec_mgr_free - free an Intel FPGA security manager created
>> + *with ifpga_sec_mgr_create()
>> + *
>> + * @imgr:Intel FPGA security manager structure
>> + */
>> +void ifpga_sec_mgr_free(struct ifpga_sec_mgr *imgr)
>> +{
>> +ida_simple_remove(&ifpga_sec_mgr_ida, imgr->dev.id);
>> +kfree(imgr);
>> +}
>> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_free);
>> +
>> +static void devm_ifpga_sec_mgr_release(struct device *dev, void *res)
>> +{
>> +struct ifpga_sec_mgr *imgr = *(struct ifpga_sec_mgr **)res;
>> +
>> +ifpga_sec_mgr_free(imgr);
>> +}
>> +
>> +/**
>> + * devm_ifpga_sec_mgr_create - create and initialize an Intel FPGA
>> + *       security manager struct
>> + *
>> + * @dev:  Intel fpga security manager device from pdev
>> + * @name: ifpga security manager name
>> + * @iops: pointer to a structure of ifpga callback functions
>> + * @priv: ifpga security manager private data
>> + *
>> + * This function is intended for use in a Intel FPGA Security manager
>> + * driver's probe function.  After the security manager driver creates
>> + * the ifpga_sec_mgr struct with devm_fpga_mgr_create(), it should
>> + * register it with ifpga_sec_mgr_register().  The security manager
>> + * driver's remove function should call ifpga_sec_mgr_unregister().
>> + * The ifpga_sec_mgr struct allocated with this function will be freed
>> + * automatically on driver detach.  This includes the case of a probe
>> + * function returning error before calling fpga_mgr_register(), the
>> + * struct will still get cleaned up.
>> + *
>> + * Return: pointer to struct ifpga_sec_mgr or NULL
>> + */
>> +struct ifpga_sec_mgr *
>> +devm_ifpga_sec_mgr_create(struct device *dev, const char *name,
>> +  const struct ifpga_sec_mgr_ops *iops, void *priv)
>> +{
>> +struct ifpga_sec_mgr **ptr, *imgr;
>> +
>> +ptr = devres_alloc(devm_ifpga_sec_mgr_release, sizeof(*ptr),
>> GFP_KERNEL);
>> +if (!ptr)
>> +return NULL;
>> +
>> +imgr = ifpga_sec_mgr_create(dev, name, iops, priv);
>> +if (!imgr) {
>> +devres_free(ptr);
>> +} else {
>> +*ptr = imgr;
>> +devres_add(dev, ptr);
>> +}
>> +
>> +return imgr;
>> +}
>> +EXPORT_SYMBOL_GPL(devm_ifpga_sec_mgr_create);
>> +
>> +/**
>> + * ifpga_sec_mgr_register - register an Intel FPGA security manager
>> + *
>> + * @imgr: Intel fpga security manager struct
>> + *
>> + * Return: 0 on success, negative error code otherwise.
>> + */
>> +int ifpga_sec_mgr_register(struct ifpga_sec_mgr *imgr)
>> +{
>> +int ret;
>> +
>> +ret = device_add(&imgr->dev);
>> +if (ret)
>> +goto error_device;
>> +
>> +dev_info(&imgr->dev, "%s registered\n", imgr->name);
>> +
>> +return 0;
>> +
>> +error_device:
>> +ida_simple_remove(&ifpga_sec_mgr_ida, imgr->dev.id);
>> +
>> +return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_register);
>> +
>> +/**
>> + * ifpga_sec_mgr_unregister - unregister an Intel FPGA security manager
>> + *
>> + * @mgr: fpga manager struct
>> + *
>> + * This function is intended for use in an Intel FPGA security manager
>> + * driver's remove() function.
>> + */
>> +void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr)
>> +{
>> +dev_info(&imgr->dev, "%s %s\n", __func__, imgr->name);
>> +
>> +device_unregister(&imgr->dev);
>> +}
>> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_unregister);
>> +
>> +static void ifpga_sec_mgr_dev_release(struct device *dev)
>> +{
>> +}
>> +
>> +static int __init ifpga_sec_mgr_class_init(void)
>> +{
>> +pr_info("Intel FPGA Security Manager\n");
>> +
>> +ifpga_sec_mgr_class = class_create(THIS_MODULE, "ifpga_sec_mgr");
>> +if (IS_ERR(ifpga_sec_mgr_class))
>> +return PTR_ERR(ifpga_sec_mgr_class);
>> +
>> +ifpga_sec_mgr_class->dev_groups = ifpga_sec_mgr_attr_groups;
>> +ifpga_sec_mgr_class->dev_release = ifpga_sec_mgr_dev_release;
>> +
>> +return 0;
>> +}
>> +
>> +static void __exit ifpga_sec_mgr_class_exit(void)
>> +{
>> +class_destroy(ifpga_sec_mgr_class);
>> +ida_destroy(&ifpga_sec_mgr_ida);
>> +}
>> +
>> +MODULE_DESCRIPTION("Intel FPGA Security Manager Driver");
>> +MODULE_LICENSE("GPL v2");
>> +
>> +subsys_initcall(ifpga_sec_mgr_class_init);
>> +module_exit(ifpga_sec_mgr_class_exit)
>> diff --git a/include/linux/fpga/ifpga-sec-mgr.h b/include/linux/fpga/ifpga-
>> sec-mgr.h
>> new file mode 100644
>> index 000000000000..ded62090e9b9
>> --- /dev/null
>> +++ b/include/linux/fpga/ifpga-sec-mgr.h
>> @@ -0,0 +1,81 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Header file for Intel FPGA Security Manager
>> + *
>> + * Copyright (C) 2019-2020 Intel Corporation, Inc.
>> + */
>> +#ifndef _LINUX_IFPGA_SEC_MGR_H
>> +#define _LINUX_IFPGA_SEC_MGR_H
>> +
>> +#include <linux/device.h>
>> +#include <linux/mutex.h>
>> +#include <linux/types.h>
>> +
>> +struct ifpga_sec_mgr;
>> +
>> +/**
>> + * struct ifpga_sec_mgr_ops - device specific operations
>> + * @user_flash_count:    Optional: Return sysfs string output for
>> FPGA
>> + *    image flash count
>> + * @sr_root_entry_hash:    Optional: Return sysfs string output for
>> static
>> + *    region root entry hash
>> + * @pr_root_entry_hash:    Optional: Return sysfs string output for
>> partial
>> + *    reconfiguration root entry hash
>> + * @bmc_root_entry_hash:    Optional: Return sysfs string output for BMC
>> + *    root entry hash
>> + * @sr_canceled_csks:    Optional: Return sysfs string output for static
>> + *    region canceled keys
>> + * @pr_canceled_csks:    Optional: Return sysfs string output for
>> partial
>> + *    reconfiguration canceled keys
>> + * @bmc_canceled_csks:    Optional: Return sysfs string output for
>> bmc
>> + *    canceled keys
>> + * @bmc_canceled_csk_nbits: Optional: Return BMC canceled csk vector bit
>> count
>> + * @sr_canceled_csk_nbits:  Optional: Return SR canceled csk vector bit
>> count
>> + * @pr_canceled_csk_nbits:  Optional: Return PR canceled csk vector bit
>> count
>> + * @bmc_reh_size:    Optional: Return byte size for BMC root entry hash
>> + * @sr_reh_size:    Optional: Return byte size for SR root entry hash
>> + * @pr_reh_size:    Optional: Return byte size for PR root entry hash
>> + */
>> +struct ifpga_sec_mgr_ops {
>> +int (*user_flash_count)(struct ifpga_sec_mgr *imgr);
>> +int (*bmc_root_entry_hash)(struct ifpga_sec_mgr *imgr, u8 *hash,
>> +   unsigned int size);
>> +int (*sr_root_entry_hash)(struct ifpga_sec_mgr *imgr, u8 *hash,
>> +  unsigned int size);
>> +int (*pr_root_entry_hash)(struct ifpga_sec_mgr *imgr, u8 *hash,
>> +  unsigned int size);
>> +int (*bmc_canceled_csks)(struct ifpga_sec_mgr *imgr,
>> + unsigned long *csk_map, unsigned int nbits);
>> +int (*sr_canceled_csks)(struct ifpga_sec_mgr *imgr,
>> +unsigned long *csk_map, unsigned int nbits);
>> +int (*pr_canceled_csks)(struct ifpga_sec_mgr *imgr,
>> +unsigned long *csk_map, unsigned int nbits);
>> +int (*bmc_reh_size)(struct ifpga_sec_mgr *imgr);
>> +int (*sr_reh_size)(struct ifpga_sec_mgr *imgr);
>> +int (*pr_reh_size)(struct ifpga_sec_mgr *imgr);
>> +int (*bmc_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
>> +int (*sr_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
>> +int (*pr_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
> I am thinking that if these callbacks for size are really needed or not.
> If these size values are not changed dynamically, which requires no
> recalculation, then these size values can be stored in ifpga sec mgr
> data structure directly. I think the checking logic could be simpler too.
> Do you think if it is possible?
Yes - it is possible. The size could be calculated before creating the security
manager. It just means that the iops data structure has to be dynamically created.
As it turns out, we need to do that (eventually) anyway to handle some differences
between the n3000 and the d5005 devices, so I can code up the changes and see
how it looks.
>
> Thanks
> Hao
>
>> +};
>> +
>> +struct ifpga_sec_mgr {
>> +const char *name;
>> +struct device dev;
>> +const struct ifpga_sec_mgr_ops *iops;
>> +struct mutex lock;/* protect data structure contents */
>> +void *priv;
>> +};
>> +
>> +struct ifpga_sec_mgr *
>> +ifpga_sec_mgr_create(struct device *dev, const char *name,
>> +     const struct ifpga_sec_mgr_ops *iops, void *priv);
>> +
>> +struct ifpga_sec_mgr *
>> +devm_ifpga_sec_mgr_create(struct device *dev, const char *name,
>> +  const struct ifpga_sec_mgr_ops *iops, void *priv);
>> +
>> +int ifpga_sec_mgr_register(struct ifpga_sec_mgr *imgr);
>> +void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr);
>> +void ifpga_sec_mgr_free(struct ifpga_sec_mgr *imgr);
>> +
>> +#endif
>> --
>> 2.17.1


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 1/7] fpga: sec-mgr: intel fpga security manager class driver
  2020-10-06  0:05     ` Russ Weight
@ 2020-10-06  1:01       ` Russ Weight
  0 siblings, 0 replies; 25+ messages in thread
From: Russ Weight @ 2020-10-06  1:01 UTC (permalink / raw)
  To: Wu, Hao, mdf, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, Xu, Yilun, Gerlach, Matthew



On 10/5/20 5:05 PM, Russ Weight wrote:
>
> On 10/5/20 12:38 AM, Wu, Hao wrote:
>>> Subject: [PATCH v2 1/7] fpga: sec-mgr: intel fpga security manager class
>>> driver
>>>
>>> Create the Intel Security Manager class driver. The security
>>> manager provides interfaces to manage secure updates for the
>>> FPGA and BMC images that are stored in FLASH. The driver can
>>> also be used to update root entry hashes and to cancel code
>>> signing keys.
>>>
>>> This patch creates the class driver and provides sysfs
>>> interfaces for displaying root entry hashes, canceled code
>>> signing keys and flash counts.
>>>
>>> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
>>> Signed-off-by: Xu Yilun <yilun.xu@intel.com>
>>> ---
>>> v2:
>>>   - Bumped documentation dates and versions
>>>   - Added Documentation/fpga/ifpga-sec-mgr.rst
>>>   - Removed references to bmc_flash_count & smbus_flash_count (not
>>> supported)
>>>   - Split ifpga_sec_mgr_register() into create() and register() functions
>>>   - Added devm_ifpga_sec_mgr_create()
>>>   - Removed typedefs for imgr ops
>>> ---
>>>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  67 +++
>>>  Documentation/fpga/ifpga-sec-mgr.rst          |  50 ++
>>>  Documentation/fpga/index.rst                  |   1 +
>>>  MAINTAINERS                                   |   9 +
>>>  drivers/fpga/Kconfig                          |   9 +
>>>  drivers/fpga/Makefile                         |   3 +
>>>  drivers/fpga/ifpga-sec-mgr.c                  | 432 ++++++++++++++++++
>>>  include/linux/fpga/ifpga-sec-mgr.h            |  81 ++++
>>>  8 files changed, 652 insertions(+)
>>>  create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>>  create mode 100644 Documentation/fpga/ifpga-sec-mgr.rst
>>>  create mode 100644 drivers/fpga/ifpga-sec-mgr.c
>>>  create mode 100644 include/linux/fpga/ifpga-sec-mgr.h
>>>
>>> diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>> b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>> new file mode 100644
>>> index 000000000000..707958971bcb
>>> --- /dev/null
>>> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>> @@ -0,0 +1,67 @@
>>> +What: /sys/class/ifpga_sec_mgr/ifpga_secX/name
>>> +Date:Oct 2020
>>> +KernelVersion:  5.11
>>> +Contact:Russ Weight <russell.h.weight@intel.com>
>>> +Description:Name of low level fpga security manager driver.
>>> +
>>> +What:
>>> /sys/class/ifpga_sec_mgr/ifpga_secX/security/sr_root_entry_hash
>>> +Date:Oct 2020
>>> +KernelVersion:  5.11
>>> +Contact:Russ Weight <russell.h.weight@intel.com>
>>> +Description:Read only. Returns the root entry hash for the static
>>> +region if one is programmed, else it returns the
>>> +string: "hash not programmed".  This file is only
>>> +visible if the underlying device supports it.
>>> +Format: "0x%x".
>>> +
>>> +What:
>>> /sys/class/ifpga_sec_mgr/ifpga_secX/security/pr_root_entry_hash
>>> +Date:Oct 2020
>>> +KernelVersion:  5.11
>>> +Contact:Russ Weight <russell.h.weight@intel.com>
>>> +Description:Read only. Returns the root entry hash for the partial
>>> +reconfiguration region if one is programmed, else it
>>> +returns the string: "hash not programmed".  This file
>>> +is only visible if the underlying device supports it.
>>> +Format: "0x%x".
>>> +
>>> +What:
>>> /sys/class/ifpga_sec_mgr/ifpga_secX/security/bmc_root_entry_hash
>>> +Date:Oct 2020
>>> +KernelVersion:  5.11
>>> +Contact:Russ Weight <russell.h.weight@intel.com>
>>> +Description:Read only. Returns the root entry hash for the BMC image
>>> +if one is programmed, else it returns the string:
>>> +"hash not programmed".  This file is only visible if the
>>> +underlying device supports it.
>>> +Format: "0x%x".
>>> +
>>> +What:
>>> /sys/class/ifpga_sec_mgr/ifpga_secX/security/sr_canceled_csks
>>> +Date:Oct 2020
>>> +KernelVersion:  5.11
>>> +Contact:Russ Weight <russell.h.weight@intel.com>
>>> +Description:Read only. Returns a list of indices for canceled code
>>> +signing keys for the static region. The standard bitmap
>>> +list format is used (e.g. "1,2-6,9").
>>> +
>>> +What:
>>> /sys/class/ifpga_sec_mgr/ifpga_secX/security/pr_canceled_csks
>>> +Date:Oct 2020
>>> +KernelVersion:  5.11
>>> +Contact:Russ Weight <russell.h.weight@intel.com>
>>> +Description:Read only. Returns a list of indices for canceled code
>>> +signing keys for the partial reconfiguration region. The
>>> +standard bitmap list format is used (e.g. "1,2-6,9").
>>> +
>>> +What:
>>> /sys/class/ifpga_sec_mgr/ifpga_secX/security/bmc_canceled_csks
>>> +Date:Oct 2020
>>> +KernelVersion:  5.11
>>> +Contact:Russ Weight <russell.h.weight@intel.com>
>>> +Description:Read only. Returns a list of indices for canceled code
>>> +signing keys for the BMC.  The standard bitmap list format
>>> +is used (e.g. "1,2-6,9").
>>> +
>>> +What:
>>> /sys/class/ifpga_sec_mgr/ifpga_secX/security/user_flash_count
>>> +Date:Oct 2020
>>> +KernelVersion:  5.11
>>> +Contact:Russ Weight <russell.h.weight@intel.com>
>>> +Description:Read only. Returns number of times the user image for the
>>> +static region has been flashed.
>>> +Format: "%u".
>>> diff --git a/Documentation/fpga/ifpga-sec-mgr.rst
>>> b/Documentation/fpga/ifpga-sec-mgr.rst
>>> new file mode 100644
>>> index 000000000000..02f3f65b182b
>>> --- /dev/null
>>> +++ b/Documentation/fpga/ifpga-sec-mgr.rst
>>> @@ -0,0 +1,50 @@
>>> +.. SPDX-License-Identifier: GPL-2.0
>>> +
>>> +========================================
>>> +Intel FPGA Security Manager Class Driver
>>> +========================================
>>> +
>>> +The Intel FPGA Security Manager class driver provides a common
>>> +API for user-space tools to manage updates for secure Intel FPGA
>>> +devices. Device drivers that instantiate the Intel Security
>>> +Manager class driver will interact with a HW secure update
>>> +engine in order to transfer new FPGA and BMC images to FLASH so
>>> +that they will be automatically loaded when the FPGA card reboots.
>>> +
>>> +A significant difference between the FPGA Manager and the Intel FPGA
>>> +Security Manager is that the FPGA Manager does a live update (Partial
>>> +Reconfiguration) to a device, whereas the Intel FPGA Security Manager
>>> +updates the FLASH images for the Static Region and the BMC so that
>>> +they will be loaded the next time the FPGA card boots. Security is
>>> +enforced by hardware and firmware. The security manager interacts
>>> +with the firmware to initiate an update, pass in the necessary data,
>>> +and collect status on the update.
>>> +
>>> +In addition to managing secure updates of the FPGA and BMC images,
>>> +the Intel FPGA Security Manager update process may also used to
>>> +program root entry hashes and cancellation keys for the FPGA static
>>> +region, the FPGA partial reconfiguration region, and the BMC.
>>> +
>>> +Secure updates make use of the request_firmware framework, which
>>> +requires that image files are accessible under /lib/firmware. A request
>>> +for a secure update returns immediately, while the update itself
>>> +proceeds in the context of a kernel worker thread. Sysfs files provide
>>> +a means for monitoring the progress of a secure update and for
>>> +retrieving error information in the event of a failure.
>>> +
>>> +Sysfs Attributes
>>> +================
>>> +
>>> +The API consists of two groups of sysfs attributes as described below.
>>> +
>>> +1. Files in the *security* sub-directory can be used to read security
>>> +   information including: Root Entry Hashes (REH), Cancelled Code
>>> +   Signing Keys (CSK), and the flash update count for FPGA images.
>>> +
>>> +2. Files in the *update* sub-directory can be used to instantiate and
>>> +   monitor a secure update.
>>> +
>>> +
>>> +See `<../ABI/testing/sysfs-class-ifpga-sec-mgr>`__ for a full
>>> +description of the sysfs attributes for the Intel FPGA Security
>>> +Manager.
>>> diff --git a/Documentation/fpga/index.rst b/Documentation/fpga/index.rst
>>> index f80f95667ca2..ba9c6b1917bd 100644
>>> --- a/Documentation/fpga/index.rst
>>> +++ b/Documentation/fpga/index.rst
>>> @@ -8,6 +8,7 @@ fpga
>>>      :maxdepth: 1
>>>
>>>      dfl
>>> +    ifpga-sec-mgr
>>>
>>>  .. only::  subproject and html
>>>
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index 6d1175bf8529..5ffc0e02d741 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -6858,6 +6858,15 @@ F:Documentation/fpga/
>>>  F:drivers/fpga/
>>>  F:include/linux/fpga/
>>>
>>> +INTEL FPGA SECURITY MANAGER DRIVERS
>>> +M:Russ Weight <russell.h.weight@intel.com>
>>> +L:linux-fpga@vger.kernel.org
>>> +S:Maintained
>>> +F:Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>> +F:Documentation/fpga/ifpga-sec-mgr.rst
>>> +F:drivers/fpga/ifpga-sec-mgr.c
>>> +F:include/linux/fpga/ifpga-sec-mgr.h
>>> +
>>>  FPU EMULATOR
>>>  M:Bill Metzenthen <billm@melbpc.org.au>
>>>  S:Maintained
>>> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
>>> index 7cd5a29fc437..bf566a625be7 100644
>>> --- a/drivers/fpga/Kconfig
>>> +++ b/drivers/fpga/Kconfig
>>> @@ -215,4 +215,13 @@ config FPGA_MGR_ZYNQMP_FPGA
>>>    to configure the programmable logic(PL) through PS
>>>    on ZynqMP SoC.
>>>
>>> +config IFPGA_SEC_MGR
>>> +tristate "Intel Security Manager for FPGA"
>>> +help
>>> +  The Intel Security Manager class driver presents a common
>>> +  user API for managing secure updates for Intel FPGA
>>> +  devices, including flash images for the FPGA static
>>> +  region and for the BMC. Select this option to enable
>>> +  updates for secure FPGA devices.
>>> +
>>>  endif # FPGA
>>> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
>>> index d8e21dfc6778..2e1d29c3d915 100644
>>> --- a/drivers/fpga/Makefile
>>> +++ b/drivers/fpga/Makefile
>>> @@ -21,6 +21,9 @@ obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)+=
>>> zynqmp-fpga.o
>>>  obj-$(CONFIG_ALTERA_PR_IP_CORE)         += altera-pr-ip-core.o
>>>  obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT)    += altera-pr-ip-core-plat.o
>>>
>>> +# Intel FPGA Security Manager Framework
>>> +obj-$(CONFIG_IFPGA_SEC_MGR)+= ifpga-sec-mgr.o
>>> +
>>>  # FPGA Bridge Drivers
>>>  obj-$(CONFIG_FPGA_BRIDGE)+= fpga-bridge.o
>>>  obj-$(CONFIG_SOCFPGA_FPGA_BRIDGE)+= altera-hps2fpga.o altera-
>>> fpga2sdram.o
>>> diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
>>> new file mode 100644
>>> index 000000000000..f1caa4602ab3
>>> --- /dev/null
>>> +++ b/drivers/fpga/ifpga-sec-mgr.c
>>> @@ -0,0 +1,432 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Intel Security Manager for FPGA
>>> + *
>>> + * Copyright (C) 2019-2020 Intel Corporation, Inc.
>>> + */
>>> +
>>> +#include <linux/fpga/ifpga-sec-mgr.h>
>>> +#include <linux/idr.h>
>>> +#include <linux/module.h>
>>> +#include <linux/slab.h>
>>> +#include <linux/vmalloc.h>
>>> +
>>> +static DEFINE_IDA(ifpga_sec_mgr_ida);
>>> +static struct class *ifpga_sec_mgr_class;
>>> +
>>> +#define to_sec_mgr(d) container_of(d, struct ifpga_sec_mgr, dev)
>>> +
>>> +static ssize_t
>>> +show_canceled_csk(struct ifpga_sec_mgr *imgr,
>>> +  int (*get_csk)(struct ifpga_sec_mgr *imgr,
>>> + unsigned long *csk_map, unsigned int nbits),
>>> +  int (*get_csk_nbits)(struct ifpga_sec_mgr *imgr),
>>> +  char *buf)
>>> +{
>>> +unsigned long *csk_map = NULL;
>>> +unsigned int nbits;
>>> +int ret;
>>> +
>>> +ret = get_csk_nbits(imgr);
>>> +if (ret < 0)
>>> +return ret;
>>> +
>>> +nbits = (unsigned int)ret;
>>> +csk_map = vmalloc(sizeof(unsigned long) * BITS_TO_LONGS(nbits));
>>> +if (!csk_map)
>>> +return -ENOMEM;
>>> +
>>> +ret = get_csk(imgr, csk_map, nbits);
>>> +if (ret)
>>> +goto vfree_exit;
>>> +
>>> +ret = bitmap_print_to_pagebuf(1, buf, csk_map, nbits);
>>> +
>>> +vfree_exit:
>>> +vfree(csk_map);
>>> +return ret;
>>> +}
>>> +
>>> +static ssize_t
>>> +show_root_entry_hash(struct ifpga_sec_mgr *imgr,
>>> +     int (*get_reh)(struct ifpga_sec_mgr *imgr, u8 *hash,
>>> +    unsigned int size),
>>> +     int (*get_reh_size)(struct ifpga_sec_mgr *imgr),
>>> +     char *buf)
>>> +{
>>> +int size, i, cnt, ret;
>>> +u8 *hash;
>>> +
>>> +ret = get_reh_size(imgr);
>>> +if (ret < 0)
>>> +return ret;
>>> +else if (!ret)
>>> +return sprintf(buf, "hash not programmed\n");
>>> +
>>> +size = ret;
>>> +hash = vmalloc(size);
>>> +if (!hash)
>>> +return -ENOMEM;
>>> +
>>> +ret = get_reh(imgr, hash, size);
>>> +if (ret)
>>> +goto vfree_exit;
>>> +
>>> +cnt = sprintf(buf, "0x");
>>> +for (i = 0; i < size; i++)
>>> +cnt += sprintf(buf + cnt, "%02x", hash[i]);
>>> +cnt += sprintf(buf + cnt, "\n");
>>> +
>>> +vfree_exit:
>>> +vfree(hash);
>>> +return ret ? : cnt;
>>> +}
>>> +
>>> +#define DEVICE_ATTR_SEC_CSK(_name) \
>>> +static ssize_t _name##_canceled_csks_show(struct device *dev, \
>>> +  struct device_attribute *attr, \
>>> +  char *buf) \
>>> +{ \
>>> +struct ifpga_sec_mgr *imgr = to_sec_mgr(dev); \
>>> +return show_canceled_csk(imgr, \
>>> +       imgr->iops->_name##_canceled_csks, \
>>> +       imgr->iops->_name##_canceled_csk_nbits, buf); \
>>> +} \
>>> +static DEVICE_ATTR_RO(_name##_canceled_csks)
>>> +
>>> +#define DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(_name) \
>>> +static ssize_t _name##_root_entry_hash_show(struct device *dev, \
>>> +     struct device_attribute *attr, \
>>> +     char *buf) \
>>> +{ \
>>> +struct ifpga_sec_mgr *imgr = to_sec_mgr(dev); \
>>> +return show_root_entry_hash(imgr, \
>>> +       imgr->iops->_name##_root_entry_hash, \
>>> +       imgr->iops->_name##_reh_size, buf); \
>>> +} \
>>> +static DEVICE_ATTR_RO(_name##_root_entry_hash)
>>> +
>>> +static ssize_t user_flash_count_show(struct device *dev,
>>> +     struct device_attribute *attr, char *buf)
>>> +{
>>> +struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
>>> +
>>> +int cnt = imgr->iops->user_flash_count(imgr);
>>> +return cnt < 0 ? cnt : sprintf(buf, "%u\n", cnt);
>>> +}
>>> +static DEVICE_ATTR_RO(user_flash_count);
>>> +
>>> +DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(sr);
>>> +DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(pr);
>>> +DEVICE_ATTR_SEC_ROOT_ENTRY_HASH(bmc);
>>> +DEVICE_ATTR_SEC_CSK(sr);
>>> +DEVICE_ATTR_SEC_CSK(pr);
>>> +DEVICE_ATTR_SEC_CSK(bmc);
>>> +
>>> +static struct attribute *sec_mgr_security_attrs[] = {
>>> +&dev_attr_user_flash_count.attr,
>>> +&dev_attr_bmc_root_entry_hash.attr,
>>> +&dev_attr_sr_root_entry_hash.attr,
>>> +&dev_attr_pr_root_entry_hash.attr,
>>> +&dev_attr_sr_canceled_csks.attr,
>>> +&dev_attr_pr_canceled_csks.attr,
>>> +&dev_attr_bmc_canceled_csks.attr,
>>> +NULL,
>>> +};
>>> +
>>> +#define check_attr(attribute, _name) \
>>> +((attribute) == &dev_attr_##_name.attr && imgr->iops->_name)
>>> +
>>> +static umode_t sec_mgr_visible(struct kobject *kobj,
>>> +       struct attribute *attr, int n)
>>> +{
>>> +struct ifpga_sec_mgr *imgr = to_sec_mgr(kobj_to_dev(kobj));
>>> +
>>> +/*
>>> + * Only display optional sysfs attributes if a
>>> + * corresponding handler is provided
>>> + */
>>> +if (check_attr(attr, user_flash_count) ||
>>> +    check_attr(attr, bmc_root_entry_hash) ||
>>> +    check_attr(attr, sr_root_entry_hash) ||
>>> +    check_attr(attr, pr_root_entry_hash) ||
>>> +    check_attr(attr, sr_canceled_csks) ||
>>> +    check_attr(attr, pr_canceled_csks) ||
>>> +    check_attr(attr, bmc_canceled_csks))
>>> +return attr->mode;
>>> +
>>> +return 0;
>>> +}
>>> +
>>> +static struct attribute_group sec_mgr_security_attr_group = {
>>> +.name = "security",
>>> +.attrs = sec_mgr_security_attrs,
>>> +.is_visible = sec_mgr_visible,
>>> +};
>>> +
>>> +static ssize_t name_show(struct device *dev,
>>> + struct device_attribute *attr, char *buf)
>>> +{
>>> +struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
>>> +
>>> +return sprintf(buf, "%s\n", imgr->name);
>>> +}
>>> +static DEVICE_ATTR_RO(name);
>>> +
>>> +static struct attribute *sec_mgr_attrs[] = {
>>> +&dev_attr_name.attr,
>>> +NULL,
>>> +};
>>> +
>>> +static struct attribute_group sec_mgr_attr_group = {
>>> +.attrs = sec_mgr_attrs,
>>> +};
>>> +
>>> +static const struct attribute_group *ifpga_sec_mgr_attr_groups[] = {
>>> +&sec_mgr_attr_group,
>>> +&sec_mgr_security_attr_group,
>>> +NULL,
>>> +};
>>> +
>>> +static bool check_sysfs_handler(struct device *dev,
>>> +void *sysfs_handler, void *size_handler,
>>> +const char *sysfs_handler_name,
>>> +const char *size_handler_name)
>>> +{
>>> +/*
>>> + * sysfs_handler and size_handler must either both be
>>> + * defined or both be NULL.
>>> + */
>>> +if (sysfs_handler) {
>>> +if (!size_handler) {
>>> +dev_err(dev, "%s registered without %s\n",
>>> +sysfs_handler_name, size_handler_name);
>>> +return false;
>>> +}
>>> +} else if (size_handler) {
>>> +dev_err(dev, "%s registered without %s\n",
>>> +size_handler_name, sysfs_handler_name);
>>> +return false;
>>> +}
>> Optional:
>>
>> If (sysfs_handler && !size_handler) {
>>
>> } else if (!sysfs_handler && size_handler) {
>>
>> }
> Yes, I can code it that way. It would be more readable.
>>> +return true;
>>> +}
>>> +
>>> +#define check_reh_handler(_dev, _iops, _name) \
>>> +check_sysfs_handler(_dev, (_iops)->_name##_root_entry_hash, \
>>> +    (_iops)->_name##_reh_size, \
>>> +    __stringify(_name##_root_entry_hash), \
>>> +    __stringify(_name##_reh_size))
>>> +
>>> +#define check_csk_handler(_dev, _iops, _name) \
>>> +check_sysfs_handler(_dev, (_iops)->_name##_canceled_csks, \
>>> +    (_iops)->_name##_canceled_csk_nbits, \
>>> +    __stringify(_name##_canceled_csks), \
>>> +    __stringify(_name##_canceled_csk_nbits))
>>> +
>>> +/**
>>> + * ifpga_sec_mgr_create - create and initialize an Intel FPGA
>>> + *  security manager struct
>>> + *
>>> + * @dev:  Intel fpga security manager device from pdev
>>> + * @name: ifpga security manager name
>>> + * @iops: pointer to a structure of ifpga callback functions
>>> + * @priv: ifpga security manager private data
>>> + *
>>> + * The caller of this function is responsible for freeing the struct
>>> + * with ifpg_sec_mgr_free(). Using devm_ifpga_sec_mgr_create() instead
>>> + * is recommended.
>>> + *
>>> + * Return: pointer to struct ifpga_sec_mgr or NULL
>>> + */
>>> +struct ifpga_sec_mgr *
>>> +ifpga_sec_mgr_create(struct device *dev, const char *name,
>>> +     const struct ifpga_sec_mgr_ops *iops, void *priv)
>>> +{
>>> +struct ifpga_sec_mgr *imgr;
>>> +int id, ret;
>>> +
>>> +if (!check_reh_handler(dev, iops, bmc) ||
>>> +    !check_reh_handler(dev, iops, sr) ||
>>> +    !check_reh_handler(dev, iops, pr) ||
>>> +    !check_csk_handler(dev, iops, bmc) ||
>>> +    !check_csk_handler(dev, iops, sr) ||
>>> +    !check_csk_handler(dev, iops, pr)) {
>>> +return NULL;
>>> +}
>>> +
>>> +if (!name || !strlen(name)) {
>>> +dev_err(dev, "Attempt to register with no name!\n");
>>> +return NULL;
>>> +}
>>> +
>>> +imgr = kzalloc(sizeof(*imgr), GFP_KERNEL);
>>> +if (!imgr)
>>> +return NULL;
>>> +
>>> +id = ida_simple_get(&ifpga_sec_mgr_ida, 0, 0, GFP_KERNEL);
>>> +if (id < 0)
>>> +goto error_kfree;
>>> +
>>> +mutex_init(&imgr->lock);
>>> +
>>> +imgr->name = name;
>>> +imgr->priv = priv;
>>> +imgr->iops = iops;
>>> +
>>> +device_initialize(&imgr->dev);
>>> +imgr->dev.class = ifpga_sec_mgr_class;
>>> +imgr->dev.parent = dev;
>>> +imgr->dev.id = id;
>>> +
>>> +ret = dev_set_name(&imgr->dev, "ifpga_sec%d", id);
>>> +if (ret) {
>>> +dev_err(dev, "Failed to set device name: ifpga_sec%d\n", id);
>>> +goto error_device;
>>> +}
>>> +
>>> +return imgr;
>>> +
>>> +error_device:
>>> +ida_simple_remove(&ifpga_sec_mgr_ida, id);
>>> +
>>> +error_kfree:
>>> +kfree(imgr);
>>> +
>>> +return NULL;
>>> +}
>>> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_create);
>>> +
>>> +/**
>>> + * ifpga_sec_mgr_free - free an Intel FPGA security manager created
>>> + *with ifpga_sec_mgr_create()
>>> + *
>>> + * @imgr:Intel FPGA security manager structure
>>> + */
>>> +void ifpga_sec_mgr_free(struct ifpga_sec_mgr *imgr)
>>> +{
>>> +ida_simple_remove(&ifpga_sec_mgr_ida, imgr->dev.id);
>>> +kfree(imgr);
>>> +}
>>> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_free);
>>> +
>>> +static void devm_ifpga_sec_mgr_release(struct device *dev, void *res)
>>> +{
>>> +struct ifpga_sec_mgr *imgr = *(struct ifpga_sec_mgr **)res;
>>> +
>>> +ifpga_sec_mgr_free(imgr);
>>> +}
>>> +
>>> +/**
>>> + * devm_ifpga_sec_mgr_create - create and initialize an Intel FPGA
>>> + *       security manager struct
>>> + *
>>> + * @dev:  Intel fpga security manager device from pdev
>>> + * @name: ifpga security manager name
>>> + * @iops: pointer to a structure of ifpga callback functions
>>> + * @priv: ifpga security manager private data
>>> + *
>>> + * This function is intended for use in a Intel FPGA Security manager
>>> + * driver's probe function.  After the security manager driver creates
>>> + * the ifpga_sec_mgr struct with devm_fpga_mgr_create(), it should
>>> + * register it with ifpga_sec_mgr_register().  The security manager
>>> + * driver's remove function should call ifpga_sec_mgr_unregister().
>>> + * The ifpga_sec_mgr struct allocated with this function will be freed
>>> + * automatically on driver detach.  This includes the case of a probe
>>> + * function returning error before calling fpga_mgr_register(), the
>>> + * struct will still get cleaned up.
>>> + *
>>> + * Return: pointer to struct ifpga_sec_mgr or NULL
>>> + */
>>> +struct ifpga_sec_mgr *
>>> +devm_ifpga_sec_mgr_create(struct device *dev, const char *name,
>>> +  const struct ifpga_sec_mgr_ops *iops, void *priv)
>>> +{
>>> +struct ifpga_sec_mgr **ptr, *imgr;
>>> +
>>> +ptr = devres_alloc(devm_ifpga_sec_mgr_release, sizeof(*ptr),
>>> GFP_KERNEL);
>>> +if (!ptr)
>>> +return NULL;
>>> +
>>> +imgr = ifpga_sec_mgr_create(dev, name, iops, priv);
>>> +if (!imgr) {
>>> +devres_free(ptr);
>>> +} else {
>>> +*ptr = imgr;
>>> +devres_add(dev, ptr);
>>> +}
>>> +
>>> +return imgr;
>>> +}
>>> +EXPORT_SYMBOL_GPL(devm_ifpga_sec_mgr_create);
>>> +
>>> +/**
>>> + * ifpga_sec_mgr_register - register an Intel FPGA security manager
>>> + *
>>> + * @imgr: Intel fpga security manager struct
>>> + *
>>> + * Return: 0 on success, negative error code otherwise.
>>> + */
>>> +int ifpga_sec_mgr_register(struct ifpga_sec_mgr *imgr)
>>> +{
>>> +int ret;
>>> +
>>> +ret = device_add(&imgr->dev);
>>> +if (ret)
>>> +goto error_device;
>>> +
>>> +dev_info(&imgr->dev, "%s registered\n", imgr->name);
>>> +
>>> +return 0;
>>> +
>>> +error_device:
>>> +ida_simple_remove(&ifpga_sec_mgr_ida, imgr->dev.id);
>>> +
>>> +return ret;
>>> +}
>>> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_register);
>>> +
>>> +/**
>>> + * ifpga_sec_mgr_unregister - unregister an Intel FPGA security manager
>>> + *
>>> + * @mgr: fpga manager struct
>>> + *
>>> + * This function is intended for use in an Intel FPGA security manager
>>> + * driver's remove() function.
>>> + */
>>> +void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr)
>>> +{
>>> +dev_info(&imgr->dev, "%s %s\n", __func__, imgr->name);
>>> +
>>> +device_unregister(&imgr->dev);
>>> +}
>>> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_unregister);
>>> +
>>> +static void ifpga_sec_mgr_dev_release(struct device *dev)
>>> +{
>>> +}
>>> +
>>> +static int __init ifpga_sec_mgr_class_init(void)
>>> +{
>>> +pr_info("Intel FPGA Security Manager\n");
>>> +
>>> +ifpga_sec_mgr_class = class_create(THIS_MODULE, "ifpga_sec_mgr");
>>> +if (IS_ERR(ifpga_sec_mgr_class))
>>> +return PTR_ERR(ifpga_sec_mgr_class);
>>> +
>>> +ifpga_sec_mgr_class->dev_groups = ifpga_sec_mgr_attr_groups;
>>> +ifpga_sec_mgr_class->dev_release = ifpga_sec_mgr_dev_release;
>>> +
>>> +return 0;
>>> +}
>>> +
>>> +static void __exit ifpga_sec_mgr_class_exit(void)
>>> +{
>>> +class_destroy(ifpga_sec_mgr_class);
>>> +ida_destroy(&ifpga_sec_mgr_ida);
>>> +}
>>> +
>>> +MODULE_DESCRIPTION("Intel FPGA Security Manager Driver");
>>> +MODULE_LICENSE("GPL v2");
>>> +
>>> +subsys_initcall(ifpga_sec_mgr_class_init);
>>> +module_exit(ifpga_sec_mgr_class_exit)
>>> diff --git a/include/linux/fpga/ifpga-sec-mgr.h b/include/linux/fpga/ifpga-
>>> sec-mgr.h
>>> new file mode 100644
>>> index 000000000000..ded62090e9b9
>>> --- /dev/null
>>> +++ b/include/linux/fpga/ifpga-sec-mgr.h
>>> @@ -0,0 +1,81 @@
>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>> +/*
>>> + * Header file for Intel FPGA Security Manager
>>> + *
>>> + * Copyright (C) 2019-2020 Intel Corporation, Inc.
>>> + */
>>> +#ifndef _LINUX_IFPGA_SEC_MGR_H
>>> +#define _LINUX_IFPGA_SEC_MGR_H
>>> +
>>> +#include <linux/device.h>
>>> +#include <linux/mutex.h>
>>> +#include <linux/types.h>
>>> +
>>> +struct ifpga_sec_mgr;
>>> +
>>> +/**
>>> + * struct ifpga_sec_mgr_ops - device specific operations
>>> + * @user_flash_count:    Optional: Return sysfs string output for
>>> FPGA
>>> + *    image flash count
>>> + * @sr_root_entry_hash:    Optional: Return sysfs string output for
>>> static
>>> + *    region root entry hash
>>> + * @pr_root_entry_hash:    Optional: Return sysfs string output for
>>> partial
>>> + *    reconfiguration root entry hash
>>> + * @bmc_root_entry_hash:    Optional: Return sysfs string output for BMC
>>> + *    root entry hash
>>> + * @sr_canceled_csks:    Optional: Return sysfs string output for static
>>> + *    region canceled keys
>>> + * @pr_canceled_csks:    Optional: Return sysfs string output for
>>> partial
>>> + *    reconfiguration canceled keys
>>> + * @bmc_canceled_csks:    Optional: Return sysfs string output for
>>> bmc
>>> + *    canceled keys
>>> + * @bmc_canceled_csk_nbits: Optional: Return BMC canceled csk vector bit
>>> count
>>> + * @sr_canceled_csk_nbits:  Optional: Return SR canceled csk vector bit
>>> count
>>> + * @pr_canceled_csk_nbits:  Optional: Return PR canceled csk vector bit
>>> count
>>> + * @bmc_reh_size:    Optional: Return byte size for BMC root entry hash
>>> + * @sr_reh_size:    Optional: Return byte size for SR root entry hash
>>> + * @pr_reh_size:    Optional: Return byte size for PR root entry hash
>>> + */
>>> +struct ifpga_sec_mgr_ops {
>>> +int (*user_flash_count)(struct ifpga_sec_mgr *imgr);
>>> +int (*bmc_root_entry_hash)(struct ifpga_sec_mgr *imgr, u8 *hash,
>>> +   unsigned int size);
>>> +int (*sr_root_entry_hash)(struct ifpga_sec_mgr *imgr, u8 *hash,
>>> +  unsigned int size);
>>> +int (*pr_root_entry_hash)(struct ifpga_sec_mgr *imgr, u8 *hash,
>>> +  unsigned int size);
>>> +int (*bmc_canceled_csks)(struct ifpga_sec_mgr *imgr,
>>> + unsigned long *csk_map, unsigned int nbits);
>>> +int (*sr_canceled_csks)(struct ifpga_sec_mgr *imgr,
>>> +unsigned long *csk_map, unsigned int nbits);
>>> +int (*pr_canceled_csks)(struct ifpga_sec_mgr *imgr,
>>> +unsigned long *csk_map, unsigned int nbits);
>>> +int (*bmc_reh_size)(struct ifpga_sec_mgr *imgr);
>>> +int (*sr_reh_size)(struct ifpga_sec_mgr *imgr);
>>> +int (*pr_reh_size)(struct ifpga_sec_mgr *imgr);
>>> +int (*bmc_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
>>> +int (*sr_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
>>> +int (*pr_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
>> I am thinking that if these callbacks for size are really needed or not.
>> If these size values are not changed dynamically, which requires no
>> recalculation, then these size values can be stored in ifpga sec mgr
>> data structure directly. I think the checking logic could be simpler too.
>> Do you think if it is possible?
> Yes - it is possible. The size could be calculated before creating the security
> manager. It just means that the iops data structure has to be dynamically created.
> As it turns out, we need to do that (eventually) anyway to handle some differences
> between the n3000 and the d5005 devices, so I can code up the changes and see
> how it looks.
Actually - I remember now why we did it this way. If a root entry hash is not
programmed, the then size of the hash (which is read from FLASH) is zero. Once a
root entry has is programmed, then the size becomes non-zero. So, for root entry
hashes, the size can change after the driver has loaded. So I think we need to
leave it this way.

>> Thanks
>> Hao
>>
>>> +};
>>> +
>>> +struct ifpga_sec_mgr {
>>> +const char *name;
>>> +struct device dev;
>>> +const struct ifpga_sec_mgr_ops *iops;
>>> +struct mutex lock;/* protect data structure contents */
>>> +void *priv;
>>> +};
>>> +
>>> +struct ifpga_sec_mgr *
>>> +ifpga_sec_mgr_create(struct device *dev, const char *name,
>>> +     const struct ifpga_sec_mgr_ops *iops, void *priv);
>>> +
>>> +struct ifpga_sec_mgr *
>>> +devm_ifpga_sec_mgr_create(struct device *dev, const char *name,
>>> +  const struct ifpga_sec_mgr_ops *iops, void *priv);
>>> +
>>> +int ifpga_sec_mgr_register(struct ifpga_sec_mgr *imgr);
>>> +void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr);
>>> +void ifpga_sec_mgr_free(struct ifpga_sec_mgr *imgr);
>>> +
>>> +#endif
>>> --
>>> 2.17.1


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 2/7] fpga: sec-mgr: enable secure updates
  2020-10-05  8:19   ` Wu, Hao
@ 2020-10-06 18:55     ` Russ Weight
  0 siblings, 0 replies; 25+ messages in thread
From: Russ Weight @ 2020-10-06 18:55 UTC (permalink / raw)
  To: Wu, Hao, mdf, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, Xu, Yilun, Gerlach, Matthew



On 10/5/20 1:19 AM, Wu, Hao wrote:
>> -----Original Message-----
>> From: Russ Weight <russell.h.weight@intel.com>
>> Sent: Saturday, October 3, 2020 6:37 AM
>> To: mdf@kernel.org; linux-fpga@vger.kernel.org; linux-
>> kernel@vger.kernel.org
>> Cc: trix@redhat.com; lgoncalv@redhat.com; Xu, Yilun <yilun.xu@intel.com>;
>> Wu, Hao <hao.wu@intel.com>; Gerlach, Matthew
>> <matthew.gerlach@intel.com>; Weight, Russell H
>> <russell.h.weight@intel.com>
>> Subject: [PATCH v2 2/7] fpga: sec-mgr: enable secure updates
>>
>> Extend the FPGA Intel Security Manager class driver to
>> include an update/filename sysfs node that can be used
>> to initiate a security update.  The filename of a secure
>> update file (BMC image, FPGA image, Root Entry Hash image,
>> or Code Signing Key cancellation image) can be written to
>> this sysfs entry to cause a secure update to occur.
>>
>> The write of the filename will return immediately, and the
>> update will begin in the context of a kernel worker thread.
>> This tool utilizes the request_firmware framework, which
>> requires that the image file reside under /lib/firmware.
>>
>> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
>> ---
>> v2:
>>   - Bumped documentation date and version
>>   - Removed explicit value assignments in enums
>>   - Other minor code cleanup per review comments
>> ---
>>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  13 ++
>>  drivers/fpga/ifpga-sec-mgr.c                  | 157 ++++++++++++++++++
>>  include/linux/fpga/ifpga-sec-mgr.h            |  49 ++++++
>>  3 files changed, 219 insertions(+)
>>
>> diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> index 707958971bcb..4f375f132c34 100644
>> --- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> @@ -65,3 +65,16 @@ Contact:Russ Weight <russell.h.weight@intel.com>
>>  Description:Read only. Returns number of times the user image for the
>>  static region has been flashed.
>>  Format: "%u".
>> +
>> +What:
>> /sys/class/ifpga_sec_mgr/ifpga_secX/update/filename
>> +Date:Oct 2020
>> +KernelVersion:  5.11
>> +Contact:Russ Weight <russell.h.weight@intel.com>
>> +Description:Write only. Write the filename of an Intel image
>> +file to this sysfs file to initiate a secure
>> +update. The file must have an appropriate header
>> +which, among other things, identifies the target
>> +for the update. This mechanism is used to update
>> +BMC images, BMC firmware, Static Region images,
>> +and Root Entry Hashes, and to cancel Code Signing
>> +Keys (CSK).
>> diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
>> index f1caa4602ab3..7d5a4979554b 100644
>> --- a/drivers/fpga/ifpga-sec-mgr.c
>> +++ b/drivers/fpga/ifpga-sec-mgr.c
>> @@ -5,8 +5,11 @@
>>   * Copyright (C) 2019-2020 Intel Corporation, Inc.
>>   */
>>
>> +#include <linux/delay.h>
>> +#include <linux/firmware.h>
>>  #include <linux/fpga/ifpga-sec-mgr.h>
>>  #include <linux/idr.h>
>> +#include <linux/kernel.h>
>>  #include <linux/module.h>
>>  #include <linux/slab.h>
>>  #include <linux/vmalloc.h>
>> @@ -14,6 +17,8 @@
>>  static DEFINE_IDA(ifpga_sec_mgr_ida);
>>  static struct class *ifpga_sec_mgr_class;
>>
>> +#define WRITE_BLOCK_SIZE0x4000
> Maybe some comments here for this value or should this be a parameter
> of ifpga sec mgr, provided from low level driver during initialization?
I'll add a comment. The only purpose of WRITE_BLOCK_SIZE is to ensure
that the remaining_size gets updated at regular intervals to show progress
during the writing phase.
>
>> +
>>  #define to_sec_mgr(d) container_of(d, struct ifpga_sec_mgr, dev)
>>
>>  static ssize_t
>> @@ -134,6 +139,96 @@ static struct attribute *sec_mgr_security_attrs[] = {
>>  NULL,
>>  };
>>
>> +static void ifpga_sec_dev_error(struct ifpga_sec_mgr *imgr,
>> +enum ifpga_sec_err err_code)
>> +{
>> +imgr->err_code = err_code;
>> +imgr->iops->cancel(imgr);
>> +}
>> +
>> +static void progress_complete(struct ifpga_sec_mgr *imgr)
>> +{
>> +mutex_lock(&imgr->lock);
>> +imgr->progress = IFPGA_SEC_PROG_IDLE;
>> +complete_all(&imgr->update_done);
>> +mutex_unlock(&imgr->lock);
>> +}
>> +
>> +static void ifpga_sec_mgr_update(struct work_struct *work)
>> +{
>> +u32 size, blk_size, offset = 0;
>> +struct ifpga_sec_mgr *imgr;
>> +const struct firmware *fw;
>> +enum ifpga_sec_err ret;
>> +
>> +imgr = container_of(work, struct ifpga_sec_mgr, work);
>> +
>> +get_device(&imgr->dev);
>> +if (request_firmware(&fw, imgr->filename, &imgr->dev)) {
>> +imgr->err_code = IFPGA_SEC_ERR_FILE_READ;
>> +goto idle_exit;
>> +}
>> +
>> +imgr->data = fw->data;
>> +imgr->remaining_size = fw->size;
>> +
>> +if (!try_module_get(imgr->dev.parent->driver->owner)) {
>> +imgr->err_code = IFPGA_SEC_ERR_BUSY;
>> +goto release_fw_exit;
>> +}
>> +
>> +imgr->progress = IFPGA_SEC_PROG_PREPARING;
>> +ret = imgr->iops->prepare(imgr);
>> +if (ret) {
>> +ifpga_sec_dev_error(imgr, ret);
>> +goto modput_exit;
>> +}
>> +
>> +imgr->progress = IFPGA_SEC_PROG_WRITING;
>> +size = imgr->remaining_size;
>> +while (size) {
>> +blk_size = min_t(u32, size, WRITE_BLOCK_SIZE);
>> +size -= blk_size;
>> +ret = imgr->iops->write_blk(imgr, offset, blk_size);
>> +if (ret) {
>> +ifpga_sec_dev_error(imgr, ret);
>> +goto done;
>> +}
>> +
>> +imgr->remaining_size = size;
>> +offset += blk_size;
>> +}
> Looks like we can remove size and just use remaining_size here?
We could, but it would change the meaning of remaining size a little bit.
Currently, remaining size represents the number bytes that are confirmed
to be written to the flash. If we eliminate size, then we would be updating
remaining_size before the next block of bytes are written.

What do you think? Is it worth making a change here?
>
>> +
>> +imgr->progress = IFPGA_SEC_PROG_PROGRAMMING;
>> +ret = imgr->iops->poll_complete(imgr);
>> +if (ret) {
>> +ifpga_sec_dev_error(imgr, ret);
>> +goto done;
> Looks like no need for this goto done.
Yes - I'll remove it.
>
>> +}
>> +
>> +done:
>> +if (imgr->iops->cleanup)
>> +imgr->iops->cleanup(imgr);
>> +
>> +modput_exit:
>> +module_put(imgr->dev.parent->driver->owner);
>> +
>> +release_fw_exit:
>> +imgr->data = NULL;
>> +release_firmware(fw);
>> +
>> +idle_exit:
>> +/*
>> + * Note: imgr->remaining_size is left unmodified here to
>> + * provide additional information on errors. It will be
>> + * reinitialized when the next secure update begins.
>> + */
>> +kfree(imgr->filename);
>> +imgr->filename = NULL;
>> +put_device(&imgr->dev);
>> +progress_complete(imgr);
> Should it call this function progress complete even in failure case?
> A little confusing.
Yes - this function returns us to the idle state and signals a completion
structure for waiting threads. Do you think a name change is needed? Any
suggestions? progress_done?
>
>> +}
>> +
>>  #define check_attr(attribute, _name) \
>>  ((attribute) == &dev_attr_##_name.attr && imgr->iops->_name)
>>
>> @@ -164,6 +259,48 @@ static struct attribute_group
>> sec_mgr_security_attr_group = {
>>  .is_visible = sec_mgr_visible,
>>  };
>>
>> +static ssize_t filename_store(struct device *dev, struct device_attribute *attr,
>> +      const char *buf, size_t count)
>> +{
>> +struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
>> +int ret = count;
>> +
>> +if (count == 0 || count >= PATH_MAX)
>> +return -EINVAL;
>> +
>> +mutex_lock(&imgr->lock);
>> +if (imgr->driver_unload || imgr->progress != IFPGA_SEC_PROG_IDLE)
>> {
>> +ret = -EBUSY;
>> +goto unlock_exit;
>> +}
>> +
>> +imgr->filename = kstrndup(buf, count - 1, GFP_KERNEL);
>> +if (!imgr->filename) {
>> +ret = -ENOMEM;
>> +goto unlock_exit;
>> +}
>> +
>> +imgr->err_code = IFPGA_SEC_ERR_NONE;
>> +imgr->progress = IFPGA_SEC_PROG_READING;
>> +reinit_completion(&imgr->update_done);
>> +schedule_work(&imgr->work);
>> +
>> +unlock_exit:
>> +mutex_unlock(&imgr->lock);
>> +return ret;
>> +}
>> +static DEVICE_ATTR_WO(filename);
>> +
>> +static struct attribute *sec_mgr_update_attrs[] = {
>> +&dev_attr_filename.attr,
>> +NULL,
>> +};
>> +
>> +static struct attribute_group sec_mgr_update_attr_group = {
>> +.name = "update",
>> +.attrs = sec_mgr_update_attrs,
>> +};
>> +
>>  static ssize_t name_show(struct device *dev,
>>   struct device_attribute *attr, char *buf)
>>  {
>> @@ -185,6 +322,7 @@ static struct attribute_group sec_mgr_attr_group = {
>>  static const struct attribute_group *ifpga_sec_mgr_attr_groups[] = {
>>  &sec_mgr_attr_group,
>>  &sec_mgr_security_attr_group,
>> +&sec_mgr_update_attr_group,
>>  NULL,
>>  };
>>
>> @@ -245,6 +383,12 @@ ifpga_sec_mgr_create(struct device *dev, const char
>> *name,
>>  struct ifpga_sec_mgr *imgr;
>>  int id, ret;
>>
>> +if (!iops || !iops->cancel || !iops->prepare ||
>> +    !iops->write_blk || !iops->poll_complete) {
>> +dev_err(dev, "Attempt to register without required ops\n");
>> +return NULL;
>> +}
>> +
>>  if (!check_reh_handler(dev, iops, bmc) ||
>>      !check_reh_handler(dev, iops, sr) ||
>>      !check_reh_handler(dev, iops, pr) ||
>> @@ -272,6 +416,8 @@ ifpga_sec_mgr_create(struct device *dev, const char
>> *name,
>>  imgr->name = name;
>>  imgr->priv = priv;
>>  imgr->iops = iops;
>> +init_completion(&imgr->update_done);
>> +INIT_WORK(&imgr->work, ifpga_sec_mgr_update);
>>
>>  device_initialize(&imgr->dev);
>>  imgr->dev.class = ifpga_sec_mgr_class;
>> @@ -397,6 +543,17 @@ void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr
>> *imgr)
>>  {
>>  dev_info(&imgr->dev, "%s %s\n", __func__, imgr->name);
>>
>> +mutex_lock(&imgr->lock);
>> +imgr->driver_unload = true;
> May need some comments here, do you mean get module doesn't work here
> to prevent unexpected driver unloading? Or you mean parent device maybe
> hot unplug in some cases?
The driver_unload flag is used to:
(1) prevent another update from startingwhile waiting to unregister
(2) signal the parent driver that the driver is being unloaded/unbound.

Generally, the driver cannot be interrupted (CTRL-C) once the authentication
begins, which can take 30+ minutes to complete. The driver_unload flag signals
the parent driver to abort if someone is trying to unload/unbind the driver.

Without this flag, "modprobe -r" could hang for 30 minutes or more.

Does this seem like a reasonable way to handle it?

I'll add comments to this function.
>
> Thanks
> Hao
>
>> +if (imgr->progress == IFPGA_SEC_PROG_IDLE) {
>> +mutex_unlock(&imgr->lock);
>> +goto unregister;
>> +}
>> +
>> +mutex_unlock(&imgr->lock);
>> +wait_for_completion(&imgr->update_done);
>> +
>> +unregister:
>>  device_unregister(&imgr->dev);
>>  }
>>  EXPORT_SYMBOL_GPL(ifpga_sec_mgr_unregister);
>> diff --git a/include/linux/fpga/ifpga-sec-mgr.h b/include/linux/fpga/ifpga-
>> sec-mgr.h
>> index ded62090e9b9..27008abd8e75 100644
>> --- a/include/linux/fpga/ifpga-sec-mgr.h
>> +++ b/include/linux/fpga/ifpga-sec-mgr.h
>> @@ -7,12 +7,26 @@
>>  #ifndef _LINUX_IFPGA_SEC_MGR_H
>>  #define _LINUX_IFPGA_SEC_MGR_H
>>
>> +#include <linux/completion.h>
>>  #include <linux/device.h>
>>  #include <linux/mutex.h>
>>  #include <linux/types.h>
>>
>>  struct ifpga_sec_mgr;
>>
>> +enum ifpga_sec_err {
>> +IFPGA_SEC_ERR_NONE,
>> +IFPGA_SEC_ERR_HW_ERROR,
>> +IFPGA_SEC_ERR_TIMEOUT,
>> +IFPGA_SEC_ERR_CANCELED,
>> +IFPGA_SEC_ERR_BUSY,
>> +IFPGA_SEC_ERR_INVALID_SIZE,
>> +IFPGA_SEC_ERR_RW_ERROR,
>> +IFPGA_SEC_ERR_WEAROUT,
>> +IFPGA_SEC_ERR_FILE_READ,
>> +IFPGA_SEC_ERR_MAX
>> +};
>> +
>>  /**
>>   * struct ifpga_sec_mgr_ops - device specific operations
>>   * @user_flash_count:    Optional: Return sysfs string output for FPGA
>> @@ -35,6 +49,17 @@ struct ifpga_sec_mgr;
>>   * @bmc_reh_size:    Optional: Return byte size for BMC root entry hash
>>   * @sr_reh_size:    Optional: Return byte size for SR root entry hash
>>   * @pr_reh_size:    Optional: Return byte size for PR root entry hash
>> + * @prepare:    Required: Prepare secure update
>> + * @write_blk:    Required: Write a block of data
>> + * @poll_complete:    Required: Check for the completion of the
>> + *    HW authentication/programming process. This
>> + *    function should check for imgr->driver_unload
>> + *    and abort with IFPGA_SEC_ERR_CANCELED when
>> true.
>> + * @cancel:    Required: Signal HW to cancel update
>> + * @cleanup:    Optional: Complements the prepare()
>> + *    function and is called at the completion
>> + *    of the update, whether success or failure,
>> + *    if the prepare function succeeded.
>>   */
>>  struct ifpga_sec_mgr_ops {
>>  int (*user_flash_count)(struct ifpga_sec_mgr *imgr);
>> @@ -56,6 +81,22 @@ struct ifpga_sec_mgr_ops {
>>  int (*bmc_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
>>  int (*sr_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
>>  int (*pr_canceled_csk_nbits)(struct ifpga_sec_mgr *imgr);
>> +enum ifpga_sec_err (*prepare)(struct ifpga_sec_mgr *imgr);
>> +enum ifpga_sec_err (*write_blk)(struct ifpga_sec_mgr *imgr,
>> +u32 offset, u32 size);
>> +enum ifpga_sec_err (*poll_complete)(struct ifpga_sec_mgr *imgr);
>> +void (*cleanup)(struct ifpga_sec_mgr *imgr);
>> +enum ifpga_sec_err (*cancel)(struct ifpga_sec_mgr *imgr);
>> +};
>> +
>> +/* Update progress codes */
>> +enum ifpga_sec_prog {
>> +IFPGA_SEC_PROG_IDLE,
>> +IFPGA_SEC_PROG_READING,
>> +IFPGA_SEC_PROG_PREPARING,
>> +IFPGA_SEC_PROG_WRITING,
>> +IFPGA_SEC_PROG_PROGRAMMING,
>> +IFPGA_SEC_PROG_MAX
>>  };
>>
>>  struct ifpga_sec_mgr {
>> @@ -63,6 +104,14 @@ struct ifpga_sec_mgr {
>>  struct device dev;
>>  const struct ifpga_sec_mgr_ops *iops;
>>  struct mutex lock;/* protect data structure contents */
>> +struct work_struct work;
>> +struct completion update_done;
>> +char *filename;
>> +const u8 *data;/* pointer to update data */
>> +u32 remaining_size;/* size remaining to transfer */
>> +enum ifpga_sec_prog progress;
>> +enum ifpga_sec_err err_code;/* security manager error code */
>> +bool driver_unload;
>>  void *priv;
>>  };
>>
>> --
>> 2.17.1


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 3/7] fpga: sec-mgr: expose sec-mgr update status
  2020-10-05  8:41   ` Wu, Hao
@ 2020-10-06 19:46     ` Russ Weight
  0 siblings, 0 replies; 25+ messages in thread
From: Russ Weight @ 2020-10-06 19:46 UTC (permalink / raw)
  To: Wu, Hao, mdf, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, Xu, Yilun, Gerlach, Matthew



On 10/5/20 1:41 AM, Wu, Hao wrote:
>> Subject: [PATCH v2 3/7] fpga: sec-mgr: expose sec-mgr update status
>>
>> Extend the Intel Security Manager class driver to
>> include an update/status sysfs node that can be polled
>> and read to monitor the progress of an ongoing secure
>> update. Sysfs_notify() is used to signal transitions
>> between different phases of the update process.
>>
>> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
>> ---
>> v2:
>>   - Bumped documentation date and version
>>   - Changed progress state "read_file" to "reading"
>> ---
>>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 11 +++++
>>  drivers/fpga/ifpga-sec-mgr.c                  | 40 +++++++++++++++++--
>>  2 files changed, 47 insertions(+), 4 deletions(-)
>>
>> diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> index 4f375f132c34..73a5246fea1b 100644
>> --- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> @@ -78,3 +78,14 @@ Description:Write only. Write the filename of an
>> Intel image
>>  BMC images, BMC firmware, Static Region images,
>>  and Root Entry Hashes, and to cancel Code Signing
>>  Keys (CSK).
>> +
>> +What: /sys/class/ifpga_sec_mgr/ifpga_secX/update/status
>> +Date:Oct 2020
>> +KernelVersion:  5.11
>> +Contact:Russ Weight <russell.h.weight@intel.com>
>> +Description:Read-only. Returns a string describing the current
>> +status of an update. The string will be one of the
>> +following: idle, reading, preparing, writing,
>> +programming. Userspace code can poll on this file,
>> +as it will be signaled by sysfs_notify() on each
>> +state change.
>> diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
>> index 7d5a4979554b..ad918fb42dc2 100644
>> --- a/drivers/fpga/ifpga-sec-mgr.c
>> +++ b/drivers/fpga/ifpga-sec-mgr.c
>> @@ -139,6 +139,13 @@ static struct attribute *sec_mgr_security_attrs[] = {
>>  NULL,
>>  };
>>
>> +static void update_progress(struct ifpga_sec_mgr *imgr,
>> +    enum ifpga_sec_prog new_progress)
>> +{
>> +imgr->progress = new_progress;
>> +sysfs_notify(&imgr->dev.kobj, "update", "status");
>> +}
>> +
>>  static void ifpga_sec_dev_error(struct ifpga_sec_mgr *imgr,
>>  enum ifpga_sec_err err_code)
>>  {
>> @@ -149,7 +156,7 @@ static void ifpga_sec_dev_error(struct ifpga_sec_mgr
>> *imgr,
>>  static void progress_complete(struct ifpga_sec_mgr *imgr)
>>  {
>>  mutex_lock(&imgr->lock);
>> -imgr->progress = IFPGA_SEC_PROG_IDLE;
>> +update_progress(imgr, IFPGA_SEC_PROG_IDLE);
>>  complete_all(&imgr->update_done);
>>  mutex_unlock(&imgr->lock);
>>  }
>> @@ -177,14 +184,14 @@ static void ifpga_sec_mgr_update(struct
>> work_struct *work)
>>  goto release_fw_exit;
>>  }
>>
>> -imgr->progress = IFPGA_SEC_PROG_PREPARING;
>> +update_progress(imgr, IFPGA_SEC_PROG_PREPARING);
>>  ret = imgr->iops->prepare(imgr);
>>  if (ret) {
>>  ifpga_sec_dev_error(imgr, ret);
>>  goto modput_exit;
>>  }
>>
>> -imgr->progress = IFPGA_SEC_PROG_WRITING;
>> +update_progress(imgr, IFPGA_SEC_PROG_WRITING);
>>  size = imgr->remaining_size;
>>  while (size) {
>>  blk_size = min_t(u32, size, WRITE_BLOCK_SIZE);
>> @@ -199,7 +206,7 @@ static void ifpga_sec_mgr_update(struct work_struct
>> *work)
>>  offset += blk_size;
>>  }
>>
>> -imgr->progress = IFPGA_SEC_PROG_PROGRAMMING;
>> +update_progress(imgr, IFPGA_SEC_PROG_PROGRAMMING);
>>  ret = imgr->iops->poll_complete(imgr);
>>  if (ret) {
>>  ifpga_sec_dev_error(imgr, ret);
>> @@ -259,6 +266,30 @@ static struct attribute_group
>> sec_mgr_security_attr_group = {
>>  .is_visible = sec_mgr_visible,
>>  };
>>
>> +static const char * const sec_mgr_prog_str[] = {
>> +"idle",/* IFPGA_SEC_PROG_IDLE */
>> +"reading",/* IFPGA_SEC_PROG_READING */
>> +"preparing",/* IFPGA_SEC_PROG_PREPARING */
>> +"writing",/* IFPGA_SEC_PROG_WRITING */
>> +"programming"/* IFPGA_SEC_PROG_PROGRAMMING */
>> +};
>> +
>> +static ssize_t
>> +status_show(struct device *dev, struct device_attribute *attr, char *buf)
>> +{
>> +struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
>> +const char *status = "unknown-status";
>> +
>> +if (imgr->progress < IFPGA_SEC_PROG_MAX)
>> +status = sec_mgr_prog_str[imgr->progress];
> I am not sure if this would be a problem that as there is no lock protection for
> the progress value. If someone changes imgr->progress into a bad value just
> after the first check imgr->progress < IFPGA_SEC_PROG_MAX passed.
I'll read imgr->progress into a local variable and operate off of that so that I
am using a consistent value.

We really should never see an invalid value. These values are set explicitly (not
incremented or decremented) during the update process. If we do see an invalid
value, it would indicate a driver bug.
>
>> +else
>> +dev_warn(dev, "Invalid status during secure update: %d\n",
>> + imgr->progress);
> One minor thing, dev_err or even WARN_ON should be better, and I think
> if it hits this, that will be a critical issue in the driver, isn't it?
Yes. I'll switch to dev_err(). A stack trace probably wouldn't be useful
since the error would be happening in a different kernel thread.
>
> Thanks
> Hao
>
>> +
>> +return sprintf(buf, "%s\n", status);
>> +}
>> +static DEVICE_ATTR_RO(status);
>> +
>>  static ssize_t filename_store(struct device *dev, struct device_attribute *attr,
>>        const char *buf, size_t count)
>>  {
>> @@ -293,6 +324,7 @@ static DEVICE_ATTR_WO(filename);
>>
>>  static struct attribute *sec_mgr_update_attrs[] = {
>>  &dev_attr_filename.attr,
>> +&dev_attr_status.attr,
>>  NULL,
>>  };
>>
>> --
>> 2.17.1


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 4/7] fpga: sec-mgr: expose sec-mgr update errors
  2020-10-05  8:55   ` Wu, Hao
@ 2020-10-06 20:00     ` Russ Weight
  0 siblings, 0 replies; 25+ messages in thread
From: Russ Weight @ 2020-10-06 20:00 UTC (permalink / raw)
  To: Wu, Hao, mdf, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, Xu, Yilun, Gerlach, Matthew



On 10/5/20 1:55 AM, Wu, Hao wrote:
>> Subject: [PATCH v2 4/7] fpga: sec-mgr: expose sec-mgr update errors
>>
>> Extend Intel Security Manager class driver to include
>> an update/error sysfs node that can be read for error
>> information when a secure update fails.
>>
>> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
>> ---
>> v2:
>>   - Bumped documentation date and version
>>   - Added warning to sec_progress() for invalid progress status
>>   - Added sec_error() function (similar to sec_progress())
>> ---
>>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 17 ++++
>>  drivers/fpga/ifpga-sec-mgr.c                  | 81 ++++++++++++++++---
>>  include/linux/fpga/ifpga-sec-mgr.h            |  1 +
>>  3 files changed, 89 insertions(+), 10 deletions(-)
>>
>> diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> index 73a5246fea1b..1f9f2c215e0c 100644
>> --- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> @@ -89,3 +89,20 @@ Description:Read-only. Returns a string describing
>> the current
>>  programming. Userspace code can poll on this file,
>>  as it will be signaled by sysfs_notify() on each
>>  state change.
>> +
>> +What: /sys/class/ifpga_sec_mgr/ifpga_secX/update/error
>> +Date:Oct 2020
>> +KernelVersion:  5.11
>> +Contact:Russ Weight <russell.h.weight@intel.com>
>> +Description:Read-only. Returns a string describing the failure
>> +of a secure update. This string will be in the form
>> +of <STATUS>:<ERROR>, where <STATUS> will be one of
>> +the status strings described for the status sysfs
>> +file and <ERROR> will be one of the following:
>> +hw-error, timeout, user-abort, device-busy,
>> +invalid-file-size, read-write-error, flash-wearout,
>> +file-read-error.  The error sysfs file is only
>> +meaningful when the secure update engine is in the
>> +idle state. If this file is read while a secure
>> +update is in progress, then the read will fail with
>> +EBUSY.
>> diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
>> index ad918fb42dc2..456ea0b71e3d 100644
>> --- a/drivers/fpga/ifpga-sec-mgr.c
>> +++ b/drivers/fpga/ifpga-sec-mgr.c
>> @@ -146,10 +146,16 @@ static void update_progress(struct ifpga_sec_mgr
>> *imgr,
>>  sysfs_notify(&imgr->dev.kobj, "update", "status");
>>  }
>>
>> +static void set_error(struct ifpga_sec_mgr *imgr, enum ifpga_sec_err
>> err_code)
>> +{
>> +imgr->err_state = imgr->progress;
>> +imgr->err_code = err_code;
>> +}
>> +
>>  static void ifpga_sec_dev_error(struct ifpga_sec_mgr *imgr,
>>  enum ifpga_sec_err err_code)
>>  {
>> -imgr->err_code = err_code;
>> +set_error(imgr, err_code);
>>  imgr->iops->cancel(imgr);
>>  }
>>
>> @@ -172,7 +178,7 @@ static void ifpga_sec_mgr_update(struct work_struct
>> *work)
>>
>>  get_device(&imgr->dev);
>>  if (request_firmware(&fw, imgr->filename, &imgr->dev)) {
>> -imgr->err_code = IFPGA_SEC_ERR_FILE_READ;
>> +set_error(imgr, IFPGA_SEC_ERR_FILE_READ);
>>  goto idle_exit;
>>  }
>>
>> @@ -180,7 +186,7 @@ static void ifpga_sec_mgr_update(struct work_struct
>> *work)
>>  imgr->remaining_size = fw->size;
>>
>>  if (!try_module_get(imgr->dev.parent->driver->owner)) {
>> -imgr->err_code = IFPGA_SEC_ERR_BUSY;
>> +set_error(imgr, IFPGA_SEC_ERR_BUSY);
>>  goto release_fw_exit;
>>  }
>>
>> @@ -274,22 +280,76 @@ static const char * const sec_mgr_prog_str[] = {
>>  "programming"/* IFPGA_SEC_PROG_PROGRAMMING */
>>  };
>>
>> -static ssize_t
>> -status_show(struct device *dev, struct device_attribute *attr, char *buf)
>> +static const char * const sec_mgr_err_str[] = {
>> +"none",/* IFPGA_SEC_ERR_NONE */
>> +"hw-error",/* IFPGA_SEC_ERR_HW_ERROR */
>> +"timeout",/* IFPGA_SEC_ERR_TIMEOUT */
>> +"user-abort",/* IFPGA_SEC_ERR_CANCELED */
>> +"device-busy",/* IFPGA_SEC_ERR_BUSY */
>> +"invalid-file-size",/* IFPGA_SEC_ERR_INVALID_SIZE */
>> +"read-write-error",/* IFPGA_SEC_ERR_RW_ERROR */
>> +"flash-wearout",/* IFPGA_SEC_ERR_WEAROUT */
>> +"file-read-error"/* IFPGA_SEC_ERR_FILE_READ */
>> +};
>> +
>> +static const char *sec_progress(struct device *dev, enum ifpga_sec_prog
>> prog)
>>  {
>> -struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
>>  const char *status = "unknown-status";
>>
>> -if (imgr->progress < IFPGA_SEC_PROG_MAX)
>> -status = sec_mgr_prog_str[imgr->progress];
>> +if (prog < IFPGA_SEC_PROG_MAX)
>> +status = sec_mgr_prog_str[prog];
>>  else
>>  dev_warn(dev, "Invalid status during secure update: %d\n",
>> - imgr->progress);
>> + prog);
>> +
>> +return status;
>> +}
>> +
>> +static const char *sec_error(struct device *dev, enum ifpga_sec_err
>> err_code)
>> +{
>> +const char *error = "unknown-error";
>> +
>> +if (err_code < IFPGA_SEC_ERR_MAX)
>> +error = sec_mgr_err_str[err_code];
>> +else
>> +dev_warn(dev, "Invalid error code during secure
>> update: %d\n",
>> + err_code);
>> +
>> +return error;
>> +}
>> +
>> +static ssize_t
>> +status_show(struct device *dev, struct device_attribute *attr, char *buf)
>> +{
>> +struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
>>
>> -return sprintf(buf, "%s\n", status);
>> +return sprintf(buf, "%s\n", sec_progress(dev, imgr->progress));
>>  }
>>  static DEVICE_ATTR_RO(status);
>>
>> +static ssize_t
>> +error_show(struct device *dev, struct device_attribute *attr, char *buf)
>> +{
>> +struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
>> +int ret;
>> +
>> +mutex_lock(&imgr->lock);
>> +
>> +if (imgr->progress != IFPGA_SEC_PROG_IDLE)
>> +ret = -EBUSY;
>> +else if (!imgr->err_code)
>> +ret = 0;
>> +else
>> +ret = sprintf(buf, "%s:%s\n",
>> +      sec_progress(dev, imgr->err_state),
>> +      sec_error(dev, imgr->err_code));
> In scheduled work for update, there is no lock protection, would that be a
> real problem here? e.g. progress is changed, or err_state and err_code
> are not matched.
-EBUSY is returned unless we are in the IDLE state. Also, the lock is held
during this function, so new updates cannot begin. This means there is no
worker thread in progress and there is no concurrent execution context
that can change the err_state and err_code values. They would retain the
error state from the previous update.

Thanks for the comments!
- Russ
>
> Thanks
> Hao
>
>> +
>> +mutex_unlock(&imgr->lock);
>> +
>> +return ret;
>> +}
>> +static DEVICE_ATTR_RO(error);
>> +
>>  static ssize_t filename_store(struct device *dev, struct device_attribute *attr,
>>        const char *buf, size_t count)
>>  {
>> @@ -325,6 +385,7 @@ static DEVICE_ATTR_WO(filename);
>>  static struct attribute *sec_mgr_update_attrs[] = {
>>  &dev_attr_filename.attr,
>>  &dev_attr_status.attr,
>> +&dev_attr_error.attr,
>>  NULL,
>>  };
>>
>> diff --git a/include/linux/fpga/ifpga-sec-mgr.h b/include/linux/fpga/ifpga-
>> sec-mgr.h
>> index 27008abd8e75..246e3d452c59 100644
>> --- a/include/linux/fpga/ifpga-sec-mgr.h
>> +++ b/include/linux/fpga/ifpga-sec-mgr.h
>> @@ -110,6 +110,7 @@ struct ifpga_sec_mgr {
>>  const u8 *data;/* pointer to update data */
>>  u32 remaining_size;/* size remaining to transfer */
>>  enum ifpga_sec_prog progress;
>> +enum ifpga_sec_prog err_state;/* progress state at time of
>> failure */
>>  enum ifpga_sec_err err_code;/* security manager error code */
>>  bool driver_unload;
>>  void *priv;
>> --
>> 2.17.1


^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2020-10-06 20:00 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-02 22:36 [PATCH v2 0/7] Intel FPGA Security Manager Class Driver Russ Weight
2020-10-02 22:36 ` [PATCH v2 1/7] fpga: sec-mgr: intel fpga security manager class driver Russ Weight
2020-10-02 23:03   ` Russ Weight
2020-10-03  1:02     ` Moritz Fischer
2020-10-04 20:43   ` Tom Rix
2020-10-05  7:38   ` Wu, Hao
2020-10-06  0:05     ` Russ Weight
2020-10-06  1:01       ` Russ Weight
2020-10-02 22:36 ` [PATCH v2 2/7] fpga: sec-mgr: enable secure updates Russ Weight
2020-10-04 20:54   ` Tom Rix
2020-10-05  8:19   ` Wu, Hao
2020-10-06 18:55     ` Russ Weight
2020-10-02 22:36 ` [PATCH v2 3/7] fpga: sec-mgr: expose sec-mgr update status Russ Weight
2020-10-04 21:00   ` Tom Rix
2020-10-05  8:41   ` Wu, Hao
2020-10-06 19:46     ` Russ Weight
2020-10-02 22:36 ` [PATCH v2 4/7] fpga: sec-mgr: expose sec-mgr update errors Russ Weight
2020-10-04 21:06   ` Tom Rix
2020-10-05  8:55   ` Wu, Hao
2020-10-06 20:00     ` Russ Weight
2020-10-02 22:36 ` [PATCH v2 5/7] fpga: sec-mgr: expose sec-mgr update size Russ Weight
2020-10-02 22:37 ` [PATCH v2 6/7] fpga: sec-mgr: enable cancel of secure update Russ Weight
2020-10-04 21:13   ` Tom Rix
2020-10-02 22:37 ` [PATCH v2 7/7] fpga: sec-mgr: expose hardware error info Russ Weight
2020-10-04 21:19 ` [PATCH v2 0/7] Intel FPGA Security Manager Class Driver Tom Rix

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).