143 lines
3.4 KiB
C
143 lines
3.4 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* HYGON CSV interface
|
|
*
|
|
* Copyright (C) 2024 Hygon Info Technologies Ltd.
|
|
*
|
|
* Author: Liyang Han <hanliyang@hygon.cn>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
|
|
#include <linux/psp.h>
|
|
#include <linux/psp-hygon.h>
|
|
#include <uapi/linux/psp-hygon.h>
|
|
|
|
#include "psp-dev.h"
|
|
|
|
/*
|
|
* Hygon CSV build info:
|
|
* Hygon CSV build info is 32-bit in length other than 8-bit as that
|
|
* in AMD SEV.
|
|
*/
|
|
u32 hygon_csv_build;
|
|
|
|
/*
|
|
* csv_update_api_version used to update the api version of HYGON CSV
|
|
* firmwareat driver side.
|
|
* Currently, we only need to update @hygon_csv_build.
|
|
*/
|
|
void csv_update_api_version(struct sev_user_data_status *status)
|
|
{
|
|
if (status) {
|
|
hygon_csv_build = (status->flags >> 9) |
|
|
((u32)status->build << 23);
|
|
}
|
|
}
|
|
|
|
int csv_cmd_buffer_len(int cmd)
|
|
{
|
|
switch (cmd) {
|
|
case CSV_CMD_HGSC_CERT_IMPORT: return sizeof(struct csv_data_hgsc_cert_import);
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
static int csv_ioctl_do_hgsc_import(struct sev_issue_cmd *argp)
|
|
{
|
|
struct csv_user_data_hgsc_cert_import input;
|
|
struct csv_data_hgsc_cert_import *data;
|
|
void *hgscsk_blob, *hgsc_blob;
|
|
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;
|
|
|
|
/* copy HGSCSK certificate blobs from userspace */
|
|
hgscsk_blob = psp_copy_user_blob(input.hgscsk_cert_address, input.hgscsk_cert_len);
|
|
if (IS_ERR(hgscsk_blob)) {
|
|
ret = PTR_ERR(hgscsk_blob);
|
|
goto e_free;
|
|
}
|
|
|
|
data->hgscsk_cert_address = __psp_pa(hgscsk_blob);
|
|
data->hgscsk_cert_len = input.hgscsk_cert_len;
|
|
|
|
/* copy HGSC certificate blobs from userspace */
|
|
hgsc_blob = psp_copy_user_blob(input.hgsc_cert_address, input.hgsc_cert_len);
|
|
if (IS_ERR(hgsc_blob)) {
|
|
ret = PTR_ERR(hgsc_blob);
|
|
goto e_free_hgscsk;
|
|
}
|
|
|
|
data->hgsc_cert_address = __psp_pa(hgsc_blob);
|
|
data->hgsc_cert_len = input.hgsc_cert_len;
|
|
|
|
ret = hygon_psp_hooks.__sev_do_cmd_locked(CSV_CMD_HGSC_CERT_IMPORT,
|
|
data, &argp->error);
|
|
|
|
kfree(hgsc_blob);
|
|
e_free_hgscsk:
|
|
kfree(hgscsk_blob);
|
|
e_free:
|
|
kfree(data);
|
|
return ret;
|
|
}
|
|
|
|
static long csv_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
|
|
{
|
|
void __user *argp = (void __user *)arg;
|
|
struct sev_issue_cmd input;
|
|
int ret = -EFAULT;
|
|
|
|
if (!hygon_psp_hooks.sev_dev_hooks_installed)
|
|
return -ENODEV;
|
|
|
|
if (!psp_master || !psp_master->sev_data)
|
|
return -ENODEV;
|
|
|
|
if (ioctl != SEV_ISSUE_CMD)
|
|
return -EINVAL;
|
|
|
|
if (copy_from_user(&input, argp, sizeof(struct sev_issue_cmd)))
|
|
return -EFAULT;
|
|
|
|
if (input.cmd > CSV_MAX)
|
|
return -EINVAL;
|
|
|
|
mutex_lock(hygon_psp_hooks.sev_cmd_mutex);
|
|
|
|
switch (input.cmd) {
|
|
case CSV_HGSC_CERT_IMPORT:
|
|
ret = csv_ioctl_do_hgsc_import(&input);
|
|
break;
|
|
default:
|
|
/*
|
|
* If the command is compatible between CSV and SEV, the
|
|
* native implementation of the driver is invoked.
|
|
* Release the mutex before calling the native ioctl function
|
|
* because it will acquires the mutex.
|
|
*/
|
|
mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
|
|
return hygon_psp_hooks.sev_ioctl(file, ioctl, arg);
|
|
}
|
|
|
|
if (copy_to_user(argp, &input, sizeof(struct sev_issue_cmd)))
|
|
ret = -EFAULT;
|
|
|
|
mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
|
|
|
|
return ret;
|
|
}
|
|
|
|
const struct file_operations csv_fops = {
|
|
.owner = THIS_MODULE,
|
|
.unlocked_ioctl = csv_ioctl,
|
|
};
|