[RFC PATCH 2/3] drivers: fpga: Add user-key encrypted FPGA Image loading support

From: Nava kishore Manne
Date: Wed Nov 22 2023 - 00:44:29 EST


Adds parse_aes_key() callback to fpga_manager_ops, It will read the
AES key from firmware to support user-key encrypted bitstream loading.

Signed-off-by: Nava kishore Manne <nava.kishore.manne@xxxxxxx>
---
drivers/fpga/fpga-mgr.c | 86 ++++++++++++++++++++++++++++++++---
drivers/fpga/of-fpga-region.c | 10 ++++
include/linux/fpga/fpga-mgr.h | 8 ++++
3 files changed, 97 insertions(+), 7 deletions(-)

diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c
index 06651389c592..c8e20e8f4b6f 100644
--- a/drivers/fpga/fpga-mgr.c
+++ b/drivers/fpga/fpga-mgr.c
@@ -83,6 +83,15 @@ static inline int fpga_mgr_parse_header(struct fpga_manager *mgr,
return 0;
}

+static inline int fpga_mgr_parse_aes_key(struct fpga_manager *mgr,
+ struct fpga_image_info *info,
+ const char *buf, size_t count)
+{
+ if (mgr->mops->parse_aes_key)
+ return mgr->mops->parse_aes_key(mgr, info, buf, count);
+ return 0;
+}
+
static inline int fpga_mgr_write_init(struct fpga_manager *mgr,
struct fpga_image_info *info,
const char *buf, size_t count)
@@ -559,6 +568,43 @@ static int fpga_mgr_firmware_load(struct fpga_manager *mgr,
return ret;
}

+/**
+ * fpga_mgr_get_aes_key - request aes key form the firmware class
+ * @mgr: fpga manager
+ * @info: fpga image specific information
+ * @image_name: name of image file on the aes key firmware search path
+ *
+ *
+ * Request an aes key image using the firmware class, then Step the low level
+ * fpga manager through the device-specific steps. Update the state before each
+ * step to provide info on what step failed if there is a failure.
+ *
+ * Return: 0 on success, negative error code otherwise.
+ */
+static int fpga_mgr_get_aes_key(struct fpga_manager *mgr,
+ struct fpga_image_info *info,
+ const char *image_name,
+ const struct firmware *fw)
+{
+ struct device *dev = &mgr->dev;
+ int ret;
+
+ dev_info(dev, "Get Aes-key: %s to %s\n", image_name, mgr->name);
+
+ mgr->state = FPGA_MGR_STATE_FIRMWARE_REQ;
+
+ ret = request_firmware(&fw, image_name, dev);
+ if (ret) {
+ mgr->state = FPGA_MGR_STATE_FIRMWARE_REQ_ERR;
+ dev_err(dev, "Error requesting firmware %s\n", image_name);
+ return ret;
+ }
+
+ ret = fpga_mgr_parse_aes_key(mgr, info, fw->data, fw->size);
+
+ return ret;
+}
+
/**
* fpga_mgr_load - load FPGA from scatter/gather table, buffer, or firmware
* @mgr: fpga manager
@@ -571,15 +617,41 @@ static int fpga_mgr_firmware_load(struct fpga_manager *mgr,
*/
int fpga_mgr_load(struct fpga_manager *mgr, struct fpga_image_info *info)
{
+ const struct firmware *fw;
+ int ret;
+
info->header_size = mgr->mops->initial_header_size;

- if (info->sgt)
- return fpga_mgr_buf_load_sg(mgr, info, info->sgt);
- if (info->buf && info->count)
- return fpga_mgr_buf_load(mgr, info, info->buf, info->count);
- if (info->firmware_name)
- return fpga_mgr_firmware_load(mgr, info, info->firmware_name);
- return -EINVAL;
+ if (info->encrypted_key_name) {
+ ret = fpga_mgr_get_aes_key(mgr, info,
+ info->encrypted_key_name, fw);
+ if (ret)
+ return ret;
+
+ info->flags |= FPGA_MGR_USRKEY_ENCRYPTED_BITSTREAM;
+ }
+
+ if (info->sgt) {
+ ret = fpga_mgr_buf_load_sg(mgr, info, info->sgt);
+ if (ret)
+ goto free_fw;
+ } else if (info->buf && info->count) {
+ ret = fpga_mgr_buf_load(mgr, info, info->buf, info->count);
+ if (ret)
+ goto free_fw;
+ } else if (info->firmware_name) {
+ ret = fpga_mgr_firmware_load(mgr, info, info->firmware_name);
+ if (ret)
+ goto free_fw;
+ } else {
+ ret = -EINVAL;
+ }
+
+free_fw:
+ if (info->encrypted_key_name)
+ release_firmware(fw);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(fpga_mgr_load);

diff --git a/drivers/fpga/of-fpga-region.c b/drivers/fpga/of-fpga-region.c
index a6affd83f275..e9ddece4b82d 100644
--- a/drivers/fpga/of-fpga-region.c
+++ b/drivers/fpga/of-fpga-region.c
@@ -196,6 +196,7 @@ of_fpga_region_parse_ov(struct fpga_region *region,
struct device_node *overlay)
{
struct device *dev = &region->dev;
+ const char *encrypted_key_name;
struct fpga_image_info *info;
const char *firmware_name;
int ret;
@@ -238,6 +239,15 @@ of_fpga_region_parse_ov(struct fpga_region *region,
return ERR_PTR(-ENOMEM);
}

+ if (!of_property_read_string(overlay, "encrypted-key-name",
+ &encrypted_key_name)) {
+ info->encrypted_key_name = devm_kstrdup(dev,
+ encrypted_key_name,
+ GFP_KERNEL);
+ if (!info->encrypted_key_name)
+ return ERR_PTR(-ENOMEM);
+ }
+
of_property_read_u32(overlay, "region-unfreeze-timeout-us",
&info->enable_timeout_us);

diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h
index 54f63459efd6..303264d89922 100644
--- a/include/linux/fpga/fpga-mgr.h
+++ b/include/linux/fpga/fpga-mgr.h
@@ -71,12 +71,15 @@ enum fpga_mgr_states {
* %FPGA_MGR_BITSTREAM_LSB_FIRST: SPI bitstream bit order is LSB first
*
* %FPGA_MGR_COMPRESSED_BITSTREAM: FPGA bitstream is compressed
+ *
+ * %FPGA_MGR_USRKEY_ENCRYPTED_BITSTREAM: indicates bitstream is encrypted with user-key
*/
#define FPGA_MGR_PARTIAL_RECONFIG BIT(0)
#define FPGA_MGR_EXTERNAL_CONFIG BIT(1)
#define FPGA_MGR_ENCRYPTED_BITSTREAM BIT(2)
#define FPGA_MGR_BITSTREAM_LSB_FIRST BIT(3)
#define FPGA_MGR_COMPRESSED_BITSTREAM BIT(4)
+#define FPGA_MGR_USRKEY_ENCRYPTED_BITSTREAM BIT(5)

/**
* struct fpga_image_info - information specific to an FPGA image
@@ -86,6 +89,7 @@ enum fpga_mgr_states {
* @config_complete_timeout_us: maximum time for FPGA to switch to operating
* status in the write_complete op.
* @firmware_name: name of FPGA image firmware file
+ * @encrypted_key_name: name of the FPGA image encrypted user-key file
* @sgt: scatter/gather table containing FPGA image
* @buf: contiguous buffer containing FPGA image
* @count: size of buf
@@ -102,6 +106,7 @@ struct fpga_image_info {
u32 disable_timeout_us;
u32 config_complete_timeout_us;
char *firmware_name;
+ char *encrypted_key_name;
struct sg_table *sgt;
const char *buf;
size_t count;
@@ -172,6 +177,9 @@ struct fpga_manager_ops {
bool skip_header;
enum fpga_mgr_states (*state)(struct fpga_manager *mgr);
u64 (*status)(struct fpga_manager *mgr);
+ int (*parse_aes_key)(struct fpga_manager *mgr,
+ struct fpga_image_info *info,
+ const char *buf, size_t count);
int (*parse_header)(struct fpga_manager *mgr,
struct fpga_image_info *info,
const char *buf, size_t count);
--
2.25.1