|
@@ -302,6 +302,69 @@ static int sev_ioctl_do_pek_pdh_gen(int cmd, struct sev_issue_cmd *argp)
|
|
|
return __sev_do_cmd_locked(cmd, 0, &argp->error);
|
|
|
}
|
|
|
|
|
|
+static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp)
|
|
|
+{
|
|
|
+ struct sev_user_data_pek_csr input;
|
|
|
+ struct sev_data_pek_csr *data;
|
|
|
+ void *blob = NULL;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (copy_from_user(&input, (void __user *)argp->data, sizeof(input)))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
|
|
|
+ if (!data)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ /* userspace wants to query CSR length */
|
|
|
+ if (!input.address || !input.length)
|
|
|
+ goto cmd;
|
|
|
+
|
|
|
+ /* allocate a physically contiguous buffer to store the CSR blob */
|
|
|
+ if (!access_ok(VERIFY_WRITE, input.address, input.length) ||
|
|
|
+ input.length > SEV_FW_BLOB_MAX_SIZE) {
|
|
|
+ ret = -EFAULT;
|
|
|
+ goto e_free;
|
|
|
+ }
|
|
|
+
|
|
|
+ blob = kmalloc(input.length, GFP_KERNEL);
|
|
|
+ if (!blob) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto e_free;
|
|
|
+ }
|
|
|
+
|
|
|
+ data->address = __psp_pa(blob);
|
|
|
+ data->len = input.length;
|
|
|
+
|
|
|
+cmd:
|
|
|
+ if (psp_master->sev_state == SEV_STATE_UNINIT) {
|
|
|
+ ret = __sev_platform_init_locked(&argp->error);
|
|
|
+ if (ret)
|
|
|
+ goto e_free_blob;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = __sev_do_cmd_locked(SEV_CMD_PEK_CSR, data, &argp->error);
|
|
|
+
|
|
|
+ /* If we query the CSR length, FW responded with expected data. */
|
|
|
+ input.length = data->len;
|
|
|
+
|
|
|
+ if (copy_to_user((void __user *)argp->data, &input, sizeof(input))) {
|
|
|
+ ret = -EFAULT;
|
|
|
+ goto e_free_blob;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (blob) {
|
|
|
+ if (copy_to_user((void __user *)input.address, blob, input.length))
|
|
|
+ ret = -EFAULT;
|
|
|
+ }
|
|
|
+
|
|
|
+e_free_blob:
|
|
|
+ kfree(blob);
|
|
|
+e_free:
|
|
|
+ kfree(data);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
|
|
|
{
|
|
|
void __user *argp = (void __user *)arg;
|
|
@@ -336,6 +399,9 @@ static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
|
|
|
case SEV_PDH_GEN:
|
|
|
ret = sev_ioctl_do_pek_pdh_gen(SEV_CMD_PDH_GEN, &input);
|
|
|
break;
|
|
|
+ case SEV_PEK_CSR:
|
|
|
+ ret = sev_ioctl_do_pek_csr(&input);
|
|
|
+ break;
|
|
|
default:
|
|
|
ret = -EINVAL;
|
|
|
goto out;
|