From patchwork Fri Sep 4 23:52:54 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russ Weight X-Patchwork-Id: 11758727 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 53681925 for ; Fri, 4 Sep 2020 23:54:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3364B208C7 for ; Fri, 4 Sep 2020 23:54:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728098AbgIDXxV (ORCPT ); Fri, 4 Sep 2020 19:53:21 -0400 Received: from mga06.intel.com ([134.134.136.31]:64693 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726317AbgIDXxQ (ORCPT ); Fri, 4 Sep 2020 19:53:16 -0400 IronPort-SDR: zwvtl0BSQfKgIA2Ket6v1uGdDXFyR9rmX1K1EgWDAvo6CwwU7HMVrpB9eFifpZl3tGFVY1qpES 0C6qL2gKI8yA== X-IronPort-AV: E=McAfee;i="6000,8403,9734"; a="219386183" X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="219386183" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Sep 2020 16:53:14 -0700 IronPort-SDR: aqsW3WlM7skxnnR+r/60bL8FBGA8BrdDxIQaiU1YKiPKjru629WYAI+4XTTUK9Iq0QOjUOv1b1 Y07LK9gJGOiA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="284656176" Received: from rhweight-mobl2.amr.corp.intel.com (HELO rhweight-mobl2.ra.intel.com) ([10.251.151.80]) by fmsmga008.fm.intel.com with ESMTP; 04 Sep 2020 16:53:13 -0700 From: Russ Weight To: mdf@kernel.org, lee.jones@linaro.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Cc: trix@redhat.com, lgoncalv@redhat.com, yilun.xu@intel.com, hao.wu@intel.com, matthew.gerlach@intel.com, Russ Weight Subject: [PATCH v1 01/12] fpga: fpga security manager class driver Date: Fri, 4 Sep 2020 16:52:54 -0700 Message-Id: <20200904235305.6254-2-russell.h.weight@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200904235305.6254-1-russell.h.weight@intel.com> References: <20200904235305.6254-1-russell.h.weight@intel.com> Sender: linux-fpga-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org 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 Signed-off-by: Xu Yilun --- .../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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 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 +#include +#include +#include +#include + +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 +#include +#include + +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 From patchwork Fri Sep 4 23:52:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russ Weight X-Patchwork-Id: 11758711 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C108914F9 for ; Fri, 4 Sep 2020 23:53:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AD14B2098B for ; Fri, 4 Sep 2020 23:53:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727860AbgIDXxV (ORCPT ); Fri, 4 Sep 2020 19:53:21 -0400 Received: from mga06.intel.com ([134.134.136.31]:64696 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726329AbgIDXxQ (ORCPT ); Fri, 4 Sep 2020 19:53:16 -0400 IronPort-SDR: 0JdLOLG0rQzYBXQ7mLx49JDfVBB4xopStNIBhxgAsc/K+T2+jLlonsCP3CEtIaw/2Gs21LI+R9 QrHzoue1mZaA== X-IronPort-AV: E=McAfee;i="6000,8403,9734"; a="219386186" X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="219386186" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Sep 2020 16:53:15 -0700 IronPort-SDR: K6eKWnuH+blU+JdV4qRU3V1B1PsmQEizpg4Sni9tr/6+8ql70QjC0wYqC7oaAT1Zl7MzgQXzWo j3BeHeOO7JRQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="284656197" Received: from rhweight-mobl2.amr.corp.intel.com (HELO rhweight-mobl2.ra.intel.com) ([10.251.151.80]) by fmsmga008.fm.intel.com with ESMTP; 04 Sep 2020 16:53:14 -0700 From: Russ Weight To: mdf@kernel.org, lee.jones@linaro.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Cc: trix@redhat.com, lgoncalv@redhat.com, yilun.xu@intel.com, hao.wu@intel.com, matthew.gerlach@intel.com, Russ Weight Subject: [PATCH v1 02/12] fpga: create intel max10 bmc security engine Date: Fri, 4 Sep 2020 16:52:55 -0700 Message-Id: <20200904235305.6254-3-russell.h.weight@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200904235305.6254-1-russell.h.weight@intel.com> References: <20200904235305.6254-1-russell.h.weight@intel.com> Sender: linux-fpga-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org 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 Reviewed-by: Wu Hao --- 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 +#include +#include +#include +#include +#include + +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) From patchwork Fri Sep 4 23:52:56 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russ Weight X-Patchwork-Id: 11758731 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3B28914F9 for ; Fri, 4 Sep 2020 23:54:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 298D0208C7 for ; Fri, 4 Sep 2020 23:54:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728350AbgIDXyD (ORCPT ); Fri, 4 Sep 2020 19:54:03 -0400 Received: from mga06.intel.com ([134.134.136.31]:64701 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727800AbgIDXxR (ORCPT ); Fri, 4 Sep 2020 19:53:17 -0400 IronPort-SDR: wXZzE7G/Cfs3my7w763kKgrOWbnA0VjtAJYMHaT/36iIV6xW5xxf3EOsJAu+LI6rnWmQwNiijr 8ZDpATMneUMA== X-IronPort-AV: E=McAfee;i="6000,8403,9734"; a="219386190" X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="219386190" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Sep 2020 16:53:15 -0700 IronPort-SDR: 7uAvyzgKfXtYLIKsTQnUbnhvYtRNTXkDlnIRQIqmSAufRqNMrgaSuZw3kV3pnSu4vTTExlNrS0 55/i2LEGnssw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="284656204" Received: from rhweight-mobl2.amr.corp.intel.com (HELO rhweight-mobl2.ra.intel.com) ([10.251.151.80]) by fmsmga008.fm.intel.com with ESMTP; 04 Sep 2020 16:53:15 -0700 From: Russ Weight To: mdf@kernel.org, lee.jones@linaro.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Cc: trix@redhat.com, lgoncalv@redhat.com, yilun.xu@intel.com, hao.wu@intel.com, matthew.gerlach@intel.com, Russ Weight Subject: [PATCH v1 03/12] fpga: expose max10 flash update counts in sysfs Date: Fri, 4 Sep 2020 16:52:56 -0700 Message-Id: <20200904235305.6254-4-russell.h.weight@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200904235305.6254-1-russell.h.weight@intel.com> References: <20200904235305.6254-1-russell.h.weight@intel.com> Sender: linux-fpga-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org 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 Reviewed-by: Wu Hao --- 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 #include #include +#include #include 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, From patchwork Fri Sep 4 23:52:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russ Weight X-Patchwork-Id: 11758729 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7B746925 for ; Fri, 4 Sep 2020 23:54:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6BE6A208C7 for ; Fri, 4 Sep 2020 23:54:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728355AbgIDXyD (ORCPT ); Fri, 4 Sep 2020 19:54:03 -0400 Received: from mga06.intel.com ([134.134.136.31]:64696 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726277AbgIDXxT (ORCPT ); Fri, 4 Sep 2020 19:53:19 -0400 IronPort-SDR: KVRTl1KTa+AfHSdVnyDc+TY5rlGqVncyNBjqW4ptBCJgqmpIDP3/5f1DmyCK8MMlZC0LDQROK4 G+xmUPNPoV5A== X-IronPort-AV: E=McAfee;i="6000,8403,9734"; a="219386192" X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="219386192" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Sep 2020 16:53:16 -0700 IronPort-SDR: YLqLc/x7mHM0QumtFzNG/L8YGrZeq3wayJFuQry1c5Y+sZ2K2flDetyBWcgOmFOE4bkfpM14Db +D0QjgpS89HA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="284656215" Received: from rhweight-mobl2.amr.corp.intel.com (HELO rhweight-mobl2.ra.intel.com) ([10.251.151.80]) by fmsmga008.fm.intel.com with ESMTP; 04 Sep 2020 16:53:15 -0700 From: Russ Weight To: mdf@kernel.org, lee.jones@linaro.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Cc: trix@redhat.com, lgoncalv@redhat.com, yilun.xu@intel.com, hao.wu@intel.com, matthew.gerlach@intel.com, Russ Weight Subject: [PATCH v1 04/12] fpga: expose max10 canceled keys in sysfs Date: Fri, 4 Sep 2020 16:52:57 -0700 Message-Id: <20200904235305.6254-5-russell.h.weight@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200904235305.6254-1-russell.h.weight@intel.com> References: <20200904235305.6254-1-russell.h.weight@intel.com> Sender: linux-fpga-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org 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 Reviewed-by: Wu Hao --- 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) From patchwork Fri Sep 4 23:52:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russ Weight X-Patchwork-Id: 11758733 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5E1761599 for ; Fri, 4 Sep 2020 23:54:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 45CC7208C7 for ; Fri, 4 Sep 2020 23:54:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728186AbgIDXyC (ORCPT ); Fri, 4 Sep 2020 19:54:02 -0400 Received: from mga06.intel.com ([134.134.136.31]:64693 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727850AbgIDXxU (ORCPT ); Fri, 4 Sep 2020 19:53:20 -0400 IronPort-SDR: eTESmrBVDjMzhr13HTaRK/UI7syTQKAX2Pi6LtEs2UwZ2M4WhJdsaINI7JGwkCml6bRDO3wMLR 7jNaOWD7JSVg== X-IronPort-AV: E=McAfee;i="6000,8403,9734"; a="219386197" X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="219386197" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Sep 2020 16:53:16 -0700 IronPort-SDR: IXIpG2xGps7cqalhDoYKLPdNQgPPziug+tNnnl9aQEqvYYGoM5iSRhlfOTxT3DReAQNruUbL8v FXTF67OQBCCg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="284656248" Received: from rhweight-mobl2.amr.corp.intel.com (HELO rhweight-mobl2.ra.intel.com) ([10.251.151.80]) by fmsmga008.fm.intel.com with ESMTP; 04 Sep 2020 16:53:16 -0700 From: Russ Weight To: mdf@kernel.org, lee.jones@linaro.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Cc: trix@redhat.com, lgoncalv@redhat.com, yilun.xu@intel.com, hao.wu@intel.com, matthew.gerlach@intel.com, Russ Weight Subject: [PATCH v1 05/12] fpga: enable secure updates Date: Fri, 4 Sep 2020 16:52:58 -0700 Message-Id: <20200904235305.6254-6-russell.h.weight@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200904235305.6254-1-russell.h.weight@intel.com> References: <20200904235305.6254-1-russell.h.weight@intel.com> Sender: linux-fpga-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org 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 --- .../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 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 +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 +#include #include #include +#include #include #include #include @@ -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 #include #include #include @@ -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; }; From patchwork Fri Sep 4 23:52:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russ Weight X-Patchwork-Id: 11758725 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B796E1599 for ; Fri, 4 Sep 2020 23:54:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A2B9521481 for ; Fri, 4 Sep 2020 23:54:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728161AbgIDXxW (ORCPT ); Fri, 4 Sep 2020 19:53:22 -0400 Received: from mga06.intel.com ([134.134.136.31]:64701 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727921AbgIDXxV (ORCPT ); Fri, 4 Sep 2020 19:53:21 -0400 IronPort-SDR: MDaT43Bplui3l5DD8ZNzh4AQDhzZe9rdo9FNDFl1Dq0aQv6EnMwczM1ayv0SGGJs7h3YLsHTeR u4Jw5rLo4T7w== X-IronPort-AV: E=McAfee;i="6000,8403,9734"; a="219386201" X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="219386201" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Sep 2020 16:53:17 -0700 IronPort-SDR: fhyzUpk1ZvkCpEQ5TCleISxf0+ekzBMUHelbwy91GaoPiLNjYZBCeVYrWxuWk9xXmDgNjGLjxH 881thOodun8A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="284656291" Received: from rhweight-mobl2.amr.corp.intel.com (HELO rhweight-mobl2.ra.intel.com) ([10.251.151.80]) by fmsmga008.fm.intel.com with ESMTP; 04 Sep 2020 16:53:16 -0700 From: Russ Weight To: mdf@kernel.org, lee.jones@linaro.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Cc: trix@redhat.com, lgoncalv@redhat.com, yilun.xu@intel.com, hao.wu@intel.com, matthew.gerlach@intel.com, Russ Weight Subject: [PATCH v1 06/12] fpga: add max10 secure update functions Date: Fri, 4 Sep 2020 16:52:59 -0700 Message-Id: <20200904235305.6254-7-russell.h.weight@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200904235305.6254-1-russell.h.weight@intel.com> References: <20200904235305.6254-1-russell.h.weight@intel.com> Sender: linux-fpga-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org 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 Reviewed-by: Wu Hao --- 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 #include #include #include @@ -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 */ From patchwork Fri Sep 4 23:53:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russ Weight X-Patchwork-Id: 11758723 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7A8D614F9 for ; Fri, 4 Sep 2020 23:54:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6A5FD208C7 for ; Fri, 4 Sep 2020 23:54:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728323AbgIDXxx (ORCPT ); Fri, 4 Sep 2020 19:53:53 -0400 Received: from mga06.intel.com ([134.134.136.31]:64696 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727986AbgIDXxW (ORCPT ); Fri, 4 Sep 2020 19:53:22 -0400 IronPort-SDR: 1YX5vJfTKfFfiqrzel1W/JioLSrHhlJx80LzFe5u7pgZ4i4gxpg/DXFwLuK4Y1Eiu6Bh2qqeE4 BzuEZ13RkQCg== X-IronPort-AV: E=McAfee;i="6000,8403,9734"; a="219386204" X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="219386204" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Sep 2020 16:53:18 -0700 IronPort-SDR: 8e6BVrpMDBtTw+YGicNcmBo8lnTKNNODJYoY1X9YATr8Exb0YVbuHJggiwA1bjWLsXrFBeWrzE RCJ4r4ouHI3A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="284656352" Received: from rhweight-mobl2.amr.corp.intel.com (HELO rhweight-mobl2.ra.intel.com) ([10.251.151.80]) by fmsmga008.fm.intel.com with ESMTP; 04 Sep 2020 16:53:17 -0700 From: Russ Weight To: mdf@kernel.org, lee.jones@linaro.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Cc: trix@redhat.com, lgoncalv@redhat.com, yilun.xu@intel.com, hao.wu@intel.com, matthew.gerlach@intel.com, Russ Weight Subject: [PATCH v1 07/12] fpga: expose sec-mgr update status Date: Fri, 4 Sep 2020 16:53:00 -0700 Message-Id: <20200904235305.6254-8-russell.h.weight@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200904235305.6254-1-russell.h.weight@intel.com> References: <20200904235305.6254-1-russell.h.weight@intel.com> Sender: linux-fpga-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org 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 Reviewed-by: Wu Hao --- .../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 +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, }; From patchwork Fri Sep 4 23:53:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russ Weight X-Patchwork-Id: 11758719 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E470014F9 for ; Fri, 4 Sep 2020 23:53:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CE241206CB for ; Fri, 4 Sep 2020 23:53:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728217AbgIDXxY (ORCPT ); Fri, 4 Sep 2020 19:53:24 -0400 Received: from mga06.intel.com ([134.134.136.31]:64693 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728061AbgIDXxW (ORCPT ); Fri, 4 Sep 2020 19:53:22 -0400 IronPort-SDR: McjwtTfm3hGIpYUljXiE/7wasTv9CuXDhHF1BZ6fE4dp45ufrin09zkyli0lmzSRDeb8jCqbsh SHwLAlVJKz1Q== X-IronPort-AV: E=McAfee;i="6000,8403,9734"; a="219386208" X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="219386208" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Sep 2020 16:53:18 -0700 IronPort-SDR: E4E5py9oYGWaclhQ5c1YshgaVenKA6bg91R109QKJhWzraxuW0Wxzy6Kw8DB49x+xNC2v3sMhC f4jwXSoXv1QQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="284656400" Received: from rhweight-mobl2.amr.corp.intel.com (HELO rhweight-mobl2.ra.intel.com) ([10.251.151.80]) by fmsmga008.fm.intel.com with ESMTP; 04 Sep 2020 16:53:18 -0700 From: Russ Weight To: mdf@kernel.org, lee.jones@linaro.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Cc: trix@redhat.com, lgoncalv@redhat.com, yilun.xu@intel.com, hao.wu@intel.com, matthew.gerlach@intel.com, Russ Weight Subject: [PATCH v1 08/12] fpga: expose sec-mgr update errors Date: Fri, 4 Sep 2020 16:53:01 -0700 Message-Id: <20200904235305.6254-9-russell.h.weight@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200904235305.6254-1-russell.h.weight@intel.com> References: <20200904235305.6254-1-russell.h.weight@intel.com> Sender: linux-fpga-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org 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 Reviewed-by: Wu Hao --- .../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 +Description: Read-only. Returns a string describing the failure + of a secure update. This string will be in the form + of :, where will be one of + the status strings described for the status sysfs + file and 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; From patchwork Fri Sep 4 23:53:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russ Weight X-Patchwork-Id: 11758721 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3B6CB925 for ; Fri, 4 Sep 2020 23:53:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2C288208C7 for ; Fri, 4 Sep 2020 23:53:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728326AbgIDXxx (ORCPT ); Fri, 4 Sep 2020 19:53:53 -0400 Received: from mga06.intel.com ([134.134.136.31]:64701 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728140AbgIDXxW (ORCPT ); Fri, 4 Sep 2020 19:53:22 -0400 IronPort-SDR: doP+68r8rgUHiqkTlLIKyXDHSIc0o/wMYYCgPJ+9Blgky4T1XmdO39kIBVJ+KM7/f9+zxpzRox xobsD8KGzwxw== X-IronPort-AV: E=McAfee;i="6000,8403,9734"; a="219386211" X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="219386211" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Sep 2020 16:53:19 -0700 IronPort-SDR: Gz2Iu1HvC9zc10GPl92UMGLimuHP7T6K2IGDJelknZg+t6pCwhI37rnZyCH3L9sP7Y8C8TRtd+ /5dNMnGjya6A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="284656440" Received: from rhweight-mobl2.amr.corp.intel.com (HELO rhweight-mobl2.ra.intel.com) ([10.251.151.80]) by fmsmga008.fm.intel.com with ESMTP; 04 Sep 2020 16:53:18 -0700 From: Russ Weight To: mdf@kernel.org, lee.jones@linaro.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Cc: trix@redhat.com, lgoncalv@redhat.com, yilun.xu@intel.com, hao.wu@intel.com, matthew.gerlach@intel.com, Russ Weight Subject: [PATCH v1 09/12] fpga: expose sec-mgr update size Date: Fri, 4 Sep 2020 16:53:02 -0700 Message-Id: <20200904235305.6254-10-russell.h.weight@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200904235305.6254-1-russell.h.weight@intel.com> References: <20200904235305.6254-1-russell.h.weight@intel.com> Sender: linux-fpga-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org 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 Reviewed-by: Wu Hao Reviewed-by: Tom Rix --- 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 +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, }; From patchwork Fri Sep 4 23:53:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russ Weight X-Patchwork-Id: 11758717 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B20241599 for ; Fri, 4 Sep 2020 23:53:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A340220FC3 for ; Fri, 4 Sep 2020 23:53:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728258AbgIDXx3 (ORCPT ); Fri, 4 Sep 2020 19:53:29 -0400 Received: from mga06.intel.com ([134.134.136.31]:64693 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728197AbgIDXxY (ORCPT ); Fri, 4 Sep 2020 19:53:24 -0400 IronPort-SDR: D330fQ94ovp7BUPR+pLzR3n/rc+OS5KGYLURUeemmAmRwwT4i/OLLu3f3P2WyFqLa9qVTv1O7N wryHb6lKpupw== X-IronPort-AV: E=McAfee;i="6000,8403,9734"; a="219386215" X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="219386215" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Sep 2020 16:53:19 -0700 IronPort-SDR: WLbPsB2SjpX7rtkaXev1/3oqiLUThGZrGNA2osd6bG/2LvHss3+AzGUdjXLAnTmqgqpdO/cBae W6Zx07x+aDCA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="284656510" Received: from rhweight-mobl2.amr.corp.intel.com (HELO rhweight-mobl2.ra.intel.com) ([10.251.151.80]) by fmsmga008.fm.intel.com with ESMTP; 04 Sep 2020 16:53:19 -0700 From: Russ Weight To: mdf@kernel.org, lee.jones@linaro.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Cc: trix@redhat.com, lgoncalv@redhat.com, yilun.xu@intel.com, hao.wu@intel.com, matthew.gerlach@intel.com, Russ Weight Subject: [PATCH v1 10/12] fpga: enable sec-mgr update cancel Date: Fri, 4 Sep 2020 16:53:03 -0700 Message-Id: <20200904235305.6254-11-russell.h.weight@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200904235305.6254-1-russell.h.weight@intel.com> References: <20200904235305.6254-1-russell.h.weight@intel.com> Sender: linux-fpga-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org 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 --- .../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 +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; }; From patchwork Fri Sep 4 23:53:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russ Weight X-Patchwork-Id: 11758715 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 95662925 for ; Fri, 4 Sep 2020 23:53:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8353120DD4 for ; Fri, 4 Sep 2020 23:53:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728253AbgIDXx3 (ORCPT ); Fri, 4 Sep 2020 19:53:29 -0400 Received: from mga06.intel.com ([134.134.136.31]:64701 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728202AbgIDXxZ (ORCPT ); Fri, 4 Sep 2020 19:53:25 -0400 IronPort-SDR: vbKgI5QBrK1xcRb1Y1BrWCCxPObzmjGASKbkwEkrT+GMtIMjauRQ8PbqvYZ5hG5mEKtvg2WkAc jObqDbebUbCw== X-IronPort-AV: E=McAfee;i="6000,8403,9734"; a="219386217" X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="219386217" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Sep 2020 16:53:20 -0700 IronPort-SDR: CJf/Vfunu4BGZuqI1xOJKfWDJCi/HxKZlKc0vg6+QswWanXRnNguakxc0AeYKVeS1FF1sueeCb aHuM6xll6O8g== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="284656540" Received: from rhweight-mobl2.amr.corp.intel.com (HELO rhweight-mobl2.ra.intel.com) ([10.251.151.80]) by fmsmga008.fm.intel.com with ESMTP; 04 Sep 2020 16:53:19 -0700 From: Russ Weight To: mdf@kernel.org, lee.jones@linaro.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Cc: trix@redhat.com, lgoncalv@redhat.com, yilun.xu@intel.com, hao.wu@intel.com, matthew.gerlach@intel.com, Russ Weight Subject: [PATCH v1 11/12] fpga: expose hardware error info in sysfs Date: Fri, 4 Sep 2020 16:53:04 -0700 Message-Id: <20200904235305.6254-12-russell.h.weight@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200904235305.6254-1-russell.h.weight@intel.com> References: <20200904235305.6254-1-russell.h.weight@intel.com> Sender: linux-fpga-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org 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 Reviewed-by: Wu Hao Reviewed-by: Tom Rix --- .../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 +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; From patchwork Fri Sep 4 23:53:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russ Weight X-Patchwork-Id: 11758713 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E252A1599 for ; Fri, 4 Sep 2020 23:53:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CA62B206CB for ; Fri, 4 Sep 2020 23:53:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728241AbgIDXx2 (ORCPT ); Fri, 4 Sep 2020 19:53:28 -0400 Received: from mga06.intel.com ([134.134.136.31]:64696 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728210AbgIDXxY (ORCPT ); Fri, 4 Sep 2020 19:53:24 -0400 IronPort-SDR: QpNcjZNP9wvgadeR55Efh2M3kw9Ym1n3IJokRGpORpBp2R7s8h+EtsVxmyTwFeAjzxxw225Xqb P3cjMSoQJ2/w== X-IronPort-AV: E=McAfee;i="6000,8403,9734"; a="219386219" X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="219386219" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Sep 2020 16:53:20 -0700 IronPort-SDR: EMeUMxuTkHFBA2CB9KPJpLPRA22Udhc1zLg8PlndRF++SF0ck+vTnBM1M0otE0A5MPwIUa+fGO taflrfMea+ug== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,391,1592895600"; d="scan'208";a="284656595" Received: from rhweight-mobl2.amr.corp.intel.com (HELO rhweight-mobl2.ra.intel.com) ([10.251.151.80]) by fmsmga008.fm.intel.com with ESMTP; 04 Sep 2020 16:53:20 -0700 From: Russ Weight To: mdf@kernel.org, lee.jones@linaro.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Cc: trix@redhat.com, lgoncalv@redhat.com, yilun.xu@intel.com, hao.wu@intel.com, matthew.gerlach@intel.com, Russ Weight Subject: [PATCH v1 12/12] fpga: add max10 get_hw_errinfo callback func Date: Fri, 4 Sep 2020 16:53:05 -0700 Message-Id: <20200904235305.6254-13-russell.h.weight@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200904235305.6254-1-russell.h.weight@intel.com> References: <20200904235305.6254-1-russell.h.weight@intel.com> Sender: linux-fpga-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org 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 Reviewed-by: Wu Hao --- 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)