0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/acpi.h>
0013 #include <linux/of.h>
0014 #include <linux/of_platform.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/tee_drv.h>
0017 #include <linux/tpm.h>
0018 #include <linux/uuid.h>
0019
0020 #include "tpm.h"
0021 #include "tpm_ftpm_tee.h"
0022
0023
0024
0025
0026
0027
0028
0029
0030 static const uuid_t ftpm_ta_uuid =
0031 UUID_INIT(0xBC50D971, 0xD4C9, 0x42C4,
0032 0x82, 0xCB, 0x34, 0x3F, 0xB7, 0xF3, 0x78, 0x96);
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044 static int ftpm_tee_tpm_op_recv(struct tpm_chip *chip, u8 *buf, size_t count)
0045 {
0046 struct ftpm_tee_private *pvt_data = dev_get_drvdata(chip->dev.parent);
0047 size_t len;
0048
0049 len = pvt_data->resp_len;
0050 if (count < len) {
0051 dev_err(&chip->dev,
0052 "%s: Invalid size in recv: count=%zd, resp_len=%zd\n",
0053 __func__, count, len);
0054 return -EIO;
0055 }
0056
0057 memcpy(buf, pvt_data->resp_buf, len);
0058 pvt_data->resp_len = 0;
0059
0060 return len;
0061 }
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073 static int ftpm_tee_tpm_op_send(struct tpm_chip *chip, u8 *buf, size_t len)
0074 {
0075 struct ftpm_tee_private *pvt_data = dev_get_drvdata(chip->dev.parent);
0076 size_t resp_len;
0077 int rc;
0078 u8 *temp_buf;
0079 struct tpm_header *resp_header;
0080 struct tee_ioctl_invoke_arg transceive_args;
0081 struct tee_param command_params[4];
0082 struct tee_shm *shm = pvt_data->shm;
0083
0084 if (len > MAX_COMMAND_SIZE) {
0085 dev_err(&chip->dev,
0086 "%s: len=%zd exceeds MAX_COMMAND_SIZE supported by fTPM TA\n",
0087 __func__, len);
0088 return -EIO;
0089 }
0090
0091 memset(&transceive_args, 0, sizeof(transceive_args));
0092 memset(command_params, 0, sizeof(command_params));
0093 pvt_data->resp_len = 0;
0094
0095
0096 transceive_args = (struct tee_ioctl_invoke_arg) {
0097 .func = FTPM_OPTEE_TA_SUBMIT_COMMAND,
0098 .session = pvt_data->session,
0099 .num_params = 4,
0100 };
0101
0102
0103 command_params[0] = (struct tee_param) {
0104 .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
0105 .u.memref = {
0106 .shm = shm,
0107 .size = len,
0108 .shm_offs = 0,
0109 },
0110 };
0111
0112 temp_buf = tee_shm_get_va(shm, 0);
0113 if (IS_ERR(temp_buf)) {
0114 dev_err(&chip->dev, "%s: tee_shm_get_va failed for transmit\n",
0115 __func__);
0116 return PTR_ERR(temp_buf);
0117 }
0118 memset(temp_buf, 0, (MAX_COMMAND_SIZE + MAX_RESPONSE_SIZE));
0119 memcpy(temp_buf, buf, len);
0120
0121 command_params[1] = (struct tee_param) {
0122 .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT,
0123 .u.memref = {
0124 .shm = shm,
0125 .size = MAX_RESPONSE_SIZE,
0126 .shm_offs = MAX_COMMAND_SIZE,
0127 },
0128 };
0129
0130 rc = tee_client_invoke_func(pvt_data->ctx, &transceive_args,
0131 command_params);
0132 if ((rc < 0) || (transceive_args.ret != 0)) {
0133 dev_err(&chip->dev, "%s: SUBMIT_COMMAND invoke error: 0x%x\n",
0134 __func__, transceive_args.ret);
0135 return (rc < 0) ? rc : transceive_args.ret;
0136 }
0137
0138 temp_buf = tee_shm_get_va(shm, command_params[1].u.memref.shm_offs);
0139 if (IS_ERR(temp_buf)) {
0140 dev_err(&chip->dev, "%s: tee_shm_get_va failed for receive\n",
0141 __func__);
0142 return PTR_ERR(temp_buf);
0143 }
0144
0145 resp_header = (struct tpm_header *)temp_buf;
0146 resp_len = be32_to_cpu(resp_header->length);
0147
0148
0149 if (resp_len < TPM_HEADER_SIZE) {
0150 dev_err(&chip->dev, "%s: tpm response header too small\n",
0151 __func__);
0152 return -EIO;
0153 }
0154 if (resp_len > MAX_RESPONSE_SIZE) {
0155 dev_err(&chip->dev,
0156 "%s: resp_len=%zd exceeds MAX_RESPONSE_SIZE\n",
0157 __func__, resp_len);
0158 return -EIO;
0159 }
0160
0161
0162 memcpy(pvt_data->resp_buf, temp_buf, resp_len);
0163 pvt_data->resp_len = resp_len;
0164
0165 return 0;
0166 }
0167
0168 static void ftpm_tee_tpm_op_cancel(struct tpm_chip *chip)
0169 {
0170
0171 }
0172
0173 static u8 ftpm_tee_tpm_op_status(struct tpm_chip *chip)
0174 {
0175 return 0;
0176 }
0177
0178 static bool ftpm_tee_tpm_req_canceled(struct tpm_chip *chip, u8 status)
0179 {
0180 return false;
0181 }
0182
0183 static const struct tpm_class_ops ftpm_tee_tpm_ops = {
0184 .flags = TPM_OPS_AUTO_STARTUP,
0185 .recv = ftpm_tee_tpm_op_recv,
0186 .send = ftpm_tee_tpm_op_send,
0187 .cancel = ftpm_tee_tpm_op_cancel,
0188 .status = ftpm_tee_tpm_op_status,
0189 .req_complete_mask = 0,
0190 .req_complete_val = 0,
0191 .req_canceled = ftpm_tee_tpm_req_canceled,
0192 };
0193
0194
0195
0196
0197
0198 static int ftpm_tee_match(struct tee_ioctl_version_data *ver, const void *data)
0199 {
0200
0201
0202
0203 if ((ver->impl_id == TEE_IMPL_ID_OPTEE) &&
0204 (ver->gen_caps & TEE_GEN_CAP_GP))
0205 return 1;
0206 else
0207 return 0;
0208 }
0209
0210
0211
0212
0213
0214
0215
0216
0217 static int ftpm_tee_probe(struct device *dev)
0218 {
0219 int rc;
0220 struct tpm_chip *chip;
0221 struct ftpm_tee_private *pvt_data = NULL;
0222 struct tee_ioctl_open_session_arg sess_arg;
0223
0224 pvt_data = devm_kzalloc(dev, sizeof(struct ftpm_tee_private),
0225 GFP_KERNEL);
0226 if (!pvt_data)
0227 return -ENOMEM;
0228
0229 dev_set_drvdata(dev, pvt_data);
0230
0231
0232 pvt_data->ctx = tee_client_open_context(NULL, ftpm_tee_match, NULL,
0233 NULL);
0234 if (IS_ERR(pvt_data->ctx)) {
0235 if (PTR_ERR(pvt_data->ctx) == -ENOENT)
0236 return -EPROBE_DEFER;
0237 dev_err(dev, "%s: tee_client_open_context failed\n", __func__);
0238 return PTR_ERR(pvt_data->ctx);
0239 }
0240
0241
0242 memset(&sess_arg, 0, sizeof(sess_arg));
0243 export_uuid(sess_arg.uuid, &ftpm_ta_uuid);
0244 sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
0245 sess_arg.num_params = 0;
0246
0247 rc = tee_client_open_session(pvt_data->ctx, &sess_arg, NULL);
0248 if ((rc < 0) || (sess_arg.ret != 0)) {
0249 dev_err(dev, "%s: tee_client_open_session failed, err=%x\n",
0250 __func__, sess_arg.ret);
0251 rc = -EINVAL;
0252 goto out_tee_session;
0253 }
0254 pvt_data->session = sess_arg.session;
0255
0256
0257 pvt_data->shm = tee_shm_alloc_kernel_buf(pvt_data->ctx,
0258 MAX_COMMAND_SIZE +
0259 MAX_RESPONSE_SIZE);
0260 if (IS_ERR(pvt_data->shm)) {
0261 dev_err(dev, "%s: tee_shm_alloc_kernel_buf failed\n", __func__);
0262 rc = -ENOMEM;
0263 goto out_shm_alloc;
0264 }
0265
0266
0267 chip = tpm_chip_alloc(dev, &ftpm_tee_tpm_ops);
0268 if (IS_ERR(chip)) {
0269 dev_err(dev, "%s: tpm_chip_alloc failed\n", __func__);
0270 rc = PTR_ERR(chip);
0271 goto out_chip_alloc;
0272 }
0273
0274 pvt_data->chip = chip;
0275 pvt_data->chip->flags |= TPM_CHIP_FLAG_TPM2;
0276
0277
0278 rc = tpm_chip_register(pvt_data->chip);
0279 if (rc) {
0280 dev_err(dev, "%s: tpm_chip_register failed with rc=%d\n",
0281 __func__, rc);
0282 goto out_chip;
0283 }
0284
0285 return 0;
0286
0287 out_chip:
0288 put_device(&pvt_data->chip->dev);
0289 out_chip_alloc:
0290 tee_shm_free(pvt_data->shm);
0291 out_shm_alloc:
0292 tee_client_close_session(pvt_data->ctx, pvt_data->session);
0293 out_tee_session:
0294 tee_client_close_context(pvt_data->ctx);
0295
0296 return rc;
0297 }
0298
0299 static int ftpm_plat_tee_probe(struct platform_device *pdev)
0300 {
0301 struct device *dev = &pdev->dev;
0302
0303 return ftpm_tee_probe(dev);
0304 }
0305
0306
0307
0308
0309
0310
0311
0312
0313 static int ftpm_tee_remove(struct device *dev)
0314 {
0315 struct ftpm_tee_private *pvt_data = dev_get_drvdata(dev);
0316
0317
0318 tpm_chip_unregister(pvt_data->chip);
0319
0320
0321 put_device(&pvt_data->chip->dev);
0322
0323
0324 tee_shm_free(pvt_data->shm);
0325
0326
0327 tee_client_close_session(pvt_data->ctx, pvt_data->session);
0328
0329
0330 tee_client_close_context(pvt_data->ctx);
0331
0332
0333
0334 return 0;
0335 }
0336
0337 static int ftpm_plat_tee_remove(struct platform_device *pdev)
0338 {
0339 struct device *dev = &pdev->dev;
0340
0341 return ftpm_tee_remove(dev);
0342 }
0343
0344
0345
0346
0347
0348 static void ftpm_plat_tee_shutdown(struct platform_device *pdev)
0349 {
0350 struct ftpm_tee_private *pvt_data = dev_get_drvdata(&pdev->dev);
0351
0352 tee_shm_free(pvt_data->shm);
0353 tee_client_close_session(pvt_data->ctx, pvt_data->session);
0354 tee_client_close_context(pvt_data->ctx);
0355 }
0356
0357 static const struct of_device_id of_ftpm_tee_ids[] = {
0358 { .compatible = "microsoft,ftpm" },
0359 { }
0360 };
0361 MODULE_DEVICE_TABLE(of, of_ftpm_tee_ids);
0362
0363 static struct platform_driver ftpm_tee_plat_driver = {
0364 .driver = {
0365 .name = "ftpm-tee",
0366 .of_match_table = of_match_ptr(of_ftpm_tee_ids),
0367 },
0368 .shutdown = ftpm_plat_tee_shutdown,
0369 .probe = ftpm_plat_tee_probe,
0370 .remove = ftpm_plat_tee_remove,
0371 };
0372
0373
0374 static const struct tee_client_device_id optee_ftpm_id_table[] = {
0375 {UUID_INIT(0xbc50d971, 0xd4c9, 0x42c4,
0376 0x82, 0xcb, 0x34, 0x3f, 0xb7, 0xf3, 0x78, 0x96)},
0377 {}
0378 };
0379
0380 MODULE_DEVICE_TABLE(tee, optee_ftpm_id_table);
0381
0382 static struct tee_client_driver ftpm_tee_driver = {
0383 .id_table = optee_ftpm_id_table,
0384 .driver = {
0385 .name = "optee-ftpm",
0386 .bus = &tee_bus_type,
0387 .probe = ftpm_tee_probe,
0388 .remove = ftpm_tee_remove,
0389 },
0390 };
0391
0392 static int __init ftpm_mod_init(void)
0393 {
0394 int rc;
0395
0396 rc = platform_driver_register(&ftpm_tee_plat_driver);
0397 if (rc)
0398 return rc;
0399
0400 return driver_register(&ftpm_tee_driver.driver);
0401 }
0402
0403 static void __exit ftpm_mod_exit(void)
0404 {
0405 platform_driver_unregister(&ftpm_tee_plat_driver);
0406 driver_unregister(&ftpm_tee_driver.driver);
0407 }
0408
0409 module_init(ftpm_mod_init);
0410 module_exit(ftpm_mod_exit);
0411
0412 MODULE_AUTHOR("Thirupathaiah Annapureddy <thiruan@microsoft.com>");
0413 MODULE_DESCRIPTION("TPM Driver for fTPM TA in TEE");
0414 MODULE_LICENSE("GPL v2");