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