@@ -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: December 2020
+KernelVersion: 5.11
+Contact: Russ Weight <russell.h.weight@intel.com>
+Description: Write-only. Write a "1" to this file to request
+ that a current update be canceled. This request
+ will be rejected (EBUSY) if the programming phase
+ has already started or (ENODEV) if there is no
+ update in progress.
+
What: /sys/class/fpga_sec_mgr/fpga_secX/update/status
Date: December 2020
KernelVersion: 5.11
@@ -45,6 +45,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) {
+ 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);
@@ -76,16 +93,20 @@ 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);
+ if (progress_transition(smgr, FPGA_SEC_PROG_WRITING))
+ goto done;
+
size = smgr->remaining_size;
- while (size) {
+ while (size && !smgr->request_cancel) {
blk_size = min_t(u32, size, WRITE_BLOCK_SIZE);
size -= blk_size;
ret = smgr->sops->write_blk(smgr, offset, blk_size);
@@ -98,7 +119,9 @@ static void fpga_sec_mgr_update(struct work_struct *work)
offset += blk_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);
@@ -235,6 +258,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);
@@ -245,8 +269,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,
@@ -468,6 +516,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);
@@ -73,6 +73,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;
};