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