linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 00/12] Intel FPGA Security Manager Class Driver
@ 2020-09-04 23:52 Russ Weight
  2020-09-04 23:52 ` [PATCH v1 01/12] fpga: fpga security manager class driver Russ Weight
                   ` (14 more replies)
  0 siblings, 15 replies; 57+ messages in thread
From: Russ Weight @ 2020-09-04 23:52 UTC (permalink / raw)
  To: mdf, lee.jones, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, yilun.xu, hao.wu, matthew.gerlach, Russ Weight


These patches depend on the patchset: "add regmap-spi-avmm & Intel
Max10 BMC chip support" which is currently under review.

           --------------------------------------------------

This patchset introduces the Intel Security Manager class driver
for managing secure updates on Intel FPGA Cards. It also provides
the n3000bmc-secure mfd sub-driver for the MAX10 BMC for the n3000
Programmable Acceleration Cards (PAC). The n3000bmc-secure driver
is implemented using the Intel Security Manager class driver.

The Intel Security Manager class driver provides a common API for
user-space tools to manage updates for Secure FPGA devices. Device
drivers that instantiate the Intel Security Manager class driver will
interact with the 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.

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.

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 n3000bmc-secure driver instantiates the Intel Security Manager
class driver and provides the callback functions required to support
secure updates on Intel n3000 PAC devices.

Russ Weight (12):
  fpga: fpga security manager class driver
  fpga: create intel max10 bmc security engine
  fpga: expose max10 flash update counts in sysfs
  fpga: expose max10 canceled keys in sysfs
  fpga: enable secure updates
  fpga: add max10 secure update functions
  fpga: expose sec-mgr update status
  fpga: expose sec-mgr update errors
  fpga: expose sec-mgr update size
  fpga: enable sec-mgr update cancel
  fpga: expose hardware error info in sysfs
  fpga: add max10 get_hw_errinfo callback func

 .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 151 ++++
 MAINTAINERS                                   |   8 +
 drivers/fpga/Kconfig                          |  20 +
 drivers/fpga/Makefile                         |   6 +
 drivers/fpga/ifpga-sec-mgr.c                  | 669 ++++++++++++++++++
 drivers/fpga/intel-m10-bmc-secure.c           | 557 +++++++++++++++
 include/linux/fpga/ifpga-sec-mgr.h            | 201 ++++++
 include/linux/mfd/intel-m10-bmc.h             | 116 +++
 8 files changed, 1728 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
 create mode 100644 drivers/fpga/ifpga-sec-mgr.c
 create mode 100644 drivers/fpga/intel-m10-bmc-secure.c
 create mode 100644 include/linux/fpga/ifpga-sec-mgr.h

-- 
2.17.1


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

* [PATCH v1 01/12] fpga: fpga security manager class driver
  2020-09-04 23:52 [PATCH v1 00/12] Intel FPGA Security Manager Class Driver Russ Weight
@ 2020-09-04 23:52 ` Russ Weight
  2020-09-04 23:57   ` Randy Dunlap
                     ` (3 more replies)
  2020-09-04 23:52 ` [PATCH v1 02/12] fpga: create intel max10 bmc security engine Russ Weight
                   ` (13 subsequent siblings)
  14 siblings, 4 replies; 57+ messages in thread
From: Russ Weight @ 2020-09-04 23:52 UTC (permalink / raw)
  To: mdf, lee.jones, 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>
---
 .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  75 ++++
 MAINTAINERS                                   |   8 +
 drivers/fpga/Kconfig                          |   9 +
 drivers/fpga/Makefile                         |   3 +
 drivers/fpga/ifpga-sec-mgr.c                  | 339 ++++++++++++++++++
 include/linux/fpga/ifpga-sec-mgr.h            | 145 ++++++++
 6 files changed, 579 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
 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..86f8992559bf
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
@@ -0,0 +1,75 @@
+What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/name
+Date:		Sep 2020
+KernelVersion:  5.10
+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:		Sep 2020
+KernelVersion:  5.10
+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:		Sep 2020
+KernelVersion:  5.10
+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:		Sep 2020
+KernelVersion:  5.10
+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:		Sep 2020
+KernelVersion:  5.10
+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:		Sep 2020
+KernelVersion:  5.10
+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:		Sep 2020
+KernelVersion:  5.10
+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:		Sep 2020
+KernelVersion:  5.10
+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: "%d".
+
+What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/bmc_flash_count
+Date:		Sep 2020
+KernelVersion:  5.10
+Contact:	Russ Weight <russell.h.weight@intel.com>
+Description:	Read only. Returns number of times the BMC image has been
+		flashed.
+		Format: "%d".
diff --git a/MAINTAINERS b/MAINTAINERS
index deaafb617361..4a2ebe6b120d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6830,6 +6830,14 @@ 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:	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 88f64fbf55e3..97c0a6cc2ba7 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -235,4 +235,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 c69bfc931519..ec9fbacdedd8 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..97bf80277ed2
--- /dev/null
+++ b/drivers/fpga/ifpga-sec-mgr.c
@@ -0,0 +1,339 @@
+// 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;
+
+static ssize_t show_canceled_csk(struct ifpga_sec_mgr *imgr,
+				 sysfs_csk_hndlr_t get_csk,
+				 sysfs_csk_nbits_t get_csk_nbits,
+				 char *buf)
+{
+	unsigned long *csk_map = NULL;
+	unsigned int nbits;
+	int cnt, 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;
+
+	cnt = bitmap_print_to_pagebuf(1, buf, csk_map, nbits);
+
+vfree_exit:
+	vfree(csk_map);
+	return ret ? : cnt;
+}
+
+static ssize_t show_root_entry_hash(struct ifpga_sec_mgr *imgr,
+				    sysfs_reh_hndlr_t get_reh,
+				    sysfs_reh_size_t get_reh_size,
+				    char *buf)
+{
+	unsigned int size, i;
+	int ret, cnt = 0;
+	u8 *hash;
+
+	ret = get_reh_size(imgr);
+	if (ret < 0)
+		return ret;
+	else if (!ret)
+		return sprintf(buf, "hash not programmed\n");
+
+	size = (unsigned int)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 to_sec_mgr(d) container_of(d, struct ifpga_sec_mgr, dev)
+
+#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)
+
+#define DEVICE_ATTR_SEC_FLASH_CNT(_name) \
+static ssize_t _name##_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->_name##_flash_count(imgr); \
+	return cnt < 0 ? cnt : sprintf(buf, "%d\n", cnt); \
+} \
+static DEVICE_ATTR_RO(_name##_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_FLASH_CNT(user);
+DEVICE_ATTR_SEC_FLASH_CNT(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_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));
+
+	if (check_attr(attr, user_flash_count) ||
+	    check_attr(attr, bmc_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)
+{
+	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_register - register an IFPGA security manager struct
+ *
+ * @dev:  create ifpga 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
+ *
+ * Returns &struct ifpga_sec_mgr pointer on success, or ERR_PTR() on error.
+ */
+struct ifpga_sec_mgr *
+ifpga_sec_mgr_register(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 ERR_PTR(-EINVAL);
+	}
+
+	if (!name || !strlen(name)) {
+		dev_err(dev, "Attempt to register with no name!\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	imgr = kzalloc(sizeof(*imgr), GFP_KERNEL);
+	if (!imgr)
+		return ERR_PTR(-ENOMEM);
+
+	imgr->name = name;
+	imgr->priv = priv;
+	imgr->iops = iops;
+	mutex_init(&imgr->lock);
+
+	id = ida_simple_get(&ifpga_sec_mgr_ida, 0, 0, GFP_KERNEL);
+	if (id < 0) {
+		ret = id;
+		goto exit_free;
+	}
+
+	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);
+		ida_simple_remove(&ifpga_sec_mgr_ida, id);
+		goto exit_free;
+	}
+
+	ret = device_register(&imgr->dev);
+	if (ret) {
+		put_device(&imgr->dev);
+		return ERR_PTR(ret);
+	}
+
+	return imgr;
+
+exit_free:
+	kfree(dev);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(ifpga_sec_mgr_register);
+
+/**
+ * ifpga_sec_mgr_unregister - unregister a IFPGA security manager
+ *
+ * @mgr: fpga manager struct
+ *
+ * This function is intended for use in a IFPGA 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)
+{
+	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
+
+	mutex_destroy(&imgr->lock);
+	ida_simple_remove(&ifpga_sec_mgr_ida, imgr->dev.id);
+	kfree(imgr);
+}
+
+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..e391b0c8f448
--- /dev/null
+++ b/include/linux/fpga/ifpga-sec-mgr.h
@@ -0,0 +1,145 @@
+/* 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;
+
+/**
+ * typedef sysfs_reh_size_t - Function to return byte size of root entry hash
+ *
+ * @imgr:      pointer to security manager structure
+ *
+ * This datatype is used to define a function that returns the byte size of a
+ * root entry hash.
+ *
+ * Context: No locking requirements are imposed by the security manager.
+ * Return:  Byte count on success, negative errno on failure
+ */
+typedef int (*sysfs_reh_size_t)(struct ifpga_sec_mgr *imgr);
+
+/**
+ * typedef sysfs_reh_hndlr_t - Function pointer to sysfs file handler
+ *			       for root entry hashes
+ * @imgr:      pointer to security manager structure
+ * @hash:      pointer to an array of bytes in which to store the hash
+ * @size:      byte size of root entry hash
+ *
+ * This datatype is used to define a sysfs file handler function to
+ * return root entry hash data to be displayed via sysfs.
+ *
+ * Context: No locking requirements are imposed by the security manager.
+ * Return:  0 on success, negative errno on failure
+ */
+typedef int (*sysfs_reh_hndlr_t)(struct ifpga_sec_mgr *imgr, u8 *hash,
+				 unsigned int size);
+
+/**
+ * typedef sysfs_cnt_hndlr_t - Function pointer to sysfs file handler
+ *			       for flash counts
+ * @imgr: pointer to security manager structure
+ *
+ * This datatype is used to define a sysfs file handler function to
+ * return a flash count to be displayed via sysfs.
+ *
+ * Context: No locking requirements are imposed by the security manager
+ * Return: flash count or negative errno
+ */
+typedef int (*sysfs_cnt_hndlr_t)(struct ifpga_sec_mgr *imgr);
+
+/**
+ * typedef sysfs_csk_nbits_t - Function to return the number of bits in
+ *				      a Code Signing Key cancellation vector
+ *
+ * @imgr:      pointer to security manager structure
+ *
+ * This datatype is used to define a function that returns the number of bits
+ * in a Code Signing Key cancellation vector.
+ *
+ * Context: No locking requirements are imposed by the security manager.
+ * Return:  Number of bits on success, negative errno on failure
+ */
+typedef int (*sysfs_csk_nbits_t)(struct ifpga_sec_mgr *imgr);
+
+/**
+ * typedef sysfs_csk_hndlr_t - Function pointer to sysfs file handler
+ *			       bit vector of canceled keys
+ *
+ * @imgr:    pointer to security manager structure
+ * @csk_map: pointer to a bitmap to contain cancellation key vector
+ * @nbits:   number of bits in CSK vector
+ *
+ * This datatype is used to define a sysfs file handler function to
+ * return a bitmap of canceled keys to be displayed via sysfs.
+ *
+ * Context: No locking requirements are imposed by the security manager.
+ * Return:  0 on success, negative errno on failure
+ */
+typedef int (*sysfs_csk_hndlr_t)(struct ifpga_sec_mgr *imgr,
+				 unsigned long *csk_map, unsigned int nbits);
+
+/**
+ * struct ifpga_sec_mgr_ops - device specific operations
+ * @user_flash_count:	    Optional: Return sysfs string output for FPGA
+ *			    image flash count
+ * @bmc_flash_count:	    Optional: Return sysfs string output for BMC
+ *			    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 {
+	sysfs_cnt_hndlr_t user_flash_count;
+	sysfs_cnt_hndlr_t bmc_flash_count;
+	sysfs_cnt_hndlr_t smbus_flash_count;
+	sysfs_reh_hndlr_t sr_root_entry_hash;
+	sysfs_reh_hndlr_t pr_root_entry_hash;
+	sysfs_reh_hndlr_t bmc_root_entry_hash;
+	sysfs_csk_hndlr_t sr_canceled_csks;
+	sysfs_csk_hndlr_t pr_canceled_csks;
+	sysfs_csk_hndlr_t bmc_canceled_csks;
+	sysfs_reh_size_t bmc_reh_size;
+	sysfs_reh_size_t sr_reh_size;
+	sysfs_reh_size_t pr_reh_size;
+	sysfs_csk_nbits_t bmc_canceled_csk_nbits;
+	sysfs_csk_nbits_t sr_canceled_csk_nbits;
+	sysfs_csk_nbits_t pr_canceled_csk_nbits;
+};
+
+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_register(struct device *dev, const char *name,
+		       const struct ifpga_sec_mgr_ops *iops, void *priv);
+void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr);
+
+#endif
-- 
2.17.1


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

* [PATCH v1 02/12] fpga: create intel max10 bmc security engine
  2020-09-04 23:52 [PATCH v1 00/12] Intel FPGA Security Manager Class Driver Russ Weight
  2020-09-04 23:52 ` [PATCH v1 01/12] fpga: fpga security manager class driver Russ Weight
@ 2020-09-04 23:52 ` Russ Weight
  2020-09-05  0:01   ` Randy Dunlap
                     ` (2 more replies)
  2020-09-04 23:52 ` [PATCH v1 03/12] fpga: expose max10 flash update counts in sysfs Russ Weight
                   ` (12 subsequent siblings)
  14 siblings, 3 replies; 57+ messages in thread
From: Russ Weight @ 2020-09-04 23:52 UTC (permalink / raw)
  To: mdf, lee.jones, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, yilun.xu, hao.wu, matthew.gerlach, Russ Weight

Create a platform driver that can be invoked as a sub
driver for the Intel MAX10 BMC in order to support
secure updates. This sub-driver will invoke an
instance of the Intel FPGA Security Manager class driver
in order to expose sysfs interfaces for managing and
monitoring secure updates to FPGA and BMC images.

This patch creates the MAX10 BMC Security Engine driver and
provides support for displaying the current root entry hashes
for the FPGA static region, the FPGA PR region, and the MAX10
BMC.

Signed-off-by: Russ Weight <russell.h.weight@intel.com>
Reviewed-by: Wu Hao <hao.wu@intel.com>
---
 drivers/fpga/Kconfig                |  11 ++
 drivers/fpga/Makefile               |   3 +
 drivers/fpga/intel-m10-bmc-secure.c | 170 ++++++++++++++++++++++++++++
 include/linux/mfd/intel-m10-bmc.h   |  15 +++
 4 files changed, 199 insertions(+)
 create mode 100644 drivers/fpga/intel-m10-bmc-secure.c

diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index 97c0a6cc2ba7..0f0bed68e618 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -244,4 +244,15 @@ config IFPGA_SEC_MGR
 	  region and for the BMC. Select this option to enable
 	  updates for secure FPGA devices.
 
+config IFPGA_M10_BMC_SECURE
+        tristate "Intel MAX10 BMC security engine"
+	depends on MFD_INTEL_M10_BMC && IFPGA_SEC_MGR
+        help
+          Secure update support for the Intel MAX10 board management
+	  controller.
+
+	  This is a subdriver of the Intel MAX10 board management controller
+	  (BMC) and provides support for secure updates for the BMC image,
+	  the FPGA image, the Root Entry Hashes, etc.
+
 endif # FPGA
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index ec9fbacdedd8..451a23ec3168 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -24,6 +24,9 @@ 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
 
+# Intel Security Manager Drivers
+obj-$(CONFIG_IFPGA_M10_BMC_SECURE)	+= intel-m10-bmc-secure.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/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c
new file mode 100644
index 000000000000..1f86bfb694b4
--- /dev/null
+++ b/drivers/fpga/intel-m10-bmc-secure.c
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel Max10 Board Management Controller Security Engine Driver
+ *
+ * Copyright (C) 2019-2020 Intel Corporation. All rights reserved.
+ *
+ */
+#include <linux/device.h>
+#include <linux/fpga/ifpga-sec-mgr.h>
+#include <linux/mfd/intel-m10-bmc.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/vmalloc.h>
+
+struct m10bmc_sec {
+	struct device *dev;
+	struct intel_m10bmc *m10bmc;
+	struct ifpga_sec_mgr *imgr;
+};
+
+#define SHA256_REH_SIZE		32
+#define SHA384_REH_SIZE		48
+
+static int get_reh_size(struct ifpga_sec_mgr *imgr,
+			u32 exp_magic, u32 prog_addr)
+{
+	struct m10bmc_sec *sec = imgr->priv;
+	int sha_num_bytes, ret;
+	u32 magic;
+
+	ret = m10bmc_raw_read(sec->m10bmc, prog_addr, &magic);
+	if (ret)
+		return ret;
+
+	dev_dbg(sec->dev, "%s magic 0x%08x\n", __func__, magic);
+
+	if ((magic & 0xffff) != exp_magic)
+		return 0;
+
+	sha_num_bytes = ((magic >> 16) & 0xffff) / 8;
+
+	if (sha_num_bytes != SHA256_REH_SIZE &&
+	    sha_num_bytes != SHA384_REH_SIZE)   {
+		dev_err(sec->dev, "%s bad sha num bytes %d\n", __func__,
+			sha_num_bytes);
+		return -EINVAL;
+	}
+
+	return sha_num_bytes;
+}
+
+#define BMC_REH_ADDR 0x17ffc004
+#define BMC_PROG_ADDR 0x17ffc000
+#define BMC_PROG_MAGIC 0x5746
+
+#define SR_REH_ADDR 0x17ffd004
+#define SR_PROG_ADDR 0x17ffd000
+#define SR_PROG_MAGIC 0x5253
+
+#define PR_REH_ADDR 0x17ffe004
+#define PR_PROG_ADDR 0x17ffe000
+#define PR_PROG_MAGIC 0x5250
+
+#define SYSFS_GET_REH_SIZE(_name, _exp_magic, _prog_addr) \
+static int get_##_name##_reh_size(struct ifpga_sec_mgr *imgr) \
+{ \
+	return get_reh_size(imgr, _exp_magic, _prog_addr); \
+}
+
+SYSFS_GET_REH_SIZE(bmc, BMC_PROG_MAGIC, BMC_PROG_ADDR)
+SYSFS_GET_REH_SIZE(sr, SR_PROG_MAGIC, SR_PROG_ADDR)
+SYSFS_GET_REH_SIZE(pr, PR_PROG_MAGIC, PR_PROG_ADDR)
+
+static int get_root_entry_hash(struct ifpga_sec_mgr *imgr,
+			       u32 hash_addr, u8 *hash,
+			       unsigned int size)
+{
+	struct m10bmc_sec *sec = imgr->priv;
+	unsigned int stride = regmap_get_reg_stride(sec->m10bmc->regmap);
+	int ret;
+
+	ret = m10bmc_raw_bulk_read(sec->m10bmc, hash_addr,
+				   hash, size / stride);
+	if (ret)
+		dev_err(sec->dev, "bulk_read of 0x%x failed %d",
+			hash_addr, ret);
+
+	return ret;
+}
+
+#define SYSFS_GET_REH(_name, _hash_addr) \
+static int get_##_name##_root_entry_hash(struct ifpga_sec_mgr *imgr, \
+					 u8 *hash, unsigned int size) \
+{ \
+	return get_root_entry_hash(imgr, _hash_addr, hash, size); \
+}
+
+SYSFS_GET_REH(bmc, BMC_REH_ADDR)
+SYSFS_GET_REH(sr, SR_REH_ADDR)
+SYSFS_GET_REH(pr, PR_REH_ADDR)
+
+static const struct ifpga_sec_mgr_ops m10bmc_iops = {
+	.bmc_root_entry_hash = get_bmc_root_entry_hash,
+	.sr_root_entry_hash = get_sr_root_entry_hash,
+	.pr_root_entry_hash = get_pr_root_entry_hash,
+	.bmc_reh_size = get_bmc_reh_size,
+	.sr_reh_size = get_sr_reh_size,
+	.pr_reh_size = get_pr_reh_size,
+};
+
+static void ifpga_sec_mgr_uinit(struct m10bmc_sec *sec)
+{
+	ifpga_sec_mgr_unregister(sec->imgr);
+}
+
+static int ifpga_sec_mgr_init(struct m10bmc_sec *sec)
+{
+	struct ifpga_sec_mgr *imgr;
+
+	imgr = ifpga_sec_mgr_register(sec->dev, "Max10 BMC Security Manager",
+				      &m10bmc_iops, sec);
+	if (IS_ERR(imgr))
+		return PTR_ERR(imgr);
+
+	sec->imgr = imgr;
+	return 0;
+}
+
+static int m10bmc_secure_probe(struct platform_device *pdev)
+{
+	struct m10bmc_sec *sec;
+	int ret;
+
+	sec = devm_kzalloc(&pdev->dev, sizeof(*sec), GFP_KERNEL);
+	if (!sec)
+		return -ENOMEM;
+
+	sec->dev = &pdev->dev;
+	sec->m10bmc = dev_get_drvdata(pdev->dev.parent);
+	dev_set_drvdata(&pdev->dev, sec);
+
+	ret = ifpga_sec_mgr_init(sec);
+	if (ret)
+		dev_err(&pdev->dev,
+			"Security manager failed to start: %d\n", ret);
+
+	return ret;
+}
+
+static int m10bmc_secure_remove(struct platform_device *pdev)
+{
+	struct m10bmc_sec *sec = dev_get_drvdata(&pdev->dev);
+
+	ifpga_sec_mgr_uinit(sec);
+	return 0;
+}
+
+static struct platform_driver intel_m10bmc_secure_driver = {
+	.probe = m10bmc_secure_probe,
+	.remove = m10bmc_secure_remove,
+	.driver = {
+		.name = "n3000bmc-secure",
+	},
+};
+module_platform_driver(intel_m10bmc_secure_driver);
+
+MODULE_ALIAS("platform:n3000bmc-secure");
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Intel MAX10 BMC secure engine");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h
index d4cb01b73357..7fe465c320c2 100644
--- a/include/linux/mfd/intel-m10-bmc.h
+++ b/include/linux/mfd/intel-m10-bmc.h
@@ -63,6 +63,7 @@ struct intel_m10bmc {
  * register access helper functions.
  *
  * m10bmc_raw_read - read m10bmc register per addr
+ * m10bmc_raw_bulk_read - bulk_read max10 registers per addr
  * m10bmc_sys_read - read m10bmc system register per offset
  */
 static inline int
@@ -79,6 +80,20 @@ m10bmc_raw_read(struct intel_m10bmc *m10bmc, unsigned int addr,
 	return ret;
 }
 
+static inline int
+m10bmc_raw_bulk_read(struct intel_m10bmc *m10bmc, unsigned int addr,
+		     void *val, size_t cnt)
+{
+	int ret;
+
+	ret = regmap_bulk_read(m10bmc->regmap, addr, val, cnt);
+	if (ret)
+		dev_err(m10bmc->dev, "fail to read raw reg %x cnt %zx: %d\n",
+			addr, cnt, ret);
+
+	return ret;
+}
+
 #define m10bmc_sys_read(m10bmc, offset, val) \
 	m10bmc_raw_read(m10bmc, M10BMC_SYS_BASE + (offset), val)
 
-- 
2.17.1


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

* [PATCH v1 03/12] fpga: expose max10 flash update counts in sysfs
  2020-09-04 23:52 [PATCH v1 00/12] Intel FPGA Security Manager Class Driver Russ Weight
  2020-09-04 23:52 ` [PATCH v1 01/12] fpga: fpga security manager class driver Russ Weight
  2020-09-04 23:52 ` [PATCH v1 02/12] fpga: create intel max10 bmc security engine Russ Weight
@ 2020-09-04 23:52 ` Russ Weight
  2020-09-05 20:39   ` Tom Rix
  2020-09-04 23:52 ` [PATCH v1 04/12] fpga: expose max10 canceled keys " Russ Weight
                   ` (11 subsequent siblings)
  14 siblings, 1 reply; 57+ messages in thread
From: Russ Weight @ 2020-09-04 23:52 UTC (permalink / raw)
  To: mdf, lee.jones, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, yilun.xu, hao.wu, matthew.gerlach, Russ Weight

Extend the MAX10 BMC Security Engine driver to provide a
handler to expose the flash update count for the FPGA user
image.

Signed-off-by: Russ Weight <russell.h.weight@intel.com>
Reviewed-by: Wu Hao <hao.wu@intel.com>
---
 drivers/fpga/intel-m10-bmc-secure.c | 32 +++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/drivers/fpga/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c
index 1f86bfb694b4..b824790e43aa 100644
--- a/drivers/fpga/intel-m10-bmc-secure.c
+++ b/drivers/fpga/intel-m10-bmc-secure.c
@@ -10,6 +10,7 @@
 #include <linux/mfd/intel-m10-bmc.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
 #include <linux/vmalloc.h>
 
 struct m10bmc_sec {
@@ -99,7 +100,38 @@ SYSFS_GET_REH(bmc, BMC_REH_ADDR)
 SYSFS_GET_REH(sr, SR_REH_ADDR)
 SYSFS_GET_REH(pr, PR_REH_ADDR)
 
+#define FLASH_COUNT_SIZE 4096
+#define USER_FLASH_COUNT 0x17ffb000
+
+static int get_qspi_flash_count(struct ifpga_sec_mgr *imgr)
+{
+	struct m10bmc_sec *sec = imgr->priv;
+	unsigned int stride = regmap_get_reg_stride(sec->m10bmc->regmap);
+	unsigned int cnt, num_bits = FLASH_COUNT_SIZE * 8;
+	u8 *flash_buf;
+	int ret;
+
+	flash_buf = kmalloc(FLASH_COUNT_SIZE, GFP_KERNEL);
+	if (!flash_buf)
+		return -ENOMEM;
+
+	ret = m10bmc_raw_bulk_read(sec->m10bmc, USER_FLASH_COUNT, flash_buf,
+				   FLASH_COUNT_SIZE / stride);
+	if (ret) {
+		dev_err(sec->dev, "%s failed to read %d\n", __func__, ret);
+		goto exit_free;
+	}
+
+	cnt = num_bits - bitmap_weight((unsigned long *)flash_buf, num_bits);
+
+exit_free:
+	kfree(flash_buf);
+
+	return ret ? : cnt;
+}
+
 static const struct ifpga_sec_mgr_ops m10bmc_iops = {
+	.user_flash_count = get_qspi_flash_count,
 	.bmc_root_entry_hash = get_bmc_root_entry_hash,
 	.sr_root_entry_hash = get_sr_root_entry_hash,
 	.pr_root_entry_hash = get_pr_root_entry_hash,
-- 
2.17.1


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

* [PATCH v1 04/12] fpga: expose max10 canceled keys in sysfs
  2020-09-04 23:52 [PATCH v1 00/12] Intel FPGA Security Manager Class Driver Russ Weight
                   ` (2 preceding siblings ...)
  2020-09-04 23:52 ` [PATCH v1 03/12] fpga: expose max10 flash update counts in sysfs Russ Weight
@ 2020-09-04 23:52 ` Russ Weight
  2020-09-05 20:52   ` Tom Rix
  2020-09-04 23:52 ` [PATCH v1 05/12] fpga: enable secure updates Russ Weight
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 57+ messages in thread
From: Russ Weight @ 2020-09-04 23:52 UTC (permalink / raw)
  To: mdf, lee.jones, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, yilun.xu, hao.wu, matthew.gerlach, Russ Weight

Extend the MAX10 BMC Security Engine driver to provide a
handler to expose the canceled code signing key (CSK) bit
vectors. These use the standard bitmap list format
(e.g. 1,2-6,9).

Signed-off-by: Russ Weight <russell.h.weight@intel.com>
Reviewed-by: Wu Hao <hao.wu@intel.com>
---
 drivers/fpga/intel-m10-bmc-secure.c | 60 +++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

diff --git a/drivers/fpga/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c
index b824790e43aa..46cd49a08be0 100644
--- a/drivers/fpga/intel-m10-bmc-secure.c
+++ b/drivers/fpga/intel-m10-bmc-secure.c
@@ -130,14 +130,74 @@ static int get_qspi_flash_count(struct ifpga_sec_mgr *imgr)
 	return ret ? : cnt;
 }
 
+#define CSK_BIT_LEN			128U
+#define CSK_32ARRAY_SIZE(_nbits)	DIV_ROUND_UP(_nbits, 32)
+
+#define SYSFS_GET_CSK_CANCEL_NBITS(_name) \
+static int get_##_name##_csk_cancel_nbits(struct ifpga_sec_mgr *imgr) \
+{ \
+	return (int)CSK_BIT_LEN; \
+}
+
+SYSFS_GET_CSK_CANCEL_NBITS(bmc)
+SYSFS_GET_CSK_CANCEL_NBITS(sr)
+SYSFS_GET_CSK_CANCEL_NBITS(pr)
+
+static int get_csk_vector(struct ifpga_sec_mgr *imgr, u32 addr,
+			  unsigned long *csk_map, unsigned int nbits)
+{
+	unsigned int i, arr_size = CSK_32ARRAY_SIZE(nbits);
+	struct m10bmc_sec *sec = imgr->priv;
+	u32 *csk32;
+	int ret;
+
+	csk32 = vmalloc(arr_size);
+	if (!csk32)
+		return -ENOMEM;
+
+	ret = m10bmc_raw_bulk_read(sec->m10bmc, addr, csk32, arr_size);
+	if (ret) {
+		dev_err(sec->dev, "%s failed to read %d\n", __func__, ret);
+		goto vfree_exit;
+	}
+
+	for (i = 0; i < arr_size; i++)
+		csk32[i] = le32_to_cpu(csk32[i]);
+
+	bitmap_from_arr32(csk_map, csk32, nbits);
+	bitmap_complement(csk_map, csk_map, nbits);
+
+vfree_exit:
+	vfree(csk32);
+	return ret;
+}
+
+#define SYSFS_GET_CSK_VEC(_name, _addr) \
+static int get_##_name##_canceled_csks(struct ifpga_sec_mgr *imgr, \
+				       unsigned long *csk_map, \
+				       unsigned int nbits) \
+{ return get_csk_vector(imgr, _addr, csk_map, nbits); }
+
+#define CSK_VEC_OFFSET 0x34
+
+SYSFS_GET_CSK_VEC(bmc, BMC_PROG_ADDR + CSK_VEC_OFFSET)
+SYSFS_GET_CSK_VEC(sr, SR_PROG_ADDR + CSK_VEC_OFFSET)
+SYSFS_GET_CSK_VEC(pr, PR_PROG_ADDR + CSK_VEC_OFFSET)
+
 static const struct ifpga_sec_mgr_ops m10bmc_iops = {
 	.user_flash_count = get_qspi_flash_count,
 	.bmc_root_entry_hash = get_bmc_root_entry_hash,
 	.sr_root_entry_hash = get_sr_root_entry_hash,
 	.pr_root_entry_hash = get_pr_root_entry_hash,
+	.bmc_canceled_csks = get_bmc_canceled_csks,
+	.sr_canceled_csks = get_sr_canceled_csks,
+	.pr_canceled_csks = get_pr_canceled_csks,
 	.bmc_reh_size = get_bmc_reh_size,
 	.sr_reh_size = get_sr_reh_size,
 	.pr_reh_size = get_pr_reh_size,
+	.bmc_canceled_csk_nbits = get_bmc_csk_cancel_nbits,
+	.sr_canceled_csk_nbits = get_sr_csk_cancel_nbits,
+	.pr_canceled_csk_nbits = get_pr_csk_cancel_nbits
 };
 
 static void ifpga_sec_mgr_uinit(struct m10bmc_sec *sec)
-- 
2.17.1


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

* [PATCH v1 05/12] fpga: enable secure updates
  2020-09-04 23:52 [PATCH v1 00/12] Intel FPGA Security Manager Class Driver Russ Weight
                   ` (3 preceding siblings ...)
  2020-09-04 23:52 ` [PATCH v1 04/12] fpga: expose max10 canceled keys " Russ Weight
@ 2020-09-04 23:52 ` Russ Weight
  2020-09-05 22:04   ` Tom Rix
  2020-09-04 23:52 ` [PATCH v1 06/12] fpga: add max10 secure update functions Russ Weight
                   ` (9 subsequent siblings)
  14 siblings, 1 reply; 57+ messages in thread
From: Russ Weight @ 2020-09-04 23:52 UTC (permalink / raw)
  To: mdf, lee.jones, 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>
---
 .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  13 ++
 drivers/fpga/ifpga-sec-mgr.c                  | 155 ++++++++++++++++++
 include/linux/fpga/ifpga-sec-mgr.h            |  49 ++++++
 3 files changed, 217 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
index 86f8992559bf..a476504b7ae9 100644
--- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
+++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
@@ -73,3 +73,16 @@ Contact:	Russ Weight <russell.h.weight@intel.com>
 Description:	Read only. Returns number of times the BMC image has been
 		flashed.
 		Format: "%d".
+
+What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/update/filename
+Date:		Sep 2020
+KernelVersion:  5.10
+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 97bf80277ed2..73173badbe96 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
+
 static ssize_t show_canceled_csk(struct ifpga_sec_mgr *imgr,
 				 sysfs_csk_hndlr_t get_csk,
 				 sysfs_csk_nbits_t get_csk_nbits,
@@ -134,6 +139,91 @@ 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:
+	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)
 
@@ -161,6 +251,51 @@ 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 = 0;
+
+	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, PATH_MAX - 1, GFP_KERNEL);
+	if (!imgr->filename) {
+		ret = -ENOMEM;
+		goto unlock_exit;
+	}
+
+	if (imgr->filename[strlen(imgr->filename) - 1] == '\n')
+		imgr->filename[strlen(imgr->filename) - 1] = '\0';
+
+	imgr->err_code = IFPGA_SEC_ERR_NONE;
+	imgr->progress = IFPGA_SEC_PROG_READ_FILE;
+	reinit_completion(&imgr->update_done);
+	schedule_work(&imgr->work);
+
+unlock_exit:
+	mutex_unlock(&imgr->lock);
+	return ret ? : count;
+}
+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)
 {
@@ -182,6 +317,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,
 };
 
@@ -233,6 +369,12 @@ ifpga_sec_mgr_register(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 ifpga_sec_mgr_ops\n");
+		return NULL;
+	}
+
 	if (!check_reh_handler(dev, iops, bmc) ||
 	    !check_reh_handler(dev, iops, sr) ||
 	    !check_reh_handler(dev, iops, pr) ||
@@ -254,6 +396,8 @@ ifpga_sec_mgr_register(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);
 	mutex_init(&imgr->lock);
 
 	id = ida_simple_get(&ifpga_sec_mgr_ida, 0, 0, GFP_KERNEL);
@@ -299,6 +443,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 e391b0c8f448..4da2864e251c 100644
--- a/include/linux/fpga/ifpga-sec-mgr.h
+++ b/include/linux/fpga/ifpga-sec-mgr.h
@@ -7,6 +7,7 @@
 #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>
@@ -86,6 +87,19 @@ typedef int (*sysfs_csk_nbits_t)(struct ifpga_sec_mgr *imgr);
 typedef int (*sysfs_csk_hndlr_t)(struct ifpga_sec_mgr *imgr,
 				 unsigned long *csk_map, unsigned int nbits);
 
+enum ifpga_sec_err {
+	IFPGA_SEC_ERR_NONE	   = 0x0,
+	IFPGA_SEC_ERR_HW_ERROR	   = 0x1,
+	IFPGA_SEC_ERR_TIMEOUT	   = 0x2,
+	IFPGA_SEC_ERR_CANCELED	   = 0x3,
+	IFPGA_SEC_ERR_BUSY	   = 0x4,
+	IFPGA_SEC_ERR_INVALID_SIZE = 0x5,
+	IFPGA_SEC_ERR_RW_ERROR	   = 0x6,
+	IFPGA_SEC_ERR_WEAROUT	   = 0x7,
+	IFPGA_SEC_ERR_FILE_READ	   = 0x8,
+	IFPGA_SEC_ERR_MAX	   = 0x9
+};
+
 /**
  * struct ifpga_sec_mgr_ops - device specific operations
  * @user_flash_count:	    Optional: Return sysfs string output for FPGA
@@ -110,6 +124,17 @@ typedef int (*sysfs_csk_hndlr_t)(struct ifpga_sec_mgr *imgr,
  * @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 {
 	sysfs_cnt_hndlr_t user_flash_count;
@@ -127,6 +152,22 @@ struct ifpga_sec_mgr_ops {
 	sysfs_csk_nbits_t bmc_canceled_csk_nbits;
 	sysfs_csk_nbits_t sr_canceled_csk_nbits;
 	sysfs_csk_nbits_t pr_canceled_csk_nbits;
+	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	   = 0x0,
+	IFPGA_SEC_PROG_READ_FILE   = 0x1,
+	IFPGA_SEC_PROG_PREPARING   = 0x2,
+	IFPGA_SEC_PROG_WRITING	   = 0x3,
+	IFPGA_SEC_PROG_PROGRAMMING = 0x4,
+	IFPGA_SEC_PROG_MAX	   = 0x5
 };
 
 struct ifpga_sec_mgr {
@@ -134,6 +175,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] 57+ messages in thread

* [PATCH v1 06/12] fpga: add max10 secure update functions
  2020-09-04 23:52 [PATCH v1 00/12] Intel FPGA Security Manager Class Driver Russ Weight
                   ` (4 preceding siblings ...)
  2020-09-04 23:52 ` [PATCH v1 05/12] fpga: enable secure updates Russ Weight
@ 2020-09-04 23:52 ` Russ Weight
  2020-09-06 16:10   ` Tom Rix
  2020-09-08  8:05   ` Lee Jones
  2020-09-04 23:53 ` [PATCH v1 07/12] fpga: expose sec-mgr update status Russ Weight
                   ` (8 subsequent siblings)
  14 siblings, 2 replies; 57+ messages in thread
From: Russ Weight @ 2020-09-04 23:52 UTC (permalink / raw)
  To: mdf, lee.jones, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, yilun.xu, hao.wu, matthew.gerlach, Russ Weight

Extend the MAX10 BMC Security Engine driver to include
the functions that enable secure updates of BMC images,
FPGA images, etc.

Signed-off-by: Russ Weight <russell.h.weight@intel.com>
Reviewed-by: Wu Hao <hao.wu@intel.com>
---
 drivers/fpga/intel-m10-bmc-secure.c | 272 +++++++++++++++++++++++++++-
 include/linux/mfd/intel-m10-bmc.h   | 101 +++++++++++
 2 files changed, 372 insertions(+), 1 deletion(-)

diff --git a/drivers/fpga/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c
index 46cd49a08be0..4a66c2d448eb 100644
--- a/drivers/fpga/intel-m10-bmc-secure.c
+++ b/drivers/fpga/intel-m10-bmc-secure.c
@@ -5,6 +5,7 @@
  * Copyright (C) 2019-2020 Intel Corporation. All rights reserved.
  *
  */
+#include <linux/bitfield.h>
 #include <linux/device.h>
 #include <linux/fpga/ifpga-sec-mgr.h>
 #include <linux/mfd/intel-m10-bmc.h>
@@ -184,6 +185,271 @@ SYSFS_GET_CSK_VEC(bmc, BMC_PROG_ADDR + CSK_VEC_OFFSET)
 SYSFS_GET_CSK_VEC(sr, SR_PROG_ADDR + CSK_VEC_OFFSET)
 SYSFS_GET_CSK_VEC(pr, PR_PROG_ADDR + CSK_VEC_OFFSET)
 
+static void log_error_regs(struct m10bmc_sec *sec, u32 doorbell)
+{
+	u32 auth_result;
+
+	dev_err(sec->dev, "RSU error status: 0x%08x\n", doorbell);
+
+	if (!m10bmc_sys_read(sec->m10bmc, M10BMC_AUTH_RESULT, &auth_result))
+		dev_err(sec->dev, "RSU auth result: 0x%08x\n", auth_result);
+}
+
+static enum ifpga_sec_err rsu_check_idle(struct m10bmc_sec *sec)
+{
+	u32 doorbell;
+	int ret;
+
+	ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell);
+	if (ret)
+		return IFPGA_SEC_ERR_RW_ERROR;
+
+	if (rsu_prog(doorbell) != RSU_PROG_IDLE &&
+	    rsu_prog(doorbell) != RSU_PROG_RSU_DONE) {
+		log_error_regs(sec, doorbell);
+		return IFPGA_SEC_ERR_BUSY;
+	}
+
+	return IFPGA_SEC_ERR_NONE;
+}
+
+static inline bool rsu_start_done(u32 doorbell)
+{
+	return (!(doorbell & RSU_REQUEST) &&
+		(rsu_stat(doorbell) == RSU_STAT_ERASE_FAIL ||
+		rsu_stat(doorbell) == RSU_STAT_WEAROUT ||
+		(rsu_prog(doorbell) != RSU_PROG_IDLE &&
+		 rsu_prog(doorbell) != RSU_PROG_RSU_DONE)));
+}
+
+static enum ifpga_sec_err rsu_update_init(struct m10bmc_sec *sec)
+{
+	u32 doorbell;
+	int ret;
+
+	ret = m10bmc_sys_update_bits(sec->m10bmc, M10BMC_DOORBELL,
+				     RSU_REQUEST | HOST_STATUS, RSU_REQUEST |
+				     FIELD_PREP(HOST_STATUS, HOST_STATUS_IDLE));
+	if (ret)
+		return IFPGA_SEC_ERR_RW_ERROR;
+
+	ret = regmap_read_poll_timeout(sec->m10bmc->regmap,
+				       M10BMC_SYS_BASE + M10BMC_DOORBELL,
+				       doorbell,
+				       rsu_start_done(doorbell),
+				       NIOS_HANDSHAKE_INTERVAL_US,
+				       NIOS_HANDSHAKE_TIMEOUT_US);
+
+	if (ret == -ETIMEDOUT) {
+		log_error_regs(sec, doorbell);
+		return IFPGA_SEC_ERR_TIMEOUT;
+	} else if (ret) {
+		return IFPGA_SEC_ERR_RW_ERROR;
+	}
+
+	if (rsu_stat(doorbell) == RSU_STAT_WEAROUT) {
+		dev_warn(sec->dev, "Excessive flash update count detected\n");
+		return IFPGA_SEC_ERR_WEAROUT;
+	} else if (rsu_stat(doorbell) == RSU_STAT_ERASE_FAIL) {
+		log_error_regs(sec, doorbell);
+		return IFPGA_SEC_ERR_HW_ERROR;
+	}
+
+	return IFPGA_SEC_ERR_NONE;
+}
+
+static enum ifpga_sec_err rsu_prog_ready(struct m10bmc_sec *sec)
+{
+	unsigned long poll_timeout;
+	u32 doorbell;
+	int ret;
+
+	ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell);
+	poll_timeout = jiffies + msecs_to_jiffies(RSU_PREP_TIMEOUT_MS);
+	while (!ret && !time_after(jiffies, poll_timeout)) {
+		if (rsu_prog(doorbell) != RSU_PROG_PREPARE)
+			break;
+		msleep(RSU_PREP_INTERVAL_MS);
+		ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell);
+	}
+
+	if (ret) {
+		return IFPGA_SEC_ERR_RW_ERROR;
+	} else if (rsu_prog(doorbell) == RSU_PROG_PREPARE) {
+		log_error_regs(sec, doorbell);
+		return IFPGA_SEC_ERR_TIMEOUT;
+	} else if (rsu_prog(doorbell) != RSU_PROG_READY) {
+		log_error_regs(sec, doorbell);
+		return IFPGA_SEC_ERR_HW_ERROR;
+	}
+
+	return IFPGA_SEC_ERR_NONE;
+}
+
+static enum ifpga_sec_err rsu_send_data(struct m10bmc_sec *sec)
+{
+	u32 doorbell;
+	int ret;
+
+	ret = m10bmc_sys_update_bits(sec->m10bmc, M10BMC_DOORBELL, HOST_STATUS,
+				     FIELD_PREP(HOST_STATUS,
+						HOST_STATUS_WRITE_DONE));
+	if (ret)
+		return IFPGA_SEC_ERR_RW_ERROR;
+
+	ret = regmap_read_poll_timeout(sec->m10bmc->regmap,
+				       M10BMC_SYS_BASE + M10BMC_DOORBELL,
+				       doorbell,
+				       rsu_prog(doorbell) != RSU_PROG_READY,
+				       NIOS_HANDSHAKE_INTERVAL_US,
+				       NIOS_HANDSHAKE_TIMEOUT_US);
+
+	if (ret == -ETIMEDOUT) {
+		log_error_regs(sec, doorbell);
+		return IFPGA_SEC_ERR_TIMEOUT;
+	} else if (ret) {
+		return IFPGA_SEC_ERR_RW_ERROR;
+	}
+
+	switch (rsu_stat(doorbell)) {
+	case RSU_STAT_NORMAL:
+	case RSU_STAT_NIOS_OK:
+	case RSU_STAT_USER_OK:
+	case RSU_STAT_FACTORY_OK:
+		break;
+	default:
+		log_error_regs(sec, doorbell);
+		return IFPGA_SEC_ERR_HW_ERROR;
+	}
+
+	return IFPGA_SEC_ERR_NONE;
+}
+
+static int rsu_check_complete(struct m10bmc_sec *sec, u32 *doorbell)
+{
+	if (m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, doorbell))
+		return -EIO;
+
+	switch (rsu_stat(*doorbell)) {
+	case RSU_STAT_NORMAL:
+	case RSU_STAT_NIOS_OK:
+	case RSU_STAT_USER_OK:
+	case RSU_STAT_FACTORY_OK:
+	case RSU_STAT_WEAROUT:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (rsu_prog(*doorbell)) {
+	case RSU_PROG_IDLE:
+	case RSU_PROG_RSU_DONE:
+		return 0;
+	case RSU_PROG_AUTHENTICATING:
+	case RSU_PROG_COPYING:
+	case RSU_PROG_UPDATE_CANCEL:
+	case RSU_PROG_PROGRAM_KEY_HASH:
+		return -EAGAIN;
+	default:
+		return -EINVAL;
+	}
+}
+
+static enum ifpga_sec_err m10bmc_sec_prepare(struct ifpga_sec_mgr *imgr)
+{
+	struct m10bmc_sec *sec = imgr->priv;
+	enum ifpga_sec_err ret;
+
+	if (imgr->remaining_size > M10BMC_STAGING_SIZE)
+		return IFPGA_SEC_ERR_INVALID_SIZE;
+
+	ret = rsu_check_idle(sec);
+	if (ret)
+		return ret;
+
+	ret = rsu_update_init(sec);
+	if (ret)
+		return ret;
+
+	return rsu_prog_ready(sec);
+}
+
+static enum ifpga_sec_err
+m10bmc_sec_write_blk(struct ifpga_sec_mgr *imgr, u32 offset, u32 size)
+{
+	struct m10bmc_sec *sec = imgr->priv;
+	unsigned int stride = regmap_get_reg_stride(sec->m10bmc->regmap);
+	u32 doorbell;
+	int ret;
+
+	ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell);
+	if (ret) {
+		return IFPGA_SEC_ERR_RW_ERROR;
+	} else if (rsu_prog(doorbell) != RSU_PROG_READY) {
+		log_error_regs(sec, doorbell);
+		return IFPGA_SEC_ERR_HW_ERROR;
+	}
+
+	ret = m10bmc_raw_bulk_write(sec->m10bmc, M10BMC_STAGING_BASE + offset,
+				    (void *)imgr->data + offset, size / stride);
+
+	return ret ? IFPGA_SEC_ERR_RW_ERROR : IFPGA_SEC_ERR_NONE;
+}
+
+static enum ifpga_sec_err m10bmc_sec_poll_complete(struct ifpga_sec_mgr *imgr)
+{
+	struct m10bmc_sec *sec = imgr->priv;
+	unsigned long poll_timeout;
+	enum ifpga_sec_err result;
+	u32 doorbell;
+	int ret;
+
+	result = rsu_send_data(sec);
+	if (result)
+		return result;
+
+	ret = rsu_check_complete(sec, &doorbell);
+	poll_timeout = jiffies + msecs_to_jiffies(RSU_COMPLETE_TIMEOUT_MS);
+	while (ret == -EAGAIN && !time_after(jiffies, poll_timeout)) {
+		msleep(RSU_COMPLETE_INTERVAL_MS);
+		ret = rsu_check_complete(sec, &doorbell);
+		if (imgr->driver_unload)
+			return IFPGA_SEC_ERR_CANCELED;
+	}
+
+	if (ret == -EAGAIN) {
+		log_error_regs(sec, doorbell);
+		return IFPGA_SEC_ERR_TIMEOUT;
+	} else if (ret == -EIO) {
+		return IFPGA_SEC_ERR_RW_ERROR;
+	} else if (ret) {
+		log_error_regs(sec, doorbell);
+		return IFPGA_SEC_ERR_HW_ERROR;
+	}
+
+	return IFPGA_SEC_ERR_NONE;
+}
+
+static enum ifpga_sec_err m10bmc_sec_cancel(struct ifpga_sec_mgr *imgr)
+{
+	struct m10bmc_sec *sec = imgr->priv;
+	u32 doorbell;
+	int ret;
+
+	ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell);
+	if (ret)
+		return IFPGA_SEC_ERR_RW_ERROR;
+
+	if (rsu_prog(doorbell) != RSU_PROG_READY)
+		return IFPGA_SEC_ERR_BUSY;
+
+	ret = m10bmc_sys_update_bits(sec->m10bmc, M10BMC_DOORBELL, HOST_STATUS,
+				     FIELD_PREP(HOST_STATUS,
+						HOST_STATUS_ABORT_RSU));
+
+	return ret ? IFPGA_SEC_ERR_RW_ERROR : IFPGA_SEC_ERR_NONE;
+}
+
 static const struct ifpga_sec_mgr_ops m10bmc_iops = {
 	.user_flash_count = get_qspi_flash_count,
 	.bmc_root_entry_hash = get_bmc_root_entry_hash,
@@ -197,7 +463,11 @@ static const struct ifpga_sec_mgr_ops m10bmc_iops = {
 	.pr_reh_size = get_pr_reh_size,
 	.bmc_canceled_csk_nbits = get_bmc_csk_cancel_nbits,
 	.sr_canceled_csk_nbits = get_sr_csk_cancel_nbits,
-	.pr_canceled_csk_nbits = get_pr_csk_cancel_nbits
+	.pr_canceled_csk_nbits = get_pr_csk_cancel_nbits,
+	.prepare = m10bmc_sec_prepare,
+	.write_blk = m10bmc_sec_write_blk,
+	.poll_complete = m10bmc_sec_poll_complete,
+	.cancel = m10bmc_sec_cancel
 };
 
 static void ifpga_sec_mgr_uinit(struct m10bmc_sec *sec)
diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h
index 7fe465c320c2..5d2860d8a0cf 100644
--- a/include/linux/mfd/intel-m10-bmc.h
+++ b/include/linux/mfd/intel-m10-bmc.h
@@ -13,6 +13,9 @@
 #define M10BMC_SYS_BASE			0x300800
 #define M10BMC_MEM_END			0x200000fc
 
+#define M10BMC_STAGING_BASE		0x18000000
+#define M10BMC_STAGING_SIZE		0x3800000
+
 /* Register offset of system registers */
 #define NIOS2_FW_VERSION		0x0
 #define M10BMC_MACADDR1			0x10
@@ -36,6 +39,70 @@
 #define SERDES_VERSION			GENMASK(15, 0)
 #define SBUS_VERSION			GENMASK(31, 16)
 
+/* Secure update doorbell register, in system register region */
+#define M10BMC_DOORBELL			0x400
+#define RSU_REQUEST			BIT(0)
+#define RSU_PROGRESS			GENMASK(7, 4)
+#define HOST_STATUS			GENMASK(11, 8)
+#define RSU_STATUS			GENMASK(23, 16)
+#define PKVL_EEPROM_LOAD_SEC		BIT(24)
+#define PKVL1_POLL_EN			BIT(25)
+#define PKVL2_POLL_EN			BIT(26)
+#define CONFIG_SEL			BIT(28)
+#define REBOOT_REQ			BIT(29)
+#define REBOOT_DISABLED			BIT(30)
+
+/* Progress states */
+#define RSU_PROG_IDLE			0x0
+#define RSU_PROG_PREPARE		0x1
+#define RSU_PROG_READY			0x3
+#define RSU_PROG_AUTHENTICATING		0x4
+#define RSU_PROG_COPYING		0x5
+#define RSU_PROG_UPDATE_CANCEL		0x6
+#define RSU_PROG_PROGRAM_KEY_HASH	0x7
+#define RSU_PROG_RSU_DONE		0x8
+#define RSU_PROG_PKVL_PROM_DONE		0x9
+
+/* Device and error states */
+#define RSU_STAT_NORMAL			0x0
+#define RSU_STAT_TIMEOUT		0x1
+#define RSU_STAT_AUTH_FAIL		0x2
+#define RSU_STAT_COPY_FAIL		0x3
+#define RSU_STAT_FATAL			0x4
+#define RSU_STAT_PKVL_REJECT		0x5
+#define RSU_STAT_NON_INC		0x6
+#define RSU_STAT_ERASE_FAIL		0x7
+#define RSU_STAT_WEAROUT		0x8
+#define RSU_STAT_NIOS_OK		0x80
+#define RSU_STAT_USER_OK		0x81
+#define RSU_STAT_FACTORY_OK		0x82
+#define RSU_STAT_USER_FAIL		0x83
+#define RSU_STAT_FACTORY_FAIL		0x84
+#define RSU_STAT_NIOS_FLASH_ERR		0x85
+#define RSU_STAT_FPGA_FLASH_ERR		0x86
+
+#define HOST_STATUS_IDLE		0x0
+#define HOST_STATUS_WRITE_DONE		0x1
+#define HOST_STATUS_ABORT_RSU		0x2
+
+#define rsu_prog(doorbell)		FIELD_GET(RSU_PROGRESS, doorbell)
+#define rsu_stat(doorbell)		FIELD_GET(RSU_STATUS, doorbell)
+
+/* interval 100ms and timeout 5s */
+#define NIOS_HANDSHAKE_INTERVAL_US	(100 * 1000)
+#define NIOS_HANDSHAKE_TIMEOUT_US	(5 * 1000 * 1000)
+
+/* RSU PREP Timeout (2 minutes) to erase flash staging area */
+#define RSU_PREP_INTERVAL_MS		100
+#define RSU_PREP_TIMEOUT_MS		(2 * 60 * 1000)
+
+/* RSU Complete Timeout (40 minutes) for full flash update */
+#define RSU_COMPLETE_INTERVAL_MS	1000
+#define RSU_COMPLETE_TIMEOUT_MS		(40 * 60 * 1000)
+
+/* Authorization Result register, in system register region */
+#define M10BMC_AUTH_RESULT		0x404
+
 /**
  * struct intel_m10bmc_retimer_pdata - subdev retimer platform data
  *
@@ -64,7 +131,10 @@ struct intel_m10bmc {
  *
  * m10bmc_raw_read - read m10bmc register per addr
  * m10bmc_raw_bulk_read - bulk_read max10 registers per addr
+ * m10bmc_raw_bulk_write - bulk_write max10 registers per addr
+ * m10bmc_raw_update_bits - update max10 register per addr
  * m10bmc_sys_read - read m10bmc system register per offset
+ * m10bmc_sys_update_bits - update max10 system register per offset
  */
 static inline int
 m10bmc_raw_read(struct intel_m10bmc *m10bmc, unsigned int addr,
@@ -94,7 +164,38 @@ m10bmc_raw_bulk_read(struct intel_m10bmc *m10bmc, unsigned int addr,
 	return ret;
 }
 
+static inline int
+m10bmc_raw_bulk_write(struct intel_m10bmc *m10bmc, unsigned int addr,
+		      void *val, size_t cnt)
+{
+	int ret;
+
+	ret = regmap_bulk_write(m10bmc->regmap, addr, val, cnt);
+	if (ret)
+		dev_err(m10bmc->dev, "fail to write raw reg %x cnt %zx: %d\n",
+			addr, cnt, ret);
+
+	return ret;
+}
+
+static inline int
+m10bmc_raw_update_bits(struct intel_m10bmc *m10bmc, unsigned int addr,
+		       unsigned int msk, unsigned int val)
+{
+	int ret;
+
+	ret = regmap_update_bits(m10bmc->regmap, addr, msk, val);
+	if (ret)
+		dev_err(m10bmc->dev, "fail to update raw reg %x: %d\n",
+			addr, ret);
+
+	return ret;
+}
+
 #define m10bmc_sys_read(m10bmc, offset, val) \
 	m10bmc_raw_read(m10bmc, M10BMC_SYS_BASE + (offset), val)
 
+#define m10bmc_sys_update_bits(m10bmc, offset, msk, val) \
+	m10bmc_raw_update_bits(m10bmc, M10BMC_SYS_BASE + (offset), msk, val)
+
 #endif /* __MFD_INTEL_M10_BMC_H */
-- 
2.17.1


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

* [PATCH v1 07/12] fpga: expose sec-mgr update status
  2020-09-04 23:52 [PATCH v1 00/12] Intel FPGA Security Manager Class Driver Russ Weight
                   ` (5 preceding siblings ...)
  2020-09-04 23:52 ` [PATCH v1 06/12] fpga: add max10 secure update functions Russ Weight
@ 2020-09-04 23:53 ` Russ Weight
  2020-09-06 16:16   ` Tom Rix
  2020-09-04 23:53 ` [PATCH v1 08/12] fpga: expose sec-mgr update errors Russ Weight
                   ` (7 subsequent siblings)
  14 siblings, 1 reply; 57+ messages in thread
From: Russ Weight @ 2020-09-04 23:53 UTC (permalink / raw)
  To: mdf, lee.jones, 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>
Reviewed-by: Wu Hao <hao.wu@intel.com>
---
 .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 11 ++++++
 drivers/fpga/ifpga-sec-mgr.c                  | 34 ++++++++++++++++---
 2 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
index a476504b7ae9..849ccb2802f8 100644
--- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
+++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
@@ -86,3 +86,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:		Sep 2020
+KernelVersion:  5.10
+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, read_file, 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 73173badbe96..5fe3d85e2963 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);
@@ -251,6 +258,24 @@ 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 */
+	"read_file",		/* IFPGA_SEC_PROG_READ_FILE */
+	"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);
+
+	return sprintf(buf, "%s\n", (imgr->progress < IFPGA_SEC_PROG_MAX) ?
+		       sec_mgr_prog_str[imgr->progress] : "unknown-status");
+}
+static DEVICE_ATTR_RO(status);
+
 static ssize_t filename_store(struct device *dev, struct device_attribute *attr,
 			      const char *buf, size_t count)
 {
@@ -288,6 +313,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] 57+ messages in thread

* [PATCH v1 08/12] fpga: expose sec-mgr update errors
  2020-09-04 23:52 [PATCH v1 00/12] Intel FPGA Security Manager Class Driver Russ Weight
                   ` (6 preceding siblings ...)
  2020-09-04 23:53 ` [PATCH v1 07/12] fpga: expose sec-mgr update status Russ Weight
@ 2020-09-04 23:53 ` Russ Weight
  2020-09-06 16:27   ` Tom Rix
  2020-09-04 23:53 ` [PATCH v1 09/12] fpga: expose sec-mgr update size Russ Weight
                   ` (6 subsequent siblings)
  14 siblings, 1 reply; 57+ messages in thread
From: Russ Weight @ 2020-09-04 23:53 UTC (permalink / raw)
  To: mdf, lee.jones, 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>
Reviewed-by: Wu Hao <hao.wu@intel.com>
---
 .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 17 ++++++
 drivers/fpga/ifpga-sec-mgr.c                  | 60 +++++++++++++++++--
 include/linux/fpga/ifpga-sec-mgr.h            |  1 +
 3 files changed, 73 insertions(+), 5 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
index 849ccb2802f8..e7b1b02bf7ee 100644
--- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
+++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
@@ -97,3 +97,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:		Sep 2020
+KernelVersion:  5.10
+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 5fe3d85e2963..a7718bd8ee61 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;
 	}
 
@@ -266,16 +272,59 @@ static const char * const sec_mgr_prog_str[] = {
 	"programming"		/* IFPGA_SEC_PROG_PROGRAMMING */
 };
 
+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(enum ifpga_sec_prog prog)
+{
+	return (prog < IFPGA_SEC_PROG_MAX) ?
+		sec_mgr_prog_str[prog] : "unknown-status";
+}
+
 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", (imgr->progress < IFPGA_SEC_PROG_MAX) ?
-		       sec_mgr_prog_str[imgr->progress] : "unknown-status");
+	return sprintf(buf, "%s\n", sec_progress(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);
+	enum ifpga_sec_err err_code;
+	const char *prog_str;
+	int ret;
+
+	mutex_lock(&imgr->lock);
+	if (imgr->progress != IFPGA_SEC_PROG_IDLE) {
+		ret = -EBUSY;
+	} else if (!imgr->err_code) {
+		ret = 0;
+	} else {
+		err_code = imgr->err_code;
+		prog_str = sec_progress(imgr->err_state);
+		ret = sprintf(buf, "%s:%s\n", prog_str,
+			      (err_code < IFPGA_SEC_ERR_MAX) ?
+			      sec_mgr_err_str[err_code] : "unknown-error");
+	}
+	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)
 {
@@ -314,6 +363,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 4da2864e251c..f04bf9e30c67 100644
--- a/include/linux/fpga/ifpga-sec-mgr.h
+++ b/include/linux/fpga/ifpga-sec-mgr.h
@@ -181,6 +181,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] 57+ messages in thread

* [PATCH v1 09/12] fpga: expose sec-mgr update size
  2020-09-04 23:52 [PATCH v1 00/12] Intel FPGA Security Manager Class Driver Russ Weight
                   ` (7 preceding siblings ...)
  2020-09-04 23:53 ` [PATCH v1 08/12] fpga: expose sec-mgr update errors Russ Weight
@ 2020-09-04 23:53 ` Russ Weight
  2020-09-06 16:39   ` Tom Rix
  2020-09-04 23:53 ` [PATCH v1 10/12] fpga: enable sec-mgr update cancel Russ Weight
                   ` (5 subsequent siblings)
  14 siblings, 1 reply; 57+ messages in thread
From: Russ Weight @ 2020-09-04 23:53 UTC (permalink / raw)
  To: mdf, lee.jones, 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: Wu Hao <hao.wu@intel.com>
---
 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 e7b1b02bf7ee..cf1967f1b3e3 100644
--- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
+++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
@@ -98,6 +98,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:		Sep 2020
+KernelVersion:  5.10
+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:		Sep 2020
 KernelVersion:  5.10
diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
index a7718bd8ee61..4ca5d13e5656 100644
--- a/drivers/fpga/ifpga-sec-mgr.c
+++ b/drivers/fpga/ifpga-sec-mgr.c
@@ -325,6 +325,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)
 {
@@ -364,6 +373,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	[flat|nested] 57+ messages in thread

* [PATCH v1 10/12] fpga: enable sec-mgr update cancel
  2020-09-04 23:52 [PATCH v1 00/12] Intel FPGA Security Manager Class Driver Russ Weight
                   ` (8 preceding siblings ...)
  2020-09-04 23:53 ` [PATCH v1 09/12] fpga: expose sec-mgr update size Russ Weight
@ 2020-09-04 23:53 ` Russ Weight
  2020-09-06 17:00   ` Tom Rix
  2020-09-04 23:53 ` [PATCH v1 11/12] fpga: expose hardware error info in sysfs Russ Weight
                   ` (4 subsequent siblings)
  14 siblings, 1 reply; 57+ messages in thread
From: Russ Weight @ 2020-09-04 23:53 UTC (permalink / raw)
  To: mdf, lee.jones, 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>
---
 .../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 cf1967f1b3e3..762a7dee9453 100644
--- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
+++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
@@ -87,6 +87,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:		Sep 2020
+KernelVersion:  5.10
+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:		Sep 2020
 KernelVersion:  5.10
diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
index 4ca5d13e5656..afd97c135ebe 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);
@@ -359,6 +382,7 @@ static ssize_t filename_store(struct device *dev, struct device_attribute *attr,
 		imgr->filename[strlen(imgr->filename) - 1] = '\0';
 
 	imgr->err_code = IFPGA_SEC_ERR_NONE;
+	imgr->request_cancel = false;
 	imgr->progress = IFPGA_SEC_PROG_READ_FILE;
 	reinit_completion(&imgr->update_done);
 	schedule_work(&imgr->work);
@@ -369,8 +393,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 = 0;
+
+	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 ? : count;
+}
+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,
@@ -536,6 +584,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 f04bf9e30c67..f51ed663a723 100644
--- a/include/linux/fpga/ifpga-sec-mgr.h
+++ b/include/linux/fpga/ifpga-sec-mgr.h
@@ -183,6 +183,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	[flat|nested] 57+ messages in thread

* [PATCH v1 11/12] fpga: expose hardware error info in sysfs
  2020-09-04 23:52 [PATCH v1 00/12] Intel FPGA Security Manager Class Driver Russ Weight
                   ` (9 preceding siblings ...)
  2020-09-04 23:53 ` [PATCH v1 10/12] fpga: enable sec-mgr update cancel Russ Weight
@ 2020-09-04 23:53 ` Russ Weight
  2020-09-06 17:06   ` Tom Rix
  2020-09-04 23:53 ` [PATCH v1 12/12] fpga: add max10 get_hw_errinfo callback func Russ Weight
                   ` (3 subsequent siblings)
  14 siblings, 1 reply; 57+ messages in thread
From: Russ Weight @ 2020-09-04 23:53 UTC (permalink / raw)
  To: mdf, lee.jones, 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: Wu Hao <hao.wu@intel.com>
---
 .../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 762a7dee9453..20bde1abb5e4 100644
--- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
+++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
@@ -135,3 +135,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:		Sep 2020
+KernelVersion:  5.10
+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 afd97c135ebe..6944396eff80 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);
 }
 
@@ -348,6 +355,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)
 {
@@ -382,6 +406,7 @@ static ssize_t filename_store(struct device *dev, struct device_attribute *attr,
 		imgr->filename[strlen(imgr->filename) - 1] = '\0';
 
 	imgr->err_code = IFPGA_SEC_ERR_NONE;
+	imgr->hw_errinfo = 0;
 	imgr->request_cancel = false;
 	imgr->progress = IFPGA_SEC_PROG_READ_FILE;
 	reinit_completion(&imgr->update_done);
@@ -416,18 +441,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 f51ed663a723..3be8d8da078a 100644
--- a/include/linux/fpga/ifpga-sec-mgr.h
+++ b/include/linux/fpga/ifpga-sec-mgr.h
@@ -135,6 +135,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 {
 	sysfs_cnt_hndlr_t user_flash_count;
@@ -158,6 +161,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 */
@@ -183,6 +187,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	[flat|nested] 57+ messages in thread

* [PATCH v1 12/12] fpga: add max10 get_hw_errinfo callback func
  2020-09-04 23:52 [PATCH v1 00/12] Intel FPGA Security Manager Class Driver Russ Weight
                   ` (10 preceding siblings ...)
  2020-09-04 23:53 ` [PATCH v1 11/12] fpga: expose hardware error info in sysfs Russ Weight
@ 2020-09-04 23:53 ` Russ Weight
  2020-09-06 17:14   ` Tom Rix
  2020-09-05 14:13 ` [PATCH v1 00/12] Intel FPGA Security Manager Class Driver Wu, Hao
                   ` (2 subsequent siblings)
  14 siblings, 1 reply; 57+ messages in thread
From: Russ Weight @ 2020-09-04 23:53 UTC (permalink / raw)
  To: mdf, lee.jones, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, yilun.xu, hao.wu, matthew.gerlach, Russ Weight

Extend the MAX10 BMC Security Engine driver to include
a function that returns 64 bits of additional HW specific
data for errors that require additional information.
This callback function enables the hw_errinfo sysfs
node in the Intel Security Manager class driver.

Signed-off-by: Russ Weight <russell.h.weight@intel.com>
Reviewed-by: Wu Hao <hao.wu@intel.com>
---
 drivers/fpga/intel-m10-bmc-secure.c | 27 ++++++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/drivers/fpga/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c
index 4a66c2d448eb..7fb1c805f654 100644
--- a/drivers/fpga/intel-m10-bmc-secure.c
+++ b/drivers/fpga/intel-m10-bmc-secure.c
@@ -450,6 +450,30 @@ static enum ifpga_sec_err m10bmc_sec_cancel(struct ifpga_sec_mgr *imgr)
 	return ret ? IFPGA_SEC_ERR_RW_ERROR : IFPGA_SEC_ERR_NONE;
 }
 
+static u64 m10bmc_sec_hw_errinfo(struct ifpga_sec_mgr *imgr)
+{
+	struct m10bmc_sec *sec = imgr->priv;
+	u32 doorbell = 0, auth_result = 0;
+	u64 hw_errinfo = 0;
+
+	switch (imgr->err_code) {
+	case IFPGA_SEC_ERR_HW_ERROR:
+	case IFPGA_SEC_ERR_TIMEOUT:
+	case IFPGA_SEC_ERR_BUSY:
+	case IFPGA_SEC_ERR_WEAROUT:
+		if (!m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell))
+			hw_errinfo = (u64)doorbell << 32;
+
+		if (!m10bmc_sys_read(sec->m10bmc, M10BMC_AUTH_RESULT,
+				     &auth_result))
+			hw_errinfo |= (u64)auth_result;
+
+		return hw_errinfo;
+	default:
+		return 0;
+	}
+}
+
 static const struct ifpga_sec_mgr_ops m10bmc_iops = {
 	.user_flash_count = get_qspi_flash_count,
 	.bmc_root_entry_hash = get_bmc_root_entry_hash,
@@ -467,7 +491,8 @@ static const struct ifpga_sec_mgr_ops m10bmc_iops = {
 	.prepare = m10bmc_sec_prepare,
 	.write_blk = m10bmc_sec_write_blk,
 	.poll_complete = m10bmc_sec_poll_complete,
-	.cancel = m10bmc_sec_cancel
+	.cancel = m10bmc_sec_cancel,
+	.get_hw_errinfo = m10bmc_sec_hw_errinfo
 };
 
 static void ifpga_sec_mgr_uinit(struct m10bmc_sec *sec)
-- 
2.17.1


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

* Re: [PATCH v1 01/12] fpga: fpga security manager class driver
  2020-09-04 23:52 ` [PATCH v1 01/12] fpga: fpga security manager class driver Russ Weight
@ 2020-09-04 23:57   ` Randy Dunlap
  2020-09-05  0:23   ` Moritz Fischer
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 57+ messages in thread
From: Randy Dunlap @ 2020-09-04 23:57 UTC (permalink / raw)
  To: Russ Weight, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, yilun.xu, hao.wu, matthew.gerlach

On 9/4/20 4:52 PM, Russ Weight wrote:
> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> index 88f64fbf55e3..97c0a6cc2ba7 100644
> --- a/drivers/fpga/Kconfig
> +++ b/drivers/fpga/Kconfig
> @@ -235,4 +235,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

Use one tab instead of spaces to indent "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

thanks.
-- 
~Randy


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

* Re: [PATCH v1 02/12] fpga: create intel max10 bmc security engine
  2020-09-04 23:52 ` [PATCH v1 02/12] fpga: create intel max10 bmc security engine Russ Weight
@ 2020-09-05  0:01   ` Randy Dunlap
  2020-09-05  0:05     ` Russ Weight
  2020-09-05 20:22   ` Tom Rix
  2020-09-16 20:33   ` Moritz Fischer
  2 siblings, 1 reply; 57+ messages in thread
From: Randy Dunlap @ 2020-09-05  0:01 UTC (permalink / raw)
  To: Russ Weight, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, yilun.xu, hao.wu, matthew.gerlach

On 9/4/20 4:52 PM, Russ Weight wrote:
> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> index 97c0a6cc2ba7..0f0bed68e618 100644
> --- a/drivers/fpga/Kconfig
> +++ b/drivers/fpga/Kconfig
> @@ -244,4 +244,15 @@ config IFPGA_SEC_MGR
>  	  region and for the BMC. Select this option to enable
>  	  updates for secure FPGA devices.
>  
> +config IFPGA_M10_BMC_SECURE
> +        tristate "Intel MAX10 BMC security engine"
> +	depends on MFD_INTEL_M10_BMC && IFPGA_SEC_MGR
> +        help
> +          Secure update support for the Intel MAX10 board management
> +	  controller.

Please consistently use one tab to indent Kconfig keywords (tristate, depends, help)
and one tab + 2 spaces to indent help text.
(as in Documentation/process/coding-style.rst)

> +
> +	  This is a subdriver of the Intel MAX10 board management controller
> +	  (BMC) and provides support for secure updates for the BMC image,
> +	  the FPGA image, the Root Entry Hashes, etc.
> +
>  endif # FPGA


thanks.
-- 
~Randy


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

* Re: [PATCH v1 02/12] fpga: create intel max10 bmc security engine
  2020-09-05  0:01   ` Randy Dunlap
@ 2020-09-05  0:05     ` Russ Weight
  0 siblings, 0 replies; 57+ messages in thread
From: Russ Weight @ 2020-09-05  0:05 UTC (permalink / raw)
  To: Randy Dunlap, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 9/4/20 5:01 PM, Randy Dunlap wrote:
> On 9/4/20 4:52 PM, Russ Weight wrote:
>> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
>> index 97c0a6cc2ba7..0f0bed68e618 100644
>> --- a/drivers/fpga/Kconfig
>> +++ b/drivers/fpga/Kconfig
>> @@ -244,4 +244,15 @@ config IFPGA_SEC_MGR
>>   	  region and for the BMC. Select this option to enable
>>   	  updates for secure FPGA devices.
>>   
>> +config IFPGA_M10_BMC_SECURE
>> +        tristate "Intel MAX10 BMC security engine"
>> +	depends on MFD_INTEL_M10_BMC && IFPGA_SEC_MGR
>> +        help
>> +          Secure update support for the Intel MAX10 board management
>> +	  controller.
> Please consistently use one tab to indent Kconfig keywords (tristate, depends, help)
> and one tab + 2 spaces to indent help text.
> (as in Documentation/process/coding-style.rst)

Thanks for the feedback. I'll fix these.

>> +
>> +	  This is a subdriver of the Intel MAX10 board management controller
>> +	  (BMC) and provides support for secure updates for the BMC image,
>> +	  the FPGA image, the Root Entry Hashes, etc.
>> +
>>   endif # FPGA
>
> thanks.

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

* Re: [PATCH v1 01/12] fpga: fpga security manager class driver
  2020-09-04 23:52 ` [PATCH v1 01/12] fpga: fpga security manager class driver Russ Weight
  2020-09-04 23:57   ` Randy Dunlap
@ 2020-09-05  0:23   ` Moritz Fischer
  2020-09-05  0:44     ` Russ Weight
  2020-09-05 19:09   ` Tom Rix
  2020-09-16 20:16   ` Moritz Fischer
  3 siblings, 1 reply; 57+ messages in thread
From: Moritz Fischer @ 2020-09-05  0:23 UTC (permalink / raw)
  To: Russ Weight
  Cc: mdf, lee.jones, linux-fpga, linux-kernel, trix, lgoncalv,
	yilun.xu, hao.wu, matthew.gerlach

Hi Russ,

On Fri, Sep 04, 2020 at 04:52:54PM -0700, 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>

As for Reviewed-by tags I had seen on other patches in the series, I'd
prefer for that to happen on public mailing lists. If Hao reviewed
patches on some internal Intel list I won't know about it, so please
have him properly Ack/Reviewed-by tag things on a public mailing list.

> ---
>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  75 ++++
>  MAINTAINERS                                   |   8 +
>  drivers/fpga/Kconfig                          |   9 +
>  drivers/fpga/Makefile                         |   3 +
>  drivers/fpga/ifpga-sec-mgr.c                  | 339 ++++++++++++++++++
>  include/linux/fpga/ifpga-sec-mgr.h            | 145 ++++++++
>  6 files changed, 579 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>  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..86f8992559bf
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> @@ -0,0 +1,75 @@
> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/name
> +Date:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
> +KernelVersion:  5.10
> +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: "%d".
> +
> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/bmc_flash_count
> +Date:		Sep 2020
> +KernelVersion:  5.10
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Read only. Returns number of times the BMC image has been
> +		flashed.
> +		Format: "%d".
> diff --git a/MAINTAINERS b/MAINTAINERS
> index deaafb617361..4a2ebe6b120d 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -6830,6 +6830,14 @@ 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:	drivers/fpga/ifpga-sec-mgr.c
> +F:	include/linux/fpga/ifpga-sec-mgr.h

Generally not against having more people help out, but do we need a
per driver maintainer?

> +
>  FPU EMULATOR
>  M:	Bill Metzenthen <billm@melbpc.org.au>
>  S:	Maintained
> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> index 88f64fbf55e3..97c0a6cc2ba7 100644
> --- a/drivers/fpga/Kconfig
> +++ b/drivers/fpga/Kconfig
> @@ -235,4 +235,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 c69bfc931519..ec9fbacdedd8 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..97bf80277ed2
> --- /dev/null
> +++ b/drivers/fpga/ifpga-sec-mgr.c
> @@ -0,0 +1,339 @@
> +// 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;
> +
> +static ssize_t show_canceled_csk(struct ifpga_sec_mgr *imgr,
> +				 sysfs_csk_hndlr_t get_csk,
> +				 sysfs_csk_nbits_t get_csk_nbits,
> +				 char *buf)
> +{
> +	unsigned long *csk_map = NULL;
> +	unsigned int nbits;
> +	int cnt, 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;
> +
> +	cnt = bitmap_print_to_pagebuf(1, buf, csk_map, nbits);
> +
> +vfree_exit:
> +	vfree(csk_map);
> +	return ret ? : cnt;
> +}
> +
> +static ssize_t show_root_entry_hash(struct ifpga_sec_mgr *imgr,
> +				    sysfs_reh_hndlr_t get_reh,
> +				    sysfs_reh_size_t get_reh_size,
> +				    char *buf)
> +{
> +	unsigned int size, i;
> +	int ret, cnt = 0;
> +	u8 *hash;
> +
> +	ret = get_reh_size(imgr);
> +	if (ret < 0)
> +		return ret;
> +	else if (!ret)
> +		return sprintf(buf, "hash not programmed\n");
> +
> +	size = (unsigned int)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 to_sec_mgr(d) container_of(d, struct ifpga_sec_mgr, dev)
> +
> +#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)
> +
> +#define DEVICE_ATTR_SEC_FLASH_CNT(_name) \
> +static ssize_t _name##_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->_name##_flash_count(imgr); \
> +	return cnt < 0 ? cnt : sprintf(buf, "%d\n", cnt); \
> +} \
> +static DEVICE_ATTR_RO(_name##_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_FLASH_CNT(user);
> +DEVICE_ATTR_SEC_FLASH_CNT(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_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));
> +
> +	if (check_attr(attr, user_flash_count) ||
> +	    check_attr(attr, bmc_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)
> +{
> +	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_register - register an IFPGA security manager struct
> + *
> + * @dev:  create ifpga 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
> + *
> + * Returns &struct ifpga_sec_mgr pointer on success, or ERR_PTR() on error.
> + */
> +struct ifpga_sec_mgr *
> +ifpga_sec_mgr_register(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 ERR_PTR(-EINVAL);
> +	}
> +
> +	if (!name || !strlen(name)) {
> +		dev_err(dev, "Attempt to register with no name!\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	imgr = kzalloc(sizeof(*imgr), GFP_KERNEL);
> +	if (!imgr)
> +		return ERR_PTR(-ENOMEM);
> +
> +	imgr->name = name;
> +	imgr->priv = priv;
> +	imgr->iops = iops;
> +	mutex_init(&imgr->lock);
> +
> +	id = ida_simple_get(&ifpga_sec_mgr_ida, 0, 0, GFP_KERNEL);
> +	if (id < 0) {
> +		ret = id;
> +		goto exit_free;
> +	}
> +
> +	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);
> +		ida_simple_remove(&ifpga_sec_mgr_ida, id);
> +		goto exit_free;
> +	}
> +
> +	ret = device_register(&imgr->dev);
> +	if (ret) {
> +		put_device(&imgr->dev);
> +		return ERR_PTR(ret);
> +	}
> +
> +	return imgr;
> +
> +exit_free:
> +	kfree(dev);
> +	return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_register);
> +
> +/**
> + * ifpga_sec_mgr_unregister - unregister a IFPGA security manager
> + *
> + * @mgr: fpga manager struct
> + *
> + * This function is intended for use in a IFPGA 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)
> +{
> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
> +
> +	mutex_destroy(&imgr->lock);
> +	ida_simple_remove(&ifpga_sec_mgr_ida, imgr->dev.id);
> +	kfree(imgr);
> +}
> +
> +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..e391b0c8f448
> --- /dev/null
> +++ b/include/linux/fpga/ifpga-sec-mgr.h
> @@ -0,0 +1,145 @@
> +/* 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;
> +
> +/**
> + * typedef sysfs_reh_size_t - Function to return byte size of root entry hash
> + *
> + * @imgr:      pointer to security manager structure
> + *
> + * This datatype is used to define a function that returns the byte size of a
> + * root entry hash.
> + *
> + * Context: No locking requirements are imposed by the security manager.
> + * Return:  Byte count on success, negative errno on failure
> + */
> +typedef int (*sysfs_reh_size_t)(struct ifpga_sec_mgr *imgr);
> +
> +/**
> + * typedef sysfs_reh_hndlr_t - Function pointer to sysfs file handler
> + *			       for root entry hashes
> + * @imgr:      pointer to security manager structure
> + * @hash:      pointer to an array of bytes in which to store the hash
> + * @size:      byte size of root entry hash
> + *
> + * This datatype is used to define a sysfs file handler function to
> + * return root entry hash data to be displayed via sysfs.
> + *
> + * Context: No locking requirements are imposed by the security manager.
> + * Return:  0 on success, negative errno on failure
> + */
> +typedef int (*sysfs_reh_hndlr_t)(struct ifpga_sec_mgr *imgr, u8 *hash,
> +				 unsigned int size);
> +
> +/**
> + * typedef sysfs_cnt_hndlr_t - Function pointer to sysfs file handler
> + *			       for flash counts
> + * @imgr: pointer to security manager structure
> + *
> + * This datatype is used to define a sysfs file handler function to
> + * return a flash count to be displayed via sysfs.
> + *
> + * Context: No locking requirements are imposed by the security manager
> + * Return: flash count or negative errno
> + */
> +typedef int (*sysfs_cnt_hndlr_t)(struct ifpga_sec_mgr *imgr);
> +
> +/**
> + * typedef sysfs_csk_nbits_t - Function to return the number of bits in
> + *				      a Code Signing Key cancellation vector
> + *
> + * @imgr:      pointer to security manager structure
> + *
> + * This datatype is used to define a function that returns the number of bits
> + * in a Code Signing Key cancellation vector.
> + *
> + * Context: No locking requirements are imposed by the security manager.
> + * Return:  Number of bits on success, negative errno on failure
> + */
> +typedef int (*sysfs_csk_nbits_t)(struct ifpga_sec_mgr *imgr);
> +
> +/**
> + * typedef sysfs_csk_hndlr_t - Function pointer to sysfs file handler
> + *			       bit vector of canceled keys
> + *
> + * @imgr:    pointer to security manager structure
> + * @csk_map: pointer to a bitmap to contain cancellation key vector
> + * @nbits:   number of bits in CSK vector
> + *
> + * This datatype is used to define a sysfs file handler function to
> + * return a bitmap of canceled keys to be displayed via sysfs.
> + *
> + * Context: No locking requirements are imposed by the security manager.
> + * Return:  0 on success, negative errno on failure
> + */
> +typedef int (*sysfs_csk_hndlr_t)(struct ifpga_sec_mgr *imgr,
> +				 unsigned long *csk_map, unsigned int nbits);
> +
> +/**
> + * struct ifpga_sec_mgr_ops - device specific operations
> + * @user_flash_count:	    Optional: Return sysfs string output for FPGA
> + *			    image flash count
> + * @bmc_flash_count:	    Optional: Return sysfs string output for BMC
> + *			    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 {
> +	sysfs_cnt_hndlr_t user_flash_count;
> +	sysfs_cnt_hndlr_t bmc_flash_count;
> +	sysfs_cnt_hndlr_t smbus_flash_count;
> +	sysfs_reh_hndlr_t sr_root_entry_hash;
> +	sysfs_reh_hndlr_t pr_root_entry_hash;
> +	sysfs_reh_hndlr_t bmc_root_entry_hash;
> +	sysfs_csk_hndlr_t sr_canceled_csks;
> +	sysfs_csk_hndlr_t pr_canceled_csks;
> +	sysfs_csk_hndlr_t bmc_canceled_csks;
> +	sysfs_reh_size_t bmc_reh_size;
> +	sysfs_reh_size_t sr_reh_size;
> +	sysfs_reh_size_t pr_reh_size;
> +	sysfs_csk_nbits_t bmc_canceled_csk_nbits;
> +	sysfs_csk_nbits_t sr_canceled_csk_nbits;
> +	sysfs_csk_nbits_t pr_canceled_csk_nbits;
> +};
> +
> +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_register(struct device *dev, const char *name,
> +		       const struct ifpga_sec_mgr_ops *iops, void *priv);
> +void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr);
> +
> +#endif
> -- 
> 2.17.1
> 

This will take me a while,

Thanks,
Moritz

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

* Re: [PATCH v1 01/12] fpga: fpga security manager class driver
  2020-09-05  0:23   ` Moritz Fischer
@ 2020-09-05  0:44     ` Russ Weight
  2020-09-05 13:39       ` Wu, Hao
  0 siblings, 1 reply; 57+ messages in thread
From: Russ Weight @ 2020-09-05  0:44 UTC (permalink / raw)
  To: Moritz Fischer
  Cc: lee.jones, linux-fpga, linux-kernel, trix, lgoncalv, yilun.xu,
	hao.wu, matthew.gerlach


On 9/4/20 5:23 PM, Moritz Fischer wrote:
> Hi Russ,
>
> On Fri, Sep 04, 2020 at 04:52:54PM -0700, 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>
> As for Reviewed-by tags I had seen on other patches in the series, I'd
> prefer for that to happen on public mailing lists. If Hao reviewed
> patches on some internal Intel list I won't know about it, so please
> have him properly Ack/Reviewed-by tag things on a public mailing list.

Sure - I'll remove the Ack/Reviewed-by tags that were added internally 
before I submit the next version of the patchset (except where Hao 
re-adds them on the public list during this review cycle).

>
>> ---
>>   .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  75 ++++
>>   MAINTAINERS                                   |   8 +
>>   drivers/fpga/Kconfig                          |   9 +
>>   drivers/fpga/Makefile                         |   3 +
>>   drivers/fpga/ifpga-sec-mgr.c                  | 339 ++++++++++++++++++
>>   include/linux/fpga/ifpga-sec-mgr.h            | 145 ++++++++
>>   6 files changed, 579 insertions(+)
>>   create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>   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..86f8992559bf
>> --- /dev/null
>> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> @@ -0,0 +1,75 @@
>> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/name
>> +Date:		Sep 2020
>> +KernelVersion:  5.10
>> +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:		Sep 2020
>> +KernelVersion:  5.10
>> +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:		Sep 2020
>> +KernelVersion:  5.10
>> +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:		Sep 2020
>> +KernelVersion:  5.10
>> +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:		Sep 2020
>> +KernelVersion:  5.10
>> +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:		Sep 2020
>> +KernelVersion:  5.10
>> +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:		Sep 2020
>> +KernelVersion:  5.10
>> +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:		Sep 2020
>> +KernelVersion:  5.10
>> +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: "%d".
>> +
>> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/bmc_flash_count
>> +Date:		Sep 2020
>> +KernelVersion:  5.10
>> +Contact:	Russ Weight <russell.h.weight@intel.com>
>> +Description:	Read only. Returns number of times the BMC image has been
>> +		flashed.
>> +		Format: "%d".
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index deaafb617361..4a2ebe6b120d 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -6830,6 +6830,14 @@ 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:	drivers/fpga/ifpga-sec-mgr.c
>> +F:	include/linux/fpga/ifpga-sec-mgr.h
> Generally not against having more people help out, but do we need a
> per driver maintainer?
>
>> +
>>   FPU EMULATOR
>>   M:	Bill Metzenthen <billm@melbpc.org.au>
>>   S:	Maintained
>> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
>> index 88f64fbf55e3..97c0a6cc2ba7 100644
>> --- a/drivers/fpga/Kconfig
>> +++ b/drivers/fpga/Kconfig
>> @@ -235,4 +235,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 c69bfc931519..ec9fbacdedd8 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..97bf80277ed2
>> --- /dev/null
>> +++ b/drivers/fpga/ifpga-sec-mgr.c
>> @@ -0,0 +1,339 @@
>> +// 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;
>> +
>> +static ssize_t show_canceled_csk(struct ifpga_sec_mgr *imgr,
>> +				 sysfs_csk_hndlr_t get_csk,
>> +				 sysfs_csk_nbits_t get_csk_nbits,
>> +				 char *buf)
>> +{
>> +	unsigned long *csk_map = NULL;
>> +	unsigned int nbits;
>> +	int cnt, 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;
>> +
>> +	cnt = bitmap_print_to_pagebuf(1, buf, csk_map, nbits);
>> +
>> +vfree_exit:
>> +	vfree(csk_map);
>> +	return ret ? : cnt;
>> +}
>> +
>> +static ssize_t show_root_entry_hash(struct ifpga_sec_mgr *imgr,
>> +				    sysfs_reh_hndlr_t get_reh,
>> +				    sysfs_reh_size_t get_reh_size,
>> +				    char *buf)
>> +{
>> +	unsigned int size, i;
>> +	int ret, cnt = 0;
>> +	u8 *hash;
>> +
>> +	ret = get_reh_size(imgr);
>> +	if (ret < 0)
>> +		return ret;
>> +	else if (!ret)
>> +		return sprintf(buf, "hash not programmed\n");
>> +
>> +	size = (unsigned int)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 to_sec_mgr(d) container_of(d, struct ifpga_sec_mgr, dev)
>> +
>> +#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)
>> +
>> +#define DEVICE_ATTR_SEC_FLASH_CNT(_name) \
>> +static ssize_t _name##_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->_name##_flash_count(imgr); \
>> +	return cnt < 0 ? cnt : sprintf(buf, "%d\n", cnt); \
>> +} \
>> +static DEVICE_ATTR_RO(_name##_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_FLASH_CNT(user);
>> +DEVICE_ATTR_SEC_FLASH_CNT(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_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));
>> +
>> +	if (check_attr(attr, user_flash_count) ||
>> +	    check_attr(attr, bmc_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)
>> +{
>> +	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_register - register an IFPGA security manager struct
>> + *
>> + * @dev:  create ifpga 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
>> + *
>> + * Returns &struct ifpga_sec_mgr pointer on success, or ERR_PTR() on error.
>> + */
>> +struct ifpga_sec_mgr *
>> +ifpga_sec_mgr_register(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 ERR_PTR(-EINVAL);
>> +	}
>> +
>> +	if (!name || !strlen(name)) {
>> +		dev_err(dev, "Attempt to register with no name!\n");
>> +		return ERR_PTR(-EINVAL);
>> +	}
>> +
>> +	imgr = kzalloc(sizeof(*imgr), GFP_KERNEL);
>> +	if (!imgr)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	imgr->name = name;
>> +	imgr->priv = priv;
>> +	imgr->iops = iops;
>> +	mutex_init(&imgr->lock);
>> +
>> +	id = ida_simple_get(&ifpga_sec_mgr_ida, 0, 0, GFP_KERNEL);
>> +	if (id < 0) {
>> +		ret = id;
>> +		goto exit_free;
>> +	}
>> +
>> +	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);
>> +		ida_simple_remove(&ifpga_sec_mgr_ida, id);
>> +		goto exit_free;
>> +	}
>> +
>> +	ret = device_register(&imgr->dev);
>> +	if (ret) {
>> +		put_device(&imgr->dev);
>> +		return ERR_PTR(ret);
>> +	}
>> +
>> +	return imgr;
>> +
>> +exit_free:
>> +	kfree(dev);
>> +	return ERR_PTR(ret);
>> +}
>> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_register);
>> +
>> +/**
>> + * ifpga_sec_mgr_unregister - unregister a IFPGA security manager
>> + *
>> + * @mgr: fpga manager struct
>> + *
>> + * This function is intended for use in a IFPGA 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)
>> +{
>> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
>> +
>> +	mutex_destroy(&imgr->lock);
>> +	ida_simple_remove(&ifpga_sec_mgr_ida, imgr->dev.id);
>> +	kfree(imgr);
>> +}
>> +
>> +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..e391b0c8f448
>> --- /dev/null
>> +++ b/include/linux/fpga/ifpga-sec-mgr.h
>> @@ -0,0 +1,145 @@
>> +/* 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;
>> +
>> +/**
>> + * typedef sysfs_reh_size_t - Function to return byte size of root entry hash
>> + *
>> + * @imgr:      pointer to security manager structure
>> + *
>> + * This datatype is used to define a function that returns the byte size of a
>> + * root entry hash.
>> + *
>> + * Context: No locking requirements are imposed by the security manager.
>> + * Return:  Byte count on success, negative errno on failure
>> + */
>> +typedef int (*sysfs_reh_size_t)(struct ifpga_sec_mgr *imgr);
>> +
>> +/**
>> + * typedef sysfs_reh_hndlr_t - Function pointer to sysfs file handler
>> + *			       for root entry hashes
>> + * @imgr:      pointer to security manager structure
>> + * @hash:      pointer to an array of bytes in which to store the hash
>> + * @size:      byte size of root entry hash
>> + *
>> + * This datatype is used to define a sysfs file handler function to
>> + * return root entry hash data to be displayed via sysfs.
>> + *
>> + * Context: No locking requirements are imposed by the security manager.
>> + * Return:  0 on success, negative errno on failure
>> + */
>> +typedef int (*sysfs_reh_hndlr_t)(struct ifpga_sec_mgr *imgr, u8 *hash,
>> +				 unsigned int size);
>> +
>> +/**
>> + * typedef sysfs_cnt_hndlr_t - Function pointer to sysfs file handler
>> + *			       for flash counts
>> + * @imgr: pointer to security manager structure
>> + *
>> + * This datatype is used to define a sysfs file handler function to
>> + * return a flash count to be displayed via sysfs.
>> + *
>> + * Context: No locking requirements are imposed by the security manager
>> + * Return: flash count or negative errno
>> + */
>> +typedef int (*sysfs_cnt_hndlr_t)(struct ifpga_sec_mgr *imgr);
>> +
>> +/**
>> + * typedef sysfs_csk_nbits_t - Function to return the number of bits in
>> + *				      a Code Signing Key cancellation vector
>> + *
>> + * @imgr:      pointer to security manager structure
>> + *
>> + * This datatype is used to define a function that returns the number of bits
>> + * in a Code Signing Key cancellation vector.
>> + *
>> + * Context: No locking requirements are imposed by the security manager.
>> + * Return:  Number of bits on success, negative errno on failure
>> + */
>> +typedef int (*sysfs_csk_nbits_t)(struct ifpga_sec_mgr *imgr);
>> +
>> +/**
>> + * typedef sysfs_csk_hndlr_t - Function pointer to sysfs file handler
>> + *			       bit vector of canceled keys
>> + *
>> + * @imgr:    pointer to security manager structure
>> + * @csk_map: pointer to a bitmap to contain cancellation key vector
>> + * @nbits:   number of bits in CSK vector
>> + *
>> + * This datatype is used to define a sysfs file handler function to
>> + * return a bitmap of canceled keys to be displayed via sysfs.
>> + *
>> + * Context: No locking requirements are imposed by the security manager.
>> + * Return:  0 on success, negative errno on failure
>> + */
>> +typedef int (*sysfs_csk_hndlr_t)(struct ifpga_sec_mgr *imgr,
>> +				 unsigned long *csk_map, unsigned int nbits);
>> +
>> +/**
>> + * struct ifpga_sec_mgr_ops - device specific operations
>> + * @user_flash_count:	    Optional: Return sysfs string output for FPGA
>> + *			    image flash count
>> + * @bmc_flash_count:	    Optional: Return sysfs string output for BMC
>> + *			    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 {
>> +	sysfs_cnt_hndlr_t user_flash_count;
>> +	sysfs_cnt_hndlr_t bmc_flash_count;
>> +	sysfs_cnt_hndlr_t smbus_flash_count;
>> +	sysfs_reh_hndlr_t sr_root_entry_hash;
>> +	sysfs_reh_hndlr_t pr_root_entry_hash;
>> +	sysfs_reh_hndlr_t bmc_root_entry_hash;
>> +	sysfs_csk_hndlr_t sr_canceled_csks;
>> +	sysfs_csk_hndlr_t pr_canceled_csks;
>> +	sysfs_csk_hndlr_t bmc_canceled_csks;
>> +	sysfs_reh_size_t bmc_reh_size;
>> +	sysfs_reh_size_t sr_reh_size;
>> +	sysfs_reh_size_t pr_reh_size;
>> +	sysfs_csk_nbits_t bmc_canceled_csk_nbits;
>> +	sysfs_csk_nbits_t sr_canceled_csk_nbits;
>> +	sysfs_csk_nbits_t pr_canceled_csk_nbits;
>> +};
>> +
>> +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_register(struct device *dev, const char *name,
>> +		       const struct ifpga_sec_mgr_ops *iops, void *priv);
>> +void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr);
>> +
>> +#endif
>> -- 
>> 2.17.1
>>
> This will take me a while,
>
> Thanks,
> Moritz

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

* RE: [PATCH v1 01/12] fpga: fpga security manager class driver
  2020-09-05  0:44     ` Russ Weight
@ 2020-09-05 13:39       ` Wu, Hao
  0 siblings, 0 replies; 57+ messages in thread
From: Wu, Hao @ 2020-09-05 13:39 UTC (permalink / raw)
  To: Weight, Russell H, Moritz Fischer
  Cc: lee.jones, linux-fpga, linux-kernel, trix, lgoncalv, Xu, Yilun,
	Gerlach, Matthew

> On 9/4/20 5:23 PM, Moritz Fischer wrote:
> > Hi Russ,
> >
> > On Fri, Sep 04, 2020 at 04:52:54PM -0700, 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>
> > As for Reviewed-by tags I had seen on other patches in the series, I'd
> > prefer for that to happen on public mailing lists. If Hao reviewed
> > patches on some internal Intel list I won't know about it, so please
> > have him properly Ack/Reviewed-by tag things on a public mailing list.
> 
> Sure - I'll remove the Ack/Reviewed-by tags that were added internally
> before I submit the next version of the patchset (except where Hao
> re-adds them on the public list during this review cycle).

Yes, please remove it to avoid confusing. I haven't looked at the latest code yet.
Anyway, let's follow up this in public mailing list.

Thanks
Hao

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

* RE: [PATCH v1 00/12] Intel FPGA Security Manager Class Driver
  2020-09-04 23:52 [PATCH v1 00/12] Intel FPGA Security Manager Class Driver Russ Weight
                   ` (11 preceding siblings ...)
  2020-09-04 23:53 ` [PATCH v1 12/12] fpga: add max10 get_hw_errinfo callback func Russ Weight
@ 2020-09-05 14:13 ` Wu, Hao
  2020-10-01 20:42   ` Russ Weight
  2020-09-05 16:10 ` Tom Rix
  2020-09-05 17:16 ` Tom Rix
  14 siblings, 1 reply; 57+ messages in thread
From: Wu, Hao @ 2020-09-05 14:13 UTC (permalink / raw)
  To: Weight, Russell H, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, Xu, Yilun, Gerlach, Matthew

> Subject: [PATCH v1 00/12] Intel FPGA Security Manager Class Driver
> 
> 
> These patches depend on the patchset: "add regmap-spi-avmm & Intel
> Max10 BMC chip support" which is currently under review.
> 
>            --------------------------------------------------
> 
> This patchset introduces the Intel Security Manager class driver
> for managing secure updates on Intel FPGA Cards. It also provides
> the n3000bmc-secure mfd sub-driver for the MAX10 BMC for the n3000
> Programmable Acceleration Cards (PAC). The n3000bmc-secure driver
> is implemented using the Intel Security Manager class driver.

So this patchset contains two parts
(1) adding a new class driver for Intel FPGA secure update.
(2) a new driver which uses (1) to implement secure update for n3000 PAC.

And only part (2) depends on "Intel MAX10 BMC chip support" patchset.
(Maybe you can provide a link to that thread). 

Is my understanding correct? If yes, is it possible to reorder these patches?
At least there is no dependency on the class driver patches, right?

> 
> The Intel Security Manager class driver provides a common API for
> user-space tools to manage updates for Secure FPGA devices. Device
> drivers that instantiate the Intel Security Manager class driver will
> interact with the 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.
> 
> 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.
> 
> 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.

Maybe you can explain a little more on why we need to have this done
via a class driver not just some internal code in max10 driver? This class
driver will be reused in different cases? And why adding a new class
driver not just reuse or extend fpga manager (existing fpga mgr is used
to update fpga too).

> 
> The n3000bmc-secure driver instantiates the Intel Security Manager
> class driver and provides the callback functions required to support
> secure updates on Intel n3000 PAC devices.
> 
> Russ Weight (12):
>   fpga: fpga security manager class driver

Intel FPGA Security Manager?

>   fpga: create intel max10 bmc security engine
>   fpga: expose max10 flash update counts in sysfs
>   fpga: expose max10 canceled keys in sysfs
>   fpga: enable secure updates
>   fpga: add max10 secure update functions
>   fpga: expose sec-mgr update status
>   fpga: expose sec-mgr update errors
>   fpga: expose sec-mgr update size
>   fpga: enable sec-mgr update cancel
>   fpga: expose hardware error info in sysfs

For these patches, is it possible to have a better title for these patches.
Then it will be easier to know which component this patch is going to modify.
e.g. fpga: ifpga-sec-mgr: xxxxxx

Thanks
Hao

>   fpga: add max10 get_hw_errinfo callback func
> 
>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 151 ++++
>  MAINTAINERS                                   |   8 +
>  drivers/fpga/Kconfig                          |  20 +
>  drivers/fpga/Makefile                         |   6 +
>  drivers/fpga/ifpga-sec-mgr.c                  | 669 ++++++++++++++++++
>  drivers/fpga/intel-m10-bmc-secure.c           | 557 +++++++++++++++
>  include/linux/fpga/ifpga-sec-mgr.h            | 201 ++++++
>  include/linux/mfd/intel-m10-bmc.h             | 116 +++
>  8 files changed, 1728 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>  create mode 100644 drivers/fpga/ifpga-sec-mgr.c
>  create mode 100644 drivers/fpga/intel-m10-bmc-secure.c
>  create mode 100644 include/linux/fpga/ifpga-sec-mgr.h
> 
> --
> 2.17.1


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

* Re: [PATCH v1 00/12] Intel FPGA Security Manager Class Driver
  2020-09-04 23:52 [PATCH v1 00/12] Intel FPGA Security Manager Class Driver Russ Weight
                   ` (12 preceding siblings ...)
  2020-09-05 14:13 ` [PATCH v1 00/12] Intel FPGA Security Manager Class Driver Wu, Hao
@ 2020-09-05 16:10 ` Tom Rix
  2020-09-05 17:16 ` Tom Rix
  14 siblings, 0 replies; 57+ messages in thread
From: Tom Rix @ 2020-09-05 16:10 UTC (permalink / raw)
  To: Russ Weight, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 9/4/20 4:52 PM, Russ Weight wrote:
> These patches depend on the patchset: "add regmap-spi-avmm & Intel
> Max10 BMC chip support" which is currently under review.

https://marc.info/?l=linux-kernel&m=159782274232229&w=2

regmap-spi-avmm is in linux-next.

max10 is not. however applying it does not resolve resolve git am conflicts with yesterday's linux-next.  I normally build the larger patchsets as a test.

>            --------------------------------------------------
>
> This patchset introduces the Intel Security Manager class driver
> for managing secure updates on Intel FPGA Cards. It also provides
> the n3000bmc-secure mfd sub-driver for the MAX10 BMC for the n3000
> Programmable Acceleration Cards (PAC). The n3000bmc-secure driver
> is implemented using the Intel Security Manager class driver.
>
> The Intel Security Manager class driver provides a common API for
> user-space tools to manage updates for Secure FPGA devices. Device
> drivers that instantiate the Intel Security Manager class driver will
> interact with the 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.
>
> 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.
>
> 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 n3000bmc-secure driver instantiates the Intel Security Manager
> class driver and provides the callback functions required to support
> secure updates on Intel n3000 PAC devices.

This is a good description.  Because security manager is a new interface, there should be a Documentation/fpga/ifpga-sec-mgr.rst to collect this description.

How will these devices be discovered ? n3000 is a dfl device, will there be a dfl feature id for it at some point ? 

Can you describe if/how the security manager would live outside of dfl ?  I am wondering why this shouldn't be dfl-sec-mgr. 

I did not see any version handling.  How would this sw adapt to a newer or older version of the bmc interface?

Tom

>
> Russ Weight (12):
>   fpga: fpga security manager class driver
>   fpga: create intel max10 bmc security engine
>   fpga: expose max10 flash update counts in sysfs
>   fpga: expose max10 canceled keys in sysfs
>   fpga: enable secure updates
>   fpga: add max10 secure update functions
>   fpga: expose sec-mgr update status
>   fpga: expose sec-mgr update errors
>   fpga: expose sec-mgr update size
>   fpga: enable sec-mgr update cancel
>   fpga: expose hardware error info in sysfs
>   fpga: add max10 get_hw_errinfo callback func
>
>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 151 ++++
>  MAINTAINERS                                   |   8 +
>  drivers/fpga/Kconfig                          |  20 +
>  drivers/fpga/Makefile                         |   6 +
>  drivers/fpga/ifpga-sec-mgr.c                  | 669 ++++++++++++++++++
>  drivers/fpga/intel-m10-bmc-secure.c           | 557 +++++++++++++++
>  include/linux/fpga/ifpga-sec-mgr.h            | 201 ++++++
>  include/linux/mfd/intel-m10-bmc.h             | 116 +++
>  8 files changed, 1728 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>  create mode 100644 drivers/fpga/ifpga-sec-mgr.c
>  create mode 100644 drivers/fpga/intel-m10-bmc-secure.c
>  create mode 100644 include/linux/fpga/ifpga-sec-mgr.h
>


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

* Re: [PATCH v1 00/12] Intel FPGA Security Manager Class Driver
  2020-09-04 23:52 [PATCH v1 00/12] Intel FPGA Security Manager Class Driver Russ Weight
                   ` (13 preceding siblings ...)
  2020-09-05 16:10 ` Tom Rix
@ 2020-09-05 17:16 ` Tom Rix
  2020-10-01  0:19   ` Russ Weight
  14 siblings, 1 reply; 57+ messages in thread
From: Tom Rix @ 2020-09-05 17:16 UTC (permalink / raw)
  To: linux-kernel, linux-fpga

resending.
sorry for blowing past 80 chars.

On 9/4/20 4:52 PM, Russ Weight wrote:
> These patches depend on the patchset: "add regmap-spi-avmm & Intel
> Max10 BMC chip support" which is currently under review.

https://marc.info/?l=linux-kernel&m=159782274232229&w=2

regmap-spi-avmm is in linux-next.

max10 is not. however applying it does not resolve resolve
git am conflicts with yesterday's linux-next.
I normally build the larger patchsets as a test.

>
>            --------------------------------------------------
>
> This patchset introduces the Intel Security Manager class driver
> for managing secure updates on Intel FPGA Cards. It also provides
> the n3000bmc-secure mfd sub-driver for the MAX10 BMC for the n3000
> Programmable Acceleration Cards (PAC). The n3000bmc-secure driver
> is implemented using the Intel Security Manager class driver.
>
> The Intel Security Manager class driver provides a common API for
> user-space tools to manage updates for Secure FPGA devices. Device
> drivers that instantiate the Intel Security Manager class driver will
> interact with the 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.
>
> 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.
>
> 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 n3000bmc-secure driver instantiates the Intel Security Manager
> class driver and provides the callback functions required to support
> secure updates on Intel n3000 PAC devices.

This is a good description.  Because security manager is a new
interface, there should be a Documentation/fpga/ifpga-sec-mgr.rst
to collect this description.

How will these devices be discovered ? n3000 is a dfl device,
will there be a dfl feature id for it at some point ? 

Can you describe if/how the security manager would live outside
of dfl ?  I am wondering why this shouldn't be dfl-sec-mgr. 

I did not see any version handling.  How would this sw adapt
to a newer or older version of the bmc interface?

Tom

>
> Russ Weight (12):
>   fpga: fpga security manager class driver
>   fpga: create intel max10 bmc security engine
>   fpga: expose max10 flash update counts in sysfs
>   fpga: expose max10 canceled keys in sysfs
>   fpga: enable secure updates
>   fpga: add max10 secure update functions
>   fpga: expose sec-mgr update status
>   fpga: expose sec-mgr update errors
>   fpga: expose sec-mgr update size
>   fpga: enable sec-mgr update cancel
>   fpga: expose hardware error info in sysfs
>   fpga: add max10 get_hw_errinfo callback func
>
>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 151 ++++
>  MAINTAINERS                                   |   8 +
>  drivers/fpga/Kconfig                          |  20 +
>  drivers/fpga/Makefile                         |   6 +
>  drivers/fpga/ifpga-sec-mgr.c                  | 669 ++++++++++++++++++
>  drivers/fpga/intel-m10-bmc-secure.c           | 557 +++++++++++++++
>  include/linux/fpga/ifpga-sec-mgr.h            | 201 ++++++
>  include/linux/mfd/intel-m10-bmc.h             | 116 +++
>  8 files changed, 1728 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>  create mode 100644 drivers/fpga/ifpga-sec-mgr.c
>  create mode 100644 drivers/fpga/intel-m10-bmc-secure.c
>  create mode 100644 include/linux/fpga/ifpga-sec-mgr.h
>


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

* Re: [PATCH v1 01/12] fpga: fpga security manager class driver
  2020-09-04 23:52 ` [PATCH v1 01/12] fpga: fpga security manager class driver Russ Weight
  2020-09-04 23:57   ` Randy Dunlap
  2020-09-05  0:23   ` Moritz Fischer
@ 2020-09-05 19:09   ` Tom Rix
       [not found]     ` <ebf251a0-5f13-d1a1-6915-e3c940bb19fe@intel.com>
  2020-09-16 20:16   ` Moritz Fischer
  3 siblings, 1 reply; 57+ messages in thread
From: Tom Rix @ 2020-09-05 19:09 UTC (permalink / raw)
  To: Russ Weight, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 9/4/20 4:52 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>
> ---
>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  75 ++++
>  MAINTAINERS                                   |   8 +
>  drivers/fpga/Kconfig                          |   9 +
>  drivers/fpga/Makefile                         |   3 +
>  drivers/fpga/ifpga-sec-mgr.c                  | 339 ++++++++++++++++++
>  include/linux/fpga/ifpga-sec-mgr.h            | 145 ++++++++
>  6 files changed, 579 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>  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..86f8992559bf
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> @@ -0,0 +1,75 @@
> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/name
> +Date:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
> +KernelVersion:  5.10
> +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: "%d".
could this be %u ?
> +
> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/bmc_flash_count
> +Date:		Sep 2020
> +KernelVersion:  5.10
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Read only. Returns number of times the BMC image has been
> +		flashed.
> +		Format: "%d".
> diff --git a/MAINTAINERS b/MAINTAINERS
> index deaafb617361..4a2ebe6b120d 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -6830,6 +6830,14 @@ 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:	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 88f64fbf55e3..97c0a6cc2ba7 100644
> --- a/drivers/fpga/Kconfig
> +++ b/drivers/fpga/Kconfig
> @@ -235,4 +235,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 c69bfc931519..ec9fbacdedd8 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..97bf80277ed2
> --- /dev/null
> +++ b/drivers/fpga/ifpga-sec-mgr.c
> @@ -0,0 +1,339 @@
> +// 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;
> +
> +static ssize_t show_canceled_csk(struct ifpga_sec_mgr *imgr,
> +				 sysfs_csk_hndlr_t get_csk,
> +				 sysfs_csk_nbits_t get_csk_nbits,

Param 2&3 can be accessed by imgr->iops so the signature

of this and similar functions should be reduced.

> +				 char *buf)
> +{
> +	unsigned long *csk_map = NULL;
> +	unsigned int nbits;
> +	int cnt, ret;
> +
> +	ret = get_csk_nbits(imgr);

Any access to a function pointer must check if the

the pointer is valid.

> +	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);

The type of returned by get_csk_nbits and its use should

be consistent. likely this is 'int'

> +	if (ret)
> +		goto vfree_exit;
> +
> +	cnt = bitmap_print_to_pagebuf(1, buf, csk_map, nbits);

simplify to

ret = ..


> +
> +vfree_exit:
> +	vfree(csk_map);
> +	return ret ? : cnt;
> +}
> +
> +static ssize_t show_root_entry_hash(struct ifpga_sec_mgr *imgr,
> +				    sysfs_reh_hndlr_t get_reh,
> +				    sysfs_reh_size_t get_reh_size,
> +				    char *buf)
> +{
> +	unsigned int size, i;
> +	int ret, cnt = 0;
> +	u8 *hash;
> +
> +	ret = get_reh_size(imgr);
> +	if (ret < 0)
> +		return ret;
> +	else if (!ret)
> +		return sprintf(buf, "hash not programmed\n");
> +
> +	size = (unsigned int)ret;
does size and i need to unsigned?
> +	hash = vmalloc(size);
> +	if (!hash)
> +		return -ENOMEM;
> +
> +	ret = get_reh(imgr, hash, size);
> +	if (ret)
> +		goto vfree_exit;

ret is 0 here

so simplify replacing cnt with ret.

> +
> +	cnt += sprintf(buf, "0x");
or change += to =, this is the first time sprintf is done.
> +	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;

with simplification this should be

return ret;

> +}
> +
> +#define to_sec_mgr(d) container_of(d, struct ifpga_sec_mgr, dev)
Since this is used widely move closer to top of file.
> +
> +#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)
> +
> +#define DEVICE_ATTR_SEC_FLASH_CNT(_name) \
> +static ssize_t _name##_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->_name##_flash_count(imgr); \
> +	return cnt < 0 ? cnt : sprintf(buf, "%d\n", cnt); \
> +} \
> +static DEVICE_ATTR_RO(_name##_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_FLASH_CNT(user);
> +DEVICE_ATTR_SEC_FLASH_CNT(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_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));
> +
> +	if (check_attr(attr, user_flash_count) ||
> +	    check_attr(attr, bmc_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;
> +

This is all or nothing, shouldn't the interface

allow for null iop ?

> +	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)
> +{
> +	if (sysfs_handler) {

These two checks can be simplified to

if (!sysfs_handler || !size_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_register - register an IFPGA security manager struct
> + *
> + * @dev:  create ifpga 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
> + *
> + * Returns &struct ifpga_sec_mgr pointer on success, or ERR_PTR() on error.
> + */
> +struct ifpga_sec_mgr *
> +ifpga_sec_mgr_register(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 ERR_PTR(-EINVAL);
> +	}
> +
> +	if (!name || !strlen(name)) {
> +		dev_err(dev, "Attempt to register with no name!\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	imgr = kzalloc(sizeof(*imgr), GFP_KERNEL);
> +	if (!imgr)
> +		return ERR_PTR(-ENOMEM);
> +
> +	imgr->name = name;
should name be dup-ed?
> +	imgr->priv = priv;
> +	imgr->iops = iops;
> +	mutex_init(&imgr->lock);
> +
> +	id = ida_simple_get(&ifpga_sec_mgr_ida, 0, 0, GFP_KERNEL);
> +	if (id < 0) {
> +		ret = id;
> +		goto exit_free;
> +	}
> +
> +	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);
> +		ida_simple_remove(&ifpga_sec_mgr_ida, id);
> +		goto exit_free;
> +	}
> +
> +	ret = device_register(&imgr->dev);
> +	if (ret) {
> +		put_device(&imgr->dev);
> +		return ERR_PTR(ret);
> +	}
> +
> +	return imgr;
> +
> +exit_free:
> +	kfree(dev);
> +	return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_register);
> +
> +/**
> + * ifpga_sec_mgr_unregister - unregister a IFPGA security manager
> + *
> + * @mgr: fpga manager struct
> + *
> + * This function is intended for use in a IFPGA 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)
> +{
> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
> +
> +	mutex_destroy(&imgr->lock);
> +	ida_simple_remove(&ifpga_sec_mgr_ida, imgr->dev.id);
> +	kfree(imgr);
> +}
> +
> +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..e391b0c8f448
> --- /dev/null
> +++ b/include/linux/fpga/ifpga-sec-mgr.h
> @@ -0,0 +1,145 @@
> +/* 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;
> +
> +/**
> + * typedef sysfs_reh_size_t - Function to return byte size of root entry hash
> + *
> + * @imgr:      pointer to security manager structure
> + *
> + * This datatype is used to define a function that returns the byte size of a
> + * root entry hash.
> + *
> + * Context: No locking requirements are imposed by the security manager.
> + * Return:  Byte count on success, negative errno on failure
> + */
> +typedef int (*sysfs_reh_size_t)(struct ifpga_sec_mgr *imgr);
> +
> +/**
> + * typedef sysfs_reh_hndlr_t - Function pointer to sysfs file handler
> + *			       for root entry hashes
> + * @imgr:      pointer to security manager structure
> + * @hash:      pointer to an array of bytes in which to store the hash
> + * @size:      byte size of root entry hash
> + *
> + * This datatype is used to define a sysfs file handler function to
> + * return root entry hash data to be displayed via sysfs.
> + *
> + * Context: No locking requirements are imposed by the security manager.
> + * Return:  0 on success, negative errno on failure
> + */
> +typedef int (*sysfs_reh_hndlr_t)(struct ifpga_sec_mgr *imgr, u8 *hash,
> +				 unsigned int size);
> +
> +/**
> + * typedef sysfs_cnt_hndlr_t - Function pointer to sysfs file handler
> + *			       for flash counts
> + * @imgr: pointer to security manager structure
> + *
> + * This datatype is used to define a sysfs file handler function to
> + * return a flash count to be displayed via sysfs.
> + *
> + * Context: No locking requirements are imposed by the security manager
> + * Return: flash count or negative errno
> + */
> +typedef int (*sysfs_cnt_hndlr_t)(struct ifpga_sec_mgr *imgr);
> +
> +/**
> + * typedef sysfs_csk_nbits_t - Function to return the number of bits in
> + *				      a Code Signing Key cancellation vector
> + *
> + * @imgr:      pointer to security manager structure
> + *
> + * This datatype is used to define a function that returns the number of bits
> + * in a Code Signing Key cancellation vector.
> + *
> + * Context: No locking requirements are imposed by the security manager.
> + * Return:  Number of bits on success, negative errno on failure
> + */
> +typedef int (*sysfs_csk_nbits_t)(struct ifpga_sec_mgr *imgr);
> +
> +/**
> + * typedef sysfs_csk_hndlr_t - Function pointer to sysfs file handler
> + *			       bit vector of canceled keys
> + *
> + * @imgr:    pointer to security manager structure
> + * @csk_map: pointer to a bitmap to contain cancellation key vector
> + * @nbits:   number of bits in CSK vector
> + *
> + * This datatype is used to define a sysfs file handler function to
> + * return a bitmap of canceled keys to be displayed via sysfs.
> + *
> + * Context: No locking requirements are imposed by the security manager.
> + * Return:  0 on success, negative errno on failure
> + */
> +typedef int (*sysfs_csk_hndlr_t)(struct ifpga_sec_mgr *imgr,
> +				 unsigned long *csk_map, unsigned int nbits);
> +
> +/**
> + * struct ifpga_sec_mgr_ops - device specific operations
> + * @user_flash_count:	    Optional: Return sysfs string output for FPGA
> + *			    image flash count
> + * @bmc_flash_count:	    Optional: Return sysfs string output for BMC
> + *			    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 {
> +	sysfs_cnt_hndlr_t user_flash_count;

These typedef's hide the function signatures and are

not consistent with how the other headers in include/linux/fpga

specify ops.

> +	sysfs_cnt_hndlr_t bmc_flash_count;
> +	sysfs_cnt_hndlr_t smbus_flash_count;
> +	sysfs_reh_hndlr_t sr_root_entry_hash;
> +	sysfs_reh_hndlr_t pr_root_entry_hash;
> +	sysfs_reh_hndlr_t bmc_root_entry_hash;
> +	sysfs_csk_hndlr_t sr_canceled_csks;
> +	sysfs_csk_hndlr_t pr_canceled_csks;
> +	sysfs_csk_hndlr_t bmc_canceled_csks;
> +	sysfs_reh_size_t bmc_reh_size;
> +	sysfs_reh_size_t sr_reh_size;
> +	sysfs_reh_size_t pr_reh_size;
> +	sysfs_csk_nbits_t bmc_canceled_csk_nbits;
> +	sysfs_csk_nbits_t sr_canceled_csk_nbits;
> +	sysfs_csk_nbits_t pr_canceled_csk_nbits;
> +};
> +
> +struct ifpga_sec_mgr {
> +	const char *name;
> +	struct device dev;
> +	const struct ifpga_sec_mgr_ops *iops;
> +	struct mutex lock;		/* protect data structure contents */

comment is redundant for a lock.

Tom

> +	void *priv;
> +};
> +
> +struct ifpga_sec_mgr *
> +ifpga_sec_mgr_register(struct device *dev, const char *name,
> +		       const struct ifpga_sec_mgr_ops *iops, void *priv);
> +void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr);
> +
> +#endif


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

* Re: [PATCH v1 02/12] fpga: create intel max10 bmc security engine
  2020-09-04 23:52 ` [PATCH v1 02/12] fpga: create intel max10 bmc security engine Russ Weight
  2020-09-05  0:01   ` Randy Dunlap
@ 2020-09-05 20:22   ` Tom Rix
  2020-09-14 19:07     ` Russ Weight
  2020-09-16 20:33   ` Moritz Fischer
  2 siblings, 1 reply; 57+ messages in thread
From: Tom Rix @ 2020-09-05 20:22 UTC (permalink / raw)
  To: Russ Weight, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 9/4/20 4:52 PM, Russ Weight wrote:
> Create a platform driver that can be invoked as a sub
> driver for the Intel MAX10 BMC in order to support
> secure updates. This sub-driver will invoke an
> instance of the Intel FPGA Security Manager class driver
> in order to expose sysfs interfaces for managing and
> monitoring secure updates to FPGA and BMC images.
>
> This patch creates the MAX10 BMC Security Engine driver and
> provides support for displaying the current root entry hashes
> for the FPGA static region, the FPGA PR region, and the MAX10
> BMC.
>
> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
> Reviewed-by: Wu Hao <hao.wu@intel.com>
> ---
>  drivers/fpga/Kconfig                |  11 ++
>  drivers/fpga/Makefile               |   3 +
>  drivers/fpga/intel-m10-bmc-secure.c | 170 ++++++++++++++++++++++++++++
>  include/linux/mfd/intel-m10-bmc.h   |  15 +++
>  4 files changed, 199 insertions(+)
>  create mode 100644 drivers/fpga/intel-m10-bmc-secure.c
>
> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> index 97c0a6cc2ba7..0f0bed68e618 100644
> --- a/drivers/fpga/Kconfig
> +++ b/drivers/fpga/Kconfig
> @@ -244,4 +244,15 @@ config IFPGA_SEC_MGR
>  	  region and for the BMC. Select this option to enable
>  	  updates for secure FPGA devices.
>  
> +config IFPGA_M10_BMC_SECURE
> +        tristate "Intel MAX10 BMC security engine"
> +	depends on MFD_INTEL_M10_BMC && IFPGA_SEC_MGR
> +        help
> +          Secure update support for the Intel MAX10 board management
> +	  controller.
> +
> +	  This is a subdriver of the Intel MAX10 board management controller
> +	  (BMC) and provides support for secure updates for the BMC image,
> +	  the FPGA image, the Root Entry Hashes, etc.
> +
>  endif # FPGA
> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
> index ec9fbacdedd8..451a23ec3168 100644
> --- a/drivers/fpga/Makefile
> +++ b/drivers/fpga/Makefile
> @@ -24,6 +24,9 @@ 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
>  
> +# Intel Security Manager Drivers
> +obj-$(CONFIG_IFPGA_M10_BMC_SECURE)	+= intel-m10-bmc-secure.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/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c
> new file mode 100644
> index 000000000000..1f86bfb694b4
> --- /dev/null
> +++ b/drivers/fpga/intel-m10-bmc-secure.c
> @@ -0,0 +1,170 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Intel Max10 Board Management Controller Security Engine Driver
> + *
> + * Copyright (C) 2019-2020 Intel Corporation. All rights reserved.
> + *
> + */
> +#include <linux/device.h>
> +#include <linux/fpga/ifpga-sec-mgr.h>
> +#include <linux/mfd/intel-m10-bmc.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/vmalloc.h>
> +
> +struct m10bmc_sec {
> +	struct device *dev;
> +	struct intel_m10bmc *m10bmc;
> +	struct ifpga_sec_mgr *imgr;
> +};
> +
> +#define SHA256_REH_SIZE		32
> +#define SHA384_REH_SIZE		48
> +
> +static int get_reh_size(struct ifpga_sec_mgr *imgr,
> +			u32 exp_magic, u32 prog_addr)
> +{
> +	struct m10bmc_sec *sec = imgr->priv;
> +	int sha_num_bytes, ret;
> +	u32 magic;
> +
> +	ret = m10bmc_raw_read(sec->m10bmc, prog_addr, &magic);
> +	if (ret)
> +		return ret;
> +
> +	dev_dbg(sec->dev, "%s magic 0x%08x\n", __func__, magic);
> +
> +	if ((magic & 0xffff) != exp_magic)
return -EINVAL ?
> +		return 0;
> +
> +	sha_num_bytes = ((magic >> 16) & 0xffff) / 8;
> +
> +	if (sha_num_bytes != SHA256_REH_SIZE &&
> +	    sha_num_bytes != SHA384_REH_SIZE)   {
> +		dev_err(sec->dev, "%s bad sha num bytes %d\n", __func__,
> +			sha_num_bytes);
> +		return -EINVAL;
> +	}
> +
> +	return sha_num_bytes;
> +}
> +
> +#define BMC_REH_ADDR 0x17ffc004
> +#define BMC_PROG_ADDR 0x17ffc000
> +#define BMC_PROG_MAGIC 0x5746
> +
> +#define SR_REH_ADDR 0x17ffd004
> +#define SR_PROG_ADDR 0x17ffd000
> +#define SR_PROG_MAGIC 0x5253
> +
> +#define PR_REH_ADDR 0x17ffe004
> +#define PR_PROG_ADDR 0x17ffe000
> +#define PR_PROG_MAGIC 0x5250
Why shouldn't these #defines be collected in the intel-m10-bmc.h ?
> +
> +#define SYSFS_GET_REH_SIZE(_name, _exp_magic, _prog_addr) \
> +static int get_##_name##_reh_size(struct ifpga_sec_mgr *imgr) \
> +{ \
> +	return get_reh_size(imgr, _exp_magic, _prog_addr); \
> +}
Is this macro overkill for a 1 liner ?
> +
> +SYSFS_GET_REH_SIZE(bmc, BMC_PROG_MAGIC, BMC_PROG_ADDR)
> +SYSFS_GET_REH_SIZE(sr, SR_PROG_MAGIC, SR_PROG_ADDR)
> +SYSFS_GET_REH_SIZE(pr, PR_PROG_MAGIC, PR_PROG_ADDR)

These and similar below do not directly interact

with the sysfs so the sysfs_ prefix should not be needed.

> +
> +static int get_root_entry_hash(struct ifpga_sec_mgr *imgr,
> +			       u32 hash_addr, u8 *hash,
> +			       unsigned int size)
> +{
> +	struct m10bmc_sec *sec = imgr->priv;
> +	unsigned int stride = regmap_get_reg_stride(sec->m10bmc->regmap);
> +	int ret;
> +
> +	ret = m10bmc_raw_bulk_read(sec->m10bmc, hash_addr,
> +				   hash, size / stride);
> +	if (ret)
> +		dev_err(sec->dev, "bulk_read of 0x%x failed %d",
> +			hash_addr, ret);
> +
> +	return ret;
> +}
> +
> +#define SYSFS_GET_REH(_name, _hash_addr) \
> +static int get_##_name##_root_entry_hash(struct ifpga_sec_mgr *imgr, \
> +					 u8 *hash, unsigned int size) \
> +{ \
> +	return get_root_entry_hash(imgr, _hash_addr, hash, size); \
> +}
> +
> +SYSFS_GET_REH(bmc, BMC_REH_ADDR)
> +SYSFS_GET_REH(sr, SR_REH_ADDR)
> +SYSFS_GET_REH(pr, PR_REH_ADDR)
> +
> +static const struct ifpga_sec_mgr_ops m10bmc_iops = {
> +	.bmc_root_entry_hash = get_bmc_root_entry_hash,
> +	.sr_root_entry_hash = get_sr_root_entry_hash,
> +	.pr_root_entry_hash = get_pr_root_entry_hash,
> +	.bmc_reh_size = get_bmc_reh_size,
> +	.sr_reh_size = get_sr_reh_size,
> +	.pr_reh_size = get_pr_reh_size,

The prefix of the ops should be similar to the file name.

so consider changing get_pr_reh_size to max10_pr_reh_size

> +};
> +
> +static void ifpga_sec_mgr_uinit(struct m10bmc_sec *sec)
> +{
> +	ifpga_sec_mgr_unregister(sec->imgr);
> +}
> +
> +static int ifpga_sec_mgr_init(struct m10bmc_sec *sec)
> +{
> +	struct ifpga_sec_mgr *imgr;
> +
> +	imgr = ifpga_sec_mgr_register(sec->dev, "Max10 BMC Security Manager",
> +				      &m10bmc_iops, sec);
> +	if (IS_ERR(imgr))
> +		return PTR_ERR(imgr);
> +
> +	sec->imgr = imgr;
> +	return 0;
> +}
> +
> +static int m10bmc_secure_probe(struct platform_device *pdev)
> +{
> +	struct m10bmc_sec *sec;
> +	int ret;
> +
> +	sec = devm_kzalloc(&pdev->dev, sizeof(*sec), GFP_KERNEL);
> +	if (!sec)
> +		return -ENOMEM;
> +
> +	sec->dev = &pdev->dev;
> +	sec->m10bmc = dev_get_drvdata(pdev->dev.parent);
> +	dev_set_drvdata(&pdev->dev, sec);
> +
> +	ret = ifpga_sec_mgr_init(sec);
> +	if (ret)
> +		dev_err(&pdev->dev,
> +			"Security manager failed to start: %d\n", ret);
> +
> +	return ret;
> +}
> +
> +static int m10bmc_secure_remove(struct platform_device *pdev)
> +{
> +	struct m10bmc_sec *sec = dev_get_drvdata(&pdev->dev);
> +
> +	ifpga_sec_mgr_uinit(sec);
> +	return 0;
> +}
> +
> +static struct platform_driver intel_m10bmc_secure_driver = {
> +	.probe = m10bmc_secure_probe,
> +	.remove = m10bmc_secure_remove,
> +	.driver = {
> +		.name = "n3000bmc-secure",

From the filename, should this be "max10bmc-secure" ?

> +	},
> +};
> +module_platform_driver(intel_m10bmc_secure_driver);
> +
> +MODULE_ALIAS("platform:n3000bmc-secure");
> +MODULE_AUTHOR("Intel Corporation");
> +MODULE_DESCRIPTION("Intel MAX10 BMC secure engine");
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h
> index d4cb01b73357..7fe465c320c2 100644
> --- a/include/linux/mfd/intel-m10-bmc.h
> +++ b/include/linux/mfd/intel-m10-bmc.h
> @@ -63,6 +63,7 @@ struct intel_m10bmc {
>   * register access helper functions.
>   *
>   * m10bmc_raw_read - read m10bmc register per addr
> + * m10bmc_raw_bulk_read - bulk_read max10 registers per addr

second '_' should be removed so it reads like

bulk read max10 registers..

Tom

>   * m10bmc_sys_read - read m10bmc system register per offset
>   */
>  static inline int
> @@ -79,6 +80,20 @@ m10bmc_raw_read(struct intel_m10bmc *m10bmc, unsigned int addr,
>  	return ret;
>  }
>  
> +static inline int
> +m10bmc_raw_bulk_read(struct intel_m10bmc *m10bmc, unsigned int addr,
> +		     void *val, size_t cnt)
> +{
> +	int ret;
> +
> +	ret = regmap_bulk_read(m10bmc->regmap, addr, val, cnt);
> +	if (ret)
> +		dev_err(m10bmc->dev, "fail to read raw reg %x cnt %zx: %d\n",
> +			addr, cnt, ret);
> +
> +	return ret;
> +}
> +
>  #define m10bmc_sys_read(m10bmc, offset, val) \
>  	m10bmc_raw_read(m10bmc, M10BMC_SYS_BASE + (offset), val)
>  


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

* Re: [PATCH v1 03/12] fpga: expose max10 flash update counts in sysfs
  2020-09-04 23:52 ` [PATCH v1 03/12] fpga: expose max10 flash update counts in sysfs Russ Weight
@ 2020-09-05 20:39   ` Tom Rix
  2020-09-16 18:37     ` Russ Weight
  0 siblings, 1 reply; 57+ messages in thread
From: Tom Rix @ 2020-09-05 20:39 UTC (permalink / raw)
  To: Russ Weight, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 9/4/20 4:52 PM, Russ Weight wrote:
> Extend the MAX10 BMC Security Engine driver to provide a
> handler to expose the flash update count for the FPGA user
> image.
>
> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
> Reviewed-by: Wu Hao <hao.wu@intel.com>
> ---
>  drivers/fpga/intel-m10-bmc-secure.c | 32 +++++++++++++++++++++++++++++
>  1 file changed, 32 insertions(+)
>
> diff --git a/drivers/fpga/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c
> index 1f86bfb694b4..b824790e43aa 100644
> --- a/drivers/fpga/intel-m10-bmc-secure.c
> +++ b/drivers/fpga/intel-m10-bmc-secure.c
> @@ -10,6 +10,7 @@
>  #include <linux/mfd/intel-m10-bmc.h>
>  #include <linux/module.h>
>  #include <linux/platform_device.h>
> +#include <linux/slab.h>
>  #include <linux/vmalloc.h>
>  
>  struct m10bmc_sec {
> @@ -99,7 +100,38 @@ SYSFS_GET_REH(bmc, BMC_REH_ADDR)
>  SYSFS_GET_REH(sr, SR_REH_ADDR)
>  SYSFS_GET_REH(pr, PR_REH_ADDR)
>  
> +#define FLASH_COUNT_SIZE 4096
This seems too high at most it should be 64.
> +#define USER_FLASH_COUNT 0x17ffb000
Why shouldn't this be in intel-m10-bmc.h ?
> +
> +static int get_qspi_flash_count(struct ifpga_sec_mgr *imgr)

what does 'qspi' mean ?

unless there are going to be several *flash_count's consider

removing this substring.

> +{
> +	struct m10bmc_sec *sec = imgr->priv;
> +	unsigned int stride = regmap_get_reg_stride(sec->m10bmc->regmap);
> +	unsigned int cnt, num_bits = FLASH_COUNT_SIZE * 8;
> +	u8 *flash_buf;
> +	int ret;
> +
> +	flash_buf = kmalloc(FLASH_COUNT_SIZE, GFP_KERNEL);
> +	if (!flash_buf)
> +		return -ENOMEM;
> +
> +	ret = m10bmc_raw_bulk_read(sec->m10bmc, USER_FLASH_COUNT, flash_buf,
> +				   FLASH_COUNT_SIZE / stride);
> +	if (ret) {
> +		dev_err(sec->dev, "%s failed to read %d\n", __func__, ret);
> +		goto exit_free;
> +	}
> +
> +	cnt = num_bits - bitmap_weight((unsigned long *)flash_buf, num_bits);
Simplify ret = num_bits...
> +
> +exit_free:
> +	kfree(flash_buf);
> +
> +	return ret ? : cnt;

Then simplify

return ret;

Tom

> +}
> +
>  static const struct ifpga_sec_mgr_ops m10bmc_iops = {
> +	.user_flash_count = get_qspi_flash_count,
>  	.bmc_root_entry_hash = get_bmc_root_entry_hash,
>  	.sr_root_entry_hash = get_sr_root_entry_hash,
>  	.pr_root_entry_hash = get_pr_root_entry_hash,


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

* Re: [PATCH v1 04/12] fpga: expose max10 canceled keys in sysfs
  2020-09-04 23:52 ` [PATCH v1 04/12] fpga: expose max10 canceled keys " Russ Weight
@ 2020-09-05 20:52   ` Tom Rix
  0 siblings, 0 replies; 57+ messages in thread
From: Tom Rix @ 2020-09-05 20:52 UTC (permalink / raw)
  To: Russ Weight, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 9/4/20 4:52 PM, Russ Weight wrote:
> Extend the MAX10 BMC Security Engine driver to provide a
> handler to expose the canceled code signing key (CSK) bit
> vectors. These use the standard bitmap list format
> (e.g. 1,2-6,9).
>
> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
> Reviewed-by: Wu Hao <hao.wu@intel.com>
> ---
>  drivers/fpga/intel-m10-bmc-secure.c | 60 +++++++++++++++++++++++++++++
>  1 file changed, 60 insertions(+)
>
> diff --git a/drivers/fpga/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c
> index b824790e43aa..46cd49a08be0 100644
> --- a/drivers/fpga/intel-m10-bmc-secure.c
> +++ b/drivers/fpga/intel-m10-bmc-secure.c
> @@ -130,14 +130,74 @@ static int get_qspi_flash_count(struct ifpga_sec_mgr *imgr)
>  	return ret ? : cnt;
>  }
>  
> +#define CSK_BIT_LEN			128U
> +#define CSK_32ARRAY_SIZE(_nbits)	DIV_ROUND_UP(_nbits, 32)
> +
> +#define SYSFS_GET_CSK_CANCEL_NBITS(_name) \
> +static int get_##_name##_csk_cancel_nbits(struct ifpga_sec_mgr *imgr) \
> +{ \
> +	return (int)CSK_BIT_LEN; \
> +}
> +
> +SYSFS_GET_CSK_CANCEL_NBITS(bmc)
> +SYSFS_GET_CSK_CANCEL_NBITS(sr)
> +SYSFS_GET_CSK_CANCEL_NBITS(pr)

> +
> +static int get_csk_vector(struct ifpga_sec_mgr *imgr, u32 addr,
> +			  unsigned long *csk_map, unsigned int nbits)
> +{
> +	unsigned int i, arr_size = CSK_32ARRAY_SIZE(nbits);

> +	struct m10bmc_sec *sec = imgr->priv;
> +	u32 *csk32;
> +	int ret;
> +
> +	csk32 = vmalloc(arr_size);
> +	if (!csk32)
> +		return -ENOMEM;
> +
> +	ret = m10bmc_raw_bulk_read(sec->m10bmc, addr, csk32, arr_size);

Is this correct ? other similar bulk read used the

regmap stride.

> +	if (ret) {
> +		dev_err(sec->dev, "%s failed to read %d\n", __func__, ret);
> +		goto vfree_exit;
> +	}
> +
> +	for (i = 0; i < arr_size; i++)
> +		csk32[i] = le32_to_cpu(csk32[i]);
> +
> +	bitmap_from_arr32(csk_map, csk32, nbits);
> +	bitmap_complement(csk_map, csk_map, nbits);
> +
> +vfree_exit:
> +	vfree(csk32);
> +	return ret;
> +}
> +
> +#define SYSFS_GET_CSK_VEC(_name, _addr) \
> +static int get_##_name##_canceled_csks(struct ifpga_sec_mgr *imgr, \
> +				       unsigned long *csk_map, \
> +				       unsigned int nbits) \
> +{ return get_csk_vector(imgr, _addr, csk_map, nbits); }
> +
> +#define CSK_VEC_OFFSET 0x34
> +
> +SYSFS_GET_CSK_VEC(bmc, BMC_PROG_ADDR + CSK_VEC_OFFSET)
> +SYSFS_GET_CSK_VEC(sr, SR_PROG_ADDR + CSK_VEC_OFFSET)
> +SYSFS_GET_CSK_VEC(pr, PR_PROG_ADDR + CSK_VEC_OFFSET)
Issues similar with earlier patches.
> +
>  static const struct ifpga_sec_mgr_ops m10bmc_iops = {
>  	.user_flash_count = get_qspi_flash_count,
>  	.bmc_root_entry_hash = get_bmc_root_entry_hash,
>  	.sr_root_entry_hash = get_sr_root_entry_hash,
>  	.pr_root_entry_hash = get_pr_root_entry_hash,
> +	.bmc_canceled_csks = get_bmc_canceled_csks,
> +	.sr_canceled_csks = get_sr_canceled_csks,
> +	.pr_canceled_csks = get_pr_canceled_csks,
>  	.bmc_reh_size = get_bmc_reh_size,
>  	.sr_reh_size = get_sr_reh_size,
>  	.pr_reh_size = get_pr_reh_size,
> +	.bmc_canceled_csk_nbits = get_bmc_csk_cancel_nbits,
> +	.sr_canceled_csk_nbits = get_sr_csk_cancel_nbits,
> +	.pr_canceled_csk_nbits = get_pr_csk_cancel_nbits

These are copies the same function, replace with a

common function.

Tom

>  };
>  
>  static void ifpga_sec_mgr_uinit(struct m10bmc_sec *sec)


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

* Re: [PATCH v1 05/12] fpga: enable secure updates
  2020-09-04 23:52 ` [PATCH v1 05/12] fpga: enable secure updates Russ Weight
@ 2020-09-05 22:04   ` Tom Rix
       [not found]     ` <1d90bfb6-417c-55df-9290-991c391158a9@intel.com>
  0 siblings, 1 reply; 57+ messages in thread
From: Tom Rix @ 2020-09-05 22:04 UTC (permalink / raw)
  To: Russ Weight, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 9/4/20 4:52 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>
> ---
>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  13 ++
>  drivers/fpga/ifpga-sec-mgr.c                  | 155 ++++++++++++++++++
>  include/linux/fpga/ifpga-sec-mgr.h            |  49 ++++++
>  3 files changed, 217 insertions(+)
>
> diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> index 86f8992559bf..a476504b7ae9 100644
> --- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> @@ -73,3 +73,16 @@ Contact:	Russ Weight <russell.h.weight@intel.com>
>  Description:	Read only. Returns number of times the BMC image has been
>  		flashed.
>  		Format: "%d".
> +
> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/update/filename
> +Date:		Sep 2020
> +KernelVersion:  5.10
> +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 97bf80277ed2..73173badbe96 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
> +
>  static ssize_t show_canceled_csk(struct ifpga_sec_mgr *imgr,
>  				 sysfs_csk_hndlr_t get_csk,
>  				 sysfs_csk_nbits_t get_csk_nbits,
> @@ -134,6 +139,91 @@ 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);

Why not lock here ? It seems like filename and other

state could be changed out from under the work func.

> +
> +	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);

Check for function pointer later, good.

Could writing a short block be handled like libc's write()

by passing back the bytes written ?

> +		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;
> +	}
Add a paranoid crc check the flash is what was written ?
> +
> +done:
> +	if (imgr->iops->cleanup)
> +		imgr->iops->cleanup(imgr);
> +
> +modput_exit:
> +	module_put(imgr->dev.parent->driver->owner);
> +
> +release_fw_exit:
> +	imgr->data = NULL;
clear remaining_size ?
> +	release_firmware(fw);
> +
> +idle_exit:
> +	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)
>  
> @@ -161,6 +251,51 @@ 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 = 0;
> +
> +	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, PATH_MAX - 1, GFP_KERNEL);
shouldn't this be 'count - 1' ?
> +	if (!imgr->filename) {
> +		ret = -ENOMEM;
> +		goto unlock_exit;
> +	}
> +
> +	if (imgr->filename[strlen(imgr->filename) - 1] == '\n')
> +		imgr->filename[strlen(imgr->filename) - 1] = '\0';

If you are catching the '\n' is a more general striping of

whitespace needed ?

Could a file exists check be done before kicking off the worker?

> +
> +	imgr->err_code = IFPGA_SEC_ERR_NONE;
> +	imgr->progress = IFPGA_SEC_PROG_READ_FILE;
> +	reinit_completion(&imgr->update_done);
> +	schedule_work(&imgr->work);

Skip the if-check at the end

ret = count.

> +
> +unlock_exit:
> +	mutex_unlock(&imgr->lock);
> +	return ret ? : count;
> +}
> +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)
>  {
> @@ -182,6 +317,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,
>  };
>  
> @@ -233,6 +369,12 @@ ifpga_sec_mgr_register(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) {
Comments in ifpga-sec-mgr.h say 'Required: ' good.
> +		dev_err(dev, "Attempt to register without ifpga_sec_mgr_ops\n");
without required ifpga_sec_mgr_ops
> +		return NULL;
> +	}
> +
>  	if (!check_reh_handler(dev, iops, bmc) ||
>  	    !check_reh_handler(dev, iops, sr) ||
>  	    !check_reh_handler(dev, iops, pr) ||
> @@ -254,6 +396,8 @@ ifpga_sec_mgr_register(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);
>  	mutex_init(&imgr->lock);
>  
>  	id = ida_simple_get(&ifpga_sec_mgr_ida, 0, 0, GFP_KERNEL);
> @@ -299,6 +443,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 e391b0c8f448..4da2864e251c 100644
> --- a/include/linux/fpga/ifpga-sec-mgr.h
> +++ b/include/linux/fpga/ifpga-sec-mgr.h
> @@ -7,6 +7,7 @@
>  #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>
> @@ -86,6 +87,19 @@ typedef int (*sysfs_csk_nbits_t)(struct ifpga_sec_mgr *imgr);
>  typedef int (*sysfs_csk_hndlr_t)(struct ifpga_sec_mgr *imgr,
>  				 unsigned long *csk_map, unsigned int nbits);
>  
> +enum ifpga_sec_err {
> +	IFPGA_SEC_ERR_NONE	   = 0x0,
> +	IFPGA_SEC_ERR_HW_ERROR	   = 0x1,
> +	IFPGA_SEC_ERR_TIMEOUT	   = 0x2,
> +	IFPGA_SEC_ERR_CANCELED	   = 0x3,
> +	IFPGA_SEC_ERR_BUSY	   = 0x4,
> +	IFPGA_SEC_ERR_INVALID_SIZE = 0x5,
> +	IFPGA_SEC_ERR_RW_ERROR	   = 0x6,
> +	IFPGA_SEC_ERR_WEAROUT	   = 0x7,
> +	IFPGA_SEC_ERR_FILE_READ	   = 0x8,
> +	IFPGA_SEC_ERR_MAX	   = 0x9
The initializers are redundant.
> +};
> +
>  /**
>   * struct ifpga_sec_mgr_ops - device specific operations
>   * @user_flash_count:	    Optional: Return sysfs string output for FPGA
> @@ -110,6 +124,17 @@ typedef int (*sysfs_csk_hndlr_t)(struct ifpga_sec_mgr *imgr,
>   * @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 {
>  	sysfs_cnt_hndlr_t user_flash_count;
> @@ -127,6 +152,22 @@ struct ifpga_sec_mgr_ops {
>  	sysfs_csk_nbits_t bmc_canceled_csk_nbits;
>  	sysfs_csk_nbits_t sr_canceled_csk_nbits;
>  	sysfs_csk_nbits_t pr_canceled_csk_nbits;
> +	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	   = 0x0,
> +	IFPGA_SEC_PROG_READ_FILE   = 0x1,
> +	IFPGA_SEC_PROG_PREPARING   = 0x2,
> +	IFPGA_SEC_PROG_WRITING	   = 0x3,
> +	IFPGA_SEC_PROG_PROGRAMMING = 0x4,
> +	IFPGA_SEC_PROG_MAX	   = 0x5

ditto

Tom

>  };
>  
>  struct ifpga_sec_mgr {
> @@ -134,6 +175,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;
>  };
>  


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

* Re: [PATCH v1 06/12] fpga: add max10 secure update functions
  2020-09-04 23:52 ` [PATCH v1 06/12] fpga: add max10 secure update functions Russ Weight
@ 2020-09-06 16:10   ` Tom Rix
  2020-09-22  1:15     ` Russ Weight
  2020-09-08  8:05   ` Lee Jones
  1 sibling, 1 reply; 57+ messages in thread
From: Tom Rix @ 2020-09-06 16:10 UTC (permalink / raw)
  To: Russ Weight, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach

With the v4 max10 change, this patch did not apply to linux-next.

So it will need at least another review when max10 lands in linux-next.

On 9/4/20 4:52 PM, Russ Weight wrote:
> Extend the MAX10 BMC Security Engine driver to include
> the functions that enable secure updates of BMC images,
> FPGA images, etc.
>
> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
> Reviewed-by: Wu Hao <hao.wu@intel.com>
> ---
>  drivers/fpga/intel-m10-bmc-secure.c | 272 +++++++++++++++++++++++++++-
>  include/linux/mfd/intel-m10-bmc.h   | 101 +++++++++++
>  2 files changed, 372 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/fpga/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c
> index 46cd49a08be0..4a66c2d448eb 100644
> --- a/drivers/fpga/intel-m10-bmc-secure.c
> +++ b/drivers/fpga/intel-m10-bmc-secure.c
> @@ -5,6 +5,7 @@
>   * Copyright (C) 2019-2020 Intel Corporation. All rights reserved.
>   *
>   */
> +#include <linux/bitfield.h>
>  #include <linux/device.h>
>  #include <linux/fpga/ifpga-sec-mgr.h>
>  #include <linux/mfd/intel-m10-bmc.h>
> @@ -184,6 +185,271 @@ SYSFS_GET_CSK_VEC(bmc, BMC_PROG_ADDR + CSK_VEC_OFFSET)
>  SYSFS_GET_CSK_VEC(sr, SR_PROG_ADDR + CSK_VEC_OFFSET)
>  SYSFS_GET_CSK_VEC(pr, PR_PROG_ADDR + CSK_VEC_OFFSET)
>  
> +static void log_error_regs(struct m10bmc_sec *sec, u32 doorbell)
> +{
> +	u32 auth_result;
> +
> +	dev_err(sec->dev, "RSU error status: 0x%08x\n", doorbell);
> +
> +	if (!m10bmc_sys_read(sec->m10bmc, M10BMC_AUTH_RESULT, &auth_result))
> +		dev_err(sec->dev, "RSU auth result: 0x%08x\n", auth_result);

If the read fails, auth_result will have garbage in it.

> +}
> +
> +static enum ifpga_sec_err rsu_check_idle(struct m10bmc_sec *sec)
> +{
> +	u32 doorbell;
> +	int ret;
> +
> +	ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell);
> +	if (ret)
> +		return IFPGA_SEC_ERR_RW_ERROR;
> +
> +	if (rsu_prog(doorbell) != RSU_PROG_IDLE &&
> +	    rsu_prog(doorbell) != RSU_PROG_RSU_DONE) {
> +		log_error_regs(sec, doorbell);
> +		return IFPGA_SEC_ERR_BUSY;
> +	}
> +
> +	return IFPGA_SEC_ERR_NONE;

Why do you need custom error codes here and below ?

Should return int and use -EIO, -EBUSY, 0

> +}
> +
> +static inline bool rsu_start_done(u32 doorbell)
> +{
> +	return (!(doorbell & RSU_REQUEST) &&
> +		(rsu_stat(doorbell) == RSU_STAT_ERASE_FAIL ||
> +		rsu_stat(doorbell) == RSU_STAT_WEAROUT ||
> +		(rsu_prog(doorbell) != RSU_PROG_IDLE &&
> +		 rsu_prog(doorbell) != RSU_PROG_RSU_DONE)));

This is complicated, try simplifying or adding a comment.

The rsu_stat & rsu_prog only need to be called once.

stat = rsu_stat(doorbell)

.. and then something like ..

if (stat & (RSU_STAT_ERASE_FAIL | RSU_STAT_WEAROUT))

> +}
> +
> +static enum ifpga_sec_err rsu_update_init(struct m10bmc_sec *sec)
> +{
> +	u32 doorbell;
> +	int ret;
> +
> +	ret = m10bmc_sys_update_bits(sec->m10bmc, M10BMC_DOORBELL,
> +				     RSU_REQUEST | HOST_STATUS, RSU_REQUEST |
> +				     FIELD_PREP(HOST_STATUS, HOST_STATUS_IDLE));
> +	if (ret)
> +		return IFPGA_SEC_ERR_RW_ERROR;
> +
> +	ret = regmap_read_poll_timeout(sec->m10bmc->regmap,
> +				       M10BMC_SYS_BASE + M10BMC_DOORBELL,
> +				       doorbell,
> +				       rsu_start_done(doorbell),
doorbell needs to be initialized to 0
> +				       NIOS_HANDSHAKE_INTERVAL_US,
> +				       NIOS_HANDSHAKE_TIMEOUT_US);
> +
> +	if (ret == -ETIMEDOUT) {
> +		log_error_regs(sec, doorbell);
> +		return IFPGA_SEC_ERR_TIMEOUT;
> +	} else if (ret) {
> +		return IFPGA_SEC_ERR_RW_ERROR;
> +	}
> +
> +	if (rsu_stat(doorbell) == RSU_STAT_WEAROUT) {
call rsu_stat once
> +		dev_warn(sec->dev, "Excessive flash update count detected\n");
> +		return IFPGA_SEC_ERR_WEAROUT;
> +	} else if (rsu_stat(doorbell) == RSU_STAT_ERASE_FAIL) {
> +		log_error_regs(sec, doorbell);
> +		return IFPGA_SEC_ERR_HW_ERROR;
> +	}
> +
> +	return IFPGA_SEC_ERR_NONE;
> +}
> +
> +static enum ifpga_sec_err rsu_prog_ready(struct m10bmc_sec *sec)
> +{
> +	unsigned long poll_timeout;
> +	u32 doorbell;
> +	int ret;
> +
> +	ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell);
return here on error.
> +	poll_timeout = jiffies + msecs_to_jiffies(RSU_PREP_TIMEOUT_MS);
> +	while (!ret && !time_after(jiffies, poll_timeout)) {
> +		if (rsu_prog(doorbell) != RSU_PROG_PREPARE)

This seems to be the main condition, consider exchanging

it for the time_after in your while() condition

> +			break;
> +		msleep(RSU_PREP_INTERVAL_MS);
> +		ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell);
return here on error
> +	}
> +
> +	if (ret) {
> +		return IFPGA_SEC_ERR_RW_ERROR;
> +	} else if (rsu_prog(doorbell) == RSU_PROG_PREPARE) {
> +		log_error_regs(sec, doorbell);
> +		return IFPGA_SEC_ERR_TIMEOUT;
> +	} else if (rsu_prog(doorbell) != RSU_PROG_READY) {
> +		log_error_regs(sec, doorbell);
> +		return IFPGA_SEC_ERR_HW_ERROR;
> +	}
> +
> +	return IFPGA_SEC_ERR_NONE;
> +}
> +
> +static enum ifpga_sec_err rsu_send_data(struct m10bmc_sec *sec)
> +{
> +	u32 doorbell;
> +	int ret;
> +
> +	ret = m10bmc_sys_update_bits(sec->m10bmc, M10BMC_DOORBELL, HOST_STATUS,
> +				     FIELD_PREP(HOST_STATUS,
> +						HOST_STATUS_WRITE_DONE));
> +	if (ret)
> +		return IFPGA_SEC_ERR_RW_ERROR;
> +
> +	ret = regmap_read_poll_timeout(sec->m10bmc->regmap,
> +				       M10BMC_SYS_BASE + M10BMC_DOORBELL,
> +				       doorbell,
> +				       rsu_prog(doorbell) != RSU_PROG_READY,
similar to above doorbell must be initialized to 0
> +				       NIOS_HANDSHAKE_INTERVAL_US,
> +				       NIOS_HANDSHAKE_TIMEOUT_US);
> +
> +	if (ret == -ETIMEDOUT) {
> +		log_error_regs(sec, doorbell);
> +		return IFPGA_SEC_ERR_TIMEOUT;
> +	} else if (ret) {
> +		return IFPGA_SEC_ERR_RW_ERROR;
> +	}
> +
> +	switch (rsu_stat(doorbell)) {
> +	case RSU_STAT_NORMAL:
> +	case RSU_STAT_NIOS_OK:
> +	case RSU_STAT_USER_OK:
> +	case RSU_STAT_FACTORY_OK:
> +		break;
> +	default:
> +		log_error_regs(sec, doorbell);
> +		return IFPGA_SEC_ERR_HW_ERROR;
> +	}
> +
> +	return IFPGA_SEC_ERR_NONE;
> +}
> +
> +static int rsu_check_complete(struct m10bmc_sec *sec, u32 *doorbell)
> +{
> +	if (m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, doorbell))
> +		return -EIO;
> +
> +	switch (rsu_stat(*doorbell)) {
> +	case RSU_STAT_NORMAL:
> +	case RSU_STAT_NIOS_OK:
> +	case RSU_STAT_USER_OK:
> +	case RSU_STAT_FACTORY_OK:
> +	case RSU_STAT_WEAROUT:
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	switch (rsu_prog(*doorbell)) {
> +	case RSU_PROG_IDLE:
> +	case RSU_PROG_RSU_DONE:
> +		return 0;
> +	case RSU_PROG_AUTHENTICATING:
> +	case RSU_PROG_COPYING:
> +	case RSU_PROG_UPDATE_CANCEL:
> +	case RSU_PROG_PROGRAM_KEY_HASH:
> +		return -EAGAIN;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static enum ifpga_sec_err m10bmc_sec_prepare(struct ifpga_sec_mgr *imgr)
> +{
> +	struct m10bmc_sec *sec = imgr->priv;
> +	enum ifpga_sec_err ret;
> +
> +	if (imgr->remaining_size > M10BMC_STAGING_SIZE)
> +		return IFPGA_SEC_ERR_INVALID_SIZE;
Could this check be moved closer to when the fw is opened ?
> +
> +	ret = rsu_check_idle(sec);
> +	if (ret)
> +		return ret;
> +
> +	ret = rsu_update_init(sec);
> +	if (ret)
> +		return ret;
> +
> +	return rsu_prog_ready(sec);
> +}
> +
> +static enum ifpga_sec_err
> +m10bmc_sec_write_blk(struct ifpga_sec_mgr *imgr, u32 offset, u32 size)

Function name should be consistent with existing

m10bmc_raw_bulk_write, likely m10bmc_sec_bulk_write.

Why should not this call go in to intel-m10-bmc.c ?

the imgr parameter is only used to get to the m10bmc.

> +{
> +	struct m10bmc_sec *sec = imgr->priv;
> +	unsigned int stride = regmap_get_reg_stride(sec->m10bmc->regmap);
> +	u32 doorbell;
> +	int ret;
> +
> +	ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell);
> +	if (ret) {
> +		return IFPGA_SEC_ERR_RW_ERROR;
> +	} else if (rsu_prog(doorbell) != RSU_PROG_READY) {
> +		log_error_regs(sec, doorbell);
> +		return IFPGA_SEC_ERR_HW_ERROR;
> +	}
> +
> +	ret = m10bmc_raw_bulk_write(sec->m10bmc, M10BMC_STAGING_BASE + offset,
> +				    (void *)imgr->data + offset, size / stride);
> +
> +	return ret ? IFPGA_SEC_ERR_RW_ERROR : IFPGA_SEC_ERR_NONE;
> +}
> +
> +static enum ifpga_sec_err m10bmc_sec_poll_complete(struct ifpga_sec_mgr *imgr)
> +{
> +	struct m10bmc_sec *sec = imgr->priv;
> +	unsigned long poll_timeout;
> +	enum ifpga_sec_err result;
> +	u32 doorbell;
> +	int ret;
> +
> +	result = rsu_send_data(sec);
> +	if (result)
> +		return result;
> +
> +	ret = rsu_check_complete(sec, &doorbell);
> +	poll_timeout = jiffies + msecs_to_jiffies(RSU_COMPLETE_TIMEOUT_MS);
Maybe a whitespace issue here.
> +	while (ret == -EAGAIN && !time_after(jiffies, poll_timeout)) {
> +		msleep(RSU_COMPLETE_INTERVAL_MS);
> +		ret = rsu_check_complete(sec, &doorbell);
> +		if (imgr->driver_unload)
> +			return IFPGA_SEC_ERR_CANCELED;
unload was not checked in other polling, why not ?
> +	}
> +
> +	if (ret == -EAGAIN) {
> +		log_error_regs(sec, doorbell);
> +		return IFPGA_SEC_ERR_TIMEOUT;
> +	} else if (ret == -EIO) {
> +		return IFPGA_SEC_ERR_RW_ERROR;
> +	} else if (ret) {
> +		log_error_regs(sec, doorbell);
> +		return IFPGA_SEC_ERR_HW_ERROR;
> +	}
> +
> +	return IFPGA_SEC_ERR_NONE;
> +}
> +
> +static enum ifpga_sec_err m10bmc_sec_cancel(struct ifpga_sec_mgr *imgr)
> +{
> +	struct m10bmc_sec *sec = imgr->priv;
> +	u32 doorbell;
> +	int ret;
> +
> +	ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell);
> +	if (ret)
> +		return IFPGA_SEC_ERR_RW_ERROR;
> +
> +	if (rsu_prog(doorbell) != RSU_PROG_READY)
> +		return IFPGA_SEC_ERR_BUSY;
> +
> +	ret = m10bmc_sys_update_bits(sec->m10bmc, M10BMC_DOORBELL, HOST_STATUS,
> +				     FIELD_PREP(HOST_STATUS,
> +						HOST_STATUS_ABORT_RSU));
> +
> +	return ret ? IFPGA_SEC_ERR_RW_ERROR : IFPGA_SEC_ERR_NONE;
> +}
> +
>  static const struct ifpga_sec_mgr_ops m10bmc_iops = {
>  	.user_flash_count = get_qspi_flash_count,
>  	.bmc_root_entry_hash = get_bmc_root_entry_hash,
> @@ -197,7 +463,11 @@ static const struct ifpga_sec_mgr_ops m10bmc_iops = {
>  	.pr_reh_size = get_pr_reh_size,
>  	.bmc_canceled_csk_nbits = get_bmc_csk_cancel_nbits,
>  	.sr_canceled_csk_nbits = get_sr_csk_cancel_nbits,
> -	.pr_canceled_csk_nbits = get_pr_csk_cancel_nbits
> +	.pr_canceled_csk_nbits = get_pr_csk_cancel_nbits,
> +	.prepare = m10bmc_sec_prepare,
> +	.write_blk = m10bmc_sec_write_blk,
> +	.poll_complete = m10bmc_sec_poll_complete,
> +	.cancel = m10bmc_sec_cancel
>  };
>  
>  static void ifpga_sec_mgr_uinit(struct m10bmc_sec *sec)
> diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h

This likely needs to be split out into it's own patch

since it is another subsystem. Deferring to Lee.

> index 7fe465c320c2..5d2860d8a0cf 100644
> --- a/include/linux/mfd/intel-m10-bmc.h
> +++ b/include/linux/mfd/intel-m10-bmc.h
> @@ -13,6 +13,9 @@
>  #define M10BMC_SYS_BASE			0x300800
>  #define M10BMC_MEM_END			0x200000fc
>  
> +#define M10BMC_STAGING_BASE		0x18000000
> +#define M10BMC_STAGING_SIZE		0x3800000
> +
>  /* Register offset of system registers */
>  #define NIOS2_FW_VERSION		0x0
>  #define M10BMC_MACADDR1			0x10
> @@ -36,6 +39,70 @@
>  #define SERDES_VERSION			GENMASK(15, 0)
>  #define SBUS_VERSION			GENMASK(31, 16)
>  
> +/* Secure update doorbell register, in system register region */
> +#define M10BMC_DOORBELL			0x400
> +#define RSU_REQUEST			BIT(0)
> +#define RSU_PROGRESS			GENMASK(7, 4)
> +#define HOST_STATUS			GENMASK(11, 8)
> +#define RSU_STATUS			GENMASK(23, 16)
> +#define PKVL_EEPROM_LOAD_SEC		BIT(24)
> +#define PKVL1_POLL_EN			BIT(25)
> +#define PKVL2_POLL_EN			BIT(26)
> +#define CONFIG_SEL			BIT(28)
> +#define REBOOT_REQ			BIT(29)
> +#define REBOOT_DISABLED			BIT(30)
These are similar should have a prefix, likely M10BMC_SEC_
> +
> +/* Progress states */
> +#define RSU_PROG_IDLE			0x0
> +#define RSU_PROG_PREPARE		0x1
> +#define RSU_PROG_READY			0x3
> +#define RSU_PROG_AUTHENTICATING		0x4
> +#define RSU_PROG_COPYING		0x5
> +#define RSU_PROG_UPDATE_CANCEL		0x6
> +#define RSU_PROG_PROGRAM_KEY_HASH	0x7
> +#define RSU_PROG_RSU_DONE		0x8
> +#define RSU_PROG_PKVL_PROM_DONE		0x9
> +
> +/* Device and error states */
> +#define RSU_STAT_NORMAL			0x0
> +#define RSU_STAT_TIMEOUT		0x1
> +#define RSU_STAT_AUTH_FAIL		0x2
> +#define RSU_STAT_COPY_FAIL		0x3
> +#define RSU_STAT_FATAL			0x4
> +#define RSU_STAT_PKVL_REJECT		0x5
> +#define RSU_STAT_NON_INC		0x6
> +#define RSU_STAT_ERASE_FAIL		0x7
> +#define RSU_STAT_WEAROUT		0x8
> +#define RSU_STAT_NIOS_OK		0x80
> +#define RSU_STAT_USER_OK		0x81
> +#define RSU_STAT_FACTORY_OK		0x82
> +#define RSU_STAT_USER_FAIL		0x83
> +#define RSU_STAT_FACTORY_FAIL		0x84
> +#define RSU_STAT_NIOS_FLASH_ERR		0x85
> +#define RSU_STAT_FPGA_FLASH_ERR		0x86
> +
> +#define HOST_STATUS_IDLE		0x0
> +#define HOST_STATUS_WRITE_DONE		0x1
> +#define HOST_STATUS_ABORT_RSU		0x2
> +
> +#define rsu_prog(doorbell)		FIELD_GET(RSU_PROGRESS, doorbell)
> +#define rsu_stat(doorbell)		FIELD_GET(RSU_STATUS, doorbell)
> +
> +/* interval 100ms and timeout 5s */
> +#define NIOS_HANDSHAKE_INTERVAL_US	(100 * 1000)
> +#define NIOS_HANDSHAKE_TIMEOUT_US	(5 * 1000 * 1000)
> +
> +/* RSU PREP Timeout (2 minutes) to erase flash staging area */
> +#define RSU_PREP_INTERVAL_MS		100
> +#define RSU_PREP_TIMEOUT_MS		(2 * 60 * 1000)
> +
> +/* RSU Complete Timeout (40 minutes) for full flash update */
> +#define RSU_COMPLETE_INTERVAL_MS	1000
> +#define RSU_COMPLETE_TIMEOUT_MS		(40 * 60 * 1000)
> +
> +/* Authorization Result register, in system register region */
> +#define M10BMC_AUTH_RESULT		0x404

Needs to move to where the other registers are

defined.

> +
>  /**
>   * struct intel_m10bmc_retimer_pdata - subdev retimer platform data
>   *
> @@ -64,7 +131,10 @@ struct intel_m10bmc {
>   *
>   * m10bmc_raw_read - read m10bmc register per addr
>   * m10bmc_raw_bulk_read - bulk_read max10 registers per addr
> + * m10bmc_raw_bulk_write - bulk_write max10 registers per addr
> + * m10bmc_raw_update_bits - update max10 register per addr
>   * m10bmc_sys_read - read m10bmc system register per offset
> + * m10bmc_sys_update_bits - update max10 system register per offset
>   */
>  static inline int
>  m10bmc_raw_read(struct intel_m10bmc *m10bmc, unsigned int addr,
> @@ -94,7 +164,38 @@ m10bmc_raw_bulk_read(struct intel_m10bmc *m10bmc, unsigned int addr,
>  	return ret;
>  }
>  
> +static inline int
> +m10bmc_raw_bulk_write(struct intel_m10bmc *m10bmc, unsigned int addr,
> +		      void *val, size_t cnt)
> +{
> +	int ret;
> +
> +	ret = regmap_bulk_write(m10bmc->regmap, addr, val, cnt);
> +	if (ret)
> +		dev_err(m10bmc->dev, "fail to write raw reg %x cnt %zx: %d\n",
> +			addr, cnt, ret);
> +
> +	return ret;
> +}
> +
> +static inline int
> +m10bmc_raw_update_bits(struct intel_m10bmc *m10bmc, unsigned int addr,
> +		       unsigned int msk, unsigned int val)
> +{
> +	int ret;
> +
> +	ret = regmap_update_bits(m10bmc->regmap, addr, msk, val);
> +	if (ret)
> +		dev_err(m10bmc->dev, "fail to update raw reg %x: %d\n",
> +			addr, ret);
> +
> +	return ret;
> +}
> +
>  #define m10bmc_sys_read(m10bmc, offset, val) \
>  	m10bmc_raw_read(m10bmc, M10BMC_SYS_BASE + (offset), val)
>  
> +#define m10bmc_sys_update_bits(m10bmc, offset, msk, val) \
> +	m10bmc_raw_update_bits(m10bmc, M10BMC_SYS_BASE + (offset), msk, val)
> +

There is discussion on m10bmc patch around the

#define m10bmc_sys_read.

It would be better if m10bmc_sys_update_bits was a real function.

Tom

>  #endif /* __MFD_INTEL_M10_BMC_H */


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

* Re: [PATCH v1 07/12] fpga: expose sec-mgr update status
  2020-09-04 23:53 ` [PATCH v1 07/12] fpga: expose sec-mgr update status Russ Weight
@ 2020-09-06 16:16   ` Tom Rix
  2020-09-22 22:31     ` Russ Weight
  0 siblings, 1 reply; 57+ messages in thread
From: Tom Rix @ 2020-09-06 16:16 UTC (permalink / raw)
  To: Russ Weight, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 9/4/20 4:53 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>
> Reviewed-by: Wu Hao <hao.wu@intel.com>
> ---
>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 11 ++++++
>  drivers/fpga/ifpga-sec-mgr.c                  | 34 ++++++++++++++++---
>  2 files changed, 41 insertions(+), 4 deletions(-)
>
> diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> index a476504b7ae9..849ccb2802f8 100644
> --- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> @@ -86,3 +86,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:		Sep 2020
> +KernelVersion:  5.10
> +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, read_file, preparing, writing,
For consistency, read_file -> reading
> +		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 73173badbe96..5fe3d85e2963 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);
> @@ -251,6 +258,24 @@ 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 */
> +	"read_file",		/* IFPGA_SEC_PROG_READ_FILE */
"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);
> +
> +	return sprintf(buf, "%s\n", (imgr->progress < IFPGA_SEC_PROG_MAX) ?
> +		       sec_mgr_prog_str[imgr->progress] : "unknown-status");

when imgr->progress is unknown, should there be a dev_warn ?

Tom

> +}
> +static DEVICE_ATTR_RO(status);
> +
>  static ssize_t filename_store(struct device *dev, struct device_attribute *attr,
>  			      const char *buf, size_t count)
>  {
> @@ -288,6 +313,7 @@ static DEVICE_ATTR_WO(filename);
>  
>  static struct attribute *sec_mgr_update_attrs[] = {
>  	&dev_attr_filename.attr,
> +	&dev_attr_status.attr,
>  	NULL,
>  };
>  


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

* Re: [PATCH v1 08/12] fpga: expose sec-mgr update errors
  2020-09-04 23:53 ` [PATCH v1 08/12] fpga: expose sec-mgr update errors Russ Weight
@ 2020-09-06 16:27   ` Tom Rix
  2020-09-22 23:42     ` Russ Weight
  0 siblings, 1 reply; 57+ messages in thread
From: Tom Rix @ 2020-09-06 16:27 UTC (permalink / raw)
  To: Russ Weight, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 9/4/20 4:53 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>
> Reviewed-by: Wu Hao <hao.wu@intel.com>
> ---
>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 17 ++++++
>  drivers/fpga/ifpga-sec-mgr.c                  | 60 +++++++++++++++++--
>  include/linux/fpga/ifpga-sec-mgr.h            |  1 +
>  3 files changed, 73 insertions(+), 5 deletions(-)
>
> diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> index 849ccb2802f8..e7b1b02bf7ee 100644
> --- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> @@ -97,3 +97,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:		Sep 2020
> +KernelVersion:  5.10
> +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 5fe3d85e2963..a7718bd8ee61 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;
>  	}
>  
> @@ -266,16 +272,59 @@ static const char * const sec_mgr_prog_str[] = {
>  	"programming"		/* IFPGA_SEC_PROG_PROGRAMMING */
>  };
>  
> +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(enum ifpga_sec_prog prog)
> +{
A consistent api would have imgr as the parameter.
> +	return (prog < IFPGA_SEC_PROG_MAX) ?
> +		sec_mgr_prog_str[prog] : "unknown-status";
> +}
> +
>  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", (imgr->progress < IFPGA_SEC_PROG_MAX) ?
> -		       sec_mgr_prog_str[imgr->progress] : "unknown-status");
> +	return sprintf(buf, "%s\n", sec_progress(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);
> +	enum ifpga_sec_err err_code;
> +	const char *prog_str;
> +	int ret;
> +
> +	mutex_lock(&imgr->lock);
> +	if (imgr->progress != IFPGA_SEC_PROG_IDLE) {
> +		ret = -EBUSY;
> +	} else if (!imgr->err_code) {
> +		ret = 0;
> +	} else {
> +		err_code = imgr->err_code;
> +		prog_str = sec_progress(imgr->err_state);
> +		ret = sprintf(buf, "%s:%s\n", prog_str,
> +			      (err_code < IFPGA_SEC_ERR_MAX) ?
> +			      sec_mgr_err_str[err_code] : "unknown-error");

Should have sec_error() call to match the new sec_progress()

Tom

> +	}
> +	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)
>  {
> @@ -314,6 +363,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 4da2864e251c..f04bf9e30c67 100644
> --- a/include/linux/fpga/ifpga-sec-mgr.h
> +++ b/include/linux/fpga/ifpga-sec-mgr.h
> @@ -181,6 +181,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;


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

* Re: [PATCH v1 09/12] fpga: expose sec-mgr update size
  2020-09-04 23:53 ` [PATCH v1 09/12] fpga: expose sec-mgr update size Russ Weight
@ 2020-09-06 16:39   ` Tom Rix
  0 siblings, 0 replies; 57+ messages in thread
From: Tom Rix @ 2020-09-06 16:39 UTC (permalink / raw)
  To: Russ Weight, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 9/4/20 4:53 PM, Russ Weight wrote:
> 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: Wu Hao <hao.wu@intel.com>
> ---
>  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 e7b1b02bf7ee..cf1967f1b3e3 100644
> --- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> @@ -98,6 +98,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:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
>  KernelVersion:  5.10
> diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
> index a7718bd8ee61..4ca5d13e5656 100644
> --- a/drivers/fpga/ifpga-sec-mgr.c
> +++ b/drivers/fpga/ifpga-sec-mgr.c
> @@ -325,6 +325,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)
>  {
> @@ -364,6 +373,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,
>  };
>  

Looks fine.

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


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

* Re: [PATCH v1 10/12] fpga: enable sec-mgr update cancel
  2020-09-04 23:53 ` [PATCH v1 10/12] fpga: enable sec-mgr update cancel Russ Weight
@ 2020-09-06 17:00   ` Tom Rix
       [not found]     ` <678f8d39-a244-42d0-4c56-91eb859b43f0@intel.com>
  0 siblings, 1 reply; 57+ messages in thread
From: Tom Rix @ 2020-09-06 17:00 UTC (permalink / raw)
  To: Russ Weight, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 9/4/20 4:53 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>
> ---
>  .../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 cf1967f1b3e3..762a7dee9453 100644
> --- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> @@ -87,6 +87,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:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
>  KernelVersion:  5.10
> diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
> index 4ca5d13e5656..afd97c135ebe 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);

check cancel() for double error ?

should request_cancel be cleared ?

> +		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);
> @@ -359,6 +382,7 @@ static ssize_t filename_store(struct device *dev, struct device_attribute *attr,
>  		imgr->filename[strlen(imgr->filename) - 1] = '\0';
>  
>  	imgr->err_code = IFPGA_SEC_ERR_NONE;
> +	imgr->request_cancel = false;
>  	imgr->progress = IFPGA_SEC_PROG_READ_FILE;
>  	reinit_completion(&imgr->update_done);
>  	schedule_work(&imgr->work);
> @@ -369,8 +393,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 = 0;
int ret = count;
> +
> +	if (kstrtobool(buf, &cancel) || !cancel)

This does not match your description in the testing section.

kstrtobool has many other valid inputs.

maybe check if count is 1 and buf[0] == '1'

> +		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 ? : count;

return ret;

Tom

> +}
> +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,
> @@ -536,6 +584,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 f04bf9e30c67..f51ed663a723 100644
> --- a/include/linux/fpga/ifpga-sec-mgr.h
> +++ b/include/linux/fpga/ifpga-sec-mgr.h
> @@ -183,6 +183,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;
>  };


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

* Re: [PATCH v1 11/12] fpga: expose hardware error info in sysfs
  2020-09-04 23:53 ` [PATCH v1 11/12] fpga: expose hardware error info in sysfs Russ Weight
@ 2020-09-06 17:06   ` Tom Rix
  0 siblings, 0 replies; 57+ messages in thread
From: Tom Rix @ 2020-09-06 17:06 UTC (permalink / raw)
  To: Russ Weight, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 9/4/20 4:53 PM, Russ Weight wrote:
> 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: Wu Hao <hao.wu@intel.com>
> ---
>  .../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 762a7dee9453..20bde1abb5e4 100644
> --- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> @@ -135,3 +135,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:		Sep 2020
> +KernelVersion:  5.10
> +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 afd97c135ebe..6944396eff80 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);
>  }
>  
> @@ -348,6 +355,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)
>  {
> @@ -382,6 +406,7 @@ static ssize_t filename_store(struct device *dev, struct device_attribute *attr,
>  		imgr->filename[strlen(imgr->filename) - 1] = '\0';
>  
>  	imgr->err_code = IFPGA_SEC_ERR_NONE;
> +	imgr->hw_errinfo = 0;
>  	imgr->request_cancel = false;
>  	imgr->progress = IFPGA_SEC_PROG_READ_FILE;
>  	reinit_completion(&imgr->update_done);
> @@ -416,18 +441,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 f51ed663a723..3be8d8da078a 100644
> --- a/include/linux/fpga/ifpga-sec-mgr.h
> +++ b/include/linux/fpga/ifpga-sec-mgr.h
> @@ -135,6 +135,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 {
>  	sysfs_cnt_hndlr_t user_flash_count;
> @@ -158,6 +161,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 */
> @@ -183,6 +187,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;

This looks fine.

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


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

* Re: [PATCH v1 12/12] fpga: add max10 get_hw_errinfo callback func
  2020-09-04 23:53 ` [PATCH v1 12/12] fpga: add max10 get_hw_errinfo callback func Russ Weight
@ 2020-09-06 17:14   ` Tom Rix
  2020-09-24 21:48     ` Russ Weight
  0 siblings, 1 reply; 57+ messages in thread
From: Tom Rix @ 2020-09-06 17:14 UTC (permalink / raw)
  To: Russ Weight, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 9/4/20 4:53 PM, Russ Weight wrote:
> Extend the MAX10 BMC Security Engine driver to include
> a function that returns 64 bits of additional HW specific
> data for errors that require additional information.
> This callback function enables the hw_errinfo sysfs
> node in the Intel Security Manager class driver.
>
> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
> Reviewed-by: Wu Hao <hao.wu@intel.com>
> ---
>  drivers/fpga/intel-m10-bmc-secure.c | 27 ++++++++++++++++++++++++++-
>  1 file changed, 26 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/fpga/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c
> index 4a66c2d448eb..7fb1c805f654 100644
> --- a/drivers/fpga/intel-m10-bmc-secure.c
> +++ b/drivers/fpga/intel-m10-bmc-secure.c
> @@ -450,6 +450,30 @@ static enum ifpga_sec_err m10bmc_sec_cancel(struct ifpga_sec_mgr *imgr)
>  	return ret ? IFPGA_SEC_ERR_RW_ERROR : IFPGA_SEC_ERR_NONE;
>  }
>  
> +static u64 m10bmc_sec_hw_errinfo(struct ifpga_sec_mgr *imgr)
> +{
> +	struct m10bmc_sec *sec = imgr->priv;
> +	u32 doorbell = 0, auth_result = 0;
> +	u64 hw_errinfo = 0;

hw_errinfo should be initialized to some poison value like -1

to cover the case if either of sys_read's fail.

Tom

> +
> +	switch (imgr->err_code) {
> +	case IFPGA_SEC_ERR_HW_ERROR:
> +	case IFPGA_SEC_ERR_TIMEOUT:
> +	case IFPGA_SEC_ERR_BUSY:
> +	case IFPGA_SEC_ERR_WEAROUT:
> +		if (!m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell))
> +			hw_errinfo = (u64)doorbell << 32;
> +
> +		if (!m10bmc_sys_read(sec->m10bmc, M10BMC_AUTH_RESULT,
> +				     &auth_result))
> +			hw_errinfo |= (u64)auth_result;
> +
> +		return hw_errinfo;
> +	default:
> +		return 0;
> +	}
> +}
> +
>  static const struct ifpga_sec_mgr_ops m10bmc_iops = {
>  	.user_flash_count = get_qspi_flash_count,
>  	.bmc_root_entry_hash = get_bmc_root_entry_hash,
> @@ -467,7 +491,8 @@ static const struct ifpga_sec_mgr_ops m10bmc_iops = {
>  	.prepare = m10bmc_sec_prepare,
>  	.write_blk = m10bmc_sec_write_blk,
>  	.poll_complete = m10bmc_sec_poll_complete,
> -	.cancel = m10bmc_sec_cancel
> +	.cancel = m10bmc_sec_cancel,
> +	.get_hw_errinfo = m10bmc_sec_hw_errinfo
>  };
>  
>  static void ifpga_sec_mgr_uinit(struct m10bmc_sec *sec)


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

* Re: [PATCH v1 06/12] fpga: add max10 secure update functions
  2020-09-04 23:52 ` [PATCH v1 06/12] fpga: add max10 secure update functions Russ Weight
  2020-09-06 16:10   ` Tom Rix
@ 2020-09-08  8:05   ` Lee Jones
  1 sibling, 0 replies; 57+ messages in thread
From: Lee Jones @ 2020-09-08  8:05 UTC (permalink / raw)
  To: Russ Weight
  Cc: mdf, linux-fpga, linux-kernel, trix, lgoncalv, yilun.xu, hao.wu,
	matthew.gerlach

On Fri, 04 Sep 2020, Russ Weight wrote:

> Extend the MAX10 BMC Security Engine driver to include
> the functions that enable secure updates of BMC images,
> FPGA images, etc.
> 
> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
> Reviewed-by: Wu Hao <hao.wu@intel.com>
> ---
>  drivers/fpga/intel-m10-bmc-secure.c | 272 +++++++++++++++++++++++++++-
>  include/linux/mfd/intel-m10-bmc.h   | 101 +++++++++++
>  2 files changed, 372 insertions(+), 1 deletion(-)

>  /**
>   * struct intel_m10bmc_retimer_pdata - subdev retimer platform data
>   *
> @@ -64,7 +131,10 @@ struct intel_m10bmc {
>   *
>   * m10bmc_raw_read - read m10bmc register per addr
>   * m10bmc_raw_bulk_read - bulk_read max10 registers per addr
> + * m10bmc_raw_bulk_write - bulk_write max10 registers per addr
> + * m10bmc_raw_update_bits - update max10 register per addr
>   * m10bmc_sys_read - read m10bmc system register per offset
> + * m10bmc_sys_update_bits - update max10 system register per offset
>   */
>  static inline int
>  m10bmc_raw_read(struct intel_m10bmc *m10bmc, unsigned int addr,
> @@ -94,7 +164,38 @@ m10bmc_raw_bulk_read(struct intel_m10bmc *m10bmc, unsigned int addr,
>  	return ret;
>  }
>  
> +static inline int
> +m10bmc_raw_bulk_write(struct intel_m10bmc *m10bmc, unsigned int addr,
> +		      void *val, size_t cnt)
> +{
> +	int ret;
> +
> +	ret = regmap_bulk_write(m10bmc->regmap, addr, val, cnt);
> +	if (ret)
> +		dev_err(m10bmc->dev, "fail to write raw reg %x cnt %zx: %d\n",
> +			addr, cnt, ret);
> +
> +	return ret;
> +}
> +
> +static inline int
> +m10bmc_raw_update_bits(struct intel_m10bmc *m10bmc, unsigned int addr,
> +		       unsigned int msk, unsigned int val)
> +{
> +	int ret;
> +
> +	ret = regmap_update_bits(m10bmc->regmap, addr, msk, val);
> +	if (ret)
> +		dev_err(m10bmc->dev, "fail to update raw reg %x: %d\n",
> +			addr, ret);
> +
> +	return ret;
> +}
> +

I really do dislike abstraction for abstraction's sake.

What's stopping you from just using the Regmap API in-place?

-- 
Lee Jones [李琼斯]
Senior Technical Lead - Developer Services
Linaro.org │ Open source software for Arm SoCs
Follow Linaro: Facebook | Twitter | Blog

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

* Re: [PATCH v1 01/12] fpga: fpga security manager class driver
       [not found]     ` <ebf251a0-5f13-d1a1-6915-e3c940bb19fe@intel.com>
@ 2020-09-10 21:51       ` Tom Rix
  2020-09-10 23:05         ` Russ Weight
  0 siblings, 1 reply; 57+ messages in thread
From: Tom Rix @ 2020-09-10 21:51 UTC (permalink / raw)
  To: Russ Weight, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 9/10/20 1:22 PM, Russ Weight wrote:
>     
>
> On 9/5/20 12:09 PM, Tom Rix wrote:
>
>    
>
>>       
>> On 9/4/20 4:52 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>
>>> ---
>>>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  75 ++++
>>>  MAINTAINERS                                   |   8 +
>>>  drivers/fpga/Kconfig                          |   9 +
>>>  drivers/fpga/Makefile                         |   3 +
>>>  drivers/fpga/ifpga-sec-mgr.c                  | 339 ++++++++++++++++++
>>>  include/linux/fpga/ifpga-sec-mgr.h            | 145 ++++++++
>>>  6 files changed, 579 insertions(+)
>>>  create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>>  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..86f8992559bf
>>> --- /dev/null
>>> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>> @@ -0,0 +1,75 @@
>>> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/name
>>> +Date:		Sep 2020
>>> +KernelVersion:  5.10
>>> +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:		Sep 2020
>>> +KernelVersion:  5.10
>>> +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:		Sep 2020
>>> +KernelVersion:  5.10
>>> +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:		Sep 2020
>>> +KernelVersion:  5.10
>>> +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:		Sep 2020
>>> +KernelVersion:  5.10
>>> +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:		Sep 2020
>>> +KernelVersion:  5.10
>>> +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:		Sep 2020
>>> +KernelVersion:  5.10
>>> +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:		Sep 2020
>>> +KernelVersion:  5.10
>>> +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: "%d".
>>>       
>>       
>> could this be %u ?
>>     
> Yes - I'll make the change for both of the flash update counts.
>
>>       
>>>         
>>> +
>>> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/bmc_flash_count
>>> +Date:		Sep 2020
>>> +KernelVersion:  5.10
>>> +Contact:	Russ Weight <russell.h.weight@intel.com>
>>> +Description:	Read only. Returns number of times the BMC image has been
>>> +		flashed.
>>> +		Format: "%d".
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index deaafb617361..4a2ebe6b120d 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -6830,6 +6830,14 @@ 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:	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 88f64fbf55e3..97c0a6cc2ba7 100644
>>> --- a/drivers/fpga/Kconfig
>>> +++ b/drivers/fpga/Kconfig
>>> @@ -235,4 +235,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 c69bfc931519..ec9fbacdedd8 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..97bf80277ed2
>>> --- /dev/null
>>> +++ b/drivers/fpga/ifpga-sec-mgr.c
>>> @@ -0,0 +1,339 @@
>>> +// 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;
>>> +
>>> +static ssize_t show_canceled_csk(struct ifpga_sec_mgr *imgr,
>>> +				 sysfs_csk_hndlr_t get_csk,
>>> +				 sysfs_csk_nbits_t get_csk_nbits,
>>>       
>>       
>> Param 2&3 can be accessed by imgr->iops so the signature
>>
>> of this and similar functions should be reduced.
>>     
> There are three different types of CSK vectors (sr, pr, and bmc).
> For each type, there are two function pointers. When calling
> show_canceled_csk, it is necessary to identify the type of CSK.
> While it is true that all three pairs of pointers are in imgr->iops,
> I think the easiest way to identify the CSK type is by passing in
> the appropriate pair of pointers.
ok.
>>       
>>       
>>>         
>>> +				 char *buf)
>>> +{
>>> +	unsigned long *csk_map = NULL;
>>> +	unsigned int nbits;
>>> +	int cnt, ret;
>>> +
>>> +	ret = get_csk_nbits(imgr);
>>>       
>>       
>> Any access to a function pointer must check if the
>>
>> the pointer is valid.
>>     
> The pointers are all validated when a device driver registers with the class
> driver. The corresponding CSK sysfs file will only be visible if the pointers
> have been validated. Is that sufficient, or should I add a redundant check
> here? I don't mind doing it if you think it is needed.
ok, fine as-is.
>
>>       
>>       
>>>         
>>> +	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);
>>>       
>>       
>> The type of returned by get_csk_nbits and its use should
>>
>> be consistent. likely this is 'int'
> The CSK data is returned using memory provided by the csk_map pointer parameter. The
> return value is an integer value and provides error/success status. Do you think
> something should be changed here?

Later i comment on how the error code duplicate standard error codes.

It would be good the standard codes could be used, part of that

is returning int.

>
>>       
>>>         
>>> +	if (ret)
>>> +		goto vfree_exit;
>>> +
>>> +	cnt = bitmap_print_to_pagebuf(1, buf, csk_map, nbits);
>>>       
>>       
>> simplify to
>>
>> ret = ..
> Sure - I will do that.
>
>>
>>       
>>>         
>>> +
>>> +vfree_exit:
>>> +	vfree(csk_map);
>>> +	return ret ? : cnt;
>>> +}
>>> +
>>> +static ssize_t show_root_entry_hash(struct ifpga_sec_mgr *imgr,
>>> +				    sysfs_reh_hndlr_t get_reh,
>>> +				    sysfs_reh_size_t get_reh_size,
>>> +				    char *buf)
>>> +{
>>> +	unsigned int size, i;
>>> +	int ret, cnt = 0;
>>> +	u8 *hash;
>>> +
>>> +	ret = get_reh_size(imgr);
>>> +	if (ret < 0)
>>> +		return ret;
>>> +	else if (!ret)
>>> +		return sprintf(buf, "hash not programmed\n");
>>> +
>>> +	size = (unsigned int)ret;
>>>       
>>       
>> does size and i need to unsigned?
> In the context of their usage here, they should never be negative. Sizes are
> typically unsigned, right? Would there be a reason to prefer int over unsigned?

My issue is specifically the typecast. It would be good

if the typecast could be removed.

>
>>       
>>>         
>>> +	hash = vmalloc(size);
>>> +	if (!hash)
>>> +		return -ENOMEM;
>>> +
>>> +	ret = get_reh(imgr, hash, size);
>>> +	if (ret)
>>> +		goto vfree_exit;
>>>       
>>       
>> ret is 0 here
>>
>> so simplify replacing cnt with ret.
> Is the goal to have less variables? It seems like a trade-off with readability...
>
> I can make this change.

The next comment/change will makes this comment superfluous.

ignore it. 

>
>>       
>>>         
>>> +
>>> +	cnt += sprintf(buf, "0x");
>>>       
>>       
>> or change += to =, this is the first time sprintf is done.
> Sure - I 'll just do the assignment instead if initializing to zero.
>
>>       
>>>         
>>> +	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;
>>>       
>>       
>> with simplification this should be
>>
>> return ret;
>>
>>       
>>>         
>>> +}
>>> +
>>> +#define to_sec_mgr(d) container_of(d, struct ifpga_sec_mgr, dev)
>>>       
>>       
>> Since this is used widely move closer to top of file.
> OK
>
>>       
>>>         
>>> +
>>> +#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)
>>> +
>>> +#define DEVICE_ATTR_SEC_FLASH_CNT(_name) \
>>> +static ssize_t _name##_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->_name##_flash_count(imgr); \
>>> +	return cnt < 0 ? cnt : sprintf(buf, "%d\n", cnt); \
>>> +} \
>>> +static DEVICE_ATTR_RO(_name##_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_FLASH_CNT(user);
>>> +DEVICE_ATTR_SEC_FLASH_CNT(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_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));
>>> +
>>> +	if (check_attr(attr, user_flash_count) ||
>>> +	    check_attr(attr, bmc_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;
>>> +
>>>       
>>       
>> This is all or nothing, shouldn't the interface
>>
>> allow for null iop ?
> All or nothing? Each of the above attributes is optional and is enabled by
> providing a handler function. This is the "is_visible" op for sysfs and it
> ensures that only the enabled sysfs entries are displayed (any combination
> of enabled sysfs files).
>
> While these operations are all optional, there are some required operations in iops
> for the update process (in a later patch), so for the overall patchset iops
> cannot be NULL.
Ok. then add a comment.
>
>>       
>>>         
>>> +	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)
>>> +{
>>> +	if (sysfs_handler) {
>>>       
>>       
>> These two checks can be simplified to
>>
>> if (!sysfs_handler || !size_handler)
> That would require changes to the "else if" condition that follows, which
> assumes that syfs_handler is null. The purpose of this block of code is
> to ensure that if the size_handler or the sysfs_handler is defined, that
> they are both defined. It is OK if they are both undefined.
>
> If you wanted to reduce the code, I think we could do something like this, but
> but I'm afraid it might be confusing and less readable.
>
> if (!!size_handler != !!sysfs_handler) {
> 	dev_err(dev, "%s and %s must both be registered to enable the sysfs file\n",
> 		size_handler_name, sysfs_handler_name);
> 	return false;
> }
>
> What do you think?

The more creative uses of '!' the better. ;)

This is fine as-is, maybe add a comment.

>
>>       
>>>         
>>> +		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_register - register an IFPGA security manager struct
>>> + *
>>> + * @dev:  create ifpga 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
>>> + *
>>> + * Returns &struct ifpga_sec_mgr pointer on success, or ERR_PTR() on error.
>>> + */
>>> +struct ifpga_sec_mgr *
>>> +ifpga_sec_mgr_register(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 ERR_PTR(-EINVAL);
>>> +	}
>>> +
>>> +	if (!name || !strlen(name)) {
>>> +		dev_err(dev, "Attempt to register with no name!\n");
>>> +		return ERR_PTR(-EINVAL);
>>> +	}
>>> +
>>> +	imgr = kzalloc(sizeof(*imgr), GFP_KERNEL);
>>> +	if (!imgr)
>>> +		return ERR_PTR(-ENOMEM);
>>> +
>>> +	imgr->name = name;
>>>       
>>       
>> should name be dup-ed?
> The name is string constant that is provided by the underlying device driver
> (from the kernel space) so I don't think it would be necessary to dup the string.

If the underlying driver unloads, the name ptr will be invalid.

Will the driver unregister remove its use here ?

>
>>       
>>>         
>>> +	imgr->priv = priv;
>>> +	imgr->iops = iops;
>>> +	mutex_init(&imgr->lock);
>>> +
>>> +	id = ida_simple_get(&ifpga_sec_mgr_ida, 0, 0, GFP_KERNEL);
>>> +	if (id < 0) {
>>> +		ret = id;
>>> +		goto exit_free;
>>> +	}
>>> +
>>> +	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);
>>> +		ida_simple_remove(&ifpga_sec_mgr_ida, id);
>>> +		goto exit_free;
>>> +	}
>>> +
>>> +	ret = device_register(&imgr->dev);
>>> +	if (ret) {
>>> +		put_device(&imgr->dev);
>>> +		return ERR_PTR(ret);
>>> +	}
>>> +
>>> +	return imgr;
>>> +
>>> +exit_free:
>>> +	kfree(dev);
>>> +	return ERR_PTR(ret);
>>> +}
>>> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_register);
>>> +
>>> +/**
>>> + * ifpga_sec_mgr_unregister - unregister a IFPGA security manager
>>> + *
>>> + * @mgr: fpga manager struct
>>> + *
>>> + * This function is intended for use in a IFPGA 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)
>>> +{
>>> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
>>> +
>>> +	mutex_destroy(&imgr->lock);
>>> +	ida_simple_remove(&ifpga_sec_mgr_ida, imgr->dev.id);
>>> +	kfree(imgr);
>>> +}
>>> +
>>> +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..e391b0c8f448
>>> --- /dev/null
>>> +++ b/include/linux/fpga/ifpga-sec-mgr.h
>>> @@ -0,0 +1,145 @@
>>> +/* 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;
>>> +
>>> +/**
>>> + * typedef sysfs_reh_size_t - Function to return byte size of root entry hash
>>> + *
>>> + * @imgr:      pointer to security manager structure
>>> + *
>>> + * This datatype is used to define a function that returns the byte size of a
>>> + * root entry hash.
>>> + *
>>> + * Context: No locking requirements are imposed by the security manager.
>>> + * Return:  Byte count on success, negative errno on failure
>>> + */
>>> +typedef int (*sysfs_reh_size_t)(struct ifpga_sec_mgr *imgr);
>>> +
>>> +/**
>>> + * typedef sysfs_reh_hndlr_t - Function pointer to sysfs file handler
>>> + *			       for root entry hashes
>>> + * @imgr:      pointer to security manager structure
>>> + * @hash:      pointer to an array of bytes in which to store the hash
>>> + * @size:      byte size of root entry hash
>>> + *
>>> + * This datatype is used to define a sysfs file handler function to
>>> + * return root entry hash data to be displayed via sysfs.
>>> + *
>>> + * Context: No locking requirements are imposed by the security manager.
>>> + * Return:  0 on success, negative errno on failure
>>> + */
>>> +typedef int (*sysfs_reh_hndlr_t)(struct ifpga_sec_mgr *imgr, u8 *hash,
>>> +				 unsigned int size);
>>> +
>>> +/**
>>> + * typedef sysfs_cnt_hndlr_t - Function pointer to sysfs file handler
>>> + *			       for flash counts
>>> + * @imgr: pointer to security manager structure
>>> + *
>>> + * This datatype is used to define a sysfs file handler function to
>>> + * return a flash count to be displayed via sysfs.
>>> + *
>>> + * Context: No locking requirements are imposed by the security manager
>>> + * Return: flash count or negative errno
>>> + */
>>> +typedef int (*sysfs_cnt_hndlr_t)(struct ifpga_sec_mgr *imgr);
>>> +
>>> +/**
>>> + * typedef sysfs_csk_nbits_t - Function to return the number of bits in
>>> + *				      a Code Signing Key cancellation vector
>>> + *
>>> + * @imgr:      pointer to security manager structure
>>> + *
>>> + * This datatype is used to define a function that returns the number of bits
>>> + * in a Code Signing Key cancellation vector.
>>> + *
>>> + * Context: No locking requirements are imposed by the security manager.
>>> + * Return:  Number of bits on success, negative errno on failure
>>> + */
>>> +typedef int (*sysfs_csk_nbits_t)(struct ifpga_sec_mgr *imgr);
>>> +
>>> +/**
>>> + * typedef sysfs_csk_hndlr_t - Function pointer to sysfs file handler
>>> + *			       bit vector of canceled keys
>>> + *
>>> + * @imgr:    pointer to security manager structure
>>> + * @csk_map: pointer to a bitmap to contain cancellation key vector
>>> + * @nbits:   number of bits in CSK vector
>>> + *
>>> + * This datatype is used to define a sysfs file handler function to
>>> + * return a bitmap of canceled keys to be displayed via sysfs.
>>> + *
>>> + * Context: No locking requirements are imposed by the security manager.
>>> + * Return:  0 on success, negative errno on failure
>>> + */
>>> +typedef int (*sysfs_csk_hndlr_t)(struct ifpga_sec_mgr *imgr,
>>> +				 unsigned long *csk_map, unsigned int nbits);
>>> +
>>> +/**
>>> + * struct ifpga_sec_mgr_ops - device specific operations
>>> + * @user_flash_count:	    Optional: Return sysfs string output for FPGA
>>> + *			    image flash count
>>> + * @bmc_flash_count:	    Optional: Return sysfs string output for BMC
>>> + *			    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 {
>>> +	sysfs_cnt_hndlr_t user_flash_count;
>>>       
>>       
>> These typedef's hide the function signatures and are
>>
>> not consistent with how the other headers in include/linux/fpga
>>
>> specify ops.
> OK - I can remove the typedefs.
>
>>       
>>>         
>>> +	sysfs_cnt_hndlr_t bmc_flash_count;
>>> +	sysfs_cnt_hndlr_t smbus_flash_count;
>>> +	sysfs_reh_hndlr_t sr_root_entry_hash;
>>> +	sysfs_reh_hndlr_t pr_root_entry_hash;
>>> +	sysfs_reh_hndlr_t bmc_root_entry_hash;
>>> +	sysfs_csk_hndlr_t sr_canceled_csks;
>>> +	sysfs_csk_hndlr_t pr_canceled_csks;
>>> +	sysfs_csk_hndlr_t bmc_canceled_csks;
>>> +	sysfs_reh_size_t bmc_reh_size;
>>> +	sysfs_reh_size_t sr_reh_size;
>>> +	sysfs_reh_size_t pr_reh_size;
>>> +	sysfs_csk_nbits_t bmc_canceled_csk_nbits;
>>> +	sysfs_csk_nbits_t sr_canceled_csk_nbits;
>>> +	sysfs_csk_nbits_t pr_canceled_csk_nbits;
>>> +};
>>> +
>>> +struct ifpga_sec_mgr {
>>> +	const char *name;
>>> +	struct device dev;
>>> +	const struct ifpga_sec_mgr_ops *iops;
>>> +	struct mutex lock;		/* protect data structure contents */
>>>       
>>       
>> comment is redundant for a lock.
> "scripts/checkpatch.pl --strict" will complain about mutex definitions that do not
> have a comment. Are you asking for a more descriptive comment? Or are you saying
> that the comment is not required?

Fine as-is.

If checkpatch wants it, just do it.

Tom

>
>> Tom
>>
>>       
>>>         
>>> +	void *priv;
>>> +};
>>> +
>>> +struct ifpga_sec_mgr *
>>> +ifpga_sec_mgr_register(struct device *dev, const char *name,
>>> +		       const struct ifpga_sec_mgr_ops *iops, void *priv);
>>> +void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr);
>>> +
>>> +#endif
>>>       
>>     


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

* Re: [PATCH v1 01/12] fpga: fpga security manager class driver
  2020-09-10 21:51       ` Tom Rix
@ 2020-09-10 23:05         ` Russ Weight
  0 siblings, 0 replies; 57+ messages in thread
From: Russ Weight @ 2020-09-10 23:05 UTC (permalink / raw)
  To: Tom Rix, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach



On 9/10/20 2:51 PM, Tom Rix wrote:
> On 9/10/20 1:22 PM, Russ Weight wrote:
>>     
>>
>> On 9/5/20 12:09 PM, Tom Rix wrote:
>>
>>    
>>
>>>       
>>> On 9/4/20 4:52 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>
>>>> ---
>>>>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  75 ++++
>>>>  MAINTAINERS                                   |   8 +
>>>>  drivers/fpga/Kconfig                          |   9 +
>>>>  drivers/fpga/Makefile                         |   3 +
>>>>  drivers/fpga/ifpga-sec-mgr.c                  | 339 ++++++++++++++++++
>>>>  include/linux/fpga/ifpga-sec-mgr.h            | 145 ++++++++
>>>>  6 files changed, 579 insertions(+)
>>>>  create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>>>  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..86f8992559bf
>>>> --- /dev/null
>>>> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>>> @@ -0,0 +1,75 @@
>>>> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/name
>>>> +Date:		Sep 2020
>>>> +KernelVersion:  5.10
>>>> +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:		Sep 2020
>>>> +KernelVersion:  5.10
>>>> +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:		Sep 2020
>>>> +KernelVersion:  5.10
>>>> +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:		Sep 2020
>>>> +KernelVersion:  5.10
>>>> +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:		Sep 2020
>>>> +KernelVersion:  5.10
>>>> +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:		Sep 2020
>>>> +KernelVersion:  5.10
>>>> +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:		Sep 2020
>>>> +KernelVersion:  5.10
>>>> +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:		Sep 2020
>>>> +KernelVersion:  5.10
>>>> +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: "%d".
>>>>       
>>>       
>>> could this be %u ?
>>>     
>> Yes - I'll make the change for both of the flash update counts.
>>
>>>       
>>>>         
>>>> +
>>>> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/bmc_flash_count
>>>> +Date:		Sep 2020
>>>> +KernelVersion:  5.10
>>>> +Contact:	Russ Weight <russell.h.weight@intel.com>
>>>> +Description:	Read only. Returns number of times the BMC image has been
>>>> +		flashed.
>>>> +		Format: "%d".
>>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>>> index deaafb617361..4a2ebe6b120d 100644
>>>> --- a/MAINTAINERS
>>>> +++ b/MAINTAINERS
>>>> @@ -6830,6 +6830,14 @@ 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:	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 88f64fbf55e3..97c0a6cc2ba7 100644
>>>> --- a/drivers/fpga/Kconfig
>>>> +++ b/drivers/fpga/Kconfig
>>>> @@ -235,4 +235,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 c69bfc931519..ec9fbacdedd8 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..97bf80277ed2
>>>> --- /dev/null
>>>> +++ b/drivers/fpga/ifpga-sec-mgr.c
>>>> @@ -0,0 +1,339 @@
>>>> +// 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;
>>>> +
>>>> +static ssize_t show_canceled_csk(struct ifpga_sec_mgr *imgr,
>>>> +				 sysfs_csk_hndlr_t get_csk,
>>>> +				 sysfs_csk_nbits_t get_csk_nbits,
>>>>       
>>>       
>>> Param 2&3 can be accessed by imgr->iops so the signature
>>>
>>> of this and similar functions should be reduced.
>>>     
>> There are three different types of CSK vectors (sr, pr, and bmc).
>> For each type, there are two function pointers. When calling
>> show_canceled_csk, it is necessary to identify the type of CSK.
>> While it is true that all three pairs of pointers are in imgr->iops,
>> I think the easiest way to identify the CSK type is by passing in
>> the appropriate pair of pointers.
> ok.
>>>       
>>>       
>>>>         
>>>> +				 char *buf)
>>>> +{
>>>> +	unsigned long *csk_map = NULL;
>>>> +	unsigned int nbits;
>>>> +	int cnt, ret;
>>>> +
>>>> +	ret = get_csk_nbits(imgr);
>>>>       
>>>       
>>> Any access to a function pointer must check if the
>>>
>>> the pointer is valid.
>>>     
>> The pointers are all validated when a device driver registers with the class
>> driver. The corresponding CSK sysfs file will only be visible if the pointers
>> have been validated. Is that sufficient, or should I add a redundant check
>> here? I don't mind doing it if you think it is needed.
> ok, fine as-is.
>>>       
>>>       
>>>>         
>>>> +	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);
>>>>       
>>>       
>>> The type of returned by get_csk_nbits and its use should
>>>
>>> be consistent. likely this is 'int'
>> The CSK data is returned using memory provided by the csk_map pointer parameter. The
>> return value is an integer value and provides error/success status. Do you think
>> something should be changed here?
> Later i comment on how the error code duplicate standard error codes.
>
> It would be good the standard codes could be used, part of that
>
> is returning int.

get_csk_nbits() _does_ return int.
 

>>>       
>>>>         
>>>> +	if (ret)
>>>> +		goto vfree_exit;
>>>> +
>>>> +	cnt = bitmap_print_to_pagebuf(1, buf, csk_map, nbits);
>>>>       
>>>       
>>> simplify to
>>>
>>> ret = ..
>> Sure - I will do that.
>>
>>>       
>>>>         
>>>> +
>>>> +vfree_exit:
>>>> +	vfree(csk_map);
>>>> +	return ret ? : cnt;
>>>> +}
>>>> +
>>>> +static ssize_t show_root_entry_hash(struct ifpga_sec_mgr *imgr,
>>>> +				    sysfs_reh_hndlr_t get_reh,
>>>> +				    sysfs_reh_size_t get_reh_size,
>>>> +				    char *buf)
>>>> +{
>>>> +	unsigned int size, i;
>>>> +	int ret, cnt = 0;
>>>> +	u8 *hash;
>>>> +
>>>> +	ret = get_reh_size(imgr);
>>>> +	if (ret < 0)
>>>> +		return ret;
>>>> +	else if (!ret)
>>>> +		return sprintf(buf, "hash not programmed\n");
>>>> +
>>>> +	size = (unsigned int)ret;
>>>>       
>>>       
>>> does size and i need to unsigned?
>> In the context of their usage here, they should never be negative. Sizes are
>> typically unsigned, right? Would there be a reason to prefer int over unsigned?
> My issue is specifically the typecast. It would be good
>
> if the typecast could be removed.

OK - I can change the types so that the typecast can be dropped.

>
>>>       
>>>>         
>>>> +	hash = vmalloc(size);
>>>> +	if (!hash)
>>>> +		return -ENOMEM;
>>>> +
>>>> +	ret = get_reh(imgr, hash, size);
>>>> +	if (ret)
>>>> +		goto vfree_exit;
>>>>       
>>>       
>>> ret is 0 here
>>>
>>> so simplify replacing cnt with ret.
>> Is the goal to have less variables? It seems like a trade-off with readability...
>>
>> I can make this change.
> The next comment/change will makes this comment superfluous.
>
> ignore it. 
>
>>>       
>>>>         
>>>> +
>>>> +	cnt += sprintf(buf, "0x");
>>>>       
>>>       
>>> or change += to =, this is the first time sprintf is done.
>> Sure - I 'll just do the assignment instead if initializing to zero.
>>
>>>       
>>>>         
>>>> +	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;
>>>>       
>>>       
>>> with simplification this should be
>>>
>>> return ret;
>>>
>>>       
>>>>         
>>>> +}
>>>> +
>>>> +#define to_sec_mgr(d) container_of(d, struct ifpga_sec_mgr, dev)
>>>>       
>>>       
>>> Since this is used widely move closer to top of file.
>> OK
>>
>>>       
>>>>         
>>>> +
>>>> +#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)
>>>> +
>>>> +#define DEVICE_ATTR_SEC_FLASH_CNT(_name) \
>>>> +static ssize_t _name##_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->_name##_flash_count(imgr); \
>>>> +	return cnt < 0 ? cnt : sprintf(buf, "%d\n", cnt); \
>>>> +} \
>>>> +static DEVICE_ATTR_RO(_name##_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_FLASH_CNT(user);
>>>> +DEVICE_ATTR_SEC_FLASH_CNT(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_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));
>>>> +
>>>> +	if (check_attr(attr, user_flash_count) ||
>>>> +	    check_attr(attr, bmc_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;
>>>> +
>>>>       
>>>       
>>> This is all or nothing, shouldn't the interface
>>>
>>> allow for null iop ?
>> All or nothing? Each of the above attributes is optional and is enabled by
>> providing a handler function. This is the "is_visible" op for sysfs and it
>> ensures that only the enabled sysfs entries are displayed (any combination
>> of enabled sysfs files).
>>
>> While these operations are all optional, there are some required operations in iops
>> for the update process (in a later patch), so for the overall patchset iops
>> cannot be NULL.
> Ok. then add a comment.

Will do.

>>>       
>>>>         
>>>> +	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)
>>>> +{
>>>> +	if (sysfs_handler) {
>>>>       
>>>       
>>> These two checks can be simplified to
>>>
>>> if (!sysfs_handler || !size_handler)
>> That would require changes to the "else if" condition that follows, which
>> assumes that syfs_handler is null. The purpose of this block of code is
>> to ensure that if the size_handler or the sysfs_handler is defined, that
>> they are both defined. It is OK if they are both undefined.
>>
>> If you wanted to reduce the code, I think we could do something like this, but
>> but I'm afraid it might be confusing and less readable.
>>
>> if (!!size_handler != !!sysfs_handler) {
>> 	dev_err(dev, "%s and %s must both be registered to enable the sysfs file\n",
>> 		size_handler_name, sysfs_handler_name);
>> 	return false;
>> }
>>
>> What do you think?
> The more creative uses of '!' the better. ;)
>
> This is fine as-is, maybe add a comment.
>
>>>       
>>>>         
>>>> +		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_register - register an IFPGA security manager struct
>>>> + *
>>>> + * @dev:  create ifpga 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
>>>> + *
>>>> + * Returns &struct ifpga_sec_mgr pointer on success, or ERR_PTR() on error.
>>>> + */
>>>> +struct ifpga_sec_mgr *
>>>> +ifpga_sec_mgr_register(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 ERR_PTR(-EINVAL);
>>>> +	}
>>>> +
>>>> +	if (!name || !strlen(name)) {
>>>> +		dev_err(dev, "Attempt to register with no name!\n");
>>>> +		return ERR_PTR(-EINVAL);
>>>> +	}
>>>> +
>>>> +	imgr = kzalloc(sizeof(*imgr), GFP_KERNEL);
>>>> +	if (!imgr)
>>>> +		return ERR_PTR(-ENOMEM);
>>>> +
>>>> +	imgr->name = name;
>>>>       
>>>       
>>> should name be dup-ed?
>> The name is string constant that is provided by the underlying device driver
>> (from the kernel space) so I don't think it would be necessary to dup the string.
> If the underlying driver unloads, the name ptr will be invalid.
>
> Will the driver unregister remove its use here ?
Yes. If the underlying driver is unloaded, it will unregister with the class driver.
>
>>>       
>>>>         
>>>> +	imgr->priv = priv;
>>>> +	imgr->iops = iops;
>>>> +	mutex_init(&imgr->lock);
>>>> +
>>>> +	id = ida_simple_get(&ifpga_sec_mgr_ida, 0, 0, GFP_KERNEL);
>>>> +	if (id < 0) {
>>>> +		ret = id;
>>>> +		goto exit_free;
>>>> +	}
>>>> +
>>>> +	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);
>>>> +		ida_simple_remove(&ifpga_sec_mgr_ida, id);
>>>> +		goto exit_free;
>>>> +	}
>>>> +
>>>> +	ret = device_register(&imgr->dev);
>>>> +	if (ret) {
>>>> +		put_device(&imgr->dev);
>>>> +		return ERR_PTR(ret);
>>>> +	}
>>>> +
>>>> +	return imgr;
>>>> +
>>>> +exit_free:
>>>> +	kfree(dev);
>>>> +	return ERR_PTR(ret);
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_register);
>>>> +
>>>> +/**
>>>> + * ifpga_sec_mgr_unregister - unregister a IFPGA security manager
>>>> + *
>>>> + * @mgr: fpga manager struct
>>>> + *
>>>> + * This function is intended for use in a IFPGA 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)
>>>> +{
>>>> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
>>>> +
>>>> +	mutex_destroy(&imgr->lock);
>>>> +	ida_simple_remove(&ifpga_sec_mgr_ida, imgr->dev.id);
>>>> +	kfree(imgr);
>>>> +}
>>>> +
>>>> +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..e391b0c8f448
>>>> --- /dev/null
>>>> +++ b/include/linux/fpga/ifpga-sec-mgr.h
>>>> @@ -0,0 +1,145 @@
>>>> +/* 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;
>>>> +
>>>> +/**
>>>> + * typedef sysfs_reh_size_t - Function to return byte size of root entry hash
>>>> + *
>>>> + * @imgr:      pointer to security manager structure
>>>> + *
>>>> + * This datatype is used to define a function that returns the byte size of a
>>>> + * root entry hash.
>>>> + *
>>>> + * Context: No locking requirements are imposed by the security manager.
>>>> + * Return:  Byte count on success, negative errno on failure
>>>> + */
>>>> +typedef int (*sysfs_reh_size_t)(struct ifpga_sec_mgr *imgr);
>>>> +
>>>> +/**
>>>> + * typedef sysfs_reh_hndlr_t - Function pointer to sysfs file handler
>>>> + *			       for root entry hashes
>>>> + * @imgr:      pointer to security manager structure
>>>> + * @hash:      pointer to an array of bytes in which to store the hash
>>>> + * @size:      byte size of root entry hash
>>>> + *
>>>> + * This datatype is used to define a sysfs file handler function to
>>>> + * return root entry hash data to be displayed via sysfs.
>>>> + *
>>>> + * Context: No locking requirements are imposed by the security manager.
>>>> + * Return:  0 on success, negative errno on failure
>>>> + */
>>>> +typedef int (*sysfs_reh_hndlr_t)(struct ifpga_sec_mgr *imgr, u8 *hash,
>>>> +				 unsigned int size);
>>>> +
>>>> +/**
>>>> + * typedef sysfs_cnt_hndlr_t - Function pointer to sysfs file handler
>>>> + *			       for flash counts
>>>> + * @imgr: pointer to security manager structure
>>>> + *
>>>> + * This datatype is used to define a sysfs file handler function to
>>>> + * return a flash count to be displayed via sysfs.
>>>> + *
>>>> + * Context: No locking requirements are imposed by the security manager
>>>> + * Return: flash count or negative errno
>>>> + */
>>>> +typedef int (*sysfs_cnt_hndlr_t)(struct ifpga_sec_mgr *imgr);
>>>> +
>>>> +/**
>>>> + * typedef sysfs_csk_nbits_t - Function to return the number of bits in
>>>> + *				      a Code Signing Key cancellation vector
>>>> + *
>>>> + * @imgr:      pointer to security manager structure
>>>> + *
>>>> + * This datatype is used to define a function that returns the number of bits
>>>> + * in a Code Signing Key cancellation vector.
>>>> + *
>>>> + * Context: No locking requirements are imposed by the security manager.
>>>> + * Return:  Number of bits on success, negative errno on failure
>>>> + */
>>>> +typedef int (*sysfs_csk_nbits_t)(struct ifpga_sec_mgr *imgr);
>>>> +
>>>> +/**
>>>> + * typedef sysfs_csk_hndlr_t - Function pointer to sysfs file handler
>>>> + *			       bit vector of canceled keys
>>>> + *
>>>> + * @imgr:    pointer to security manager structure
>>>> + * @csk_map: pointer to a bitmap to contain cancellation key vector
>>>> + * @nbits:   number of bits in CSK vector
>>>> + *
>>>> + * This datatype is used to define a sysfs file handler function to
>>>> + * return a bitmap of canceled keys to be displayed via sysfs.
>>>> + *
>>>> + * Context: No locking requirements are imposed by the security manager.
>>>> + * Return:  0 on success, negative errno on failure
>>>> + */
>>>> +typedef int (*sysfs_csk_hndlr_t)(struct ifpga_sec_mgr *imgr,
>>>> +				 unsigned long *csk_map, unsigned int nbits);
>>>> +
>>>> +/**
>>>> + * struct ifpga_sec_mgr_ops - device specific operations
>>>> + * @user_flash_count:	    Optional: Return sysfs string output for FPGA
>>>> + *			    image flash count
>>>> + * @bmc_flash_count:	    Optional: Return sysfs string output for BMC
>>>> + *			    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 {
>>>> +	sysfs_cnt_hndlr_t user_flash_count;
>>>>       
>>>       
>>> These typedef's hide the function signatures and are
>>>
>>> not consistent with how the other headers in include/linux/fpga
>>>
>>> specify ops.
>> OK - I can remove the typedefs.
>>
>>>       
>>>>         
>>>> +	sysfs_cnt_hndlr_t bmc_flash_count;
>>>> +	sysfs_cnt_hndlr_t smbus_flash_count;
>>>> +	sysfs_reh_hndlr_t sr_root_entry_hash;
>>>> +	sysfs_reh_hndlr_t pr_root_entry_hash;
>>>> +	sysfs_reh_hndlr_t bmc_root_entry_hash;
>>>> +	sysfs_csk_hndlr_t sr_canceled_csks;
>>>> +	sysfs_csk_hndlr_t pr_canceled_csks;
>>>> +	sysfs_csk_hndlr_t bmc_canceled_csks;
>>>> +	sysfs_reh_size_t bmc_reh_size;
>>>> +	sysfs_reh_size_t sr_reh_size;
>>>> +	sysfs_reh_size_t pr_reh_size;
>>>> +	sysfs_csk_nbits_t bmc_canceled_csk_nbits;
>>>> +	sysfs_csk_nbits_t sr_canceled_csk_nbits;
>>>> +	sysfs_csk_nbits_t pr_canceled_csk_nbits;
>>>> +};
>>>> +
>>>> +struct ifpga_sec_mgr {
>>>> +	const char *name;
>>>> +	struct device dev;
>>>> +	const struct ifpga_sec_mgr_ops *iops;
>>>> +	struct mutex lock;		/* protect data structure contents */
>>>>       
>>>       
>>> comment is redundant for a lock.
>> "scripts/checkpatch.pl --strict" will complain about mutex definitions that do not
>> have a comment. Are you asking for a more descriptive comment? Or are you saying
>> that the comment is not required?
> Fine as-is.
>
> If checkpatch wants it, just do it.
>
> Tom
>
>>> Tom
>>>
>>>       
>>>>         
>>>> +	void *priv;
>>>> +};
>>>> +
>>>> +struct ifpga_sec_mgr *
>>>> +ifpga_sec_mgr_register(struct device *dev, const char *name,
>>>> +		       const struct ifpga_sec_mgr_ops *iops, void *priv);
>>>> +void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr);
>>>> +
>>>> +#endif
>>>>       
>>>     


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

* Re: [PATCH v1 02/12] fpga: create intel max10 bmc security engine
  2020-09-05 20:22   ` Tom Rix
@ 2020-09-14 19:07     ` Russ Weight
  2020-09-14 20:48       ` Tom Rix
  0 siblings, 1 reply; 57+ messages in thread
From: Russ Weight @ 2020-09-14 19:07 UTC (permalink / raw)
  To: Tom Rix, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach



On 9/5/20 1:22 PM, Tom Rix wrote:
> On 9/4/20 4:52 PM, Russ Weight wrote:
>> Create a platform driver that can be invoked as a sub
>> driver for the Intel MAX10 BMC in order to support
>> secure updates. This sub-driver will invoke an
>> instance of the Intel FPGA Security Manager class driver
>> in order to expose sysfs interfaces for managing and
>> monitoring secure updates to FPGA and BMC images.
>>
>> This patch creates the MAX10 BMC Security Engine driver and
>> provides support for displaying the current root entry hashes
>> for the FPGA static region, the FPGA PR region, and the MAX10
>> BMC.
>>
>> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
>> Reviewed-by: Wu Hao <hao.wu@intel.com>
>> ---
>>  drivers/fpga/Kconfig                |  11 ++
>>  drivers/fpga/Makefile               |   3 +
>>  drivers/fpga/intel-m10-bmc-secure.c | 170 ++++++++++++++++++++++++++++
>>  include/linux/mfd/intel-m10-bmc.h   |  15 +++
>>  4 files changed, 199 insertions(+)
>>  create mode 100644 drivers/fpga/intel-m10-bmc-secure.c
>>
>> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
>> index 97c0a6cc2ba7..0f0bed68e618 100644
>> --- a/drivers/fpga/Kconfig
>> +++ b/drivers/fpga/Kconfig
>> @@ -244,4 +244,15 @@ config IFPGA_SEC_MGR
>>  	  region and for the BMC. Select this option to enable
>>  	  updates for secure FPGA devices.
>>  
>> +config IFPGA_M10_BMC_SECURE
>> +        tristate "Intel MAX10 BMC security engine"
>> +	depends on MFD_INTEL_M10_BMC && IFPGA_SEC_MGR
>> +        help
>> +          Secure update support for the Intel MAX10 board management
>> +	  controller.
>> +
>> +	  This is a subdriver of the Intel MAX10 board management controller
>> +	  (BMC) and provides support for secure updates for the BMC image,
>> +	  the FPGA image, the Root Entry Hashes, etc.
>> +
>>  endif # FPGA
>> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
>> index ec9fbacdedd8..451a23ec3168 100644
>> --- a/drivers/fpga/Makefile
>> +++ b/drivers/fpga/Makefile
>> @@ -24,6 +24,9 @@ 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
>>  
>> +# Intel Security Manager Drivers
>> +obj-$(CONFIG_IFPGA_M10_BMC_SECURE)	+= intel-m10-bmc-secure.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/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c
>> new file mode 100644
>> index 000000000000..1f86bfb694b4
>> --- /dev/null
>> +++ b/drivers/fpga/intel-m10-bmc-secure.c
>> @@ -0,0 +1,170 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Intel Max10 Board Management Controller Security Engine Driver
>> + *
>> + * Copyright (C) 2019-2020 Intel Corporation. All rights reserved.
>> + *
>> + */
>> +#include <linux/device.h>
>> +#include <linux/fpga/ifpga-sec-mgr.h>
>> +#include <linux/mfd/intel-m10-bmc.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/vmalloc.h>
>> +
>> +struct m10bmc_sec {
>> +	struct device *dev;
>> +	struct intel_m10bmc *m10bmc;
>> +	struct ifpga_sec_mgr *imgr;
>> +};
>> +
>> +#define SHA256_REH_SIZE		32
>> +#define SHA384_REH_SIZE		48
>> +
>> +static int get_reh_size(struct ifpga_sec_mgr *imgr,
>> +			u32 exp_magic, u32 prog_addr)
>> +{
>> +	struct m10bmc_sec *sec = imgr->priv;
>> +	int sha_num_bytes, ret;
>> +	u32 magic;
>> +
>> +	ret = m10bmc_raw_read(sec->m10bmc, prog_addr, &magic);
>> +	if (ret)
>> +		return ret;
>> +
>> +	dev_dbg(sec->dev, "%s magic 0x%08x\n", __func__, magic);
>> +
>> +	if ((magic & 0xffff) != exp_magic)
> return -EINVAL ?

The absence of the magic number indicates that a Root Entry Hash has
not been programmed. So a null string (string size of zero) is appropriate
here.

I'll add a comment.

>> +		return 0;
>> +
>> +	sha_num_bytes = ((magic >> 16) & 0xffff) / 8;
>> +
>> +	if (sha_num_bytes != SHA256_REH_SIZE &&
>> +	    sha_num_bytes != SHA384_REH_SIZE)   {
>> +		dev_err(sec->dev, "%s bad sha num bytes %d\n", __func__,
>> +			sha_num_bytes);
>> +		return -EINVAL;
>> +	}
>> +
>> +	return sha_num_bytes;
>> +}
>> +
>> +#define BMC_REH_ADDR 0x17ffc004
>> +#define BMC_PROG_ADDR 0x17ffc000
>> +#define BMC_PROG_MAGIC 0x5746
>> +
>> +#define SR_REH_ADDR 0x17ffd004
>> +#define SR_PROG_ADDR 0x17ffd000
>> +#define SR_PROG_MAGIC 0x5253
>> +
>> +#define PR_REH_ADDR 0x17ffe004
>> +#define PR_PROG_ADDR 0x17ffe000
>> +#define PR_PROG_MAGIC 0x5250
> Why shouldn't these #defines be collected in the intel-m10-bmc.h ?

Placing them in intel-m10-bmc-h would give them a broader scope and make them
available to all m10-bmc sub-drivers. I placed them here to limit the scope to
the only file that should care about these definitions.

Is this OK - or should they be moved to the header file?

>> +
>> +#define SYSFS_GET_REH_SIZE(_name, _exp_magic, _prog_addr) \
>> +static int get_##_name##_reh_size(struct ifpga_sec_mgr *imgr) \
>> +{ \
>> +	return get_reh_size(imgr, _exp_magic, _prog_addr); \
>> +}
> Is this macro overkill for a 1 liner ?

It gives a slight reduction in code. I could go either way. What do you think? Should I take out the macros? Or leave it as is?

>> +
>> +SYSFS_GET_REH_SIZE(bmc, BMC_PROG_MAGIC, BMC_PROG_ADDR)
>> +SYSFS_GET_REH_SIZE(sr, SR_PROG_MAGIC, SR_PROG_ADDR)
>> +SYSFS_GET_REH_SIZE(pr, PR_PROG_MAGIC, PR_PROG_ADDR)
> These and similar below do not directly interact
>
> with the sysfs so the sysfs_ prefix should not be needed.

OK - I'll remove the SYSFS_ prefix.

>
>> +
>> +static int get_root_entry_hash(struct ifpga_sec_mgr *imgr,
>> +			       u32 hash_addr, u8 *hash,
>> +			       unsigned int size)
>> +{
>> +	struct m10bmc_sec *sec = imgr->priv;
>> +	unsigned int stride = regmap_get_reg_stride(sec->m10bmc->regmap);
>> +	int ret;
>> +
>> +	ret = m10bmc_raw_bulk_read(sec->m10bmc, hash_addr,
>> +				   hash, size / stride);
>> +	if (ret)
>> +		dev_err(sec->dev, "bulk_read of 0x%x failed %d",
>> +			hash_addr, ret);
>> +
>> +	return ret;
>> +}
>> +
>> +#define SYSFS_GET_REH(_name, _hash_addr) \
>> +static int get_##_name##_root_entry_hash(struct ifpga_sec_mgr *imgr, \
>> +					 u8 *hash, unsigned int size) \
>> +{ \
>> +	return get_root_entry_hash(imgr, _hash_addr, hash, size); \
>> +}
>> +
>> +SYSFS_GET_REH(bmc, BMC_REH_ADDR)
>> +SYSFS_GET_REH(sr, SR_REH_ADDR)
>> +SYSFS_GET_REH(pr, PR_REH_ADDR)
>> +
>> +static const struct ifpga_sec_mgr_ops m10bmc_iops = {
>> +	.bmc_root_entry_hash = get_bmc_root_entry_hash,
>> +	.sr_root_entry_hash = get_sr_root_entry_hash,
>> +	.pr_root_entry_hash = get_pr_root_entry_hash,
>> +	.bmc_reh_size = get_bmc_reh_size,
>> +	.sr_reh_size = get_sr_reh_size,
>> +	.pr_reh_size = get_pr_reh_size,
> The prefix of the ops should be similar to the file name.
>
> so consider changing get_pr_reh_size to max10_pr_reh_size

I'll switch to a prefix of m10bmc_ to be consistent with the probe and
remove functions.

>
>> +};
>> +
>> +static void ifpga_sec_mgr_uinit(struct m10bmc_sec *sec)
>> +{
>> +	ifpga_sec_mgr_unregister(sec->imgr);
>> +}
>> +
>> +static int ifpga_sec_mgr_init(struct m10bmc_sec *sec)
>> +{
>> +	struct ifpga_sec_mgr *imgr;
>> +
>> +	imgr = ifpga_sec_mgr_register(sec->dev, "Max10 BMC Security Manager",
>> +				      &m10bmc_iops, sec);
>> +	if (IS_ERR(imgr))
>> +		return PTR_ERR(imgr);
>> +
>> +	sec->imgr = imgr;
>> +	return 0;
>> +}
>> +
>> +static int m10bmc_secure_probe(struct platform_device *pdev)
>> +{
>> +	struct m10bmc_sec *sec;
>> +	int ret;
>> +
>> +	sec = devm_kzalloc(&pdev->dev, sizeof(*sec), GFP_KERNEL);
>> +	if (!sec)
>> +		return -ENOMEM;
>> +
>> +	sec->dev = &pdev->dev;
>> +	sec->m10bmc = dev_get_drvdata(pdev->dev.parent);
>> +	dev_set_drvdata(&pdev->dev, sec);
>> +
>> +	ret = ifpga_sec_mgr_init(sec);
>> +	if (ret)
>> +		dev_err(&pdev->dev,
>> +			"Security manager failed to start: %d\n", ret);
>> +
>> +	return ret;
>> +}
>> +
>> +static int m10bmc_secure_remove(struct platform_device *pdev)
>> +{
>> +	struct m10bmc_sec *sec = dev_get_drvdata(&pdev->dev);
>> +
>> +	ifpga_sec_mgr_uinit(sec);
>> +	return 0;
>> +}
>> +
>> +static struct platform_driver intel_m10bmc_secure_driver = {
>> +	.probe = m10bmc_secure_probe,
>> +	.remove = m10bmc_secure_remove,
>> +	.driver = {
>> +		.name = "n3000bmc-secure",
> From the filename, should this be "max10bmc-secure" ?

This driver file will also service other devices. A future patch will add support
for the d5005 card and the same driver code will be used, with some conditional
logic, to support the d5005 card under the name "d5005bmc-secure". See the following
link for a preview of these changes.

https://github.com/OPAE/linux-dfl/blob/8e94e1f41c1571a322aac0c8d6ab8ee282e45016/drivers/mfd/intel-m10-bmc-secure.c#L803

I chose to put n3000 in the name now so that the driver name (visible to user
space applications) will not have to change names the d5005 functionality is added.

The source filename is intel-m10-bmc-secure.c. Would it be better to call this driver
n3000-m10bmc-secure? 

Should I introduce the struct platform_device_id array (see the above link) now with
a single entry for the n3000? So that the initial version of this file will contain
the main driver name (intel-m10bmc-secure) as well as the n3000bmc-secure name?

>
>> +	},
>> +};
>> +module_platform_driver(intel_m10bmc_secure_driver);
>> +
>> +MODULE_ALIAS("platform:n3000bmc-secure");
>> +MODULE_AUTHOR("Intel Corporation");
>> +MODULE_DESCRIPTION("Intel MAX10 BMC secure engine");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h
>> index d4cb01b73357..7fe465c320c2 100644
>> --- a/include/linux/mfd/intel-m10-bmc.h
>> +++ b/include/linux/mfd/intel-m10-bmc.h
>> @@ -63,6 +63,7 @@ struct intel_m10bmc {
>>   * register access helper functions.
>>   *
>>   * m10bmc_raw_read - read m10bmc register per addr
>> + * m10bmc_raw_bulk_read - bulk_read max10 registers per addr
> second '_' should be removed so it reads like
>
> bulk read max10 registers..

Thanks for the comments! I'll fix this.

>
> Tom
>
>>   * m10bmc_sys_read - read m10bmc system register per offset
>>   */
>>  static inline int
>> @@ -79,6 +80,20 @@ m10bmc_raw_read(struct intel_m10bmc *m10bmc, unsigned int addr,
>>  	return ret;
>>  }
>>  
>> +static inline int
>> +m10bmc_raw_bulk_read(struct intel_m10bmc *m10bmc, unsigned int addr,
>> +		     void *val, size_t cnt)
>> +{
>> +	int ret;
>> +
>> +	ret = regmap_bulk_read(m10bmc->regmap, addr, val, cnt);
>> +	if (ret)
>> +		dev_err(m10bmc->dev, "fail to read raw reg %x cnt %zx: %d\n",
>> +			addr, cnt, ret);
>> +
>> +	return ret;
>> +}
>> +
>>  #define m10bmc_sys_read(m10bmc, offset, val) \
>>  	m10bmc_raw_read(m10bmc, M10BMC_SYS_BASE + (offset), val)
>>  


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

* Re: [PATCH v1 02/12] fpga: create intel max10 bmc security engine
  2020-09-14 19:07     ` Russ Weight
@ 2020-09-14 20:48       ` Tom Rix
  2020-09-14 21:40         ` Russ Weight
  0 siblings, 1 reply; 57+ messages in thread
From: Tom Rix @ 2020-09-14 20:48 UTC (permalink / raw)
  To: Russ Weight, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 9/14/20 12:07 PM, Russ Weight wrote:
>
> On 9/5/20 1:22 PM, Tom Rix wrote:
>> On 9/4/20 4:52 PM, Russ Weight wrote:
>>> Create a platform driver that can be invoked as a sub
>>> driver for the Intel MAX10 BMC in order to support
>>> secure updates. This sub-driver will invoke an
>>> instance of the Intel FPGA Security Manager class driver
>>> in order to expose sysfs interfaces for managing and
>>> monitoring secure updates to FPGA and BMC images.
>>>
>>> This patch creates the MAX10 BMC Security Engine driver and
>>> provides support for displaying the current root entry hashes
>>> for the FPGA static region, the FPGA PR region, and the MAX10
>>> BMC.
>>>
>>> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
>>> Reviewed-by: Wu Hao <hao.wu@intel.com>
>>> ---
>>>  drivers/fpga/Kconfig                |  11 ++
>>>  drivers/fpga/Makefile               |   3 +
>>>  drivers/fpga/intel-m10-bmc-secure.c | 170 ++++++++++++++++++++++++++++
>>>  include/linux/mfd/intel-m10-bmc.h   |  15 +++
>>>  4 files changed, 199 insertions(+)
>>>  create mode 100644 drivers/fpga/intel-m10-bmc-secure.c
>>>
>>> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
>>> index 97c0a6cc2ba7..0f0bed68e618 100644
>>> --- a/drivers/fpga/Kconfig
>>> +++ b/drivers/fpga/Kconfig
>>> @@ -244,4 +244,15 @@ config IFPGA_SEC_MGR
>>>  	  region and for the BMC. Select this option to enable
>>>  	  updates for secure FPGA devices.
>>>  
>>> +config IFPGA_M10_BMC_SECURE
>>> +        tristate "Intel MAX10 BMC security engine"
>>> +	depends on MFD_INTEL_M10_BMC && IFPGA_SEC_MGR
>>> +        help
>>> +          Secure update support for the Intel MAX10 board management
>>> +	  controller.
>>> +
>>> +	  This is a subdriver of the Intel MAX10 board management controller
>>> +	  (BMC) and provides support for secure updates for the BMC image,
>>> +	  the FPGA image, the Root Entry Hashes, etc.
>>> +
>>>  endif # FPGA
>>> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
>>> index ec9fbacdedd8..451a23ec3168 100644
>>> --- a/drivers/fpga/Makefile
>>> +++ b/drivers/fpga/Makefile
>>> @@ -24,6 +24,9 @@ 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
>>>  
>>> +# Intel Security Manager Drivers
>>> +obj-$(CONFIG_IFPGA_M10_BMC_SECURE)	+= intel-m10-bmc-secure.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/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c
>>> new file mode 100644
>>> index 000000000000..1f86bfb694b4
>>> --- /dev/null
>>> +++ b/drivers/fpga/intel-m10-bmc-secure.c
>>> @@ -0,0 +1,170 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Intel Max10 Board Management Controller Security Engine Driver
>>> + *
>>> + * Copyright (C) 2019-2020 Intel Corporation. All rights reserved.
>>> + *
>>> + */
>>> +#include <linux/device.h>
>>> +#include <linux/fpga/ifpga-sec-mgr.h>
>>> +#include <linux/mfd/intel-m10-bmc.h>
>>> +#include <linux/module.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/vmalloc.h>
>>> +
>>> +struct m10bmc_sec {
>>> +	struct device *dev;
>>> +	struct intel_m10bmc *m10bmc;
>>> +	struct ifpga_sec_mgr *imgr;
>>> +};
>>> +
>>> +#define SHA256_REH_SIZE		32
>>> +#define SHA384_REH_SIZE		48
>>> +
>>> +static int get_reh_size(struct ifpga_sec_mgr *imgr,
>>> +			u32 exp_magic, u32 prog_addr)
>>> +{
>>> +	struct m10bmc_sec *sec = imgr->priv;
>>> +	int sha_num_bytes, ret;
>>> +	u32 magic;
>>> +
>>> +	ret = m10bmc_raw_read(sec->m10bmc, prog_addr, &magic);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	dev_dbg(sec->dev, "%s magic 0x%08x\n", __func__, magic);
>>> +
>>> +	if ((magic & 0xffff) != exp_magic)
>> return -EINVAL ?
> The absence of the magic number indicates that a Root Entry Hash has
> not been programmed. So a null string (string size of zero) is appropriate
> here.
>
> I'll add a comment.
>
>>> +		return 0;
>>> +
>>> +	sha_num_bytes = ((magic >> 16) & 0xffff) / 8;
>>> +
>>> +	if (sha_num_bytes != SHA256_REH_SIZE &&
>>> +	    sha_num_bytes != SHA384_REH_SIZE)   {
>>> +		dev_err(sec->dev, "%s bad sha num bytes %d\n", __func__,
>>> +			sha_num_bytes);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	return sha_num_bytes;
>>> +}
>>> +
>>> +#define BMC_REH_ADDR 0x17ffc004
>>> +#define BMC_PROG_ADDR 0x17ffc000
>>> +#define BMC_PROG_MAGIC 0x5746
>>> +
>>> +#define SR_REH_ADDR 0x17ffd004
>>> +#define SR_PROG_ADDR 0x17ffd000
>>> +#define SR_PROG_MAGIC 0x5253
>>> +
>>> +#define PR_REH_ADDR 0x17ffe004
>>> +#define PR_PROG_ADDR 0x17ffe000
>>> +#define PR_PROG_MAGIC 0x5250
>> Why shouldn't these #defines be collected in the intel-m10-bmc.h ?
> Placing them in intel-m10-bmc-h would give them a broader scope and make them
> available to all m10-bmc sub-drivers. I placed them here to limit the scope to
> the only file that should care about these definitions.
>
> Is this OK - or should they be moved to the header file?

My thinking keeping all the register defines in one place is

better than spreading it all out.  This would help with possible

future changes that effected the entire register set.

>
>>> +
>>> +#define SYSFS_GET_REH_SIZE(_name, _exp_magic, _prog_addr) \
>>> +static int get_##_name##_reh_size(struct ifpga_sec_mgr *imgr) \
>>> +{ \
>>> +	return get_reh_size(imgr, _exp_magic, _prog_addr); \
>>> +}
>> Is this macro overkill for a 1 liner ?
> It gives a slight reduction in code. I could go either way. What do you think? Should I take out the macros? Or leave it as is?
>
>>> +
>>> +SYSFS_GET_REH_SIZE(bmc, BMC_PROG_MAGIC, BMC_PROG_ADDR)
>>> +SYSFS_GET_REH_SIZE(sr, SR_PROG_MAGIC, SR_PROG_ADDR)
>>> +SYSFS_GET_REH_SIZE(pr, PR_PROG_MAGIC, PR_PROG_ADDR)
>> These and similar below do not directly interact
>>
>> with the sysfs so the sysfs_ prefix should not be needed.
> OK - I'll remove the SYSFS_ prefix.
>
>>> +
>>> +static int get_root_entry_hash(struct ifpga_sec_mgr *imgr,
>>> +			       u32 hash_addr, u8 *hash,
>>> +			       unsigned int size)
>>> +{
>>> +	struct m10bmc_sec *sec = imgr->priv;
>>> +	unsigned int stride = regmap_get_reg_stride(sec->m10bmc->regmap);
>>> +	int ret;
>>> +
>>> +	ret = m10bmc_raw_bulk_read(sec->m10bmc, hash_addr,
>>> +				   hash, size / stride);
>>> +	if (ret)
>>> +		dev_err(sec->dev, "bulk_read of 0x%x failed %d",
>>> +			hash_addr, ret);
>>> +
>>> +	return ret;
>>> +}
>>> +
>>> +#define SYSFS_GET_REH(_name, _hash_addr) \
>>> +static int get_##_name##_root_entry_hash(struct ifpga_sec_mgr *imgr, \
>>> +					 u8 *hash, unsigned int size) \
>>> +{ \
>>> +	return get_root_entry_hash(imgr, _hash_addr, hash, size); \
>>> +}
>>> +
>>> +SYSFS_GET_REH(bmc, BMC_REH_ADDR)
>>> +SYSFS_GET_REH(sr, SR_REH_ADDR)
>>> +SYSFS_GET_REH(pr, PR_REH_ADDR)
>>> +
>>> +static const struct ifpga_sec_mgr_ops m10bmc_iops = {
>>> +	.bmc_root_entry_hash = get_bmc_root_entry_hash,
>>> +	.sr_root_entry_hash = get_sr_root_entry_hash,
>>> +	.pr_root_entry_hash = get_pr_root_entry_hash,
>>> +	.bmc_reh_size = get_bmc_reh_size,
>>> +	.sr_reh_size = get_sr_reh_size,
>>> +	.pr_reh_size = get_pr_reh_size,
>> The prefix of the ops should be similar to the file name.
>>
>> so consider changing get_pr_reh_size to max10_pr_reh_size
> I'll switch to a prefix of m10bmc_ to be consistent with the probe and
> remove functions.
>
>>> +};
>>> +
>>> +static void ifpga_sec_mgr_uinit(struct m10bmc_sec *sec)
>>> +{
>>> +	ifpga_sec_mgr_unregister(sec->imgr);
>>> +}
>>> +
>>> +static int ifpga_sec_mgr_init(struct m10bmc_sec *sec)
>>> +{
>>> +	struct ifpga_sec_mgr *imgr;
>>> +
>>> +	imgr = ifpga_sec_mgr_register(sec->dev, "Max10 BMC Security Manager",
>>> +				      &m10bmc_iops, sec);
>>> +	if (IS_ERR(imgr))
>>> +		return PTR_ERR(imgr);
>>> +
>>> +	sec->imgr = imgr;
>>> +	return 0;
>>> +}
>>> +
>>> +static int m10bmc_secure_probe(struct platform_device *pdev)
>>> +{
>>> +	struct m10bmc_sec *sec;
>>> +	int ret;
>>> +
>>> +	sec = devm_kzalloc(&pdev->dev, sizeof(*sec), GFP_KERNEL);
>>> +	if (!sec)
>>> +		return -ENOMEM;
>>> +
>>> +	sec->dev = &pdev->dev;
>>> +	sec->m10bmc = dev_get_drvdata(pdev->dev.parent);
>>> +	dev_set_drvdata(&pdev->dev, sec);
>>> +
>>> +	ret = ifpga_sec_mgr_init(sec);
>>> +	if (ret)
>>> +		dev_err(&pdev->dev,
>>> +			"Security manager failed to start: %d\n", ret);
>>> +
>>> +	return ret;
>>> +}
>>> +
>>> +static int m10bmc_secure_remove(struct platform_device *pdev)
>>> +{
>>> +	struct m10bmc_sec *sec = dev_get_drvdata(&pdev->dev);
>>> +
>>> +	ifpga_sec_mgr_uinit(sec);
>>> +	return 0;
>>> +}
>>> +
>>> +static struct platform_driver intel_m10bmc_secure_driver = {
>>> +	.probe = m10bmc_secure_probe,
>>> +	.remove = m10bmc_secure_remove,
>>> +	.driver = {
>>> +		.name = "n3000bmc-secure",
>> From the filename, should this be "max10bmc-secure" ?
> This driver file will also service other devices. A future patch will add support
> for the d5005 card and the same driver code will be used, with some conditional
> logic, to support the d5005 card under the name "d5005bmc-secure". See the following
> link for a preview of these changes.
>
> https://github.com/OPAE/linux-dfl/blob/8e94e1f41c1571a322aac0c8d6ab8ee282e45016/drivers/mfd/intel-m10-bmc-secure.c#L803
>
> I chose to put n3000 in the name now so that the driver name (visible to user
> space applications) will not have to change names the d5005 functionality is added.
>
> The source filename is intel-m10-bmc-secure.c. Would it be better to call this driver
> n3000-m10bmc-secure? 
>
> Should I introduce the struct platform_device_id array (see the above link) now with
> a single entry for the n3000? So that the initial version of this file will contain
> the main driver name (intel-m10bmc-secure) as well as the n3000bmc-secure name?

Thanks for you explanation that this will also be used by d5005.

I think you have fine as-is.

Thanks

Tom

>
>>> +	},
>>> +};
>>> +module_platform_driver(intel_m10bmc_secure_driver);
>>> +
>>> +MODULE_ALIAS("platform:n3000bmc-secure");
>>> +MODULE_AUTHOR("Intel Corporation");
>>> +MODULE_DESCRIPTION("Intel MAX10 BMC secure engine");
>>> +MODULE_LICENSE("GPL v2");
>>> diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h
>>> index d4cb01b73357..7fe465c320c2 100644
>>> --- a/include/linux/mfd/intel-m10-bmc.h
>>> +++ b/include/linux/mfd/intel-m10-bmc.h
>>> @@ -63,6 +63,7 @@ struct intel_m10bmc {
>>>   * register access helper functions.
>>>   *
>>>   * m10bmc_raw_read - read m10bmc register per addr
>>> + * m10bmc_raw_bulk_read - bulk_read max10 registers per addr
>> second '_' should be removed so it reads like
>>
>> bulk read max10 registers..
> Thanks for the comments! I'll fix this.
>
>> Tom
>>
>>>   * m10bmc_sys_read - read m10bmc system register per offset
>>>   */
>>>  static inline int
>>> @@ -79,6 +80,20 @@ m10bmc_raw_read(struct intel_m10bmc *m10bmc, unsigned int addr,
>>>  	return ret;
>>>  }
>>>  
>>> +static inline int
>>> +m10bmc_raw_bulk_read(struct intel_m10bmc *m10bmc, unsigned int addr,
>>> +		     void *val, size_t cnt)
>>> +{
>>> +	int ret;
>>> +
>>> +	ret = regmap_bulk_read(m10bmc->regmap, addr, val, cnt);
>>> +	if (ret)
>>> +		dev_err(m10bmc->dev, "fail to read raw reg %x cnt %zx: %d\n",
>>> +			addr, cnt, ret);
>>> +
>>> +	return ret;
>>> +}
>>> +
>>>  #define m10bmc_sys_read(m10bmc, offset, val) \
>>>  	m10bmc_raw_read(m10bmc, M10BMC_SYS_BASE + (offset), val)
>>>  


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

* Re: [PATCH v1 02/12] fpga: create intel max10 bmc security engine
  2020-09-14 20:48       ` Tom Rix
@ 2020-09-14 21:40         ` Russ Weight
  0 siblings, 0 replies; 57+ messages in thread
From: Russ Weight @ 2020-09-14 21:40 UTC (permalink / raw)
  To: Tom Rix, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach



On 9/14/20 1:48 PM, Tom Rix wrote:
> On 9/14/20 12:07 PM, Russ Weight wrote:
>> On 9/5/20 1:22 PM, Tom Rix wrote:
>>> On 9/4/20 4:52 PM, Russ Weight wrote:
>>>> Create a platform driver that can be invoked as a sub
>>>> driver for the Intel MAX10 BMC in order to support
>>>> secure updates. This sub-driver will invoke an
>>>> instance of the Intel FPGA Security Manager class driver
>>>> in order to expose sysfs interfaces for managing and
>>>> monitoring secure updates to FPGA and BMC images.
>>>>
>>>> This patch creates the MAX10 BMC Security Engine driver and
>>>> provides support for displaying the current root entry hashes
>>>> for the FPGA static region, the FPGA PR region, and the MAX10
>>>> BMC.
>>>>
>>>> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
>>>> Reviewed-by: Wu Hao <hao.wu@intel.com>
>>>> ---
>>>>  drivers/fpga/Kconfig                |  11 ++
>>>>  drivers/fpga/Makefile               |   3 +
>>>>  drivers/fpga/intel-m10-bmc-secure.c | 170 ++++++++++++++++++++++++++++
>>>>  include/linux/mfd/intel-m10-bmc.h   |  15 +++
>>>>  4 files changed, 199 insertions(+)
>>>>  create mode 100644 drivers/fpga/intel-m10-bmc-secure.c
>>>>
>>>> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
>>>> index 97c0a6cc2ba7..0f0bed68e618 100644
>>>> --- a/drivers/fpga/Kconfig
>>>> +++ b/drivers/fpga/Kconfig
>>>> @@ -244,4 +244,15 @@ config IFPGA_SEC_MGR
>>>>  	  region and for the BMC. Select this option to enable
>>>>  	  updates for secure FPGA devices.
>>>>  
>>>> +config IFPGA_M10_BMC_SECURE
>>>> +        tristate "Intel MAX10 BMC security engine"
>>>> +	depends on MFD_INTEL_M10_BMC && IFPGA_SEC_MGR
>>>> +        help
>>>> +          Secure update support for the Intel MAX10 board management
>>>> +	  controller.
>>>> +
>>>> +	  This is a subdriver of the Intel MAX10 board management controller
>>>> +	  (BMC) and provides support for secure updates for the BMC image,
>>>> +	  the FPGA image, the Root Entry Hashes, etc.
>>>> +
>>>>  endif # FPGA
>>>> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
>>>> index ec9fbacdedd8..451a23ec3168 100644
>>>> --- a/drivers/fpga/Makefile
>>>> +++ b/drivers/fpga/Makefile
>>>> @@ -24,6 +24,9 @@ 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
>>>>  
>>>> +# Intel Security Manager Drivers
>>>> +obj-$(CONFIG_IFPGA_M10_BMC_SECURE)	+= intel-m10-bmc-secure.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/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c
>>>> new file mode 100644
>>>> index 000000000000..1f86bfb694b4
>>>> --- /dev/null
>>>> +++ b/drivers/fpga/intel-m10-bmc-secure.c
>>>> @@ -0,0 +1,170 @@
>>>> +// SPDX-License-Identifier: GPL-2.0
>>>> +/*
>>>> + * Intel Max10 Board Management Controller Security Engine Driver
>>>> + *
>>>> + * Copyright (C) 2019-2020 Intel Corporation. All rights reserved.
>>>> + *
>>>> + */
>>>> +#include <linux/device.h>
>>>> +#include <linux/fpga/ifpga-sec-mgr.h>
>>>> +#include <linux/mfd/intel-m10-bmc.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/vmalloc.h>
>>>> +
>>>> +struct m10bmc_sec {
>>>> +	struct device *dev;
>>>> +	struct intel_m10bmc *m10bmc;
>>>> +	struct ifpga_sec_mgr *imgr;
>>>> +};
>>>> +
>>>> +#define SHA256_REH_SIZE		32
>>>> +#define SHA384_REH_SIZE		48
>>>> +
>>>> +static int get_reh_size(struct ifpga_sec_mgr *imgr,
>>>> +			u32 exp_magic, u32 prog_addr)
>>>> +{
>>>> +	struct m10bmc_sec *sec = imgr->priv;
>>>> +	int sha_num_bytes, ret;
>>>> +	u32 magic;
>>>> +
>>>> +	ret = m10bmc_raw_read(sec->m10bmc, prog_addr, &magic);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>>> +	dev_dbg(sec->dev, "%s magic 0x%08x\n", __func__, magic);
>>>> +
>>>> +	if ((magic & 0xffff) != exp_magic)
>>> return -EINVAL ?
>> The absence of the magic number indicates that a Root Entry Hash has
>> not been programmed. So a null string (string size of zero) is appropriate
>> here.
>>
>> I'll add a comment.
>>
>>>> +		return 0;
>>>> +
>>>> +	sha_num_bytes = ((magic >> 16) & 0xffff) / 8;
>>>> +
>>>> +	if (sha_num_bytes != SHA256_REH_SIZE &&
>>>> +	    sha_num_bytes != SHA384_REH_SIZE)   {
>>>> +		dev_err(sec->dev, "%s bad sha num bytes %d\n", __func__,
>>>> +			sha_num_bytes);
>>>> +		return -EINVAL;
>>>> +	}
>>>> +
>>>> +	return sha_num_bytes;
>>>> +}
>>>> +
>>>> +#define BMC_REH_ADDR 0x17ffc004
>>>> +#define BMC_PROG_ADDR 0x17ffc000
>>>> +#define BMC_PROG_MAGIC 0x5746
>>>> +
>>>> +#define SR_REH_ADDR 0x17ffd004
>>>> +#define SR_PROG_ADDR 0x17ffd000
>>>> +#define SR_PROG_MAGIC 0x5253
>>>> +
>>>> +#define PR_REH_ADDR 0x17ffe004
>>>> +#define PR_PROG_ADDR 0x17ffe000
>>>> +#define PR_PROG_MAGIC 0x5250
>>> Why shouldn't these #defines be collected in the intel-m10-bmc.h ?
>> Placing them in intel-m10-bmc-h would give them a broader scope and make them
>> available to all m10-bmc sub-drivers. I placed them here to limit the scope to
>> the only file that should care about these definitions.
>>
>> Is this OK - or should they be moved to the header file?
> My thinking keeping all the register defines in one place is
>
> better than spreading it all out.  This would help with possible
>
> future changes that effected the entire register set.

OK - I'll try to consolidate register definitions in the intel-m10-bmc-h header file.

>
>>>> +
>>>> +#define SYSFS_GET_REH_SIZE(_name, _exp_magic, _prog_addr) \
>>>> +static int get_##_name##_reh_size(struct ifpga_sec_mgr *imgr) \
>>>> +{ \
>>>> +	return get_reh_size(imgr, _exp_magic, _prog_addr); \
>>>> +}
>>> Is this macro overkill for a 1 liner ?
>> It gives a slight reduction in code. I could go either way. What do you think? Should I take out the macros? Or leave it as is?
>>
>>>> +
>>>> +SYSFS_GET_REH_SIZE(bmc, BMC_PROG_MAGIC, BMC_PROG_ADDR)
>>>> +SYSFS_GET_REH_SIZE(sr, SR_PROG_MAGIC, SR_PROG_ADDR)
>>>> +SYSFS_GET_REH_SIZE(pr, PR_PROG_MAGIC, PR_PROG_ADDR)
>>> These and similar below do not directly interact
>>>
>>> with the sysfs so the sysfs_ prefix should not be needed.
>> OK - I'll remove the SYSFS_ prefix.
>>
>>>> +
>>>> +static int get_root_entry_hash(struct ifpga_sec_mgr *imgr,
>>>> +			       u32 hash_addr, u8 *hash,
>>>> +			       unsigned int size)
>>>> +{
>>>> +	struct m10bmc_sec *sec = imgr->priv;
>>>> +	unsigned int stride = regmap_get_reg_stride(sec->m10bmc->regmap);
>>>> +	int ret;
>>>> +
>>>> +	ret = m10bmc_raw_bulk_read(sec->m10bmc, hash_addr,
>>>> +				   hash, size / stride);
>>>> +	if (ret)
>>>> +		dev_err(sec->dev, "bulk_read of 0x%x failed %d",
>>>> +			hash_addr, ret);
>>>> +
>>>> +	return ret;
>>>> +}
>>>> +
>>>> +#define SYSFS_GET_REH(_name, _hash_addr) \
>>>> +static int get_##_name##_root_entry_hash(struct ifpga_sec_mgr *imgr, \
>>>> +					 u8 *hash, unsigned int size) \
>>>> +{ \
>>>> +	return get_root_entry_hash(imgr, _hash_addr, hash, size); \
>>>> +}
>>>> +
>>>> +SYSFS_GET_REH(bmc, BMC_REH_ADDR)
>>>> +SYSFS_GET_REH(sr, SR_REH_ADDR)
>>>> +SYSFS_GET_REH(pr, PR_REH_ADDR)
>>>> +
>>>> +static const struct ifpga_sec_mgr_ops m10bmc_iops = {
>>>> +	.bmc_root_entry_hash = get_bmc_root_entry_hash,
>>>> +	.sr_root_entry_hash = get_sr_root_entry_hash,
>>>> +	.pr_root_entry_hash = get_pr_root_entry_hash,
>>>> +	.bmc_reh_size = get_bmc_reh_size,
>>>> +	.sr_reh_size = get_sr_reh_size,
>>>> +	.pr_reh_size = get_pr_reh_size,
>>> The prefix of the ops should be similar to the file name.
>>>
>>> so consider changing get_pr_reh_size to max10_pr_reh_size
>> I'll switch to a prefix of m10bmc_ to be consistent with the probe and
>> remove functions.
>>
>>>> +};
>>>> +
>>>> +static void ifpga_sec_mgr_uinit(struct m10bmc_sec *sec)
>>>> +{
>>>> +	ifpga_sec_mgr_unregister(sec->imgr);
>>>> +}
>>>> +
>>>> +static int ifpga_sec_mgr_init(struct m10bmc_sec *sec)
>>>> +{
>>>> +	struct ifpga_sec_mgr *imgr;
>>>> +
>>>> +	imgr = ifpga_sec_mgr_register(sec->dev, "Max10 BMC Security Manager",
>>>> +				      &m10bmc_iops, sec);
>>>> +	if (IS_ERR(imgr))
>>>> +		return PTR_ERR(imgr);
>>>> +
>>>> +	sec->imgr = imgr;
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int m10bmc_secure_probe(struct platform_device *pdev)
>>>> +{
>>>> +	struct m10bmc_sec *sec;
>>>> +	int ret;
>>>> +
>>>> +	sec = devm_kzalloc(&pdev->dev, sizeof(*sec), GFP_KERNEL);
>>>> +	if (!sec)
>>>> +		return -ENOMEM;
>>>> +
>>>> +	sec->dev = &pdev->dev;
>>>> +	sec->m10bmc = dev_get_drvdata(pdev->dev.parent);
>>>> +	dev_set_drvdata(&pdev->dev, sec);
>>>> +
>>>> +	ret = ifpga_sec_mgr_init(sec);
>>>> +	if (ret)
>>>> +		dev_err(&pdev->dev,
>>>> +			"Security manager failed to start: %d\n", ret);
>>>> +
>>>> +	return ret;
>>>> +}
>>>> +
>>>> +static int m10bmc_secure_remove(struct platform_device *pdev)
>>>> +{
>>>> +	struct m10bmc_sec *sec = dev_get_drvdata(&pdev->dev);
>>>> +
>>>> +	ifpga_sec_mgr_uinit(sec);
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static struct platform_driver intel_m10bmc_secure_driver = {
>>>> +	.probe = m10bmc_secure_probe,
>>>> +	.remove = m10bmc_secure_remove,
>>>> +	.driver = {
>>>> +		.name = "n3000bmc-secure",
>>> From the filename, should this be "max10bmc-secure" ?
>> This driver file will also service other devices. A future patch will add support
>> for the d5005 card and the same driver code will be used, with some conditional
>> logic, to support the d5005 card under the name "d5005bmc-secure". See the following
>> link for a preview of these changes.
>>
>> https://github.com/OPAE/linux-dfl/blob/8e94e1f41c1571a322aac0c8d6ab8ee282e45016/drivers/mfd/intel-m10-bmc-secure.c#L803
>>
>> I chose to put n3000 in the name now so that the driver name (visible to user
>> space applications) will not have to change names the d5005 functionality is added.
>>
>> The source filename is intel-m10-bmc-secure.c. Would it be better to call this driver
>> n3000-m10bmc-secure? 
>>
>> Should I introduce the struct platform_device_id array (see the above link) now with
>> a single entry for the n3000? So that the initial version of this file will contain
>> the main driver name (intel-m10bmc-secure) as well as the n3000bmc-secure name?
> Thanks for you explanation that this will also be used by d5005.
>
> I think you have fine as-is.
>
> Thanks
>
> Tom
>
>>>> +	},
>>>> +};
>>>> +module_platform_driver(intel_m10bmc_secure_driver);
>>>> +
>>>> +MODULE_ALIAS("platform:n3000bmc-secure");
>>>> +MODULE_AUTHOR("Intel Corporation");
>>>> +MODULE_DESCRIPTION("Intel MAX10 BMC secure engine");
>>>> +MODULE_LICENSE("GPL v2");
>>>> diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h
>>>> index d4cb01b73357..7fe465c320c2 100644
>>>> --- a/include/linux/mfd/intel-m10-bmc.h
>>>> +++ b/include/linux/mfd/intel-m10-bmc.h
>>>> @@ -63,6 +63,7 @@ struct intel_m10bmc {
>>>>   * register access helper functions.
>>>>   *
>>>>   * m10bmc_raw_read - read m10bmc register per addr
>>>> + * m10bmc_raw_bulk_read - bulk_read max10 registers per addr
>>> second '_' should be removed so it reads like
>>>
>>> bulk read max10 registers..
>> Thanks for the comments! I'll fix this.
>>
>>> Tom
>>>
>>>>   * m10bmc_sys_read - read m10bmc system register per offset
>>>>   */
>>>>  static inline int
>>>> @@ -79,6 +80,20 @@ m10bmc_raw_read(struct intel_m10bmc *m10bmc, unsigned int addr,
>>>>  	return ret;
>>>>  }
>>>>  
>>>> +static inline int
>>>> +m10bmc_raw_bulk_read(struct intel_m10bmc *m10bmc, unsigned int addr,
>>>> +		     void *val, size_t cnt)
>>>> +{
>>>> +	int ret;
>>>> +
>>>> +	ret = regmap_bulk_read(m10bmc->regmap, addr, val, cnt);
>>>> +	if (ret)
>>>> +		dev_err(m10bmc->dev, "fail to read raw reg %x cnt %zx: %d\n",
>>>> +			addr, cnt, ret);
>>>> +
>>>> +	return ret;
>>>> +}
>>>> +
>>>>  #define m10bmc_sys_read(m10bmc, offset, val) \
>>>>  	m10bmc_raw_read(m10bmc, M10BMC_SYS_BASE + (offset), val)
>>>>  


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

* Re: [PATCH v1 03/12] fpga: expose max10 flash update counts in sysfs
  2020-09-05 20:39   ` Tom Rix
@ 2020-09-16 18:37     ` Russ Weight
  0 siblings, 0 replies; 57+ messages in thread
From: Russ Weight @ 2020-09-16 18:37 UTC (permalink / raw)
  To: Tom Rix, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach



On 9/5/20 1:39 PM, Tom Rix wrote:
> On 9/4/20 4:52 PM, Russ Weight wrote:
>> Extend the MAX10 BMC Security Engine driver to provide a
>> handler to expose the flash update count for the FPGA user
>> image.
>>
>> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
>> Reviewed-by: Wu Hao <hao.wu@intel.com>
>> ---
>>  drivers/fpga/intel-m10-bmc-secure.c | 32 +++++++++++++++++++++++++++++
>>  1 file changed, 32 insertions(+)
>>
>> diff --git a/drivers/fpga/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c
>> index 1f86bfb694b4..b824790e43aa 100644
>> --- a/drivers/fpga/intel-m10-bmc-secure.c
>> +++ b/drivers/fpga/intel-m10-bmc-secure.c
>> @@ -10,6 +10,7 @@
>>  #include <linux/mfd/intel-m10-bmc.h>
>>  #include <linux/module.h>
>>  #include <linux/platform_device.h>
>> +#include <linux/slab.h>
>>  #include <linux/vmalloc.h>
>>  
>>  struct m10bmc_sec {
>> @@ -99,7 +100,38 @@ SYSFS_GET_REH(bmc, BMC_REH_ADDR)
>>  SYSFS_GET_REH(sr, SR_REH_ADDR)
>>  SYSFS_GET_REH(pr, PR_REH_ADDR)
>>  
>> +#define FLASH_COUNT_SIZE 4096
> This seems too high at most it should be 64.

The flash count size represents the size of the flash memory that stores the
count. The count is represented in flash as an inverted bit vector.

I suppose a comment would be helpful here...

>> +#define USER_FLASH_COUNT 0x17ffb000
> Why shouldn't this be in intel-m10-bmc.h ?

Sure - I'll move it there with the other addresses.

>> +
>> +static int get_qspi_flash_count(struct ifpga_sec_mgr *imgr)
> what does 'qspi' mean ?

It means Quad-SPI, the controller type that connects to the FLASH. This term
does seem out of place here. There is also a BMC flash count. I'll change this to
"user".

>
> unless there are going to be several *flash_count's consider
>
> removing this substring.
>
>> +{
>> +	struct m10bmc_sec *sec = imgr->priv;
>> +	unsigned int stride = regmap_get_reg_stride(sec->m10bmc->regmap);
>> +	unsigned int cnt, num_bits = FLASH_COUNT_SIZE * 8;
>> +	u8 *flash_buf;
>> +	int ret;
>> +
>> +	flash_buf = kmalloc(FLASH_COUNT_SIZE, GFP_KERNEL);
>> +	if (!flash_buf)
>> +		return -ENOMEM;
>> +
>> +	ret = m10bmc_raw_bulk_read(sec->m10bmc, USER_FLASH_COUNT, flash_buf,
>> +				   FLASH_COUNT_SIZE / stride);
>> +	if (ret) {
>> +		dev_err(sec->dev, "%s failed to read %d\n", __func__, ret);
>> +		goto exit_free;
>> +	}
>> +
>> +	cnt = num_bits - bitmap_weight((unsigned long *)flash_buf, num_bits);
> Simplify ret = num_bits...

yes - will do.
Thanks!

- Russ

>> +
>> +exit_free:
>> +	kfree(flash_buf);
>> +
>> +	return ret ? : cnt;
> Then simplify
>
> return ret;
>
> Tom
>
>> +}
>> +
>>  static const struct ifpga_sec_mgr_ops m10bmc_iops = {
>> +	.user_flash_count = get_qspi_flash_count,
>>  	.bmc_root_entry_hash = get_bmc_root_entry_hash,
>>  	.sr_root_entry_hash = get_sr_root_entry_hash,
>>  	.pr_root_entry_hash = get_pr_root_entry_hash,


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

* Re: [PATCH v1 01/12] fpga: fpga security manager class driver
  2020-09-04 23:52 ` [PATCH v1 01/12] fpga: fpga security manager class driver Russ Weight
                     ` (2 preceding siblings ...)
  2020-09-05 19:09   ` Tom Rix
@ 2020-09-16 20:16   ` Moritz Fischer
  2020-09-30 20:54     ` Russ Weight
  3 siblings, 1 reply; 57+ messages in thread
From: Moritz Fischer @ 2020-09-16 20:16 UTC (permalink / raw)
  To: Russ Weight
  Cc: mdf, lee.jones, linux-fpga, linux-kernel, trix, lgoncalv,
	yilun.xu, hao.wu, matthew.gerlach

Hi Russ,

On Fri, Sep 04, 2020 at 04:52:54PM -0700, 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>
> ---
>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  75 ++++
>  MAINTAINERS                                   |   8 +
>  drivers/fpga/Kconfig                          |   9 +
>  drivers/fpga/Makefile                         |   3 +
>  drivers/fpga/ifpga-sec-mgr.c                  | 339 ++++++++++++++++++
>  include/linux/fpga/ifpga-sec-mgr.h            | 145 ++++++++
>  6 files changed, 579 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>  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..86f8992559bf
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> @@ -0,0 +1,75 @@
> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/name
> +Date:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
> +KernelVersion:  5.10
> +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:		Sep 2020
> +KernelVersion:  5.10
> +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: "%d".
> +
> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/bmc_flash_count
> +Date:		Sep 2020
> +KernelVersion:  5.10
> +Contact:	Russ Weight <russell.h.weight@intel.com>
> +Description:	Read only. Returns number of times the BMC image has been
> +		flashed.
> +		Format: "%d".
> diff --git a/MAINTAINERS b/MAINTAINERS
> index deaafb617361..4a2ebe6b120d 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -6830,6 +6830,14 @@ 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:	drivers/fpga/ifpga-sec-mgr.c
> +F:	include/linux/fpga/ifpga-sec-mgr.h

Actually, ignore my previous comment, feel free to leave this in.
> +
>  FPU EMULATOR
>  M:	Bill Metzenthen <billm@melbpc.org.au>
>  S:	Maintained
> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> index 88f64fbf55e3..97c0a6cc2ba7 100644
> --- a/drivers/fpga/Kconfig
> +++ b/drivers/fpga/Kconfig
> @@ -235,4 +235,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 c69bfc931519..ec9fbacdedd8 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..97bf80277ed2
> --- /dev/null
> +++ b/drivers/fpga/ifpga-sec-mgr.c
> @@ -0,0 +1,339 @@
> +// 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;
> +
> +static ssize_t show_canceled_csk(struct ifpga_sec_mgr *imgr,
> +				 sysfs_csk_hndlr_t get_csk,
> +				 sysfs_csk_nbits_t get_csk_nbits,
> +				 char *buf)
> +{
> +	unsigned long *csk_map = NULL;
> +	unsigned int nbits;
> +	int cnt, 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;
> +
> +	cnt = bitmap_print_to_pagebuf(1, buf, csk_map, nbits);
> +
> +vfree_exit:
> +	vfree(csk_map);
> +	return ret ? : cnt;
> +}
> +
> +static ssize_t show_root_entry_hash(struct ifpga_sec_mgr *imgr,
> +				    sysfs_reh_hndlr_t get_reh,
> +				    sysfs_reh_size_t get_reh_size,
> +				    char *buf)
> +{
> +	unsigned int size, i;
> +	int ret, cnt = 0;
> +	u8 *hash;
> +
> +	ret = get_reh_size(imgr);
> +	if (ret < 0)
> +		return ret;
> +	else if (!ret)
> +		return sprintf(buf, "hash not programmed\n");
> +
> +	size = (unsigned int)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 to_sec_mgr(d) container_of(d, struct ifpga_sec_mgr, dev)
> +
> +#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)
> +
> +#define DEVICE_ATTR_SEC_FLASH_CNT(_name) \
> +static ssize_t _name##_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->_name##_flash_count(imgr); \
> +	return cnt < 0 ? cnt : sprintf(buf, "%d\n", cnt); \
> +} \
> +static DEVICE_ATTR_RO(_name##_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_FLASH_CNT(user);
> +DEVICE_ATTR_SEC_FLASH_CNT(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_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));
> +
> +	if (check_attr(attr, user_flash_count) ||
> +	    check_attr(attr, bmc_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)
> +{
> +	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_register - register an IFPGA security manager struct
> + *
> + * @dev:  create ifpga security manager device from pdev
Create or register? Consider splitting this into a create and a
register function.

Also it might be nice to have a devm_ifpga_create_sec_mgr /
ifpga_register_sec_mgr set.

> + * @name: ifpga security manager name
> + * @iops: pointer to a structure of ifpga callback functions
> + * @priv: ifpga security manager private data
> + *
> + * Returns &struct ifpga_sec_mgr pointer on success, or ERR_PTR() on error.
> + */
> +struct ifpga_sec_mgr *
> +ifpga_sec_mgr_register(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 ERR_PTR(-EINVAL);
> +	}
> +
> +	if (!name || !strlen(name)) {
> +		dev_err(dev, "Attempt to register with no name!\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	imgr = kzalloc(sizeof(*imgr), GFP_KERNEL);
> +	if (!imgr)
> +		return ERR_PTR(-ENOMEM);
> +
> +	imgr->name = name;
> +	imgr->priv = priv;
> +	imgr->iops = iops;
> +	mutex_init(&imgr->lock);
> +
> +	id = ida_simple_get(&ifpga_sec_mgr_ida, 0, 0, GFP_KERNEL);
> +	if (id < 0) {
> +		ret = id;
> +		goto exit_free;
> +	}
> +
> +	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);
> +		ida_simple_remove(&ifpga_sec_mgr_ida, id);
> +		goto exit_free;
> +	}

Consider
   	ret = dev_set_name(&imgr->dev, "ifpga_sec%d", id);
   	if (ret) {
		goto exit_device;
   	}
and above exit_free:
exit_device:
   		ida_simple_remove(&ifpga_sec_mgr_ida, id);

> +
> +	ret = device_register(&imgr->dev);
> +	if (ret) {
> +		put_device(&imgr->dev);
> +		return ERR_PTR(ret);
> +	}
> +
> +	return imgr;
> +
> +exit_free:
> +	kfree(dev);
> +	return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_register);
> +
> +/**
> + * ifpga_sec_mgr_unregister - unregister a IFPGA security manager
Nit: a or an IFPGA?
> + *
> + * @mgr: fpga manager struct
> + *
> + * This function is intended for use in a IFPGA security manager
Nit: a or an?
> + * 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)
> +{
> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
> +
> +	mutex_destroy(&imgr->lock);
> +	ida_simple_remove(&ifpga_sec_mgr_ida, imgr->dev.id);
> +	kfree(imgr);
> +}
> +
> +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..e391b0c8f448
> --- /dev/null
> +++ b/include/linux/fpga/ifpga-sec-mgr.h
> @@ -0,0 +1,145 @@
> +/* 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;
> +
> +/**
> + * typedef sysfs_reh_size_t - Function to return byte size of root entry hash
> + *
> + * @imgr:      pointer to security manager structure
> + *
> + * This datatype is used to define a function that returns the byte size of a
> + * root entry hash.
> + *
> + * Context: No locking requirements are imposed by the security manager.
> + * Return:  Byte count on success, negative errno on failure
> + */
> +typedef int (*sysfs_reh_size_t)(struct ifpga_sec_mgr *imgr);
> +
> +/**
> + * typedef sysfs_reh_hndlr_t - Function pointer to sysfs file handler
> + *			       for root entry hashes
> + * @imgr:      pointer to security manager structure
> + * @hash:      pointer to an array of bytes in which to store the hash
> + * @size:      byte size of root entry hash
> + *
> + * This datatype is used to define a sysfs file handler function to
> + * return root entry hash data to be displayed via sysfs.
> + *
> + * Context: No locking requirements are imposed by the security manager.
> + * Return:  0 on success, negative errno on failure
> + */
> +typedef int (*sysfs_reh_hndlr_t)(struct ifpga_sec_mgr *imgr, u8 *hash,
> +				 unsigned int size);
> +
> +/**
> + * typedef sysfs_cnt_hndlr_t - Function pointer to sysfs file handler
> + *			       for flash counts
> + * @imgr: pointer to security manager structure
> + *
> + * This datatype is used to define a sysfs file handler function to
> + * return a flash count to be displayed via sysfs.
> + *
> + * Context: No locking requirements are imposed by the security manager
> + * Return: flash count or negative errno
> + */
> +typedef int (*sysfs_cnt_hndlr_t)(struct ifpga_sec_mgr *imgr);
> +
> +/**
> + * typedef sysfs_csk_nbits_t - Function to return the number of bits in
> + *				      a Code Signing Key cancellation vector
> + *
> + * @imgr:      pointer to security manager structure
> + *
> + * This datatype is used to define a function that returns the number of bits
> + * in a Code Signing Key cancellation vector.
> + *
> + * Context: No locking requirements are imposed by the security manager.
> + * Return:  Number of bits on success, negative errno on failure
> + */
> +typedef int (*sysfs_csk_nbits_t)(struct ifpga_sec_mgr *imgr);
> +
> +/**
> + * typedef sysfs_csk_hndlr_t - Function pointer to sysfs file handler
> + *			       bit vector of canceled keys
> + *
> + * @imgr:    pointer to security manager structure
> + * @csk_map: pointer to a bitmap to contain cancellation key vector
> + * @nbits:   number of bits in CSK vector
> + *
> + * This datatype is used to define a sysfs file handler function to
> + * return a bitmap of canceled keys to be displayed via sysfs.
> + *
> + * Context: No locking requirements are imposed by the security manager.
> + * Return:  0 on success, negative errno on failure
> + */
> +typedef int (*sysfs_csk_hndlr_t)(struct ifpga_sec_mgr *imgr,
> +				 unsigned long *csk_map, unsigned int nbits);
> +
> +/**
> + * struct ifpga_sec_mgr_ops - device specific operations
> + * @user_flash_count:	    Optional: Return sysfs string output for FPGA
> + *			    image flash count
> + * @bmc_flash_count:	    Optional: Return sysfs string output for BMC
> + *			    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 {
> +	sysfs_cnt_hndlr_t user_flash_count;
> +	sysfs_cnt_hndlr_t bmc_flash_count;
> +	sysfs_cnt_hndlr_t smbus_flash_count;
> +	sysfs_reh_hndlr_t sr_root_entry_hash;
> +	sysfs_reh_hndlr_t pr_root_entry_hash;
> +	sysfs_reh_hndlr_t bmc_root_entry_hash;
> +	sysfs_csk_hndlr_t sr_canceled_csks;
> +	sysfs_csk_hndlr_t pr_canceled_csks;
> +	sysfs_csk_hndlr_t bmc_canceled_csks;
> +	sysfs_reh_size_t bmc_reh_size;
> +	sysfs_reh_size_t sr_reh_size;
> +	sysfs_reh_size_t pr_reh_size;
> +	sysfs_csk_nbits_t bmc_canceled_csk_nbits;
> +	sysfs_csk_nbits_t sr_canceled_csk_nbits;
> +	sysfs_csk_nbits_t pr_canceled_csk_nbits;
> +};

I agree with Tom's feedback, please don't use typedefs here.
> +
> +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_register(struct device *dev, const char *name,
> +		       const struct ifpga_sec_mgr_ops *iops, void *priv);
> +void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr);
> +
> +#endif
> -- 
> 2.17.1
> 

Thanks,
Moritz

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

* Re: [PATCH v1 02/12] fpga: create intel max10 bmc security engine
  2020-09-04 23:52 ` [PATCH v1 02/12] fpga: create intel max10 bmc security engine Russ Weight
  2020-09-05  0:01   ` Randy Dunlap
  2020-09-05 20:22   ` Tom Rix
@ 2020-09-16 20:33   ` Moritz Fischer
  2020-09-30 23:14     ` Russ Weight
  2 siblings, 1 reply; 57+ messages in thread
From: Moritz Fischer @ 2020-09-16 20:33 UTC (permalink / raw)
  To: Russ Weight
  Cc: mdf, lee.jones, linux-fpga, linux-kernel, trix, lgoncalv,
	yilun.xu, hao.wu, matthew.gerlach

Russ,

On Fri, Sep 04, 2020 at 04:52:55PM -0700, Russ Weight wrote:
> Create a platform driver that can be invoked as a sub
> driver for the Intel MAX10 BMC in order to support
> secure updates. This sub-driver will invoke an
> instance of the Intel FPGA Security Manager class driver
> in order to expose sysfs interfaces for managing and
> monitoring secure updates to FPGA and BMC images.
> 
> This patch creates the MAX10 BMC Security Engine driver and
> provides support for displaying the current root entry hashes
> for the FPGA static region, the FPGA PR region, and the MAX10
> BMC.
> 
> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
> Reviewed-by: Wu Hao <hao.wu@intel.com>
> ---
>  drivers/fpga/Kconfig                |  11 ++
>  drivers/fpga/Makefile               |   3 +
>  drivers/fpga/intel-m10-bmc-secure.c | 170 ++++++++++++++++++++++++++++
>  include/linux/mfd/intel-m10-bmc.h   |  15 +++
>  4 files changed, 199 insertions(+)
>  create mode 100644 drivers/fpga/intel-m10-bmc-secure.c
> 
> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> index 97c0a6cc2ba7..0f0bed68e618 100644
> --- a/drivers/fpga/Kconfig
> +++ b/drivers/fpga/Kconfig
> @@ -244,4 +244,15 @@ config IFPGA_SEC_MGR
>  	  region and for the BMC. Select this option to enable
>  	  updates for secure FPGA devices.
>  
> +config IFPGA_M10_BMC_SECURE
> +        tristate "Intel MAX10 BMC security engine"
> +	depends on MFD_INTEL_M10_BMC && IFPGA_SEC_MGR
> +        help
> +          Secure update support for the Intel MAX10 board management
> +	  controller.
> +
> +	  This is a subdriver of the Intel MAX10 board management controller
> +	  (BMC) and provides support for secure updates for the BMC image,
> +	  the FPGA image, the Root Entry Hashes, etc.
> +
>  endif # FPGA
> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
> index ec9fbacdedd8..451a23ec3168 100644
> --- a/drivers/fpga/Makefile
> +++ b/drivers/fpga/Makefile
> @@ -24,6 +24,9 @@ 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
>  
> +# Intel Security Manager Drivers
> +obj-$(CONFIG_IFPGA_M10_BMC_SECURE)	+= intel-m10-bmc-secure.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/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c
> new file mode 100644
> index 000000000000..1f86bfb694b4
> --- /dev/null
> +++ b/drivers/fpga/intel-m10-bmc-secure.c
> @@ -0,0 +1,170 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Intel Max10 Board Management Controller Security Engine Driver
> + *
> + * Copyright (C) 2019-2020 Intel Corporation. All rights reserved.
> + *
> + */
> +#include <linux/device.h>
> +#include <linux/fpga/ifpga-sec-mgr.h>
> +#include <linux/mfd/intel-m10-bmc.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/vmalloc.h>
> +
> +struct m10bmc_sec {
> +	struct device *dev;
> +	struct intel_m10bmc *m10bmc;
> +	struct ifpga_sec_mgr *imgr;
> +};
> +
> +#define SHA256_REH_SIZE		32
> +#define SHA384_REH_SIZE		48
> +
> +static int get_reh_size(struct ifpga_sec_mgr *imgr,
> +			u32 exp_magic, u32 prog_addr)
> +{
> +	struct m10bmc_sec *sec = imgr->priv;
> +	int sha_num_bytes, ret;
> +	u32 magic;
> +
> +	ret = m10bmc_raw_read(sec->m10bmc, prog_addr, &magic);
> +	if (ret)
> +		return ret;
> +
> +	dev_dbg(sec->dev, "%s magic 0x%08x\n", __func__, magic);
> +
> +	if ((magic & 0xffff) != exp_magic)
Consider using GENMASK() here.
> +		return 0;
> +
> +	sha_num_bytes = ((magic >> 16) & 0xffff) / 8;
And here.
> +
> +	if (sha_num_bytes != SHA256_REH_SIZE &&
> +	    sha_num_bytes != SHA384_REH_SIZE)   {
> +		dev_err(sec->dev, "%s bad sha num bytes %d\n", __func__,
> +			sha_num_bytes);
> +		return -EINVAL;
> +	}
> +
> +	return sha_num_bytes;
> +}
> +
> +#define BMC_REH_ADDR 0x17ffc004
> +#define BMC_PROG_ADDR 0x17ffc000
> +#define BMC_PROG_MAGIC 0x5746
> +
> +#define SR_REH_ADDR 0x17ffd004
> +#define SR_PROG_ADDR 0x17ffd000
> +#define SR_PROG_MAGIC 0x5253
> +
> +#define PR_REH_ADDR 0x17ffe004
> +#define PR_PROG_ADDR 0x17ffe000
> +#define PR_PROG_MAGIC 0x5250
> +
> +#define SYSFS_GET_REH_SIZE(_name, _exp_magic, _prog_addr) \
> +static int get_##_name##_reh_size(struct ifpga_sec_mgr *imgr) \
> +{ \
> +	return get_reh_size(imgr, _exp_magic, _prog_addr); \
> +}
> +
> +SYSFS_GET_REH_SIZE(bmc, BMC_PROG_MAGIC, BMC_PROG_ADDR)
> +SYSFS_GET_REH_SIZE(sr, SR_PROG_MAGIC, SR_PROG_ADDR)
> +SYSFS_GET_REH_SIZE(pr, PR_PROG_MAGIC, PR_PROG_ADDR)
> +
> +static int get_root_entry_hash(struct ifpga_sec_mgr *imgr,
> +			       u32 hash_addr, u8 *hash,
> +			       unsigned int size)
> +{
> +	struct m10bmc_sec *sec = imgr->priv;
> +	unsigned int stride = regmap_get_reg_stride(sec->m10bmc->regmap);
> +	int ret;
> +
> +	ret = m10bmc_raw_bulk_read(sec->m10bmc, hash_addr,
> +				   hash, size / stride);
> +	if (ret)
> +		dev_err(sec->dev, "bulk_read of 0x%x failed %d",
> +			hash_addr, ret);
> +
> +	return ret;
> +}
> +
> +#define SYSFS_GET_REH(_name, _hash_addr) \
> +static int get_##_name##_root_entry_hash(struct ifpga_sec_mgr *imgr, \
> +					 u8 *hash, unsigned int size) \
> +{ \
> +	return get_root_entry_hash(imgr, _hash_addr, hash, size); \
> +}
> +
> +SYSFS_GET_REH(bmc, BMC_REH_ADDR)
> +SYSFS_GET_REH(sr, SR_REH_ADDR)
> +SYSFS_GET_REH(pr, PR_REH_ADDR)

Tbh, I'd drop the macro and just have the functions as one liners,
and yes, please add the prefix.
> +
> +static const struct ifpga_sec_mgr_ops m10bmc_iops = {
> +	.bmc_root_entry_hash = get_bmc_root_entry_hash,
> +	.sr_root_entry_hash = get_sr_root_entry_hash,
> +	.pr_root_entry_hash = get_pr_root_entry_hash,
> +	.bmc_reh_size = get_bmc_reh_size,
> +	.sr_reh_size = get_sr_reh_size,
> +	.pr_reh_size = get_pr_reh_size,
> +};
> +
> +static void ifpga_sec_mgr_uinit(struct m10bmc_sec *sec)
> +{
> +	ifpga_sec_mgr_unregister(sec->imgr);
> +}
Consider dropping this function (see below).
> +
> +static int ifpga_sec_mgr_init(struct m10bmc_sec *sec)
> +{
> +	struct ifpga_sec_mgr *imgr;
> +
> +	imgr = ifpga_sec_mgr_register(sec->dev, "Max10 BMC Security Manager",
> +				      &m10bmc_iops, sec);
> +	if (IS_ERR(imgr))
> +		return PTR_ERR(imgr);
> +
> +	sec->imgr = imgr;
> +	return 0;
> +}
> +
> +static int m10bmc_secure_probe(struct platform_device *pdev)
> +{
> +	struct m10bmc_sec *sec;
> +	int ret;
> +
> +	sec = devm_kzalloc(&pdev->dev, sizeof(*sec), GFP_KERNEL);
> +	if (!sec)
> +		return -ENOMEM;
> +
> +	sec->dev = &pdev->dev;
> +	sec->m10bmc = dev_get_drvdata(pdev->dev.parent);
> +	dev_set_drvdata(&pdev->dev, sec);

If you implement the devm_ versions then this could be:

	imgr = devm_ifpga_sec_mgr_create(&pdev->dev, "Max10 BMC Security
					Manager", &m10bmc_ips, sec);
	if (IS_ERR(imgr))
		return PTR_ERR(imgr);
	sec->imgr = imgr;

	return ifpga_sec_mgr_register(imgr);

> +
> +	ret = ifpga_sec_mgr_init(sec);
> +	if (ret)
> +		dev_err(&pdev->dev,
> +			"Security manager failed to start: %d\n", ret);
> +
> +	return ret;
> +}
> +
> +static int m10bmc_secure_remove(struct platform_device *pdev)
> +{
> +	struct m10bmc_sec *sec = dev_get_drvdata(&pdev->dev);
> +
> +	ifpga_sec_mgr_uinit(sec);

If you drop the above:
	ifpga_sec_mgr_remove(sec->imgr);
> +	return 0;
> +}
> +
> +static struct platform_driver intel_m10bmc_secure_driver = {
> +	.probe = m10bmc_secure_probe,
> +	.remove = m10bmc_secure_remove,
> +	.driver = {
> +		.name = "n3000bmc-secure",
> +	},
> +};
> +module_platform_driver(intel_m10bmc_secure_driver);
> +
> +MODULE_ALIAS("platform:n3000bmc-secure");
> +MODULE_AUTHOR("Intel Corporation");
> +MODULE_DESCRIPTION("Intel MAX10 BMC secure engine");
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h
> index d4cb01b73357..7fe465c320c2 100644
> --- a/include/linux/mfd/intel-m10-bmc.h
> +++ b/include/linux/mfd/intel-m10-bmc.h
> @@ -63,6 +63,7 @@ struct intel_m10bmc {
>   * register access helper functions.
>   *
>   * m10bmc_raw_read - read m10bmc register per addr
> + * m10bmc_raw_bulk_read - bulk_read max10 registers per addr
>   * m10bmc_sys_read - read m10bmc system register per offset
>   */
>  static inline int
> @@ -79,6 +80,20 @@ m10bmc_raw_read(struct intel_m10bmc *m10bmc, unsigned int addr,
>  	return ret;
>  }
>  
> +static inline int
> +m10bmc_raw_bulk_read(struct intel_m10bmc *m10bmc, unsigned int addr,
> +		     void *val, size_t cnt)
> +{
> +	int ret;
> +
> +	ret = regmap_bulk_read(m10bmc->regmap, addr, val, cnt);
> +	if (ret)
> +		dev_err(m10bmc->dev, "fail to read raw reg %x cnt %zx: %d\n",
> +			addr, cnt, ret);
> +
> +	return ret;
> +}
> +
>  #define m10bmc_sys_read(m10bmc, offset, val) \
>  	m10bmc_raw_read(m10bmc, M10BMC_SYS_BASE + (offset), val)
>  
> -- 
> 2.17.1
> 

Thanks,
Moritz

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

* Re: [PATCH v1 05/12] fpga: enable secure updates
       [not found]     ` <1d90bfb6-417c-55df-9290-991c391158a9@intel.com>
@ 2020-09-20 15:24       ` Tom Rix
  0 siblings, 0 replies; 57+ messages in thread
From: Tom Rix @ 2020-09-20 15:24 UTC (permalink / raw)
  To: Russ Weight, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 9/18/20 6:10 PM, Russ Weight wrote:
>
> On 9/5/20 3:04 PM, Tom Rix wrote:
>> On 9/4/20 4:52 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>
>>> ---
>>>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  13 ++
>>>  drivers/fpga/ifpga-sec-mgr.c                  | 155 ++++++++++++++++++
>>>  include/linux/fpga/ifpga-sec-mgr.h            |  49 ++++++
>>>  3 files changed, 217 insertions(+)
>>>
>>> diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>> index 86f8992559bf..a476504b7ae9 100644
>>> --- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>> @@ -73,3 +73,16 @@ Contact:	Russ Weight <russell.h.weight@intel.com>
>>>  Description:	Read only. Returns number of times the BMC image has been
>>>  		flashed.
>>>  		Format: "%d".
>>> +
>>> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/update/filename
>>> +Date:		Sep 2020
>>> +KernelVersion:  5.10
>>> +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 97bf80277ed2..73173badbe96 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
>>> +
>>>  static ssize_t show_canceled_csk(struct ifpga_sec_mgr *imgr,
>>>  				 sysfs_csk_hndlr_t get_csk,
>>>  				 sysfs_csk_nbits_t get_csk_nbits,
>>> @@ -134,6 +139,91 @@ 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);
>> Why not lock here ? It seems like filename and other
>>
>> state could be changed out from under the work func.
> Filename_store() uses imgr->progress, imgr->driver_unload, and imgr->lock
> to ensure that only one worker thread is running at a time. In some of the later
> patches there is some lock protection around error, progress, and cancel accesses.
> At this point in the patchset, the synchronization in filename_store() should be
> sufficient.
ok
>>> +
>>> +	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);
>> Check for function pointer later, good.
>>
>> Could writing a short block be handled like libc's write()
>>
>> by passing back the bytes written ?
> It could be done, multiplexing the size into the return code. Do you think it
> would add value?
A toss up. I like consistent interfaces.
>>> +		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;
>>> +	}
>> Add a paranoid crc check the flash is what was written ?
> In the secure update implementation, the host driver transfers the data
> to a staging area in flash, and then it is up to the BMC firmware to
> actually do the programming and validation, so it is unnecessary for
> the host driver to check the flash. Also, on the n3000, the updates
> take more than 30 minutes, so adding additional checks would add
> to an already long wait.
ok
>>> +
>>> +done:
>>> +	if (imgr->iops->cleanup)
>>> +		imgr->iops->cleanup(imgr);
>>> +
>>> +modput_exit:
>>> +	module_put(imgr->dev.parent->driver->owner);
>>> +
>>> +release_fw_exit:
>>> +	imgr->data = NULL;
>> clear remaining_size ?
> Remaining size is left unchanged intentionally. On success it will be zero.
> In the case of an error it can be helpful/interesting to see how much data
> has transferred (using the remaining_size sysfs file). Remaining_size will
> be reinitialized at the start of the next instance of a secure update.

Is there a way to tell if the transfer is stuck/in the middle or a failure ?

Maybe add a comment that this is intentional so someone does not remove this later.

>>> +	release_firmware(fw);
>>> +
>>> +idle_exit:
>>> +	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)
>>>  
>>> @@ -161,6 +251,51 @@ 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 = 0;
>>> +
>>> +	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, PATH_MAX - 1, GFP_KERNEL);
>> shouldn't this be 'count - 1' ?
> Yes - you are right. I'll make that change. Thanks!
>>> +	if (!imgr->filename) {
>>> +		ret = -ENOMEM;
>>> +		goto unlock_exit;
>>> +	}
>>> +
>>> +	if (imgr->filename[strlen(imgr->filename) - 1] == '\n')
>>> +		imgr->filename[strlen(imgr->filename) - 1] = '\0';
>> If you are catching the '\n' is a more general striping of
>>
>> whitespace needed ?
> My intent was to take care of the common case, but now that you  mention it,
> I don't think the '\n' case is really required. Perhaps this check could be
> removed?
>
> Or do you think I should add more checks? Currently, if a quoted string with
> whitespace is provided for the filename, then the update will fail with
> "file-error". But it seems like an unlikely case.

Perhaps i am being paranoid, i think user inputs need extra checking.

see more comment below.

>> Could a file exists check be done before kicking off the worker?
> It could be done. I didn't include them because I thought it would be redundant
> with functionality already provided by request_firmware(). In the current
> implementation, the error sysfs file would indicate "file-error". It may be
> possible to give a more descriptive error using errno if it was detected in
> this context.

yes this would be redundant, but you would know early if filename was invalid.

toss up, change if you want.

Tom

>>> +
>>> +	imgr->err_code = IFPGA_SEC_ERR_NONE;
>>> +	imgr->progress = IFPGA_SEC_PROG_READ_FILE;
>>> +	reinit_completion(&imgr->update_done);
>>> +	schedule_work(&imgr->work);
>> Skip the if-check at the end
>>
>> ret = count.
> OK. It looks like I could just initialize ret to count.
>>> +
>>> +unlock_exit:
>>> +	mutex_unlock(&imgr->lock);
>>> +	return ret ? : count;
>>> +}
>>> +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)
>>>  {
>>> @@ -182,6 +317,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,
>>>  };
>>>  
>>> @@ -233,6 +369,12 @@ ifpga_sec_mgr_register(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) {
>> Comments in ifpga-sec-mgr.h say 'Required: ' good.
>>> +		dev_err(dev, "Attempt to register without ifpga_sec_mgr_ops\n");
>> without required ifpga_sec_mgr_ops
> Yes - I'll make the change.
>>> +		return NULL;
>>> +	}
>>> +
>>>  	if (!check_reh_handler(dev, iops, bmc) ||
>>>  	    !check_reh_handler(dev, iops, sr) ||
>>>  	    !check_reh_handler(dev, iops, pr) ||
>>> @@ -254,6 +396,8 @@ ifpga_sec_mgr_register(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);
>>>  	mutex_init(&imgr->lock);
>>>  
>>>  	id = ida_simple_get(&ifpga_sec_mgr_ida, 0, 0, GFP_KERNEL);
>>> @@ -299,6 +443,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 e391b0c8f448..4da2864e251c 100644
>>> --- a/include/linux/fpga/ifpga-sec-mgr.h
>>> +++ b/include/linux/fpga/ifpga-sec-mgr.h
>>> @@ -7,6 +7,7 @@
>>>  #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>
>>> @@ -86,6 +87,19 @@ typedef int (*sysfs_csk_nbits_t)(struct ifpga_sec_mgr *imgr);
>>>  typedef int (*sysfs_csk_hndlr_t)(struct ifpga_sec_mgr *imgr,
>>>  				 unsigned long *csk_map, unsigned int nbits);
>>>  
>>> +enum ifpga_sec_err {
>>> +	IFPGA_SEC_ERR_NONE	   = 0x0,
>>> +	IFPGA_SEC_ERR_HW_ERROR	   = 0x1,
>>> +	IFPGA_SEC_ERR_TIMEOUT	   = 0x2,
>>> +	IFPGA_SEC_ERR_CANCELED	   = 0x3,
>>> +	IFPGA_SEC_ERR_BUSY	   = 0x4,
>>> +	IFPGA_SEC_ERR_INVALID_SIZE = 0x5,
>>> +	IFPGA_SEC_ERR_RW_ERROR	   = 0x6,
>>> +	IFPGA_SEC_ERR_WEAROUT	   = 0x7,
>>> +	IFPGA_SEC_ERR_FILE_READ	   = 0x8,
>>> +	IFPGA_SEC_ERR_MAX	   = 0x9
>> The initializers are redundant.
> OK - I'll remove them.
>>> +};
>>> +
>>>  /**
>>>   * struct ifpga_sec_mgr_ops - device specific operations
>>>   * @user_flash_count:	    Optional: Return sysfs string output for FPGA
>>> @@ -110,6 +124,17 @@ typedef int (*sysfs_csk_hndlr_t)(struct ifpga_sec_mgr *imgr,
>>>   * @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 {
>>>  	sysfs_cnt_hndlr_t user_flash_count;
>>> @@ -127,6 +152,22 @@ struct ifpga_sec_mgr_ops {
>>>  	sysfs_csk_nbits_t bmc_canceled_csk_nbits;
>>>  	sysfs_csk_nbits_t sr_canceled_csk_nbits;
>>>  	sysfs_csk_nbits_t pr_canceled_csk_nbits;
>>> +	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	   = 0x0,
>>> +	IFPGA_SEC_PROG_READ_FILE   = 0x1,
>>> +	IFPGA_SEC_PROG_PREPARING   = 0x2,
>>> +	IFPGA_SEC_PROG_WRITING	   = 0x3,
>>> +	IFPGA_SEC_PROG_PROGRAMMING = 0x4,
>>> +	IFPGA_SEC_PROG_MAX	   = 0x5
>> ditto
> Yes. Thanks for the comments!
>
> - Russ
>> Tom
>>
>>>  };
>>>  
>>>  struct ifpga_sec_mgr {
>>> @@ -134,6 +175,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;
>>>  };
>>>  


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

* Re: [PATCH v1 06/12] fpga: add max10 secure update functions
  2020-09-06 16:10   ` Tom Rix
@ 2020-09-22  1:15     ` Russ Weight
  0 siblings, 0 replies; 57+ messages in thread
From: Russ Weight @ 2020-09-22  1:15 UTC (permalink / raw)
  To: Tom Rix, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach



On 9/6/20 9:10 AM, Tom Rix wrote:
> With the v4 max10 change, this patch did not apply to linux-next.
>
> So it will need at least another review when max10 lands in linux-next.
Thanks. I'll build on top of the other patchset and include a reference to the
dependency on my next submission.
>
> On 9/4/20 4:52 PM, Russ Weight wrote:
>> Extend the MAX10 BMC Security Engine driver to include
>> the functions that enable secure updates of BMC images,
>> FPGA images, etc.
>>
>> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
>> Reviewed-by: Wu Hao <hao.wu@intel.com>
>> ---
>>  drivers/fpga/intel-m10-bmc-secure.c | 272 +++++++++++++++++++++++++++-
>>  include/linux/mfd/intel-m10-bmc.h   | 101 +++++++++++
>>  2 files changed, 372 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/fpga/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c
>> index 46cd49a08be0..4a66c2d448eb 100644
>> --- a/drivers/fpga/intel-m10-bmc-secure.c
>> +++ b/drivers/fpga/intel-m10-bmc-secure.c
>> @@ -5,6 +5,7 @@
>>   * Copyright (C) 2019-2020 Intel Corporation. All rights reserved.
>>   *
>>   */
>> +#include <linux/bitfield.h>
>>  #include <linux/device.h>
>>  #include <linux/fpga/ifpga-sec-mgr.h>
>>  #include <linux/mfd/intel-m10-bmc.h>
>> @@ -184,6 +185,271 @@ SYSFS_GET_CSK_VEC(bmc, BMC_PROG_ADDR + CSK_VEC_OFFSET)
>>  SYSFS_GET_CSK_VEC(sr, SR_PROG_ADDR + CSK_VEC_OFFSET)
>>  SYSFS_GET_CSK_VEC(pr, PR_PROG_ADDR + CSK_VEC_OFFSET)
>>  
>> +static void log_error_regs(struct m10bmc_sec *sec, u32 doorbell)
>> +{
>> +	u32 auth_result;
>> +
>> +	dev_err(sec->dev, "RSU error status: 0x%08x\n", doorbell);
>> +
>> +	if (!m10bmc_sys_read(sec->m10bmc, M10BMC_AUTH_RESULT, &auth_result))
>> +		dev_err(sec->dev, "RSU auth result: 0x%08x\n", auth_result);
> If the read fails, auth_result will have garbage in it.
The if condition prevents dev_err() from being called on a failure, and
auth_result is not otherwise used, so I think this is OK?
>
>> +}
>> +
>> +static enum ifpga_sec_err rsu_check_idle(struct m10bmc_sec *sec)
>> +{
>> +	u32 doorbell;
>> +	int ret;
>> +
>> +	ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell);
>> +	if (ret)
>> +		return IFPGA_SEC_ERR_RW_ERROR;
>> +
>> +	if (rsu_prog(doorbell) != RSU_PROG_IDLE &&
>> +	    rsu_prog(doorbell) != RSU_PROG_RSU_DONE) {
>> +		log_error_regs(sec, doorbell);
>> +		return IFPGA_SEC_ERR_BUSY;
>> +	}
>> +
>> +	return IFPGA_SEC_ERR_NONE;
> Why do you need custom error codes here and below ?
The custom error codes are used specifically in the secure update flow which
executes in the context of a kernel worker thread. Any errors that occur in
this context are to be reported as an error string using the sysfs error file
(which is implemented in a later patch). Each of the custom error codes will
have a corresponding error string assigned to it.

I initially considered using standard error numbers, but it felt like I was
overloading the meaning of some of the error numbers. For example, there is
no clear mapping between any of the existing error numbers to "flash-wearout".

>
> Should return int and use -EIO, -EBUSY, 0
>
>> +}
>> +
>> +static inline bool rsu_start_done(u32 doorbell)
>> +{
>> +	return (!(doorbell & RSU_REQUEST) &&
>> +		(rsu_stat(doorbell) == RSU_STAT_ERASE_FAIL ||
>> +		rsu_stat(doorbell) == RSU_STAT_WEAROUT ||
>> +		(rsu_prog(doorbell) != RSU_PROG_IDLE &&
>> +		 rsu_prog(doorbell) != RSU_PROG_RSU_DONE)));
> This is complicated, try simplifying or adding a comment.
>
> The rsu_stat & rsu_prog only need to be called once.
>
> stat = rsu_stat(doorbell)
>
> .. and then something like ..
>
> if (stat & (RSU_STAT_ERASE_FAIL | RSU_STAT_WEAROUT))
Sure - I'll clean this up.
>
>> +}
>> +
>> +static enum ifpga_sec_err rsu_update_init(struct m10bmc_sec *sec)
>> +{
>> +	u32 doorbell;
>> +	int ret;
>> +
>> +	ret = m10bmc_sys_update_bits(sec->m10bmc, M10BMC_DOORBELL,
>> +				     RSU_REQUEST | HOST_STATUS, RSU_REQUEST |
>> +				     FIELD_PREP(HOST_STATUS, HOST_STATUS_IDLE));
>> +	if (ret)
>> +		return IFPGA_SEC_ERR_RW_ERROR;
>> +
>> +	ret = regmap_read_poll_timeout(sec->m10bmc->regmap,
>> +				       M10BMC_SYS_BASE + M10BMC_DOORBELL,
>> +				       doorbell,
>> +				       rsu_start_done(doorbell),
> doorbell needs to be initialized to 0
regmap_read_poll_timeout() is a macro, and doorbell corresponds to the third parameter:

  @val: Unsigned integer variable to read the value into

"rsu_start_done(doorbell)" corresponds to the fourth parameter:

  @cond: Break condition (usually involving @val)

Initialization isn't required in this context, as rsu_start_done() will not be called 
until after doorbell is read.

>> +				       NIOS_HANDSHAKE_INTERVAL_US,
>> +				       NIOS_HANDSHAKE_TIMEOUT_US);
>> +
>> +	if (ret == -ETIMEDOUT) {
>> +		log_error_regs(sec, doorbell);
>> +		return IFPGA_SEC_ERR_TIMEOUT;
>> +	} else if (ret) {
>> +		return IFPGA_SEC_ERR_RW_ERROR;
>> +	}
>> +
>> +	if (rsu_stat(doorbell) == RSU_STAT_WEAROUT) {
> call rsu_stat once
Sure, I'll remove the redundant macro calls.
>> +		dev_warn(sec->dev, "Excessive flash update count detected\n");
>> +		return IFPGA_SEC_ERR_WEAROUT;
>> +	} else if (rsu_stat(doorbell) == RSU_STAT_ERASE_FAIL) {
>> +		log_error_regs(sec, doorbell);
>> +		return IFPGA_SEC_ERR_HW_ERROR;
>> +	}
>> +
>> +	return IFPGA_SEC_ERR_NONE;
>> +}
>> +
>> +static enum ifpga_sec_err rsu_prog_ready(struct m10bmc_sec *sec)
>> +{
>> +	unsigned long poll_timeout;
>> +	u32 doorbell;
>> +	int ret;
>> +
>> +	ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell);
> return here on error.
Ok. Current code falls through to the if condition at the bottom of the function, but
I can just return  IFPGA_SEC_ERR_RW_ERROR here.
>> +	poll_timeout = jiffies + msecs_to_jiffies(RSU_PREP_TIMEOUT_MS);
>> +	while (!ret && !time_after(jiffies, poll_timeout)) {
>> +		if (rsu_prog(doorbell) != RSU_PROG_PREPARE)
> This seems to be the main condition, consider exchanging
>
> it for the time_after in your while() condition
OK
>
>> +			break;
>> +		msleep(RSU_PREP_INTERVAL_MS);
>> +		ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell);
> return here on error
OK
>> +	}
>> +
>> +	if (ret) {
>> +		return IFPGA_SEC_ERR_RW_ERROR;
>> +	} else if (rsu_prog(doorbell) == RSU_PROG_PREPARE) {
I'll remove the duplicate rsu_prog() macro calls as well
>> +		log_error_regs(sec, doorbell);
>> +		return IFPGA_SEC_ERR_TIMEOUT;
>> +	} else if (rsu_prog(doorbell) != RSU_PROG_READY) {
>> +		log_error_regs(sec, doorbell);
>> +		return IFPGA_SEC_ERR_HW_ERROR;
>> +	}
>> +
>> +	return IFPGA_SEC_ERR_NONE;
>> +}
>> +
>> +static enum ifpga_sec_err rsu_send_data(struct m10bmc_sec *sec)
>> +{
>> +	u32 doorbell;
>> +	int ret;
>> +
>> +	ret = m10bmc_sys_update_bits(sec->m10bmc, M10BMC_DOORBELL, HOST_STATUS,
>> +				     FIELD_PREP(HOST_STATUS,
>> +						HOST_STATUS_WRITE_DONE));
>> +	if (ret)
>> +		return IFPGA_SEC_ERR_RW_ERROR;
>> +
>> +	ret = regmap_read_poll_timeout(sec->m10bmc->regmap,
>> +				       M10BMC_SYS_BASE + M10BMC_DOORBELL,
>> +				       doorbell,
>> +				       rsu_prog(doorbell) != RSU_PROG_READY,
> similar to above doorbell must be initialized to 0
>> +				       NIOS_HANDSHAKE_INTERVAL_US,
>> +				       NIOS_HANDSHAKE_TIMEOUT_US);
>> +
>> +	if (ret == -ETIMEDOUT) {
>> +		log_error_regs(sec, doorbell);
>> +		return IFPGA_SEC_ERR_TIMEOUT;
>> +	} else if (ret) {
>> +		return IFPGA_SEC_ERR_RW_ERROR;
>> +	}
>> +
>> +	switch (rsu_stat(doorbell)) {
>> +	case RSU_STAT_NORMAL:
>> +	case RSU_STAT_NIOS_OK:
>> +	case RSU_STAT_USER_OK:
>> +	case RSU_STAT_FACTORY_OK:
>> +		break;
>> +	default:
>> +		log_error_regs(sec, doorbell);
>> +		return IFPGA_SEC_ERR_HW_ERROR;
>> +	}
>> +
>> +	return IFPGA_SEC_ERR_NONE;
>> +}
>> +
>> +static int rsu_check_complete(struct m10bmc_sec *sec, u32 *doorbell)
>> +{
>> +	if (m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, doorbell))
>> +		return -EIO;
>> +
>> +	switch (rsu_stat(*doorbell)) {
>> +	case RSU_STAT_NORMAL:
>> +	case RSU_STAT_NIOS_OK:
>> +	case RSU_STAT_USER_OK:
>> +	case RSU_STAT_FACTORY_OK:
>> +	case RSU_STAT_WEAROUT:
>> +		break;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +
>> +	switch (rsu_prog(*doorbell)) {
>> +	case RSU_PROG_IDLE:
>> +	case RSU_PROG_RSU_DONE:
>> +		return 0;
>> +	case RSU_PROG_AUTHENTICATING:
>> +	case RSU_PROG_COPYING:
>> +	case RSU_PROG_UPDATE_CANCEL:
>> +	case RSU_PROG_PROGRAM_KEY_HASH:
>> +		return -EAGAIN;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +}
>> +
>> +static enum ifpga_sec_err m10bmc_sec_prepare(struct ifpga_sec_mgr *imgr)
>> +{
>> +	struct m10bmc_sec *sec = imgr->priv;
>> +	enum ifpga_sec_err ret;
>> +
>> +	if (imgr->remaining_size > M10BMC_STAGING_SIZE)
>> +		return IFPGA_SEC_ERR_INVALID_SIZE;
> Could this check be moved closer to when the fw is opened ?
m10bmc_sec_prepare() is the first device driver function that is invoked by the
class driver during an update, so this is actually the earliest possible place
that this check can be done, given that the staging size is device specific.
>> +
>> +	ret = rsu_check_idle(sec);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = rsu_update_init(sec);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return rsu_prog_ready(sec);
>> +}
>> +
>> +static enum ifpga_sec_err
>> +m10bmc_sec_write_blk(struct ifpga_sec_mgr *imgr, u32 offset, u32 size)
> Function name should be consistent with existing
>
> m10bmc_raw_bulk_write, likely m10bmc_sec_bulk_write.
>
> Why should not this call go in to intel-m10-bmc.c ?
>
> the imgr parameter is only used to get to the m10bmc.
This function is really in a different class than m10bmc_raw_bulk_write()
and company, which are generic read/write primitives for accessing the MAX10
address space.

This function specifically belongs to the MAX10 Secure Engine (this driver) and is
one of the call-back operations provided to the Security Manager Class driver for
doing secure updates. This is the function that transfers the image data to the
staging area in the flash. It uses the m10bmc_raw_bulk_write() function to write to
the flash.

Is the name confusing? I think it is somewhat consistent with the other Security
Manager callback functions:

    .prepare = m10bmc_sec_prepare,
    .write_blk = m10bmc_sec_write_blk,
    .poll_complete = m10bmc_sec_poll_complete,
    .cancel = m10bmc_sec_cancel



>
>> +{
>> +	struct m10bmc_sec *sec = imgr->priv;
>> +	unsigned int stride = regmap_get_reg_stride(sec->m10bmc->regmap);
>> +	u32 doorbell;
>> +	int ret;
>> +
>> +	ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell);
>> +	if (ret) {
>> +		return IFPGA_SEC_ERR_RW_ERROR;
>> +	} else if (rsu_prog(doorbell) != RSU_PROG_READY) {
>> +		log_error_regs(sec, doorbell);
>> +		return IFPGA_SEC_ERR_HW_ERROR;
>> +	}
>> +
>> +	ret = m10bmc_raw_bulk_write(sec->m10bmc, M10BMC_STAGING_BASE + offset,
>> +				    (void *)imgr->data + offset, size / stride);
>> +
>> +	return ret ? IFPGA_SEC_ERR_RW_ERROR : IFPGA_SEC_ERR_NONE;
>> +}
>> +
>> +static enum ifpga_sec_err m10bmc_sec_poll_complete(struct ifpga_sec_mgr *imgr)
>> +{
>> +	struct m10bmc_sec *sec = imgr->priv;
>> +	unsigned long poll_timeout;
>> +	enum ifpga_sec_err result;
>> +	u32 doorbell;
>> +	int ret;
>> +
>> +	result = rsu_send_data(sec);
>> +	if (result)
>> +		return result;
>> +
>> +	ret = rsu_check_complete(sec, &doorbell);
>> +	poll_timeout = jiffies + msecs_to_jiffies(RSU_COMPLETE_TIMEOUT_MS);
> Maybe a whitespace issue here.
OK
>> +	while (ret == -EAGAIN && !time_after(jiffies, poll_timeout)) {
>> +		msleep(RSU_COMPLETE_INTERVAL_MS);
>> +		ret = rsu_check_complete(sec, &doorbell);
>> +		if (imgr->driver_unload)
>> +			return IFPGA_SEC_ERR_CANCELED;
> unload was not checked in other polling, why not ?
imgr->driver_unload is set in ifpga_sec_mgr_unregister() if someone tries
to unload the driver. In a later patch, the imgr->cancel_request is also
set in ifpga_sec_mgr_unregister(). The imgr->cancel_request flag will be
checked between the calls to m10bmc_sec_write_blk() and allows for a clean
abort of the update.

This case is special because at this point the secure update operation is
100% in the hands of the BMC firmware and there is nothing that the host
driver can do to stop it. It could take another 30+ minutes
to complete. Under these circumstances, we are not allowing this
function to be aborted with a cancel request. However, if the user uses
root privileges to force-unload the driver, then we abort.

Note that even though we are allowing the abort of the driver, the BMC
will continue doing the update in the absence of monitoring from the
host driver.

Do you think comments are required here?
>> +	}
>> +
>> +	if (ret == -EAGAIN) {
>> +		log_error_regs(sec, doorbell);
>> +		return IFPGA_SEC_ERR_TIMEOUT;
>> +	} else if (ret == -EIO) {
>> +		return IFPGA_SEC_ERR_RW_ERROR;
>> +	} else if (ret) {
>> +		log_error_regs(sec, doorbell);
>> +		return IFPGA_SEC_ERR_HW_ERROR;
>> +	}
>> +
>> +	return IFPGA_SEC_ERR_NONE;
>> +}
>> +
>> +static enum ifpga_sec_err m10bmc_sec_cancel(struct ifpga_sec_mgr *imgr)
>> +{
>> +	struct m10bmc_sec *sec = imgr->priv;
>> +	u32 doorbell;
>> +	int ret;
>> +
>> +	ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell);
>> +	if (ret)
>> +		return IFPGA_SEC_ERR_RW_ERROR;
>> +
>> +	if (rsu_prog(doorbell) != RSU_PROG_READY)
>> +		return IFPGA_SEC_ERR_BUSY;
>> +
>> +	ret = m10bmc_sys_update_bits(sec->m10bmc, M10BMC_DOORBELL, HOST_STATUS,
>> +				     FIELD_PREP(HOST_STATUS,
>> +						HOST_STATUS_ABORT_RSU));
>> +
>> +	return ret ? IFPGA_SEC_ERR_RW_ERROR : IFPGA_SEC_ERR_NONE;
>> +}
>> +
>>  static const struct ifpga_sec_mgr_ops m10bmc_iops = {
>>  	.user_flash_count = get_qspi_flash_count,
>>  	.bmc_root_entry_hash = get_bmc_root_entry_hash,
>> @@ -197,7 +463,11 @@ static const struct ifpga_sec_mgr_ops m10bmc_iops = {
>>  	.pr_reh_size = get_pr_reh_size,
>>  	.bmc_canceled_csk_nbits = get_bmc_csk_cancel_nbits,
>>  	.sr_canceled_csk_nbits = get_sr_csk_cancel_nbits,
>> -	.pr_canceled_csk_nbits = get_pr_csk_cancel_nbits
>> +	.pr_canceled_csk_nbits = get_pr_csk_cancel_nbits,
>> +	.prepare = m10bmc_sec_prepare,
>> +	.write_blk = m10bmc_sec_write_blk,
>> +	.poll_complete = m10bmc_sec_poll_complete,
>> +	.cancel = m10bmc_sec_cancel
>>  };
>>  
>>  static void ifpga_sec_mgr_uinit(struct m10bmc_sec *sec)
>> diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h
> This likely needs to be split out into it's own patch
>
> since it is another subsystem. Deferring to Lee.
>
>> index 7fe465c320c2..5d2860d8a0cf 100644
>> --- a/include/linux/mfd/intel-m10-bmc.h
>> +++ b/include/linux/mfd/intel-m10-bmc.h
>> @@ -13,6 +13,9 @@
>>  #define M10BMC_SYS_BASE			0x300800
>>  #define M10BMC_MEM_END			0x200000fc
>>  
>> +#define M10BMC_STAGING_BASE		0x18000000
>> +#define M10BMC_STAGING_SIZE		0x3800000
>> +
>>  /* Register offset of system registers */
>>  #define NIOS2_FW_VERSION		0x0
>>  #define M10BMC_MACADDR1			0x10
>> @@ -36,6 +39,70 @@
>>  #define SERDES_VERSION			GENMASK(15, 0)
>>  #define SBUS_VERSION			GENMASK(31, 16)
>>  
>> +/* Secure update doorbell register, in system register region */
>> +#define M10BMC_DOORBELL			0x400
>> +#define RSU_REQUEST			BIT(0)
>> +#define RSU_PROGRESS			GENMASK(7, 4)
>> +#define HOST_STATUS			GENMASK(11, 8)
>> +#define RSU_STATUS			GENMASK(23, 16)
>> +#define PKVL_EEPROM_LOAD_SEC		BIT(24)
>> +#define PKVL1_POLL_EN			BIT(25)
>> +#define PKVL2_POLL_EN			BIT(26)
>> +#define CONFIG_SEL			BIT(28)
>> +#define REBOOT_REQ			BIT(29)
>> +#define REBOOT_DISABLED			BIT(30)
> These are similar should have a prefix, likely M10BMC_SEC_
These are all fields associated with the doorbell. Perhaps a DOORBELL_ prefix?
>> +
>> +/* Progress states */
>> +#define RSU_PROG_IDLE			0x0
>> +#define RSU_PROG_PREPARE		0x1
>> +#define RSU_PROG_READY			0x3
>> +#define RSU_PROG_AUTHENTICATING		0x4
>> +#define RSU_PROG_COPYING		0x5
>> +#define RSU_PROG_UPDATE_CANCEL		0x6
>> +#define RSU_PROG_PROGRAM_KEY_HASH	0x7
>> +#define RSU_PROG_RSU_DONE		0x8
>> +#define RSU_PROG_PKVL_PROM_DONE		0x9
>> +
>> +/* Device and error states */
>> +#define RSU_STAT_NORMAL			0x0
>> +#define RSU_STAT_TIMEOUT		0x1
>> +#define RSU_STAT_AUTH_FAIL		0x2
>> +#define RSU_STAT_COPY_FAIL		0x3
>> +#define RSU_STAT_FATAL			0x4
>> +#define RSU_STAT_PKVL_REJECT		0x5
>> +#define RSU_STAT_NON_INC		0x6
>> +#define RSU_STAT_ERASE_FAIL		0x7
>> +#define RSU_STAT_WEAROUT		0x8
>> +#define RSU_STAT_NIOS_OK		0x80
>> +#define RSU_STAT_USER_OK		0x81
>> +#define RSU_STAT_FACTORY_OK		0x82
>> +#define RSU_STAT_USER_FAIL		0x83
>> +#define RSU_STAT_FACTORY_FAIL		0x84
>> +#define RSU_STAT_NIOS_FLASH_ERR		0x85
>> +#define RSU_STAT_FPGA_FLASH_ERR		0x86
>> +
>> +#define HOST_STATUS_IDLE		0x0
>> +#define HOST_STATUS_WRITE_DONE		0x1
>> +#define HOST_STATUS_ABORT_RSU		0x2
>> +
>> +#define rsu_prog(doorbell)		FIELD_GET(RSU_PROGRESS, doorbell)
>> +#define rsu_stat(doorbell)		FIELD_GET(RSU_STATUS, doorbell)
>> +
>> +/* interval 100ms and timeout 5s */
>> +#define NIOS_HANDSHAKE_INTERVAL_US	(100 * 1000)
>> +#define NIOS_HANDSHAKE_TIMEOUT_US	(5 * 1000 * 1000)
>> +
>> +/* RSU PREP Timeout (2 minutes) to erase flash staging area */
>> +#define RSU_PREP_INTERVAL_MS		100
>> +#define RSU_PREP_TIMEOUT_MS		(2 * 60 * 1000)
>> +
>> +/* RSU Complete Timeout (40 minutes) for full flash update */
>> +#define RSU_COMPLETE_INTERVAL_MS	1000
>> +#define RSU_COMPLETE_TIMEOUT_MS		(40 * 60 * 1000)
>> +
>> +/* Authorization Result register, in system register region */
>> +#define M10BMC_AUTH_RESULT		0x404
> Needs to move to where the other registers are
>
> defined.
OK
>
>> +
>>  /**
>>   * struct intel_m10bmc_retimer_pdata - subdev retimer platform data
>>   *
>> @@ -64,7 +131,10 @@ struct intel_m10bmc {
>>   *
>>   * m10bmc_raw_read - read m10bmc register per addr
>>   * m10bmc_raw_bulk_read - bulk_read max10 registers per addr
>> + * m10bmc_raw_bulk_write - bulk_write max10 registers per addr
>> + * m10bmc_raw_update_bits - update max10 register per addr
>>   * m10bmc_sys_read - read m10bmc system register per offset
>> + * m10bmc_sys_update_bits - update max10 system register per offset
>>   */
>>  static inline int
>>  m10bmc_raw_read(struct intel_m10bmc *m10bmc, unsigned int addr,
>> @@ -94,7 +164,38 @@ m10bmc_raw_bulk_read(struct intel_m10bmc *m10bmc, unsigned int addr,
>>  	return ret;
>>  }
>>  
>> +static inline int
>> +m10bmc_raw_bulk_write(struct intel_m10bmc *m10bmc, unsigned int addr,
>> +		      void *val, size_t cnt)
>> +{
>> +	int ret;
>> +
>> +	ret = regmap_bulk_write(m10bmc->regmap, addr, val, cnt);
>> +	if (ret)
>> +		dev_err(m10bmc->dev, "fail to write raw reg %x cnt %zx: %d\n",
>> +			addr, cnt, ret);
>> +
>> +	return ret;
>> +}
>> +
>> +static inline int
>> +m10bmc_raw_update_bits(struct intel_m10bmc *m10bmc, unsigned int addr,
>> +		       unsigned int msk, unsigned int val)
>> +{
>> +	int ret;
>> +
>> +	ret = regmap_update_bits(m10bmc->regmap, addr, msk, val);
>> +	if (ret)
>> +		dev_err(m10bmc->dev, "fail to update raw reg %x: %d\n",
>> +			addr, ret);
>> +
>> +	return ret;
>> +}
>> +
>>  #define m10bmc_sys_read(m10bmc, offset, val) \
>>  	m10bmc_raw_read(m10bmc, M10BMC_SYS_BASE + (offset), val)
>>  
>> +#define m10bmc_sys_update_bits(m10bmc, offset, msk, val) \
>> +	m10bmc_raw_update_bits(m10bmc, M10BMC_SYS_BASE + (offset), msk, val)
>> +
> There is discussion on m10bmc patch around the
>
> #define m10bmc_sys_read.
>
> It would be better if m10bmc_sys_update_bits was a real function.
Yes - I'll pick up Yilun's latest patches and follow his convention, make sure
it all compiles together.

Thanks for the comments!
>
> Tom
>
>>  #endif /* __MFD_INTEL_M10_BMC_H */


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

* Re: [PATCH v1 07/12] fpga: expose sec-mgr update status
  2020-09-06 16:16   ` Tom Rix
@ 2020-09-22 22:31     ` Russ Weight
  0 siblings, 0 replies; 57+ messages in thread
From: Russ Weight @ 2020-09-22 22:31 UTC (permalink / raw)
  To: Tom Rix, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach



On 9/6/20 9:16 AM, Tom Rix wrote:
> On 9/4/20 4:53 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>
>> Reviewed-by: Wu Hao <hao.wu@intel.com>
>> ---
>>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 11 ++++++
>>  drivers/fpga/ifpga-sec-mgr.c                  | 34 ++++++++++++++++---
>>  2 files changed, 41 insertions(+), 4 deletions(-)
>>
>> diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> index a476504b7ae9..849ccb2802f8 100644
>> --- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> @@ -86,3 +86,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:		Sep 2020
>> +KernelVersion:  5.10
>> +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, read_file, preparing, writing,
> For consistency, read_file -> reading
Yes - I'll make the change.
>> +		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 73173badbe96..5fe3d85e2963 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);
>> @@ -251,6 +258,24 @@ 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 */
>> +	"read_file",		/* IFPGA_SEC_PROG_READ_FILE */
> "reading"
yes
>> +	"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);
>> +
>> +	return sprintf(buf, "%s\n", (imgr->progress < IFPGA_SEC_PROG_MAX) ?
>> +		       sec_mgr_prog_str[imgr->progress] : "unknown-status");
> when imgr->progress is unknown, should there be a dev_warn ?
Yes, this is a case that should not happen so it probably warrants something in
the kernel log. I'll add that.
>
> Tom
>
>> +}
>> +static DEVICE_ATTR_RO(status);
>> +
>>  static ssize_t filename_store(struct device *dev, struct device_attribute *attr,
>>  			      const char *buf, size_t count)
>>  {
>> @@ -288,6 +313,7 @@ static DEVICE_ATTR_WO(filename);
>>  
>>  static struct attribute *sec_mgr_update_attrs[] = {
>>  	&dev_attr_filename.attr,
>> +	&dev_attr_status.attr,
>>  	NULL,
>>  };
>>  


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

* Re: [PATCH v1 08/12] fpga: expose sec-mgr update errors
  2020-09-06 16:27   ` Tom Rix
@ 2020-09-22 23:42     ` Russ Weight
  2020-09-23 12:52       ` Tom Rix
  0 siblings, 1 reply; 57+ messages in thread
From: Russ Weight @ 2020-09-22 23:42 UTC (permalink / raw)
  To: Tom Rix, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach



On 9/6/20 9:27 AM, Tom Rix wrote:
> On 9/4/20 4:53 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>
>> Reviewed-by: Wu Hao <hao.wu@intel.com>
>> ---
>>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 17 ++++++
>>  drivers/fpga/ifpga-sec-mgr.c                  | 60 +++++++++++++++++--
>>  include/linux/fpga/ifpga-sec-mgr.h            |  1 +
>>  3 files changed, 73 insertions(+), 5 deletions(-)
>>
>> diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> index 849ccb2802f8..e7b1b02bf7ee 100644
>> --- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> @@ -97,3 +97,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:		Sep 2020
>> +KernelVersion:  5.10
>> +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 5fe3d85e2963..a7718bd8ee61 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;
>>  	}
>>  
>> @@ -266,16 +272,59 @@ static const char * const sec_mgr_prog_str[] = {
>>  	"programming"		/* IFPGA_SEC_PROG_PROGRAMMING */
>>  };
>>  
>> +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(enum ifpga_sec_prog prog)
>> +{
> A consistent api would have imgr as the parameter.

There are two calls to this function: one passes imgr->progress, and one
passes imgr->err_status. For this function, passing imgr alone would be
insufficient.
>> +	return (prog < IFPGA_SEC_PROG_MAX) ?
>> +		sec_mgr_prog_str[prog] : "unknown-status";
>> +}
>> +
>>  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", (imgr->progress < IFPGA_SEC_PROG_MAX) ?
>> -		       sec_mgr_prog_str[imgr->progress] : "unknown-status");
>> +	return sprintf(buf, "%s\n", sec_progress(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);
>> +	enum ifpga_sec_err err_code;
>> +	const char *prog_str;
>> +	int ret;
>> +
>> +	mutex_lock(&imgr->lock);
>> +	if (imgr->progress != IFPGA_SEC_PROG_IDLE) {
>> +		ret = -EBUSY;
>> +	} else if (!imgr->err_code) {
>> +		ret = 0;
>> +	} else {
>> +		err_code = imgr->err_code;
>> +		prog_str = sec_progress(imgr->err_state);
>> +		ret = sprintf(buf, "%s:%s\n", prog_str,
>> +			      (err_code < IFPGA_SEC_ERR_MAX) ?
>> +			      sec_mgr_err_str[err_code] : "unknown-error");
> Should have sec_error() call to match the new sec_progress()
OK - I'll add the sec_error() function.
>
> Tom
>
>> +	}
>> +	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)
>>  {
>> @@ -314,6 +363,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 4da2864e251c..f04bf9e30c67 100644
>> --- a/include/linux/fpga/ifpga-sec-mgr.h
>> +++ b/include/linux/fpga/ifpga-sec-mgr.h
>> @@ -181,6 +181,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;


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

* Re: [PATCH v1 08/12] fpga: expose sec-mgr update errors
  2020-09-22 23:42     ` Russ Weight
@ 2020-09-23 12:52       ` Tom Rix
  0 siblings, 0 replies; 57+ messages in thread
From: Tom Rix @ 2020-09-23 12:52 UTC (permalink / raw)
  To: Russ Weight, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 9/22/20 4:42 PM, Russ Weight wrote:
>
> On 9/6/20 9:27 AM, Tom Rix wrote:
>> On 9/4/20 4:53 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>
>>> Reviewed-by: Wu Hao <hao.wu@intel.com>
>>> ---
>>>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 17 ++++++
>>>  drivers/fpga/ifpga-sec-mgr.c                  | 60 +++++++++++++++++--
>>>  include/linux/fpga/ifpga-sec-mgr.h            |  1 +
>>>  3 files changed, 73 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>> index 849ccb2802f8..e7b1b02bf7ee 100644
>>> --- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>> @@ -97,3 +97,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:		Sep 2020
>>> +KernelVersion:  5.10
>>> +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 5fe3d85e2963..a7718bd8ee61 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;
>>>  	}
>>>  
>>> @@ -266,16 +272,59 @@ static const char * const sec_mgr_prog_str[] = {
>>>  	"programming"		/* IFPGA_SEC_PROG_PROGRAMMING */
>>>  };
>>>  
>>> +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(enum ifpga_sec_prog prog)
>>> +{
>> A consistent api would have imgr as the parameter.
> There are two calls to this function: one passes imgr->progress, and one
> passes imgr->err_status. For this function, passing imgr alone would be
> insufficient.

ok.

Tom

>>> +	return (prog < IFPGA_SEC_PROG_MAX) ?
>>> +		sec_mgr_prog_str[prog] : "unknown-status";
>>> +}
>>> +
>>>  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", (imgr->progress < IFPGA_SEC_PROG_MAX) ?
>>> -		       sec_mgr_prog_str[imgr->progress] : "unknown-status");
>>> +	return sprintf(buf, "%s\n", sec_progress(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);
>>> +	enum ifpga_sec_err err_code;
>>> +	const char *prog_str;
>>> +	int ret;
>>> +
>>> +	mutex_lock(&imgr->lock);
>>> +	if (imgr->progress != IFPGA_SEC_PROG_IDLE) {
>>> +		ret = -EBUSY;
>>> +	} else if (!imgr->err_code) {
>>> +		ret = 0;
>>> +	} else {
>>> +		err_code = imgr->err_code;
>>> +		prog_str = sec_progress(imgr->err_state);
>>> +		ret = sprintf(buf, "%s:%s\n", prog_str,
>>> +			      (err_code < IFPGA_SEC_ERR_MAX) ?
>>> +			      sec_mgr_err_str[err_code] : "unknown-error");
>> Should have sec_error() call to match the new sec_progress()
> OK - I'll add the sec_error() function.
>> Tom
>>
>>> +	}
>>> +	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)
>>>  {
>>> @@ -314,6 +363,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 4da2864e251c..f04bf9e30c67 100644
>>> --- a/include/linux/fpga/ifpga-sec-mgr.h
>>> +++ b/include/linux/fpga/ifpga-sec-mgr.h
>>> @@ -181,6 +181,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;


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

* Re: [PATCH v1 10/12] fpga: enable sec-mgr update cancel
       [not found]     ` <678f8d39-a244-42d0-4c56-91eb859b43f0@intel.com>
@ 2020-09-23 13:02       ` Tom Rix
  0 siblings, 0 replies; 57+ messages in thread
From: Tom Rix @ 2020-09-23 13:02 UTC (permalink / raw)
  To: Russ Weight, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach


On 9/22/20 5:55 PM, Russ Weight wrote:
>
> On 9/6/20 10:00 AM, Tom Rix wrote:
>> On 9/4/20 4:53 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>
>>> ---
>>>  .../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 cf1967f1b3e3..762a7dee9453 100644
>>> --- a/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>> @@ -87,6 +87,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:		Sep 2020
>>> +KernelVersion:  5.10
>>> +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:		Sep 2020
>>>  KernelVersion:  5.10
>>> diff --git a/drivers/fpga/ifpga-sec-mgr.c b/drivers/fpga/ifpga-sec-mgr.c
>>> index 4ca5d13e5656..afd97c135ebe 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);
>> check cancel() for double error ?
> Meaning - what if the cancel function returns an error? I have been of the opinion that the first event (in this case, the cancel) is the most important one to report. In the unlikely event that an error occurred during the cancel, if it was a persistent error, it would be reported on the next secure update. Do you think this is a problem? Do you think it would be worth adding logic to report both errors? One thought would be to add a flag to the ifpga_sec_mgr structure to indicate that the error being reported occurred while canceling. And then the error_show() logic could append two error strings (something like: "user-abort+read-write-error"). In this case we could also enable hw_errinfo. What do you think? Would it be better to make this change?
Ok, we will let the next secure update catch the problem.
>> should request_cancel be cleared ?
> I don't think it needs to be cleared here, as we are exiting on error/abort and
> we initialize request_cancel at the beginning of a new secure update.
ok
>>> +		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);
>>> @@ -359,6 +382,7 @@ static ssize_t filename_store(struct device *dev, struct device_attribute *attr,
>>>  		imgr->filename[strlen(imgr->filename) - 1] = '\0';
>>>  
>>>  	imgr->err_code = IFPGA_SEC_ERR_NONE;
>>> +	imgr->request_cancel = false;
>>>  	imgr->progress = IFPGA_SEC_PROG_READ_FILE;
>>>  	reinit_completion(&imgr->update_done);
>>>  	schedule_work(&imgr->work);
>>> @@ -369,8 +393,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 = 0;
>> int ret = count;
> OK
>>> +
>>> +	if (kstrtobool(buf, &cancel) || !cancel)
>> This does not match your description in the testing section.
>>
>> kstrtobool has many other valid inputs.
>>
>> maybe check if count is 1 and buf[0] == '1'
> The documentation is not really incorrect though, is it? I see several other instances
> of *_store() functions that use krstrtobool for input and document that a 1 or a 0
> should be written as input.
>
> However, I'm willing to change it if you think it needs to be changed.

I am being pedantic.

This is ok as-is, testing would work.

Tom

>
>>> +		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 ? : count;
>> return ret;
> Yes - I'll change this.
>> Tom
>>
>>> +}
>>> +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,
>>> @@ -536,6 +584,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 f04bf9e30c67..f51ed663a723 100644
>>> --- a/include/linux/fpga/ifpga-sec-mgr.h
>>> +++ b/include/linux/fpga/ifpga-sec-mgr.h
>>> @@ -183,6 +183,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;
>>>  };


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

* Re: [PATCH v1 12/12] fpga: add max10 get_hw_errinfo callback func
  2020-09-06 17:14   ` Tom Rix
@ 2020-09-24 21:48     ` Russ Weight
  0 siblings, 0 replies; 57+ messages in thread
From: Russ Weight @ 2020-09-24 21:48 UTC (permalink / raw)
  To: Tom Rix, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: lgoncalv, yilun.xu, hao.wu, matthew.gerlach



On 9/6/20 10:14 AM, Tom Rix wrote:
> On 9/4/20 4:53 PM, Russ Weight wrote:
>> Extend the MAX10 BMC Security Engine driver to include
>> a function that returns 64 bits of additional HW specific
>> data for errors that require additional information.
>> This callback function enables the hw_errinfo sysfs
>> node in the Intel Security Manager class driver.
>>
>> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
>> Reviewed-by: Wu Hao <hao.wu@intel.com>
>> ---
>>  drivers/fpga/intel-m10-bmc-secure.c | 27 ++++++++++++++++++++++++++-
>>  1 file changed, 26 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/fpga/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c
>> index 4a66c2d448eb..7fb1c805f654 100644
>> --- a/drivers/fpga/intel-m10-bmc-secure.c
>> +++ b/drivers/fpga/intel-m10-bmc-secure.c
>> @@ -450,6 +450,30 @@ static enum ifpga_sec_err m10bmc_sec_cancel(struct ifpga_sec_mgr *imgr)
>>  	return ret ? IFPGA_SEC_ERR_RW_ERROR : IFPGA_SEC_ERR_NONE;
>>  }
>>  
>> +static u64 m10bmc_sec_hw_errinfo(struct ifpga_sec_mgr *imgr)
>> +{
>> +	struct m10bmc_sec *sec = imgr->priv;
>> +	u32 doorbell = 0, auth_result = 0;
>> +	u64 hw_errinfo = 0;
> hw_errinfo should be initialized to some poison value like -1
>
> to cover the case if either of sys_read's fail.
Yes - that is a good idea. I'll make a change for the next patch version.

- Russ
>
> Tom
>
>> +
>> +	switch (imgr->err_code) {
>> +	case IFPGA_SEC_ERR_HW_ERROR:
>> +	case IFPGA_SEC_ERR_TIMEOUT:
>> +	case IFPGA_SEC_ERR_BUSY:
>> +	case IFPGA_SEC_ERR_WEAROUT:
>> +		if (!m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell))
>> +			hw_errinfo = (u64)doorbell << 32;
>> +
>> +		if (!m10bmc_sys_read(sec->m10bmc, M10BMC_AUTH_RESULT,
>> +				     &auth_result))
>> +			hw_errinfo |= (u64)auth_result;
>> +
>> +		return hw_errinfo;
>> +	default:
>> +		return 0;
>> +	}
>> +}
>> +
>>  static const struct ifpga_sec_mgr_ops m10bmc_iops = {
>>  	.user_flash_count = get_qspi_flash_count,
>>  	.bmc_root_entry_hash = get_bmc_root_entry_hash,
>> @@ -467,7 +491,8 @@ static const struct ifpga_sec_mgr_ops m10bmc_iops = {
>>  	.prepare = m10bmc_sec_prepare,
>>  	.write_blk = m10bmc_sec_write_blk,
>>  	.poll_complete = m10bmc_sec_poll_complete,
>> -	.cancel = m10bmc_sec_cancel
>> +	.cancel = m10bmc_sec_cancel,
>> +	.get_hw_errinfo = m10bmc_sec_hw_errinfo
>>  };
>>  
>>  static void ifpga_sec_mgr_uinit(struct m10bmc_sec *sec)


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

* Re: [PATCH v1 01/12] fpga: fpga security manager class driver
  2020-09-16 20:16   ` Moritz Fischer
@ 2020-09-30 20:54     ` Russ Weight
  2020-10-01  0:31       ` Moritz Fischer
  0 siblings, 1 reply; 57+ messages in thread
From: Russ Weight @ 2020-09-30 20:54 UTC (permalink / raw)
  To: Moritz Fischer
  Cc: lee.jones, linux-fpga, linux-kernel, trix, lgoncalv, yilun.xu,
	hao.wu, matthew.gerlach



On 9/16/20 1:16 PM, Moritz Fischer wrote:
> Hi Russ,
>
> On Fri, Sep 04, 2020 at 04:52:54PM -0700, 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>
>> ---
>>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  75 ++++
>>  MAINTAINERS                                   |   8 +
>>  drivers/fpga/Kconfig                          |   9 +
>>  drivers/fpga/Makefile                         |   3 +
>>  drivers/fpga/ifpga-sec-mgr.c                  | 339 ++++++++++++++++++
>>  include/linux/fpga/ifpga-sec-mgr.h            | 145 ++++++++
>>  6 files changed, 579 insertions(+)
>>  create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>  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..86f8992559bf
>> --- /dev/null
>> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>> @@ -0,0 +1,75 @@
>> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/name
>> +Date:		Sep 2020
>> +KernelVersion:  5.10
>> +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:		Sep 2020
>> +KernelVersion:  5.10
>> +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:		Sep 2020
>> +KernelVersion:  5.10
>> +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:		Sep 2020
>> +KernelVersion:  5.10
>> +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:		Sep 2020
>> +KernelVersion:  5.10
>> +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:		Sep 2020
>> +KernelVersion:  5.10
>> +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:		Sep 2020
>> +KernelVersion:  5.10
>> +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:		Sep 2020
>> +KernelVersion:  5.10
>> +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: "%d".
>> +
>> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/bmc_flash_count
>> +Date:		Sep 2020
>> +KernelVersion:  5.10
>> +Contact:	Russ Weight <russell.h.weight@intel.com>
>> +Description:	Read only. Returns number of times the BMC image has been
>> +		flashed.
>> +		Format: "%d".
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index deaafb617361..4a2ebe6b120d 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -6830,6 +6830,14 @@ 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:	drivers/fpga/ifpga-sec-mgr.c
>> +F:	include/linux/fpga/ifpga-sec-mgr.h
> Actually, ignore my previous comment, feel free to leave this in.
OK. I'll also add the intel-m10-bmc-secure.c file to the maintained files (in
the appropriate patch), as it is the first use of the security manager class
driver.
>> +
>>  FPU EMULATOR
>>  M:	Bill Metzenthen <billm@melbpc.org.au>
>>  S:	Maintained
>> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
>> index 88f64fbf55e3..97c0a6cc2ba7 100644
>> --- a/drivers/fpga/Kconfig
>> +++ b/drivers/fpga/Kconfig
>> @@ -235,4 +235,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 c69bfc931519..ec9fbacdedd8 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..97bf80277ed2
>> --- /dev/null
>> +++ b/drivers/fpga/ifpga-sec-mgr.c
>> @@ -0,0 +1,339 @@
>> +// 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;
>> +
>> +static ssize_t show_canceled_csk(struct ifpga_sec_mgr *imgr,
>> +				 sysfs_csk_hndlr_t get_csk,
>> +				 sysfs_csk_nbits_t get_csk_nbits,
>> +				 char *buf)
>> +{
>> +	unsigned long *csk_map = NULL;
>> +	unsigned int nbits;
>> +	int cnt, 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;
>> +
>> +	cnt = bitmap_print_to_pagebuf(1, buf, csk_map, nbits);
>> +
>> +vfree_exit:
>> +	vfree(csk_map);
>> +	return ret ? : cnt;
>> +}
>> +
>> +static ssize_t show_root_entry_hash(struct ifpga_sec_mgr *imgr,
>> +				    sysfs_reh_hndlr_t get_reh,
>> +				    sysfs_reh_size_t get_reh_size,
>> +				    char *buf)
>> +{
>> +	unsigned int size, i;
>> +	int ret, cnt = 0;
>> +	u8 *hash;
>> +
>> +	ret = get_reh_size(imgr);
>> +	if (ret < 0)
>> +		return ret;
>> +	else if (!ret)
>> +		return sprintf(buf, "hash not programmed\n");
>> +
>> +	size = (unsigned int)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 to_sec_mgr(d) container_of(d, struct ifpga_sec_mgr, dev)
>> +
>> +#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)
>> +
>> +#define DEVICE_ATTR_SEC_FLASH_CNT(_name) \
>> +static ssize_t _name##_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->_name##_flash_count(imgr); \
>> +	return cnt < 0 ? cnt : sprintf(buf, "%d\n", cnt); \
>> +} \
>> +static DEVICE_ATTR_RO(_name##_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_FLASH_CNT(user);
>> +DEVICE_ATTR_SEC_FLASH_CNT(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_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));
>> +
>> +	if (check_attr(attr, user_flash_count) ||
>> +	    check_attr(attr, bmc_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)
>> +{
>> +	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_register - register an IFPGA security manager struct
>> + *
>> + * @dev:  create ifpga security manager device from pdev
> Create or register? Consider splitting this into a create and a
> register function.
I had originally coded it with both a create() and a register() function, but I
became convinced that there wasn't a use case for doing anything between the create()
and register() in the success case, or for doing anything other than failing out when
create() or register() fails - and that error handling would be simpler for the caller
if these functions were combined.

If I do split these up, then I believe the caller would be responsible for doing
"put_device(&imgr->dev)" if register() fails.

Do you think it is better, more standard to split these up? I can do that for the
next patch submission if you would like to see it that way.

>
> Also it might be nice to have a devm_ifpga_create_sec_mgr /
> ifpga_register_sec_mgr set.

I also considered a devm_ function, as is done in the fpga manager. As I understand it,
the purpose of the devm_ functions is to automatically clean up the memory resources
so that it does not have to be done explicitly in error handling. Currently, there
is a class dev_release() function ifpga_sec_mgr_dev_release() that frees the resources.
It seemed to me that it was essentially performing the same function as the managed
resource approach.

Looking at the core device function, device_release(), I can see that it calls first
the managed device functions, and later the class dev_release functions. So if I
provide both methods, then both methods would be called in the devm_ case, right?
So I would need to alter ifpga_sec_mgr_dev_release() to check/avoid a double free?

Am I understanding this correctly? I'm not sure I understand why the devm_ version of
a function might be preferred in this case, but I'm happy to code this up if you think
it is needed.
>> + * @name: ifpga security manager name
>> + * @iops: pointer to a structure of ifpga callback functions
>> + * @priv: ifpga security manager private data
>> + *
>> + * Returns &struct ifpga_sec_mgr pointer on success, or ERR_PTR() on error.
>> + */
>> +struct ifpga_sec_mgr *
>> +ifpga_sec_mgr_register(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 ERR_PTR(-EINVAL);
>> +	}
>> +
>> +	if (!name || !strlen(name)) {
>> +		dev_err(dev, "Attempt to register with no name!\n");
>> +		return ERR_PTR(-EINVAL);
>> +	}
>> +
>> +	imgr = kzalloc(sizeof(*imgr), GFP_KERNEL);
>> +	if (!imgr)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	imgr->name = name;
>> +	imgr->priv = priv;
>> +	imgr->iops = iops;
>> +	mutex_init(&imgr->lock);
>> +
>> +	id = ida_simple_get(&ifpga_sec_mgr_ida, 0, 0, GFP_KERNEL);
>> +	if (id < 0) {
>> +		ret = id;
>> +		goto exit_free;
>> +	}
>> +
>> +	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);
>> +		ida_simple_remove(&ifpga_sec_mgr_ida, id);
>> +		goto exit_free;
>> +	}
> Consider
>    	ret = dev_set_name(&imgr->dev, "ifpga_sec%d", id);
>    	if (ret) {
> 		goto exit_device;
>    	}
> and above exit_free:
> exit_device:
>    		ida_simple_remove(&ifpga_sec_mgr_ida, id);
Yes - I'll change it this way.
>
>> +
>> +	ret = device_register(&imgr->dev);
>> +	if (ret) {
>> +		put_device(&imgr->dev);
>> +		return ERR_PTR(ret);
>> +	}
>> +
>> +	return imgr;
>> +
>> +exit_free:
>> +	kfree(dev);
>> +	return ERR_PTR(ret);
>> +}
>> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_register);
>> +
>> +/**
>> + * ifpga_sec_mgr_unregister - unregister a IFPGA security manager
> Nit: a or an IFPGA?
Yes - I'll change it. Actually, I think I'll change IFPGA to Intel FPGA as well.
>> + *
>> + * @mgr: fpga manager struct
>> + *
>> + * This function is intended for use in a IFPGA security manager
> Nit: a or an?
Same
>> + * 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)
>> +{
>> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
>> +
>> +	mutex_destroy(&imgr->lock);
>> +	ida_simple_remove(&ifpga_sec_mgr_ida, imgr->dev.id);
>> +	kfree(imgr);
>> +}
>> +
>> +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..e391b0c8f448
>> --- /dev/null
>> +++ b/include/linux/fpga/ifpga-sec-mgr.h
>> @@ -0,0 +1,145 @@
>> +/* 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;
>> +
>> +/**
>> + * typedef sysfs_reh_size_t - Function to return byte size of root entry hash
>> + *
>> + * @imgr:      pointer to security manager structure
>> + *
>> + * This datatype is used to define a function that returns the byte size of a
>> + * root entry hash.
>> + *
>> + * Context: No locking requirements are imposed by the security manager.
>> + * Return:  Byte count on success, negative errno on failure
>> + */
>> +typedef int (*sysfs_reh_size_t)(struct ifpga_sec_mgr *imgr);
>> +
>> +/**
>> + * typedef sysfs_reh_hndlr_t - Function pointer to sysfs file handler
>> + *			       for root entry hashes
>> + * @imgr:      pointer to security manager structure
>> + * @hash:      pointer to an array of bytes in which to store the hash
>> + * @size:      byte size of root entry hash
>> + *
>> + * This datatype is used to define a sysfs file handler function to
>> + * return root entry hash data to be displayed via sysfs.
>> + *
>> + * Context: No locking requirements are imposed by the security manager.
>> + * Return:  0 on success, negative errno on failure
>> + */
>> +typedef int (*sysfs_reh_hndlr_t)(struct ifpga_sec_mgr *imgr, u8 *hash,
>> +				 unsigned int size);
>> +
>> +/**
>> + * typedef sysfs_cnt_hndlr_t - Function pointer to sysfs file handler
>> + *			       for flash counts
>> + * @imgr: pointer to security manager structure
>> + *
>> + * This datatype is used to define a sysfs file handler function to
>> + * return a flash count to be displayed via sysfs.
>> + *
>> + * Context: No locking requirements are imposed by the security manager
>> + * Return: flash count or negative errno
>> + */
>> +typedef int (*sysfs_cnt_hndlr_t)(struct ifpga_sec_mgr *imgr);
>> +
>> +/**
>> + * typedef sysfs_csk_nbits_t - Function to return the number of bits in
>> + *				      a Code Signing Key cancellation vector
>> + *
>> + * @imgr:      pointer to security manager structure
>> + *
>> + * This datatype is used to define a function that returns the number of bits
>> + * in a Code Signing Key cancellation vector.
>> + *
>> + * Context: No locking requirements are imposed by the security manager.
>> + * Return:  Number of bits on success, negative errno on failure
>> + */
>> +typedef int (*sysfs_csk_nbits_t)(struct ifpga_sec_mgr *imgr);
>> +
>> +/**
>> + * typedef sysfs_csk_hndlr_t - Function pointer to sysfs file handler
>> + *			       bit vector of canceled keys
>> + *
>> + * @imgr:    pointer to security manager structure
>> + * @csk_map: pointer to a bitmap to contain cancellation key vector
>> + * @nbits:   number of bits in CSK vector
>> + *
>> + * This datatype is used to define a sysfs file handler function to
>> + * return a bitmap of canceled keys to be displayed via sysfs.
>> + *
>> + * Context: No locking requirements are imposed by the security manager.
>> + * Return:  0 on success, negative errno on failure
>> + */
>> +typedef int (*sysfs_csk_hndlr_t)(struct ifpga_sec_mgr *imgr,
>> +				 unsigned long *csk_map, unsigned int nbits);
>> +
>> +/**
>> + * struct ifpga_sec_mgr_ops - device specific operations
>> + * @user_flash_count:	    Optional: Return sysfs string output for FPGA
>> + *			    image flash count
>> + * @bmc_flash_count:	    Optional: Return sysfs string output for BMC
>> + *			    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 {
>> +	sysfs_cnt_hndlr_t user_flash_count;
>> +	sysfs_cnt_hndlr_t bmc_flash_count;
>> +	sysfs_cnt_hndlr_t smbus_flash_count;
>> +	sysfs_reh_hndlr_t sr_root_entry_hash;
>> +	sysfs_reh_hndlr_t pr_root_entry_hash;
>> +	sysfs_reh_hndlr_t bmc_root_entry_hash;
>> +	sysfs_csk_hndlr_t sr_canceled_csks;
>> +	sysfs_csk_hndlr_t pr_canceled_csks;
>> +	sysfs_csk_hndlr_t bmc_canceled_csks;
>> +	sysfs_reh_size_t bmc_reh_size;
>> +	sysfs_reh_size_t sr_reh_size;
>> +	sysfs_reh_size_t pr_reh_size;
>> +	sysfs_csk_nbits_t bmc_canceled_csk_nbits;
>> +	sysfs_csk_nbits_t sr_canceled_csk_nbits;
>> +	sysfs_csk_nbits_t pr_canceled_csk_nbits;
>> +};
> I agree with Tom's feedback, please don't use typedefs here.
I'll remove them.

Thanks for the comments! I've been reworking the patches. I'll split up the class
driver and the Max10 BMC security engine into two patch sets for the next submission.

- Russ
>> +
>> +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_register(struct device *dev, const char *name,
>> +		       const struct ifpga_sec_mgr_ops *iops, void *priv);
>> +void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr);
>> +
>> +#endif
>> -- 
>> 2.17.1
>>
> Thanks,
> Moritz


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

* Re: [PATCH v1 02/12] fpga: create intel max10 bmc security engine
  2020-09-16 20:33   ` Moritz Fischer
@ 2020-09-30 23:14     ` Russ Weight
  0 siblings, 0 replies; 57+ messages in thread
From: Russ Weight @ 2020-09-30 23:14 UTC (permalink / raw)
  To: Moritz Fischer
  Cc: lee.jones, linux-fpga, linux-kernel, trix, lgoncalv, yilun.xu,
	hao.wu, matthew.gerlach

Hi Moritz,

On 9/16/20 1:33 PM, Moritz Fischer wrote:
> Russ,
>
> On Fri, Sep 04, 2020 at 04:52:55PM -0700, Russ Weight wrote:
>> Create a platform driver that can be invoked as a sub
>> driver for the Intel MAX10 BMC in order to support
>> secure updates. This sub-driver will invoke an
>> instance of the Intel FPGA Security Manager class driver
>> in order to expose sysfs interfaces for managing and
>> monitoring secure updates to FPGA and BMC images.
>>
>> This patch creates the MAX10 BMC Security Engine driver and
>> provides support for displaying the current root entry hashes
>> for the FPGA static region, the FPGA PR region, and the MAX10
>> BMC.
>>
>> Signed-off-by: Russ Weight <russell.h.weight@intel.com>
>> Reviewed-by: Wu Hao <hao.wu@intel.com>
>> ---
>>  drivers/fpga/Kconfig                |  11 ++
>>  drivers/fpga/Makefile               |   3 +
>>  drivers/fpga/intel-m10-bmc-secure.c | 170 ++++++++++++++++++++++++++++
>>  include/linux/mfd/intel-m10-bmc.h   |  15 +++
>>  4 files changed, 199 insertions(+)
>>  create mode 100644 drivers/fpga/intel-m10-bmc-secure.c
>>
>> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
>> index 97c0a6cc2ba7..0f0bed68e618 100644
>> --- a/drivers/fpga/Kconfig
>> +++ b/drivers/fpga/Kconfig
>> @@ -244,4 +244,15 @@ config IFPGA_SEC_MGR
>>  	  region and for the BMC. Select this option to enable
>>  	  updates for secure FPGA devices.
>>  
>> +config IFPGA_M10_BMC_SECURE
>> +        tristate "Intel MAX10 BMC security engine"
>> +	depends on MFD_INTEL_M10_BMC && IFPGA_SEC_MGR
>> +        help
>> +          Secure update support for the Intel MAX10 board management
>> +	  controller.
>> +
>> +	  This is a subdriver of the Intel MAX10 board management controller
>> +	  (BMC) and provides support for secure updates for the BMC image,
>> +	  the FPGA image, the Root Entry Hashes, etc.
>> +
>>  endif # FPGA
>> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
>> index ec9fbacdedd8..451a23ec3168 100644
>> --- a/drivers/fpga/Makefile
>> +++ b/drivers/fpga/Makefile
>> @@ -24,6 +24,9 @@ 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
>>  
>> +# Intel Security Manager Drivers
>> +obj-$(CONFIG_IFPGA_M10_BMC_SECURE)	+= intel-m10-bmc-secure.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/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c
>> new file mode 100644
>> index 000000000000..1f86bfb694b4
>> --- /dev/null
>> +++ b/drivers/fpga/intel-m10-bmc-secure.c
>> @@ -0,0 +1,170 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Intel Max10 Board Management Controller Security Engine Driver
>> + *
>> + * Copyright (C) 2019-2020 Intel Corporation. All rights reserved.
>> + *
>> + */
>> +#include <linux/device.h>
>> +#include <linux/fpga/ifpga-sec-mgr.h>
>> +#include <linux/mfd/intel-m10-bmc.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/vmalloc.h>
>> +
>> +struct m10bmc_sec {
>> +	struct device *dev;
>> +	struct intel_m10bmc *m10bmc;
>> +	struct ifpga_sec_mgr *imgr;
>> +};
>> +
>> +#define SHA256_REH_SIZE		32
>> +#define SHA384_REH_SIZE		48
>> +
>> +static int get_reh_size(struct ifpga_sec_mgr *imgr,
>> +			u32 exp_magic, u32 prog_addr)
>> +{
>> +	struct m10bmc_sec *sec = imgr->priv;
>> +	int sha_num_bytes, ret;
>> +	u32 magic;
>> +
>> +	ret = m10bmc_raw_read(sec->m10bmc, prog_addr, &magic);
>> +	if (ret)
>> +		return ret;
>> +
>> +	dev_dbg(sec->dev, "%s magic 0x%08x\n", __func__, magic);
>> +
>> +	if ((magic & 0xffff) != exp_magic)
> Consider using GENMASK() here.
Yes - will do.
>> +		return 0;
>> +
>> +	sha_num_bytes = ((magic >> 16) & 0xffff) / 8;
> And here.
Yes
>> +
>> +	if (sha_num_bytes != SHA256_REH_SIZE &&
>> +	    sha_num_bytes != SHA384_REH_SIZE)   {
>> +		dev_err(sec->dev, "%s bad sha num bytes %d\n", __func__,
>> +			sha_num_bytes);
>> +		return -EINVAL;
>> +	}
>> +
>> +	return sha_num_bytes;
>> +}
>> +
>> +#define BMC_REH_ADDR 0x17ffc004
>> +#define BMC_PROG_ADDR 0x17ffc000
>> +#define BMC_PROG_MAGIC 0x5746
>> +
>> +#define SR_REH_ADDR 0x17ffd004
>> +#define SR_PROG_ADDR 0x17ffd000
>> +#define SR_PROG_MAGIC 0x5253
>> +
>> +#define PR_REH_ADDR 0x17ffe004
>> +#define PR_PROG_ADDR 0x17ffe000
>> +#define PR_PROG_MAGIC 0x5250
>> +
>> +#define SYSFS_GET_REH_SIZE(_name, _exp_magic, _prog_addr) \
>> +static int get_##_name##_reh_size(struct ifpga_sec_mgr *imgr) \
>> +{ \
>> +	return get_reh_size(imgr, _exp_magic, _prog_addr); \
>> +}
>> +
>> +SYSFS_GET_REH_SIZE(bmc, BMC_PROG_MAGIC, BMC_PROG_ADDR)
>> +SYSFS_GET_REH_SIZE(sr, SR_PROG_MAGIC, SR_PROG_ADDR)
>> +SYSFS_GET_REH_SIZE(pr, PR_PROG_MAGIC, PR_PROG_ADDR)
>> +
>> +static int get_root_entry_hash(struct ifpga_sec_mgr *imgr,
>> +			       u32 hash_addr, u8 *hash,
>> +			       unsigned int size)
>> +{
>> +	struct m10bmc_sec *sec = imgr->priv;
>> +	unsigned int stride = regmap_get_reg_stride(sec->m10bmc->regmap);
>> +	int ret;
>> +
>> +	ret = m10bmc_raw_bulk_read(sec->m10bmc, hash_addr,
>> +				   hash, size / stride);
>> +	if (ret)
>> +		dev_err(sec->dev, "bulk_read of 0x%x failed %d",
>> +			hash_addr, ret);
>> +
>> +	return ret;
>> +}
>> +
>> +#define SYSFS_GET_REH(_name, _hash_addr) \
>> +static int get_##_name##_root_entry_hash(struct ifpga_sec_mgr *imgr, \
>> +					 u8 *hash, unsigned int size) \
>> +{ \
>> +	return get_root_entry_hash(imgr, _hash_addr, hash, size); \
>> +}
>> +
>> +SYSFS_GET_REH(bmc, BMC_REH_ADDR)
>> +SYSFS_GET_REH(sr, SR_REH_ADDR)
>> +SYSFS_GET_REH(pr, PR_REH_ADDR)
> Tbh, I'd drop the macro and just have the functions as one liners,
> and yes, please add the prefix.
OK - I'll drop the macros and add the prefixes.

>> +
>> +static const struct ifpga_sec_mgr_ops m10bmc_iops = {
>> +	.bmc_root_entry_hash = get_bmc_root_entry_hash,
>> +	.sr_root_entry_hash = get_sr_root_entry_hash,
>> +	.pr_root_entry_hash = get_pr_root_entry_hash,
>> +	.bmc_reh_size = get_bmc_reh_size,
>> +	.sr_reh_size = get_sr_reh_size,
>> +	.pr_reh_size = get_pr_reh_size,
>> +};
>> +
>> +static void ifpga_sec_mgr_uinit(struct m10bmc_sec *sec)
>> +{
>> +	ifpga_sec_mgr_unregister(sec->imgr);
>> +}
> Consider dropping this function (see below).
Sure - I can drop the init and uinit functions.
>> +
>> +static int ifpga_sec_mgr_init(struct m10bmc_sec *sec)
>> +{
>> +	struct ifpga_sec_mgr *imgr;
>> +
>> +	imgr = ifpga_sec_mgr_register(sec->dev, "Max10 BMC Security Manager",
>> +				      &m10bmc_iops, sec);
>> +	if (IS_ERR(imgr))
>> +		return PTR_ERR(imgr);
>> +
>> +	sec->imgr = imgr;
>> +	return 0;
>> +}
>> +
>> +static int m10bmc_secure_probe(struct platform_device *pdev)
>> +{
>> +	struct m10bmc_sec *sec;
>> +	int ret;
>> +
>> +	sec = devm_kzalloc(&pdev->dev, sizeof(*sec), GFP_KERNEL);
>> +	if (!sec)
>> +		return -ENOMEM;
>> +
>> +	sec->dev = &pdev->dev;
>> +	sec->m10bmc = dev_get_drvdata(pdev->dev.parent);
>> +	dev_set_drvdata(&pdev->dev, sec);
> If you implement the devm_ versions then this could be:
>
> 	imgr = devm_ifpga_sec_mgr_create(&pdev->dev, "Max10 BMC Security
> 					Manager", &m10bmc_ips, sec);
> 	if (IS_ERR(imgr))
> 		return PTR_ERR(imgr);
> 	sec->imgr = imgr;
>
> 	return ifpga_sec_mgr_register(imgr);
If ifpga_sec_mgr_register fails, I think it would be necessary to call
"put_device(&imgr->dev)" here to release the device created by
devm_ifpga_sec_mgr_create()?

Thanks,
- Russ
>
>> +
>> +	ret = ifpga_sec_mgr_init(sec);
>> +	if (ret)
>> +		dev_err(&pdev->dev,
>> +			"Security manager failed to start: %d\n", ret);
>> +
>> +	return ret;
>> +}
>> +
>> +static int m10bmc_secure_remove(struct platform_device *pdev)
>> +{
>> +	struct m10bmc_sec *sec = dev_get_drvdata(&pdev->dev);
>> +
>> +	ifpga_sec_mgr_uinit(sec);
> If you drop the above:
> 	ifpga_sec_mgr_remove(sec->imgr);
>> +	return 0;
>> +}
>> +
>> +static struct platform_driver intel_m10bmc_secure_driver = {
>> +	.probe = m10bmc_secure_probe,
>> +	.remove = m10bmc_secure_remove,
>> +	.driver = {
>> +		.name = "n3000bmc-secure",
>> +	},
>> +};
>> +module_platform_driver(intel_m10bmc_secure_driver);
>> +
>> +MODULE_ALIAS("platform:n3000bmc-secure");
>> +MODULE_AUTHOR("Intel Corporation");
>> +MODULE_DESCRIPTION("Intel MAX10 BMC secure engine");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h
>> index d4cb01b73357..7fe465c320c2 100644
>> --- a/include/linux/mfd/intel-m10-bmc.h
>> +++ b/include/linux/mfd/intel-m10-bmc.h
>> @@ -63,6 +63,7 @@ struct intel_m10bmc {
>>   * register access helper functions.
>>   *
>>   * m10bmc_raw_read - read m10bmc register per addr
>> + * m10bmc_raw_bulk_read - bulk_read max10 registers per addr
>>   * m10bmc_sys_read - read m10bmc system register per offset
>>   */
>>  static inline int
>> @@ -79,6 +80,20 @@ m10bmc_raw_read(struct intel_m10bmc *m10bmc, unsigned int addr,
>>  	return ret;
>>  }
>>  
>> +static inline int
>> +m10bmc_raw_bulk_read(struct intel_m10bmc *m10bmc, unsigned int addr,
>> +		     void *val, size_t cnt)
>> +{
>> +	int ret;
>> +
>> +	ret = regmap_bulk_read(m10bmc->regmap, addr, val, cnt);
>> +	if (ret)
>> +		dev_err(m10bmc->dev, "fail to read raw reg %x cnt %zx: %d\n",
>> +			addr, cnt, ret);
>> +
>> +	return ret;
>> +}
>> +
>>  #define m10bmc_sys_read(m10bmc, offset, val) \
>>  	m10bmc_raw_read(m10bmc, M10BMC_SYS_BASE + (offset), val)
>>  
>> -- 
>> 2.17.1
>>
> Thanks,
> Moritz


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

* Re: [PATCH v1 00/12] Intel FPGA Security Manager Class Driver
  2020-09-05 17:16 ` Tom Rix
@ 2020-10-01  0:19   ` Russ Weight
  0 siblings, 0 replies; 57+ messages in thread
From: Russ Weight @ 2020-10-01  0:19 UTC (permalink / raw)
  To: Tom Rix, linux-kernel, linux-fpga



On 9/5/20 10:16 AM, Tom Rix wrote:
> resending.
> sorry for blowing past 80 chars.
>
> On 9/4/20 4:52 PM, Russ Weight wrote:
>> These patches depend on the patchset: "add regmap-spi-avmm & Intel
>> Max10 BMC chip support" which is currently under review.
> https://marc.info/?l=linux-kernel&m=159782274232229&w=2
>
> regmap-spi-avmm is in linux-next.
>
> max10 is not. however applying it does not resolve resolve
> git am conflicts with yesterday's linux-next.
> I normally build the larger patchsets as a test.
I have rebased to a more recent version of linux-next. I'll make sure to
send dependency information with the next patch set. I'll also split it
into two patch sets, since the class driver has no dependencies on patches
that are in flight.
>
>>            --------------------------------------------------
>>
>> This patchset introduces the Intel Security Manager class driver
>> for managing secure updates on Intel FPGA Cards. It also provides
>> the n3000bmc-secure mfd sub-driver for the MAX10 BMC for the n3000
>> Programmable Acceleration Cards (PAC). The n3000bmc-secure driver
>> is implemented using the Intel Security Manager class driver.
>>
>> The Intel Security Manager class driver provides a common API for
>> user-space tools to manage updates for Secure FPGA devices. Device
>> drivers that instantiate the Intel Security Manager class driver will
>> interact with the 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.
>>
>> 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.
>>
>> 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 n3000bmc-secure driver instantiates the Intel Security Manager
>> class driver and provides the callback functions required to support
>> secure updates on Intel n3000 PAC devices.
> This is a good description.  Because security manager is a new
> interface, there should be a Documentation/fpga/ifpga-sec-mgr.rst
> to collect this description.
Sure - I'll create the documentation file.
>
> How will these devices be discovered ? n3000 is a dfl device,
> will there be a dfl feature id for it at some point ? 

The n3000 implementation of the MAX10 BMC, and eventually the d5005
implementation of the MAX10 BMC, both instantiate the MAX10 BMC Secure
Engine as a sub device. There is a dfl feature ID for the SPI interface
to the BMC, but no dfl feature ID for the secure engine itself.

Given that the security manager is dependent on other hardware and
firmware to manage the root entry hashes and to verify and program
the images, I think it is safe to say that implementations of the
security manager will always be implemented as sub devices. I can't
think of a case for giving it it's own dfl feature ID.

The class driver, of course, is an abstraction above the MAX10 BMC
implementation.
> Can you describe if/how the security manager would live outside
> of dfl ?  I am wondering why this shouldn't be dfl-sec-mgr. 
The Intel FPGA Security Manager could be used by Intel FPGA devices that
are implemented without a Device Feature List.

> I did not see any version handling.  How would this sw adapt
> to a newer or older version of the bmc interface?
There are some slight differences in the implementation of the MAX10 BMC
Secure Engine between the n3000 and d5005 implementations. The d5005
support is not in the current patch set, but when it is included there
will be a different device name to indicate which code variations should
be active. Also, different platform data can be passed into the secure
engine by the parent MAX10 device if needed for new versions of the BMC.

Thanks,
- Russ
>
> Tom
>
>> Russ Weight (12):
>>   fpga: fpga security manager class driver
>>   fpga: create intel max10 bmc security engine
>>   fpga: expose max10 flash update counts in sysfs
>>   fpga: expose max10 canceled keys in sysfs
>>   fpga: enable secure updates
>>   fpga: add max10 secure update functions
>>   fpga: expose sec-mgr update status
>>   fpga: expose sec-mgr update errors
>>   fpga: expose sec-mgr update size
>>   fpga: enable sec-mgr update cancel
>>   fpga: expose hardware error info in sysfs
>>   fpga: add max10 get_hw_errinfo callback func
>>
>>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 151 ++++
>>  MAINTAINERS                                   |   8 +
>>  drivers/fpga/Kconfig                          |  20 +
>>  drivers/fpga/Makefile                         |   6 +
>>  drivers/fpga/ifpga-sec-mgr.c                  | 669 ++++++++++++++++++
>>  drivers/fpga/intel-m10-bmc-secure.c           | 557 +++++++++++++++
>>  include/linux/fpga/ifpga-sec-mgr.h            | 201 ++++++
>>  include/linux/mfd/intel-m10-bmc.h             | 116 +++
>>  8 files changed, 1728 insertions(+)
>>  create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>  create mode 100644 drivers/fpga/ifpga-sec-mgr.c
>>  create mode 100644 drivers/fpga/intel-m10-bmc-secure.c
>>  create mode 100644 include/linux/fpga/ifpga-sec-mgr.h
>>


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

* Re: [PATCH v1 01/12] fpga: fpga security manager class driver
  2020-09-30 20:54     ` Russ Weight
@ 2020-10-01  0:31       ` Moritz Fischer
  2020-10-01  1:07         ` Russ Weight
  0 siblings, 1 reply; 57+ messages in thread
From: Moritz Fischer @ 2020-10-01  0:31 UTC (permalink / raw)
  To: Russ Weight
  Cc: Moritz Fischer, lee.jones, linux-fpga, linux-kernel, trix,
	lgoncalv, yilun.xu, hao.wu, matthew.gerlach

Hi Russ,

On Wed, Sep 30, 2020 at 01:54:50PM -0700, Russ Weight wrote:
> 
> 
> On 9/16/20 1:16 PM, Moritz Fischer wrote:
> > Hi Russ,
> >
> > On Fri, Sep 04, 2020 at 04:52:54PM -0700, 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>
> >> ---
> >>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     |  75 ++++
> >>  MAINTAINERS                                   |   8 +
> >>  drivers/fpga/Kconfig                          |   9 +
> >>  drivers/fpga/Makefile                         |   3 +
> >>  drivers/fpga/ifpga-sec-mgr.c                  | 339 ++++++++++++++++++
> >>  include/linux/fpga/ifpga-sec-mgr.h            | 145 ++++++++
> >>  6 files changed, 579 insertions(+)
> >>  create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> >>  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..86f8992559bf
> >> --- /dev/null
> >> +++ b/Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
> >> @@ -0,0 +1,75 @@
> >> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/name
> >> +Date:		Sep 2020
> >> +KernelVersion:  5.10
Looking at the timing, those'll probably become 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:		Sep 2020
> >> +KernelVersion:  5.10
> >> +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:		Sep 2020
> >> +KernelVersion:  5.10
> >> +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:		Sep 2020
> >> +KernelVersion:  5.10
> >> +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:		Sep 2020
> >> +KernelVersion:  5.10
> >> +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:		Sep 2020
> >> +KernelVersion:  5.10
> >> +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:		Sep 2020
> >> +KernelVersion:  5.10
> >> +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:		Sep 2020
> >> +KernelVersion:  5.10
> >> +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: "%d".
> >> +
> >> +What: 		/sys/class/ifpga_sec_mgr/ifpga_secX/security/bmc_flash_count
> >> +Date:		Sep 2020
> >> +KernelVersion:  5.10
> >> +Contact:	Russ Weight <russell.h.weight@intel.com>
> >> +Description:	Read only. Returns number of times the BMC image has been
> >> +		flashed.
> >> +		Format: "%d".
> >> diff --git a/MAINTAINERS b/MAINTAINERS
> >> index deaafb617361..4a2ebe6b120d 100644
> >> --- a/MAINTAINERS
> >> +++ b/MAINTAINERS
> >> @@ -6830,6 +6830,14 @@ 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:	drivers/fpga/ifpga-sec-mgr.c
> >> +F:	include/linux/fpga/ifpga-sec-mgr.h
> > Actually, ignore my previous comment, feel free to leave this in.
> OK. I'll also add the intel-m10-bmc-secure.c file to the maintained files (in
> the appropriate patch), as it is the first use of the security manager class
> driver.

Works for me.
> >> +
> >>  FPU EMULATOR
> >>  M:	Bill Metzenthen <billm@melbpc.org.au>
> >>  S:	Maintained
> >> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> >> index 88f64fbf55e3..97c0a6cc2ba7 100644
> >> --- a/drivers/fpga/Kconfig
> >> +++ b/drivers/fpga/Kconfig
> >> @@ -235,4 +235,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 c69bfc931519..ec9fbacdedd8 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..97bf80277ed2
> >> --- /dev/null
> >> +++ b/drivers/fpga/ifpga-sec-mgr.c
> >> @@ -0,0 +1,339 @@
> >> +// 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;
> >> +
> >> +static ssize_t show_canceled_csk(struct ifpga_sec_mgr *imgr,
> >> +				 sysfs_csk_hndlr_t get_csk,
> >> +				 sysfs_csk_nbits_t get_csk_nbits,
> >> +				 char *buf)
> >> +{
> >> +	unsigned long *csk_map = NULL;
> >> +	unsigned int nbits;
> >> +	int cnt, 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;
> >> +
> >> +	cnt = bitmap_print_to_pagebuf(1, buf, csk_map, nbits);
> >> +
> >> +vfree_exit:
> >> +	vfree(csk_map);
> >> +	return ret ? : cnt;
> >> +}
> >> +
> >> +static ssize_t show_root_entry_hash(struct ifpga_sec_mgr *imgr,
> >> +				    sysfs_reh_hndlr_t get_reh,
> >> +				    sysfs_reh_size_t get_reh_size,
> >> +				    char *buf)
> >> +{
> >> +	unsigned int size, i;
> >> +	int ret, cnt = 0;
> >> +	u8 *hash;
> >> +
> >> +	ret = get_reh_size(imgr);
> >> +	if (ret < 0)
> >> +		return ret;
> >> +	else if (!ret)
> >> +		return sprintf(buf, "hash not programmed\n");
> >> +
> >> +	size = (unsigned int)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 to_sec_mgr(d) container_of(d, struct ifpga_sec_mgr, dev)
> >> +
> >> +#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)
> >> +
> >> +#define DEVICE_ATTR_SEC_FLASH_CNT(_name) \
> >> +static ssize_t _name##_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->_name##_flash_count(imgr); \
> >> +	return cnt < 0 ? cnt : sprintf(buf, "%d\n", cnt); \
> >> +} \
> >> +static DEVICE_ATTR_RO(_name##_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_FLASH_CNT(user);
> >> +DEVICE_ATTR_SEC_FLASH_CNT(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_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));
> >> +
> >> +	if (check_attr(attr, user_flash_count) ||
> >> +	    check_attr(attr, bmc_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)
> >> +{
> >> +	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_register - register an IFPGA security manager struct
> >> + *
> >> + * @dev:  create ifpga security manager device from pdev
> > Create or register? Consider splitting this into a create and a
> > register function.
> I had originally coded it with both a create() and a register() function, but I
> became convinced that there wasn't a use case for doing anything between the create()
> and register() in the success case, or for doing anything other than failing out when
> create() or register() fails - and that error handling would be simpler for the caller
> if these functions were combined.
> 
> If I do split these up, then I believe the caller would be responsible for doing
> "put_device(&imgr->dev)" if register() fails.

You can look at the fpga_mgr/bridge/region for a working pattern. I
think devres and the release functions as a result take care of it.

> Do you think it is better, more standard to split these up? I can do that for the
> next patch submission if you would like to see it that way.

I think providing the devm_ managed APIs is nicer, and makes it easier
for the consumer of the API to do the right thing.
> 
> >
> > Also it might be nice to have a devm_ifpga_create_sec_mgr /
> > ifpga_register_sec_mgr set.
> 
> I also considered a devm_ function, as is done in the fpga manager. As I understand it,
> the purpose of the devm_ functions is to automatically clean up the memory resources
> so that it does not have to be done explicitly in error handling. Currently, there
> is a class dev_release() function ifpga_sec_mgr_dev_release() that frees the resources.
> It seemed to me that it was essentially performing the same function as the managed
> resource approach.

I'd prefer if we could keep the pattern the same within drivers/fpga,
that makes refactoring easier if we decide to do so.

I think the networking subsystem uses a similar pattern with alloc() and
register() split up.

The SPI subsystem uses a variation of it.

> Looking at the core device function, device_release(), I can see that it calls first
> the managed device functions, and later the class dev_release functions. So if I
> provide both methods, then both methods would be called in the devm_ case, right?
> So I would need to alter ifpga_sec_mgr_dev_release() to check/avoid a double free?

If you look at FPGA manager/bridge code the class release ones are empty.
> 
> Am I understanding this correctly? I'm not sure I understand why the devm_ version of
> a function might be preferred in this case, but I'm happy to code this up if you think
> it is needed.

You might want to have finer control over when you unregister vs free.
The current pattern provides that.

I think we had originally discussed making it a devm_register() API that
would do all the cleanup and unregister in one go, but I don't recall
why we didn't go that far. I'll try to remember :)

> >> + * @name: ifpga security manager name
> >> + * @iops: pointer to a structure of ifpga callback functions
> >> + * @priv: ifpga security manager private data
> >> + *
> >> + * Returns &struct ifpga_sec_mgr pointer on success, or ERR_PTR() on error.
> >> + */
> >> +struct ifpga_sec_mgr *
> >> +ifpga_sec_mgr_register(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 ERR_PTR(-EINVAL);
> >> +	}
> >> +
> >> +	if (!name || !strlen(name)) {
> >> +		dev_err(dev, "Attempt to register with no name!\n");
> >> +		return ERR_PTR(-EINVAL);
> >> +	}
> >> +
> >> +	imgr = kzalloc(sizeof(*imgr), GFP_KERNEL);
> >> +	if (!imgr)
> >> +		return ERR_PTR(-ENOMEM);
> >> +
> >> +	imgr->name = name;
> >> +	imgr->priv = priv;
> >> +	imgr->iops = iops;
> >> +	mutex_init(&imgr->lock);
> >> +
> >> +	id = ida_simple_get(&ifpga_sec_mgr_ida, 0, 0, GFP_KERNEL);
> >> +	if (id < 0) {
> >> +		ret = id;
> >> +		goto exit_free;
> >> +	}
> >> +
> >> +	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);
> >> +		ida_simple_remove(&ifpga_sec_mgr_ida, id);
> >> +		goto exit_free;
> >> +	}
> > Consider
> >    	ret = dev_set_name(&imgr->dev, "ifpga_sec%d", id);
> >    	if (ret) {
> > 		goto exit_device;
> >    	}
> > and above exit_free:
> > exit_device:
> >    		ida_simple_remove(&ifpga_sec_mgr_ida, id);
> Yes - I'll change it this way.
> >
> >> +
> >> +	ret = device_register(&imgr->dev);
> >> +	if (ret) {
> >> +		put_device(&imgr->dev);
> >> +		return ERR_PTR(ret);
> >> +	}
> >> +
> >> +	return imgr;
> >> +
> >> +exit_free:
> >> +	kfree(dev);
> >> +	return ERR_PTR(ret);
> >> +}
> >> +EXPORT_SYMBOL_GPL(ifpga_sec_mgr_register);
> >> +
> >> +/**
> >> + * ifpga_sec_mgr_unregister - unregister a IFPGA security manager
> > Nit: a or an IFPGA?
> Yes - I'll change it. Actually, I think I'll change IFPGA to Intel FPGA as well.
> >> + *
> >> + * @mgr: fpga manager struct
> >> + *
> >> + * This function is intended for use in a IFPGA security manager
> > Nit: a or an?
> Same
> >> + * 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)
> >> +{
> >> +	struct ifpga_sec_mgr *imgr = to_sec_mgr(dev);
> >> +
> >> +	mutex_destroy(&imgr->lock);
> >> +	ida_simple_remove(&ifpga_sec_mgr_ida, imgr->dev.id);
> >> +	kfree(imgr);
> >> +}
> >> +
> >> +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..e391b0c8f448
> >> --- /dev/null
> >> +++ b/include/linux/fpga/ifpga-sec-mgr.h
> >> @@ -0,0 +1,145 @@
> >> +/* 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;
> >> +
> >> +/**
> >> + * typedef sysfs_reh_size_t - Function to return byte size of root entry hash
> >> + *
> >> + * @imgr:      pointer to security manager structure
> >> + *
> >> + * This datatype is used to define a function that returns the byte size of a
> >> + * root entry hash.
> >> + *
> >> + * Context: No locking requirements are imposed by the security manager.
> >> + * Return:  Byte count on success, negative errno on failure
> >> + */
> >> +typedef int (*sysfs_reh_size_t)(struct ifpga_sec_mgr *imgr);

As I had mentioned can we keep those as function pointers?
> >> +
> >> +/**
> >> + * typedef sysfs_reh_hndlr_t - Function pointer to sysfs file handler
> >> + *			       for root entry hashes
> >> + * @imgr:      pointer to security manager structure
> >> + * @hash:      pointer to an array of bytes in which to store the hash
> >> + * @size:      byte size of root entry hash
> >> + *
> >> + * This datatype is used to define a sysfs file handler function to
> >> + * return root entry hash data to be displayed via sysfs.
> >> + *
> >> + * Context: No locking requirements are imposed by the security manager.
> >> + * Return:  0 on success, negative errno on failure
> >> + */
> >> +typedef int (*sysfs_reh_hndlr_t)(struct ifpga_sec_mgr *imgr, u8 *hash,
> >> +				 unsigned int size);
> >> +
> >> +/**
> >> + * typedef sysfs_cnt_hndlr_t - Function pointer to sysfs file handler
> >> + *			       for flash counts
> >> + * @imgr: pointer to security manager structure
> >> + *
> >> + * This datatype is used to define a sysfs file handler function to
> >> + * return a flash count to be displayed via sysfs.
> >> + *
> >> + * Context: No locking requirements are imposed by the security manager
> >> + * Return: flash count or negative errno
> >> + */
> >> +typedef int (*sysfs_cnt_hndlr_t)(struct ifpga_sec_mgr *imgr);
> >> +
> >> +/**
> >> + * typedef sysfs_csk_nbits_t - Function to return the number of bits in
> >> + *				      a Code Signing Key cancellation vector
> >> + *
> >> + * @imgr:      pointer to security manager structure
> >> + *
> >> + * This datatype is used to define a function that returns the number of bits
> >> + * in a Code Signing Key cancellation vector.
> >> + *
> >> + * Context: No locking requirements are imposed by the security manager.
> >> + * Return:  Number of bits on success, negative errno on failure
> >> + */
> >> +typedef int (*sysfs_csk_nbits_t)(struct ifpga_sec_mgr *imgr);
> >> +
> >> +/**
> >> + * typedef sysfs_csk_hndlr_t - Function pointer to sysfs file handler
> >> + *			       bit vector of canceled keys
> >> + *
> >> + * @imgr:    pointer to security manager structure
> >> + * @csk_map: pointer to a bitmap to contain cancellation key vector
> >> + * @nbits:   number of bits in CSK vector
> >> + *
> >> + * This datatype is used to define a sysfs file handler function to
> >> + * return a bitmap of canceled keys to be displayed via sysfs.
> >> + *
> >> + * Context: No locking requirements are imposed by the security manager.
> >> + * Return:  0 on success, negative errno on failure
> >> + */
> >> +typedef int (*sysfs_csk_hndlr_t)(struct ifpga_sec_mgr *imgr,
> >> +				 unsigned long *csk_map, unsigned int nbits);
> >> +
> >> +/**
> >> + * struct ifpga_sec_mgr_ops - device specific operations
> >> + * @user_flash_count:	    Optional: Return sysfs string output for FPGA
> >> + *			    image flash count
> >> + * @bmc_flash_count:	    Optional: Return sysfs string output for BMC
> >> + *			    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 {
> >> +	sysfs_cnt_hndlr_t user_flash_count;
> >> +	sysfs_cnt_hndlr_t bmc_flash_count;
> >> +	sysfs_cnt_hndlr_t smbus_flash_count;
> >> +	sysfs_reh_hndlr_t sr_root_entry_hash;
> >> +	sysfs_reh_hndlr_t pr_root_entry_hash;
> >> +	sysfs_reh_hndlr_t bmc_root_entry_hash;
> >> +	sysfs_csk_hndlr_t sr_canceled_csks;
> >> +	sysfs_csk_hndlr_t pr_canceled_csks;
> >> +	sysfs_csk_hndlr_t bmc_canceled_csks;
> >> +	sysfs_reh_size_t bmc_reh_size;
> >> +	sysfs_reh_size_t sr_reh_size;
> >> +	sysfs_reh_size_t pr_reh_size;
> >> +	sysfs_csk_nbits_t bmc_canceled_csk_nbits;
> >> +	sysfs_csk_nbits_t sr_canceled_csk_nbits;
> >> +	sysfs_csk_nbits_t pr_canceled_csk_nbits;
> >> +};
> > I agree with Tom's feedback, please don't use typedefs here.
> I'll remove them.
> 
> Thanks for the comments! I've been reworking the patches. I'll split up the class
> driver and the Max10 BMC security engine into two patch sets for the next submission.

Great. Send a new version, and then we can see where it's at :-)
> 
> - Russ
> >> +
> >> +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_register(struct device *dev, const char *name,
> >> +		       const struct ifpga_sec_mgr_ops *iops, void *priv);
> >> +void ifpga_sec_mgr_unregister(struct ifpga_sec_mgr *imgr);
> >> +
> >> +#endif
> >> -- 
> >> 2.17.1
> >>
> > Thanks,
> > Moritz
> 

Thanks,
Moritz

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

* Re: [PATCH v1 01/12] fpga: fpga security manager class driver
  2020-10-01  0:31       ` Moritz Fischer
@ 2020-10-01  1:07         ` Russ Weight
  2020-10-01 19:07           ` Moritz Fischer
  0 siblings, 1 reply; 57+ messages in thread
From: Russ Weight @ 2020-10-01  1:07 UTC (permalink / raw)
  To: Moritz Fischer
  Cc: lee.jones, linux-fpga, linux-kernel, trix, lgoncalv, yilun.xu,
	hao.wu, matthew.gerlach


Hi Moritz,

On 9/30/20 5:31 PM, Moritz Fischer wrote:
> I think providing the devm_ managed APIs is nicer, and makes it easier
> for the consumer of the API to do the right thing.

I see that the fpga_mgr code has support for two versions of the create()
and register() functions, one uses the devm_ approach, and the other does
not. Would also want to have two versions for the security manager?

- Russ

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

* Re: [PATCH v1 01/12] fpga: fpga security manager class driver
  2020-10-01  1:07         ` Russ Weight
@ 2020-10-01 19:07           ` Moritz Fischer
  0 siblings, 0 replies; 57+ messages in thread
From: Moritz Fischer @ 2020-10-01 19:07 UTC (permalink / raw)
  To: Russ Weight
  Cc: Moritz Fischer, lee.jones, linux-fpga, linux-kernel, trix,
	lgoncalv, yilun.xu, hao.wu, matthew.gerlach

Hi Russ,

On Wed, Sep 30, 2020 at 06:07:00PM -0700, Russ Weight wrote:
> 
> Hi Moritz,
> 
> On 9/30/20 5:31 PM, Moritz Fischer wrote:
> > I think providing the devm_ managed APIs is nicer, and makes it easier
> > for the consumer of the API to do the right thing.
> 
> I see that the fpga_mgr code has support for two versions of the create()
> and register() functions, one uses the devm_ approach, and the other does
> not. Would also want to have two versions for the security manager?

The devm_fpga_mgr_create() just wraps the other one. I think that's a
good way to handle it for now.

I'd keep the breakdown the same.

Cheers,
Moritz

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

* Re: [PATCH v1 00/12] Intel FPGA Security Manager Class Driver
  2020-09-05 14:13 ` [PATCH v1 00/12] Intel FPGA Security Manager Class Driver Wu, Hao
@ 2020-10-01 20:42   ` Russ Weight
  0 siblings, 0 replies; 57+ messages in thread
From: Russ Weight @ 2020-10-01 20:42 UTC (permalink / raw)
  To: Wu, Hao, mdf, lee.jones, linux-fpga, linux-kernel
  Cc: trix, lgoncalv, Xu, Yilun, Gerlach, Matthew



On 9/5/20 7:13 AM, Wu, Hao wrote:
>> Subject: [PATCH v1 00/12] Intel FPGA Security Manager Class Driver
>>
>>
>> These patches depend on the patchset: "add regmap-spi-avmm & Intel
>> Max10 BMC chip support" which is currently under review.
>>
>>            --------------------------------------------------
>>
>> This patchset introduces the Intel Security Manager class driver
>> for managing secure updates on Intel FPGA Cards. It also provides
>> the n3000bmc-secure mfd sub-driver for the MAX10 BMC for the n3000
>> Programmable Acceleration Cards (PAC). The n3000bmc-secure driver
>> is implemented using the Intel Security Manager class driver.
> So this patchset contains two parts
> (1) adding a new class driver for Intel FPGA secure update.
> (2) a new driver which uses (1) to implement secure update for n3000 PAC.
Yes - that is correct
>
> And only part (2) depends on "Intel MAX10 BMC chip support" patchset.
> (Maybe you can provide a link to that thread).
>
> Is my understanding correct? If yes, is it possible to reorder these patches?
> At least there is no dependency on the class driver patches, right?
Yes - I'm splitting the patch set, and I'll provide links for the dependencies
on the MAX10 BMC Secure Engine patch set.
>
>> The Intel Security Manager class driver provides a common API for
>> user-space tools to manage updates for Secure FPGA devices. Device
>> drivers that instantiate the Intel Security Manager class driver will
>> interact with the 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.
>>
>> 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.
>>
>> 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.
> Maybe you can explain a little more on why we need to have this done
> via a class driver not just some internal code in max10 driver? This class
> driver will be reused in different cases? And why adding a new class
> driver not just reuse or extend fpga manager (existing fpga mgr is used
> to update fpga too).
Yes - I'll so that in the next patch set.
>
>> The n3000bmc-secure driver instantiates the Intel Security Manager
>> class driver and provides the callback functions required to support
>> secure updates on Intel n3000 PAC devices.
>>
>> Russ Weight (12):
>>   fpga: fpga security manager class driver
> Intel FPGA Security Manager?
Yes - I'll make that change
>
>>   fpga: create intel max10 bmc security engine
>>   fpga: expose max10 flash update counts in sysfs
>>   fpga: expose max10 canceled keys in sysfs
>>   fpga: enable secure updates
>>   fpga: add max10 secure update functions
>>   fpga: expose sec-mgr update status
>>   fpga: expose sec-mgr update errors
>>   fpga: expose sec-mgr update size
>>   fpga: enable sec-mgr update cancel
>>   fpga: expose hardware error info in sysfs
> For these patches, is it possible to have a better title for these patches.
> Then it will be easier to know which component this patch is going to modify.
> e.g. fpga: ifpga-sec-mgr: xxxxxx
Yes. Thanks for the comments.

- Russ
>
> Thanks
> Hao
>
>>   fpga: add max10 get_hw_errinfo callback func
>>
>>  .../ABI/testing/sysfs-class-ifpga-sec-mgr     | 151 ++++
>>  MAINTAINERS                                   |   8 +
>>  drivers/fpga/Kconfig                          |  20 +
>>  drivers/fpga/Makefile                         |   6 +
>>  drivers/fpga/ifpga-sec-mgr.c                  | 669 ++++++++++++++++++
>>  drivers/fpga/intel-m10-bmc-secure.c           | 557 +++++++++++++++
>>  include/linux/fpga/ifpga-sec-mgr.h            | 201 ++++++
>>  include/linux/mfd/intel-m10-bmc.h             | 116 +++
>>  8 files changed, 1728 insertions(+)
>>  create mode 100644 Documentation/ABI/testing/sysfs-class-ifpga-sec-mgr
>>  create mode 100644 drivers/fpga/ifpga-sec-mgr.c
>>  create mode 100644 drivers/fpga/intel-m10-bmc-secure.c
>>  create mode 100644 include/linux/fpga/ifpga-sec-mgr.h
>>
>> --
>> 2.17.1


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

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

Thread overview: 57+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-04 23:52 [PATCH v1 00/12] Intel FPGA Security Manager Class Driver Russ Weight
2020-09-04 23:52 ` [PATCH v1 01/12] fpga: fpga security manager class driver Russ Weight
2020-09-04 23:57   ` Randy Dunlap
2020-09-05  0:23   ` Moritz Fischer
2020-09-05  0:44     ` Russ Weight
2020-09-05 13:39       ` Wu, Hao
2020-09-05 19:09   ` Tom Rix
     [not found]     ` <ebf251a0-5f13-d1a1-6915-e3c940bb19fe@intel.com>
2020-09-10 21:51       ` Tom Rix
2020-09-10 23:05         ` Russ Weight
2020-09-16 20:16   ` Moritz Fischer
2020-09-30 20:54     ` Russ Weight
2020-10-01  0:31       ` Moritz Fischer
2020-10-01  1:07         ` Russ Weight
2020-10-01 19:07           ` Moritz Fischer
2020-09-04 23:52 ` [PATCH v1 02/12] fpga: create intel max10 bmc security engine Russ Weight
2020-09-05  0:01   ` Randy Dunlap
2020-09-05  0:05     ` Russ Weight
2020-09-05 20:22   ` Tom Rix
2020-09-14 19:07     ` Russ Weight
2020-09-14 20:48       ` Tom Rix
2020-09-14 21:40         ` Russ Weight
2020-09-16 20:33   ` Moritz Fischer
2020-09-30 23:14     ` Russ Weight
2020-09-04 23:52 ` [PATCH v1 03/12] fpga: expose max10 flash update counts in sysfs Russ Weight
2020-09-05 20:39   ` Tom Rix
2020-09-16 18:37     ` Russ Weight
2020-09-04 23:52 ` [PATCH v1 04/12] fpga: expose max10 canceled keys " Russ Weight
2020-09-05 20:52   ` Tom Rix
2020-09-04 23:52 ` [PATCH v1 05/12] fpga: enable secure updates Russ Weight
2020-09-05 22:04   ` Tom Rix
     [not found]     ` <1d90bfb6-417c-55df-9290-991c391158a9@intel.com>
2020-09-20 15:24       ` Tom Rix
2020-09-04 23:52 ` [PATCH v1 06/12] fpga: add max10 secure update functions Russ Weight
2020-09-06 16:10   ` Tom Rix
2020-09-22  1:15     ` Russ Weight
2020-09-08  8:05   ` Lee Jones
2020-09-04 23:53 ` [PATCH v1 07/12] fpga: expose sec-mgr update status Russ Weight
2020-09-06 16:16   ` Tom Rix
2020-09-22 22:31     ` Russ Weight
2020-09-04 23:53 ` [PATCH v1 08/12] fpga: expose sec-mgr update errors Russ Weight
2020-09-06 16:27   ` Tom Rix
2020-09-22 23:42     ` Russ Weight
2020-09-23 12:52       ` Tom Rix
2020-09-04 23:53 ` [PATCH v1 09/12] fpga: expose sec-mgr update size Russ Weight
2020-09-06 16:39   ` Tom Rix
2020-09-04 23:53 ` [PATCH v1 10/12] fpga: enable sec-mgr update cancel Russ Weight
2020-09-06 17:00   ` Tom Rix
     [not found]     ` <678f8d39-a244-42d0-4c56-91eb859b43f0@intel.com>
2020-09-23 13:02       ` Tom Rix
2020-09-04 23:53 ` [PATCH v1 11/12] fpga: expose hardware error info in sysfs Russ Weight
2020-09-06 17:06   ` Tom Rix
2020-09-04 23:53 ` [PATCH v1 12/12] fpga: add max10 get_hw_errinfo callback func Russ Weight
2020-09-06 17:14   ` Tom Rix
2020-09-24 21:48     ` Russ Weight
2020-09-05 14:13 ` [PATCH v1 00/12] Intel FPGA Security Manager Class Driver Wu, Hao
2020-10-01 20:42   ` Russ Weight
2020-09-05 16:10 ` Tom Rix
2020-09-05 17:16 ` Tom Rix
2020-10-01  0:19   ` Russ Weight

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).