1 /* $OpenBSD: qcscm.c,v 1.3 2023/04/28 10:19:07 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 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, #0]\n" 193 "ldp x2, x3, [%0, #16]\n" 194 "ldp x4, x5, [%0, #32]\n" 195 "ldp x6, x7, [%0, #48]\n" 196 "smc #0\n" 197 "stp x0, x1, [%1, #0]\n" 198 "stp x2, x3, [%1, #16]\n" 199 "stp x4, x5, [%1, #32]\n" 200 "stp x6, x7, [%1, #48]\n" :: 201 "r" (in), "r" (out) : 202 "x0", "x1", "x2", "x3", 203 "x4", "x5", "x6", "x7", 204 "memory"); 205 } 206 207 int 208 qcscm_smc_call(struct qcscm_softc *sc, uint8_t owner, uint8_t svc, uint8_t cmd, 209 uint32_t arginfo, uint64_t *args, int arglen, uint64_t *res) 210 { 211 uint64_t smcreq[8] = { 0 }, smcres[8] = { 0 }; 212 uint64_t *smcextreq; 213 int i; 214 215 /* 4 of our 10 possible args fit into x2-x5 */ 216 smcreq[0] = ARM_SMCCC_STD_CALL | ARM_SMCCC_LP64 | 217 owner << 24 | svc << 8 | cmd; 218 smcreq[1] = arginfo; 219 for (i = 0; i < min(arglen, 4); i++) 220 smcreq[2 + i] = args[i]; 221 222 /* In case we have more than 4, use x5 as ptr to extra args */ 223 smcextreq = QCSCM_DMA_KVA(sc->sc_extarg); 224 if (arglen > 4) { 225 smcreq[5] = QCSCM_DMA_DVA(sc->sc_extarg); 226 smcextreq = QCSCM_DMA_KVA(sc->sc_extarg); 227 for (i = 0; i < min(arglen - 3, 7); i++) { 228 smcextreq[i] = args[3 + i]; 229 } 230 } 231 232 for (;;) { 233 qcscm_smc_exec(smcreq, smcres); 234 /* If the call gets interrupted, try again and re-pass x0/x6 */ 235 if (smcres[0] == QCSCM_INTERRUPTED) { 236 smcreq[0] = smcres[0]; 237 smcreq[6] = smcres[6]; 238 continue; 239 } 240 break; 241 } 242 243 if (res) { 244 res[0] = smcres[1]; 245 res[1] = smcres[2]; 246 res[2] = smcres[3]; 247 } 248 249 return smcres[0]; 250 } 251 252 /* Retrieve id of app running in TEE by name */ 253 int 254 qcscm_tee_app_get_id(struct qcscm_softc *sc, const char *name, uint32_t *id) 255 { 256 struct qcscm_dmamem *qdm; 257 uint64_t res[3]; 258 uint64_t args[2]; 259 uint32_t arginfo; 260 int ret; 261 262 /* Max name length is 64 */ 263 if (strlen(name) > 64) 264 return EINVAL; 265 266 /* Alloc some phys mem to hold the name */ 267 qdm = qcscm_dmamem_alloc(sc, PAGE_SIZE, 8); 268 if (qdm == NULL) 269 return ENOMEM; 270 271 /* Copy name of app we want to get an id for to page */ 272 memcpy(QCSCM_DMA_KVA(qdm), name, strlen(name)); 273 274 /* Pass address of name and length */ 275 arginfo = QCSCM_ARGINFO_NUM(nitems(args)); 276 arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_RW); 277 arginfo |= QCSCM_ARGINFO_TYPE(1, QCSCM_ARGINFO_TYPE_VAL); 278 args[0] = QCSCM_DMA_DVA(qdm); 279 args[1] = strlen(name); 280 281 /* Make call into TEE */ 282 ret = qcscm_smc_call(sc, QCTEE_TZ_OWNER_QSEE_OS, QCTEE_TZ_SVC_APP_MGR, 283 0x03, arginfo, args, nitems(args), res); 284 285 /* If the call succeeded, check the response status */ 286 if (ret == 0) 287 ret = res[0]; 288 289 /* If the response status is successful as well, retrieve data */ 290 if (ret == 0) 291 *id = res[2]; 292 293 qcscm_dmamem_free(sc, qdm); 294 return ret; 295 } 296 297 /* Message interface to app running in TEE */ 298 int 299 qcscm_tee_app_send(struct qcscm_softc *sc, uint32_t id, uint64_t req_phys, 300 uint64_t req_len, uint64_t rsp_phys, uint64_t rsp_len) 301 { 302 uint64_t res[3]; 303 uint64_t args[5]; 304 uint32_t arginfo; 305 int ret; 306 307 /* Pass id of app we target, plus request and response buffers */ 308 arginfo = QCSCM_ARGINFO_NUM(nitems(args)); 309 arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_VAL); 310 arginfo |= QCSCM_ARGINFO_TYPE(1, QCSCM_ARGINFO_TYPE_RW); 311 arginfo |= QCSCM_ARGINFO_TYPE(2, QCSCM_ARGINFO_TYPE_VAL); 312 arginfo |= QCSCM_ARGINFO_TYPE(3, QCSCM_ARGINFO_TYPE_RW); 313 arginfo |= QCSCM_ARGINFO_TYPE(4, QCSCM_ARGINFO_TYPE_VAL); 314 args[0] = id; 315 args[1] = req_phys; 316 args[2] = req_len; 317 args[3] = rsp_phys; 318 args[4] = rsp_len; 319 320 membar_sync(); 321 322 /* Make call into TEE */ 323 ret = qcscm_smc_call(sc, QCTEE_TZ_OWNER_TZ_APPS, 324 QCTEE_TZ_SVC_APP_ID_PLACEHOLDER, 0x01, 325 arginfo, args, nitems(args), res); 326 327 membar_sync(); 328 329 /* If the call succeeded, check the response status */ 330 if (ret == 0) 331 ret = res[0]; 332 333 return ret; 334 } 335 336 struct qcscm_req_uefi_get_variable { 337 uint32_t command_id; 338 uint32_t length; 339 uint32_t name_offset; 340 uint32_t name_size; 341 uint32_t guid_offset; 342 uint32_t guid_size; 343 uint32_t data_size; 344 }; 345 346 struct qcscm_rsp_uefi_get_variable { 347 uint32_t command_id; 348 uint32_t length; 349 uint32_t status; 350 uint32_t attributes; 351 uint32_t data_offset; 352 uint32_t data_size; 353 }; 354 355 EFI_STATUS 356 qcscm_uefi_get_variable(struct qcscm_softc *sc, 357 CHAR16 *name, int name_size, EFI_GUID *guid, 358 uint32_t *attributes, uint8_t *data, int *data_size) 359 { 360 struct qcscm_req_uefi_get_variable *req; 361 struct qcscm_rsp_uefi_get_variable *resp; 362 struct qcscm_dmamem *qdm; 363 size_t reqsize, respsize; 364 off_t reqoff, respoff; 365 int ret; 366 367 reqsize = ALIGN(sizeof(*req)) + ALIGN(name_size) + ALIGN(sizeof(*guid)); 368 respsize = ALIGN(sizeof(*resp)) + ALIGN(*data_size); 369 370 reqoff = 0; 371 respoff = reqsize; 372 373 qdm = qcscm_dmamem_alloc(sc, round_page(reqsize + respsize), 8); 374 if (qdm == NULL) 375 return QCTEE_UEFI_DEVICE_ERROR; 376 377 req = QCSCM_DMA_KVA(qdm) + reqoff; 378 req->command_id = QCTEE_UEFI_GET_VARIABLE; 379 req->data_size = *data_size; 380 req->name_offset = ALIGN(sizeof(*req)); 381 req->name_size = name_size; 382 req->guid_offset = ALIGN(req->name_offset + req->name_size); 383 req->guid_size = sizeof(*guid); 384 req->length = req->guid_offset + req->guid_size; 385 386 memcpy((char *)req + req->guid_offset, guid, sizeof(*guid)); 387 memcpy((char *)req + req->name_offset, name, name_size); 388 389 ret = qcscm_tee_app_send(sc, sc->sc_uefi_id, 390 QCSCM_DMA_DVA(qdm) + reqoff, reqsize, 391 QCSCM_DMA_DVA(qdm) + respoff, respsize); 392 if (ret) { 393 qcscm_dmamem_free(sc, qdm); 394 return QCTEE_UEFI_DEVICE_ERROR; 395 } 396 397 resp = QCSCM_DMA_KVA(qdm) + respoff; 398 if (resp->command_id != QCTEE_UEFI_GET_VARIABLE || 399 resp->length < sizeof(*resp) || resp->length > respsize) { 400 qcscm_dmamem_free(sc, qdm); 401 return QCTEE_UEFI_DEVICE_ERROR; 402 } 403 404 if (resp->status) { 405 if (resp->status == QCTEE_UEFI_BUFFER_TOO_SMALL) 406 *data_size = resp->data_size; 407 if (attributes) 408 *attributes = resp->attributes; 409 ret = resp->status; 410 qcscm_dmamem_free(sc, qdm); 411 return ret; 412 } 413 414 if (resp->data_offset + resp->data_size > resp->length) { 415 qcscm_dmamem_free(sc, qdm); 416 return QCTEE_UEFI_DEVICE_ERROR; 417 } 418 419 if (attributes) 420 *attributes = resp->attributes; 421 422 if (*data_size == 0) { 423 *data_size = resp->data_size; 424 qcscm_dmamem_free(sc, qdm); 425 return QCTEE_UEFI_SUCCESS; 426 } 427 428 if (resp->data_size > *data_size) { 429 *data_size = resp->data_size; 430 qcscm_dmamem_free(sc, qdm); 431 return QCTEE_UEFI_BUFFER_TOO_SMALL; 432 } 433 434 memcpy(data, (char *)resp + resp->data_offset, resp->data_size); 435 *data_size = resp->data_size; 436 437 qcscm_dmamem_free(sc, qdm); 438 return EFI_SUCCESS; 439 } 440 441 struct qcscm_req_uefi_set_variable { 442 uint32_t command_id; 443 uint32_t length; 444 uint32_t name_offset; 445 uint32_t name_size; 446 uint32_t guid_offset; 447 uint32_t guid_size; 448 uint32_t attributes; 449 uint32_t data_offset; 450 uint32_t data_size; 451 }; 452 453 struct qcscm_rsp_uefi_set_variable { 454 uint32_t command_id; 455 uint32_t length; 456 uint32_t status; 457 uint32_t unknown[2]; 458 }; 459 460 EFI_STATUS 461 qcscm_uefi_set_variable(struct qcscm_softc *sc, 462 CHAR16 *name, int name_size, EFI_GUID *guid, 463 uint32_t attributes, uint8_t *data, int data_size) 464 { 465 struct qcscm_req_uefi_set_variable *req; 466 struct qcscm_rsp_uefi_set_variable *resp; 467 struct qcscm_dmamem *qdm; 468 size_t reqsize, respsize; 469 off_t reqoff, respoff; 470 int ret; 471 472 reqsize = ALIGN(sizeof(*req)) + ALIGN(name_size) + ALIGN(sizeof(*guid)) + 473 ALIGN(data_size); 474 respsize = ALIGN(sizeof(*resp)); 475 476 reqoff = 0; 477 respoff = reqsize; 478 479 qdm = qcscm_dmamem_alloc(sc, round_page(reqsize + respsize), 8); 480 if (qdm == NULL) 481 return QCTEE_UEFI_DEVICE_ERROR; 482 483 req = QCSCM_DMA_KVA(qdm) + reqoff; 484 req->command_id = QCTEE_UEFI_SET_VARIABLE; 485 req->attributes = attributes; 486 req->name_offset = ALIGN(sizeof(*req)); 487 req->name_size = name_size; 488 req->guid_offset = ALIGN(req->name_offset + req->name_size); 489 req->guid_size = sizeof(*guid); 490 req->data_offset = ALIGN(req->guid_offset + req->guid_size); 491 req->data_size = data_size; 492 req->length = req->data_offset + req->data_size; 493 494 memcpy((char *)req + req->name_offset, name, name_size); 495 memcpy((char *)req + req->guid_offset, guid, sizeof(*guid)); 496 memcpy((char *)req + req->data_offset, data, data_size); 497 498 ret = qcscm_tee_app_send(sc, sc->sc_uefi_id, 499 QCSCM_DMA_DVA(qdm) + reqoff, reqsize, 500 QCSCM_DMA_DVA(qdm) + respoff, respsize); 501 if (ret) { 502 qcscm_dmamem_free(sc, qdm); 503 return QCTEE_UEFI_DEVICE_ERROR; 504 } 505 506 resp = QCSCM_DMA_KVA(qdm) + respoff; 507 if (resp->command_id != QCTEE_UEFI_SET_VARIABLE || 508 resp->length < sizeof(*resp) || resp->length > respsize) { 509 qcscm_dmamem_free(sc, qdm); 510 return QCTEE_UEFI_DEVICE_ERROR; 511 } 512 513 if (resp->status) { 514 ret = resp->status; 515 qcscm_dmamem_free(sc, qdm); 516 return ret; 517 } 518 519 qcscm_dmamem_free(sc, qdm); 520 return QCTEE_UEFI_SUCCESS; 521 } 522 523 struct qcscm_req_uefi_get_next_variable { 524 uint32_t command_id; 525 uint32_t length; 526 uint32_t guid_offset; 527 uint32_t guid_size; 528 uint32_t name_offset; 529 uint32_t name_size; 530 }; 531 532 struct qcscm_rsp_uefi_get_next_variable { 533 uint32_t command_id; 534 uint32_t length; 535 uint32_t status; 536 uint32_t guid_offset; 537 uint32_t guid_size; 538 uint32_t name_offset; 539 uint32_t name_size; 540 }; 541 542 EFI_STATUS 543 qcscm_uefi_get_next_variable(struct qcscm_softc *sc, 544 CHAR16 *name, int *name_size, EFI_GUID *guid) 545 { 546 struct qcscm_req_uefi_get_next_variable *req; 547 struct qcscm_rsp_uefi_get_next_variable *resp; 548 struct qcscm_dmamem *qdm; 549 size_t reqsize, respsize; 550 off_t reqoff, respoff; 551 int ret; 552 553 reqsize = ALIGN(sizeof(*req)) + ALIGN(sizeof(*guid)) + ALIGN(*name_size); 554 respsize = ALIGN(sizeof(*resp)) + ALIGN(sizeof(*guid)) + ALIGN(*name_size); 555 556 reqoff = 0; 557 respoff = reqsize; 558 559 qdm = qcscm_dmamem_alloc(sc, round_page(reqsize + respsize), 8); 560 if (qdm == NULL) 561 return QCTEE_UEFI_DEVICE_ERROR; 562 563 req = QCSCM_DMA_KVA(qdm) + reqoff; 564 req->command_id = QCTEE_UEFI_GET_NEXT_VARIABLE; 565 req->guid_offset = ALIGN(sizeof(*req)); 566 req->guid_size = sizeof(*guid); 567 req->name_offset = ALIGN(req->guid_offset + req->guid_size); 568 req->name_size = *name_size; 569 req->length = req->name_offset + req->name_size; 570 571 memcpy((char *)req + req->guid_offset, guid, sizeof(*guid)); 572 memcpy((char *)req + req->name_offset, name, *name_size); 573 574 ret = qcscm_tee_app_send(sc, sc->sc_uefi_id, 575 QCSCM_DMA_DVA(qdm) + reqoff, reqsize, 576 QCSCM_DMA_DVA(qdm) + respoff, respsize); 577 if (ret) { 578 qcscm_dmamem_free(sc, qdm); 579 return QCTEE_UEFI_DEVICE_ERROR; 580 } 581 582 resp = QCSCM_DMA_KVA(qdm) + respoff; 583 if (resp->command_id != QCTEE_UEFI_GET_NEXT_VARIABLE || 584 resp->length < sizeof(*resp) || resp->length > respsize) { 585 qcscm_dmamem_free(sc, qdm); 586 return QCTEE_UEFI_DEVICE_ERROR; 587 } 588 589 if (resp->status) { 590 if (resp->status == QCTEE_UEFI_BUFFER_TOO_SMALL) 591 *name_size = resp->name_size; 592 ret = resp->status; 593 qcscm_dmamem_free(sc, qdm); 594 return ret; 595 } 596 597 if (resp->guid_offset + resp->guid_size > resp->length || 598 resp->name_offset + resp->name_size > resp->length) { 599 qcscm_dmamem_free(sc, qdm); 600 return QCTEE_UEFI_DEVICE_ERROR; 601 } 602 603 if (resp->guid_size != sizeof(*guid)) { 604 qcscm_dmamem_free(sc, qdm); 605 return QCTEE_UEFI_DEVICE_ERROR; 606 } 607 608 if (resp->name_size > *name_size) { 609 *name_size = resp->name_size; 610 qcscm_dmamem_free(sc, qdm); 611 return QCTEE_UEFI_BUFFER_TOO_SMALL; 612 } 613 614 memcpy(guid, (char *)resp + resp->guid_offset, sizeof(*guid)); 615 memcpy(name, (char *)resp + resp->name_offset, resp->name_size); 616 *name_size = resp->name_size; 617 618 qcscm_dmamem_free(sc, qdm); 619 return QCTEE_UEFI_SUCCESS; 620 } 621 622 #ifdef QCSCM_DEBUG 623 void 624 qcscm_uefi_dump_variables(struct qcscm_softc *sc) 625 { 626 CHAR16 name[128]; 627 EFI_GUID guid; 628 int namesize = sizeof(name); 629 int i, ret; 630 631 memset(name, 0, sizeof(name)); 632 memset(&guid, 0, sizeof(guid)); 633 634 for (;;) { 635 ret = qcscm_uefi_get_next_variable(sc, name, &namesize, &guid); 636 if (ret == 0) { 637 printf("%s: ", sc->sc_dev.dv_xname); 638 for (i = 0; i < namesize / 2; i++) 639 printf("%c", name[i]); 640 printf(" { 0x%08x, 0x%04x, 0x%04x, { ", 641 guid.Data1, guid.Data2, guid.Data3); 642 for (i = 0; i < 8; i++) { 643 printf(" 0x%02x,", guid.Data4[i]); 644 } 645 printf(" }"); 646 printf("\n"); 647 namesize = sizeof(name); 648 continue; 649 } 650 break; 651 } 652 } 653 654 void 655 qcscm_uefi_dump_variable(struct qcscm_softc *sc, CHAR16 *name, int namesize, 656 EFI_GUID *guid) 657 { 658 uint8_t data[512]; 659 int datasize = sizeof(data); 660 int i, ret; 661 662 ret = qcscm_uefi_get_variable(sc, name, namesize, guid, 663 NULL, data, &datasize); 664 if (ret != QCTEE_UEFI_SUCCESS) { 665 printf("%s: error reading ", sc->sc_dev.dv_xname); 666 for (i = 0; i < namesize / 2; i++) 667 printf("%c", name[i]); 668 printf("\n"); 669 return; 670 } 671 672 printf("%s: ", sc->sc_dev.dv_xname); 673 for (i = 0; i < namesize / 2; i++) 674 printf("%c", name[i]); 675 printf(" = "); 676 for (i = 0; i < datasize; i++) 677 printf("%02x", data[i]); 678 printf("\n"); 679 } 680 #endif 681 682 int 683 qcscm_uefi_rtc_get(uint32_t *off) 684 { 685 struct qcscm_softc *sc = qcscm_sc; 686 uint32_t rtcinfo[3]; 687 int rtcinfosize = sizeof(rtcinfo); 688 689 if (sc == NULL) 690 return ENXIO; 691 692 if (qcscm_uefi_get_variable(sc, u"RTCInfo", sizeof(u"RTCInfo"), 693 &qcscm_uefi_rtcinfo_guid, NULL, (uint8_t *)rtcinfo, 694 &rtcinfosize) != 0) 695 return EIO; 696 697 *off = rtcinfo[0]; 698 return 0; 699 } 700 701 int 702 qcscm_uefi_rtc_set(uint32_t off) 703 { 704 struct qcscm_softc *sc = qcscm_sc; 705 uint32_t rtcinfo[3]; 706 int rtcinfosize = sizeof(rtcinfo); 707 708 if (sc == NULL) 709 return ENXIO; 710 711 if (qcscm_uefi_get_variable(sc, u"RTCInfo", sizeof(u"RTCInfo"), 712 &qcscm_uefi_rtcinfo_guid, NULL, (uint8_t *)rtcinfo, 713 &rtcinfosize) != 0) 714 return EIO; 715 716 /* No need to set if we're not changing anything */ 717 if (rtcinfo[0] == off) 718 return 0; 719 720 rtcinfo[0] = off; 721 rtcinfo[1] = 0x10000; 722 rtcinfo[2] = 0; 723 724 if (qcscm_uefi_set_variable(sc, u"RTCInfo", sizeof(u"RTCInfo"), 725 &qcscm_uefi_rtcinfo_guid, EFI_VARIABLE_NON_VOLATILE | 726 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 727 (uint8_t *)rtcinfo, sizeof(rtcinfo)) != 0) 728 return EIO; 729 730 return 0; 731 } 732 733 /* DMA code */ 734 struct qcscm_dmamem * 735 qcscm_dmamem_alloc(struct qcscm_softc *sc, bus_size_t size, bus_size_t align) 736 { 737 struct qcscm_dmamem *qdm; 738 int nsegs; 739 740 qdm = malloc(sizeof(*qdm), M_DEVBUF, M_WAITOK | M_ZERO); 741 qdm->qdm_size = size; 742 743 if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 744 BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &qdm->qdm_map) != 0) 745 goto qdmfree; 746 747 if (bus_dmamem_alloc_range(sc->sc_dmat, size, align, 0, 748 &qdm->qdm_seg, 1, &nsegs, BUS_DMA_WAITOK, 0, 0xffffffff) != 0) 749 goto destroy; 750 751 if (bus_dmamem_map(sc->sc_dmat, &qdm->qdm_seg, nsegs, size, 752 &qdm->qdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0) 753 goto free; 754 755 if (bus_dmamap_load(sc->sc_dmat, qdm->qdm_map, qdm->qdm_kva, size, 756 NULL, BUS_DMA_WAITOK) != 0) 757 goto unmap; 758 759 bzero(qdm->qdm_kva, size); 760 761 return (qdm); 762 763 unmap: 764 bus_dmamem_unmap(sc->sc_dmat, qdm->qdm_kva, size); 765 free: 766 bus_dmamem_free(sc->sc_dmat, &qdm->qdm_seg, 1); 767 destroy: 768 bus_dmamap_destroy(sc->sc_dmat, qdm->qdm_map); 769 qdmfree: 770 free(qdm, M_DEVBUF, sizeof(*qdm)); 771 772 return (NULL); 773 } 774 775 void 776 qcscm_dmamem_free(struct qcscm_softc *sc, struct qcscm_dmamem *qdm) 777 { 778 bus_dmamem_unmap(sc->sc_dmat, qdm->qdm_kva, qdm->qdm_size); 779 bus_dmamem_free(sc->sc_dmat, &qdm->qdm_seg, 1); 780 bus_dmamap_destroy(sc->sc_dmat, qdm->qdm_map); 781 free(qdm, M_DEVBUF, sizeof(*qdm)); 782 } 783