From patchwork Mon May 17 02:31:49 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Moritz Fischer X-Patchwork-Id: 12260777 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.0 required=3.0 tests=BAYES_00,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3520FC433B4 for ; Mon, 17 May 2021 02:32:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0AF20611CB for ; Mon, 17 May 2021 02:32:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233187AbhEQCeB (ORCPT ); Sun, 16 May 2021 22:34:01 -0400 Received: from mail-pg1-f181.google.com ([209.85.215.181]:38679 "EHLO mail-pg1-f181.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230104AbhEQCeB (ORCPT ); Sun, 16 May 2021 22:34:01 -0400 Received: by mail-pg1-f181.google.com with SMTP id 6so3630117pgk.5 for ; Sun, 16 May 2021 19:32:46 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=k57gZ29SV/KR0zdC2Ie93XnRc0lvguGCXFLVY5QtoJo=; b=Z+ITKdweth04UcvLYlJJgH2bkFG3dBBi5iGsD0cFjOYX3Mx8s8yDq4/pL2jFxYu2B/ WHk3dHxfgcpt54RBJG04C9ecUA6yBUWwfxjPh6cRijW6dkB4bjWXOIdbiMWgKMWVR17O LbUpTMoLU5EciKldpenv+hRfW9NzQeWfP9LhVoT36CvgVnwHtGBM8tN82wKBsK+XbCjy l9+se2aI/6sOEgycEtDa+dnBuUUtcTseHKgY6X87mEG4NpOzBKf54uJyjWnF9geL/Y7a /o4Xf9ufoOmzQSu3X3ucocfEiSXk4GbwgI7Dw2Y+/alo5htdp558QsOSe+SrKuimHJSr EPdw== X-Gm-Message-State: AOAM533P5iAQFmIctVRFWruG3w8TiQjVvEYoz5ALuPumY65LIFE50AP6 A3A/eCK9fCG4rTVWOUvAmcw= X-Google-Smtp-Source: ABdhPJzBhnUuQV/d6rH5s1htSL5iASeShfinvkRHuIEcyiXSwRp4e3uf/W2e9bOV9RavPah+Wn2UWg== X-Received: by 2002:aa7:96ea:0:b029:28c:e131:f0f with SMTP id i10-20020aa796ea0000b029028ce1310f0fmr57964893pfq.11.1621218765863; Sun, 16 May 2021 19:32:45 -0700 (PDT) Received: from localhost ([2601:647:5b00:1161:a4cc:eef9:fbc0:2781]) by smtp.gmail.com with ESMTPSA id 85sm8823421pge.92.2021.05.16.19.32.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 May 2021 19:32:45 -0700 (PDT) From: Moritz Fischer To: gregkh@linuxfoundation.org Cc: linux-fpga@vger.kernel.org, moritzf@google.com, Moritz Fischer , Russ Weight , Xu Yilun , Tom Rix Subject: [PATCH 01/12] fpga: sec-mgr: fpga security manager class driver Date: Sun, 16 May 2021 19:31:49 -0700 Message-Id: <20210517023200.52707-2-mdf@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210517023200.52707-1-mdf@kernel.org> References: <20210517023200.52707-1-mdf@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org From: Russ Weight Create the FPGA 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. The image type is encoded in the image file and is decoded by the HW/FW secure update engine. Signed-off-by: Russ Weight Signed-off-by: Xu Yilun Reviewed-by: Tom Rix Signed-off-by: Moritz Fischer --- .../ABI/testing/sysfs-class-fpga-sec-mgr | 5 + Documentation/fpga/fpga-sec-mgr.rst | 44 +++ Documentation/fpga/index.rst | 1 + MAINTAINERS | 9 + drivers/fpga/Kconfig | 9 + drivers/fpga/Makefile | 3 + drivers/fpga/fpga-sec-mgr.c | 296 ++++++++++++++++++ include/linux/fpga/fpga-sec-mgr.h | 44 +++ 8 files changed, 411 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-class-fpga-sec-mgr create mode 100644 Documentation/fpga/fpga-sec-mgr.rst create mode 100644 drivers/fpga/fpga-sec-mgr.c create mode 100644 include/linux/fpga/fpga-sec-mgr.h diff --git a/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr new file mode 100644 index 000000000000..2498aef0ac51 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr @@ -0,0 +1,5 @@ +What: /sys/class/fpga_sec_mgr/fpga_secX/name +Date: June 2021 +KernelVersion: 5.14 +Contact: Russ Weight +Description: Name of low level fpga security manager driver. diff --git a/Documentation/fpga/fpga-sec-mgr.rst b/Documentation/fpga/fpga-sec-mgr.rst new file mode 100644 index 000000000000..9f74c29fe63d --- /dev/null +++ b/Documentation/fpga/fpga-sec-mgr.rst @@ -0,0 +1,44 @@ +.. SPDX-License-Identifier: GPL-2.0 + +======================================== +FPGA Security Manager Class Driver +======================================== + +The FPGA Security Manager class driver provides a common +API for user-space tools to manage updates for secure FPGA +devices. Device drivers that instantiate the Security +Manager class driver will interact with a HW secure update +engine in order to transfer new FPGA and BMC images to FLASH so +that they will be automatically loaded when the FPGA card reboots. + +A significant difference between the FPGA Manager and the FPGA +Security Manager is that the FPGA Manager does a live update (Partial +Reconfiguration) to a device, whereas the FPGA Security Manager +updates the FLASH images for the Static Region and the BMC so that +they will be loaded the next time the FPGA card boots. Security is +enforced by hardware and firmware. The security manager interacts +with the firmware to initiate an update, pass in the necessary data, +and collect status on the update. + +In addition to managing secure updates of the FPGA and BMC images, +the FPGA Security Manager update process may also be used to +program root entry hashes and cancellation keys for the FPGA static +region, the FPGA partial reconfiguration region, and the BMC. + +Secure updates make use of the request_firmware framework, which +requires that image files are accessible under /lib/firmware. A request +for a secure update returns immediately, while the update itself +proceeds in the context of a kernel worker thread. Sysfs files provide +a means for monitoring the progress of a secure update and for +retrieving error information in the event of a failure. + +Sysfs Attributes +================ + +The API includes a sysfs entry *name* to export the name of the parent +driver. It also includes an *update* sub-directory that can be used to +instantiate and monitor a secure update. + +See `<../ABI/testing/sysfs-class-fpga-sec-mgr>`__ for a full +description of the sysfs attributes for the FPGA Security +Manager. diff --git a/Documentation/fpga/index.rst b/Documentation/fpga/index.rst index f80f95667ca2..0b2f427042af 100644 --- a/Documentation/fpga/index.rst +++ b/Documentation/fpga/index.rst @@ -8,6 +8,7 @@ fpga :maxdepth: 1 dfl + fpga-sec-mgr .. only:: subproject and html diff --git a/MAINTAINERS b/MAINTAINERS index bd7aff0c120f..ac81adcd8579 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7136,6 +7136,15 @@ F: Documentation/fpga/ F: drivers/fpga/ F: include/linux/fpga/ +FPGA SECURITY MANAGER DRIVERS +M: Russ Weight +L: linux-fpga@vger.kernel.org +S: Maintained +F: Documentation/ABI/testing/sysfs-class-fpga-sec-mgr +F: Documentation/fpga/fpga-sec-mgr.rst +F: drivers/fpga/fpga-sec-mgr.c +F: include/linux/fpga/fpga-sec-mgr.h + FPU EMULATOR M: Bill Metzenthen S: Maintained diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 33e15058d0dc..09a8d915db26 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -234,4 +234,13 @@ config FPGA_MGR_ZYNQMP_FPGA to configure the programmable logic(PL) through PS on ZynqMP SoC. +config FPGA_SEC_MGR + tristate "FPGA Security Manager" + help + The Security Manager class driver presents a common + user API for managing secure updates for 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 18dc9885883a..22576d1a3996 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 +# FPGA Security Manager Framework +obj-$(CONFIG_FPGA_SEC_MGR) += fpga-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/fpga-sec-mgr.c b/drivers/fpga/fpga-sec-mgr.c new file mode 100644 index 000000000000..468379e0c825 --- /dev/null +++ b/drivers/fpga/fpga-sec-mgr.c @@ -0,0 +1,296 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * FPGA Security Manager + * + * Copyright (C) 2019-2020 Intel Corporation, Inc. + */ + +#include +#include +#include +#include +#include + +static DEFINE_IDA(fpga_sec_mgr_ida); +static struct class *fpga_sec_mgr_class; + +struct fpga_sec_mgr_devres { + struct fpga_sec_mgr *smgr; +}; + +#define to_sec_mgr(d) container_of(d, struct fpga_sec_mgr, dev) + +static ssize_t name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fpga_sec_mgr *smgr = to_sec_mgr(dev); + + return sysfs_emit(buf, "%s\n", smgr->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 *fpga_sec_mgr_attr_groups[] = { + &sec_mgr_attr_group, + NULL, +}; + +/** + * fpga_sec_mgr_create - create and initialize an FPGA + * security manager struct + * + * @dev: fpga security manager device from pdev + * @name: fpga security manager name + * @sops: pointer to a structure of fpga callback functions + * @priv: fpga security manager private data + * + * The caller of this function is responsible for freeing the struct + * with ifpg_sec_mgr_free(). Using devm_fpga_sec_mgr_create() instead + * is recommended. + * + * Return: pointer to struct fpga_sec_mgr or NULL + */ +struct fpga_sec_mgr * +fpga_sec_mgr_create(struct device *dev, const char *name, + const struct fpga_sec_mgr_ops *sops, void *priv) +{ + struct fpga_sec_mgr *smgr; + int id, ret; + + if (!name || !strlen(name)) { + dev_err(dev, "Attempt to register with no name!\n"); + return NULL; + } + + smgr = kzalloc(sizeof(*smgr), GFP_KERNEL); + if (!smgr) + return NULL; + + id = ida_simple_get(&fpga_sec_mgr_ida, 0, 0, GFP_KERNEL); + if (id < 0) + goto error_kfree; + + mutex_init(&smgr->lock); + + smgr->name = name; + smgr->priv = priv; + smgr->sops = sops; + + device_initialize(&smgr->dev); + smgr->dev.class = fpga_sec_mgr_class; + smgr->dev.parent = dev; + smgr->dev.id = id; + + ret = dev_set_name(&smgr->dev, "fpga_sec%d", id); + if (ret) { + dev_err(dev, "Failed to set device name: fpga_sec%d\n", id); + goto error_device; + } + + return smgr; + +error_device: + ida_simple_remove(&fpga_sec_mgr_ida, id); + +error_kfree: + kfree(smgr); + + return NULL; +} +EXPORT_SYMBOL_GPL(fpga_sec_mgr_create); + +/** + * fpga_sec_mgr_free - free an FPGA security manager created + * with fpga_sec_mgr_create() + * + * @smgr: FPGA security manager structure + */ +void fpga_sec_mgr_free(struct fpga_sec_mgr *smgr) +{ + ida_simple_remove(&fpga_sec_mgr_ida, smgr->dev.id); + kfree(smgr); +} +EXPORT_SYMBOL_GPL(fpga_sec_mgr_free); + +static void devm_fpga_sec_mgr_release(struct device *dev, void *res) +{ + struct fpga_sec_mgr_devres *dr = res; + + fpga_sec_mgr_free(dr->smgr); +} + +/** + * devm_fpga_sec_mgr_create - create and initialize an FPGA + * security manager struct + * + * @dev: fpga security manager device from pdev + * @name: fpga security manager name + * @sops: pointer to a structure of fpga callback functions + * @priv: fpga security manager private data + * + * This function is intended for use in a FPGA Security manager + * driver's probe function. After the security manager driver creates + * the fpga_sec_mgr struct with devm_fpga_sec_mgr_create(), it should + * register it with devm_fpga_sec_mgr_register(). + * The fpga_sec_mgr struct allocated with this function will be freed + * automatically on driver detach. + * + * Return: pointer to struct fpga_sec_mgr or NULL + */ +struct fpga_sec_mgr * +devm_fpga_sec_mgr_create(struct device *dev, const char *name, + const struct fpga_sec_mgr_ops *sops, void *priv) +{ + struct fpga_sec_mgr_devres *dr; + + dr = devres_alloc(devm_fpga_sec_mgr_release, sizeof(*dr), GFP_KERNEL); + if (!dr) + return NULL; + + dr->smgr = fpga_sec_mgr_create(dev, name, sops, priv); + if (!dr->smgr) { + devres_free(dr); + return NULL; + } + + devres_add(dev, dr); + + return dr->smgr; +} +EXPORT_SYMBOL_GPL(devm_fpga_sec_mgr_create); + +/** + * fpga_sec_mgr_register - register an FPGA security manager + * + * @smgr: fpga security manager struct + * + * Return: 0 on success, negative error code otherwise. + */ +int fpga_sec_mgr_register(struct fpga_sec_mgr *smgr) +{ + int ret; + + ret = device_add(&smgr->dev); + if (ret) + goto error_device; + + dev_info(&smgr->dev, "%s registered\n", smgr->name); + + return 0; + +error_device: + ida_simple_remove(&fpga_sec_mgr_ida, smgr->dev.id); + + return ret; +} +EXPORT_SYMBOL_GPL(fpga_sec_mgr_register); + +/** + * fpga_sec_mgr_unregister - unregister an FPGA security manager + * + * @mgr: fpga manager struct + * + * This function is intended for use in an FPGA security manager + * driver's remove() function. + */ +void fpga_sec_mgr_unregister(struct fpga_sec_mgr *smgr) +{ + dev_info(&smgr->dev, "%s %s\n", __func__, smgr->name); + + device_unregister(&smgr->dev); +} +EXPORT_SYMBOL_GPL(fpga_sec_mgr_unregister); + +static int fpga_sec_mgr_devres_match(struct device *dev, void *res, + void *match_data) +{ + struct fpga_sec_mgr_devres *dr = res; + + return match_data == dr->smgr; +} + +static void devm_fpga_sec_mgr_unregister(struct device *dev, void *res) +{ + struct fpga_sec_mgr_devres *dr = res; + + fpga_sec_mgr_unregister(dr->smgr); +} + +/** + * devm_fpga_sec_mgr_register - resource managed variant of + * fpga_sec_mgr_register() + * + * @dev: managing device for this FPGA security manager + * @smgr: fpga security manager struct + * + * This is the devres variant of fpga_sec_mgr_register() for which the + * unregister function will be called automatically when the managing + * device is detached. + */ +int devm_fpga_sec_mgr_register(struct device *dev, struct fpga_sec_mgr *smgr) +{ + struct fpga_sec_mgr_devres *dr; + int ret; + + /* + * Make sure that the struct fpga_sec_mgr * that is passed in is + * managed itself. + */ + if (WARN_ON(!devres_find(dev, devm_fpga_sec_mgr_release, + fpga_sec_mgr_devres_match, smgr))) + return -EINVAL; + + dr = devres_alloc(devm_fpga_sec_mgr_unregister, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + ret = fpga_sec_mgr_register(smgr); + if (ret) { + devres_free(dr); + return ret; + } + + dr->smgr = smgr; + devres_add(dev, dr); + + return 0; +} +EXPORT_SYMBOL_GPL(devm_fpga_sec_mgr_register); + +static void fpga_sec_mgr_dev_release(struct device *dev) +{ +} + +static int __init fpga_sec_mgr_class_init(void) +{ + pr_info("FPGA Security Manager\n"); + + fpga_sec_mgr_class = class_create(THIS_MODULE, "fpga_sec_mgr"); + if (IS_ERR(fpga_sec_mgr_class)) + return PTR_ERR(fpga_sec_mgr_class); + + fpga_sec_mgr_class->dev_groups = fpga_sec_mgr_attr_groups; + fpga_sec_mgr_class->dev_release = fpga_sec_mgr_dev_release; + + return 0; +} + +static void __exit fpga_sec_mgr_class_exit(void) +{ + class_destroy(fpga_sec_mgr_class); + ida_destroy(&fpga_sec_mgr_ida); +} + +MODULE_DESCRIPTION("FPGA Security Manager Driver"); +MODULE_LICENSE("GPL v2"); + +subsys_initcall(fpga_sec_mgr_class_init); +module_exit(fpga_sec_mgr_class_exit) diff --git a/include/linux/fpga/fpga-sec-mgr.h b/include/linux/fpga/fpga-sec-mgr.h new file mode 100644 index 000000000000..f85665b79b9d --- /dev/null +++ b/include/linux/fpga/fpga-sec-mgr.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Header file for FPGA Security Manager + * + * Copyright (C) 2019-2020 Intel Corporation, Inc. + */ +#ifndef _LINUX_FPGA_SEC_MGR_H +#define _LINUX_FPGA_SEC_MGR_H + +#include +#include +#include + +struct fpga_sec_mgr; + +/** + * struct fpga_sec_mgr_ops - device specific operations + */ +struct fpga_sec_mgr_ops { +}; + +struct fpga_sec_mgr { + const char *name; + struct device dev; + const struct fpga_sec_mgr_ops *sops; + struct mutex lock; /* protect data structure contents */ + void *priv; +}; + +struct fpga_sec_mgr * +fpga_sec_mgr_create(struct device *dev, const char *name, + const struct fpga_sec_mgr_ops *sops, void *priv); + +struct fpga_sec_mgr * +devm_fpga_sec_mgr_create(struct device *dev, const char *name, + const struct fpga_sec_mgr_ops *sops, void *priv); + +int fpga_sec_mgr_register(struct fpga_sec_mgr *smgr); +int devm_fpga_sec_mgr_register(struct device *dev, + struct fpga_sec_mgr *smgr); +void fpga_sec_mgr_unregister(struct fpga_sec_mgr *smgr); +void fpga_sec_mgr_free(struct fpga_sec_mgr *smgr); + +#endif From patchwork Mon May 17 02:31:50 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Moritz Fischer X-Patchwork-Id: 12260779 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.0 required=3.0 tests=BAYES_00,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4DD43C433ED for ; Mon, 17 May 2021 02:32:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 259C3611CB for ; Mon, 17 May 2021 02:32:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233188AbhEQCeE (ORCPT ); Sun, 16 May 2021 22:34:04 -0400 Received: from mail-pj1-f54.google.com ([209.85.216.54]:34675 "EHLO mail-pj1-f54.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230104AbhEQCeD (ORCPT ); Sun, 16 May 2021 22:34:03 -0400 Received: by mail-pj1-f54.google.com with SMTP id g6-20020a17090adac6b029015d1a9a6f1aso3719086pjx.1 for ; Sun, 16 May 2021 19:32:48 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=y9tMH+0TdOlsiQsiU+ZYlnbGJ4LNpI44bkuE11T9YTs=; b=p37d1cE8Xlz4+mghPbkUQfvm5TfG2fFVCfrJQiqdLpJ+WL1rYYLw4GKrIsSlBbY8KR bc17/uUmbptTvDu1x+8voSqTgwiDFeUlV1fOlLbTlsLahlAzgep57F9/FS13f6ykTx3m /AePOPH3hTctIATKJK7+w+xNfdG49Q12HK4ZQk/4WL+Y8YLxWg1x0zW4IWzZkZPhwj1f T6Q9Jw0ysS2hYKUhC3+ftCCEWiDEd79lk2vekUi6QJW3pc4Ndby8NI53z5Up7meBFmC2 W1VtgLI3BbSIcJLrYWVooi4rWS9M+Uv5+zUeouJyRbYEYAivBa0YrJshoxEd2ud12rGT tCCg== X-Gm-Message-State: AOAM5326NL4suHWKOAs2yYuvxnVvb1zf9+Dz/vBsL7UrOYhuQ8u+Cdgz 6lpGZmNgKKSfmyibEofevH4= X-Google-Smtp-Source: ABdhPJzVTzkBO6GZoU4iZuVKcRp5xt9nxnKXdQ9J5X5CSiOPsaD7I2oNNW8/AW38kFMc6oCNjZH9Aw== X-Received: by 2002:a17:90b:4386:: with SMTP id in6mr16297568pjb.160.1621218767712; Sun, 16 May 2021 19:32:47 -0700 (PDT) Received: from localhost ([2601:647:5b00:1161:a4cc:eef9:fbc0:2781]) by smtp.gmail.com with ESMTPSA id l14sm13308320pji.20.2021.05.16.19.32.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 May 2021 19:32:47 -0700 (PDT) From: Moritz Fischer To: gregkh@linuxfoundation.org Cc: linux-fpga@vger.kernel.org, moritzf@google.com, Moritz Fischer , Russ Weight , Tom Rix Subject: [PATCH 02/12] fpga: sec-mgr: enable secure updates Date: Sun, 16 May 2021 19:31:50 -0700 Message-Id: <20210517023200.52707-3-mdf@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210517023200.52707-1-mdf@kernel.org> References: <20210517023200.52707-1-mdf@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org From: Russ Weight Extend the FPGA Security Manager class driver to include an update/filename sysfs node that can be used to initiate a secure 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 Reviewed-by: Tom Rix Signed-off-by: Moritz Fischer --- .../ABI/testing/sysfs-class-fpga-sec-mgr | 13 ++ drivers/fpga/fpga-sec-mgr.c | 160 ++++++++++++++++++ include/linux/fpga/fpga-sec-mgr.h | 48 ++++++ 3 files changed, 221 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr index 2498aef0ac51..36d1b6ba8d76 100644 --- a/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr +++ b/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr @@ -3,3 +3,16 @@ Date: June 2021 KernelVersion: 5.14 Contact: Russ Weight Description: Name of low level fpga security manager driver. + +What: /sys/class/fpga_sec_mgr/fpga_secX/update/filename +Date: June 2021 +KernelVersion: 5.14 +Contact: Russ Weight +Description: Write only. Write the filename of an 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/fpga-sec-mgr.c b/drivers/fpga/fpga-sec-mgr.c index 468379e0c825..bfdb01d2de57 100644 --- a/drivers/fpga/fpga-sec-mgr.c +++ b/drivers/fpga/fpga-sec-mgr.c @@ -5,8 +5,11 @@ * Copyright (C) 2019-2020 Intel Corporation, Inc. */ +#include +#include #include #include +#include #include #include #include @@ -20,6 +23,132 @@ struct fpga_sec_mgr_devres { #define to_sec_mgr(d) container_of(d, struct fpga_sec_mgr, dev) +static void fpga_sec_dev_error(struct fpga_sec_mgr *smgr, + enum fpga_sec_err err_code) +{ + smgr->err_code = err_code; + smgr->sops->cancel(smgr); +} + +static void progress_complete(struct fpga_sec_mgr *smgr) +{ + mutex_lock(&smgr->lock); + smgr->progress = FPGA_SEC_PROG_IDLE; + complete_all(&smgr->update_done); + mutex_unlock(&smgr->lock); +} + +static void fpga_sec_mgr_update(struct work_struct *work) +{ + struct fpga_sec_mgr *smgr; + const struct firmware *fw; + enum fpga_sec_err ret; + u32 offset = 0; + + smgr = container_of(work, struct fpga_sec_mgr, work); + + get_device(&smgr->dev); + if (request_firmware(&fw, smgr->filename, &smgr->dev)) { + smgr->err_code = FPGA_SEC_ERR_FILE_READ; + goto idle_exit; + } + + smgr->data = fw->data; + smgr->remaining_size = fw->size; + + if (!try_module_get(smgr->dev.parent->driver->owner)) { + smgr->err_code = FPGA_SEC_ERR_BUSY; + goto release_fw_exit; + } + + smgr->progress = FPGA_SEC_PROG_PREPARING; + ret = smgr->sops->prepare(smgr); + if (ret != FPGA_SEC_ERR_NONE) { + fpga_sec_dev_error(smgr, ret); + goto modput_exit; + } + + smgr->progress = FPGA_SEC_PROG_WRITING; + while (smgr->remaining_size) { + ret = smgr->sops->write_blk(smgr, offset); + if (ret != FPGA_SEC_ERR_NONE) { + fpga_sec_dev_error(smgr, ret); + goto done; + } + + offset = fw->size - smgr->remaining_size; + } + + smgr->progress = FPGA_SEC_PROG_PROGRAMMING; + ret = smgr->sops->poll_complete(smgr); + if (ret != FPGA_SEC_ERR_NONE) + fpga_sec_dev_error(smgr, ret); + +done: + if (smgr->sops->cleanup) + smgr->sops->cleanup(smgr); + +modput_exit: + module_put(smgr->dev.parent->driver->owner); + +release_fw_exit: + smgr->data = NULL; + release_firmware(fw); + +idle_exit: + /* + * Note: smgr->remaining_size is left unmodified here to + * provide additional information on errors. It will be + * reinitialized when the next secure update begins. + */ + kfree(smgr->filename); + smgr->filename = NULL; + put_device(&smgr->dev); + progress_complete(smgr); +} + +static ssize_t filename_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fpga_sec_mgr *smgr = to_sec_mgr(dev); + int ret = count; + + if (!count || count >= PATH_MAX) + return -EINVAL; + + mutex_lock(&smgr->lock); + if (smgr->driver_unload || smgr->progress != FPGA_SEC_PROG_IDLE) { + ret = -EBUSY; + goto unlock_exit; + } + + smgr->filename = kmemdup_nul(buf, count, GFP_KERNEL); + if (!smgr->filename) { + ret = -ENOMEM; + goto unlock_exit; + } + + smgr->err_code = FPGA_SEC_ERR_NONE; + smgr->progress = FPGA_SEC_PROG_READING; + reinit_completion(&smgr->update_done); + schedule_work(&smgr->work); + +unlock_exit: + mutex_unlock(&smgr->lock); + return ret; +} +static DEVICE_ATTR_WO(filename); + +static struct attribute *sec_mgr_update_attrs[] = { + &dev_attr_filename.attr, + NULL, +}; + +static struct attribute_group sec_mgr_update_attr_group = { + .name = "update", + .attrs = sec_mgr_update_attrs, +}; + static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -40,6 +169,7 @@ static struct attribute_group sec_mgr_attr_group = { static const struct attribute_group *fpga_sec_mgr_attr_groups[] = { &sec_mgr_attr_group, + &sec_mgr_update_attr_group, NULL, }; @@ -65,6 +195,12 @@ fpga_sec_mgr_create(struct device *dev, const char *name, struct fpga_sec_mgr *smgr; int id, ret; + if (!sops || !sops->cancel || !sops->prepare || + !sops->write_blk || !sops->poll_complete) { + dev_err(dev, "Attempt to register without all required ops\n"); + return NULL; + } + if (!name || !strlen(name)) { dev_err(dev, "Attempt to register with no name!\n"); return NULL; @@ -83,6 +219,10 @@ fpga_sec_mgr_create(struct device *dev, const char *name, smgr->name = name; smgr->priv = priv; smgr->sops = sops; + smgr->err_code = FPGA_SEC_ERR_NONE; + smgr->progress = FPGA_SEC_PROG_IDLE; + init_completion(&smgr->update_done); + INIT_WORK(&smgr->work, fpga_sec_mgr_update); device_initialize(&smgr->dev); smgr->dev.class = fpga_sec_mgr_class; @@ -200,11 +340,31 @@ EXPORT_SYMBOL_GPL(fpga_sec_mgr_register); * * This function is intended for use in an FPGA security manager * driver's remove() function. + * + * For some devices, once the secure update has begun authentication + * the hardware cannot be signaled to stop, and the driver will not + * exit until the hardware signals completion. This could be 30+ + * minutes of waiting. The driver_unload flag enables a force-unload + * of the driver (e.g. modprobe -r) by signaling the parent driver to + * exit even if the hardware update is incomplete. The driver_unload + * flag also prevents new updates from starting once the unregister + * process has begun. */ void fpga_sec_mgr_unregister(struct fpga_sec_mgr *smgr) { dev_info(&smgr->dev, "%s %s\n", __func__, smgr->name); + mutex_lock(&smgr->lock); + smgr->driver_unload = true; + if (smgr->progress == FPGA_SEC_PROG_IDLE) { + mutex_unlock(&smgr->lock); + goto unregister; + } + + mutex_unlock(&smgr->lock); + wait_for_completion(&smgr->update_done); + +unregister: device_unregister(&smgr->dev); } EXPORT_SYMBOL_GPL(fpga_sec_mgr_unregister); diff --git a/include/linux/fpga/fpga-sec-mgr.h b/include/linux/fpga/fpga-sec-mgr.h index f85665b79b9d..978ab98ffac5 100644 --- a/include/linux/fpga/fpga-sec-mgr.h +++ b/include/linux/fpga/fpga-sec-mgr.h @@ -7,16 +7,56 @@ #ifndef _LINUX_FPGA_SEC_MGR_H #define _LINUX_FPGA_SEC_MGR_H +#include #include #include #include struct fpga_sec_mgr; +enum fpga_sec_err { + FPGA_SEC_ERR_NONE, + FPGA_SEC_ERR_HW_ERROR, + FPGA_SEC_ERR_TIMEOUT, + FPGA_SEC_ERR_CANCELED, + FPGA_SEC_ERR_BUSY, + FPGA_SEC_ERR_INVALID_SIZE, + FPGA_SEC_ERR_RW_ERROR, + FPGA_SEC_ERR_WEAROUT, + FPGA_SEC_ERR_FILE_READ, + FPGA_SEC_ERR_MAX +}; + /** * struct fpga_sec_mgr_ops - device specific operations + * @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 smgr->driver_unload + * and abort with FPGA_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 fpga_sec_mgr_ops { + enum fpga_sec_err (*prepare)(struct fpga_sec_mgr *smgr); + enum fpga_sec_err (*write_blk)(struct fpga_sec_mgr *smgr, u32 offset); + enum fpga_sec_err (*poll_complete)(struct fpga_sec_mgr *smgr); + enum fpga_sec_err (*cancel)(struct fpga_sec_mgr *smgr); + void (*cleanup)(struct fpga_sec_mgr *smgr); +}; + +/* Update progress codes */ +enum fpga_sec_prog { + FPGA_SEC_PROG_IDLE, + FPGA_SEC_PROG_READING, + FPGA_SEC_PROG_PREPARING, + FPGA_SEC_PROG_WRITING, + FPGA_SEC_PROG_PROGRAMMING, + FPGA_SEC_PROG_MAX }; struct fpga_sec_mgr { @@ -24,6 +64,14 @@ struct fpga_sec_mgr { struct device dev; const struct fpga_sec_mgr_ops *sops; 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 fpga_sec_prog progress; + enum fpga_sec_err err_code; /* security manager error code */ + bool driver_unload; void *priv; }; From patchwork Mon May 17 02:31:51 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Moritz Fischer X-Patchwork-Id: 12260781 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.0 required=3.0 tests=BAYES_00,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E2F26C433ED for ; Mon, 17 May 2021 02:32:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BC55D611CB for ; Mon, 17 May 2021 02:32:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233540AbhEQCeG (ORCPT ); Sun, 16 May 2021 22:34:06 -0400 Received: from mail-pj1-f44.google.com ([209.85.216.44]:39887 "EHLO mail-pj1-f44.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230104AbhEQCeG (ORCPT ); Sun, 16 May 2021 22:34:06 -0400 Received: by mail-pj1-f44.google.com with SMTP id o17-20020a17090a9f91b029015cef5b3c50so4704098pjp.4 for ; Sun, 16 May 2021 19:32:49 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=DJP2r0HTltsuZLhBCo0vZGGWtiQ8kd8CkqmXzteVj+M=; b=agYdqmFcXkEdwOxvoeKT+0E/RJ/4quHeELsxfQbANzI0TFY5h6BfdNKjOyVrbXYT1a xlKE04Vkf2Csw4z/FkG7wfUn2UAvvyMqQKU97T+rlPd4bfcX4y9xHNQdLREQn2du1Rwh 2Fq5C0Z2CaHt4xt55YOWLI5sOadoXAd4Ue3R9Ezwg/tGxwDEDnUILYdKlMJiO3Yo1JQH SKajn5CLB1tmf5mfagvIa0VkMzwMOzK7ITj/J+NGJ3nIKwn704EeXaODNm5f4jtbWdKx AZxRgSKihU1Z1znyXrVMbK1sl6a3xptA5XCc+OkSSVZwOmAGcvSAFKBdlQl60Xx6/qB+ DTzw== X-Gm-Message-State: AOAM530whvXGGuSqSWOfzkJXuyptJxCUQuR3a0/SVgRV75OxfwDVdwtK k/o03KWqis+DSCCJaMdaOAM= X-Google-Smtp-Source: ABdhPJxWJPkSXoThXZNpcllFrZZ2aCWgHWz+LjV/G7lymIqndGCtqL7Azthd2xEYfzLzobmy3OtEjw== X-Received: by 2002:a17:90a:aa96:: with SMTP id l22mr23682002pjq.173.1621218769329; Sun, 16 May 2021 19:32:49 -0700 (PDT) Received: from localhost ([2601:647:5b00:1161:a4cc:eef9:fbc0:2781]) by smtp.gmail.com with ESMTPSA id 184sm1774468pfv.38.2021.05.16.19.32.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 May 2021 19:32:48 -0700 (PDT) From: Moritz Fischer To: gregkh@linuxfoundation.org Cc: linux-fpga@vger.kernel.org, moritzf@google.com, Moritz Fischer , Russ Weight , Tom Rix Subject: [PATCH 03/12] fpga: sec-mgr: expose sec-mgr update status Date: Sun, 16 May 2021 19:31:51 -0700 Message-Id: <20210517023200.52707-4-mdf@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210517023200.52707-1-mdf@kernel.org> References: <20210517023200.52707-1-mdf@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org From: Russ Weight Extend the FPGA 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: Tom Rix Signed-off-by: Moritz Fischer --- .../ABI/testing/sysfs-class-fpga-sec-mgr | 11 +++++ drivers/fpga/fpga-sec-mgr.c | 42 +++++++++++++++++-- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr index 36d1b6ba8d76..b962ad2cf18d 100644 --- a/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr +++ b/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr @@ -16,3 +16,14 @@ Description: Write only. Write the filename of an image BMC images, BMC firmware, Static Region images, and Root Entry Hashes, and to cancel Code Signing Keys (CSK). + +What: /sys/class/fpga_sec_mgr/fpga_secX/update/status +Date: June 2021 +KernelVersion: 5.14 +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, reading, preparing, writing, + programming. Userspace code can poll on this file, + as it will be signaled by sysfs_notify() on each + state change. diff --git a/drivers/fpga/fpga-sec-mgr.c b/drivers/fpga/fpga-sec-mgr.c index bfdb01d2de57..19f60048a965 100644 --- a/drivers/fpga/fpga-sec-mgr.c +++ b/drivers/fpga/fpga-sec-mgr.c @@ -23,6 +23,13 @@ struct fpga_sec_mgr_devres { #define to_sec_mgr(d) container_of(d, struct fpga_sec_mgr, dev) +static void update_progress(struct fpga_sec_mgr *smgr, + enum fpga_sec_prog new_progress) +{ + smgr->progress = new_progress; + sysfs_notify(&smgr->dev.kobj, "update", "status"); +} + static void fpga_sec_dev_error(struct fpga_sec_mgr *smgr, enum fpga_sec_err err_code) { @@ -33,7 +40,7 @@ static void fpga_sec_dev_error(struct fpga_sec_mgr *smgr, static void progress_complete(struct fpga_sec_mgr *smgr) { mutex_lock(&smgr->lock); - smgr->progress = FPGA_SEC_PROG_IDLE; + update_progress(smgr, FPGA_SEC_PROG_IDLE); complete_all(&smgr->update_done); mutex_unlock(&smgr->lock); } @@ -61,14 +68,14 @@ static void fpga_sec_mgr_update(struct work_struct *work) goto release_fw_exit; } - smgr->progress = FPGA_SEC_PROG_PREPARING; + update_progress(smgr, FPGA_SEC_PROG_PREPARING); ret = smgr->sops->prepare(smgr); if (ret != FPGA_SEC_ERR_NONE) { fpga_sec_dev_error(smgr, ret); goto modput_exit; } - smgr->progress = FPGA_SEC_PROG_WRITING; + update_progress(smgr, FPGA_SEC_PROG_WRITING); while (smgr->remaining_size) { ret = smgr->sops->write_blk(smgr, offset); if (ret != FPGA_SEC_ERR_NONE) { @@ -79,7 +86,7 @@ static void fpga_sec_mgr_update(struct work_struct *work) offset = fw->size - smgr->remaining_size; } - smgr->progress = FPGA_SEC_PROG_PROGRAMMING; + update_progress(smgr, FPGA_SEC_PROG_PROGRAMMING); ret = smgr->sops->poll_complete(smgr); if (ret != FPGA_SEC_ERR_NONE) fpga_sec_dev_error(smgr, ret); @@ -107,6 +114,32 @@ static void fpga_sec_mgr_update(struct work_struct *work) progress_complete(smgr); } +static const char * const sec_mgr_prog_str[] = { + [FPGA_SEC_PROG_IDLE] = "idle", + [FPGA_SEC_PROG_READING] = "reading", + [FPGA_SEC_PROG_PREPARING] = "preparing", + [FPGA_SEC_PROG_WRITING] = "writing", + [FPGA_SEC_PROG_PROGRAMMING] = "programming" +}; + +static ssize_t +status_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct fpga_sec_mgr *smgr = to_sec_mgr(dev); + const char *status = "unknown-status"; + enum fpga_sec_prog progress; + + progress = smgr->progress; + if (progress < FPGA_SEC_PROG_MAX) + status = sec_mgr_prog_str[progress]; + else + dev_err(dev, "Invalid status during secure update: %d\n", + progress); + + return sysfs_emit(buf, "%s\n", status); +} +static DEVICE_ATTR_RO(status); + static ssize_t filename_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -141,6 +174,7 @@ static DEVICE_ATTR_WO(filename); static struct attribute *sec_mgr_update_attrs[] = { &dev_attr_filename.attr, + &dev_attr_status.attr, NULL, }; From patchwork Mon May 17 02:31:52 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Moritz Fischer X-Patchwork-Id: 12260783 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.0 required=3.0 tests=BAYES_00,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 03AC3C433B4 for ; Mon, 17 May 2021 02:32:53 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D60506117A for ; Mon, 17 May 2021 02:32:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233286AbhEQCeH (ORCPT ); Sun, 16 May 2021 22:34:07 -0400 Received: from mail-pj1-f47.google.com ([209.85.216.47]:56142 "EHLO mail-pj1-f47.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230104AbhEQCeH (ORCPT ); Sun, 16 May 2021 22:34:07 -0400 Received: by mail-pj1-f47.google.com with SMTP id gm21so2826036pjb.5 for ; Sun, 16 May 2021 19:32:51 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ehdtCvrQFrOOSfyoxkOjmU0xRJHpl55+MdR/k6VjjDk=; b=I3TzG+TkgxyfYUtnY+EASpjB3DRyLktuppXs2yFEyEAE1zkjmsoXfL8gV4vfNfcrGX /MIftOYDpZtw7rsS2HXEuRtO6rH7Pe7J1ywE3LqaWyh7eznpieLG5egJTWeBfI/sIA/D KvqKBssJhsjeIyuxt+vNSK2mliHWKXJrrZtVN1eFT0QAsi0CSrD36dXbD2PebEaNjp8y 3blMvuREowpyxogqQ4LfH+mMvF8D73sI1sbC2tbpET5q8PkGSsmB8kx7hV2d/ofziN8j 1reNBa5Hs9zFTl/EU+uslalA3dQk+SnuJGV7/LpHNtnrm3FRrswMb5uPYDSpkl9PfWeH W1OQ== X-Gm-Message-State: AOAM533kQAfOgiTOOrJb+ghIcy1fDjoq6Q07cZtr+PllFG+B4/i5rMQb CzTQqDLg+Q+dK1s4OBD1u+U= X-Google-Smtp-Source: ABdhPJyTmML9vm/r9BOVmc4V36BpIVWE8SVl2daKbtONB+zjPCnF/WIHMQiGalg5afJXp4m/QpNklw== X-Received: by 2002:a17:90a:c285:: with SMTP id f5mr1123211pjt.221.1621218770990; Sun, 16 May 2021 19:32:50 -0700 (PDT) Received: from localhost ([2601:647:5b00:1161:a4cc:eef9:fbc0:2781]) by smtp.gmail.com with ESMTPSA id i123sm8911486pfc.53.2021.05.16.19.32.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 May 2021 19:32:50 -0700 (PDT) From: Moritz Fischer To: gregkh@linuxfoundation.org Cc: linux-fpga@vger.kernel.org, moritzf@google.com, Moritz Fischer , Russ Weight , Tom Rix Subject: [PATCH 04/12] fpga: sec-mgr: expose sec-mgr update errors Date: Sun, 16 May 2021 19:31:52 -0700 Message-Id: <20210517023200.52707-5-mdf@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210517023200.52707-1-mdf@kernel.org> References: <20210517023200.52707-1-mdf@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org From: Russ Weight Extend the FPGA 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: Tom Rix Signed-off-by: Moritz Fischer --- .../ABI/testing/sysfs-class-fpga-sec-mgr | 17 ++++ drivers/fpga/fpga-sec-mgr.c | 83 ++++++++++++++++--- include/linux/fpga/fpga-sec-mgr.h | 1 + 3 files changed, 89 insertions(+), 12 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr index b962ad2cf18d..24890d04521f 100644 --- a/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr +++ b/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr @@ -27,3 +27,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/fpga_sec_mgr/fpga_secX/update/error +Date: June 2021 +KernelVersion: 5.14 +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/fpga-sec-mgr.c b/drivers/fpga/fpga-sec-mgr.c index 19f60048a965..903385779a1f 100644 --- a/drivers/fpga/fpga-sec-mgr.c +++ b/drivers/fpga/fpga-sec-mgr.c @@ -30,10 +30,16 @@ static void update_progress(struct fpga_sec_mgr *smgr, sysfs_notify(&smgr->dev.kobj, "update", "status"); } +static void fpga_sec_set_error(struct fpga_sec_mgr *smgr, enum fpga_sec_err err_code) +{ + smgr->err_state = smgr->progress; + smgr->err_code = err_code; +} + static void fpga_sec_dev_error(struct fpga_sec_mgr *smgr, enum fpga_sec_err err_code) { - smgr->err_code = err_code; + fpga_sec_set_error(smgr, err_code); smgr->sops->cancel(smgr); } @@ -56,7 +62,7 @@ static void fpga_sec_mgr_update(struct work_struct *work) get_device(&smgr->dev); if (request_firmware(&fw, smgr->filename, &smgr->dev)) { - smgr->err_code = FPGA_SEC_ERR_FILE_READ; + fpga_sec_set_error(smgr, FPGA_SEC_ERR_FILE_READ); goto idle_exit; } @@ -64,7 +70,7 @@ static void fpga_sec_mgr_update(struct work_struct *work) smgr->remaining_size = fw->size; if (!try_module_get(smgr->dev.parent->driver->owner)) { - smgr->err_code = FPGA_SEC_ERR_BUSY; + fpga_sec_set_error(smgr, FPGA_SEC_ERR_BUSY); goto release_fw_exit; } @@ -122,24 +128,76 @@ static const char * const sec_mgr_prog_str[] = { [FPGA_SEC_PROG_PROGRAMMING] = "programming" }; -static ssize_t -status_show(struct device *dev, struct device_attribute *attr, char *buf) +static const char * const sec_mgr_err_str[] = { + [FPGA_SEC_ERR_NONE] = "none", + [FPGA_SEC_ERR_HW_ERROR] = "hw-error", + [FPGA_SEC_ERR_TIMEOUT] = "timeout", + [FPGA_SEC_ERR_CANCELED] = "user-abort", + [FPGA_SEC_ERR_BUSY] = "device-busy", + [FPGA_SEC_ERR_INVALID_SIZE] = "invalid-file-size", + [FPGA_SEC_ERR_RW_ERROR] = "read-write-error", + [FPGA_SEC_ERR_WEAROUT] = "flash-wearout", + [FPGA_SEC_ERR_FILE_READ] = "file-read-error" +}; + +static const char *sec_progress(struct device *dev, enum fpga_sec_prog prog) { - struct fpga_sec_mgr *smgr = to_sec_mgr(dev); const char *status = "unknown-status"; - enum fpga_sec_prog progress; - progress = smgr->progress; - if (progress < FPGA_SEC_PROG_MAX) - status = sec_mgr_prog_str[progress]; + if (prog < FPGA_SEC_PROG_MAX) + status = sec_mgr_prog_str[prog]; else dev_err(dev, "Invalid status during secure update: %d\n", - progress); + prog); + + return status; +} + +static const char *sec_error(struct device *dev, enum fpga_sec_err err_code) +{ + const char *error = "unknown-error"; + + if (err_code < FPGA_SEC_ERR_MAX) + error = sec_mgr_err_str[err_code]; + else + dev_err(dev, "Invalid error code during secure update: %d\n", + err_code); + + return error; +} + +static ssize_t +status_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct fpga_sec_mgr *smgr = to_sec_mgr(dev); - return sysfs_emit(buf, "%s\n", status); + return sysfs_emit(buf, "%s\n", sec_progress(dev, smgr->progress)); } static DEVICE_ATTR_RO(status); +static ssize_t +error_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct fpga_sec_mgr *smgr = to_sec_mgr(dev); + int ret; + + mutex_lock(&smgr->lock); + + if (smgr->progress != FPGA_SEC_PROG_IDLE) + ret = -EBUSY; + else if (!smgr->err_code) + ret = 0; + else + ret = sysfs_emit(buf, "%s:%s\n", + sec_progress(dev, smgr->err_state), + sec_error(dev, smgr->err_code)); + + mutex_unlock(&smgr->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) { @@ -175,6 +233,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/fpga-sec-mgr.h b/include/linux/fpga/fpga-sec-mgr.h index 978ab98ffac5..6b7b8a3d6aac 100644 --- a/include/linux/fpga/fpga-sec-mgr.h +++ b/include/linux/fpga/fpga-sec-mgr.h @@ -70,6 +70,7 @@ struct fpga_sec_mgr { const u8 *data; /* pointer to update data */ u32 remaining_size; /* size remaining to transfer */ enum fpga_sec_prog progress; + enum fpga_sec_prog err_state; /* progress state at time of failure */ enum fpga_sec_err err_code; /* security manager error code */ bool driver_unload; void *priv; From patchwork Mon May 17 02:31:53 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Moritz Fischer X-Patchwork-Id: 12260785 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.0 required=3.0 tests=BAYES_00,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 91E4AC433ED for ; Mon, 17 May 2021 02:32:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6A4566117A for ; Mon, 17 May 2021 02:32:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233294AbhEQCeM (ORCPT ); Sun, 16 May 2021 22:34:12 -0400 Received: from mail-pj1-f41.google.com ([209.85.216.41]:35792 "EHLO mail-pj1-f41.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233096AbhEQCeJ (ORCPT ); Sun, 16 May 2021 22:34:09 -0400 Received: by mail-pj1-f41.google.com with SMTP id pf4-20020a17090b1d84b029015ccffe0f2eso4706067pjb.0 for ; Sun, 16 May 2021 19:32:53 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=0btgXLjqzTnoe7nolXFIuQ+q6HadfQT66f7WbOwLQgM=; b=LKxblQ01hYf3tKOapkQ4Jg8yuPzcO/b5NZatx1blOzGAxv5DvCbDCFvx8ovnbeoiNt Lvea/eqX0RALE++Rz9EZSTE/wqGwr7LVPN8RPElmdAqPcvH1Fxk4LdvO3rYv9IccIhXf ZI43EC/SFaS8jmSZRbYavUn/oxTUpFkszhRmvSageRLA66KYIhIE7rqA5crcL5OrSFBP vwlR+rzuvVTpdhi2u+/Aztbi1YZjRVx+Q6iE19zvmJuu6oCZZ5knkYxhZa7LVQypl+tJ ehxut6DoSa0otW/FeJO4rH7UHnD+XchwYjkK6e0WNNiOpwmJRWpIKh9iNcSjgki69HQ1 EzNg== X-Gm-Message-State: AOAM532ZSpz3PHrOX93cV14hkidNPxW8WnlU7QC7VLWQnDM3INp+PIRq y/lXFmkqIFfi6OCNVDYc51I= X-Google-Smtp-Source: ABdhPJyot9VxIL2bavZ6WpHvKbtPt7qlIVVssPYASSg5auIvqh3ZcEbi7QcNmG8lBzKk93nDYnEyaQ== X-Received: by 2002:a17:902:bcc7:b029:ed:6f73:ffc4 with SMTP id o7-20020a170902bcc7b02900ed6f73ffc4mr57504712pls.1.1621218772670; Sun, 16 May 2021 19:32:52 -0700 (PDT) Received: from localhost ([2601:647:5b00:1161:a4cc:eef9:fbc0:2781]) by smtp.gmail.com with ESMTPSA id o3sm9039050pgh.22.2021.05.16.19.32.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 May 2021 19:32:52 -0700 (PDT) From: Moritz Fischer To: gregkh@linuxfoundation.org Cc: linux-fpga@vger.kernel.org, moritzf@google.com, Moritz Fischer , Russ Weight , Tom Rix Subject: [PATCH 05/12] fpga: sec-mgr: expose sec-mgr update size Date: Sun, 16 May 2021 19:31:53 -0700 Message-Id: <20210517023200.52707-6-mdf@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210517023200.52707-1-mdf@kernel.org> References: <20210517023200.52707-1-mdf@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org From: Russ Weight Extend the FPGA 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: Tom Rix Signed-off-by: Moritz Fischer --- Documentation/ABI/testing/sysfs-class-fpga-sec-mgr | 11 +++++++++++ drivers/fpga/fpga-sec-mgr.c | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr index 24890d04521f..c5d0b9d7c7e4 100644 --- a/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr +++ b/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr @@ -28,6 +28,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/fpga_sec_mgr/fpga_secX/update/remaining_size +Date: June 2021 +KernelVersion: 5.14 +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/fpga_sec_mgr/fpga_secX/update/error Date: June 2021 KernelVersion: 5.14 diff --git a/drivers/fpga/fpga-sec-mgr.c b/drivers/fpga/fpga-sec-mgr.c index 903385779a1f..bc6b35cc7237 100644 --- a/drivers/fpga/fpga-sec-mgr.c +++ b/drivers/fpga/fpga-sec-mgr.c @@ -198,6 +198,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 fpga_sec_mgr *smgr = to_sec_mgr(dev); + + return sysfs_emit(buf, "%u\n", smgr->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) { @@ -234,6 +243,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 Mon May 17 02:31:54 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Moritz Fischer X-Patchwork-Id: 12260787 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.0 required=3.0 tests=BAYES_00,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CB2AAC433B4 for ; Mon, 17 May 2021 02:32:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AAE08611CB for ; Mon, 17 May 2021 02:32:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233096AbhEQCeM (ORCPT ); Sun, 16 May 2021 22:34:12 -0400 Received: from mail-pf1-f174.google.com ([209.85.210.174]:43952 "EHLO mail-pf1-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230104AbhEQCeJ (ORCPT ); Sun, 16 May 2021 22:34:09 -0400 Received: by mail-pf1-f174.google.com with SMTP id d78so3080400pfd.10 for ; Sun, 16 May 2021 19:32:54 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=mIuyThC8N8Vs45tWKR2XaYfdwdhs1NWGJ6K0ZJ36n20=; b=JP1aAEcAQX842C82FEn6j4Am2SSwbTWVjOVhRDXI11bV26sPJhOLYux6p7QlTJdmta dFNY6+uvYwaeNJMayNdvDkN55TWGUxzQj5uidb5r7izu1oPHqli8OeyOOnUwp8YLF67b /TIEr4j+jqyFhrZ+M87xmtSewl80Pplrq8iq+imYO8fQa+DJv4CVpYWpSpm3PHMAORmy 03QqFJqvw83sDvOTY+/DoUZI43k/mMn+hmp3WHsfKVykG3+SejSPhBhlkPV77VCn9iuo zPB0lTxVSvbPvNhpmZJmQsHQFj8xNfppPXQuGSaKL0pNnvTyVuDiN3UPImk2DcY+CSyp Zb6A== X-Gm-Message-State: AOAM533NuKDASmxBZH+kldlCbcL96JbtBtr6BoZ3Qt8H67PqNg35MO29 YNltJJWAK8FhBmRIZ0i8rL8= X-Google-Smtp-Source: ABdhPJzlcFmRO8+EzxYq2eb6Qfc2AVu7uw9AGVlHZL8BpL9JUdS7WlSQh5DMOQMOwiX4Mfhoh/ox0A== X-Received: by 2002:a63:581c:: with SMTP id m28mr22453421pgb.353.1621218774250; Sun, 16 May 2021 19:32:54 -0700 (PDT) Received: from localhost ([2601:647:5b00:1161:a4cc:eef9:fbc0:2781]) by smtp.gmail.com with ESMTPSA id x27sm9050892pfo.216.2021.05.16.19.32.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 May 2021 19:32:53 -0700 (PDT) From: Moritz Fischer To: gregkh@linuxfoundation.org Cc: linux-fpga@vger.kernel.org, moritzf@google.com, Moritz Fischer , Russ Weight , Tom Rix Subject: [PATCH 06/12] fpga: sec-mgr: enable cancel of secure update Date: Sun, 16 May 2021 19:31:54 -0700 Message-Id: <20210517023200.52707-7-mdf@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210517023200.52707-1-mdf@kernel.org> References: <20210517023200.52707-1-mdf@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org From: Russ Weight Extend the FPGA 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 Reviewed-by: Tom Rix Signed-off-by: Moritz Fischer --- .../ABI/testing/sysfs-class-fpga-sec-mgr | 10 ++++ drivers/fpga/fpga-sec-mgr.c | 59 +++++++++++++++++-- include/linux/fpga/fpga-sec-mgr.h | 1 + 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr index c5d0b9d7c7e4..749f2d4c78d3 100644 --- a/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr +++ b/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr @@ -17,6 +17,16 @@ Description: Write only. Write the filename of an image and Root Entry Hashes, and to cancel Code Signing Keys (CSK). +What: /sys/class/fpga_sec_mgr/fpga_secX/update/cancel +Date: June 2021 +KernelVersion: 5.14 +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/fpga_sec_mgr/fpga_secX/update/status Date: June 2021 KernelVersion: 5.14 diff --git a/drivers/fpga/fpga-sec-mgr.c b/drivers/fpga/fpga-sec-mgr.c index bc6b35cc7237..48950843c2b4 100644 --- a/drivers/fpga/fpga-sec-mgr.c +++ b/drivers/fpga/fpga-sec-mgr.c @@ -43,6 +43,23 @@ static void fpga_sec_dev_error(struct fpga_sec_mgr *smgr, smgr->sops->cancel(smgr); } +static int progress_transition(struct fpga_sec_mgr *smgr, + enum fpga_sec_prog new_progress) +{ + int ret = 0; + + mutex_lock(&smgr->lock); + if (smgr->request_cancel) { + fpga_sec_set_error(smgr, FPGA_SEC_ERR_CANCELED); + smgr->sops->cancel(smgr); + ret = -ECANCELED; + } else { + update_progress(smgr, new_progress); + } + mutex_unlock(&smgr->lock); + return ret; +} + static void progress_complete(struct fpga_sec_mgr *smgr) { mutex_lock(&smgr->lock); @@ -74,15 +91,19 @@ static void fpga_sec_mgr_update(struct work_struct *work) goto release_fw_exit; } - update_progress(smgr, FPGA_SEC_PROG_PREPARING); + if (progress_transition(smgr, FPGA_SEC_PROG_PREPARING)) + goto modput_exit; + ret = smgr->sops->prepare(smgr); if (ret != FPGA_SEC_ERR_NONE) { fpga_sec_dev_error(smgr, ret); goto modput_exit; } - update_progress(smgr, FPGA_SEC_PROG_WRITING); - while (smgr->remaining_size) { + if (progress_transition(smgr, FPGA_SEC_PROG_WRITING)) + goto done; + + while (smgr->remaining_size && !smgr->request_cancel) { ret = smgr->sops->write_blk(smgr, offset); if (ret != FPGA_SEC_ERR_NONE) { fpga_sec_dev_error(smgr, ret); @@ -92,7 +113,9 @@ static void fpga_sec_mgr_update(struct work_struct *work) offset = fw->size - smgr->remaining_size; } - update_progress(smgr, FPGA_SEC_PROG_PROGRAMMING); + if (progress_transition(smgr, FPGA_SEC_PROG_PROGRAMMING)) + goto done; + ret = smgr->sops->poll_complete(smgr); if (ret != FPGA_SEC_ERR_NONE) fpga_sec_dev_error(smgr, ret); @@ -229,6 +252,7 @@ static ssize_t filename_store(struct device *dev, struct device_attribute *attr, } smgr->err_code = FPGA_SEC_ERR_NONE; + smgr->request_cancel = false; smgr->progress = FPGA_SEC_PROG_READING; reinit_completion(&smgr->update_done); schedule_work(&smgr->work); @@ -239,8 +263,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 fpga_sec_mgr *smgr = to_sec_mgr(dev); + bool cancel; + int ret = count; + + if (kstrtobool(buf, &cancel) || !cancel) + return -EINVAL; + + mutex_lock(&smgr->lock); + if (smgr->progress == FPGA_SEC_PROG_PROGRAMMING) + ret = -EBUSY; + else if (smgr->progress == FPGA_SEC_PROG_IDLE) + ret = -ENODEV; + else + smgr->request_cancel = true; + mutex_unlock(&smgr->lock); + + return ret; +} +static DEVICE_ATTR_WO(cancel); + static struct attribute *sec_mgr_update_attrs[] = { &dev_attr_filename.attr, + &dev_attr_cancel.attr, &dev_attr_status.attr, &dev_attr_error.attr, &dev_attr_remaining_size.attr, @@ -464,6 +512,9 @@ void fpga_sec_mgr_unregister(struct fpga_sec_mgr *smgr) goto unregister; } + if (smgr->progress != FPGA_SEC_PROG_PROGRAMMING) + smgr->request_cancel = true; + mutex_unlock(&smgr->lock); wait_for_completion(&smgr->update_done); diff --git a/include/linux/fpga/fpga-sec-mgr.h b/include/linux/fpga/fpga-sec-mgr.h index 6b7b8a3d6aac..0e1f50434024 100644 --- a/include/linux/fpga/fpga-sec-mgr.h +++ b/include/linux/fpga/fpga-sec-mgr.h @@ -72,6 +72,7 @@ struct fpga_sec_mgr { enum fpga_sec_prog progress; enum fpga_sec_prog err_state; /* progress state at time of failure */ enum fpga_sec_err err_code; /* security manager error code */ + bool request_cancel; bool driver_unload; void *priv; }; From patchwork Mon May 17 02:31:55 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Moritz Fischer X-Patchwork-Id: 12260789 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.0 required=3.0 tests=BAYES_00,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E9002C43461 for ; Mon, 17 May 2021 02:32:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CEAAD611F0 for ; Mon, 17 May 2021 02:32:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230104AbhEQCeM (ORCPT ); Sun, 16 May 2021 22:34:12 -0400 Received: from mail-pl1-f169.google.com ([209.85.214.169]:34588 "EHLO mail-pl1-f169.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233266AbhEQCeM (ORCPT ); Sun, 16 May 2021 22:34:12 -0400 Received: by mail-pl1-f169.google.com with SMTP id h7so2315947plt.1 for ; Sun, 16 May 2021 19:32:56 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=aSSYdCtIQxbcyAXdS71tqSOcp2D/L0mRXKz8gwWCGqg=; b=GvmU0wwhquo05QrVBD9WpA5FvGDYedKmQvoGZ0AVWQyG8fJ2RZw3tBkSeb5YSNmOJk BOdORsJ0AL+ofbG9Ev+Nw0GaGhmXFUn6hcrTQlcV9RIWgI23jhoClsSi7WoN6/x/o/0z VbS1XptPZKCs+958K0UAeezvBKONhGxDye6DiYeQWcxjJd8swXWNCK2LVRFfVbCE7oOl 87HTbgY8FekNYmYtjs6tZfEQtQzgX5z5ot8Hvc7UPZuAzozeNE2mIdKnJkbGVI8ND6Au /tRS5zPRCJW0/G/hMrwTdt4Z4Y5ASlrkZqhFLN7HGuvFjDG3Sl2Sc7X3S/xkdELiuYf7 9GCw== X-Gm-Message-State: AOAM530AcsSmufH4L+spcyFOltIB2UbnlosDPiqB1Os6R19MpBwsKMaq YgvtD45EgkwQeUncPlq48xM= X-Google-Smtp-Source: ABdhPJw5cfDe7LbztmX8Gzl0ryHcZBaDO079W7Un492Qn6ifkFv+MwClbeRCjwpHXzkgKg/P5zvE5A== X-Received: by 2002:a17:902:ea0c:b029:f0:af3d:c5d6 with SMTP id s12-20020a170902ea0cb02900f0af3dc5d6mr12742855plg.45.1621218775814; Sun, 16 May 2021 19:32:55 -0700 (PDT) Received: from localhost ([2601:647:5b00:1161:a4cc:eef9:fbc0:2781]) by smtp.gmail.com with ESMTPSA id o3sm9039109pgh.22.2021.05.16.19.32.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 May 2021 19:32:55 -0700 (PDT) From: Moritz Fischer To: gregkh@linuxfoundation.org Cc: linux-fpga@vger.kernel.org, moritzf@google.com, Moritz Fischer , Russ Weight , Tom Rix Subject: [PATCH 07/12] fpga: sec-mgr: expose hardware error info Date: Sun, 16 May 2021 19:31:55 -0700 Message-Id: <20210517023200.52707-8-mdf@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210517023200.52707-1-mdf@kernel.org> References: <20210517023200.52707-1-mdf@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org From: Russ Weight Extend the FPGA 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: Tom Rix Signed-off-by: Moritz Fischer --- .../ABI/testing/sysfs-class-fpga-sec-mgr | 14 +++++++ drivers/fpga/fpga-sec-mgr.c | 38 +++++++++++++++++++ include/linux/fpga/fpga-sec-mgr.h | 5 +++ 3 files changed, 57 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr b/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr index 749f2d4c78d3..f1881ce39c63 100644 --- a/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr +++ b/Documentation/ABI/testing/sysfs-class-fpga-sec-mgr @@ -65,3 +65,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/fpga_sec_mgr/fpga_secX/update/hw_errinfo +Date: June 2021 +KernelVersion: 5.14 +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/fpga-sec-mgr.c b/drivers/fpga/fpga-sec-mgr.c index 48950843c2b4..cefe9182c3c3 100644 --- a/drivers/fpga/fpga-sec-mgr.c +++ b/drivers/fpga/fpga-sec-mgr.c @@ -36,10 +36,17 @@ static void fpga_sec_set_error(struct fpga_sec_mgr *smgr, enum fpga_sec_err err_ smgr->err_code = err_code; } +static void fpga_sec_set_hw_errinfo(struct fpga_sec_mgr *smgr) +{ + if (smgr->sops->get_hw_errinfo) + smgr->hw_errinfo = smgr->sops->get_hw_errinfo(smgr); +} + static void fpga_sec_dev_error(struct fpga_sec_mgr *smgr, enum fpga_sec_err err_code) { fpga_sec_set_error(smgr, err_code); + fpga_sec_set_hw_errinfo(smgr); smgr->sops->cancel(smgr); } @@ -221,6 +228,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 fpga_sec_mgr *smgr = to_sec_mgr(dev); + int ret; + + mutex_lock(&smgr->lock); + if (smgr->progress != FPGA_SEC_PROG_IDLE) + ret = -EBUSY; + else + ret = sysfs_emit(buf, "0x%llx\n", smgr->hw_errinfo); + mutex_unlock(&smgr->lock); + + return ret; +} +static DEVICE_ATTR_RO(hw_errinfo); + static ssize_t remaining_size_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -252,6 +276,7 @@ static ssize_t filename_store(struct device *dev, struct device_attribute *attr, } smgr->err_code = FPGA_SEC_ERR_NONE; + smgr->hw_errinfo = 0; smgr->request_cancel = false; smgr->progress = FPGA_SEC_PROG_READING; reinit_completion(&smgr->update_done); @@ -286,18 +311,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 fpga_sec_mgr *smgr = to_sec_mgr(kobj_to_dev(kobj)); + + if (attr == &dev_attr_hw_errinfo.attr && !smgr->sops->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/fpga-sec-mgr.h b/include/linux/fpga/fpga-sec-mgr.h index 0e1f50434024..a99bfd28f38c 100644 --- a/include/linux/fpga/fpga-sec-mgr.h +++ b/include/linux/fpga/fpga-sec-mgr.h @@ -40,6 +40,9 @@ enum fpga_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 fpga_sec_mgr_ops { enum fpga_sec_err (*prepare)(struct fpga_sec_mgr *smgr); @@ -47,6 +50,7 @@ struct fpga_sec_mgr_ops { enum fpga_sec_err (*poll_complete)(struct fpga_sec_mgr *smgr); enum fpga_sec_err (*cancel)(struct fpga_sec_mgr *smgr); void (*cleanup)(struct fpga_sec_mgr *smgr); + u64 (*get_hw_errinfo)(struct fpga_sec_mgr *smgr); }; /* Update progress codes */ @@ -72,6 +76,7 @@ struct fpga_sec_mgr { enum fpga_sec_prog progress; enum fpga_sec_prog err_state; /* progress state at time of failure */ enum fpga_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 Mon May 17 02:31:56 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Moritz Fischer X-Patchwork-Id: 12260791 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.0 required=3.0 tests=BAYES_00,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A0FA3C433ED for ; Mon, 17 May 2021 02:32:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8416B6117A for ; Mon, 17 May 2021 02:32:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233404AbhEQCeO (ORCPT ); Sun, 16 May 2021 22:34:14 -0400 Received: from mail-pj1-f43.google.com ([209.85.216.43]:40810 "EHLO mail-pj1-f43.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233266AbhEQCeO (ORCPT ); Sun, 16 May 2021 22:34:14 -0400 Received: by mail-pj1-f43.google.com with SMTP id b9-20020a17090a9909b029015cf9effaeaso4708801pjp.5 for ; Sun, 16 May 2021 19:32:57 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=UeS8TQkM0/YCfddx57e41paQ4cWrLxmZxHFOSJQiOjY=; b=jXa3HHthXV71t29WLEVoxirV4Se7I2EwKv8yZhAXS2v3LW3S0qcIRV51YV0Gl5jZJx 3s1T7YgYIM+ohomcnpCQOLEjHP22LkN+SuzlEb7YUQjD/zgrTmTL3rR7K0VejrNhBzMO aPrpb2r/dxDPYXLZHDwTCIyGENLo3KQ/L6z7jXmcLYWaZuR1nPIcC5i90TqTo+8I5LXq rnOW7gmC5El9FR3tXPHPTpRkEn5LT7NXhwowo3pv+f4H2GxQ2RjL9EH63pfn2FacWPH3 g4GZKiNayJhksZo2LGEtwEBKHpkqP5TTyiVI8/i+5iGZIH+82zjl97vtQxNldDj9d3la Vekg== X-Gm-Message-State: AOAM530A+o1uA5P5Gue/LPB8CAkT5uL2WjVRy1v52AjfzDp4KGCNVlu5 E6TN40AsoDPNYfgtByBki7Q= X-Google-Smtp-Source: ABdhPJy1YqnWbMVjdqqF+gk4QQsYdIHTcSZKojIe+HVP8qCsvCer8lvhRxXjYWdT2Elu08SEkVoUZw== X-Received: by 2002:a17:90a:b885:: with SMTP id o5mr3419187pjr.91.1621218777466; Sun, 16 May 2021 19:32:57 -0700 (PDT) Received: from localhost ([2601:647:5b00:1161:a4cc:eef9:fbc0:2781]) by smtp.gmail.com with ESMTPSA id cv24sm9175171pjb.7.2021.05.16.19.32.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 May 2021 19:32:56 -0700 (PDT) From: Moritz Fischer To: gregkh@linuxfoundation.org Cc: linux-fpga@vger.kernel.org, moritzf@google.com, Moritz Fischer , Russ Weight , Tom Rix Subject: [PATCH 08/12] fpga: m10bmc-sec: create max10 bmc secure update driver Date: Sun, 16 May 2021 19:31:56 -0700 Message-Id: <20210517023200.52707-9-mdf@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210517023200.52707-1-mdf@kernel.org> References: <20210517023200.52707-1-mdf@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org From: Russ Weight Create a platform driver that can be invoked as a sub driver for the Intel MAX10 BMC in order to support secure updates. This sub-driver will invoke an instance of the 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 Secure Update driver and provides sysfs files 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: Tom Rix Signed-off-by: Moritz Fischer --- .../testing/sysfs-driver-intel-m10-bmc-secure | 29 ++++ MAINTAINERS | 2 + drivers/fpga/Kconfig | 11 ++ drivers/fpga/Makefile | 3 + drivers/fpga/intel-m10-bmc-secure.c | 135 ++++++++++++++++++ 5 files changed, 180 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-secure create mode 100644 drivers/fpga/intel-m10-bmc-secure.c diff --git a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-secure b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-secure new file mode 100644 index 000000000000..9a0abb147b28 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-secure @@ -0,0 +1,29 @@ +What: /sys/bus/platform/drivers/intel-m10bmc-secure/.../security/sr_root_entry_hash +Date: June 2021 +KernelVersion: 5.14 +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/bus/platform/drivers/intel-m10bmc-secure/.../security/pr_root_entry_hash +Date: June 2021 +KernelVersion: 5.14 +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/bus/platform/drivers/intel-m10bmc-secure/.../security/bmc_root_entry_hash +Date: June 2021 +KernelVersion: 5.14 +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". diff --git a/MAINTAINERS b/MAINTAINERS index ac81adcd8579..864ba65478bc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7141,8 +7141,10 @@ M: Russ Weight L: linux-fpga@vger.kernel.org S: Maintained F: Documentation/ABI/testing/sysfs-class-fpga-sec-mgr +F: Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-secure F: Documentation/fpga/fpga-sec-mgr.rst F: drivers/fpga/fpga-sec-mgr.c +F: drivers/fpga/intel-m10-bmc-secure.c F: include/linux/fpga/fpga-sec-mgr.h FPU EMULATOR diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 09a8d915db26..0f3bbebd8b08 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -243,4 +243,15 @@ config FPGA_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 Secure Update driver" + depends on MFD_INTEL_M10_BMC && FPGA_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 22576d1a3996..7259f1ab2531 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 # FPGA Security Manager Framework obj-$(CONFIG_FPGA_SEC_MGR) += fpga-sec-mgr.o +# FPGA Secure Update 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..5ac5f59b5731 --- /dev/null +++ b/drivers/fpga/intel-m10-bmc-secure.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel Max10 Board Management Controller Secure Update 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; +}; + +/* Root Entry Hash (REH) support */ +#define REH_SHA256_SIZE 32 +#define REH_SHA384_SIZE 48 +#define REH_MAGIC GENMASK(15, 0) +#define REH_SHA_NUM_BYTES GENMASK(31, 16) + +static ssize_t +show_root_entry_hash(struct device *dev, u32 exp_magic, + u32 prog_addr, u32 reh_addr, char *buf) +{ + struct m10bmc_sec *sec = dev_get_drvdata(dev); + unsigned int stride = regmap_get_reg_stride(sec->m10bmc->regmap); + int sha_num_bytes, i, cnt, ret; + u8 hash[REH_SHA384_SIZE]; + u32 magic; + + ret = m10bmc_raw_read(sec->m10bmc, prog_addr, &magic); + if (ret) + return ret; + + dev_dbg(dev, "%s magic 0x%08x\n", __func__, magic); + + if (FIELD_GET(REH_MAGIC, magic) != exp_magic) + return sysfs_emit(buf, "hash not programmed\n"); + + sha_num_bytes = FIELD_GET(REH_SHA_NUM_BYTES, magic) / 8; + if (sha_num_bytes != REH_SHA256_SIZE && + sha_num_bytes != REH_SHA384_SIZE) { + dev_err(sec->dev, "%s bad sha num bytes %d\n", __func__, + sha_num_bytes); + return -EINVAL; + } + + WARN_ON(sha_num_bytes % stride); + ret = regmap_bulk_read(sec->m10bmc->regmap, reh_addr, + hash, sha_num_bytes / stride); + if (ret) { + dev_err(dev, "failed to read root entry hash: %x cnt %x: %d\n", + reh_addr, sha_num_bytes / stride, ret); + return ret; + } + + cnt = sprintf(buf, "0x"); + for (i = 0; i < sha_num_bytes; i++) + cnt += sprintf(buf + cnt, "%02x", hash[i]); + cnt += sprintf(buf + cnt, "\n"); + + return cnt; +} + +#define DEVICE_ATTR_SEC_REH_RO(_name, _magic, _prog_addr, _reh_addr) \ +static ssize_t _name##_root_entry_hash_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ return show_root_entry_hash(dev, _magic, _prog_addr, _reh_addr, buf); } \ +static DEVICE_ATTR_RO(_name##_root_entry_hash) + +DEVICE_ATTR_SEC_REH_RO(bmc, BMC_PROG_MAGIC, BMC_PROG_ADDR, BMC_REH_ADDR); +DEVICE_ATTR_SEC_REH_RO(sr, SR_PROG_MAGIC, SR_PROG_ADDR, SR_REH_ADDR); +DEVICE_ATTR_SEC_REH_RO(pr, PR_PROG_MAGIC, PR_PROG_ADDR, PR_REH_ADDR); + +static struct attribute *m10bmc_security_attrs[] = { + &dev_attr_bmc_root_entry_hash.attr, + &dev_attr_sr_root_entry_hash.attr, + &dev_attr_pr_root_entry_hash.attr, + NULL, +}; + +static struct attribute_group m10bmc_security_attr_group = { + .name = "security", + .attrs = m10bmc_security_attrs, +}; + +static const struct attribute_group *m10bmc_sec_attr_groups[] = { + &m10bmc_security_attr_group, + NULL, +}; + +static const struct fpga_sec_mgr_ops m10bmc_sops = { }; + +static int m10bmc_secure_probe(struct platform_device *pdev) +{ + struct fpga_sec_mgr *smgr; + struct m10bmc_sec *sec; + + 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); + + smgr = devm_fpga_sec_mgr_create(sec->dev, "Max10 BMC Secure Update", + &m10bmc_sops, sec); + if (!smgr) { + dev_err(sec->dev, "Security manager failed to start\n"); + return -ENOMEM; + } + + return devm_fpga_sec_mgr_register(sec->dev, smgr); +} + +static struct platform_driver intel_m10bmc_secure_driver = { + .probe = m10bmc_secure_probe, + .driver = { + .name = "n3000bmc-secure", + .dev_groups = m10bmc_sec_attr_groups, + }, +}; +module_platform_driver(intel_m10bmc_secure_driver); + +MODULE_ALIAS("platform:n3000bmc-secure"); +MODULE_AUTHOR("Intel Corporation"); +MODULE_DESCRIPTION("Intel MAX10 BMC Secure Update"); +MODULE_LICENSE("GPL v2"); From patchwork Mon May 17 02:31:57 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Moritz Fischer X-Patchwork-Id: 12260793 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.0 required=3.0 tests=BAYES_00,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 33D13C433B4 for ; Mon, 17 May 2021 02:33:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1661D611CB for ; Mon, 17 May 2021 02:33:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233266AbhEQCeP (ORCPT ); Sun, 16 May 2021 22:34:15 -0400 Received: from mail-pf1-f171.google.com ([209.85.210.171]:44962 "EHLO mail-pf1-f171.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232417AbhEQCeO (ORCPT ); Sun, 16 May 2021 22:34:14 -0400 Received: by mail-pf1-f171.google.com with SMTP id 22so3558519pfv.11 for ; Sun, 16 May 2021 19:32:59 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=FUGSX1qCRIuUC6MduD9yhQ9xKVXDVKCIgoAMN8uhL2U=; b=EU7VTqOmrxP83IBEnqHIUf4d+ymL1hEn95wsMRcjyijTjFH3kZFYoYvG106AbibCYs ViVOtip838sf7UTdaJUAbLVGRPgnMPZcSC7lIkwmMNNLx7uQom1386S915sQYRUQx/fR KheImI5preR/dmlEGZOMn8nEZVX0TawIdpOiN5UjOUACBf9QZzClhd7XrpvsrojHIQlC dzrtxtSNylRB6a5rWVVANW96fhh2cc5Mp195GwSOQ1x5idfutH7ASLxkZDlWJcLFS2Cr W7aX+5X00Xpl6uuKHGs93c9dkkV+qQDVvY1DJKpaZ8oNiAqaz8QNHfr1bZRcTew0x7Ay AM2w== X-Gm-Message-State: AOAM530KHzfWuj0jrUP6fPUth1Y6cNSZVGwWOznmC/o1OLbG+JuHXLbY yOWSE3h8nxyYp3z4QBZuZlw= X-Google-Smtp-Source: ABdhPJxCnaQH7bqY3vvtu4Wrre0p7HdyspEfyca2we06PIY5AiL2nlyZTZTXS1ymxWgRTS7CP+FjWQ== X-Received: by 2002:a65:640c:: with SMTP id a12mr58250232pgv.229.1621218779198; Sun, 16 May 2021 19:32:59 -0700 (PDT) Received: from localhost ([2601:647:5b00:1161:a4cc:eef9:fbc0:2781]) by smtp.gmail.com with ESMTPSA id z3sm8327329pfe.78.2021.05.16.19.32.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 May 2021 19:32:58 -0700 (PDT) From: Moritz Fischer To: gregkh@linuxfoundation.org Cc: linux-fpga@vger.kernel.org, moritzf@google.com, Moritz Fischer , Russ Weight , Tom Rix Subject: [PATCH 09/12] fpga: m10bmc-sec: expose max10 flash update count Date: Sun, 16 May 2021 19:31:57 -0700 Message-Id: <20210517023200.52707-10-mdf@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210517023200.52707-1-mdf@kernel.org> References: <20210517023200.52707-1-mdf@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org From: Russ Weight Extend the MAX10 BMC Secure Update driver to provide a sysfs file to expose the flash update count for the FPGA user image. Signed-off-by: Russ Weight Reviewed-by: Tom Rix Signed-off-by: Moritz Fischer --- .../testing/sysfs-driver-intel-m10-bmc-secure | 8 ++++ drivers/fpga/intel-m10-bmc-secure.c | 37 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-secure b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-secure index 9a0abb147b28..c805c25e776d 100644 --- a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-secure +++ b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-secure @@ -27,3 +27,11 @@ Description: Read only. Returns the root entry hash for the BMC image "hash not programmed". This file is only visible if the underlying device supports it. Format: "0x%x". + +What: /sys/bus/platform/drivers/intel-m10bmc-secure/.../security/flash_count +Date: June 2021 +KernelVersion: 5.14 +Contact: Russ Weight +Description: Read only. Returns number of times the secure update + staging area has been flashed. + Format: "%u". diff --git a/drivers/fpga/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c index 5ac5f59b5731..ecd63c13cb2d 100644 --- a/drivers/fpga/intel-m10-bmc-secure.c +++ b/drivers/fpga/intel-m10-bmc-secure.c @@ -11,6 +11,7 @@ #include #include #include +#include struct m10bmc_sec { struct device *dev; @@ -78,7 +79,43 @@ DEVICE_ATTR_SEC_REH_RO(bmc, BMC_PROG_MAGIC, BMC_PROG_ADDR, BMC_REH_ADDR); DEVICE_ATTR_SEC_REH_RO(sr, SR_PROG_MAGIC, SR_PROG_ADDR, SR_REH_ADDR); DEVICE_ATTR_SEC_REH_RO(pr, PR_PROG_MAGIC, PR_PROG_ADDR, PR_REH_ADDR); +#define FLASH_COUNT_SIZE 4096 /* count stored as inverted bit vector */ + +static ssize_t flash_count_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct m10bmc_sec *sec = dev_get_drvdata(dev); + unsigned int stride, num_bits; + u8 *flash_buf; + int cnt, ret; + + stride = regmap_get_reg_stride(sec->m10bmc->regmap); + num_bits = FLASH_COUNT_SIZE * 8; + + flash_buf = kmalloc(FLASH_COUNT_SIZE, GFP_KERNEL); + if (!flash_buf) + return -ENOMEM; + + WARN_ON(FLASH_COUNT_SIZE % stride); + ret = regmap_bulk_read(sec->m10bmc->regmap, STAGING_FLASH_COUNT, + flash_buf, FLASH_COUNT_SIZE / stride); + if (ret) { + dev_err(sec->dev, + "failed to read flash count: %x cnt %x: %d\n", + STAGING_FLASH_COUNT, FLASH_COUNT_SIZE / stride, ret); + goto exit_free; + } + cnt = num_bits - bitmap_weight((unsigned long *)flash_buf, num_bits); + +exit_free: + kfree(flash_buf); + + return ret ? : sysfs_emit(buf, "%u\n", cnt); +} +static DEVICE_ATTR_RO(flash_count); + static struct attribute *m10bmc_security_attrs[] = { + &dev_attr_flash_count.attr, &dev_attr_bmc_root_entry_hash.attr, &dev_attr_sr_root_entry_hash.attr, &dev_attr_pr_root_entry_hash.attr, From patchwork Mon May 17 02:31:58 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Moritz Fischer X-Patchwork-Id: 12260795 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.0 required=3.0 tests=BAYES_00,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CF8C0C433ED for ; Mon, 17 May 2021 02:33:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B11416101E for ; Mon, 17 May 2021 02:33:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233417AbhEQCeR (ORCPT ); Sun, 16 May 2021 22:34:17 -0400 Received: from mail-pj1-f54.google.com ([209.85.216.54]:44609 "EHLO mail-pj1-f54.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232417AbhEQCeR (ORCPT ); Sun, 16 May 2021 22:34:17 -0400 Received: by mail-pj1-f54.google.com with SMTP id lj11-20020a17090b344bb029015bc3073608so2845393pjb.3 for ; Sun, 16 May 2021 19:33:01 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=rKrrJk1MFKVUPavRvSfkhmOslcbkH8ouSxGsfIRu6kI=; b=c4blNG6nJ0ZRhKHN9WkQrWXQtaSHOmzFYDSCCLw4Lt/dhyqHpLF9XR1MZ5VtvA/3a+ m+DPxWCANrBCSaXWdwb+vDYeL4bY/wVA7U+VrWV5d+H/tDz3hTpfKYM3aThc3mNA7Snq IWLSweKFN0rB+0WB3a4oeqWVU9ifsg02cMlbChi1xtzjK9JEocLCpd+h8Lp353QshgMF VsU+Ph93zB31H5ZnOfDK5ZL3DJNIINKn5VxSS/n6ccsJ/SRmFtIgPUx4mYpiedD75pBE ULXyX6zXaZoKOGuXuVM0/20UFqRy3VxlvV5gAZ4ubHeR2FV9LNMFvF1oxvvkZ5JWHRFR vBTw== X-Gm-Message-State: AOAM533PobnDyNJeL4me37xvcZZyFfHJ29qyCoogJm6rN7XboCxfO3jW H9Yt92l2RHZSeVTVOLs4fi0= X-Google-Smtp-Source: ABdhPJzk3MjWGXFbQyUOSIsO6rFtI3/0Wgdzbs4rO8MJVfF+DWnp4uhCBhguV7hARiTv5ftXpYpDBg== X-Received: by 2002:a17:90a:6345:: with SMTP id v5mr24525780pjs.139.1621218780778; Sun, 16 May 2021 19:33:00 -0700 (PDT) Received: from localhost ([2601:647:5b00:1161:a4cc:eef9:fbc0:2781]) by smtp.gmail.com with ESMTPSA id v2sm8876321pfv.97.2021.05.16.19.33.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 May 2021 19:33:00 -0700 (PDT) From: Moritz Fischer To: gregkh@linuxfoundation.org Cc: linux-fpga@vger.kernel.org, moritzf@google.com, Moritz Fischer , Russ Weight , Tom Rix Subject: [PATCH 10/12] fpga: m10bmc-sec: expose max10 canceled keys in sysfs Date: Sun, 16 May 2021 19:31:58 -0700 Message-Id: <20210517023200.52707-11-mdf@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210517023200.52707-1-mdf@kernel.org> References: <20210517023200.52707-1-mdf@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org From: Russ Weight Extend the MAX10 BMC Secure Update driver to provide sysfs files 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: Tom Rix Signed-off-by: Moritz Fischer --- .../testing/sysfs-driver-intel-m10-bmc-secure | 24 ++++++++++ drivers/fpga/intel-m10-bmc-secure.c | 48 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-secure b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-secure index c805c25e776d..798d33b625d8 100644 --- a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-secure +++ b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-secure @@ -28,6 +28,30 @@ Description: Read only. Returns the root entry hash for the BMC image underlying device supports it. Format: "0x%x". +What: /sys/bus/platform/drivers/intel-m10bmc-secure/.../security/sr_canceled_csks +Date: June 2021 +KernelVersion: 5.14 +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/bus/platform/drivers/intel-m10bmc-secure/.../security/pr_canceled_csks +Date: June 2021 +KernelVersion: 5.14 +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/bus/platform/drivers/intel-m10bmc-secure/.../security/bmc_canceled_csks +Date: June 2021 +KernelVersion: 5.14 +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/bus/platform/drivers/intel-m10bmc-secure/.../security/flash_count Date: June 2021 KernelVersion: 5.14 diff --git a/drivers/fpga/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c index ecd63c13cb2d..87e16c146569 100644 --- a/drivers/fpga/intel-m10-bmc-secure.c +++ b/drivers/fpga/intel-m10-bmc-secure.c @@ -79,6 +79,51 @@ DEVICE_ATTR_SEC_REH_RO(bmc, BMC_PROG_MAGIC, BMC_PROG_ADDR, BMC_REH_ADDR); DEVICE_ATTR_SEC_REH_RO(sr, SR_PROG_MAGIC, SR_PROG_ADDR, SR_REH_ADDR); DEVICE_ATTR_SEC_REH_RO(pr, PR_PROG_MAGIC, PR_PROG_ADDR, PR_REH_ADDR); +#define CSK_BIT_LEN 128U +#define CSK_32ARRAY_SIZE DIV_ROUND_UP(CSK_BIT_LEN, 32) + +static ssize_t +show_canceled_csk(struct device *dev, u32 addr, char *buf) +{ + unsigned int i, stride, size = CSK_32ARRAY_SIZE * sizeof(u32); + struct m10bmc_sec *sec = dev_get_drvdata(dev); + DECLARE_BITMAP(csk_map, CSK_BIT_LEN); + __le32 csk_le32[CSK_32ARRAY_SIZE]; + u32 csk32[CSK_32ARRAY_SIZE]; + int ret; + + stride = regmap_get_reg_stride(sec->m10bmc->regmap); + + WARN_ON(size % stride); + ret = regmap_bulk_read(sec->m10bmc->regmap, addr, csk_le32, + size / stride); + if (ret) { + dev_err(sec->dev, "failed to read CSK vector: %x cnt %x: %d\n", + addr, size / stride, ret); + return ret; + } + + for (i = 0; i < CSK_32ARRAY_SIZE; i++) + csk32[i] = le32_to_cpu(((csk_le32[i]))); + + bitmap_from_arr32(csk_map, csk32, CSK_BIT_LEN); + bitmap_complement(csk_map, csk_map, CSK_BIT_LEN); + return bitmap_print_to_pagebuf(1, buf, csk_map, CSK_BIT_LEN); +} + +#define DEVICE_ATTR_SEC_CSK_RO(_name, _addr) \ +static ssize_t _name##_canceled_csks_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ return show_canceled_csk(dev, _addr, buf); } \ +static DEVICE_ATTR_RO(_name##_canceled_csks) + +#define CSK_VEC_OFFSET 0x34 + +DEVICE_ATTR_SEC_CSK_RO(bmc, BMC_PROG_ADDR + CSK_VEC_OFFSET); +DEVICE_ATTR_SEC_CSK_RO(sr, SR_PROG_ADDR + CSK_VEC_OFFSET); +DEVICE_ATTR_SEC_CSK_RO(pr, PR_PROG_ADDR + CSK_VEC_OFFSET); + #define FLASH_COUNT_SIZE 4096 /* count stored as inverted bit vector */ static ssize_t flash_count_show(struct device *dev, @@ -119,6 +164,9 @@ static struct attribute *m10bmc_security_attrs[] = { &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, }; From patchwork Mon May 17 02:31:59 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Moritz Fischer X-Patchwork-Id: 12260797 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.0 required=3.0 tests=BAYES_00,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9D3F1C433B4 for ; Mon, 17 May 2021 02:33:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 823066117A for ; Mon, 17 May 2021 02:33:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232417AbhEQCeS (ORCPT ); Sun, 16 May 2021 22:34:18 -0400 Received: from mail-pj1-f41.google.com ([209.85.216.41]:33673 "EHLO mail-pj1-f41.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233425AbhEQCeS (ORCPT ); Sun, 16 May 2021 22:34:18 -0400 Received: by mail-pj1-f41.google.com with SMTP id b13-20020a17090a8c8db029015cd97baea9so3720292pjo.0 for ; Sun, 16 May 2021 19:33:02 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=+YrGzZ6MmEiwtx5btv++wc9SzwmuGUZDBQtwH1wHT74=; b=d3rMoty76HyEFeyQsIYqKtjLNWbOJ32gjMyIoWX9hYb/E3I8ID10X2XZdqIV+7WQBO hlqQUikZMRaDiT4ddZB6qKNtpBv0Aw5O0sje/K51qMmsHlm134PZ1D2FMh8TiMIPI7IS 4Eg4FvCb9PuW9RfJw26NOLLosNAE+FWNiwQLRltZ7bLHSz8r2u7Rw6nBlbB389m6Yipt nw457x0PmlWnSEVBjUWFQvnNxR7Q6y6fZdGS1kM+KeSwuf5fwizKSd+mIAMhmTcIoFPR eIXGZ1HqH2Cd4olbYdvrIY78UdeHoeX68/sGiRLf0t1m+pu5miCTwW4aOU54gMAMJdy9 KrOg== X-Gm-Message-State: AOAM530XqiS2LUVMSwQvEGGXvGHSri+Yv/lVuzfdxkR42BzfHghPoAgI EOFf3NdAtykRQCs/ct2hDIM= X-Google-Smtp-Source: ABdhPJzYln4uJOync0CY3rC7qNIq9+FjrVS1f6tH3kxxcp4PxJ5olpwYhGMyIiHs7djNTnrDpdiyWA== X-Received: by 2002:a17:902:a58b:b029:ee:d13a:2642 with SMTP id az11-20020a170902a58bb02900eed13a2642mr58095628plb.35.1621218782409; Sun, 16 May 2021 19:33:02 -0700 (PDT) Received: from localhost ([2601:647:5b00:1161:a4cc:eef9:fbc0:2781]) by smtp.gmail.com with ESMTPSA id b12sm5436327pgs.52.2021.05.16.19.33.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 May 2021 19:33:01 -0700 (PDT) From: Moritz Fischer To: gregkh@linuxfoundation.org Cc: linux-fpga@vger.kernel.org, moritzf@google.com, Moritz Fischer , Russ Weight Subject: [PATCH 11/12] fpga: m10bmc-sec: add max10 secure update functions Date: Sun, 16 May 2021 19:31:59 -0700 Message-Id: <20210517023200.52707-12-mdf@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210517023200.52707-1-mdf@kernel.org> References: <20210517023200.52707-1-mdf@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org From: Russ Weight Extend the MAX10 BMC Secure Update driver to include the functions that enable secure updates of BMC images, FPGA images, etc. Signed-off-by: Russ Weight Signed-off-by: Moritz Fischer --- drivers/fpga/intel-m10-bmc-secure.c | 310 +++++++++++++++++++++++++++- 1 file changed, 309 insertions(+), 1 deletion(-) diff --git a/drivers/fpga/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c index 87e16c146569..9d45312001a3 100644 --- a/drivers/fpga/intel-m10-bmc-secure.c +++ b/drivers/fpga/intel-m10-bmc-secure.c @@ -180,7 +180,315 @@ static const struct attribute_group *m10bmc_sec_attr_groups[] = { NULL, }; -static const struct fpga_sec_mgr_ops m10bmc_sops = { }; +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 fpga_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 FPGA_SEC_ERR_RW_ERROR; + + if (rsu_prog(doorbell) != RSU_PROG_IDLE && + rsu_prog(doorbell) != RSU_PROG_RSU_DONE) { + log_error_regs(sec, doorbell); + return FPGA_SEC_ERR_BUSY; + } + + return FPGA_SEC_ERR_NONE; +} + +static inline bool rsu_start_done(u32 doorbell) +{ + u32 status, progress; + + if (doorbell & DRBL_RSU_REQUEST) + return false; + + status = rsu_stat(doorbell); + if (status == RSU_STAT_ERASE_FAIL || status == RSU_STAT_WEAROUT) + return true; + + progress = rsu_prog(doorbell); + if (progress != RSU_PROG_IDLE && progress != RSU_PROG_RSU_DONE) + return true; + + return false; +} + +static enum fpga_sec_err rsu_update_init(struct m10bmc_sec *sec) +{ + u32 doorbell, status; + int ret; + + ret = regmap_update_bits(sec->m10bmc->regmap, + M10BMC_SYS_BASE + M10BMC_DOORBELL, + DRBL_RSU_REQUEST | DRBL_HOST_STATUS, + DRBL_RSU_REQUEST | + FIELD_PREP(DRBL_HOST_STATUS, + HOST_STATUS_IDLE)); + if (ret) + return FPGA_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 FPGA_SEC_ERR_TIMEOUT; + } else if (ret) { + return FPGA_SEC_ERR_RW_ERROR; + } + + status = rsu_stat(doorbell); + if (status == RSU_STAT_WEAROUT) { + dev_warn(sec->dev, "Excessive flash update count detected\n"); + return FPGA_SEC_ERR_WEAROUT; + } else if (status == RSU_STAT_ERASE_FAIL) { + log_error_regs(sec, doorbell); + return FPGA_SEC_ERR_HW_ERROR; + } + + return FPGA_SEC_ERR_NONE; +} + +static enum fpga_sec_err rsu_prog_ready(struct m10bmc_sec *sec) +{ + unsigned long poll_timeout; + u32 doorbell, progress; + int ret; + + ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell); + if (ret) + return FPGA_SEC_ERR_RW_ERROR; + + poll_timeout = jiffies + msecs_to_jiffies(RSU_PREP_TIMEOUT_MS); + while (rsu_prog(doorbell) == RSU_PROG_PREPARE) { + msleep(RSU_PREP_INTERVAL_MS); + if (time_after(jiffies, poll_timeout)) + break; + + ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell); + if (ret) + return FPGA_SEC_ERR_RW_ERROR; + } + + progress = rsu_prog(doorbell); + if (progress == RSU_PROG_PREPARE) { + log_error_regs(sec, doorbell); + return FPGA_SEC_ERR_TIMEOUT; + } else if (progress != RSU_PROG_READY) { + log_error_regs(sec, doorbell); + return FPGA_SEC_ERR_HW_ERROR; + } + + return FPGA_SEC_ERR_NONE; +} + +static enum fpga_sec_err rsu_send_data(struct m10bmc_sec *sec) +{ + u32 doorbell; + int ret; + + ret = regmap_update_bits(sec->m10bmc->regmap, + M10BMC_SYS_BASE + M10BMC_DOORBELL, + DRBL_HOST_STATUS, + FIELD_PREP(DRBL_HOST_STATUS, + HOST_STATUS_WRITE_DONE)); + if (ret) + return FPGA_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 FPGA_SEC_ERR_TIMEOUT; + } else if (ret) { + return FPGA_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 FPGA_SEC_ERR_HW_ERROR; + } + + return FPGA_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: + 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 fpga_sec_err m10bmc_sec_prepare(struct fpga_sec_mgr *smgr) +{ + struct m10bmc_sec *sec = smgr->priv; + enum fpga_sec_err ret; + + if (smgr->remaining_size > M10BMC_STAGING_SIZE) + return FPGA_SEC_ERR_INVALID_SIZE; + + ret = rsu_check_idle(sec); + if (ret != FPGA_SEC_ERR_NONE) + return ret; + + ret = rsu_update_init(sec); + if (ret != FPGA_SEC_ERR_NONE) + return ret; + + return rsu_prog_ready(sec); +} + +#define WRITE_BLOCK_SIZE 0x4000 /* Update remaining_size every 0x4000 bytes */ + +static enum fpga_sec_err +m10bmc_sec_write_blk(struct fpga_sec_mgr *smgr, u32 offset) +{ + struct m10bmc_sec *sec = smgr->priv; + unsigned int stride = regmap_get_reg_stride(sec->m10bmc->regmap); + u32 doorbell, blk_size; + int ret; + + ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell); + if (ret) { + return FPGA_SEC_ERR_RW_ERROR; + } else if (rsu_prog(doorbell) != RSU_PROG_READY) { + log_error_regs(sec, doorbell); + return FPGA_SEC_ERR_HW_ERROR; + } + + blk_size = min_t(u32, smgr->remaining_size, WRITE_BLOCK_SIZE); + ret = regmap_bulk_write(sec->m10bmc->regmap, + M10BMC_STAGING_BASE + offset, + (void *)smgr->data + offset, + (blk_size + stride - 1) / stride); + + if (ret) + return FPGA_SEC_ERR_RW_ERROR; + + smgr->remaining_size -= blk_size; + return FPGA_SEC_ERR_NONE; +} + +/* + * m10bmc_sec_poll_complete() is called after handing things off to + * the BMC firmware. Depending on the type of update, it could be + * 30+ minutes before the BMC firmware completes the update. The + * smgr->driver_unload check allows the driver to be unloaded, + * but the BMC firmware will continue the update and no further + * secure updates can be started for this device until the update + * is complete. + */ +static enum fpga_sec_err m10bmc_sec_poll_complete(struct fpga_sec_mgr *smgr) +{ + struct m10bmc_sec *sec = smgr->priv; + unsigned long poll_timeout; + enum fpga_sec_err result; + u32 doorbell; + int ret; + + result = rsu_send_data(sec); + if (result != FPGA_SEC_ERR_NONE) + return result; + + poll_timeout = jiffies + msecs_to_jiffies(RSU_COMPLETE_TIMEOUT_MS); + do { + msleep(RSU_COMPLETE_INTERVAL_MS); + ret = rsu_check_complete(sec, &doorbell); + if (smgr->driver_unload) + return FPGA_SEC_ERR_CANCELED; + } while (ret == -EAGAIN && !time_after(jiffies, poll_timeout)); + + if (ret == -EAGAIN) { + log_error_regs(sec, doorbell); + return FPGA_SEC_ERR_TIMEOUT; + } else if (ret == -EIO) { + return FPGA_SEC_ERR_RW_ERROR; + } else if (ret) { + log_error_regs(sec, doorbell); + return FPGA_SEC_ERR_HW_ERROR; + } + + return FPGA_SEC_ERR_NONE; +} + +static enum fpga_sec_err m10bmc_sec_cancel(struct fpga_sec_mgr *smgr) +{ + struct m10bmc_sec *sec = smgr->priv; + u32 doorbell; + int ret; + + ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell); + if (ret) + return FPGA_SEC_ERR_RW_ERROR; + + if (rsu_prog(doorbell) != RSU_PROG_READY) + return FPGA_SEC_ERR_BUSY; + + ret = regmap_update_bits(sec->m10bmc->regmap, + M10BMC_SYS_BASE + M10BMC_DOORBELL, + DRBL_HOST_STATUS, + FIELD_PREP(DRBL_HOST_STATUS, + HOST_STATUS_ABORT_RSU)); + + return ret ? FPGA_SEC_ERR_RW_ERROR : FPGA_SEC_ERR_NONE; +} + +static const struct fpga_sec_mgr_ops m10bmc_sops = { + .prepare = m10bmc_sec_prepare, + .write_blk = m10bmc_sec_write_blk, + .poll_complete = m10bmc_sec_poll_complete, + .cancel = m10bmc_sec_cancel, +}; static int m10bmc_secure_probe(struct platform_device *pdev) { From patchwork Mon May 17 02:32:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Moritz Fischer X-Patchwork-Id: 12260799 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.0 required=3.0 tests=BAYES_00,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 637DBC433B4 for ; Mon, 17 May 2021 02:33:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 47FDE6117A for ; Mon, 17 May 2021 02:33:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233501AbhEQCeV (ORCPT ); Sun, 16 May 2021 22:34:21 -0400 Received: from mail-pf1-f182.google.com ([209.85.210.182]:44977 "EHLO mail-pf1-f182.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233425AbhEQCeU (ORCPT ); Sun, 16 May 2021 22:34:20 -0400 Received: by mail-pf1-f182.google.com with SMTP id 22so3558623pfv.11 for ; Sun, 16 May 2021 19:33:04 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=zEm0VkDELCCVZA8jXceu1efKCQnTnSl7+Cx9bupm+XI=; b=p5TR464NAF46/HOwmvdtHglRoif3fwW6CxidqQpeWl8g7hx9IaWhZxrURYHEVys0I2 2dD8fw3aL8UqeT/qLYAHXszrJCJYgGr4KdtVsRazL3t5v4oSJydOYMsZmWxtER06qcJP nTOOrn4Hfj9RPW4aYnf4MV2kOkHSWPEV2Dr5guCrYwvv/BW0jg6iqtoI2Piy84wSfowE dK/JEX9dqko4nGjjeeNuBaho6WysI5jA8IyFaJG728JYOGGpVK71IeT/mApChTGFqcVN +/Ta+WfKMWTf6azIf1HXUiY5r5fpba4Oo4mqkdevDliKYJ+ppTU7kQvbUnAPdUDq7PeW HcKQ== X-Gm-Message-State: AOAM532IIgAdN25eHg2Ht/VKz7hZU7X4ZcF/Tw3j9aqO9qF9xXIMA9cB jeJ51nOL8diKSVI0Fi6JIrQ= X-Google-Smtp-Source: ABdhPJxVLTWzkSMXEGdIZr7W34QbcI9onWvjeSZxQNqpGMYQ4+K4bzPulkww2DKxTJKErYAZYo50AQ== X-Received: by 2002:a63:935b:: with SMTP id w27mr28826615pgm.264.1621218784044; Sun, 16 May 2021 19:33:04 -0700 (PDT) Received: from localhost ([2601:647:5b00:1161:a4cc:eef9:fbc0:2781]) by smtp.gmail.com with ESMTPSA id j189sm8769596pfd.21.2021.05.16.19.33.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 May 2021 19:33:03 -0700 (PDT) From: Moritz Fischer To: gregkh@linuxfoundation.org Cc: linux-fpga@vger.kernel.org, moritzf@google.com, Moritz Fischer , Russ Weight Subject: [PATCH 12/12] fpga: m10bmc-sec: add max10 get_hw_errinfo callback func Date: Sun, 16 May 2021 19:32:00 -0700 Message-Id: <20210517023200.52707-13-mdf@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210517023200.52707-1-mdf@kernel.org> References: <20210517023200.52707-1-mdf@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org From: Russ Weight Extend the MAX10 BMC Secure Update 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 Signed-off-by: Moritz Fischer --- drivers/fpga/intel-m10-bmc-secure.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/fpga/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c index 9d45312001a3..bdf87ec125fe 100644 --- a/drivers/fpga/intel-m10-bmc-secure.c +++ b/drivers/fpga/intel-m10-bmc-secure.c @@ -483,11 +483,33 @@ static enum fpga_sec_err m10bmc_sec_cancel(struct fpga_sec_mgr *smgr) return ret ? FPGA_SEC_ERR_RW_ERROR : FPGA_SEC_ERR_NONE; } +#define HW_ERRINFO_POISON GENMASK(31, 0) +static u64 m10bmc_sec_hw_errinfo(struct fpga_sec_mgr *smgr) +{ + struct m10bmc_sec *sec = smgr->priv; + u32 auth_result = HW_ERRINFO_POISON; + u32 doorbell = HW_ERRINFO_POISON; + + switch (smgr->err_code) { + case FPGA_SEC_ERR_HW_ERROR: + case FPGA_SEC_ERR_TIMEOUT: + case FPGA_SEC_ERR_BUSY: + case FPGA_SEC_ERR_WEAROUT: + m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell); + m10bmc_sys_read(sec->m10bmc, M10BMC_AUTH_RESULT, &auth_result); + + return (u64)doorbell << 32 | (u64)auth_result; + default: + return 0; + } +} + static const struct fpga_sec_mgr_ops m10bmc_sops = { .prepare = m10bmc_sec_prepare, .write_blk = m10bmc_sec_write_blk, .poll_complete = m10bmc_sec_poll_complete, .cancel = m10bmc_sec_cancel, + .get_hw_errinfo = m10bmc_sec_hw_errinfo, }; static int m10bmc_secure_probe(struct platform_device *pdev)