1 /** @addtogroup MCD_MCDIMPL_DAEMON_CONHDLR 2 * @{ 3 * @file 4 * 5 * Entry of the MobiCore Driver. 6 * 7 * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 --> 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author may not be used to endorse or promote 18 * products derived from this software without specific prior 19 * written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 22 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <cstdlib> 35 #include <signal.h> 36 #include <fcntl.h> 37 #include <stdio.h> 38 39 #include "MobiCoreDriverApi.h" 40 #include "MobiCoreDriverCmd.h" 41 #include "mcVersion.h" 42 #include "mcVersionHelper.h" 43 #include "mc_linux.h" 44 45 #include "MobiCoreDriverDaemon.h" 46 #include "MobiCoreRegistry.h" 47 #include "MobiCoreDevice.h" 48 49 #include "NetlinkServer.h" 50 51 #include "log.h" 52 53 #define DRIVER_TCI_LEN 100 54 55 #include "Mci/mci.h" 56 57 MC_CHECK_VERSION(MCI, 0, 2); 58 MC_CHECK_VERSION(SO, 2, 0); 59 MC_CHECK_VERSION(MCLF, 2, 0); 60 MC_CHECK_VERSION(CONTAINER, 2, 0); 61 62 static void checkMobiCoreVersion(MobiCoreDevice *mobiCoreDevice); 63 64 //------------------------------------------------------------------------------ 65 MobiCoreDriverDaemon::MobiCoreDriverDaemon( 66 bool enableScheduler, 67 bool loadMobicore, 68 std::string mobicoreImage, 69 unsigned int donateRamSize, 70 bool loadDriver, 71 std::string driverPath 72 ) 73 { 74 mobiCoreDevice = NULL; 75 76 this->enableScheduler = enableScheduler; 77 this->loadMobicore = loadMobicore; 78 this->mobicoreImage = mobicoreImage; 79 this->donateRamSize = donateRamSize; 80 this->loadDriver = loadDriver; 81 this->driverPath = driverPath; 82 83 for (int i = 0; i < MAX_SERVERS; i++) { 84 servers[i] = NULL; 85 } 86 } 87 88 //------------------------------------------------------------------------------ 89 MobiCoreDriverDaemon::~MobiCoreDriverDaemon( 90 void 91 ) 92 { 93 // Unload any device drivers might have been loaded 94 driverResourcesList_t::iterator it; 95 for (it = driverResources.begin(); it != driverResources.end(); it++) { 96 MobicoreDriverResources *res = *it; 97 mobiCoreDevice->closeSession(res->conn, res->sessionId); 98 mobiCoreDevice->unregisterWsmL2(res->pTciWsm); 99 } 100 delete mobiCoreDevice; 101 for (int i = 0; i < MAX_SERVERS; i++) { 102 delete servers[i]; 103 servers[i] = NULL; 104 } 105 } 106 107 108 //------------------------------------------------------------------------------ 109 void MobiCoreDriverDaemon::run( 110 void 111 ) 112 { 113 LOG_I("Daemon starting up..."); 114 LOG_I("Socket interface version is %u.%u", DAEMON_VERSION_MAJOR, DAEMON_VERSION_MINOR); 115 #ifdef MOBICORE_COMPONENT_BUILD_TAG 116 LOG_I("%s", MOBICORE_COMPONENT_BUILD_TAG); 117 #else 118 #warning "MOBICORE_COMPONENT_BUILD_TAG is not defined!" 119 #endif 120 LOG_I("Build timestamp is %s %s", __DATE__, __TIME__); 121 122 int i; 123 124 mobiCoreDevice = getDeviceInstance(); 125 126 LOG_I("Daemon scheduler is %s", enableScheduler ? "enabled" : "disabled"); 127 LOG_I("Initializing MobiCore Device"); 128 if (!mobiCoreDevice->initDevice( 129 "/dev/" MC_ADMIN_DEVNODE, 130 loadMobicore, 131 mobicoreImage.c_str(), 132 enableScheduler)) { 133 LOG_E("Could not initialize MobiCore!"); 134 return; 135 } 136 mobiCoreDevice->start(); 137 138 LOG_I("Checking version of MobiCore"); 139 checkMobiCoreVersion(mobiCoreDevice); 140 141 if (donateRamSize > 0) { 142 // Donate additional RAM to MC 143 LOG_I("Donating %u Kbytes to Mobicore", donateRamSize / 1024); 144 mobiCoreDevice->donateRam(donateRamSize); 145 } 146 147 if (mobiCoreDevice->mobicoreAlreadyRunning()) { 148 // MC is already initialized, remove all pending sessions 149 #define NUM_DRIVERS 2 150 #define NUM_TRUSTLETS 4 151 #define NUM_SESSIONS (1 + NUM_DRIVERS + NUM_TRUSTLETS) 152 for (i = 2; i < NUM_SESSIONS; i++) { 153 LOG_I("Closing session %i",i); 154 mobiCoreDevice->closeSession(i); 155 } 156 } 157 158 // Load device driver if requested 159 if (loadDriver) { 160 loadDeviceDriver(driverPath); 161 } 162 163 LOG_I("Creating socket servers"); 164 // Start listening for incoming TLC connections 165 servers[0] = new NetlinkServer(this); 166 servers[1] = new Server(this, SOCK_PATH); 167 LOG_I("Successfully created servers"); 168 169 // Start all the servers 170 for (i = 0; i < MAX_SERVERS; i++) { 171 servers[i]->start(); 172 } 173 174 // then wait for them to exit 175 for (i = 0; i < MAX_SERVERS; i++) { 176 servers[i]->join(); 177 } 178 } 179 180 181 //------------------------------------------------------------------------------ 182 MobiCoreDevice *MobiCoreDriverDaemon::getDevice( 183 uint32_t deviceId 184 ) 185 { 186 // Always return the trustZoneDevice as it is currently the only one supported 187 if (MC_DEVICE_ID_DEFAULT != deviceId) 188 return NULL; 189 return mobiCoreDevice; 190 } 191 192 193 //------------------------------------------------------------------------------ 194 void MobiCoreDriverDaemon::dropConnection( 195 Connection *connection 196 ) 197 { 198 // Check if a Device has already been registered with the connection 199 MobiCoreDevice *device = (MobiCoreDevice *) (connection->connectionData); 200 201 if (device != NULL) { 202 LOG_I("dropConnection(): closing still open device."); 203 // A connection has been found and has to be closed 204 device->close(connection); 205 } 206 } 207 208 209 //------------------------------------------------------------------------------ 210 size_t MobiCoreDriverDaemon::writeResult( 211 Connection *connection, 212 mcResult_t code 213 ) 214 { 215 if (0 != code) { 216 LOG_V(" sending error code %d", code); 217 } 218 return connection->writeData(&code, sizeof(mcResult_t)); 219 } 220 221 //------------------------------------------------------------------------------ 222 bool MobiCoreDriverDaemon::loadDeviceDriver( 223 std::string driverPath 224 ) 225 { 226 bool ret = false; 227 CWsm_ptr pWsm = NULL, pTciWsm = NULL; 228 regObject_t *regObj = NULL; 229 Connection *conn = NULL; 230 uint8_t *tci = NULL; 231 mcDrvRspOpenSession_t rspOpenSession; 232 233 do { 234 //mobiCoreDevice 235 FILE *fs = fopen (driverPath.c_str(), "rb"); 236 if (!fs) { 237 LOG_E("%s: failed: cannot open %s", __FUNCTION__, driverPath.c_str()); 238 break; 239 } 240 fclose(fs); 241 242 LOG_I("%s: loading %s", __FUNCTION__, driverPath.c_str()); 243 244 regObj = mcRegistryGetDriverBlob(driverPath.c_str()); 245 if (regObj == NULL) { 246 break;; 247 } 248 249 LOG_I("registering L2 in kmod, p=%p, len=%i", 250 regObj->value, regObj->len); 251 252 pWsm = mobiCoreDevice->registerWsmL2( 253 (addr_t)(regObj->value), regObj->len, 0); 254 if (pWsm == NULL) { 255 LOG_E("allocating WSM for Trustlet failed"); 256 break; 257 } 258 // Initialize information data of open session command 259 loadDataOpenSession_t loadDataOpenSession; 260 loadDataOpenSession.baseAddr = pWsm->physAddr; 261 loadDataOpenSession.offs = ((uint32_t) regObj->value) & 0xFFF; 262 loadDataOpenSession.len = regObj->len; 263 loadDataOpenSession.tlHeader = (mclfHeader_ptr) regObj->value; 264 265 MC_DRV_CMD_OPEN_SESSION_struct cmdOpenSession; 266 tci = (uint8_t *)malloc(DRIVER_TCI_LEN); 267 pTciWsm = mobiCoreDevice->allocateContiguousPersistentWsm(DRIVER_TCI_LEN); 268 if (pTciWsm == NULL) { 269 LOG_E("allocating WSM TCI for Trustlet failed"); 270 break; 271 } 272 cmdOpenSession.deviceId = MC_DEVICE_ID_DEFAULT; 273 cmdOpenSession.tci = (uint32_t)pTciWsm->physAddr; 274 cmdOpenSession.len = DRIVER_TCI_LEN; 275 cmdOpenSession.handle = pTciWsm->handle; 276 277 conn = new Connection(); 278 uint32_t mcRet = mobiCoreDevice->openSession( 279 conn, 280 &loadDataOpenSession, 281 &cmdOpenSession, 282 &(rspOpenSession.payload)); 283 284 // Unregister physical memory from kernel module. 285 // This will also destroy the WSM object. 286 mobiCoreDevice->unregisterWsmL2(pWsm); 287 pWsm = NULL; 288 289 // Free memory occupied by Trustlet data 290 free(regObj); 291 regObj = NULL; 292 293 if (mcRet != MC_MCP_RET_OK) { 294 LOG_E("open session error %d", mcRet); 295 break; 296 } 297 298 ret = true; 299 } while (false); 300 // Free all allocated resources 301 if (ret == false) { 302 LOG_I("%s: Freeing previously allocated resources!", __FUNCTION__); 303 if (pWsm != NULL) { 304 if (!mobiCoreDevice->unregisterWsmL2(pWsm)) { 305 // At least make sure we don't leak the WSM object 306 delete pWsm; 307 } 308 } 309 // No matter if we free NULL objects 310 free(regObj); 311 312 if (conn != NULL) { 313 delete conn; 314 } 315 } else if (conn != NULL) { 316 driverResources.push_back(new MobicoreDriverResources( 317 conn, tci, pTciWsm, rspOpenSession.payload.sessionId)); 318 } 319 320 return ret; 321 } 322 323 #define RECV_PAYLOAD_FROM_CLIENT(CONNECTION, CMD_BUFFER) \ 324 { \ 325 void *payload = (void*)((uint32_t)CMD_BUFFER + sizeof(mcDrvCommandHeader_t)); \ 326 uint32_t payload_len = sizeof(*CMD_BUFFER) - sizeof(mcDrvCommandHeader_t); \ 327 uint32_t rlen = CONNECTION->readData(payload, payload_len); \ 328 if (rlen < 0) { \ 329 LOG_E("reading from Client failed"); \ 330 /* it is questionable, if writing to broken socket has any effect here. */ \ 331 writeResult(CONNECTION, MC_DRV_ERR_DAEMON_SOCKET); \ 332 return; \ 333 } \ 334 if (rlen != payload_len) {\ 335 LOG_E("wrong buffer length %i received from Client", rlen); \ 336 writeResult(CONNECTION, MC_DRV_ERR_DAEMON_SOCKET); \ 337 return; \ 338 } \ 339 } 340 341 #define CHECK_DEVICE(DEVICE, CONNECTION) \ 342 if (DEVICE == NULL) \ 343 { \ 344 LOG_V("%s: no device associated with connection",__FUNCTION__); \ 345 writeResult(CONNECTION, MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN); \ 346 return; \ 347 } 348 349 //------------------------------------------------------------------------------ 350 void MobiCoreDriverDaemon::processOpenDevice( 351 Connection *connection 352 ) 353 { 354 MC_DRV_CMD_OPEN_DEVICE_struct cmdOpenDevice; 355 RECV_PAYLOAD_FROM_CLIENT(connection, &cmdOpenDevice); 356 357 // Check if device has been registered to the connection 358 MobiCoreDevice *device = (MobiCoreDevice *) (connection->connectionData); 359 if (NULL != device) { 360 LOG_E("processOpenDevice(): device already set"); 361 writeResult(connection, MC_DRV_ERR_DEVICE_ALREADY_OPEN); 362 return; 363 } 364 365 LOG_I(" Opening deviceId %d ", cmdOpenDevice.deviceId); 366 367 // Get device for device ID 368 device = getDevice(cmdOpenDevice.deviceId); 369 370 // Check if a device for the given name has been found 371 if (device == NULL) { 372 LOG_E("invalid deviceId"); 373 writeResult(connection, MC_DRV_ERR_UNKNOWN_DEVICE); 374 return; 375 } 376 377 // Register device object with connection 378 device->open(connection); 379 380 // Return result code to client lib (no payload) 381 writeResult(connection, MC_DRV_OK); 382 } 383 384 385 //------------------------------------------------------------------------------ 386 void MobiCoreDriverDaemon::processCloseDevice( 387 Connection *connection 388 ) 389 { 390 // there is no payload to read 391 392 // Device required 393 MobiCoreDevice *device = (MobiCoreDevice *) (connection->connectionData); 394 CHECK_DEVICE(device, connection); 395 396 // No command data will be read 397 // Unregister device object with connection 398 device->close(connection); 399 400 // there is no payload 401 writeResult(connection, MC_DRV_OK); 402 } 403 404 405 //------------------------------------------------------------------------------ 406 void MobiCoreDriverDaemon::processOpenSession( 407 Connection *connection 408 ) 409 { 410 MC_DRV_CMD_OPEN_SESSION_struct cmdOpenSession; 411 RECV_PAYLOAD_FROM_CLIENT(connection, &cmdOpenSession); 412 413 // Device required 414 MobiCoreDevice *device = (MobiCoreDevice *) (connection->connectionData); 415 CHECK_DEVICE(device, connection); 416 417 // Get service blob from registry 418 regObject_t *regObj = mcRegistryGetServiceBlob(&(cmdOpenSession.uuid)); 419 if (NULL == regObj) { 420 writeResult(connection, MC_DRV_ERR_TRUSTLET_NOT_FOUND); 421 return; 422 } 423 if (regObj->len == 0) { 424 free(regObj); 425 writeResult(connection, MC_DRV_ERR_TRUSTLET_NOT_FOUND); 426 return; 427 } 428 LOG_I(" Sharing Service loaded at %p with Secure World", (addr_t)(regObj->value)); 429 430 CWsm_ptr pWsm = device->registerWsmL2((addr_t)(regObj->value), regObj->len, 0); 431 if (pWsm == NULL) { 432 LOG_E("allocating WSM for Trustlet failed"); 433 writeResult(connection, MC_DRV_ERR_DAEMON_KMOD_ERROR); 434 return; 435 } 436 // Initialize information data of open session command 437 loadDataOpenSession_t loadDataOpenSession; 438 loadDataOpenSession.baseAddr = pWsm->physAddr; 439 loadDataOpenSession.offs = ((uint32_t) regObj->value) & 0xFFF; 440 loadDataOpenSession.len = regObj->len; 441 loadDataOpenSession.tlHeader = (mclfHeader_ptr) regObj->value; 442 443 mcDrvRspOpenSession_t rspOpenSession; 444 mcResult_t ret = device->openSession( 445 connection, 446 &loadDataOpenSession, 447 &cmdOpenSession, 448 &(rspOpenSession.payload)); 449 450 // Unregister physical memory from kernel module. 451 LOG_I(" Service buffer was copied to Secure world and processed. Stop sharing of buffer."); 452 453 // This will also destroy the WSM object. 454 if (!device->unregisterWsmL2(pWsm)) { 455 // TODO-2012-07-02-haenellu: Can this ever happen? And if so, we should assert(), also TL might still be running. 456 writeResult(connection, MC_DRV_ERR_DAEMON_KMOD_ERROR); 457 return; 458 } 459 460 // Free memory occupied by Trustlet data 461 free(regObj); 462 463 if (ret != MC_DRV_OK) { 464 LOG_E("Service could not be loaded."); 465 writeResult(connection, ret); 466 } else { 467 rspOpenSession.header.responseId = ret; 468 connection->writeData( 469 &rspOpenSession, 470 sizeof(rspOpenSession)); 471 } 472 } 473 474 475 //------------------------------------------------------------------------------ 476 void MobiCoreDriverDaemon::processCloseSession(Connection *connection) 477 { 478 MC_DRV_CMD_CLOSE_SESSION_struct cmdCloseSession; 479 RECV_PAYLOAD_FROM_CLIENT(connection, &cmdCloseSession) 480 481 // Device required 482 MobiCoreDevice *device = (MobiCoreDevice *) (connection->connectionData); 483 CHECK_DEVICE(device, connection); 484 485 mcResult_t ret = device->closeSession(connection, cmdCloseSession.sessionId); 486 487 // there is no payload 488 writeResult(connection, ret); 489 } 490 491 492 //------------------------------------------------------------------------------ 493 void MobiCoreDriverDaemon::processNqConnect(Connection *connection) 494 { 495 // Set up the channel for sending SWd notifications to the client 496 // MC_DRV_CMD_NQ_CONNECT is only allowed on new connections not 497 // associated with a device. If a device is registered to the 498 // connection NQ_CONNECT is not allowed. 499 500 // Read entire command data 501 MC_DRV_CMD_NQ_CONNECT_struct cmd; 502 RECV_PAYLOAD_FROM_CLIENT(connection, &cmd); 503 504 // device must be empty since this is a new connection 505 MobiCoreDevice *device = (MobiCoreDevice *)(connection->connectionData); 506 if (device != NULL) { 507 LOG_E("device already set\n"); 508 writeResult(connection, MC_DRV_ERR_NQ_FAILED); 509 return; 510 } 511 512 // Remove the connection from the list of known client connections 513 for (int i = 0; i < MAX_SERVERS; i++) { 514 servers[i]->detachConnection(connection); 515 } 516 517 device = getDevice(cmd.deviceId); 518 // Check if a device for the given name has been found 519 if (NULL == device) { 520 LOG_E("invalid deviceId"); 521 writeResult(connection, MC_DRV_ERR_UNKNOWN_DEVICE); 522 return; 523 } 524 525 TrustletSession *ts = device->registerTrustletConnection( 526 connection, 527 &cmd); 528 if (!ts) { 529 LOG_E("registerTrustletConnection() failed!"); 530 writeResult(connection, MC_DRV_ERR_UNKNOWN); 531 return; 532 } 533 534 writeResult(connection, MC_DRV_OK); 535 ts->processQueuedNotifications(); 536 } 537 538 539 //------------------------------------------------------------------------------ 540 void MobiCoreDriverDaemon::processNotify( 541 Connection *connection 542 ) 543 { 544 545 // Read entire command data 546 MC_DRV_CMD_NOTIFY_struct cmd; 547 //RECV_PAYLOAD_FROM_CLIENT(connection, &cmd); 548 void *payload = (void *)((uint32_t)&cmd + sizeof(mcDrvCommandHeader_t)); 549 uint32_t payload_len = sizeof(cmd) - sizeof(mcDrvCommandHeader_t); 550 uint32_t rlen = connection->readData(payload, payload_len); 551 if (rlen < 0) { 552 LOG_E("reading from Client failed"); 553 /* it is questionable, if writing to broken socket has any effect here. */ 554 // NOTE: notify fails silently 555 //writeResult(connection, MC_DRV_RSP_SOCKET_ERROR); 556 return; 557 } 558 if (rlen != payload_len) { 559 LOG_E("wrong buffer length %i received from Client", rlen); 560 // NOTE: notify fails silently 561 //writeResult(connection, MC_DRV_RSP_PAYLOAD_LENGTH_ERROR); 562 return; 563 } 564 565 // Device required 566 MobiCoreDevice *device = (MobiCoreDevice *) (connection->connectionData); 567 if (NULL == device) { 568 LOG_V("%s: no device associated with connection", __FUNCTION__); 569 // NOTE: notify fails silently 570 // writeResult(connection,MC_DRV_RSP_DEVICE_NOT_OPENED); 571 return; 572 } 573 574 // REV axh: we cannot trust the clientLib to give us a valid 575 // sessionId here. Thus we have to check that it belongs to 576 // the clientLib's process. 577 578 device->notify(cmd.sessionId); 579 // NOTE: for notifications there is no response at all 580 } 581 582 583 //------------------------------------------------------------------------------ 584 void MobiCoreDriverDaemon::processMapBulkBuf(Connection *connection) 585 { 586 MC_DRV_CMD_MAP_BULK_BUF_struct cmd; 587 588 RECV_PAYLOAD_FROM_CLIENT(connection, &cmd); 589 590 // Device required 591 MobiCoreDevice *device = (MobiCoreDevice *) (connection->connectionData); 592 CHECK_DEVICE(device, connection); 593 594 if (!device->lockWsmL2(cmd.handle)) { 595 LOG_E("Couldn't lock the buffer!"); 596 writeResult(connection, MC_DRV_ERR_DAEMON_WSM_HANDLE_NOT_FOUND); 597 return; 598 } 599 600 uint32_t secureVirtualAdr = NULL; 601 uint32_t pAddrL2 = (uint32_t)device->findWsmL2(cmd.handle); 602 603 if (pAddrL2 == 0) { 604 LOG_E("Failed to resolve WSM with handle %u", cmd.handle); 605 writeResult(connection, MC_DRV_ERR_DAEMON_WSM_HANDLE_NOT_FOUND); 606 return; 607 } 608 609 // Map bulk memory to secure world 610 mcResult_t mcResult = device->mapBulk(cmd.sessionId, cmd.handle, pAddrL2, 611 cmd.offsetPayload, cmd.lenBulkMem, &secureVirtualAdr); 612 613 if (mcResult != MC_DRV_OK) { 614 writeResult(connection, mcResult); 615 return; 616 } 617 618 mcDrvRspMapBulkMem_t rsp; 619 rsp.header.responseId = MC_DRV_OK; 620 rsp.payload.sessionId = cmd.sessionId; 621 rsp.payload.secureVirtualAdr = secureVirtualAdr; 622 connection->writeData(&rsp, sizeof(mcDrvRspMapBulkMem_t)); 623 } 624 625 626 //------------------------------------------------------------------------------ 627 void MobiCoreDriverDaemon::processUnmapBulkBuf(Connection *connection) 628 { 629 MC_DRV_CMD_UNMAP_BULK_BUF_struct cmd; 630 RECV_PAYLOAD_FROM_CLIENT(connection, &cmd) 631 632 // Device required 633 MobiCoreDevice *device = (MobiCoreDevice *) (connection->connectionData); 634 CHECK_DEVICE(device, connection); 635 636 // Unmap bulk memory from secure world 637 uint32_t mcResult = device->unmapBulk(cmd.sessionId, cmd.handle, cmd.secureVirtualAdr, cmd.lenBulkMem); 638 639 if (mcResult != MC_DRV_OK) { 640 LOG_V("MCP UNMAP returned code %d", mcResult); 641 writeResult(connection, mcResult); 642 return; 643 } 644 645 // TODO-2012-09-06-haenellu: Think about not ignoring the error case. 646 device->unlockWsmL2(cmd.handle); 647 648 writeResult(connection, MC_DRV_OK); 649 } 650 651 652 //------------------------------------------------------------------------------ 653 void MobiCoreDriverDaemon::processGetVersion( 654 Connection *connection 655 ) 656 { 657 // there is no payload to read 658 659 mcDrvRspGetVersion_t rspGetVersion; 660 rspGetVersion.version = MC_MAKE_VERSION(DAEMON_VERSION_MAJOR, DAEMON_VERSION_MINOR); 661 rspGetVersion.responseId = MC_DRV_OK; 662 663 connection->writeData(&rspGetVersion, sizeof(mcDrvRspGetVersion_t)); 664 } 665 666 //------------------------------------------------------------------------------ 667 void MobiCoreDriverDaemon::processGetMobiCoreVersion( 668 Connection *connection 669 ) 670 { 671 // there is no payload to read 672 673 // Device required 674 MobiCoreDevice *device = (MobiCoreDevice *) (connection->connectionData); 675 CHECK_DEVICE(device, connection); 676 677 // Get MobiCore version info from secure world. 678 mcDrvRspGetMobiCoreVersion_t rspGetMobiCoreVersion; 679 680 mcResult_t mcResult = device->getMobiCoreVersion(&rspGetMobiCoreVersion.payload); 681 682 if (mcResult != MC_DRV_OK) { 683 LOG_V("MC GET_MOBICORE_VERSION returned code %d", mcResult); 684 writeResult(connection, mcResult); 685 return; 686 } 687 688 rspGetMobiCoreVersion.header.responseId = MC_DRV_OK; 689 connection->writeData( 690 &rspGetMobiCoreVersion, 691 sizeof(rspGetMobiCoreVersion)); 692 } 693 694 695 //------------------------------------------------------------------------------ 696 bool MobiCoreDriverDaemon::handleConnection( 697 Connection *connection 698 ) 699 { 700 bool ret = false; 701 static CMutex mutex; 702 703 /* In case of RTM fault do not try to signal anything to MobiCore 704 * just answer NO to all incoming connections! */ 705 if (mobiCoreDevice->getMcFault()) { 706 return false; 707 } 708 709 mutex.lock(); 710 LOG_I("handleConnection()==== %p", connection); 711 do { 712 // Read header 713 mcDrvCommandHeader_t mcDrvCommandHeader; 714 ssize_t rlen = connection->readData( 715 &(mcDrvCommandHeader), 716 sizeof(mcDrvCommandHeader)); 717 718 if (rlen == 0) { 719 LOG_V(" handleConnection(): Connection closed."); 720 break; 721 } 722 if (rlen == -1) { 723 LOG_E("Socket error."); 724 break; 725 } 726 if (rlen == -2) { 727 LOG_E("Timeout."); 728 break; 729 } 730 if (rlen != sizeof(mcDrvCommandHeader)) { 731 LOG_E("Header length %i is not right.", (int)rlen); 732 break; 733 } 734 ret = true; 735 736 switch (mcDrvCommandHeader.commandId) { 737 //----------------------------------------- 738 case MC_DRV_CMD_OPEN_DEVICE: 739 processOpenDevice(connection); 740 break; 741 //----------------------------------------- 742 case MC_DRV_CMD_CLOSE_DEVICE: 743 processCloseDevice(connection); 744 break; 745 //----------------------------------------- 746 case MC_DRV_CMD_OPEN_SESSION: 747 processOpenSession(connection); 748 break; 749 //----------------------------------------- 750 case MC_DRV_CMD_CLOSE_SESSION: 751 processCloseSession(connection); 752 break; 753 //----------------------------------------- 754 case MC_DRV_CMD_NQ_CONNECT: 755 processNqConnect(connection); 756 break; 757 //----------------------------------------- 758 case MC_DRV_CMD_NOTIFY: 759 processNotify(connection); 760 break; 761 //----------------------------------------- 762 case MC_DRV_CMD_MAP_BULK_BUF: 763 processMapBulkBuf(connection); 764 break; 765 //----------------------------------------- 766 case MC_DRV_CMD_UNMAP_BULK_BUF: 767 processUnmapBulkBuf(connection); 768 break; 769 //----------------------------------------- 770 case MC_DRV_CMD_GET_VERSION: 771 processGetVersion(connection); 772 break; 773 //----------------------------------------- 774 case MC_DRV_CMD_GET_MOBICORE_VERSION: 775 processGetMobiCoreVersion(connection); 776 break; 777 //----------------------------------------- 778 779 default: 780 LOG_E("Unknown command: %d=0x%x", 781 mcDrvCommandHeader.commandId, 782 mcDrvCommandHeader.commandId); 783 ret = false; 784 break; 785 } 786 } while (0); 787 mutex.unlock(); 788 LOG_I("handleConnection()<-------"); 789 790 return ret; 791 } 792 793 //------------------------------------------------------------------------------ 794 /** 795 * Print daemon command line options 796 */ 797 798 void printUsage( 799 int argc, 800 char *args[] 801 ) 802 { 803 fprintf(stderr, "usage: %s [-mdsbh]\n", args[0]); 804 fprintf(stderr, "Start MobiCore Daemon\n\n"); 805 fprintf(stderr, "-h\t\tshow this help\n"); 806 fprintf(stderr, "-b\t\tfork to background\n"); 807 fprintf(stderr, "-m IMAGE\tload mobicore from IMAGE to DDR\n"); 808 fprintf(stderr, "-s\t\tdisable daemon scheduler(default enabled)\n"); 809 fprintf(stderr, "-d SIZE\t\tdonate SIZE bytes to mobicore(disabled on most platforms)\n"); 810 fprintf(stderr, "-r DRIVER\t\tMobiCore driver to load at start-up\n"); 811 } 812 813 //------------------------------------------------------------------------------ 814 /** 815 * Signal handler for daemon termination 816 * Using this handler instead of the standard libc one ensures the daemon 817 * can cleanup everything -> read() on a FD will now return EINTR 818 */ 819 void terminateDaemon( 820 int signum 821 ) 822 { 823 LOG_E("Signal %d received\n", signum); 824 } 825 826 //------------------------------------------------------------------------------ 827 /** 828 * Main entry of the MobiCore Driver Daemon. 829 */ 830 int main( 831 int argc, 832 char *args[] 833 ) 834 { 835 // Create the MobiCore Driver Singleton 836 MobiCoreDriverDaemon *mobiCoreDriverDaemon = NULL; 837 // Process signal action 838 struct sigaction action; 839 840 // Read the Command line options 841 extern char *optarg; 842 extern int optopt; 843 int c, errFlag = 0; 844 // Scheduler enabled by default 845 int schedulerFlag = 1; 846 // Mobicore loading disable by default 847 int mobicoreFlag = 0; 848 // Autoload driver at start-up 849 int driverLoadFlag = 0; 850 std::string mobicoreImage, driverPath; 851 // Ram donation disabled by default 852 int donationSize = 0; 853 // By default don't fork 854 bool forkDaemon = false; 855 while ((c = getopt(argc, args, "m:d:r:sbh")) != -1) { 856 switch (c) { 857 case 'h': /* Help */ 858 errFlag++; 859 break; 860 case 's': /* Disable Scheduler */ 861 schedulerFlag = 0; 862 break; 863 case 'd': /* Ram Donation size */ 864 donationSize = atoi(optarg); 865 break; 866 case 'm': /* Load mobicore image */ 867 mobicoreFlag = 1; 868 mobicoreImage = optarg; 869 break; 870 case 'b': /* Fork to background */ 871 forkDaemon = true; 872 break; 873 case 'r': /* Load mobicore driver at start-up */ 874 driverLoadFlag = 1; 875 driverPath = optarg; 876 break; 877 case ':': /* -d or -m without operand */ 878 fprintf(stderr, "Option -%c requires an operand\n", optopt); 879 errFlag++; 880 break; 881 case '?': 882 fprintf(stderr, 883 "Unrecognized option: -%c\n", optopt); 884 errFlag++; 885 } 886 } 887 if (errFlag) { 888 printUsage(argc, args); 889 exit(2); 890 } 891 892 // We should fork the daemon to background 893 if (forkDaemon == true) { 894 int i = fork(); 895 if (i < 0) { 896 exit(1); 897 } 898 // Parent 899 else if (i > 0) { 900 exit(0); 901 } 902 903 // obtain a new process group */ 904 setsid(); 905 /* close all descriptors */ 906 for (i = getdtablesize(); i >= 0; --i) { 907 close(i); 908 } 909 // STDIN, STDOUT and STDERR should all point to /dev/null */ 910 i = open("/dev/null", O_RDWR); 911 dup(i); 912 dup(i); 913 /* ignore tty signals */ 914 signal(SIGTSTP, SIG_IGN); 915 signal(SIGTTOU, SIG_IGN); 916 signal(SIGTTIN, SIG_IGN); 917 } 918 919 // Set up the structure to specify the new action. 920 action.sa_handler = terminateDaemon; 921 sigemptyset (&action.sa_mask); 922 action.sa_flags = 0; 923 sigaction (SIGINT, &action, NULL); 924 sigaction (SIGHUP, &action, NULL); 925 sigaction (SIGTERM, &action, NULL); 926 signal(SIGPIPE, SIG_IGN); 927 928 mobiCoreDriverDaemon = new MobiCoreDriverDaemon( 929 /* Scheduler status */ 930 schedulerFlag, 931 /* Mobicore loading to DDR */ 932 mobicoreFlag, 933 mobicoreImage, 934 /* Ram Donation */ 935 donationSize, 936 /* Auto Driver loading */ 937 driverLoadFlag, 938 driverPath); 939 940 // Start the driver 941 mobiCoreDriverDaemon->run(); 942 943 delete mobiCoreDriverDaemon; 944 945 // This should not happen 946 LOG_E("Exiting MobiCoreDaemon"); 947 948 return EXIT_FAILURE; 949 } 950 951 //------------------------------------------------------------------------------ 952 static void checkMobiCoreVersion( 953 MobiCoreDevice *mobiCoreDevice 954 ) 955 { 956 bool failed = false; 957 958 // Get MobiCore version info. 959 mcDrvRspGetMobiCoreVersionPayload_t versionPayload; 960 mcResult_t mcResult = mobiCoreDevice->getMobiCoreVersion(&versionPayload); 961 962 if (mcResult != MC_DRV_OK) { 963 LOG_E("Failed to obtain MobiCore version info. MCP return code: %u", mcResult); 964 failed = true; 965 } else { 966 LOG_I("Product ID is %s", versionPayload.versionInfo.productId); 967 968 // Check MobiCore version info. 969 char *msg; 970 if (!checkVersionOkMCI(versionPayload.versionInfo.versionMci, &msg)) { 971 LOG_E("%s", msg); 972 failed = true; 973 } 974 LOG_I("%s", msg); 975 if (!checkVersionOkSO(versionPayload.versionInfo.versionSo, &msg)) { 976 LOG_E("%s", msg); 977 failed = true; 978 } 979 LOG_I("%s", msg); 980 if (!checkVersionOkMCLF(versionPayload.versionInfo.versionMclf, &msg)) { 981 LOG_E("%s", msg); 982 failed = true; 983 } 984 LOG_I("%s", msg); 985 if (!checkVersionOkCONTAINER(versionPayload.versionInfo.versionContainer, &msg)) { 986 LOG_E("%s", msg); 987 failed = true; 988 } 989 LOG_I("%s", msg); 990 } 991 992 if (failed) { 993 exit(1); 994 } 995 } 996 997 /** @} */ 998