1 /* $OpenBSD: qcscm.c,v 1.4 2023/05/17 23:12:04 patrick Exp $ */ 2 /* 3 * Copyright (c) 2022 Patrick Wildt <patrick@blueri.se> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/queue.h> 21 #include <sys/malloc.h> 22 #include <sys/sysctl.h> 23 #include <sys/device.h> 24 #include <sys/evcount.h> 25 #include <sys/socket.h> 26 #include <sys/timeout.h> 27 #include <sys/atomic.h> 28 29 #include <uvm/uvm_extern.h> 30 31 #include <machine/intr.h> 32 #include <machine/bus.h> 33 #include <machine/fdt.h> 34 35 #include <dev/efi/efi.h> 36 37 #include <dev/ofw/openfirm.h> 38 #include <dev/ofw/ofw_misc.h> 39 #include <dev/ofw/fdt.h> 40 41 /* #define QCSCM_DEBUG */ 42 43 #define ARM_SMCCC_STD_CALL (0U << 31) 44 #define ARM_SMCCC_FAST_CALL (1U << 31) 45 #define ARM_SMCCC_LP64 (1U << 30) 46 #define ARM_SMCCC_OWNER_SIP 2 47 48 #define QCTEE_TZ_OWNER_TZ_APPS 48 49 #define QCTEE_TZ_OWNER_QSEE_OS 50 50 51 #define QCTEE_TZ_SVC_APP_ID_PLACEHOLDER 0 52 #define QCTEE_TZ_SVC_APP_MGR 1 53 54 #define QCTEE_OS_RESULT_SUCCESS 0 55 #define QCTEE_OS_RESULT_INCOMPLETE 1 56 #define QCTEE_OS_RESULT_BLOCKED_ON_LISTENER 2 57 #define QCTEE_OS_RESULT_FAILURE 0xffffffff 58 59 #define QCTEE_OS_SCM_RES_APP_ID 0xee01 60 #define QCTEE_OS_SCM_RES_QSEOS_LISTENER_ID 0xee02 61 62 #define QCTEE_UEFI_GET_VARIABLE 0x8000 63 #define QCTEE_UEFI_SET_VARIABLE 0x8001 64 #define QCTEE_UEFI_GET_NEXT_VARIABLE 0x8002 65 #define QCTEE_UEFI_QUERY_VARIABLE_INFO 0x8003 66 67 #define QCTEE_UEFI_SUCCESS 0 68 #define QCTEE_UEFI_BUFFER_TOO_SMALL 0x80000005 69 #define QCTEE_UEFI_DEVICE_ERROR 0x80000007 70 #define QCTEE_UEFI_NOT_FOUND 0x8000000e 71 72 #define QCSCM_SVC_PIL 0x02 73 #define QCSCM_PIL_PAS_INIT_IMAGE 0x01 74 #define QCSCM_PIL_PAS_MEM_SETUP 0x02 75 #define QCSCM_PIL_PAS_AUTH_AND_RESET 0x05 76 #define QCSCM_PIL_PAS_SHUTDOWN 0x06 77 #define QCSCM_PIL_PAS_IS_SUPPORTED 0x07 78 #define QCSCM_PIL_PAS_MSS_RESET 0x0a 79 80 #define QCSCM_INTERRUPTED 1 81 82 #define QCSCM_ARGINFO_NUM(x) (((x) & 0xf) << 0) 83 #define QCSCM_ARGINFO_TYPE(x, y) (((y) & 0x3) << (4 + 2 * (x))) 84 #define QCSCM_ARGINFO_TYPE_VAL 0 85 #define QCSCM_ARGINFO_TYPE_RO 1 86 #define QCSCM_ARGINFO_TYPE_RW 2 87 #define QCSCM_ARGINFO_TYPE_BUFVAL 3 88 89 #define EFI_VARIABLE_NON_VOLATILE 0x00000001 90 #define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002 91 #define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004 92 93 struct qcscm_dmamem { 94 bus_dmamap_t qdm_map; 95 bus_dma_segment_t qdm_seg; 96 size_t qdm_size; 97 caddr_t qdm_kva; 98 }; 99 100 #define QCSCM_DMA_MAP(_qdm) ((_qdm)->qdm_map) 101 #define QCSCM_DMA_LEN(_qdm) ((_qdm)->qdm_size) 102 #define QCSCM_DMA_DVA(_qdm) ((uint64_t)(_qdm)->qdm_map->dm_segs[0].ds_addr) 103 #define QCSCM_DMA_KVA(_qdm) ((void *)(_qdm)->qdm_kva) 104 105 EFI_GUID qcscm_uefi_rtcinfo_guid = 106 { 0x882f8c2b, 0x9646, 0x435f, 107 { 0x8d, 0xe5, 0xf2, 0x08, 0xff, 0x80, 0xc1, 0xbd } }; 108 109 struct qcscm_softc { 110 struct device sc_dev; 111 int sc_node; 112 bus_dma_tag_t sc_dmat; 113 114 struct qcscm_dmamem *sc_extarg; 115 uint32_t sc_uefi_id; 116 }; 117 118 int qcscm_match(struct device *, void *, void *); 119 void qcscm_attach(struct device *parent, struct device *self, void *args); 120 121 const struct cfattach qcscm_ca = { 122 sizeof (struct qcscm_softc), qcscm_match, qcscm_attach 123 }; 124 125 struct cfdriver qcscm_cd = { 126 NULL, "qcscm", DV_DULL 127 }; 128 129 void qcscm_smc_exec(uint64_t *, uint64_t *); 130 int qcscm_smc_call(struct qcscm_softc *, uint8_t, uint8_t, uint8_t, 131 uint32_t, uint64_t *, int, uint64_t *); 132 int qcscm_tee_app_get_id(struct qcscm_softc *, const char *, uint32_t *); 133 int qcscm_tee_app_send(struct qcscm_softc *, uint32_t, uint64_t, uint64_t, 134 uint64_t, uint64_t); 135 136 EFI_STATUS qcscm_uefi_get_variable(struct qcscm_softc *, CHAR16 *, 137 int, EFI_GUID *, uint32_t *, uint8_t *, int *); 138 EFI_STATUS qcscm_uefi_set_variable(struct qcscm_softc *, CHAR16 *, 139 int, EFI_GUID *, uint32_t, uint8_t *, int); 140 EFI_STATUS qcscm_uefi_get_next_variable(struct qcscm_softc *, 141 CHAR16 *, int *, EFI_GUID *); 142 143 #ifdef QCSCM_DEBUG 144 void qcscm_uefi_dump_variables(struct qcscm_softc *); 145 void qcscm_uefi_dump_variable(struct qcscm_softc *, CHAR16 *, int, 146 EFI_GUID *); 147 #endif 148 149 int qcscm_uefi_rtc_get(uint32_t *); 150 int qcscm_uefi_rtc_set(uint32_t); 151 152 struct qcscm_dmamem * 153 qcscm_dmamem_alloc(struct qcscm_softc *, bus_size_t, bus_size_t); 154 void qcscm_dmamem_free(struct qcscm_softc *, struct qcscm_dmamem *); 155 156 struct qcscm_softc *qcscm_sc; 157 158 int 159 qcscm_match(struct device *parent, void *match, void *aux) 160 { 161 struct fdt_attach_args *faa = aux; 162 163 return OF_is_compatible(faa->fa_node, "qcom,scm"); 164 } 165 166 void 167 qcscm_attach(struct device *parent, struct device *self, void *aux) 168 { 169 struct qcscm_softc *sc = (struct qcscm_softc *)self; 170 struct fdt_attach_args *faa = aux; 171 172 sc->sc_node = faa->fa_node; 173 sc->sc_dmat = faa->fa_dmat; 174 175 sc->sc_extarg = qcscm_dmamem_alloc(sc, PAGE_SIZE, 8); 176 if (sc->sc_extarg == NULL) { 177 printf(": can't allocate memory for extended args\n"); 178 return; 179 } 180 181 if (qcscm_tee_app_get_id(sc, "qcom.tz.uefisecapp", &sc->sc_uefi_id)) { 182 printf(": can't retrieve UEFI App\n"); 183 return; 184 } 185 186 printf("\n"); 187 qcscm_sc = sc; 188 189 #ifdef QCSCM_DEBUG 190 qcscm_uefi_dump_variables(sc); 191 qcscm_uefi_dump_variable(sc, u"RTCInfo", sizeof(u"RTCInfo"), 192 &qcscm_uefi_rtcinfo_guid); 193 #endif 194 } 195 196 /* Expects an uint64_t[8] */ 197 void 198 qcscm_smc_exec(uint64_t *in, uint64_t *out) 199 { 200 __asm( 201 "ldp x0, x1, [%0, #0]\n" 202 "ldp x2, x3, [%0, #16]\n" 203 "ldp x4, x5, [%0, #32]\n" 204 "ldp x6, x7, [%0, #48]\n" 205 "smc #0\n" 206 "stp x0, x1, [%1, #0]\n" 207 "stp x2, x3, [%1, #16]\n" 208 "stp x4, x5, [%1, #32]\n" 209 "stp x6, x7, [%1, #48]\n" :: 210 "r" (in), "r" (out) : 211 "x0", "x1", "x2", "x3", 212 "x4", "x5", "x6", "x7", 213 "memory"); 214 } 215 216 int 217 qcscm_smc_call(struct qcscm_softc *sc, uint8_t owner, uint8_t svc, uint8_t cmd, 218 uint32_t arginfo, uint64_t *args, int arglen, uint64_t *res) 219 { 220 uint64_t smcreq[8] = { 0 }, smcres[8] = { 0 }; 221 uint64_t *smcextreq; 222 int i; 223 224 /* 4 of our 10 possible args fit into x2-x5 */ 225 smcreq[0] = ARM_SMCCC_STD_CALL | ARM_SMCCC_LP64 | 226 owner << 24 | svc << 8 | cmd; 227 smcreq[1] = arginfo; 228 for (i = 0; i < min(arglen, 4); i++) 229 smcreq[2 + i] = args[i]; 230 231 /* In case we have more than 4, use x5 as ptr to extra args */ 232 smcextreq = QCSCM_DMA_KVA(sc->sc_extarg); 233 if (arglen > 4) { 234 smcreq[5] = QCSCM_DMA_DVA(sc->sc_extarg); 235 smcextreq = QCSCM_DMA_KVA(sc->sc_extarg); 236 for (i = 0; i < min(arglen - 3, 7); i++) { 237 smcextreq[i] = args[3 + i]; 238 } 239 } 240 241 for (;;) { 242 qcscm_smc_exec(smcreq, smcres); 243 /* If the call gets interrupted, try again and re-pass x0/x6 */ 244 if (smcres[0] == QCSCM_INTERRUPTED) { 245 smcreq[0] = smcres[0]; 246 smcreq[6] = smcres[6]; 247 continue; 248 } 249 break; 250 } 251 252 if (res) { 253 res[0] = smcres[1]; 254 res[1] = smcres[2]; 255 res[2] = smcres[3]; 256 } 257 258 return smcres[0]; 259 } 260 261 /* Retrieve id of app running in TEE by name */ 262 int 263 qcscm_tee_app_get_id(struct qcscm_softc *sc, const char *name, uint32_t *id) 264 { 265 struct qcscm_dmamem *qdm; 266 uint64_t res[3]; 267 uint64_t args[2]; 268 uint32_t arginfo; 269 int ret; 270 271 /* Max name length is 64 */ 272 if (strlen(name) > 64) 273 return EINVAL; 274 275 /* Alloc some phys mem to hold the name */ 276 qdm = qcscm_dmamem_alloc(sc, PAGE_SIZE, 8); 277 if (qdm == NULL) 278 return ENOMEM; 279 280 /* Copy name of app we want to get an id for to page */ 281 memcpy(QCSCM_DMA_KVA(qdm), name, strlen(name)); 282 283 /* Pass address of name and length */ 284 arginfo = QCSCM_ARGINFO_NUM(nitems(args)); 285 arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_RW); 286 arginfo |= QCSCM_ARGINFO_TYPE(1, QCSCM_ARGINFO_TYPE_VAL); 287 args[0] = QCSCM_DMA_DVA(qdm); 288 args[1] = strlen(name); 289 290 /* Make call into TEE */ 291 ret = qcscm_smc_call(sc, QCTEE_TZ_OWNER_QSEE_OS, QCTEE_TZ_SVC_APP_MGR, 292 0x03, arginfo, args, nitems(args), res); 293 294 /* If the call succeeded, check the response status */ 295 if (ret == 0) 296 ret = res[0]; 297 298 /* If the response status is successful as well, retrieve data */ 299 if (ret == 0) 300 *id = res[2]; 301 302 qcscm_dmamem_free(sc, qdm); 303 return ret; 304 } 305 306 /* Message interface to app running in TEE */ 307 int 308 qcscm_tee_app_send(struct qcscm_softc *sc, uint32_t id, uint64_t req_phys, 309 uint64_t req_len, uint64_t rsp_phys, uint64_t rsp_len) 310 { 311 uint64_t res[3]; 312 uint64_t args[5]; 313 uint32_t arginfo; 314 int ret; 315 316 /* Pass id of app we target, plus request and response buffers */ 317 arginfo = QCSCM_ARGINFO_NUM(nitems(args)); 318 arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_VAL); 319 arginfo |= QCSCM_ARGINFO_TYPE(1, QCSCM_ARGINFO_TYPE_RW); 320 arginfo |= QCSCM_ARGINFO_TYPE(2, QCSCM_ARGINFO_TYPE_VAL); 321 arginfo |= QCSCM_ARGINFO_TYPE(3, QCSCM_ARGINFO_TYPE_RW); 322 arginfo |= QCSCM_ARGINFO_TYPE(4, QCSCM_ARGINFO_TYPE_VAL); 323 args[0] = id; 324 args[1] = req_phys; 325 args[2] = req_len; 326 args[3] = rsp_phys; 327 args[4] = rsp_len; 328 329 membar_sync(); 330 331 /* Make call into TEE */ 332 ret = qcscm_smc_call(sc, QCTEE_TZ_OWNER_TZ_APPS, 333 QCTEE_TZ_SVC_APP_ID_PLACEHOLDER, 0x01, 334 arginfo, args, nitems(args), res); 335 336 membar_sync(); 337 338 /* If the call succeeded, check the response status */ 339 if (ret == 0) 340 ret = res[0]; 341 342 return ret; 343 } 344 345 struct qcscm_req_uefi_get_variable { 346 uint32_t command_id; 347 uint32_t length; 348 uint32_t name_offset; 349 uint32_t name_size; 350 uint32_t guid_offset; 351 uint32_t guid_size; 352 uint32_t data_size; 353 }; 354 355 struct qcscm_rsp_uefi_get_variable { 356 uint32_t command_id; 357 uint32_t length; 358 uint32_t status; 359 uint32_t attributes; 360 uint32_t data_offset; 361 uint32_t data_size; 362 }; 363 364 EFI_STATUS 365 qcscm_uefi_get_variable(struct qcscm_softc *sc, 366 CHAR16 *name, int name_size, EFI_GUID *guid, 367 uint32_t *attributes, uint8_t *data, int *data_size) 368 { 369 struct qcscm_req_uefi_get_variable *req; 370 struct qcscm_rsp_uefi_get_variable *resp; 371 struct qcscm_dmamem *qdm; 372 size_t reqsize, respsize; 373 off_t reqoff, respoff; 374 int ret; 375 376 reqsize = ALIGN(sizeof(*req)) + ALIGN(name_size) + ALIGN(sizeof(*guid)); 377 respsize = ALIGN(sizeof(*resp)) + ALIGN(*data_size); 378 379 reqoff = 0; 380 respoff = reqsize; 381 382 qdm = qcscm_dmamem_alloc(sc, round_page(reqsize + respsize), 8); 383 if (qdm == NULL) 384 return QCTEE_UEFI_DEVICE_ERROR; 385 386 req = QCSCM_DMA_KVA(qdm) + reqoff; 387 req->command_id = QCTEE_UEFI_GET_VARIABLE; 388 req->data_size = *data_size; 389 req->name_offset = ALIGN(sizeof(*req)); 390 req->name_size = name_size; 391 req->guid_offset = ALIGN(req->name_offset + req->name_size); 392 req->guid_size = sizeof(*guid); 393 req->length = req->guid_offset + req->guid_size; 394 395 memcpy((char *)req + req->guid_offset, guid, sizeof(*guid)); 396 memcpy((char *)req + req->name_offset, name, name_size); 397 398 ret = qcscm_tee_app_send(sc, sc->sc_uefi_id, 399 QCSCM_DMA_DVA(qdm) + reqoff, reqsize, 400 QCSCM_DMA_DVA(qdm) + respoff, respsize); 401 if (ret) { 402 qcscm_dmamem_free(sc, qdm); 403 return QCTEE_UEFI_DEVICE_ERROR; 404 } 405 406 resp = QCSCM_DMA_KVA(qdm) + respoff; 407 if (resp->command_id != QCTEE_UEFI_GET_VARIABLE || 408 resp->length < sizeof(*resp) || resp->length > respsize) { 409 qcscm_dmamem_free(sc, qdm); 410 return QCTEE_UEFI_DEVICE_ERROR; 411 } 412 413 if (resp->status) { 414 if (resp->status == QCTEE_UEFI_BUFFER_TOO_SMALL) 415 *data_size = resp->data_size; 416 if (attributes) 417 *attributes = resp->attributes; 418 ret = resp->status; 419 qcscm_dmamem_free(sc, qdm); 420 return ret; 421 } 422 423 if (resp->data_offset + resp->data_size > resp->length) { 424 qcscm_dmamem_free(sc, qdm); 425 return QCTEE_UEFI_DEVICE_ERROR; 426 } 427 428 if (attributes) 429 *attributes = resp->attributes; 430 431 if (*data_size == 0) { 432 *data_size = resp->data_size; 433 qcscm_dmamem_free(sc, qdm); 434 return QCTEE_UEFI_SUCCESS; 435 } 436 437 if (resp->data_size > *data_size) { 438 *data_size = resp->data_size; 439 qcscm_dmamem_free(sc, qdm); 440 return QCTEE_UEFI_BUFFER_TOO_SMALL; 441 } 442 443 memcpy(data, (char *)resp + resp->data_offset, resp->data_size); 444 *data_size = resp->data_size; 445 446 qcscm_dmamem_free(sc, qdm); 447 return EFI_SUCCESS; 448 } 449 450 struct qcscm_req_uefi_set_variable { 451 uint32_t command_id; 452 uint32_t length; 453 uint32_t name_offset; 454 uint32_t name_size; 455 uint32_t guid_offset; 456 uint32_t guid_size; 457 uint32_t attributes; 458 uint32_t data_offset; 459 uint32_t data_size; 460 }; 461 462 struct qcscm_rsp_uefi_set_variable { 463 uint32_t command_id; 464 uint32_t length; 465 uint32_t status; 466 uint32_t unknown[2]; 467 }; 468 469 EFI_STATUS 470 qcscm_uefi_set_variable(struct qcscm_softc *sc, 471 CHAR16 *name, int name_size, EFI_GUID *guid, 472 uint32_t attributes, uint8_t *data, int data_size) 473 { 474 struct qcscm_req_uefi_set_variable *req; 475 struct qcscm_rsp_uefi_set_variable *resp; 476 struct qcscm_dmamem *qdm; 477 size_t reqsize, respsize; 478 off_t reqoff, respoff; 479 int ret; 480 481 reqsize = ALIGN(sizeof(*req)) + ALIGN(name_size) + ALIGN(sizeof(*guid)) + 482 ALIGN(data_size); 483 respsize = ALIGN(sizeof(*resp)); 484 485 reqoff = 0; 486 respoff = reqsize; 487 488 qdm = qcscm_dmamem_alloc(sc, round_page(reqsize + respsize), 8); 489 if (qdm == NULL) 490 return QCTEE_UEFI_DEVICE_ERROR; 491 492 req = QCSCM_DMA_KVA(qdm) + reqoff; 493 req->command_id = QCTEE_UEFI_SET_VARIABLE; 494 req->attributes = attributes; 495 req->name_offset = ALIGN(sizeof(*req)); 496 req->name_size = name_size; 497 req->guid_offset = ALIGN(req->name_offset + req->name_size); 498 req->guid_size = sizeof(*guid); 499 req->data_offset = ALIGN(req->guid_offset + req->guid_size); 500 req->data_size = data_size; 501 req->length = req->data_offset + req->data_size; 502 503 memcpy((char *)req + req->name_offset, name, name_size); 504 memcpy((char *)req + req->guid_offset, guid, sizeof(*guid)); 505 memcpy((char *)req + req->data_offset, data, data_size); 506 507 ret = qcscm_tee_app_send(sc, sc->sc_uefi_id, 508 QCSCM_DMA_DVA(qdm) + reqoff, reqsize, 509 QCSCM_DMA_DVA(qdm) + respoff, respsize); 510 if (ret) { 511 qcscm_dmamem_free(sc, qdm); 512 return QCTEE_UEFI_DEVICE_ERROR; 513 } 514 515 resp = QCSCM_DMA_KVA(qdm) + respoff; 516 if (resp->command_id != QCTEE_UEFI_SET_VARIABLE || 517 resp->length < sizeof(*resp) || resp->length > respsize) { 518 qcscm_dmamem_free(sc, qdm); 519 return QCTEE_UEFI_DEVICE_ERROR; 520 } 521 522 if (resp->status) { 523 ret = resp->status; 524 qcscm_dmamem_free(sc, qdm); 525 return ret; 526 } 527 528 qcscm_dmamem_free(sc, qdm); 529 return QCTEE_UEFI_SUCCESS; 530 } 531 532 struct qcscm_req_uefi_get_next_variable { 533 uint32_t command_id; 534 uint32_t length; 535 uint32_t guid_offset; 536 uint32_t guid_size; 537 uint32_t name_offset; 538 uint32_t name_size; 539 }; 540 541 struct qcscm_rsp_uefi_get_next_variable { 542 uint32_t command_id; 543 uint32_t length; 544 uint32_t status; 545 uint32_t guid_offset; 546 uint32_t guid_size; 547 uint32_t name_offset; 548 uint32_t name_size; 549 }; 550 551 EFI_STATUS 552 qcscm_uefi_get_next_variable(struct qcscm_softc *sc, 553 CHAR16 *name, int *name_size, EFI_GUID *guid) 554 { 555 struct qcscm_req_uefi_get_next_variable *req; 556 struct qcscm_rsp_uefi_get_next_variable *resp; 557 struct qcscm_dmamem *qdm; 558 size_t reqsize, respsize; 559 off_t reqoff, respoff; 560 int ret; 561 562 reqsize = ALIGN(sizeof(*req)) + ALIGN(sizeof(*guid)) + ALIGN(*name_size); 563 respsize = ALIGN(sizeof(*resp)) + ALIGN(sizeof(*guid)) + ALIGN(*name_size); 564 565 reqoff = 0; 566 respoff = reqsize; 567 568 qdm = qcscm_dmamem_alloc(sc, round_page(reqsize + respsize), 8); 569 if (qdm == NULL) 570 return QCTEE_UEFI_DEVICE_ERROR; 571 572 req = QCSCM_DMA_KVA(qdm) + reqoff; 573 req->command_id = QCTEE_UEFI_GET_NEXT_VARIABLE; 574 req->guid_offset = ALIGN(sizeof(*req)); 575 req->guid_size = sizeof(*guid); 576 req->name_offset = ALIGN(req->guid_offset + req->guid_size); 577 req->name_size = *name_size; 578 req->length = req->name_offset + req->name_size; 579 580 memcpy((char *)req + req->guid_offset, guid, sizeof(*guid)); 581 memcpy((char *)req + req->name_offset, name, *name_size); 582 583 ret = qcscm_tee_app_send(sc, sc->sc_uefi_id, 584 QCSCM_DMA_DVA(qdm) + reqoff, reqsize, 585 QCSCM_DMA_DVA(qdm) + respoff, respsize); 586 if (ret) { 587 qcscm_dmamem_free(sc, qdm); 588 return QCTEE_UEFI_DEVICE_ERROR; 589 } 590 591 resp = QCSCM_DMA_KVA(qdm) + respoff; 592 if (resp->command_id != QCTEE_UEFI_GET_NEXT_VARIABLE || 593 resp->length < sizeof(*resp) || resp->length > respsize) { 594 qcscm_dmamem_free(sc, qdm); 595 return QCTEE_UEFI_DEVICE_ERROR; 596 } 597 598 if (resp->status) { 599 if (resp->status == QCTEE_UEFI_BUFFER_TOO_SMALL) 600 *name_size = resp->name_size; 601 ret = resp->status; 602 qcscm_dmamem_free(sc, qdm); 603 return ret; 604 } 605 606 if (resp->guid_offset + resp->guid_size > resp->length || 607 resp->name_offset + resp->name_size > resp->length) { 608 qcscm_dmamem_free(sc, qdm); 609 return QCTEE_UEFI_DEVICE_ERROR; 610 } 611 612 if (resp->guid_size != sizeof(*guid)) { 613 qcscm_dmamem_free(sc, qdm); 614 return QCTEE_UEFI_DEVICE_ERROR; 615 } 616 617 if (resp->name_size > *name_size) { 618 *name_size = resp->name_size; 619 qcscm_dmamem_free(sc, qdm); 620 return QCTEE_UEFI_BUFFER_TOO_SMALL; 621 } 622 623 memcpy(guid, (char *)resp + resp->guid_offset, sizeof(*guid)); 624 memcpy(name, (char *)resp + resp->name_offset, resp->name_size); 625 *name_size = resp->name_size; 626 627 qcscm_dmamem_free(sc, qdm); 628 return QCTEE_UEFI_SUCCESS; 629 } 630 631 #ifdef QCSCM_DEBUG 632 void 633 qcscm_uefi_dump_variables(struct qcscm_softc *sc) 634 { 635 CHAR16 name[128]; 636 EFI_GUID guid; 637 int namesize = sizeof(name); 638 int i, ret; 639 640 memset(name, 0, sizeof(name)); 641 memset(&guid, 0, sizeof(guid)); 642 643 for (;;) { 644 ret = qcscm_uefi_get_next_variable(sc, name, &namesize, &guid); 645 if (ret == 0) { 646 printf("%s: ", sc->sc_dev.dv_xname); 647 for (i = 0; i < namesize / 2; i++) 648 printf("%c", name[i]); 649 printf(" { 0x%08x, 0x%04x, 0x%04x, { ", 650 guid.Data1, guid.Data2, guid.Data3); 651 for (i = 0; i < 8; i++) { 652 printf(" 0x%02x,", guid.Data4[i]); 653 } 654 printf(" }"); 655 printf("\n"); 656 namesize = sizeof(name); 657 continue; 658 } 659 break; 660 } 661 } 662 663 void 664 qcscm_uefi_dump_variable(struct qcscm_softc *sc, CHAR16 *name, int namesize, 665 EFI_GUID *guid) 666 { 667 uint8_t data[512]; 668 int datasize = sizeof(data); 669 int i, ret; 670 671 ret = qcscm_uefi_get_variable(sc, name, namesize, guid, 672 NULL, data, &datasize); 673 if (ret != QCTEE_UEFI_SUCCESS) { 674 printf("%s: error reading ", sc->sc_dev.dv_xname); 675 for (i = 0; i < namesize / 2; i++) 676 printf("%c", name[i]); 677 printf("\n"); 678 return; 679 } 680 681 printf("%s: ", sc->sc_dev.dv_xname); 682 for (i = 0; i < namesize / 2; i++) 683 printf("%c", name[i]); 684 printf(" = "); 685 for (i = 0; i < datasize; i++) 686 printf("%02x", data[i]); 687 printf("\n"); 688 } 689 #endif 690 691 int 692 qcscm_uefi_rtc_get(uint32_t *off) 693 { 694 struct qcscm_softc *sc = qcscm_sc; 695 uint32_t rtcinfo[3]; 696 int rtcinfosize = sizeof(rtcinfo); 697 698 if (sc == NULL) 699 return ENXIO; 700 701 if (qcscm_uefi_get_variable(sc, u"RTCInfo", sizeof(u"RTCInfo"), 702 &qcscm_uefi_rtcinfo_guid, NULL, (uint8_t *)rtcinfo, 703 &rtcinfosize) != 0) 704 return EIO; 705 706 *off = rtcinfo[0]; 707 return 0; 708 } 709 710 int 711 qcscm_uefi_rtc_set(uint32_t off) 712 { 713 struct qcscm_softc *sc = qcscm_sc; 714 uint32_t rtcinfo[3]; 715 int rtcinfosize = sizeof(rtcinfo); 716 717 if (sc == NULL) 718 return ENXIO; 719 720 if (qcscm_uefi_get_variable(sc, u"RTCInfo", sizeof(u"RTCInfo"), 721 &qcscm_uefi_rtcinfo_guid, NULL, (uint8_t *)rtcinfo, 722 &rtcinfosize) != 0) 723 return EIO; 724 725 /* No need to set if we're not changing anything */ 726 if (rtcinfo[0] == off) 727 return 0; 728 729 rtcinfo[0] = off; 730 rtcinfo[1] = 0x10000; 731 rtcinfo[2] = 0; 732 733 if (qcscm_uefi_set_variable(sc, u"RTCInfo", sizeof(u"RTCInfo"), 734 &qcscm_uefi_rtcinfo_guid, EFI_VARIABLE_NON_VOLATILE | 735 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 736 (uint8_t *)rtcinfo, sizeof(rtcinfo)) != 0) 737 return EIO; 738 739 return 0; 740 } 741 742 int 743 qcscm_pas_init_image(uint32_t peripheral, paddr_t metadata) 744 { 745 struct qcscm_softc *sc = qcscm_sc; 746 uint64_t res[3]; 747 uint64_t args[2]; 748 uint32_t arginfo; 749 int ret; 750 751 if (sc == NULL) 752 return ENXIO; 753 754 arginfo = QCSCM_ARGINFO_NUM(nitems(args)); 755 arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_VAL); 756 arginfo |= QCSCM_ARGINFO_TYPE(1, QCSCM_ARGINFO_TYPE_RW); 757 args[0] = peripheral; 758 args[1] = metadata; 759 760 /* Make call into TEE */ 761 ret = qcscm_smc_call(sc, ARM_SMCCC_OWNER_SIP, QCSCM_SVC_PIL, 762 QCSCM_PIL_PAS_INIT_IMAGE, arginfo, args, nitems(args), res); 763 764 /* If the call succeeded, check the response status */ 765 if (ret == 0) 766 ret = res[0]; 767 768 return ret; 769 } 770 771 int 772 qcscm_pas_mem_setup(uint32_t peripheral, paddr_t addr, size_t size) 773 { 774 struct qcscm_softc *sc = qcscm_sc; 775 uint64_t res[3]; 776 uint64_t args[3]; 777 uint32_t arginfo; 778 int ret; 779 780 if (sc == NULL) 781 return ENXIO; 782 783 arginfo = QCSCM_ARGINFO_NUM(nitems(args)); 784 arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_VAL); 785 arginfo |= QCSCM_ARGINFO_TYPE(1, QCSCM_ARGINFO_TYPE_VAL); 786 arginfo |= QCSCM_ARGINFO_TYPE(2, QCSCM_ARGINFO_TYPE_VAL); 787 args[0] = peripheral; 788 args[1] = addr; 789 args[2] = size; 790 791 /* Make call into TEE */ 792 ret = qcscm_smc_call(sc, ARM_SMCCC_OWNER_SIP, QCSCM_SVC_PIL, 793 QCSCM_PIL_PAS_MEM_SETUP, arginfo, args, nitems(args), res); 794 795 /* If the call succeeded, check the response status */ 796 if (ret == 0) 797 ret = res[0]; 798 799 return ret; 800 } 801 802 int 803 qcscm_pas_auth_and_reset(uint32_t peripheral) 804 { 805 struct qcscm_softc *sc = qcscm_sc; 806 uint64_t res[3]; 807 uint64_t args[1]; 808 uint32_t arginfo; 809 int ret; 810 811 if (sc == NULL) 812 return ENXIO; 813 814 arginfo = QCSCM_ARGINFO_NUM(nitems(args)); 815 arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_VAL); 816 args[0] = peripheral; 817 818 /* Make call into TEE */ 819 ret = qcscm_smc_call(sc, ARM_SMCCC_OWNER_SIP, QCSCM_SVC_PIL, 820 QCSCM_PIL_PAS_AUTH_AND_RESET, arginfo, args, nitems(args), res); 821 822 /* If the call succeeded, check the response status */ 823 if (ret == 0) 824 ret = res[0]; 825 826 return ret; 827 } 828 829 /* DMA code */ 830 struct qcscm_dmamem * 831 qcscm_dmamem_alloc(struct qcscm_softc *sc, bus_size_t size, bus_size_t align) 832 { 833 struct qcscm_dmamem *qdm; 834 int nsegs; 835 836 qdm = malloc(sizeof(*qdm), M_DEVBUF, M_WAITOK | M_ZERO); 837 qdm->qdm_size = size; 838 839 if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 840 BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &qdm->qdm_map) != 0) 841 goto qdmfree; 842 843 if (bus_dmamem_alloc_range(sc->sc_dmat, size, align, 0, 844 &qdm->qdm_seg, 1, &nsegs, BUS_DMA_WAITOK, 0, 0xffffffff) != 0) 845 goto destroy; 846 847 if (bus_dmamem_map(sc->sc_dmat, &qdm->qdm_seg, nsegs, size, 848 &qdm->qdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0) 849 goto free; 850 851 if (bus_dmamap_load(sc->sc_dmat, qdm->qdm_map, qdm->qdm_kva, size, 852 NULL, BUS_DMA_WAITOK) != 0) 853 goto unmap; 854 855 bzero(qdm->qdm_kva, size); 856 857 return (qdm); 858 859 unmap: 860 bus_dmamem_unmap(sc->sc_dmat, qdm->qdm_kva, size); 861 free: 862 bus_dmamem_free(sc->sc_dmat, &qdm->qdm_seg, 1); 863 destroy: 864 bus_dmamap_destroy(sc->sc_dmat, qdm->qdm_map); 865 qdmfree: 866 free(qdm, M_DEVBUF, sizeof(*qdm)); 867 868 return (NULL); 869 } 870 871 void 872 qcscm_dmamem_free(struct qcscm_softc *sc, struct qcscm_dmamem *qdm) 873 { 874 bus_dmamem_unmap(sc->sc_dmat, qdm->qdm_kva, qdm->qdm_size); 875 bus_dmamem_free(sc->sc_dmat, &qdm->qdm_seg, 1); 876 bus_dmamap_destroy(sc->sc_dmat, qdm->qdm_map); 877 free(qdm, M_DEVBUF, sizeof(*qdm)); 878 } 879