1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. 4 */ 5 6 #include <linux/delay.h> 7 #include <linux/of.h> 8 #include <linux/firmware/qcom/qcom_pas.h> 9 #include <linux/kernel.h> 10 #include <linux/module.h> 11 #include <linux/slab.h> 12 #include <linux/tee_drv.h> 13 #include <linux/uuid.h> 14 15 #include "qcom_pas.h" 16 17 /* 18 * Peripheral Authentication Service (PAS) supported. 19 * 20 * [in] params[0].value.a: Unique 32bit remote processor identifier 21 */ 22 #define TA_QCOM_PAS_IS_SUPPORTED 1 23 24 /* 25 * PAS capabilities. 26 * 27 * [in] params[0].value.a: Unique 32bit remote processor identifier 28 * [out] params[1].value.a: PAS capability flags 29 */ 30 #define TA_QCOM_PAS_CAPABILITIES 2 31 32 /* 33 * PAS image initialization. 34 * 35 * [in] params[0].value.a: Unique 32bit remote processor identifier 36 * [in] params[1].memref: Loadable firmware metadata 37 */ 38 #define TA_QCOM_PAS_INIT_IMAGE 3 39 40 /* 41 * PAS memory setup. 42 * 43 * [in] params[0].value.a: Unique 32bit remote processor identifier 44 * [in] params[0].value.b: Relocatable firmware size 45 * [in] params[1].value.a: 32bit LSB relocatable firmware memory address 46 * [in] params[1].value.b: 32bit MSB relocatable firmware memory address 47 */ 48 #define TA_QCOM_PAS_MEM_SETUP 4 49 50 /* 51 * PAS get resource table. 52 * 53 * [in] params[0].value.a: Unique 32bit remote processor identifier 54 * [inout] params[1].memref: Resource table config 55 */ 56 #define TA_QCOM_PAS_GET_RESOURCE_TABLE 5 57 58 /* 59 * PAS image authentication and co-processor reset. 60 * 61 * [in] params[0].value.a: Unique 32bit remote processor identifier 62 * [in] params[0].value.b: Firmware size 63 * [in] params[1].value.a: 32bit LSB firmware memory address 64 * [in] params[1].value.b: 32bit MSB firmware memory address 65 * [in] params[2].memref: Optional fw memory space shared/lent 66 */ 67 #define TA_QCOM_PAS_AUTH_AND_RESET 6 68 69 /* 70 * PAS co-processor set suspend/resume state. 71 * 72 * [in] params[0].value.a: Unique 32bit remote processor identifier 73 * [in] params[0].value.b: Co-processor state identifier 74 */ 75 #define TA_QCOM_PAS_SET_REMOTE_STATE 7 76 77 /* 78 * PAS co-processor shutdown. 79 * 80 * [in] params[0].value.a: Unique 32bit remote processor identifier 81 */ 82 #define TA_QCOM_PAS_SHUTDOWN 8 83 84 #define TEE_NUM_PARAMS 4 85 86 /** 87 * struct qcom_pas_tee_private - PAS service private data 88 * @dev: PAS service device. 89 * @ctx: TEE context handler. 90 * @session_id: PAS TA session identifier. 91 */ 92 struct qcom_pas_tee_private { 93 struct device *dev; 94 struct tee_context *ctx; 95 u32 session_id; 96 }; 97 98 static bool qcom_pas_tee_supported(struct device *dev, u32 pas_id) 99 { 100 struct qcom_pas_tee_private *data = dev_get_drvdata(dev); 101 struct tee_ioctl_invoke_arg inv_arg = { 102 .func = TA_QCOM_PAS_IS_SUPPORTED, 103 .session = data->session_id, 104 .num_params = TEE_NUM_PARAMS 105 }; 106 struct tee_param param[4] = { 107 [0] = { 108 .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, 109 .u.value.a = pas_id 110 } 111 }; 112 int ret; 113 114 ret = tee_client_invoke_func(data->ctx, &inv_arg, param); 115 if (ret < 0 || inv_arg.ret != 0) { 116 dev_err(dev, "PAS not supported, pas_id: %d, ret: %d, err: 0x%x\n", 117 pas_id, ret, inv_arg.ret); 118 return false; 119 } 120 121 return true; 122 } 123 124 static int qcom_pas_tee_init_image(struct device *dev, u32 pas_id, 125 const void *metadata, size_t size, 126 struct qcom_pas_context *ctx) 127 { 128 struct qcom_pas_tee_private *data = dev_get_drvdata(dev); 129 struct tee_ioctl_invoke_arg inv_arg = { 130 .func = TA_QCOM_PAS_INIT_IMAGE, 131 .session = data->session_id, 132 .num_params = TEE_NUM_PARAMS 133 }; 134 struct tee_param param[4] = { 135 [0] = { 136 .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, 137 .u.value.a = pas_id 138 }, 139 [1] = { 140 .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT, 141 } 142 }; 143 struct tee_shm *mdata_shm; 144 u8 *mdata_buf = NULL; 145 int ret; 146 147 mdata_shm = tee_shm_alloc_kernel_buf(data->ctx, size); 148 if (IS_ERR(mdata_shm)) { 149 dev_err(dev, "mdata_shm allocation failed\n"); 150 return PTR_ERR(mdata_shm); 151 } 152 153 mdata_buf = tee_shm_get_va(mdata_shm, 0); 154 if (IS_ERR(mdata_buf)) { 155 dev_err(dev, "mdata_buf get VA failed\n"); 156 tee_shm_free(mdata_shm); 157 return PTR_ERR(mdata_buf); 158 } 159 memcpy(mdata_buf, metadata, size); 160 161 param[1].u.memref.shm = mdata_shm; 162 param[1].u.memref.size = size; 163 164 ret = tee_client_invoke_func(data->ctx, &inv_arg, param); 165 if (ret < 0 || inv_arg.ret != 0) { 166 dev_err(dev, "PAS init image failed, pas_id: %d, ret: %d, err: 0x%x\n", 167 pas_id, ret, inv_arg.ret); 168 tee_shm_free(mdata_shm); 169 return ret ?: -EINVAL; 170 } 171 172 if (ctx) 173 ctx->ptr = (void *)mdata_shm; 174 else 175 tee_shm_free(mdata_shm); 176 177 return ret; 178 } 179 180 static int qcom_pas_tee_mem_setup(struct device *dev, u32 pas_id, 181 phys_addr_t addr, phys_addr_t size) 182 { 183 struct qcom_pas_tee_private *data = dev_get_drvdata(dev); 184 struct tee_ioctl_invoke_arg inv_arg = { 185 .func = TA_QCOM_PAS_MEM_SETUP, 186 .session = data->session_id, 187 .num_params = TEE_NUM_PARAMS 188 }; 189 struct tee_param param[4] = { 190 [0] = { 191 .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, 192 .u.value.a = pas_id, 193 .u.value.b = size, 194 }, 195 [1] = { 196 .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, 197 .u.value.a = lower_32_bits(addr), 198 .u.value.b = upper_32_bits(addr), 199 } 200 }; 201 int ret; 202 203 ret = tee_client_invoke_func(data->ctx, &inv_arg, param); 204 if (ret < 0 || inv_arg.ret != 0) { 205 dev_err(dev, "PAS mem setup failed, pas_id: %d, ret: %d, err: 0x%x\n", 206 pas_id, ret, inv_arg.ret); 207 return ret ?: -EINVAL; 208 } 209 210 return ret; 211 } 212 213 DEFINE_FREE(shm_free, struct tee_shm *, tee_shm_free(_T)) 214 215 static void *qcom_pas_tee_get_rsc_table(struct device *dev, 216 struct qcom_pas_context *ctx, 217 void *input_rt, size_t input_rt_size, 218 size_t *output_rt_size) 219 { 220 struct qcom_pas_tee_private *data = dev_get_drvdata(dev); 221 struct tee_ioctl_invoke_arg inv_arg = { 222 .func = TA_QCOM_PAS_GET_RESOURCE_TABLE, 223 .session = data->session_id, 224 .num_params = TEE_NUM_PARAMS 225 }; 226 struct tee_param param[4] = { 227 [0] = { 228 .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, 229 .u.value.a = ctx->pas_id, 230 }, 231 [1] = { 232 .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT, 233 .u.memref.size = input_rt_size, 234 } 235 }; 236 void *rt_buf = NULL; 237 int ret; 238 239 ret = tee_client_invoke_func(data->ctx, &inv_arg, param); 240 if (ret < 0 || inv_arg.ret != 0) { 241 dev_err(dev, "PAS get RT failed, pas_id: %d, ret: %d, err: 0x%x\n", 242 ctx->pas_id, ret, inv_arg.ret); 243 return ret ? ERR_PTR(ret) : ERR_PTR(-EINVAL); 244 } 245 246 if (param[1].u.memref.size >= input_rt_size) { 247 struct tee_shm *rt_shm __free(shm_free) = 248 tee_shm_alloc_kernel_buf(data->ctx, 249 param[1].u.memref.size); 250 void *rt_shm_va; 251 252 if (IS_ERR_OR_NULL(rt_shm)) { 253 dev_err(dev, "rt_shm allocation failed\n"); 254 rt_shm = NULL; 255 return ERR_PTR(-ENOMEM); 256 } 257 258 rt_shm_va = tee_shm_get_va(rt_shm, 0); 259 if (IS_ERR(rt_shm_va)) { 260 dev_err(dev, "rt_shm get VA failed\n"); 261 return ERR_CAST(rt_shm_va); 262 } 263 memcpy(rt_shm_va, input_rt, input_rt_size); 264 265 param[1].u.memref.shm = rt_shm; 266 ret = tee_client_invoke_func(data->ctx, &inv_arg, param); 267 if (ret < 0 || inv_arg.ret != 0) { 268 dev_err(dev, "PAS get RT failed, pas_id: %d, ret: %d, err: 0x%x\n", 269 ctx->pas_id, ret, inv_arg.ret); 270 return ret ? ERR_PTR(ret) : ERR_PTR(-EINVAL); 271 } 272 273 if (param[1].u.memref.size) { 274 *output_rt_size = param[1].u.memref.size; 275 rt_buf = kmemdup(rt_shm_va, *output_rt_size, GFP_KERNEL); 276 if (!rt_buf) 277 return ERR_PTR(-ENOMEM); 278 } 279 } else { 280 *output_rt_size = 0; 281 } 282 283 return rt_buf; 284 } 285 286 static int __qcom_pas_tee_auth_and_reset(struct device *dev, u32 pas_id, 287 phys_addr_t mem_phys, size_t mem_size) 288 { 289 struct qcom_pas_tee_private *data = dev_get_drvdata(dev); 290 struct tee_ioctl_invoke_arg inv_arg = { 291 .func = TA_QCOM_PAS_AUTH_AND_RESET, 292 .session = data->session_id, 293 .num_params = TEE_NUM_PARAMS 294 }; 295 struct tee_param param[4] = { 296 [0] = { 297 .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, 298 .u.value.a = pas_id, 299 .u.value.b = mem_size, 300 }, 301 [1] = { 302 .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, 303 .u.value.a = lower_32_bits(mem_phys), 304 .u.value.b = upper_32_bits(mem_phys), 305 }, 306 /* Reserved for fw memory space to be shared or lent */ 307 [2] = { 308 .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT, 309 } 310 }; 311 int ret; 312 313 ret = tee_client_invoke_func(data->ctx, &inv_arg, param); 314 if (ret < 0 || inv_arg.ret != 0) { 315 dev_err(dev, "PAS auth reset failed, pas_id: %d, ret: %d, err: 0x%x\n", 316 pas_id, ret, inv_arg.ret); 317 return ret ?: -EINVAL; 318 } 319 320 return ret; 321 } 322 323 static int qcom_pas_tee_auth_and_reset(struct device *dev, u32 pas_id) 324 { 325 return __qcom_pas_tee_auth_and_reset(dev, pas_id, 0, 0); 326 } 327 328 static int qcom_pas_tee_prepare_and_auth_reset(struct device *dev, 329 struct qcom_pas_context *ctx) 330 { 331 return __qcom_pas_tee_auth_and_reset(dev, ctx->pas_id, ctx->mem_phys, 332 ctx->mem_size); 333 } 334 335 static int qcom_pas_tee_set_remote_state(struct device *dev, u32 state, 336 u32 pas_id) 337 { 338 struct qcom_pas_tee_private *data = dev_get_drvdata(dev); 339 struct tee_ioctl_invoke_arg inv_arg = { 340 .func = TA_QCOM_PAS_SET_REMOTE_STATE, 341 .session = data->session_id, 342 .num_params = TEE_NUM_PARAMS 343 }; 344 struct tee_param param[4] = { 345 [0] = { 346 .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, 347 .u.value.a = pas_id, 348 .u.value.b = state, 349 } 350 }; 351 int ret; 352 353 ret = tee_client_invoke_func(data->ctx, &inv_arg, param); 354 if (ret < 0 || inv_arg.ret != 0) { 355 dev_err(dev, "PAS set remote state failed, pas_id: %d, ret: %d, err: 0x%x\n", 356 pas_id, ret, inv_arg.ret); 357 return ret ?: -EINVAL; 358 } 359 360 return ret; 361 } 362 363 static int qcom_pas_tee_shutdown(struct device *dev, u32 pas_id) 364 { 365 struct qcom_pas_tee_private *data = dev_get_drvdata(dev); 366 struct tee_ioctl_invoke_arg inv_arg = { 367 .func = TA_QCOM_PAS_SHUTDOWN, 368 .session = data->session_id, 369 .num_params = TEE_NUM_PARAMS 370 }; 371 struct tee_param param[4] = { 372 [0] = { 373 .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, 374 .u.value.a = pas_id 375 } 376 }; 377 int ret; 378 379 ret = tee_client_invoke_func(data->ctx, &inv_arg, param); 380 if (ret < 0 || inv_arg.ret != 0) { 381 dev_err(dev, "PAS shutdown failed, pas_id: %d, ret: %d, err: 0x%x\n", 382 pas_id, ret, inv_arg.ret); 383 return ret ?: -EINVAL; 384 } 385 386 return ret; 387 } 388 389 static void qcom_pas_tee_metadata_release(struct device *dev, 390 struct qcom_pas_context *ctx) 391 { 392 struct tee_shm *mdata_shm = ctx->ptr; 393 394 tee_shm_free(mdata_shm); 395 ctx->ptr = NULL; 396 } 397 398 static struct qcom_pas_ops qcom_pas_ops_tee = { 399 .drv_name = "qcom-pas-tee", 400 .supported = qcom_pas_tee_supported, 401 .init_image = qcom_pas_tee_init_image, 402 .mem_setup = qcom_pas_tee_mem_setup, 403 .get_rsc_table = qcom_pas_tee_get_rsc_table, 404 .auth_and_reset = qcom_pas_tee_auth_and_reset, 405 .prepare_and_auth_reset = qcom_pas_tee_prepare_and_auth_reset, 406 .set_remote_state = qcom_pas_tee_set_remote_state, 407 .shutdown = qcom_pas_tee_shutdown, 408 .metadata_release = qcom_pas_tee_metadata_release, 409 }; 410 411 static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data) 412 { 413 return ver->impl_id == TEE_IMPL_ID_OPTEE; 414 } 415 416 static int qcom_pas_tee_probe(struct tee_client_device *pas_dev) 417 { 418 struct device *dev = &pas_dev->dev; 419 struct qcom_pas_tee_private *data; 420 struct tee_ioctl_open_session_arg sess_arg = { 421 .clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL 422 }; 423 int ret; 424 425 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 426 if (!data) 427 return -ENOMEM; 428 429 data->ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL); 430 if (IS_ERR(data->ctx)) 431 return -ENODEV; 432 433 export_uuid(sess_arg.uuid, &pas_dev->id.uuid); 434 ret = tee_client_open_session(data->ctx, &sess_arg, NULL); 435 if (ret < 0 || sess_arg.ret != 0) { 436 dev_err(dev, "tee_client_open_session failed, ret: %d, err: 0x%x\n", 437 ret, sess_arg.ret); 438 tee_client_close_context(data->ctx); 439 return ret ?: -EINVAL; 440 } 441 442 data->session_id = sess_arg.session; 443 dev_set_drvdata(dev, data); 444 qcom_pas_ops_tee.dev = dev; 445 qcom_pas_ops_register(&qcom_pas_ops_tee); 446 447 return ret; 448 } 449 450 static void qcom_pas_tee_remove(struct tee_client_device *pas_dev) 451 { 452 struct device *dev = &pas_dev->dev; 453 struct qcom_pas_tee_private *data = dev_get_drvdata(dev); 454 455 qcom_pas_ops_unregister(); 456 tee_client_close_session(data->ctx, data->session_id); 457 tee_client_close_context(data->ctx); 458 } 459 460 static const struct tee_client_device_id qcom_pas_tee_id_table[] = { 461 {UUID_INIT(0xcff7d191, 0x7ca0, 0x4784, 462 0xaf, 0x13, 0x48, 0x22, 0x3b, 0x9a, 0x4f, 0xbe)}, 463 {} 464 }; 465 MODULE_DEVICE_TABLE(tee, qcom_pas_tee_id_table); 466 467 static struct tee_client_driver optee_pas_tee_driver = { 468 .probe = qcom_pas_tee_probe, 469 .remove = qcom_pas_tee_remove, 470 .id_table = qcom_pas_tee_id_table, 471 .driver = { 472 .name = "qcom-pas-tee", 473 }, 474 }; 475 476 module_tee_client_driver(optee_pas_tee_driver); 477 478 MODULE_LICENSE("GPL"); 479 MODULE_DESCRIPTION("Qualcomm PAS TEE driver"); 480