Home | History | Annotate | Download | only in Daemon
      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