| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Copyright (C) 2020, Intel Corporation |
| */ |
| |
| #include <linux/arm-smccc.h> |
| #include <linux/bitfield.h> |
| #include <linux/completion.h> |
| #include <linux/delay.h> |
| #include <linux/firmware.h> |
| #include <linux/fs.h> |
| #include <linux/hw_random.h> |
| #include <linux/kobject.h> |
| #include <linux/miscdevice.h> |
| #include <linux/module.h> |
| #include <linux/mutex.h> |
| #include <linux/of.h> |
| #include <linux/of_platform.h> |
| #include <linux/platform_device.h> |
| #include <linux/firmware/intel/stratix10-svc-client.h> |
| #include <linux/string.h> |
| #include <linux/slab.h> |
| #include <linux/sysfs.h> |
| #include <linux/uaccess.h> |
| |
| #include <uapi/linux/intel_fcs-ioctl.h> |
| #include "intel_fcs_smmu.h" |
| |
| #define RANDOM_NUMBER_SIZE 32 |
| #define RANDOM_NUMBER_EXT_SIZE 4080 |
| #define RANDOM_NUMBER_EXT_OFFSET 12 |
| #define FILE_NAME_SIZE 32 |
| #define PS_BUF_SIZE 64 |
| #define SMMU_BUF_SIZE 128 |
| #define SHA384_SIZE 48 |
| #define INVALID_STATUS 0xFFFFFFFF |
| #define INVALID_ID 0xFFFFFFFF |
| #define ASYNC_POLL_SERVICE 0x00004F4E |
| |
| #define MIN_SDOS_BUF_SZ 16 |
| #define MAX_SDOS_BUF_SZ 32768 |
| #define DEC_MIN_SZ 72 |
| #define DEC_MAX_SZ 32712 |
| #define ENC_MIN_SZ 120 |
| #define ENC_MAX_SZ 32760 |
| |
| #define SUBKEY_CMD_MAX_SZ 4092 |
| #define SUBKEY_RSP_MAX_SZ 820 |
| #define MEASUREMENT_CMD_MAX_SZ 4092 |
| #define MEASUREMENT_RSP_MAX_SZ 4092 |
| #define CERTIFICATE_RSP_MAX_SZ 4096 |
| |
| #define CRYPTO_EXPORTED_KEY_OBJECT_MAX_SZ 364 |
| #define CRYPTO_GET_KEY_INFO_MAX_SZ 144 |
| |
| #define CRYPTO_ECC_PARAM_SZ 4 |
| #define CRYPTO_ECC_DIGEST_SZ_OFFSET 4 |
| |
| #define AES_CRYPT_CMD_MAX_SZ SZ_4M /* set 4 Mb for now */ |
| #define AES_BUFFER_CMD_MAX_SZ 0xE600000 /* set 230 Mb */ |
| #define HMAC_CMD_MAX_SZ 0x1D600000 /* set 470 Mb */ |
| #define ECDSA_CMD_MAX_SZ 0x1D600000 /* set 470 Mb */ |
| #define SMMU_MAX_ALLOC_SZ 0x1E000000 /* set 480 Mb */ |
| #define AES_CRYPT_MODE_ECB 0 |
| #define AES_CRYPT_MODE_CBC 1 |
| #define AES_CRYPT_MODE_CTR 2 |
| #define AES_CRYPT_PARAM_SIZE_ECB 12 |
| #define AES_CRYPT_PARAM_SIZE_CBC_CTR 28 |
| |
| #define FCS_REQUEST_TIMEOUT (msecs_to_jiffies(SVC_FCS_REQUEST_TIMEOUT_MS)) |
| #define FCS_COMPLETED_TIMEOUT (msecs_to_jiffies(SVC_COMPLETED_TIMEOUT_MS)) |
| #define SIGMA_SESSION_ID_ONE 0x1 |
| #define SIGMA_UNKNOWN_SESSION 0xffffffff |
| |
| #define SRC_BUFFER_STARTING_L2_IDX 17 |
| #define get_buffer_addr(a)(a*2*1024*1024) |
| |
| #define SDM_SMMU_FW_MIN_VER 0x2722C |
| #define ATF_SMMU_FW_MAJOR_VER 0x2 |
| #define ATF_SMMU_FW_MIN_VER 0x1 |
| #define AGILEX_PLATFORM "agilex" |
| #define AGILEX_PLATFORM_STR_LEN 6 |
| |
| #define SDOS_DECRYPTION_ERROR_102 0x102 |
| #define SDOS_DECRYPTION_ERROR_103 0x103 |
| |
| /*SDM required minimun 8 bytes of data for crypto service*/ |
| #define CRYPTO_SERVICE_MIN_DATA_SIZE 8 |
| |
| /** |
| * struct socfpga_fcs_data - FCS platform data structure. |
| * @hwrng Flag to indicate support for HW random number generator. |
| */ |
| struct socfpga_fcs_data { |
| bool have_hwrng; |
| }; |
| |
| static char *source_ptr; |
| |
| typedef void (*fcs_callback)(struct stratix10_svc_client *client, |
| struct stratix10_svc_cb_data *data); |
| |
| static void fcs_atf_version_smmu_check_callback(struct stratix10_svc_client *client, |
| struct stratix10_svc_cb_data *data) |
| { |
| struct intel_fcs_priv *priv = client->priv; |
| |
| priv->status = data->status; |
| if (data->status == BIT(SVC_STATUS_OK)) { |
| if ((*((unsigned int *)data->kaddr1) >= ATF_SMMU_FW_MAJOR_VER) && |
| (*((unsigned int *)data->kaddr2) >= ATF_SMMU_FW_MIN_VER)) |
| priv->status = 0; |
| else |
| priv->status = -1; |
| } else if (data->status == BIT(SVC_STATUS_ERROR)) { |
| priv->status = *((unsigned int *)data->kaddr1); |
| dev_err(client->dev, "mbox_error=0x%x\n", priv->status); |
| } |
| |
| complete(&priv->completion); |
| } |
| |
| static void fcs_fw_version_callback(struct stratix10_svc_client *client, |
| struct stratix10_svc_cb_data *data) |
| { |
| struct intel_fcs_priv *priv = client->priv; |
| |
| priv->status = -1; |
| if (data->status == BIT(SVC_STATUS_OK)) { |
| if (*((unsigned int *)data->kaddr1) > SDM_SMMU_FW_MIN_VER) |
| priv->status = 0; |
| } else { |
| dev_err(client->dev, "Failed to get FW version %lu\n", |
| BIT(data->status)); |
| } |
| |
| complete(&priv->completion); |
| } |
| |
| static void fcs_data_callback(struct stratix10_svc_client *client, |
| struct stratix10_svc_cb_data *data) |
| { |
| struct intel_fcs_priv *priv = client->priv; |
| |
| if ((data->status == BIT(SVC_STATUS_OK)) || |
| (data->status == BIT(SVC_STATUS_COMPLETED))) { |
| priv->status = 0; |
| priv->kbuf = data->kaddr2; |
| priv->size = *((unsigned int *)data->kaddr3); |
| } else if (data->status == BIT(SVC_STATUS_ERROR)) { |
| priv->status = *((unsigned int *)data->kaddr1); |
| dev_err(client->dev, "error, mbox_error=0x%x\n", priv->status); |
| priv->kbuf = data->kaddr2; |
| priv->size = (data->kaddr3) ? |
| *((unsigned int *)data->kaddr3) : 0; |
| } else if ((data->status == BIT(SVC_STATUS_BUSY)) || |
| (data->status == BIT(SVC_STATUS_NO_RESPONSE))) { |
| priv->status = 0; |
| priv->kbuf = NULL; |
| priv->size = 0; |
| } else { |
| dev_err(client->dev, "rejected, invalid param\n"); |
| priv->status = -EINVAL; |
| priv->kbuf = NULL; |
| priv->size = 0; |
| } |
| |
| complete(&priv->completion); |
| } |
| |
| static void fcs_vab_callback(struct stratix10_svc_client *client, |
| struct stratix10_svc_cb_data *data) |
| { |
| struct intel_fcs_priv *priv = client->priv; |
| |
| if (data->status == BIT(SVC_STATUS_ERROR)) { |
| priv->status = *((unsigned int *)data->kaddr1); |
| dev_err(client->dev, "mbox_error=0x%x\n", priv->status); |
| } else if (data->status == BIT(SVC_STATUS_BUSY)) { |
| priv->status = -ETIMEDOUT; |
| dev_err(client->dev, "timeout to get completed status\n"); |
| } else if (data->status == BIT(SVC_STATUS_INVALID_PARAM)) { |
| priv->status = -EINVAL; |
| dev_err(client->dev, "request rejected\n"); |
| } else if (data->status == BIT(SVC_STATUS_OK)) { |
| priv->status = 0; |
| } else if (data->status == BIT(SVC_STATUS_NO_SUPPORT)) { |
| priv->status = -EINVAL; |
| dev_err(client->dev, "firmware doesn't support...\n"); |
| } else { |
| priv->status = -EINVAL; |
| dev_err(client->dev, "rejected, invalid param\n"); |
| } |
| |
| complete(&priv->completion); |
| } |
| |
| static void fcs_chipid_callback(struct stratix10_svc_client *client, |
| struct stratix10_svc_cb_data *data) |
| { |
| struct intel_fcs_priv *priv = client->priv; |
| |
| priv->status = data->status; |
| if (data->status == BIT(SVC_STATUS_OK)) { |
| priv->status = 0; |
| priv->cid_low = *((unsigned int *)data->kaddr2); |
| priv->cid_high = *((unsigned int *)data->kaddr3); |
| } else if (data->status == BIT(SVC_STATUS_ERROR)) { |
| priv->status = *((unsigned int *)data->kaddr1); |
| dev_err(client->dev, "mbox_error=0x%x\n", priv->status); |
| } |
| |
| complete(&priv->completion); |
| } |
| |
| static void fcs_attestation_callback(struct stratix10_svc_client *client, |
| struct stratix10_svc_cb_data *data) |
| { |
| struct intel_fcs_priv *priv = client->priv; |
| |
| priv->status = data->status; |
| if (data->status == BIT(SVC_STATUS_OK)) { |
| priv->status = 0; |
| priv->kbuf = data->kaddr2; |
| priv->size = *((unsigned int *)data->kaddr3); |
| } else if (data->status == BIT(SVC_STATUS_ERROR)) { |
| priv->status = *((unsigned int *)data->kaddr1); |
| dev_err(client->dev, "mbox_error=0x%x\n", priv->status); |
| } |
| |
| complete(&priv->completion); |
| } |
| |
| static void fcs_crypto_sessionid_callback(struct stratix10_svc_client *client, |
| struct stratix10_svc_cb_data *data) |
| { |
| struct intel_fcs_priv *priv = client->priv; |
| |
| priv->status = data->status; |
| if (data->status == BIT(SVC_STATUS_OK)) { |
| priv->status = 0; |
| priv->sid = *((unsigned int *)data->kaddr2); |
| } else if (data->status == BIT(SVC_STATUS_ERROR)) { |
| priv->status = *((unsigned int *)data->kaddr1); |
| dev_err(client->dev, "mbox_error=0x%x\n", priv->status); |
| } |
| |
| complete(&priv->completion); |
| } |
| |
| static void fcs_hwrng_callback(struct stratix10_svc_client *client, |
| struct stratix10_svc_cb_data *data) |
| { |
| struct intel_fcs_priv *priv = client->priv; |
| |
| priv->status = 0; |
| priv->kbuf = NULL; |
| priv->size = 0; |
| |
| if ((data->status == BIT(SVC_STATUS_OK)) || |
| (data->status == BIT(SVC_STATUS_COMPLETED))) { |
| priv->kbuf = data->kaddr2; |
| priv->size = *((unsigned int *)data->kaddr3); |
| } |
| |
| complete(&priv->completion); |
| } |
| |
| static void fcs_mbox_send_cmd_callback(struct stratix10_svc_client *client, |
| struct stratix10_svc_cb_data *data) |
| { |
| struct intel_fcs_priv *priv = client->priv; |
| |
| if (data->status == BIT(SVC_STATUS_OK)) { |
| priv->status = 0; |
| priv->size = *((unsigned int *)data->kaddr2); |
| } else if (data->status == BIT(SVC_STATUS_ERROR)) { |
| priv->status = *((unsigned int *)data->kaddr1); |
| dev_err(client->dev, "mbox_error=0x%x\n", priv->status); |
| } else if (data->status == BIT(SVC_STATUS_INVALID_PARAM)) { |
| priv->status = -EINVAL; |
| dev_err(client->dev, "request rejected\n"); |
| } else { |
| priv->status = -EINVAL; |
| dev_err(client->dev, "rejected, invalid param\n"); |
| } |
| |
| complete(&priv->completion); |
| } |
| |
| static void fcs_sdos_data_poll_callback(struct stratix10_svc_client *client, |
| struct stratix10_svc_cb_data *data) |
| { |
| struct intel_fcs_priv *priv = client->priv; |
| |
| if ((data->status == BIT(SVC_STATUS_OK)) || |
| (data->status == BIT(SVC_STATUS_COMPLETED))) { |
| priv->status = (data->kaddr1) ? |
| *((unsigned int *)data->kaddr1) : 0; |
| priv->kbuf = data->kaddr2; |
| priv->size = *((unsigned int *)data->kaddr3); |
| } else if (data->status == BIT(SVC_STATUS_ERROR)) { |
| priv->status = *((unsigned int *)data->kaddr1); |
| dev_err(client->dev, "error, mbox_error=0x%x\n", priv->status); |
| priv->kbuf = data->kaddr2; |
| priv->size = (data->kaddr3) ? |
| *((unsigned int *)data->kaddr3) : 0; |
| } else if ((data->status == BIT(SVC_STATUS_BUSY)) || |
| (data->status == BIT(SVC_STATUS_NO_RESPONSE))) { |
| priv->status = 0; |
| priv->kbuf = NULL; |
| priv->size = 0; |
| } else { |
| dev_err(client->dev, "rejected, invalid param\n"); |
| priv->status = -EINVAL; |
| priv->kbuf = NULL; |
| priv->size = 0; |
| } |
| |
| complete(&priv->completion); |
| } |
| |
| static void fcs_sdos_data_callback(struct stratix10_svc_client *client, |
| struct stratix10_svc_cb_data *data) |
| { |
| struct intel_fcs_priv *priv = client->priv; |
| |
| priv->status = data->status; |
| if (data->status == BIT(SVC_STATUS_OK)) { |
| priv->status = *((unsigned int *)data->kaddr1); |
| priv->kbuf = data->kaddr2; |
| priv->size = *((unsigned int *)data->kaddr3); |
| } else if (data->status == BIT(SVC_STATUS_ERROR)) { |
| priv->status = *((unsigned int *)data->kaddr1); |
| dev_err(client->dev, "mbox_error=0x%x\n", priv->status); |
| } |
| |
| complete(&priv->completion); |
| } |
| |
| static int fcs_request_service(struct intel_fcs_priv *priv, |
| void *msg, unsigned long timeout) |
| { |
| struct stratix10_svc_client_msg *p_msg = |
| (struct stratix10_svc_client_msg *)msg; |
| int ret; |
| |
| reinit_completion(&priv->completion); |
| |
| ret = stratix10_svc_send(priv->chan, p_msg); |
| if (ret) |
| return -EINVAL; |
| |
| ret = wait_for_completion_timeout(&priv->completion, |
| timeout); |
| if (!ret) { |
| dev_err(priv->client.dev, |
| "timeout waiting for SMC call\n"); |
| ret = -ETIMEDOUT; |
| } else |
| ret = 0; |
| |
| return ret; |
| } |
| |
| static void fcs_free_memory(struct intel_fcs_priv *priv, |
| void *buf1, void *buf2, void *buf3) |
| { |
| if (buf1) |
| stratix10_svc_free_memory(priv->chan, buf1); |
| |
| if (buf2) |
| stratix10_svc_free_memory(priv->chan, buf2); |
| |
| if (buf3) |
| stratix10_svc_free_memory(priv->chan, buf3); |
| } |
| |
| static void fcs_close_services(struct intel_fcs_priv *priv, |
| void *sbuf, void *dbuf) |
| { |
| fcs_free_memory(priv, sbuf, dbuf, NULL); |
| stratix10_svc_done(priv->chan); |
| mutex_unlock(&priv->lock); |
| } |
| |
| static long fcs_ioctl(struct file *file, unsigned int cmd, |
| unsigned long arg) |
| { |
| struct intel_fcs_dev_ioctl *data; |
| struct intel_fcs_priv *priv; |
| struct device *dev; |
| struct stratix10_svc_client_msg *msg; |
| const struct firmware *fw; |
| char filename[FILE_NAME_SIZE]; |
| size_t tsz, rsz, datasz, ud_sz; |
| uint32_t sid; |
| uint32_t kuid; |
| uint32_t cid; |
| void *s_buf; |
| void *d_buf; |
| void *ps_buf; |
| void *iv_field_buf; |
| void *input_file_pointer; |
| void *output_file_pointer; |
| unsigned int buf_sz, in_sz, out_sz; |
| uint32_t remaining_size, data_size, total_out_size; |
| uint32_t sign_size; |
| int ret = 0; |
| int i; |
| int timeout; |
| phys_addr_t src_addr; |
| phys_addr_t dst_addr; |
| |
| priv = container_of(file->private_data, struct intel_fcs_priv, miscdev); |
| dev = priv->client.dev; |
| mutex_lock(&priv->lock); |
| data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); |
| if (!data) { |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| msg = devm_kzalloc(dev, sizeof(*msg), GFP_KERNEL); |
| if (!msg) { |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| switch (cmd) { |
| case INTEL_FCS_DEV_VALIDATION_REQUEST: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| /* for bitstream */ |
| dev_dbg(dev, "file_name=%s, status=%d\n", |
| (char *)data->com_paras.s_request.src, data->status); |
| scnprintf(filename, FILE_NAME_SIZE, "%s", |
| (char *)data->com_paras.s_request.src); |
| ret = request_firmware(&fw, filename, priv->client.dev); |
| if (ret) { |
| dev_err(dev, "error requesting firmware %s\n", |
| (char *)data->com_paras.s_request.src); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| dev_dbg(dev, "FW size=%ld\n", fw->size); |
| s_buf = stratix10_svc_allocate_memory(priv->chan, fw->size); |
| if (IS_ERR(s_buf)) { |
| dev_err(dev, "failed to allocate VAB buffer\n"); |
| release_firmware(fw); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| memcpy(s_buf, fw->data, fw->size); |
| |
| msg->payload_length = fw->size; |
| release_firmware(fw); |
| |
| msg->command = COMMAND_FCS_REQUEST_SERVICE; |
| msg->payload = s_buf; |
| priv->client.receive_cb = fcs_vab_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| dev_dbg(dev, "fcs_request_service ret=%d\n", ret); |
| if (!ret && !priv->status) { |
| /* to query the complete status */ |
| msg->command = COMMAND_POLL_SERVICE_STATUS; |
| priv->client.receive_cb = fcs_data_callback; |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_COMPLETED_TIMEOUT); |
| dev_dbg(dev, "fcs_request_service ret=%d\n", ret); |
| if (!ret && !priv->status) |
| data->status = 0; |
| else |
| data->status = priv->status; |
| } else |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_close_services(priv, s_buf, NULL); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, s_buf, NULL); |
| break; |
| |
| case INTEL_FCS_DEV_SEND_CERTIFICATE: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.c_request.size == 0 || |
| data->com_paras.c_request.addr == NULL) { |
| dev_err(dev, "Invalid VAB request param\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| dev_dbg(dev, "Test=%d, Size=%d; Address=0x%p\n", |
| data->com_paras.c_request.test.test_word, |
| data->com_paras.c_request.size, |
| data->com_paras.c_request.addr); |
| |
| /* Allocate memory for certificate + test word */ |
| tsz = sizeof(struct intel_fcs_cert_test_word); |
| datasz = data->com_paras.c_request.size + tsz; |
| |
| s_buf = stratix10_svc_allocate_memory(priv->chan, datasz); |
| if (IS_ERR(s_buf)) { |
| dev_err(dev, "failed to allocate VAB buffer\n"); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| ps_buf = stratix10_svc_allocate_memory(priv->chan, PS_BUF_SIZE); |
| if (IS_ERR(ps_buf)) { |
| dev_err(dev, "failed to allocate p-status buf\n"); |
| stratix10_svc_free_memory(priv->chan, s_buf); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| /* Copy the test word */ |
| memcpy(s_buf, &data->com_paras.c_request.test, tsz); |
| |
| /* Copy in the certificate data (skipping over the test word) */ |
| ret = copy_from_user(s_buf + tsz, |
| data->com_paras.c_request.addr, |
| data->com_paras.c_request.size); |
| if (ret) { |
| dev_err(dev, "failed copy buf ret=%d\n", ret); |
| fcs_free_memory(priv, s_buf, ps_buf, NULL); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| msg->payload_length = datasz; |
| msg->command = COMMAND_FCS_SEND_CERTIFICATE; |
| msg->payload = s_buf; |
| priv->client.receive_cb = fcs_vab_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| dev_dbg(dev, "fcs_request_service ret=%d\n", ret); |
| if (!ret && !priv->status) { |
| /* to query the complete status */ |
| msg->payload = ps_buf; |
| msg->payload_length = PS_BUF_SIZE; |
| msg->command = COMMAND_POLL_SERVICE_STATUS; |
| priv->client.receive_cb = fcs_data_callback; |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_COMPLETED_TIMEOUT); |
| dev_dbg(dev, "request service ret=%d\n", ret); |
| if (!ret && !priv->status) { |
| data->status = 0; |
| data->mbox_status = 0; |
| } else { |
| if (priv->kbuf) { |
| data->com_paras.c_request.c_status = |
| (*(u32 *)priv->kbuf); |
| data->mbox_status = priv->status; |
| pr_info("data->mbox_status:0x%x\n", data->mbox_status); |
| } else |
| data->com_paras.c_request.c_status = |
| INVALID_STATUS; |
| } |
| } else |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_close_services(priv, s_buf, NULL); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, s_buf, ps_buf); |
| break; |
| |
| case INTEL_FCS_DEV_COUNTER_SET_PREAUTHORIZED: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| msg->command = COMMAND_FCS_COUNTER_SET_PREAUTHORIZED; |
| msg->arg[0] = data->com_paras.i_request.counter_type; |
| msg->arg[1] = data->com_paras.i_request.counter_value; |
| msg->arg[2] = data->com_paras.i_request.test.test_word; |
| priv->client.receive_cb = fcs_vab_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (ret) { |
| dev_err(dev, "failed to send the request,ret=%d\n", |
| ret); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| |
| data->status = priv->status; |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| ret = -EFAULT; |
| } |
| fcs_close_services(priv, NULL, NULL); |
| break; |
| |
| case INTEL_FCS_DEV_RANDOM_NUMBER_GEN: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| s_buf = stratix10_svc_allocate_memory(priv->chan, |
| RANDOM_NUMBER_SIZE); |
| if (IS_ERR(s_buf)) { |
| dev_err(dev, "failed to allocate RNG buffer\n"); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| msg->command = COMMAND_FCS_RANDOM_NUMBER_GEN; |
| msg->payload = s_buf; |
| msg->payload_length = RANDOM_NUMBER_SIZE; |
| priv->client.receive_cb = fcs_data_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| |
| if (!ret && !priv->status) { |
| if (!priv->kbuf) { |
| dev_err(dev, "failure on kbuf\n"); |
| fcs_close_services(priv, s_buf, NULL); |
| return -EFAULT; |
| } |
| |
| for (i = 0; i < 8; i++) |
| dev_dbg(dev, "output_data[%d]=%d\n", i, |
| *((int *)priv->kbuf + i)); |
| |
| for (i = 0; i < 8; i++) |
| data->com_paras.rn_gen.rndm[i] = |
| *((int *)priv->kbuf + i); |
| data->status = priv->status; |
| |
| } else { |
| /* failed to get RNG */ |
| data->status = priv->status; |
| } |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_close_services(priv, s_buf, NULL); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, s_buf, NULL); |
| break; |
| |
| case INTEL_FCS_DEV_GET_PROVISION_DATA: |
| if (copy_from_user(data, (void __user *)arg, |
| sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.gp_data.size == 0 || |
| data->com_paras.gp_data.addr == NULL) { |
| dev_err(dev, "Invalid provision request param\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| s_buf = stratix10_svc_allocate_memory(priv->chan, |
| data->com_paras.gp_data.size); |
| if (IS_ERR(s_buf)) { |
| dev_err(dev, "failed allocate provision buffer\n"); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| msg->command = COMMAND_FCS_GET_PROVISION_DATA; |
| msg->payload = NULL; |
| msg->payload_length = 0; |
| priv->client.receive_cb = fcs_vab_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| /* to query the complete status */ |
| msg->arg[0] = ASYNC_POLL_SERVICE; |
| msg->payload = s_buf; |
| msg->payload_length = data->com_paras.gp_data.size; |
| msg->command = COMMAND_POLL_SERVICE_STATUS_ASYNC; |
| priv->client.receive_cb = fcs_data_callback; |
| |
| timeout = 100; |
| while (timeout != 0) { |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| dev_dbg(dev, "request service ret=%d\n", ret); |
| |
| if (!ret && !priv->status) { |
| if (priv->size) { |
| if (!priv->kbuf) { |
| dev_err(dev, "failure on kbuf\n"); |
| fcs_close_services(priv, s_buf, NULL); |
| return -EFAULT; |
| } |
| |
| data->com_paras.gp_data.size = priv->size; |
| ret = copy_to_user(data->com_paras.gp_data.addr, |
| priv->kbuf, priv->size); |
| if (ret) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_close_services(priv, s_buf, NULL); |
| return -EFAULT; |
| } |
| break; |
| } |
| } else { |
| data->com_paras.gp_data.addr = NULL; |
| data->com_paras.gp_data.size = 0; |
| break; |
| } |
| timeout--; |
| mdelay(500); |
| } |
| } else { |
| data->com_paras.gp_data.addr = NULL; |
| data->com_paras.gp_data.size = 0; |
| } |
| |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_close_services(priv, s_buf, NULL); |
| return -EFAULT; |
| } |
| |
| fcs_close_services(priv, s_buf, NULL); |
| break; |
| |
| case INTEL_FCS_DEV_DATA_ENCRYPTION: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.d_encryption.src_size < DEC_MIN_SZ || |
| data->com_paras.d_encryption.src_size > DEC_MAX_SZ) { |
| dev_err(dev, "Invalid SDOS Buffer src size:%d\n", |
| data->com_paras.d_encryption.src_size); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.d_encryption.dst_size < ENC_MIN_SZ || |
| data->com_paras.d_encryption.dst_size > ENC_MAX_SZ) { |
| dev_err(dev, "Invalid SDOS Buffer dst size:%d\n", |
| data->com_paras.d_encryption.dst_size); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.d_encryption.src == NULL || |
| data->com_paras.d_encryption.dst == NULL) { |
| dev_err(dev, "Invalid SDOS Buffer pointer\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| /* allocate buffer for both source and destination */ |
| s_buf = stratix10_svc_allocate_memory(priv->chan, |
| MAX_SDOS_BUF_SZ); |
| if (IS_ERR(s_buf)) { |
| dev_err(dev, "failed allocate encrypt src buf\n"); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| d_buf = stratix10_svc_allocate_memory(priv->chan, |
| MAX_SDOS_BUF_SZ); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed allocate encrypt dst buf\n"); |
| stratix10_svc_free_memory(priv->chan, s_buf); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| ps_buf = stratix10_svc_allocate_memory(priv->chan, PS_BUF_SIZE); |
| if (IS_ERR(ps_buf)) { |
| dev_err(dev, "failed allocate p-status buffer\n"); |
| fcs_free_memory(priv, s_buf, d_buf, NULL); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| ret = copy_from_user(s_buf, |
| data->com_paras.d_encryption.src, |
| data->com_paras.d_encryption.src_size); |
| if (ret) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| fcs_free_memory(priv, ps_buf, s_buf, d_buf); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| msg->command = COMMAND_FCS_DATA_ENCRYPTION; |
| msg->payload = s_buf; |
| msg->payload_length = |
| data->com_paras.d_encryption.src_size; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = |
| data->com_paras.d_encryption.dst_size; |
| priv->client.receive_cb = fcs_vab_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| msg->payload = ps_buf; |
| msg->payload_length = PS_BUF_SIZE; |
| msg->command = COMMAND_POLL_SERVICE_STATUS; |
| |
| priv->client.receive_cb = fcs_data_callback; |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_COMPLETED_TIMEOUT); |
| dev_dbg(dev, "request service ret=%d\n", ret); |
| |
| if (!ret && !priv->status) { |
| if (!priv->kbuf) { |
| dev_err(dev, "failure on kbuf\n"); |
| fcs_free_memory(priv, ps_buf, s_buf, d_buf); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| buf_sz = *(unsigned int *)priv->kbuf; |
| data->com_paras.d_encryption.dst_size = buf_sz; |
| data->status = 0; |
| ret = copy_to_user(data->com_paras.d_encryption.dst, |
| d_buf, buf_sz); |
| if (ret) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_free_memory(priv, ps_buf, s_buf, d_buf); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| } else { |
| data->com_paras.d_encryption.dst = NULL; |
| data->com_paras.d_encryption.dst_size = 0; |
| data->status = priv->status; |
| } |
| } else { |
| data->com_paras.d_encryption.dst = NULL; |
| data->com_paras.d_encryption.dst_size = 0; |
| data->status = priv->status; |
| } |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_free_memory(priv, ps_buf, s_buf, d_buf); |
| fcs_close_services(priv, NULL, NULL); |
| ret = -EFAULT; |
| } |
| |
| fcs_free_memory(priv, ps_buf, s_buf, d_buf); |
| fcs_close_services(priv, NULL, NULL); |
| break; |
| |
| case INTEL_FCS_DEV_DATA_DECRYPTION: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.d_encryption.src_size < ENC_MIN_SZ || |
| data->com_paras.d_encryption.src_size > ENC_MAX_SZ) { |
| dev_err(dev, "Invalid SDOS Buffer src size:%d\n", |
| data->com_paras.d_encryption.src_size); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.d_encryption.dst_size < DEC_MIN_SZ || |
| data->com_paras.d_encryption.dst_size > DEC_MAX_SZ) { |
| dev_err(dev, "Invalid SDOS Buffer dst size:%d\n", |
| data->com_paras.d_encryption.dst_size); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.d_encryption.src == NULL || |
| data->com_paras.d_encryption.dst == NULL) { |
| dev_err(dev, "Invalid SDOS Buffer pointer\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| /* allocate buffer for both source and destination */ |
| s_buf = stratix10_svc_allocate_memory(priv->chan, |
| MAX_SDOS_BUF_SZ); |
| if (IS_ERR(s_buf)) { |
| dev_err(dev, "failed allocate decrypt src buf\n"); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| d_buf = stratix10_svc_allocate_memory(priv->chan, |
| MAX_SDOS_BUF_SZ); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed allocate decrypt dst buf\n"); |
| stratix10_svc_free_memory(priv->chan, s_buf); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| ps_buf = stratix10_svc_allocate_memory(priv->chan, |
| PS_BUF_SIZE); |
| if (IS_ERR(ps_buf)) { |
| dev_err(dev, "failed allocate p-status buffer\n"); |
| fcs_free_memory(priv, s_buf, d_buf, NULL); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| ret = copy_from_user(s_buf, |
| data->com_paras.d_decryption.src, |
| data->com_paras.d_decryption.src_size); |
| if (ret) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| fcs_free_memory(priv, ps_buf, s_buf, d_buf); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| msg->command = COMMAND_FCS_DATA_DECRYPTION; |
| msg->payload = s_buf; |
| msg->payload_length = |
| data->com_paras.d_decryption.src_size; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = |
| data->com_paras.d_decryption.dst_size; |
| priv->client.receive_cb = fcs_vab_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| msg->command = COMMAND_POLL_SERVICE_STATUS; |
| msg->payload = ps_buf; |
| msg->payload_length = PS_BUF_SIZE; |
| priv->client.receive_cb = fcs_sdos_data_poll_callback; |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_COMPLETED_TIMEOUT); |
| dev_dbg(dev, "request service ret=%d\n", ret); |
| if (!ret && |
| (!priv->status || |
| priv->status == SDOS_DECRYPTION_ERROR_102 || |
| priv->status == SDOS_DECRYPTION_ERROR_103)) { |
| if (!priv->kbuf) { |
| dev_err(dev, "failure on kbuf\n"); |
| fcs_free_memory(priv, ps_buf, s_buf, d_buf); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| buf_sz = *((unsigned int *)priv->kbuf); |
| data->com_paras.d_decryption.dst_size = buf_sz; |
| data->status = priv->status; |
| ret = copy_to_user(data->com_paras.d_decryption.dst, |
| d_buf, buf_sz); |
| if (ret) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_free_memory(priv, ps_buf, s_buf, d_buf); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| } else { |
| data->com_paras.d_decryption.dst = NULL; |
| data->com_paras.d_decryption.dst_size = 0; |
| data->status = priv->status; |
| } |
| } else { |
| data->com_paras.d_decryption.dst = NULL; |
| data->com_paras.d_decryption.dst_size = 0; |
| data->status = priv->status; |
| } |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_free_memory(priv, ps_buf, s_buf, d_buf); |
| fcs_close_services(priv, NULL, NULL); |
| ret = -EFAULT; |
| } |
| |
| fcs_free_memory(priv, ps_buf, s_buf, d_buf); |
| fcs_close_services(priv, NULL, NULL); |
| break; |
| |
| case INTEL_FCS_DEV_PSGSIGMA_TEARDOWN: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| sid = data->com_paras.tdown.sid; |
| if ((sid != SIGMA_SESSION_ID_ONE) && |
| (sid != SIGMA_UNKNOWN_SESSION)) { |
| dev_err(dev, "Invalid session ID:%d\n", sid); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| msg->command = COMMAND_FCS_PSGSIGMA_TEARDOWN; |
| msg->arg[0] = sid; |
| priv->client.receive_cb = fcs_vab_callback; |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (ret) { |
| dev_err(dev, "failed to send the request,ret=%d\n", |
| ret); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| |
| data->status = priv->status; |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| ret = -EFAULT; |
| } |
| fcs_close_services(priv, NULL, NULL); |
| break; |
| |
| case INTEL_FCS_DEV_CHIP_ID: |
| msg->command = COMMAND_FCS_GET_CHIP_ID; |
| priv->client.receive_cb = fcs_chipid_callback; |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (ret) { |
| dev_err(dev, "failed to send the request,ret=%d\n", |
| ret); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| data->status = priv->status; |
| data->com_paras.c_id.chip_id_low = priv->cid_low; |
| data->com_paras.c_id.chip_id_high = priv->cid_high; |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| ret = -EFAULT; |
| } |
| fcs_close_services(priv, NULL, NULL); |
| break; |
| |
| case INTEL_FCS_DEV_ATTESTATION_SUBKEY: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.subkey.cmd_data_sz > SUBKEY_CMD_MAX_SZ) { |
| dev_err(dev, "Invalid subkey CMD size %d\n", |
| data->com_paras.subkey.cmd_data_sz); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.subkey.rsp_data_sz > SUBKEY_RSP_MAX_SZ) { |
| dev_err(dev, "Invalid subkey RSP size %d\n", |
| data->com_paras.subkey.rsp_data_sz); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.subkey.cmd_data == NULL || |
| data->com_paras.subkey.rsp_data == NULL) { |
| dev_err(dev, "Invalid subkey data pointer\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| /* allocate buffer for both soruce and destination */ |
| rsz = sizeof(struct intel_fcs_attestation_resv_word); |
| datasz = data->com_paras.subkey.cmd_data_sz + rsz; |
| |
| s_buf = stratix10_svc_allocate_memory(priv->chan, |
| SUBKEY_CMD_MAX_SZ + |
| rsz); |
| if (IS_ERR(s_buf)) { |
| dev_err(dev, "failed allocate subkey CMD buf\n"); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| d_buf = stratix10_svc_allocate_memory(priv->chan, |
| SUBKEY_RSP_MAX_SZ); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed allocate subkey RSP buf\n"); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| /* copy the reserve word first then command payload */ |
| memcpy(s_buf, &data->com_paras.subkey.resv.resv_word, rsz); |
| |
| /* Copy user data from user space to kernel space */ |
| ret = copy_from_user(s_buf + rsz, |
| data->com_paras.subkey.cmd_data, |
| data->com_paras.subkey.cmd_data_sz); |
| if (ret) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| fcs_free_memory(priv, s_buf, d_buf, NULL); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| msg->command = COMMAND_FCS_ATTESTATION_SUBKEY; |
| msg->payload = s_buf; |
| msg->payload_length = datasz; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = SUBKEY_RSP_MAX_SZ; |
| priv->client.receive_cb = fcs_attestation_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| 10 * FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| if (priv->size > SUBKEY_RSP_MAX_SZ) { |
| dev_err(dev, |
| "returned size is incorrect\n"); |
| fcs_close_services(priv, s_buf, d_buf); |
| return -EFAULT; |
| } |
| |
| memcpy(data->com_paras.subkey.rsp_data, |
| priv->kbuf, priv->size); |
| data->com_paras.subkey.rsp_data_sz = priv->size; |
| data->status = priv->status; |
| |
| } else { |
| data->com_paras.subkey.rsp_data = NULL; |
| data->com_paras.subkey.rsp_data_sz = 0; |
| data->status = priv->status; |
| } |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| fcs_close_services(priv, s_buf, d_buf); |
| break; |
| |
| case INTEL_FCS_DEV_ATTESTATION_MEASUREMENT: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.measurement.cmd_data_sz > MEASUREMENT_CMD_MAX_SZ) { |
| dev_err(dev, "Invalid measurement CMD size %d\n", |
| data->com_paras.measurement.cmd_data_sz); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.measurement.rsp_data_sz > MEASUREMENT_RSP_MAX_SZ) { |
| dev_err(dev, "Invalid measurement RSP size %d\n", |
| data->com_paras.measurement.rsp_data_sz); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.measurement.cmd_data == NULL || |
| data->com_paras.measurement.rsp_data == NULL) { |
| dev_err(dev, "Invalid measurement data pointer\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| /* allocate buffer for both soruce and destination */ |
| rsz = sizeof(struct intel_fcs_attestation_resv_word); |
| datasz = data->com_paras.measurement.cmd_data_sz + rsz; |
| |
| s_buf = stratix10_svc_allocate_memory(priv->chan, |
| MEASUREMENT_CMD_MAX_SZ + |
| rsz); |
| if (IS_ERR(s_buf)) { |
| dev_err(dev, "failed allocate measurement CMD buf\n"); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| d_buf = stratix10_svc_allocate_memory(priv->chan, |
| MEASUREMENT_RSP_MAX_SZ); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed allocate measurement RSP buf\n"); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| /* copy the reserve word first then command payload */ |
| memcpy(s_buf, &data->com_paras.measurement.resv.resv_word, rsz); |
| |
| /* Copy user data from user space to kernel space */ |
| ret = copy_from_user(s_buf + rsz, |
| data->com_paras.measurement.cmd_data, |
| data->com_paras.measurement.cmd_data_sz); |
| if (ret) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| fcs_free_memory(priv, s_buf, d_buf, NULL); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| msg->command = COMMAND_FCS_ATTESTATION_MEASUREMENTS; |
| msg->payload = s_buf; |
| msg->payload_length = datasz; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = MEASUREMENT_RSP_MAX_SZ; |
| priv->client.receive_cb = fcs_attestation_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| 10 * FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| if (priv->size > MEASUREMENT_RSP_MAX_SZ) { |
| dev_err(dev, |
| "returned size is incorrect\n"); |
| fcs_close_services(priv, s_buf, d_buf); |
| return -EFAULT; |
| } |
| |
| memcpy(data->com_paras.measurement.rsp_data, |
| priv->kbuf, priv->size); |
| data->com_paras.measurement.rsp_data_sz = priv->size; |
| data->status = priv->status; |
| } else { |
| data->com_paras.measurement.rsp_data = NULL; |
| data->com_paras.measurement.rsp_data_sz = 0; |
| data->status = priv->status; |
| } |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, s_buf, d_buf); |
| break; |
| |
| case INTEL_FCS_DEV_ATTESTATION_GET_CERTIFICATE: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.certificate.rsp_data_sz > CERTIFICATE_RSP_MAX_SZ) { |
| dev_err(dev, "Invalid certificate RSP size %d\n", |
| data->com_paras.certificate.rsp_data_sz); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| d_buf = stratix10_svc_allocate_memory(priv->chan, |
| CERTIFICATE_RSP_MAX_SZ); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed allocate certificate RSP buf\n"); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| msg->command = COMMAND_FCS_ATTESTATION_CERTIFICATE; |
| msg->payload = NULL; |
| msg->payload_length = 0; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = CERTIFICATE_RSP_MAX_SZ; |
| msg->arg[0] = data->com_paras.certificate.c_request & 0x00ff; |
| priv->client.receive_cb = fcs_attestation_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| 10 * FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| if (priv->size > CERTIFICATE_RSP_MAX_SZ) { |
| dev_err(dev, |
| "returned size is incorrect\n"); |
| fcs_close_services(priv, NULL, d_buf); |
| return -EFAULT; |
| } |
| |
| memcpy(data->com_paras.certificate.rsp_data, |
| priv->kbuf, priv->size); |
| data->com_paras.certificate.rsp_data_sz = priv->size; |
| data->status = priv->status; |
| } else { |
| data->com_paras.certificate.rsp_data = NULL; |
| data->com_paras.certificate.rsp_data_sz = 0; |
| data->status = priv->status; |
| } |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_close_services(priv, NULL, d_buf); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, NULL, d_buf); |
| break; |
| |
| case INTEL_FCS_DEV_ATTESTATION_CERTIFICATE_RELOAD: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| return -EFAULT; |
| } |
| |
| msg->command = COMMAND_FCS_ATTESTATION_CERTIFICATE_RELOAD; |
| msg->arg[0] = data->com_paras.c_reload.c_request & 0x00ff; |
| priv->client.receive_cb = fcs_vab_callback; |
| ret = fcs_request_service(priv, (void *)msg, |
| 10 * FCS_REQUEST_TIMEOUT); |
| if (ret) { |
| dev_err(dev, "failed to send the request,ret=%d\n", |
| ret); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| |
| data->status = priv->status; |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| ret = -EFAULT; |
| } |
| fcs_close_services(priv, NULL, NULL); |
| break; |
| |
| case INTEL_FCS_DEV_GET_ROM_PATCH_SHA384: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| s_buf = stratix10_svc_allocate_memory(priv->chan, |
| SHA384_SIZE); |
| if (IS_ERR(s_buf)) { |
| dev_err(dev, "failed to allocate RNG buffer\n"); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| msg->command = COMMAND_FCS_GET_ROM_PATCH_SHA384; |
| msg->payload = s_buf; |
| msg->payload_length = SHA384_SIZE; |
| priv->client.receive_cb = fcs_data_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| |
| if (!ret && !priv->status) { |
| if (!priv->kbuf) { |
| dev_err(dev, "failure on kbuf\n"); |
| fcs_close_services(priv, s_buf, NULL); |
| return -EFAULT; |
| } |
| |
| if (priv->size > SHA384_SIZE) { |
| dev_err(dev, "returned size is incorrect\n"); |
| fcs_close_services(priv, s_buf, NULL); |
| ret = -EFAULT; |
| } |
| |
| for (i = 0; i < 12; i++) |
| dev_dbg(dev, "output_data[%d]=%d\n", i, |
| *((int *)priv->kbuf + i)); |
| for (i = 0; i < 12; i++) |
| data->com_paras.sha384.checksum[i] = |
| *((int *)priv->kbuf + i); |
| data->status = priv->status; |
| |
| } else { |
| /* failed to get SHA */ |
| data->status = priv->status; |
| } |
| |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_close_services(priv, s_buf, NULL); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, s_buf, NULL); |
| break; |
| |
| case INTEL_FCS_DEV_CRYPTO_OPEN_SESSION: |
| msg->command = COMMAND_FCS_CRYPTO_OPEN_SESSION; |
| priv->client.receive_cb = fcs_crypto_sessionid_callback; |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (ret) { |
| dev_err(dev, "failed to send the cmd=%d,ret=%d\n", |
| COMMAND_FCS_CRYPTO_OPEN_SESSION, ret); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| |
| data->status = priv->status; |
| data->com_paras.s_session.sid = priv->sid; |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| ret = -EFAULT; |
| } |
| fcs_close_services(priv, NULL, NULL); |
| break; |
| |
| case INTEL_FCS_DEV_CRYPTO_CLOSE_SESSION: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| msg->command = COMMAND_FCS_CRYPTO_CLOSE_SESSION; |
| msg->arg[0] = data->com_paras.s_session.sid; |
| priv->client.receive_cb = fcs_vab_callback; |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (ret) { |
| dev_err(dev, "failed to send the request,ret=%d\n", |
| ret); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| |
| data->status = priv->status; |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| ret = -EFAULT; |
| } |
| fcs_close_services(priv, NULL, NULL); |
| break; |
| |
| case INTEL_FCS_DEV_CRYPTO_IMPORT_KEY: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.k_import.obj_data_sz == 0 || |
| data->com_paras.k_import.obj_data == NULL) { |
| dev_err(dev, "Invalid key import request param\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| /* Allocate memory for header + key object */ |
| tsz = sizeof(struct fcs_crypto_key_header); |
| datasz = data->com_paras.k_import.obj_data_sz + tsz; |
| |
| s_buf = stratix10_svc_allocate_memory(priv->chan, datasz); |
| if (IS_ERR(s_buf)) { |
| dev_err(dev, "failed to allocate key import buffer\n"); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| ps_buf = stratix10_svc_allocate_memory(priv->chan, PS_BUF_SIZE); |
| if (IS_ERR(ps_buf)) { |
| dev_err(dev, "failed allocate p-status buffer\n"); |
| fcs_free_memory(priv, s_buf, NULL, NULL); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| /* copy session ID from the header */ |
| memcpy(s_buf, &data->com_paras.k_import.hd.sid, sizeof(uint32_t)); |
| ret = copy_from_user(s_buf + tsz, |
| data->com_paras.k_import.obj_data, |
| data->com_paras.k_import.obj_data_sz); |
| if (ret) { |
| dev_err(dev, "failed copy buf ret=%d\n", ret); |
| fcs_free_memory(priv, ps_buf, s_buf, d_buf); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| msg->payload = s_buf; |
| msg->payload_length = datasz; |
| msg->command = COMMAND_FCS_CRYPTO_IMPORT_KEY; |
| priv->client.receive_cb = fcs_vab_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| dev_dbg(dev, "request service ret=%d\n", ret); |
| |
| if (!ret && !priv->status) { |
| /* to query the complete status */ |
| msg->payload = ps_buf; |
| msg->payload_length = PS_BUF_SIZE; |
| msg->command = COMMAND_POLL_SERVICE_STATUS; |
| priv->client.receive_cb = fcs_data_callback; |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_COMPLETED_TIMEOUT); |
| dev_dbg(dev, "request service ret=%d\n", ret); |
| if (!ret && !priv->status) |
| data->status = 0; |
| else { |
| data->status = priv->status; |
| if (priv->kbuf) |
| data->status |= ((*(u32 *)priv->kbuf) & 0xFF) |
| << 16; |
| } |
| } else { |
| data->status = priv->status; |
| } |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_close_services(priv, NULL, NULL); |
| fcs_free_memory(priv, ps_buf, s_buf, NULL); |
| return -EFAULT; |
| } |
| |
| fcs_close_services(priv, NULL, NULL); |
| fcs_free_memory(priv, ps_buf, s_buf, NULL); |
| break; |
| |
| case INTEL_FCS_DEV_CRYPTO_EXPORT_KEY: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.k_object.obj_data_sz > |
| CRYPTO_EXPORTED_KEY_OBJECT_MAX_SZ) { |
| dev_err(dev, "Invalid key object size %d\n", |
| data->com_paras.k_object.obj_data_sz); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| d_buf = stratix10_svc_allocate_memory(priv->chan, |
| CRYPTO_EXPORTED_KEY_OBJECT_MAX_SZ); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed allocate key object buf\n"); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| msg->command = COMMAND_FCS_CRYPTO_EXPORT_KEY; |
| msg->payload = NULL; |
| msg->payload_length = 0; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = CRYPTO_EXPORTED_KEY_OBJECT_MAX_SZ; |
| msg->arg[0] = data->com_paras.k_object.sid; |
| msg->arg[1] = data->com_paras.k_object.kid; |
| priv->client.receive_cb = fcs_attestation_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| if (priv->size > CRYPTO_EXPORTED_KEY_OBJECT_MAX_SZ) { |
| dev_err(dev, "returned size %d is incorrect\n", |
| priv->size); |
| fcs_close_services(priv, NULL, d_buf); |
| return -EFAULT; |
| } |
| |
| memcpy(data->com_paras.k_object.obj_data, |
| priv->kbuf, priv->size); |
| data->com_paras.k_object.obj_data_sz = priv->size; |
| } else { |
| data->com_paras.k_object.obj_data = NULL; |
| data->com_paras.k_object.obj_data_sz = 0; |
| } |
| |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_close_services(priv, NULL, d_buf); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, NULL, d_buf); |
| break; |
| |
| case INTEL_FCS_DEV_CRYPTO_REMOVE_KEY: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| msg->command = COMMAND_FCS_CRYPTO_REMOVE_KEY; |
| msg->arg[0] = data->com_paras.k_object.sid; |
| msg->arg[1] = data->com_paras.k_object.kid; |
| priv->client.receive_cb = fcs_vab_callback; |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (ret) { |
| dev_err(dev, "failed to send the request,ret=%d\n", |
| ret); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| data->status = priv->status; |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| ret = -EFAULT; |
| } |
| fcs_close_services(priv, NULL, NULL); |
| break; |
| |
| case INTEL_FCS_DEV_CRYPTO_GET_KEY_INFO: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.k_object.obj_data_sz > CRYPTO_GET_KEY_INFO_MAX_SZ) { |
| dev_err(dev, "Invalid key object size %d\n", |
| data->com_paras.k_object.obj_data_sz); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| d_buf = stratix10_svc_allocate_memory(priv->chan, |
| CRYPTO_GET_KEY_INFO_MAX_SZ); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed allocate key object buf\n"); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| msg->command = COMMAND_FCS_CRYPTO_GET_KEY_INFO; |
| msg->payload = NULL; |
| msg->payload_length = 0; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = CRYPTO_GET_KEY_INFO_MAX_SZ; |
| msg->arg[0] = data->com_paras.k_object.sid; |
| msg->arg[1] = data->com_paras.k_object.kid; |
| priv->client.receive_cb = fcs_attestation_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| if (priv->size > CRYPTO_GET_KEY_INFO_MAX_SZ) { |
| dev_err(dev, "returned size %d is incorrect\n", |
| priv->size); |
| fcs_close_services(priv, NULL, d_buf); |
| return -EFAULT; |
| } |
| |
| memcpy(data->com_paras.k_object.obj_data, |
| priv->kbuf, priv->size); |
| data->com_paras.k_object.obj_data_sz = priv->size; |
| } else { |
| data->com_paras.k_object.obj_data = NULL; |
| data->com_paras.k_object.obj_data_sz = 0; |
| } |
| |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_close_services(priv, NULL, d_buf); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, NULL, d_buf); |
| break; |
| |
| case INTEL_FCS_DEV_CRYPTO_AES_CRYPT: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user data\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if ((data->com_paras.a_crypt.cpara.bmode == AES_CRYPT_MODE_ECB) && |
| (data->com_paras.a_crypt.cpara_size != AES_CRYPT_PARAM_SIZE_ECB)) { |
| dev_err(dev, "AES param size incorrect. Block mode=%d, size=%d\n", |
| data->com_paras.a_crypt.cpara.bmode, |
| data->com_paras.a_crypt.cpara_size); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } else if (((data->com_paras.a_crypt.cpara.bmode == AES_CRYPT_MODE_CBC) || |
| (data->com_paras.a_crypt.cpara.bmode == AES_CRYPT_MODE_CTR)) && |
| (data->com_paras.a_crypt.cpara_size != AES_CRYPT_PARAM_SIZE_CBC_CTR)) { |
| dev_err(dev, "AES param size incorrect. Block mode=%d, size=%d\n", |
| data->com_paras.a_crypt.cpara.bmode, |
| data->com_paras.a_crypt.cpara_size); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } else if (data->com_paras.a_crypt.cpara.bmode > AES_CRYPT_MODE_CTR) { |
| dev_err(dev, "Unknown AES block mode. Block mode=%d\n", |
| data->com_paras.a_crypt.cpara.bmode); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| iv_field_buf = stratix10_svc_allocate_memory(priv->chan, 28); |
| if (IS_ERR(iv_field_buf)) { |
| dev_err(dev, "failed allocate iv_field buf\n"); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| sid = data->com_paras.a_crypt.sid; |
| cid = data->com_paras.a_crypt.cid; |
| kuid = data->com_paras.a_crypt.kuid; |
| |
| memcpy(iv_field_buf, &data->com_paras.a_crypt.cpara.bmode, 1); |
| memcpy(iv_field_buf + 1, &data->com_paras.a_crypt.cpara.aes_mode, 1); |
| memcpy(iv_field_buf + 12, data->com_paras.a_crypt.cpara.iv_field, 16); |
| |
| msg->command = COMMAND_FCS_CRYPTO_AES_CRYPT_INIT; |
| msg->payload = iv_field_buf; |
| msg->payload_length = data->com_paras.a_crypt.cpara_size; |
| msg->payload_output = NULL; |
| msg->payload_length_output = 0; |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->arg[2] = kuid; |
| |
| priv->client.receive_cb = fcs_vab_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (ret || priv->status) { |
| dev_err(dev, "failed to send the cmd=%d,ret=%d\n", |
| COMMAND_FCS_CRYPTO_AES_CRYPT_INIT, |
| ret); |
| fcs_close_services(priv, iv_field_buf, NULL); |
| return -EFAULT; |
| } |
| |
| fcs_free_memory(priv, iv_field_buf, NULL, NULL); |
| |
| s_buf = stratix10_svc_allocate_memory(priv->chan, |
| data->com_paras.a_crypt.src_size);; |
| if (IS_ERR(s_buf)) { |
| dev_err(dev, "failed allocate source buf\n"); |
| fcs_close_services(priv, NULL, NULL); |
| return -ENOMEM; |
| } |
| |
| d_buf = stratix10_svc_allocate_memory(priv->chan, |
| data->com_paras.a_crypt.src_size); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed allocate destation buf\n"); |
| fcs_close_services(priv, s_buf, NULL); |
| return -ENOMEM; |
| } |
| |
| ret = copy_from_user(s_buf, data->com_paras.a_crypt.src, |
| data->com_paras.a_crypt.src_size); |
| if (ret) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| fcs_close_services(priv, s_buf, d_buf); |
| return -EFAULT; |
| } |
| |
| ps_buf = stratix10_svc_allocate_memory(priv->chan, PS_BUF_SIZE); |
| if (IS_ERR(ps_buf)) { |
| dev_err(dev, "failed to allocate p-status buf\n"); |
| fcs_close_services(priv, s_buf, d_buf); |
| return -ENOMEM; |
| } |
| |
| msg->command = COMMAND_FCS_CRYPTO_AES_CRYPT_FINALIZE; |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->payload = s_buf; |
| msg->payload_length = data->com_paras.a_crypt.src_size; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = data->com_paras.a_crypt.dst_size; |
| priv->client.receive_cb = fcs_attestation_callback; |
| |
| ps_buf = stratix10_svc_allocate_memory(priv->chan, PS_BUF_SIZE); |
| if (!ps_buf) { |
| dev_err(dev, "failed to allocate p-status buf\n"); |
| fcs_close_services(priv, s_buf, d_buf); |
| return -ENOMEM; |
| } |
| |
| while (remaining_size > 0) { |
| if (remaining_size > AES_CRYPT_CMD_MAX_SZ) { |
| msg->command = COMMAND_FCS_CRYPTO_AES_CRYPT_UPDATE; |
| data_size = AES_CRYPT_CMD_MAX_SZ; |
| dev_dbg(dev, "AES crypt update. data_size=%d\n", data_size); |
| } else { |
| msg->command = COMMAND_FCS_CRYPTO_AES_CRYPT_FINALIZE; |
| data_size = remaining_size; |
| dev_dbg(dev, "AES crypt finalize. data_size=%d\n", data_size); |
| } |
| |
| ret = copy_from_user(s_buf, input_file_pointer, data_size); |
| |
| if (ret) { |
| dev_err(dev, "failure on copy_from_user s_buf\n"); |
| fcs_free_memory(priv, s_buf, d_buf, ps_buf); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->payload = s_buf; |
| msg->payload_length = data_size; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = data_size; |
| priv->client.receive_cb = fcs_attestation_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| /* to query the complete status */ |
| msg->payload = ps_buf; |
| msg->payload_length = PS_BUF_SIZE; |
| msg->command = COMMAND_POLL_SERVICE_STATUS; |
| priv->client.receive_cb = fcs_data_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_COMPLETED_TIMEOUT); |
| if (!ret && !priv->status) { |
| if (!priv->kbuf || priv->size != 16) { |
| dev_err(dev, "unregconize response\n"); |
| fcs_free_memory(priv, s_buf, d_buf, ps_buf); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| |
| buf_sz = ((u32 *)priv->kbuf)[3]; |
| |
| ret = copy_to_user(output_file_pointer, d_buf, buf_sz); |
| |
| total_out_size += buf_sz; |
| |
| if (ret) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_free_memory(priv, s_buf, d_buf, ps_buf); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| } |
| } else { |
| data->com_paras.a_crypt.dst = NULL; |
| data->com_paras.a_crypt.dst_size = 0; |
| dev_err(dev, "unregconize response. ret=%d. status=%d\n", |
| ret, priv->status); |
| break; |
| } |
| |
| remaining_size -= data_size; |
| if (remaining_size == 0) { |
| dev_dbg(dev, "AES crypt finish sending\n"); |
| data->com_paras.a_crypt.dst_size = total_out_size; |
| break; |
| } else { |
| input_file_pointer += data_size; |
| output_file_pointer += data_size; |
| dev_dbg(dev, "Complete one update. Remaining size = %d\n", |
| remaining_size); |
| } |
| } |
| |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| ret = -EFAULT; |
| } |
| fcs_free_memory(priv, s_buf, d_buf, ps_buf); |
| fcs_close_services(priv, NULL, NULL); |
| break; |
| |
| case INTEL_FCS_DEV_CRYPTO_GET_DIGEST: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| sid = data->com_paras.s_mac_data.sid; |
| cid = data->com_paras.s_mac_data.cid; |
| kuid = data->com_paras.s_mac_data.kuid; |
| |
| msg->command = COMMAND_FCS_CRYPTO_GET_DIGEST_INIT; |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->arg[2] = kuid; |
| msg->arg[3] = CRYPTO_ECC_PARAM_SZ; |
| msg->arg[4] = data->com_paras.s_mac_data.sha_op_mode | |
| (data->com_paras.s_mac_data.sha_digest_sz << |
| CRYPTO_ECC_DIGEST_SZ_OFFSET); |
| |
| priv->client.receive_cb = fcs_vab_callback; |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (ret || priv->status) { |
| dev_err(dev, "failed to send the cmd=%d,ret=%d, status=%d\n", |
| COMMAND_FCS_CRYPTO_GET_DIGEST_INIT, ret, priv->status); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| |
| input_file_pointer = data->com_paras.s_mac_data.src; |
| remaining_size = data->com_paras.s_mac_data.src_size; |
| |
| s_buf = stratix10_svc_allocate_memory(priv->chan, |
| AES_CRYPT_CMD_MAX_SZ); |
| if (IS_ERR(s_buf)) { |
| dev_err(dev, "failed allocate source buf\n"); |
| fcs_close_services(priv, NULL, NULL); |
| return -ENOMEM; |
| } |
| |
| d_buf = stratix10_svc_allocate_memory(priv->chan, |
| AES_CRYPT_CMD_MAX_SZ); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed allocate destation buf\n"); |
| fcs_close_services(priv, s_buf, NULL); |
| return -ENOMEM; |
| } |
| |
| while (remaining_size > 0) { |
| if (remaining_size > AES_CRYPT_CMD_MAX_SZ) { |
| msg->command = COMMAND_FCS_CRYPTO_GET_DIGEST_UPDATE; |
| data_size = AES_CRYPT_CMD_MAX_SZ; |
| dev_dbg(dev, "Crypto get digest update. data_size=%d\n", |
| data_size); |
| } else { |
| msg->command = COMMAND_FCS_CRYPTO_GET_DIGEST_FINALIZE; |
| data_size = remaining_size; |
| dev_dbg(dev, "Crypto get digest finalize. data_size=%d\n", |
| data_size); |
| } |
| |
| memcpy(s_buf, input_file_pointer, data_size); |
| |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->payload = s_buf; |
| msg->payload_length = data_size; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = AES_CRYPT_CMD_MAX_SZ; |
| priv->client.receive_cb = fcs_attestation_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| 10 * FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| if (priv->size > AES_CRYPT_CMD_MAX_SZ) { |
| dev_err(dev, "returned size %d is incorrect\n", |
| priv->size); |
| fcs_close_services(priv, s_buf, d_buf); |
| return -EFAULT; |
| } |
| } else { |
| data->com_paras.s_mac_data.dst = NULL; |
| data->com_paras.s_mac_data.dst_size = 0; |
| dev_err(dev, "unregconize response. ret=%d. status=%d\n", |
| ret, priv->status); |
| break; |
| } |
| |
| remaining_size -= data_size; |
| if (remaining_size == 0) { |
| dev_dbg(dev, "Crypto get digest finish sending\n"); |
| memcpy(data->com_paras.s_mac_data.dst, priv->kbuf, priv->size); |
| data->com_paras.s_mac_data.dst_size = priv->size; |
| break; |
| } else { |
| input_file_pointer += data_size; |
| dev_dbg(dev, "Complete update. Remaining size = %d\n", |
| remaining_size); |
| } |
| } |
| |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_close_services(priv, s_buf, d_buf); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, s_buf, d_buf); |
| break; |
| |
| case INTEL_FCS_DEV_CRYPTO_MAC_VERIFY: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| sid = data->com_paras.s_mac_data.sid; |
| cid = data->com_paras.s_mac_data.cid; |
| kuid = data->com_paras.s_mac_data.kuid; |
| out_sz = data->com_paras.s_mac_data.dst_size; |
| ud_sz = data->com_paras.s_mac_data.userdata_sz; |
| |
| msg->command = COMMAND_FCS_CRYPTO_MAC_VERIFY_INIT; |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->arg[2] = kuid; |
| msg->arg[3] = CRYPTO_ECC_PARAM_SZ; |
| msg->arg[4] = data->com_paras.s_mac_data.sha_op_mode | |
| (data->com_paras.s_mac_data.sha_digest_sz << |
| CRYPTO_ECC_DIGEST_SZ_OFFSET); |
| priv->client.receive_cb = fcs_vab_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (ret || priv->status) { |
| dev_err(dev, "failed to send the cmd=%d,ret=%d, status=%d\n", |
| COMMAND_FCS_CRYPTO_MAC_VERIFY_INIT, ret, priv->status); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| |
| input_file_pointer = data->com_paras.s_mac_data.src; |
| remaining_size = data->com_paras.s_mac_data.src_size; |
| sign_size = data->com_paras.s_mac_data.src_size |
| - data->com_paras.s_mac_data.userdata_sz; |
| |
| s_buf = stratix10_svc_allocate_memory(priv->chan, |
| AES_CRYPT_CMD_MAX_SZ); |
| if (IS_ERR(s_buf)) { |
| dev_err(dev, "failed allocate source buf\n"); |
| fcs_close_services(priv, NULL, NULL); |
| return -ENOMEM; |
| } |
| |
| d_buf = stratix10_svc_allocate_memory(priv->chan, out_sz); |
| if (!d_buf) { |
| dev_err(dev, "failed allocate destation buf\n"); |
| fcs_close_services(priv, s_buf, NULL); |
| return -ENOMEM; |
| } |
| |
| while (remaining_size > 0) { |
| if (remaining_size > AES_CRYPT_CMD_MAX_SZ) { |
| /* Finalize stage require minimun 8bytes data size */ |
| if ((remaining_size - AES_CRYPT_CMD_MAX_SZ) >= |
| (CRYPTO_SERVICE_MIN_DATA_SIZE + sign_size)) { |
| data_size = AES_CRYPT_CMD_MAX_SZ; |
| ud_sz = AES_CRYPT_CMD_MAX_SZ; |
| dev_dbg(dev, "Update full. data_size=%d, ud_sz=%ld\n", |
| data_size, ud_sz); |
| } else { |
| data_size = (remaining_size - CRYPTO_SERVICE_MIN_DATA_SIZE - |
| sign_size); |
| ud_sz = (remaining_size - CRYPTO_SERVICE_MIN_DATA_SIZE - |
| sign_size); |
| dev_dbg(dev, "Update partial. data_size=%d, ud_sz=%ld\n", |
| data_size, ud_sz); |
| } |
| msg->command = COMMAND_FCS_CRYPTO_MAC_VERIFY_UPDATE; |
| } else { |
| data_size = remaining_size; |
| ud_sz = remaining_size - sign_size; |
| msg->command = COMMAND_FCS_CRYPTO_MAC_VERIFY_FINALIZE; |
| dev_dbg(dev, "Finalize. data_size=%d, ud_sz=%ld\n", data_size, |
| ud_sz); |
| } |
| |
| memcpy(s_buf, input_file_pointer, data_size); |
| |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->arg[2] = ud_sz; |
| msg->payload = s_buf; |
| msg->payload_length = data_size; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = out_sz; |
| priv->client.receive_cb = fcs_attestation_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| 10 * FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| if (priv->size > out_sz) { |
| dev_err(dev, "returned size %d is incorrect\n", |
| priv->size); |
| fcs_close_services(priv, s_buf, d_buf); |
| return -EFAULT; |
| } |
| } else { |
| data->com_paras.s_mac_data.dst = NULL; |
| data->com_paras.s_mac_data.dst_size = 0; |
| dev_err(dev, "unregconize response. ret=%d. status=%d\n", |
| ret, priv->status); |
| break; |
| } |
| |
| remaining_size -= data_size; |
| if (remaining_size == 0) { |
| dev_dbg(dev, "Crypto get verify finish sending\n"); |
| memcpy(data->com_paras.s_mac_data.dst, priv->kbuf, priv->size); |
| data->com_paras.s_mac_data.dst_size = priv->size; |
| break; |
| } else { |
| input_file_pointer += data_size; |
| dev_dbg(dev, "Complete one update. Remaining size = %d\n", |
| remaining_size); |
| } |
| } |
| |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_close_services(priv, s_buf, d_buf); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, s_buf, d_buf); |
| break; |
| |
| case INTEL_FCS_DEV_CRYPTO_ECDSA_HASH_SIGNING: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| sid = data->com_paras.ecdsa_data.sid; |
| cid = data->com_paras.ecdsa_data.cid; |
| kuid = data->com_paras.ecdsa_data.kuid; |
| in_sz = data->com_paras.ecdsa_data.src_size; |
| out_sz = data->com_paras.ecdsa_data.dst_size; |
| |
| msg->command = COMMAND_FCS_CRYPTO_ECDSA_HASH_SIGNING_INIT; |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->arg[2] = kuid; |
| msg->arg[3] = CRYPTO_ECC_PARAM_SZ; |
| msg->arg[4] = data->com_paras.ecdsa_data.ecc_algorithm & 0xF; |
| priv->client.receive_cb = fcs_vab_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (ret || priv->status) { |
| dev_err(dev, "failed to send the cmd=%d,ret=%d, status=%d\n", |
| COMMAND_FCS_CRYPTO_ECDSA_HASH_SIGNING_INIT, |
| ret, priv->status); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| |
| s_buf = stratix10_svc_allocate_memory(priv->chan, in_sz); |
| if (IS_ERR(s_buf)) { |
| dev_err(dev, "failed allocate source buf\n"); |
| fcs_close_services(priv, NULL, NULL); |
| return -ENOMEM; |
| } |
| |
| d_buf = stratix10_svc_allocate_memory(priv->chan, out_sz); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed allocate destation buf\n"); |
| fcs_close_services(priv, s_buf, NULL); |
| return -ENOMEM; |
| } |
| |
| memcpy(s_buf, data->com_paras.ecdsa_data.src, |
| data->com_paras.ecdsa_data.src_size); |
| |
| msg->command = COMMAND_FCS_CRYPTO_ECDSA_HASH_SIGNING_FINALIZE; |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->payload = s_buf; |
| msg->payload_length = in_sz; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = out_sz; |
| priv->client.receive_cb = fcs_attestation_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| 10 * FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| if (priv->size > out_sz) { |
| dev_err(dev, "returned size %d is incorrect\n", |
| priv->size); |
| fcs_close_services(priv, s_buf, d_buf); |
| return -EFAULT; |
| } |
| |
| memcpy(data->com_paras.ecdsa_data.dst, |
| priv->kbuf, priv->size); |
| data->com_paras.ecdsa_data.dst_size = priv->size; |
| } else { |
| data->com_paras.ecdsa_data.dst = NULL; |
| data->com_paras.ecdsa_data.dst_size = 0; |
| } |
| |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_close_services(priv, s_buf, d_buf); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, s_buf, d_buf); |
| break; |
| |
| case INTEL_FCS_DEV_CRYPTO_ECDSA_SHA2_DATA_SIGNING: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| sid = data->com_paras.ecdsa_data.sid; |
| cid = data->com_paras.ecdsa_data.cid; |
| kuid = data->com_paras.ecdsa_data.kuid; |
| in_sz = data->com_paras.ecdsa_data.src_size; |
| out_sz = data->com_paras.ecdsa_data.dst_size; |
| |
| msg->command = COMMAND_FCS_CRYPTO_ECDSA_SHA2_DATA_SIGNING_INIT; |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->arg[2] = kuid; |
| msg->arg[3] = CRYPTO_ECC_PARAM_SZ; |
| msg->arg[4] = data->com_paras.ecdsa_data.ecc_algorithm & 0xF; |
| priv->client.receive_cb = fcs_vab_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (ret || priv->status) { |
| dev_err(dev, "failed to send the cmd=%d,ret=%d, status=%d\n", |
| COMMAND_FCS_CRYPTO_ECDSA_HASH_SIGNING_INIT, |
| ret, priv->status); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| |
| input_file_pointer = data->com_paras.ecdsa_data.src; |
| |
| remaining_size = data->com_paras.ecdsa_data.src_size; |
| |
| s_buf = stratix10_svc_allocate_memory(priv->chan, |
| AES_CRYPT_CMD_MAX_SZ); |
| if (IS_ERR(s_buf)) { |
| dev_err(dev, "failed allocate source buf\n"); |
| fcs_close_services(priv, NULL, NULL); |
| return -ENOMEM; |
| } |
| |
| d_buf = stratix10_svc_allocate_memory(priv->chan, out_sz); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed allocate destation buf\n"); |
| fcs_close_services(priv, s_buf, NULL); |
| return -ENOMEM; |
| } |
| |
| while (remaining_size > 0) { |
| if (remaining_size > AES_CRYPT_CMD_MAX_SZ) { |
| msg->command = |
| COMMAND_FCS_CRYPTO_ECDSA_SHA2_DATA_SIGNING_UPDATE; |
| data_size = AES_CRYPT_CMD_MAX_SZ; |
| dev_dbg(dev, "ECDSA data sign update stage. data_size=%d\n", |
| data_size); |
| } else { |
| msg->command = |
| COMMAND_FCS_CRYPTO_ECDSA_SHA2_DATA_SIGNING_FINALIZE; |
| data_size = remaining_size; |
| dev_dbg(dev, "ECDSA data sign finalize stage. data_size=%d\n", |
| data_size); |
| } |
| |
| memcpy(s_buf, input_file_pointer, data_size); |
| |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->payload = s_buf; |
| msg->payload_length = data_size; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = out_sz; |
| priv->client.receive_cb = fcs_attestation_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| 10 * FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| if (priv->size > out_sz) { |
| dev_err(dev, "returned size %d is incorrect\n", |
| priv->size); |
| fcs_close_services(priv, s_buf, d_buf); |
| return -EFAULT; |
| } |
| } else { |
| data->com_paras.ecdsa_data.dst = NULL; |
| data->com_paras.ecdsa_data.dst_size = 0; |
| dev_err(dev, "unregconize response. ret=%d. status=%d\n", |
| ret, priv->status); |
| break; |
| } |
| |
| remaining_size -= data_size; |
| if (remaining_size == 0) { |
| dev_dbg(dev, "ECDSA data sign finish sending\n"); |
| memcpy(data->com_paras.ecdsa_data.dst, priv->kbuf, priv->size); |
| data->com_paras.ecdsa_data.dst_size = priv->size; |
| break; |
| } else { |
| input_file_pointer += data_size; |
| dev_dbg(dev, "Complete update. Remaining size = %d\n", |
| remaining_size); |
| } |
| } |
| |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_close_services(priv, s_buf, d_buf); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, s_buf, d_buf); |
| break; |
| |
| case INTEL_FCS_DEV_CRYPTO_ECDSA_HASH_VERIFY: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| sid = data->com_paras.ecdsa_data.sid; |
| cid = data->com_paras.ecdsa_data.cid; |
| kuid = data->com_paras.ecdsa_data.kuid; |
| in_sz = data->com_paras.ecdsa_data.src_size; |
| out_sz = data->com_paras.ecdsa_data.dst_size; |
| |
| msg->command = COMMAND_FCS_CRYPTO_ECDSA_HASH_VERIFY_INIT; |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->arg[2] = kuid; |
| msg->arg[3] = CRYPTO_ECC_PARAM_SZ; |
| msg->arg[4] = data->com_paras.ecdsa_data.ecc_algorithm & 0xF; |
| priv->client.receive_cb = fcs_vab_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (ret || priv->status) { |
| dev_err(dev, "failed to send the cmd=%d,ret=%d, status=%d\n", |
| COMMAND_FCS_CRYPTO_ECDSA_HASH_VERIFY_INIT, |
| ret, priv->status); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| |
| s_buf = stratix10_svc_allocate_memory(priv->chan, in_sz); |
| if (IS_ERR(s_buf)) { |
| dev_err(dev, "failed allocate source buf\n"); |
| fcs_close_services(priv, NULL, NULL); |
| return -ENOMEM; |
| } |
| |
| d_buf = stratix10_svc_allocate_memory(priv->chan, out_sz); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed allocate destation buf\n"); |
| fcs_close_services(priv, s_buf, NULL); |
| return -ENOMEM; |
| } |
| |
| memcpy(s_buf, data->com_paras.ecdsa_data.src, |
| data->com_paras.ecdsa_data.src_size); |
| |
| msg->command = COMMAND_FCS_CRYPTO_ECDSA_HASH_VERIFY_FINALIZE; |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->payload = s_buf; |
| msg->payload_length = in_sz; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = out_sz; |
| priv->client.receive_cb = fcs_attestation_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| 10 * FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| if (priv->size > out_sz) { |
| dev_err(dev, "returned size %d is incorrect\n", |
| priv->size); |
| fcs_close_services(priv, s_buf, d_buf); |
| return -EFAULT; |
| } |
| |
| memcpy(data->com_paras.ecdsa_data.dst, |
| priv->kbuf, priv->size); |
| data->com_paras.ecdsa_data.dst_size = priv->size; |
| } else { |
| data->com_paras.ecdsa_data.dst = NULL; |
| data->com_paras.ecdsa_data.dst_size = 0; |
| } |
| |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_close_services(priv, s_buf, d_buf); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, s_buf, d_buf); |
| |
| break; |
| |
| case INTEL_FCS_DEV_CRYPTO_ECDSA_SHA2_DATA_VERIFY: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| sid = data->com_paras.ecdsa_sha2_data.sid; |
| cid = data->com_paras.ecdsa_sha2_data.cid; |
| kuid = data->com_paras.ecdsa_sha2_data.kuid; |
| in_sz = data->com_paras.ecdsa_sha2_data.src_size; |
| out_sz = data->com_paras.ecdsa_sha2_data.dst_size; |
| ud_sz = data->com_paras.ecdsa_sha2_data.userdata_sz; |
| |
| msg->command = COMMAND_FCS_CRYPTO_ECDSA_SHA2_VERIFY_INIT; |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->arg[2] = kuid; |
| msg->arg[3] = CRYPTO_ECC_PARAM_SZ; |
| msg->arg[4] = data->com_paras.ecdsa_sha2_data.ecc_algorithm & 0xF; |
| priv->client.receive_cb = fcs_vab_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (ret || priv->status) { |
| dev_err(dev, "failed to send the cmd=%d,ret=%d, status=%d\n", |
| COMMAND_FCS_CRYPTO_ECDSA_SHA2_VERIFY_INIT, |
| ret, priv->status); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| |
| input_file_pointer = data->com_paras.ecdsa_sha2_data.src; |
| remaining_size = data->com_paras.ecdsa_sha2_data.src_size; |
| sign_size = data->com_paras.ecdsa_sha2_data.src_size - |
| data->com_paras.ecdsa_sha2_data.userdata_sz; |
| |
| s_buf = stratix10_svc_allocate_memory(priv->chan, |
| AES_CRYPT_CMD_MAX_SZ); |
| if (IS_ERR(s_buf)) { |
| dev_err(dev, "failed allocate source buf\n"); |
| fcs_close_services(priv, NULL, NULL); |
| return -ENOMEM; |
| } |
| |
| d_buf = stratix10_svc_allocate_memory(priv->chan, out_sz); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed allocate destation buf\n"); |
| fcs_close_services(priv, s_buf, NULL); |
| return -ENOMEM; |
| } |
| |
| while (remaining_size > 0) { |
| if (remaining_size > AES_CRYPT_CMD_MAX_SZ) { |
| /* Finalize stage require minimun 8bytes data size */ |
| if ((remaining_size - AES_CRYPT_CMD_MAX_SZ) >= |
| (CRYPTO_SERVICE_MIN_DATA_SIZE + sign_size)) { |
| data_size = AES_CRYPT_CMD_MAX_SZ; |
| ud_sz = AES_CRYPT_CMD_MAX_SZ; |
| dev_dbg(dev, "Update full. data_size=%d, ud_sz=%ld\n", |
| data_size, ud_sz); |
| } else { |
| data_size = (remaining_size - CRYPTO_SERVICE_MIN_DATA_SIZE - |
| sign_size); |
| ud_sz = (remaining_size - CRYPTO_SERVICE_MIN_DATA_SIZE - |
| sign_size); |
| dev_dbg(dev, "Update partial. data_size=%d, ud_sz=%ld\n", |
| data_size, ud_sz); |
| } |
| msg->command = COMMAND_FCS_CRYPTO_ECDSA_SHA2_VERIFY_UPDATE; |
| } else { |
| data_size = remaining_size; |
| ud_sz = remaining_size - sign_size; |
| msg->command = COMMAND_FCS_CRYPTO_ECDSA_SHA2_VERIFY_FINALIZE; |
| dev_dbg(dev, "Finalize. data_size=%d, ud_sz=%ld\n", data_size, |
| ud_sz); |
| } |
| |
| memcpy(s_buf, input_file_pointer, data_size); |
| |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->arg[2] = ud_sz; |
| msg->payload = s_buf; |
| msg->payload_length = data_size; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = out_sz; |
| priv->client.receive_cb = fcs_attestation_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| 10 * FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| if (priv->size > out_sz) { |
| dev_err(dev, "returned size %d is incorrect\n", |
| priv->size); |
| fcs_close_services(priv, s_buf, d_buf); |
| return -EFAULT; |
| } |
| } else { |
| data->com_paras.ecdsa_sha2_data.dst = NULL; |
| data->com_paras.ecdsa_sha2_data.dst_size = 0; |
| dev_err(dev, "unregconize response. ret=%d. status=%d\n", |
| ret, priv->status); |
| break; |
| } |
| |
| remaining_size -= data_size; |
| if (remaining_size == 0) { |
| dev_dbg(dev, "ECDSA data verify finish sending\n"); |
| memcpy(data->com_paras.ecdsa_sha2_data.dst, priv->kbuf, |
| priv->size); |
| data->com_paras.ecdsa_sha2_data.dst_size = priv->size; |
| break; |
| } else { |
| input_file_pointer += data_size; |
| dev_dbg(dev, "Complete one update. Remaining size = %d\n", |
| remaining_size); |
| } |
| } |
| |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_close_services(priv, s_buf, d_buf); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, s_buf, d_buf); |
| break; |
| |
| case INTEL_FCS_DEV_CRYPTO_ECDSA_GET_PUBLIC_KEY: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| sid = data->com_paras.ecdsa_data.sid; |
| cid = data->com_paras.ecdsa_data.cid; |
| kuid = data->com_paras.ecdsa_data.kuid; |
| out_sz = data->com_paras.ecdsa_data.dst_size; |
| |
| msg->command = COMMAND_FCS_CRYPTO_ECDSA_GET_PUBLIC_KEY_INIT; |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->arg[2] = kuid; |
| msg->arg[3] = CRYPTO_ECC_PARAM_SZ; |
| msg->arg[4] = data->com_paras.ecdsa_data.ecc_algorithm & 0xF; |
| priv->client.receive_cb = fcs_vab_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (ret || priv->status) { |
| dev_err(dev, "failed to send the cmd=%d,ret=%d, status=%d\n", |
| COMMAND_FCS_CRYPTO_ECDSA_GET_PUBLIC_KEY_INIT, |
| ret, priv->status); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| |
| d_buf = stratix10_svc_allocate_memory(priv->chan, out_sz); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed allocate destation buf\n"); |
| fcs_close_services(priv, NULL, NULL); |
| return -ENOMEM; |
| } |
| |
| msg->command = COMMAND_FCS_CRYPTO_ECDSA_GET_PUBLIC_KEY_FINALIZE; |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->payload = NULL; |
| msg->payload_length = 0; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = out_sz; |
| priv->client.receive_cb = fcs_attestation_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| 10 * FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| if (priv->size > out_sz) { |
| dev_err(dev, "returned size %d is incorrect\n", |
| priv->size); |
| fcs_close_services(priv, NULL, d_buf); |
| return -EFAULT; |
| } |
| |
| memcpy(data->com_paras.ecdsa_data.dst, |
| priv->kbuf, priv->size); |
| data->com_paras.ecdsa_data.dst_size = priv->size; |
| } else { |
| data->com_paras.ecdsa_data.dst = NULL; |
| data->com_paras.ecdsa_data.dst_size = 0; |
| } |
| |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_close_services(priv, NULL, d_buf); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, NULL, d_buf); |
| break; |
| |
| case INTEL_FCS_DEV_CRYPTO_ECDH_REQUEST: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.ecdsa_data.src_size == 0 || |
| data->com_paras.ecdsa_data.src == NULL) { |
| dev_err(dev, "Invalid ECDH request src param\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.ecdsa_data.dst_size == 0 || |
| data->com_paras.ecdsa_data.dst == NULL) { |
| dev_err(dev, "Invalid ECDH request dst param\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| sid = data->com_paras.ecdsa_data.sid; |
| cid = data->com_paras.ecdsa_data.cid; |
| kuid = data->com_paras.ecdsa_data.kuid; |
| in_sz = data->com_paras.ecdsa_data.src_size; |
| out_sz = data->com_paras.ecdsa_data.dst_size; |
| |
| msg->command = COMMAND_FCS_CRYPTO_ECDH_REQUEST_INIT; |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->arg[2] = kuid; |
| msg->arg[3] = CRYPTO_ECC_PARAM_SZ; |
| msg->arg[4] = data->com_paras.ecdsa_data.ecc_algorithm & 0xF; |
| priv->client.receive_cb = fcs_vab_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (ret || priv->status) { |
| dev_err(dev, "failed to send the cmd=%d,ret=%d, status=%d\n", |
| COMMAND_FCS_CRYPTO_ECDH_REQUEST_INIT, |
| ret, priv->status); |
| }; |
| |
| s_buf = stratix10_svc_allocate_memory(priv->chan, in_sz); |
| if (IS_ERR(s_buf)) { |
| dev_err(dev, "failed allocate source buf\n"); |
| fcs_close_services(priv, NULL, NULL); |
| return -ENOMEM; |
| } |
| |
| d_buf = stratix10_svc_allocate_memory(priv->chan, out_sz); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed allocate destation buf\n"); |
| fcs_close_services(priv, s_buf, NULL); |
| return -ENOMEM; |
| } |
| |
| /* Copy user data from user space to kernel space */ |
| ret = copy_from_user(s_buf, |
| data->com_paras.ecdsa_data.src, |
| data->com_paras.ecdsa_data.src_size); |
| if (ret) { |
| dev_err(dev, "failed copy buf ret=%d\n", ret); |
| fcs_close_services(priv, s_buf, d_buf); |
| return -EFAULT; |
| } |
| |
| msg->command = COMMAND_FCS_CRYPTO_ECDH_REQUEST_FINALIZE; |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->payload = s_buf; |
| msg->payload_length = in_sz; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = out_sz; |
| priv->client.receive_cb = fcs_attestation_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| 10 * FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| if (priv->size > out_sz) { |
| dev_err(dev, "returned size %d is incorrect\n", |
| priv->size); |
| fcs_close_services(priv, s_buf, d_buf); |
| return -EFAULT; |
| } |
| |
| memcpy(data->com_paras.ecdsa_data.dst, |
| priv->kbuf, priv->size); |
| data->com_paras.ecdsa_data.dst_size = priv->size; |
| } else { |
| data->com_paras.ecdsa_data.dst = NULL; |
| data->com_paras.ecdsa_data.dst_size = 0; |
| } |
| |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_close_services(priv, s_buf, d_buf); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, s_buf, d_buf); |
| break; |
| |
| case INTEL_FCS_DEV_RANDOM_NUMBER_GEN_EXT: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| sid = data->com_paras.rn_gen_ext.sid; |
| cid = data->com_paras.rn_gen_ext.cid; |
| out_sz = data->com_paras.rn_gen_ext.rng_sz; |
| buf_sz = RANDOM_NUMBER_EXT_SIZE + RANDOM_NUMBER_EXT_OFFSET; |
| |
| d_buf = stratix10_svc_allocate_memory(priv->chan, buf_sz); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed to allocate RNG_EXT output buf\n"); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| msg->command = COMMAND_FCS_RANDOM_NUMBER_GEN_EXT; |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->arg[2] = out_sz; |
| priv->client.receive_cb = fcs_attestation_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| dev_dbg(dev, "request service ret=%d\n", ret); |
| |
| timeout = 100; |
| if (!ret && !priv->status) { |
| /* to query the complete status */ |
| msg->arg[0] = ASYNC_POLL_SERVICE; |
| msg->payload = d_buf; |
| msg->payload_length = buf_sz; |
| msg->command = COMMAND_POLL_SERVICE_STATUS_ASYNC; |
| priv->client.receive_cb = fcs_data_callback; |
| |
| while (timeout != 0) { |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| dev_dbg(dev, "request service ret=%d\n", ret); |
| |
| if (!ret && !priv->status) { |
| if (priv->size == out_sz + RANDOM_NUMBER_EXT_OFFSET) { |
| memcpy(data->com_paras.rn_gen_ext.rng_data, |
| priv->kbuf + RANDOM_NUMBER_EXT_OFFSET, |
| out_sz); |
| data->com_paras.rn_gen_ext.rng_sz = out_sz; |
| break; |
| } |
| } else { |
| data->com_paras.rn_gen_ext.rng_data = NULL; |
| data->com_paras.rn_gen_ext.rng_sz = 0; |
| break; |
| } |
| timeout--; |
| mdelay(500); |
| } |
| } |
| |
| if (priv->status == 0 && timeout == 0) |
| data->status = -ETIMEDOUT; |
| else |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_close_services(priv, NULL, d_buf); |
| return -EFAULT; |
| } |
| |
| fcs_close_services(priv, NULL, d_buf); |
| break; |
| |
| case INTEL_FCS_DEV_SDOS_DATA_EXT: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.data_sdos_ext.src_size == 0 || |
| data->com_paras.data_sdos_ext.src == NULL) { |
| dev_err(dev, "Invalid SDOS request src param\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.data_sdos_ext.dst_size == 0 || |
| data->com_paras.data_sdos_ext.dst == NULL) { |
| dev_err(dev, "Invalid SDOS request dst param\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| sid = data->com_paras.data_sdos_ext.sid; |
| cid = data->com_paras.data_sdos_ext.cid; |
| in_sz = data->com_paras.data_sdos_ext.src_size; |
| |
| s_buf = stratix10_svc_allocate_memory(priv->chan, in_sz); |
| if (IS_ERR(s_buf)) { |
| dev_err(dev, "failed allocate source buf\n"); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| d_buf = stratix10_svc_allocate_memory(priv->chan, AES_CRYPT_CMD_MAX_SZ); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed allocate destation buf\n"); |
| fcs_free_memory(priv, s_buf, NULL, NULL); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| /* Copy user data from user space to kernel space */ |
| ret = copy_from_user(s_buf, |
| data->com_paras.data_sdos_ext.src, |
| data->com_paras.data_sdos_ext.src_size); |
| if (ret) { |
| dev_err(dev, "failed copy buf ret=%d\n", ret); |
| fcs_close_services(priv, s_buf, d_buf); |
| return -EFAULT; |
| } |
| |
| msg->command = COMMAND_FCS_SDOS_DATA_EXT; |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->arg[2] = data->com_paras.data_sdos_ext.op_mode; |
| msg->payload = s_buf; |
| msg->payload_length = in_sz; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = AES_CRYPT_CMD_MAX_SZ; |
| priv->client.receive_cb = fcs_sdos_data_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| 10 * FCS_REQUEST_TIMEOUT); |
| if (!ret && |
| (!priv->status || |
| priv->status == SDOS_DECRYPTION_ERROR_102 || |
| priv->status == SDOS_DECRYPTION_ERROR_103)) { |
| if (priv->size > AES_CRYPT_CMD_MAX_SZ) { |
| dev_err(dev, "returned size %d is incorrect\n", |
| priv->size); |
| fcs_close_services(priv, s_buf, d_buf); |
| return -EFAULT; |
| } |
| |
| memcpy(data->com_paras.data_sdos_ext.dst, |
| priv->kbuf, priv->size); |
| data->com_paras.data_sdos_ext.dst_size = priv->size; |
| } else { |
| data->com_paras.data_sdos_ext.dst = NULL; |
| data->com_paras.data_sdos_ext.dst_size = 0; |
| } |
| |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_close_services(priv, s_buf, d_buf); |
| return -EFAULT; |
| } |
| fcs_close_services(priv, s_buf, d_buf); |
| |
| break; |
| |
| case INTEL_FCS_DEV_MBOX_SEND: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.mbox_send_cmd.cmd_data_sz % 4) { |
| dev_err(dev, "Command data size (%d) is not 4 byte align\n", |
| data->com_paras.mbox_send_cmd.cmd_data_sz); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.mbox_send_cmd.rsp_data_sz % 4) { |
| dev_err(dev, "Respond data size (%d) is not 4 byte align\n", |
| data->com_paras.mbox_send_cmd.rsp_data_sz); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| if (data->com_paras.mbox_send_cmd.cmd_data_sz) { |
| s_buf = stratix10_svc_allocate_memory(priv->chan, |
| data->com_paras.mbox_send_cmd.cmd_data_sz); |
| if (IS_ERR(s_buf)) { |
| dev_err(dev, "failed allocate source CMD buf\n"); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| } else { |
| s_buf = NULL; |
| } |
| |
| if (data->com_paras.mbox_send_cmd.rsp_data_sz) { |
| d_buf = stratix10_svc_allocate_memory(priv->chan, |
| data->com_paras.mbox_send_cmd.rsp_data_sz); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed allocate destination RSP buf\n"); |
| fcs_free_memory(priv, s_buf, NULL, NULL); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| } else { |
| d_buf = NULL; |
| } |
| |
| if (s_buf != NULL) { |
| /* Copy user data from user space to kernel space */ |
| ret = copy_from_user(s_buf, |
| data->com_paras.mbox_send_cmd.cmd_data, |
| data->com_paras.mbox_send_cmd.cmd_data_sz); |
| if (ret) { |
| dev_err(dev, "failed copy buf ret=%d\n", ret); |
| fcs_free_memory(priv, s_buf, d_buf, NULL); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| } |
| |
| msg->command = COMMAND_MBOX_SEND_CMD; |
| msg->arg[0] = data->com_paras.mbox_send_cmd.mbox_cmd; |
| msg->arg[1] = data->com_paras.mbox_send_cmd.urgent; |
| msg->payload = s_buf; |
| msg->payload_length = data->com_paras.mbox_send_cmd.cmd_data_sz; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = data->com_paras.mbox_send_cmd.rsp_data_sz; |
| priv->client.receive_cb = fcs_mbox_send_cmd_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| 10 * FCS_REQUEST_TIMEOUT); |
| |
| if (!ret && !priv->status) { |
| if (priv->size > data->com_paras.mbox_send_cmd.rsp_data_sz) { |
| dev_err(dev, "Resp data size (%d) bigger than dest size\n", |
| priv->size); |
| fcs_close_services(priv, s_buf, d_buf); |
| return -EFAULT; |
| } |
| |
| data->com_paras.mbox_send_cmd.rsp_data_sz = priv->size; |
| |
| if (data->com_paras.mbox_send_cmd.rsp_data_sz) { |
| ret = copy_to_user(data->com_paras.mbox_send_cmd.rsp_data, d_buf, |
| data->com_paras.mbox_send_cmd.rsp_data_sz); |
| |
| if (ret) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| fcs_close_services(priv, s_buf, d_buf); |
| return -EFAULT; |
| } |
| } |
| } else { |
| data->com_paras.mbox_send_cmd.rsp_data = NULL; |
| data->com_paras.mbox_send_cmd.rsp_data_sz = 0; |
| } |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, s_buf, d_buf); |
| break; |
| |
| case INTEL_FCS_DEV_CHECK_SMMU_ENABLED: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| msg->command = COMMAND_SMC_SVC_VERSION; |
| priv->client.receive_cb = fcs_atf_version_smmu_check_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| |
| if (!ret && !priv->status) |
| data->status = -1; |
| else |
| return -EFAULT; |
| |
| data->status = priv->status; |
| |
| msg->command = COMMAND_FIRMWARE_VERSION; |
| priv->client.receive_cb = fcs_fw_version_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, NULL, NULL); |
| break; |
| |
| case INTEL_FCS_DEV_CRYPTO_AES_CRYPT_SMMU: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user data\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| iv_field_buf = stratix10_svc_allocate_memory(priv->chan, 28); |
| if (IS_ERR(iv_field_buf)) { |
| dev_err(dev, "failed allocate iv_field buf\n"); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| sid = data->com_paras.a_crypt.sid; |
| cid = data->com_paras.a_crypt.cid; |
| kuid = data->com_paras.a_crypt.kuid; |
| |
| memcpy(iv_field_buf, &data->com_paras.a_crypt.cpara.bmode, 1); |
| memcpy(iv_field_buf + 1, &data->com_paras.a_crypt.cpara.aes_mode, 1); |
| memcpy(iv_field_buf + 12, data->com_paras.a_crypt.cpara.iv_field, 16); |
| |
| msg->command = COMMAND_FCS_CRYPTO_AES_CRYPT_INIT; |
| msg->payload = iv_field_buf; |
| msg->payload_length = data->com_paras.a_crypt.cpara_size; |
| msg->payload_output = NULL; |
| msg->payload_length_output = 0; |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->arg[2] = kuid; |
| |
| priv->client.receive_cb = fcs_vab_callback; |
| |
| if (data->com_paras.a_crypt.init == true) { |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (ret || priv->status) { |
| dev_err(dev, "failed to send the cmd=%d,ret=%d\n", |
| COMMAND_FCS_CRYPTO_AES_CRYPT_INIT, |
| ret); |
| fcs_close_services(priv, iv_field_buf, NULL); |
| return -EFAULT; |
| } |
| } |
| fcs_free_memory(priv, iv_field_buf, NULL, NULL); |
| |
| remaining_size = data->com_paras.a_crypt.src_size; |
| |
| ps_buf = stratix10_svc_allocate_memory(priv->chan, PS_BUF_SIZE); |
| if (IS_ERR(ps_buf)) { |
| dev_err(dev, "failed to allocate p-status buf\n"); |
| fcs_close_services(priv, NULL, NULL); |
| return -ENOMEM; |
| } |
| |
| if (remaining_size > AES_BUFFER_CMD_MAX_SZ) { |
| msg->command = COMMAND_FCS_CRYPTO_AES_CRYPT_UPDATE_SMMU; |
| data_size = AES_BUFFER_CMD_MAX_SZ; |
| dev_dbg(dev, "AES crypt update. data_size=%d\n", data_size); |
| } else { |
| msg->command = COMMAND_FCS_CRYPTO_AES_CRYPT_FINALIZE_SMMU; |
| data_size = remaining_size; |
| dev_dbg(dev, "AES crypt finalize. data_size=%d\n", data_size); |
| } |
| |
| src_addr = get_buffer_addr(SRC_BUFFER_STARTING_L2_IDX); |
| dst_addr = get_buffer_addr((SRC_BUFFER_STARTING_L2_IDX + |
| data->com_paras.a_crypt.buffer_offset)); |
| |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->payload = &src_addr; |
| msg->payload_length = data_size; |
| msg->payload_output = &dst_addr; |
| msg->payload_length_output = data_size; |
| priv->client.receive_cb = fcs_attestation_callback; |
| |
| context_bank_enable(priv); |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| /* to query the complete status */ |
| msg->payload = ps_buf; |
| msg->payload_length = PS_BUF_SIZE; |
| msg->command = COMMAND_POLL_SERVICE_STATUS; |
| priv->client.receive_cb = fcs_data_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_COMPLETED_TIMEOUT); |
| if (!ret && !priv->status) { |
| if (!priv->kbuf || priv->size != 16) { |
| dev_err(dev, "unregconize response\n"); |
| context_bank_disable(priv); |
| fcs_close_services(priv, ps_buf, NULL); |
| return -EFAULT; |
| } |
| } |
| } else { |
| data->com_paras.a_crypt.dst = NULL; |
| data->com_paras.a_crypt.dst_size = 0; |
| dev_err(dev, "unregconize response. ret=%d. status=%d\n", |
| ret, priv->status); |
| context_bank_disable(priv); |
| fcs_close_services(priv, ps_buf, NULL); |
| return -EFAULT; |
| } |
| |
| context_bank_disable(priv); |
| invalidate_smmu_tlb_entries(priv); |
| |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, ps_buf, NULL); |
| break; |
| |
| case INTEL_FCS_DEV_CRYPTO_GET_DIGEST_SMMU: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| sid = data->com_paras.s_mac_data.sid; |
| cid = data->com_paras.s_mac_data.cid; |
| kuid = data->com_paras.s_mac_data.kuid; |
| |
| msg->command = COMMAND_FCS_CRYPTO_GET_DIGEST_INIT; |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->arg[2] = kuid; |
| msg->arg[3] = CRYPTO_ECC_PARAM_SZ; |
| msg->arg[4] = data->com_paras.s_mac_data.sha_op_mode | |
| (data->com_paras.s_mac_data.sha_digest_sz << |
| CRYPTO_ECC_DIGEST_SZ_OFFSET); |
| |
| priv->client.receive_cb = fcs_vab_callback; |
| if (data->com_paras.s_mac_data.init == true) { |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (ret || priv->status) { |
| dev_err(dev, "failed to send the cmd=%d,ret=%d, status=%d\n", |
| COMMAND_FCS_CRYPTO_GET_DIGEST_INIT, ret, priv->status); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| } |
| |
| remaining_size = data->com_paras.s_mac_data.src_size; |
| |
| d_buf = stratix10_svc_allocate_memory(priv->chan, |
| AES_CRYPT_CMD_MAX_SZ); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed allocate destation buf\n"); |
| fcs_close_services(priv, NULL, NULL); |
| return -ENOMEM; |
| } |
| |
| ps_buf = stratix10_svc_allocate_memory(priv->chan, SMMU_BUF_SIZE); |
| if (IS_ERR(ps_buf)) { |
| dev_err(dev, "failed to allocate p-status buf\n"); |
| fcs_close_services(priv, d_buf, NULL); |
| return -ENOMEM; |
| } |
| |
| if (remaining_size > HMAC_CMD_MAX_SZ) { |
| msg->command = COMMAND_FCS_CRYPTO_GET_DIGEST_UPDATE_SMMU; |
| data_size = HMAC_CMD_MAX_SZ; |
| dev_dbg(dev, "Crypto get digest update. data_size=%d\n", |
| data_size); |
| } else { |
| msg->command = COMMAND_FCS_CRYPTO_GET_DIGEST_FINALIZE_SMMU; |
| data_size = remaining_size; |
| dev_dbg(dev, "Crypto get digest finalize. data_size=%d\n", |
| data_size); |
| } |
| |
| src_addr = get_buffer_addr(SRC_BUFFER_STARTING_L2_IDX); |
| |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->payload = &src_addr; |
| msg->payload_length = data_size; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = AES_CRYPT_CMD_MAX_SZ; |
| priv->client.receive_cb = fcs_attestation_callback; |
| |
| context_bank_enable(priv); |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| 10 * FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| /* to query the complete status */ |
| msg->payload = ps_buf; |
| msg->payload_length = SMMU_BUF_SIZE; |
| msg->command = COMMAND_POLL_SERVICE_STATUS; |
| priv->client.receive_cb = fcs_data_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_COMPLETED_TIMEOUT); |
| if (!ret && !priv->status) { |
| if (!priv->kbuf) { |
| dev_err(dev, "unregconize response\n"); |
| context_bank_disable(priv); |
| fcs_close_services(priv, d_buf, ps_buf); |
| return -EFAULT; |
| } |
| } |
| } else { |
| data->com_paras.s_mac_data.dst = NULL; |
| data->com_paras.s_mac_data.dst_size = 0; |
| dev_err(dev, "unregconize response. ret=%d. status=%d\n", |
| ret, priv->status); |
| context_bank_disable(priv); |
| fcs_close_services(priv, d_buf, ps_buf); |
| return -EFAULT; |
| } |
| |
| remaining_size -= data_size; |
| if (remaining_size == 0) { |
| dev_dbg(dev, "Crypto get digest finish sending\n"); |
| memcpy(data->com_paras.s_mac_data.dst, priv->kbuf, priv->size); |
| data->com_paras.s_mac_data.dst_size = priv->size; |
| } |
| |
| context_bank_disable(priv); |
| invalidate_smmu_tlb_entries(priv); |
| |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, ps_buf, d_buf); |
| break; |
| |
| case INTEL_FCS_DEV_CRYPTO_MAC_VERIFY_SMMU: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| sid = data->com_paras.s_mac_data.sid; |
| cid = data->com_paras.s_mac_data.cid; |
| kuid = data->com_paras.s_mac_data.kuid; |
| out_sz = data->com_paras.s_mac_data.dst_size; |
| ud_sz = data->com_paras.s_mac_data.userdata_sz; |
| |
| msg->command = COMMAND_FCS_CRYPTO_MAC_VERIFY_INIT; |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->arg[2] = kuid; |
| msg->arg[3] = CRYPTO_ECC_PARAM_SZ; |
| msg->arg[4] = data->com_paras.s_mac_data.sha_op_mode | |
| (data->com_paras.s_mac_data.sha_digest_sz << |
| CRYPTO_ECC_DIGEST_SZ_OFFSET); |
| priv->client.receive_cb = fcs_vab_callback; |
| |
| if (data->com_paras.s_mac_data.init == true) { |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (ret || priv->status) { |
| dev_err(dev, "failed to send the cmd=%d,ret=%d, status=%d\n", |
| COMMAND_FCS_CRYPTO_MAC_VERIFY_INIT, ret, priv->status); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| } |
| |
| remaining_size = data->com_paras.s_mac_data.src_size; |
| |
| d_buf = stratix10_svc_allocate_memory(priv->chan, out_sz); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed allocate destation buf\n"); |
| fcs_close_services(priv, NULL, NULL); |
| return -ENOMEM; |
| } |
| |
| ps_buf = stratix10_svc_allocate_memory(priv->chan, SMMU_BUF_SIZE); |
| if (IS_ERR(ps_buf)) { |
| dev_err(dev, "failed to allocate p-status buf\n"); |
| fcs_close_services(priv, d_buf, NULL); |
| return -ENOMEM; |
| } |
| |
| if (remaining_size > HMAC_CMD_MAX_SZ) { |
| if (data->com_paras.s_mac_data.userdata_sz >= HMAC_CMD_MAX_SZ) { |
| data_size = HMAC_CMD_MAX_SZ; |
| ud_sz = HMAC_CMD_MAX_SZ; |
| } else { |
| data_size = data->com_paras.s_mac_data.userdata_sz; |
| ud_sz = data->com_paras.s_mac_data.userdata_sz; |
| } |
| msg->command = COMMAND_FCS_CRYPTO_MAC_VERIFY_UPDATE_SMMU; |
| } else { |
| data_size = remaining_size; |
| ud_sz = data->com_paras.s_mac_data.userdata_sz; |
| memcpy(d_buf, (source_ptr+ud_sz), (remaining_size-ud_sz)); |
| msg->command = COMMAND_FCS_CRYPTO_MAC_VERIFY_FINALIZE_SMMU; |
| dev_dbg(dev, "Finalize. data_size=%d, ud_sz=%ld\n", data_size, |
| ud_sz); |
| |
| } |
| |
| src_addr = get_buffer_addr(SRC_BUFFER_STARTING_L2_IDX); |
| |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->arg[2] = ud_sz; |
| msg->payload = &src_addr; |
| msg->payload_length = data_size; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = out_sz; |
| priv->client.receive_cb = fcs_attestation_callback; |
| |
| context_bank_enable(priv); |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| 10 * FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| /* to query the complete status */ |
| msg->payload = ps_buf; |
| msg->payload_length = SMMU_BUF_SIZE; |
| msg->command = COMMAND_POLL_SERVICE_STATUS; |
| priv->client.receive_cb = fcs_data_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_COMPLETED_TIMEOUT); |
| if (!ret && !priv->status) { |
| if (!priv->kbuf) { |
| dev_err(dev, "unregconize response\n"); |
| context_bank_disable(priv); |
| fcs_close_services(priv, d_buf, ps_buf); |
| return -EFAULT; |
| } |
| } |
| } else { |
| data->com_paras.s_mac_data.dst = NULL; |
| data->com_paras.s_mac_data.dst_size = 0; |
| dev_err(dev, "unregconize response. ret=%d. status=%d\n", |
| ret, priv->status); |
| context_bank_disable(priv); |
| fcs_close_services(priv, ps_buf, d_buf); |
| return -EFAULT; |
| } |
| |
| remaining_size -= data_size; |
| if (remaining_size == 0) { |
| dev_dbg(dev, "Crypto get verify finish sending\n"); |
| memcpy(data->com_paras.s_mac_data.dst, priv->kbuf, priv->size); |
| data->com_paras.s_mac_data.dst_size = priv->size; |
| } |
| |
| context_bank_disable(priv); |
| invalidate_smmu_tlb_entries(priv); |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, ps_buf, d_buf); |
| break; |
| |
| case INTEL_FCS_DEV_CRYPTO_ECDSA_SHA2_DATA_SIGNING_SMMU: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| sid = data->com_paras.ecdsa_data.sid; |
| cid = data->com_paras.ecdsa_data.cid; |
| kuid = data->com_paras.ecdsa_data.kuid; |
| in_sz = data->com_paras.ecdsa_data.src_size; |
| out_sz = data->com_paras.ecdsa_data.dst_size; |
| |
| msg->command = COMMAND_FCS_CRYPTO_ECDSA_SHA2_DATA_SIGNING_INIT; |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->arg[2] = kuid; |
| msg->arg[3] = CRYPTO_ECC_PARAM_SZ; |
| msg->arg[4] = data->com_paras.ecdsa_data.ecc_algorithm & 0xF; |
| priv->client.receive_cb = fcs_vab_callback; |
| |
| if (data->com_paras.ecdsa_data.init == true) { |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (ret || priv->status) { |
| dev_err(dev, "failed to send the cmd=%d,ret=%d, status=%d\n", |
| COMMAND_FCS_CRYPTO_ECDSA_HASH_SIGNING_INIT, |
| ret, priv->status); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| } |
| |
| remaining_size = data->com_paras.ecdsa_data.src_size; |
| |
| d_buf = stratix10_svc_allocate_memory(priv->chan, out_sz); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed allocate destation buf\n"); |
| fcs_close_services(priv, NULL, NULL); |
| return -ENOMEM; |
| } |
| |
| ps_buf = stratix10_svc_allocate_memory(priv->chan, SMMU_BUF_SIZE); |
| if (IS_ERR(ps_buf)) { |
| dev_err(dev, "failed to allocate p-status buf\n"); |
| fcs_close_services(priv, d_buf, NULL); |
| return -ENOMEM; |
| } |
| |
| if (remaining_size > ECDSA_CMD_MAX_SZ) { |
| msg->command = |
| COMMAND_FCS_CRYPTO_ECDSA_SHA2_DATA_SIGNING_UPDATE_SMMU; |
| data_size = ECDSA_CMD_MAX_SZ; |
| dev_dbg(dev, "ECDSA data sign update stage. data_size=%d\n", |
| data_size); |
| } else { |
| msg->command = |
| COMMAND_FCS_CRYPTO_ECDSA_SHA2_DATA_SIGNING_FINALIZE_SMMU; |
| data_size = remaining_size; |
| dev_dbg(dev, "ECDSA data sign finalize stage. data_size=%d\n", |
| data_size); |
| } |
| |
| src_addr = get_buffer_addr(SRC_BUFFER_STARTING_L2_IDX); |
| |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->payload = &src_addr; |
| msg->payload_length = data_size; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = out_sz; |
| priv->client.receive_cb = fcs_attestation_callback; |
| |
| context_bank_enable(priv); |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| 10 * FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| msg->payload = ps_buf; |
| msg->payload_length = SMMU_BUF_SIZE; |
| msg->command = COMMAND_POLL_SERVICE_STATUS; |
| priv->client.receive_cb = fcs_data_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_COMPLETED_TIMEOUT); |
| if (!ret && !priv->status) { |
| if (!priv->kbuf) { |
| dev_err(dev, "unregconize response\n"); |
| context_bank_disable(priv); |
| fcs_close_services(priv, d_buf, ps_buf); |
| return -EFAULT; |
| } |
| } |
| } else { |
| data->com_paras.ecdsa_data.dst = NULL; |
| data->com_paras.ecdsa_data.dst_size = 0; |
| dev_err(dev, "unregconize response. ret=%d. status=%d\n", |
| ret, priv->status); |
| context_bank_disable(priv); |
| fcs_close_services(priv, d_buf, ps_buf); |
| return -EFAULT; |
| } |
| |
| remaining_size -= data_size; |
| if (remaining_size == 0) { |
| dev_dbg(dev, "ECDSA data sign finish sending\n"); |
| memcpy(data->com_paras.ecdsa_data.dst, priv->kbuf, priv->size); |
| data->com_paras.ecdsa_data.dst_size = priv->size; |
| } |
| |
| context_bank_disable(priv); |
| invalidate_smmu_tlb_entries(priv); |
| |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, ps_buf, d_buf); |
| break; |
| |
| case INTEL_FCS_DEV_CRYPTO_ECDSA_SHA2_DATA_VERIFY_SMMU: |
| if (copy_from_user(data, (void __user *)arg, sizeof(*data))) { |
| dev_err(dev, "failure on copy_from_user\n"); |
| mutex_unlock(&priv->lock); |
| return -EFAULT; |
| } |
| |
| sid = data->com_paras.ecdsa_sha2_data.sid; |
| cid = data->com_paras.ecdsa_sha2_data.cid; |
| kuid = data->com_paras.ecdsa_sha2_data.kuid; |
| in_sz = data->com_paras.ecdsa_sha2_data.src_size; |
| out_sz = data->com_paras.ecdsa_sha2_data.dst_size; |
| ud_sz = data->com_paras.ecdsa_sha2_data.userdata_sz; |
| |
| msg->command = COMMAND_FCS_CRYPTO_ECDSA_SHA2_VERIFY_INIT; |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->arg[2] = kuid; |
| msg->arg[3] = CRYPTO_ECC_PARAM_SZ; |
| msg->arg[4] = data->com_paras.ecdsa_sha2_data.ecc_algorithm & 0xF; |
| priv->client.receive_cb = fcs_vab_callback; |
| |
| if (data->com_paras.ecdsa_sha2_data.init == true) { |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (ret || priv->status) { |
| dev_err(dev, "failed to send the cmd=%d,ret=%d, status=%d\n", |
| COMMAND_FCS_CRYPTO_ECDSA_SHA2_VERIFY_INIT, |
| ret, priv->status); |
| fcs_close_services(priv, NULL, NULL); |
| return -EFAULT; |
| } |
| } |
| |
| remaining_size = data->com_paras.ecdsa_sha2_data.src_size; |
| |
| d_buf = stratix10_svc_allocate_memory(priv->chan, SMMU_BUF_SIZE); |
| if (IS_ERR(d_buf)) { |
| dev_err(dev, "failed allocate destation buf\n"); |
| fcs_close_services(priv, NULL, NULL); |
| return -ENOMEM; |
| } |
| |
| ps_buf = stratix10_svc_allocate_memory(priv->chan, SMMU_BUF_SIZE); |
| if (IS_ERR(ps_buf)) { |
| dev_err(dev, "failed to allocate p-status buf\n"); |
| fcs_close_services(priv, d_buf, NULL); |
| return -ENOMEM; |
| } |
| |
| if (remaining_size > ECDSA_CMD_MAX_SZ) { |
| if (data->com_paras.s_mac_data.userdata_sz >= ECDSA_CMD_MAX_SZ) { |
| data_size = ECDSA_CMD_MAX_SZ; |
| ud_sz = ECDSA_CMD_MAX_SZ; |
| } else { |
| data_size = data->com_paras.ecdsa_sha2_data.userdata_sz; |
| ud_sz = data->com_paras.ecdsa_sha2_data.userdata_sz; |
| } |
| msg->command = COMMAND_FCS_CRYPTO_ECDSA_SHA2_VERIFY_UPDATE_SMMU; |
| } else { |
| data_size = remaining_size; |
| ud_sz = data->com_paras.ecdsa_sha2_data.userdata_sz; |
| memcpy(d_buf, (source_ptr+ud_sz), (remaining_size-ud_sz)); |
| msg->command = COMMAND_FCS_CRYPTO_ECDSA_SHA2_VERIFY_FINALIZE_SMMU; |
| dev_dbg(dev, "Finalize. data_size=%d, ud_sz=%ld\n", data_size, |
| ud_sz); |
| } |
| |
| src_addr = get_buffer_addr(SRC_BUFFER_STARTING_L2_IDX); |
| |
| msg->arg[0] = sid; |
| msg->arg[1] = cid; |
| msg->arg[2] = ud_sz; |
| msg->payload = &src_addr; |
| msg->payload_length = data_size; |
| msg->payload_output = d_buf; |
| msg->payload_length_output = out_sz; |
| priv->client.receive_cb = fcs_attestation_callback; |
| |
| context_bank_enable(priv); |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| 10 * FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| /* to query the complete status */ |
| msg->payload = ps_buf; |
| msg->payload_length = SMMU_BUF_SIZE; |
| msg->command = COMMAND_POLL_SERVICE_STATUS; |
| priv->client.receive_cb = fcs_data_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_COMPLETED_TIMEOUT); |
| if (!ret && !priv->status) { |
| if (!priv->kbuf) { |
| dev_err(dev, "unregconize response\n"); |
| context_bank_disable(priv); |
| fcs_close_services(priv, d_buf, ps_buf); |
| return -EFAULT; |
| } |
| } |
| } else { |
| data->com_paras.ecdsa_sha2_data.dst = NULL; |
| data->com_paras.ecdsa_sha2_data.dst_size = 0; |
| dev_err(dev, "unregconize response. ret=%d. status=%d\n", |
| ret, priv->status); |
| context_bank_disable(priv); |
| fcs_close_services(priv, d_buf, ps_buf); |
| return -EFAULT; |
| } |
| |
| remaining_size -= data_size; |
| if (remaining_size == 0) { |
| dev_dbg(dev, "ECDSA data verify finish sending\n"); |
| memcpy(data->com_paras.ecdsa_sha2_data.dst, priv->kbuf, |
| priv->size); |
| data->com_paras.ecdsa_sha2_data.dst_size = priv->size; |
| } |
| |
| context_bank_disable(priv); |
| invalidate_smmu_tlb_entries(priv); |
| data->status = priv->status; |
| |
| if (copy_to_user((void __user *)arg, data, sizeof(*data))) { |
| dev_err(dev, "failure on copy_to_user\n"); |
| ret = -EFAULT; |
| } |
| |
| fcs_close_services(priv, d_buf, ps_buf); |
| break; |
| |
| default: |
| mutex_unlock(&priv->lock); |
| dev_warn(dev, "shouldn't be here [0x%x]\n", cmd); |
| break; |
| } |
| |
| return ret; |
| } |
| |
| static int fcs_open(struct inode *inode, struct file *file) |
| { |
| pr_debug("%s\n", __func__); |
| |
| return 0; |
| } |
| |
| static int fcs_close(struct inode *inode, struct file *file) |
| { |
| |
| pr_debug("%s\n", __func__); |
| |
| return 0; |
| } |
| |
| static int fcs_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait) |
| { |
| struct stratix10_svc_client_msg *msg; |
| struct intel_fcs_priv *priv; |
| struct device *dev; |
| void *s_buf; |
| int ret = 0; |
| size_t size = 0; |
| |
| priv = (struct intel_fcs_priv *)rng->priv; |
| dev = priv->client.dev; |
| mutex_lock(&priv->lock); |
| msg = devm_kzalloc(dev, sizeof(*msg), GFP_KERNEL); |
| if (!msg) { |
| dev_err(dev, "failed to allocate msg buffer\n"); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| s_buf = stratix10_svc_allocate_memory(priv->chan, |
| RANDOM_NUMBER_SIZE); |
| if (IS_ERR(s_buf)) { |
| dev_err(dev, "failed to allocate random number buffer\n"); |
| mutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| msg->command = COMMAND_FCS_RANDOM_NUMBER_GEN; |
| msg->payload = s_buf; |
| msg->payload_length = RANDOM_NUMBER_SIZE; |
| priv->client.receive_cb = fcs_hwrng_callback; |
| |
| ret = fcs_request_service(priv, (void *)msg, |
| FCS_REQUEST_TIMEOUT); |
| if (!ret && !priv->status) { |
| if (priv->size && priv->kbuf) { |
| if (max > priv->size) |
| size = priv->size; |
| else |
| size = max; |
| |
| memcpy((uint8_t *)buf, (uint8_t *)priv->kbuf, size); |
| } |
| } |
| |
| fcs_close_services(priv, s_buf, NULL); |
| |
| if (size == 0) |
| return -ENOTSUPP; |
| |
| return size; |
| } |
| |
| static int fcs_mmap(struct file *filp, struct vm_area_struct *vma) |
| { |
| unsigned long size, off; |
| struct page *page; |
| |
| if (!source_ptr) { |
| pr_err("vmalloc failed mmap %s", __func__); |
| return -ENOMEM; |
| } |
| |
| size = vma->vm_end - vma->vm_start; |
| |
| vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); |
| vma->vm_flags |= VM_DONTEXPAND; |
| for (off = 0; off < size; off += PAGE_SIZE) { |
| page = vmalloc_to_page(source_ptr + off); |
| if (vm_insert_page(vma, vma->vm_start + off, page)) |
| pr_err("vm_insert_page() failed"); |
| |
| } |
| |
| return 0; |
| } |
| |
| static const struct file_operations fcs_fops = { |
| .owner = THIS_MODULE, |
| .unlocked_ioctl = fcs_ioctl, |
| .open = fcs_open, |
| .release = fcs_close, |
| .mmap = fcs_mmap |
| }; |
| |
| static int fcs_driver_probe(struct platform_device *pdev) |
| { |
| struct device *dev = &pdev->dev; |
| struct intel_fcs_priv *priv; |
| int ret, i; |
| const char *platform; |
| struct stratix10_svc_client_msg msg; |
| unsigned long off; |
| int l2_idx = SRC_BUFFER_STARTING_L2_IDX; |
| int l3_idx = 0; |
| uint64_t phys; |
| unsigned long pfn; |
| struct page *page; |
| |
| priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
| if (!priv) |
| return -ENOMEM; |
| |
| priv->client.dev = dev; |
| priv->client.receive_cb = NULL; |
| priv->client.priv = priv; |
| priv->kbuf = NULL; |
| priv->size = 0; |
| priv->status = INVALID_STATUS; |
| priv->cid_low = INVALID_ID; |
| priv->cid_high = INVALID_ID; |
| priv->sid = INVALID_ID; |
| |
| mutex_init(&priv->lock); |
| priv->chan = stratix10_svc_request_channel_byname(&priv->client, |
| SVC_CLIENT_FCS); |
| if (IS_ERR(priv->chan)) { |
| dev_err(dev, "couldn't get service channel %s\n", |
| SVC_CLIENT_FCS); |
| return PTR_ERR(priv->chan); |
| } |
| |
| priv->miscdev.minor = MISC_DYNAMIC_MINOR; |
| priv->miscdev.name = "fcs"; |
| priv->miscdev.fops = &fcs_fops; |
| |
| init_completion(&priv->completion); |
| |
| ret = misc_register(&priv->miscdev); |
| if (ret) { |
| dev_err(dev, "can't register on minor=%d\n", |
| MISC_DYNAMIC_MINOR); |
| goto release_channel; |
| } |
| |
| priv->p_data = of_device_get_match_data(dev); |
| if (!priv->p_data) |
| goto cleanup; |
| |
| ret = of_property_read_string(dev->of_node, "platform", &platform); |
| if (ret) { |
| dev_err(dev, "can't find platform"); |
| goto cleanup; |
| } |
| |
| /* Proceed only if platform is agilex as |
| * register addresses are platform specific |
| */ |
| if (!strncmp(platform, AGILEX_PLATFORM, AGILEX_PLATFORM_STR_LEN)) { |
| |
| msg.command = COMMAND_SMC_SVC_VERSION; |
| priv->client.receive_cb = fcs_atf_version_smmu_check_callback; |
| |
| ret = stratix10_svc_send(priv->chan, &msg); |
| if (ret) |
| return -EINVAL; |
| |
| ret = wait_for_completion_timeout(&priv->completion, |
| FCS_REQUEST_TIMEOUT); |
| if (!ret) { |
| dev_err(priv->client.dev, "timeout waiting for SMC call\n"); |
| ret = -ETIMEDOUT; |
| return ret; |
| } |
| |
| /* Program registers only if ATF support programming |
| * SMMU secure register addresses |
| */ |
| if (priv->status == 0) { |
| l1_table = kmalloc((sizeof(uint64_t)*512), GFP_KERNEL); |
| if (!l1_table) |
| return -ENOMEM; |
| l2_table = kmalloc((sizeof(uint64_t)*512), GFP_KERNEL); |
| if (!l2_table) |
| return -ENOMEM; |
| |
| memcpy(l1_table, smmu_sdm_el3_l1_table, (sizeof(uint64_t)*512)); |
| memcpy(l2_table, smmu_sdm_el3_l2_table, (sizeof(uint64_t)*512)); |
| |
| for (i = 0; i < 512; i++) { |
| l3_tables[i] = kmalloc((sizeof(uint64_t)*512), GFP_KERNEL); |
| if (!l3_tables[i]) |
| return -ENOMEM; |
| memcpy(l3_tables[i], smmu_sdm_l3_def_table, (sizeof(uint64_t)*512)); |
| } |
| |
| if (source_ptr) |
| vfree(source_ptr); |
| |
| source_ptr = vmalloc_user(SMMU_MAX_ALLOC_SZ); |
| if (!source_ptr) { |
| pr_err("vmalloc failed probe %s", __func__); |
| return -ENOMEM; |
| } |
| |
| for (off = 0; off < SMMU_MAX_ALLOC_SZ; off += PAGE_SIZE) { |
| page = vmalloc_to_page(source_ptr + off); |
| pfn = page_to_pfn(page); |
| phys = __pa(pfn_to_kaddr(pfn)) + offset_in_page(source_ptr + off); |
| |
| if (l3_idx >= 512) { |
| l2_idx++; |
| l3_idx = 0; |
| } |
| fill_l3_table(phys, l2_idx, l3_idx); |
| l3_idx++; |
| } |
| |
| intel_fcs_smmu_init(priv); |
| } |
| } |
| |
| /* only register the HW RNG if the platform supports it! */ |
| if (priv->p_data->have_hwrng) { |
| /* register hwrng device */ |
| priv->rng.name = "intel-rng"; |
| priv->rng.read = fcs_rng_read; |
| priv->rng.priv = (unsigned long)priv; |
| |
| ret = hwrng_register(&priv->rng); |
| if (ret) { |
| dev_err(dev, "can't register RNG device (%d)\n", ret); |
| return ret; |
| } |
| } else { |
| /* Notes of registering /dev/hwrng: |
| * 1 For now, /dev/hwrng is not supported on Agilex devices |
| * due to hardware implementation. |
| * 2 It means On Agilex devices, /dev/hwrng is a dummy node |
| * without HW backend. You can get the HW RNG function by |
| * IOCTL command provided from this driver on Agilex devices. |
| * 3 In the future, it may be implemented in a different way. |
| */ |
| dev_notice(dev, "/dev/hwrng is not supported on Agilex devices.\n"); |
| } |
| |
| platform_set_drvdata(pdev, priv); |
| |
| return 0; |
| |
| cleanup: |
| misc_deregister(&priv->miscdev); |
| release_channel: |
| stratix10_svc_free_channel(priv->chan); |
| return -ENODEV; |
| } |
| |
| static int fcs_driver_remove(struct platform_device *pdev) |
| { |
| struct device *dev = &pdev->dev; |
| struct intel_fcs_priv *priv = platform_get_drvdata(pdev); |
| struct stratix10_svc_client_msg msg; |
| int i, ret; |
| const char *platform; |
| |
| ret = of_property_read_string(dev->of_node, "platform", &platform); |
| if (ret) |
| goto no_platform; |
| |
| if (!strncmp(platform, AGILEX_PLATFORM, AGILEX_PLATFORM_STR_LEN)) { |
| msg.command = COMMAND_SMC_SVC_VERSION; |
| priv->client.receive_cb = fcs_atf_version_smmu_check_callback; |
| |
| ret = stratix10_svc_send(priv->chan, &msg); |
| |
| ret = wait_for_completion_timeout(&priv->completion, |
| FCS_REQUEST_TIMEOUT); |
| |
| /* Program registers only if ATF support programming |
| * SMMU secure register addresses |
| */ |
| if (priv->status == 0) { |
| kfree(l1_table); |
| kfree(l2_table); |
| |
| for (i = 0; i < 512; i++) |
| kfree(l3_tables[i]); |
| |
| if (source_ptr) |
| vfree(source_ptr); |
| |
| context_bank_disable(priv); |
| } |
| } |
| |
| no_platform: |
| if (priv->p_data->have_hwrng) |
| hwrng_unregister(&priv->rng); |
| misc_deregister(&priv->miscdev); |
| stratix10_svc_free_channel(priv->chan); |
| |
| return 0; |
| } |
| |
| /* Note: /dev/hwrng is not supported on Agilex devices now! */ |
| static const struct socfpga_fcs_data agilex_fcs_data = { |
| .have_hwrng = false, |
| }; |
| |
| static const struct socfpga_fcs_data n5x_fcs_data = { |
| .have_hwrng = true, |
| }; |
| |
| static const struct socfpga_fcs_data s10_fcs_data = { |
| .have_hwrng = true, |
| }; |
| |
| static const struct of_device_id fcs_of_match[] = { |
| {.compatible = "intel,stratix10-soc-fcs", |
| .data = &s10_fcs_data |
| }, |
| {.compatible = "intel,agilex-soc-fcs", |
| .data = &agilex_fcs_data |
| }, |
| {.compatible = "intel,n5x-soc-fcs", |
| .data = &n5x_fcs_data |
| }, |
| {}, |
| }; |
| |
| static struct platform_driver fcs_driver = { |
| .probe = fcs_driver_probe, |
| .remove = fcs_driver_remove, |
| .driver = { |
| .name = "intel-fcs", |
| .of_match_table = of_match_ptr(fcs_of_match), |
| }, |
| }; |
| |
| MODULE_DEVICE_TABLE(of, fcs_of_match); |
| |
| static int __init fcs_init(void) |
| { |
| struct device_node *fw_np; |
| struct device_node *np; |
| int ret; |
| |
| fw_np = of_find_node_by_name(NULL, "svc"); |
| if (!fw_np) |
| return -ENODEV; |
| |
| of_node_get(fw_np); |
| np = of_find_matching_node(fw_np, fcs_of_match); |
| if (!np) { |
| of_node_put(fw_np); |
| return -ENODEV; |
| } |
| |
| of_node_put(np); |
| ret = of_platform_populate(fw_np, fcs_of_match, NULL, NULL); |
| of_node_put(fw_np); |
| if (ret) |
| return ret; |
| |
| return platform_driver_register(&fcs_driver); |
| } |
| |
| static void __exit fcs_exit(void) |
| { |
| return platform_driver_unregister(&fcs_driver); |
| } |
| |
| module_init(fcs_init); |
| module_exit(fcs_exit); |
| |
| MODULE_LICENSE("GPL v2"); |
| MODULE_DESCRIPTION("Intel FGPA Crypto Services Driver"); |
| MODULE_AUTHOR("Richard Gong <[email protected]>"); |