Home | History | Annotate | Download | only in Device
      1 /** @addtogroup MCD_MCDIMPL_DAEMON_DEV
      2  * @{
      3  * @file
      4  *
      5  *
      6  * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. The name of the author may not be used to endorse or promote
     17  *    products derived from this software without specific prior
     18  *    written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     21  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     22  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     24  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     26  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #include <cstdlib>
     34 #include <pthread.h>
     35 #include "McTypes.h"
     36 
     37 #include "DeviceScheduler.h"
     38 #include "DeviceIrqHandler.h"
     39 #include "ExcDevice.h"
     40 #include "Connection.h"
     41 #include "TrustletSession.h"
     42 
     43 #include "MobiCoreDevice.h"
     44 #include "Mci/mci.h"
     45 #include "mcLoadFormat.h"
     46 
     47 
     48 #include "log.h"
     49 #include "public/MobiCoreDevice.h"
     50 
     51 
     52 //------------------------------------------------------------------------------
     53 MobiCoreDevice::MobiCoreDevice()
     54 {
     55     mcFault = false;
     56 }
     57 
     58 //------------------------------------------------------------------------------
     59 MobiCoreDevice::~MobiCoreDevice()
     60 {
     61     delete mcVersionInfo;
     62     mcVersionInfo = NULL;
     63 }
     64 
     65 //------------------------------------------------------------------------------
     66 TrustletSession *MobiCoreDevice::getTrustletSession(uint32_t sessionId)
     67 {
     68     for (trustletSessionIterator_t session = trustletSessions.begin();
     69             session != trustletSessions.end();
     70             ++session) {
     71         TrustletSession *tsTmp = *session;
     72         if (tsTmp->sessionId == sessionId) {
     73             return tsTmp;
     74         }
     75     }
     76     return NULL;
     77 }
     78 
     79 
     80 void MobiCoreDevice::cleanSessionBuffers(TrustletSession *session)
     81 {
     82     CWsm_ptr pWsm = session->popBulkBuff();
     83 
     84     while (pWsm) {
     85         unlockWsmL2(pWsm->handle);
     86         pWsm = session->popBulkBuff();
     87     }
     88 }
     89 //------------------------------------------------------------------------------
     90 void MobiCoreDevice::removeTrustletSession(uint32_t sessionId)
     91 {
     92     for (trustletSessionIterator_t session = trustletSessions.begin();
     93             session != trustletSessions.end();
     94             ++session) {
     95         if ((*session)->sessionId == sessionId) {
     96             cleanSessionBuffers(*session);
     97             trustletSessions.erase(session);
     98             return;
     99         }
    100     }
    101 }
    102 //------------------------------------------------------------------------------
    103 Connection *MobiCoreDevice::getSessionConnection(uint32_t sessionId, notification_t *notification)
    104 {
    105     Connection *con = NULL;
    106     TrustletSession *ts = NULL;
    107 
    108     ts = getTrustletSession(sessionId);
    109     if (ts == NULL) {
    110         return NULL;
    111     }
    112 
    113     con = ts->notificationConnection;
    114     if (con == NULL) {
    115         ts->queueNotification(notification);
    116         return NULL;
    117     }
    118 
    119     return con;
    120 }
    121 
    122 
    123 //------------------------------------------------------------------------------
    124 bool MobiCoreDevice::open(Connection *connection)
    125 {
    126     // Link this device to the connection
    127     connection->connectionData = this;
    128     return true;
    129 }
    130 
    131 
    132 //------------------------------------------------------------------------------
    133 /**
    134  * Close device.
    135  *
    136  * Removes all sessions to a connection. Though, clientLib rejects the closeDevice()
    137  * command if still sessions connected to the device, this is needed to clean up all
    138  * sessions if client dies.
    139  */
    140 void MobiCoreDevice::close(Connection *connection)
    141 {
    142     trustletSessionList_t::reverse_iterator interator;
    143     static CMutex mutex;
    144     // 1. Iterate through device session to find connection
    145     // 2. Decide what to do with open Trustlet sessions
    146     // 3. Remove & delete deviceSession from vector
    147 
    148     // Enter critical section
    149     mutex.lock();
    150     for (interator = trustletSessions.rbegin();
    151             interator != trustletSessions.rend();
    152             interator++) {
    153         TrustletSession *ts = *interator;
    154 
    155         if (ts->deviceConnection == connection) {
    156             closeSession(connection, ts->sessionId);
    157         }
    158     }
    159     // Leave critical section
    160     mutex.unlock();
    161 
    162     // After the trustlet is done make sure to tell the driver to cleanup
    163     // all the orphaned drivers
    164     cleanupWsmL2();
    165 
    166     connection->connectionData = NULL;
    167 }
    168 
    169 
    170 //------------------------------------------------------------------------------
    171 void MobiCoreDevice::start(void)
    172 {
    173     // Call the device specific initialization
    174     //  initDevice();
    175 
    176     LOG_I("Starting DeviceIrqHandler...");
    177     // Start the irq handling thread
    178     DeviceIrqHandler::start();
    179 
    180     if (schedulerAvailable()) {
    181         LOG_I("Starting DeviceScheduler...");
    182         // Start the scheduling handling thread
    183         DeviceScheduler::start();
    184     } else {
    185         LOG_I("No DeviceScheduler available.");
    186     }
    187 }
    188 
    189 
    190 //------------------------------------------------------------------------------
    191 void MobiCoreDevice::signalMcpNotification(void)
    192 {
    193     mcpSessionNotification.signal();
    194 }
    195 
    196 
    197 //------------------------------------------------------------------------------
    198 bool MobiCoreDevice::waitMcpNotification(void)
    199 {
    200     int counter = 5;
    201     while (1) {
    202         // In case of fault just return, nothing to do here
    203         if (mcFault) {
    204             return false;
    205         }
    206         // Wait 10 seconds for notification
    207         if (mcpSessionNotification.wait(10) == false) {
    208             // No MCP answer received and mobicore halted, dump mobicore status
    209             // then throw exception
    210             LOG_I("No MCP answer received in 2 seconds.");
    211             if (getMobicoreStatus() == MC_STATUS_HALT) {
    212                 dumpMobicoreStatus();
    213                 mcFault = true;
    214                 return false;
    215             } else {
    216                 counter--;
    217                 if (counter < 1) {
    218                     mcFault = true;
    219                     return false;
    220                 }
    221             }
    222         } else {
    223             break;
    224         }
    225     }
    226 
    227     // Check healthiness state of the device
    228     if (DeviceIrqHandler::isExiting()) {
    229         LOG_I("waitMcpNotification(): IrqHandler thread died! Joining");
    230         DeviceIrqHandler::join();
    231         LOG_I("waitMcpNotification(): Joined");
    232         LOG_E("IrqHandler thread died!");
    233         return false;
    234     }
    235 
    236     if (DeviceScheduler::isExiting()) {
    237         LOG_I("waitMcpNotification(): Scheduler thread died! Joining");
    238         DeviceScheduler::join();
    239         LOG_I("waitMcpNotification(): Joined");
    240         LOG_E("Scheduler thread died!");
    241         return false;
    242     }
    243     return true;
    244 }
    245 
    246 
    247 //------------------------------------------------------------------------------
    248 mcResult_t MobiCoreDevice::openSession(
    249     Connection                      *deviceConnection,
    250     loadDataOpenSession_ptr         pLoadDataOpenSession,
    251     MC_DRV_CMD_OPEN_SESSION_struct  *cmdOpenSession,
    252     mcDrvRspOpenSessionPayload_ptr  pRspOpenSessionPayload
    253 )
    254 {
    255     do {
    256         addr_t tci;
    257         uint32_t len;
    258         uint32_t handle = cmdOpenSession->handle;
    259 
    260         if (!findContiguousWsm(handle, &tci, &len)) {
    261             LOG_E("Failed to find contiguous WSM %u", handle);
    262             return MC_DRV_ERR_DAEMON_WSM_HANDLE_NOT_FOUND;
    263         }
    264 
    265         if (!lockWsmL2(handle)) {
    266             LOG_E("Failed to lock contiguous WSM %u", handle);
    267             return MC_DRV_ERR_DAEMON_WSM_HANDLE_NOT_FOUND;
    268         }
    269 
    270         // Write MCP open message to buffer
    271         mcpMessage->cmdOpen.cmdHeader.cmdId = MC_MCP_CMD_OPEN_SESSION;
    272         mcpMessage->cmdOpen.uuid = cmdOpenSession->uuid;
    273         mcpMessage->cmdOpen.wsmTypeTci = WSM_CONTIGUOUS;
    274         mcpMessage->cmdOpen.adrTciBuffer = (uint32_t)(tci);
    275         mcpMessage->cmdOpen.ofsTciBuffer = 0;
    276         mcpMessage->cmdOpen.lenTciBuffer = len;
    277 
    278         LOG_I(" Using phys=%p, len=%d as TCI buffer",
    279               (addr_t)(cmdOpenSession->tci),
    280               cmdOpenSession->len);
    281 
    282         // check if load data is provided
    283         mcpMessage->cmdOpen.wsmTypeLoadData = WSM_L2;
    284         mcpMessage->cmdOpen.adrLoadData = (uint32_t)pLoadDataOpenSession->baseAddr;
    285         mcpMessage->cmdOpen.ofsLoadData = pLoadDataOpenSession->offs;
    286         mcpMessage->cmdOpen.lenLoadData = pLoadDataOpenSession->len;
    287         memcpy(&mcpMessage->cmdOpen.tlHeader, pLoadDataOpenSession->tlHeader, sizeof(*pLoadDataOpenSession->tlHeader));
    288 
    289         // Clear the notifications queue. We asume the race condition we have
    290         // seen in openSession never happens elsewhere
    291         notifications = std::queue<notification_t>();
    292         // Notify MC about a new command inside the MCP buffer
    293         notify(SID_MCP);
    294 
    295         // Wait till response from MC is available
    296         if (!waitMcpNotification()) {
    297             // Here Mobicore can be considered dead.
    298             unlockWsmL2(handle);
    299             return MC_DRV_ERR_DAEMON_MCI_ERROR;
    300         }
    301 
    302         // Check if the command response ID is correct
    303         if ((MC_MCP_CMD_OPEN_SESSION | FLAG_RESPONSE) != mcpMessage->rspHeader.rspId) {
    304             LOG_E("CMD_OPEN_SESSION got invalid MCP command response(0x%X)", mcpMessage->rspHeader.rspId);
    305             // Something is messing with our MCI memory, we cannot know if the Trustlet was loaded.
    306             // Had in been loaded, we are loosing track of it here.
    307             unlockWsmL2(handle);
    308             return MC_DRV_ERR_DAEMON_MCI_ERROR;
    309         }
    310 
    311         uint32_t mcRet = mcpMessage->rspOpen.rspHeader.result;
    312 
    313         if (mcRet != MC_MCP_RET_OK) {
    314             LOG_E("MCP OPEN returned code %d.", mcRet);
    315             unlockWsmL2(handle);
    316             return MAKE_MC_DRV_MCP_ERROR(mcRet);
    317         }
    318 
    319         LOG_I(" After MCP OPEN, we have %d queued notifications",
    320               notifications.size());
    321         // Read MC answer from MCP buffer
    322         TrustletSession *trustletSession = new TrustletSession(
    323             deviceConnection,
    324             mcpMessage->rspOpen.sessionId);
    325 
    326         pRspOpenSessionPayload->sessionId = trustletSession->sessionId;
    327         pRspOpenSessionPayload->deviceSessionId = (uint32_t)trustletSession;
    328         pRspOpenSessionPayload->sessionMagic = trustletSession->sessionMagic;
    329 
    330         trustletSessions.push_back(trustletSession);
    331 
    332         trustletSession->addBulkBuff(new CWsm((void *)pLoadDataOpenSession->offs, pLoadDataOpenSession->len, handle, 0));
    333 
    334         // We have some queued notifications and we need to send them to them
    335         // trustlet session
    336         while (!notifications.empty()) {
    337             trustletSession->queueNotification(&notifications.front());
    338             notifications.pop();
    339         }
    340 
    341     } while (0);
    342     return MC_DRV_OK;
    343 }
    344 
    345 
    346 //------------------------------------------------------------------------------
    347 TrustletSession *MobiCoreDevice::registerTrustletConnection(
    348     Connection                    *connection,
    349     MC_DRV_CMD_NQ_CONNECT_struct *cmdNqConnect
    350 )
    351 {
    352     LOG_I(" Registering notification socket with Service session %d.",
    353           cmdNqConnect->sessionId);
    354     LOG_V("  Searching sessionId %d with sessionMagic %d",
    355           cmdNqConnect->sessionId,
    356           cmdNqConnect->sessionMagic);
    357 
    358     for (trustletSessionIterator_t iterator = trustletSessions.begin();
    359             iterator != trustletSessions.end();
    360             ++iterator) {
    361         TrustletSession *ts = *iterator;
    362 
    363         if (ts != (TrustletSession *) (cmdNqConnect->deviceSessionId)) {
    364             continue;
    365         }
    366 
    367         if ( (ts->sessionMagic != cmdNqConnect->sessionMagic)
    368                 || (ts->sessionId != cmdNqConnect->sessionId)) {
    369             continue;
    370         }
    371 
    372         ts->notificationConnection = connection;
    373 
    374         LOG_I(" Found Service session, registered connection.");
    375 
    376         return ts;
    377     }
    378 
    379     LOG_I("registerTrustletConnection(): search failed");
    380     return NULL;
    381 }
    382 
    383 
    384 //------------------------------------------------------------------------------
    385 mcResult_t MobiCoreDevice::closeSession(uint32_t sessionId)
    386 {
    387     LOG_I(" Write MCP CLOSE message to MCI, notify and wait");
    388 
    389     // Write MCP close message to buffer
    390     mcpMessage->cmdClose.cmdHeader.cmdId = MC_MCP_CMD_CLOSE_SESSION;
    391     mcpMessage->cmdClose.sessionId = sessionId;
    392 
    393     // Notify MC about the availability of a new command inside the MCP buffer
    394     notify(SID_MCP);
    395 
    396     // Wait till response from MSH is available
    397     if (!waitMcpNotification()) {
    398         return MC_DRV_ERR_DAEMON_MCI_ERROR;
    399     }
    400 
    401     // Check if the command response ID is correct
    402     if ((MC_MCP_CMD_CLOSE_SESSION | FLAG_RESPONSE) != mcpMessage->rspHeader.rspId) {
    403         LOG_E("CMD_CLOSE_SESSION got invalid MCP response");
    404         return MC_DRV_ERR_DAEMON_MCI_ERROR;
    405     }
    406 
    407     // Read MC answer from MCP buffer
    408     uint32_t mcRet = mcpMessage->rspOpen.rspHeader.result;
    409 
    410     if (mcRet != MC_MCP_RET_OK) {
    411         LOG_E("CMD_CLOSE_SESSION error %d", mcRet);
    412         return MAKE_MC_DRV_MCP_ERROR(mcRet);
    413     }
    414 
    415     return MC_DRV_OK;
    416 }
    417 
    418 //------------------------------------------------------------------------------
    419 /**
    420  * TODO-2012-09-19-haenellu: Do some more checks here, otherwise rogue clientLib
    421  * can close sessions from different TLCs. That is, deviceConnection is ignored below.
    422  *
    423  * Need connection as well as according session ID, so that a client can not
    424  * close sessions not belonging to him.
    425  */
    426 mcResult_t MobiCoreDevice::closeSession(Connection *deviceConnection, uint32_t sessionId)
    427 {
    428     TrustletSession *ts = getTrustletSession(sessionId);
    429     if (ts == NULL) {
    430         LOG_E("no session found with id=%d", sessionId);
    431         return MC_DRV_ERR_DAEMON_UNKNOWN_SESSION;
    432     }
    433 
    434     uint32_t mcRet = closeSession(sessionId);
    435     if (mcRet != MC_DRV_OK) {
    436         return mcRet;
    437     }
    438 
    439     // remove objects
    440     removeTrustletSession(sessionId);
    441     delete ts;
    442 
    443     return MC_DRV_OK;
    444 }
    445 
    446 
    447 //------------------------------------------------------------------------------
    448 mcResult_t MobiCoreDevice::mapBulk(uint32_t sessionId, uint32_t handle, uint32_t pAddrL2,
    449                                    uint32_t offsetPayload, uint32_t lenBulkMem, uint32_t *secureVirtualAdr)
    450 {
    451     TrustletSession *ts = getTrustletSession(sessionId);
    452     if (ts == NULL) {
    453         LOG_E("no session found with id=%d", sessionId);
    454         return MC_DRV_ERR_DAEMON_UNKNOWN_SESSION;
    455     }
    456 
    457     // TODO-2012-09-06-haenellu: Think about not ignoring the error case, ClientLib does not allow this.
    458     ts->addBulkBuff(new CWsm((void *)offsetPayload, lenBulkMem, handle, (void *)pAddrL2));
    459     // Write MCP map message to buffer
    460     mcpMessage->cmdMap.cmdHeader.cmdId = MC_MCP_CMD_MAP;
    461     mcpMessage->cmdMap.sessionId = sessionId;
    462     mcpMessage->cmdMap.wsmType = WSM_L2;
    463     mcpMessage->cmdMap.adrBuffer = (uint32_t)(pAddrL2);
    464     mcpMessage->cmdMap.ofsBuffer = offsetPayload;
    465     mcpMessage->cmdMap.lenBuffer = lenBulkMem;
    466 
    467     // Notify MC about the availability of a new command inside the MCP buffer
    468     notify(SID_MCP);
    469 
    470     // Wait till response from MC is available
    471     if (!waitMcpNotification()) {
    472         return MC_DRV_ERR_DAEMON_MCI_ERROR;
    473     }
    474 
    475     // Check if the command response ID is correct
    476     if (mcpMessage->rspHeader.rspId != (MC_MCP_CMD_MAP | FLAG_RESPONSE)) {
    477         LOG_E("CMD_MAP got invalid MCP response");
    478         return MC_DRV_ERR_DAEMON_MCI_ERROR;
    479     }
    480 
    481     uint32_t mcRet = mcpMessage->rspMap.rspHeader.result;
    482 
    483     if (mcRet != MC_MCP_RET_OK) {
    484         LOG_E("MCP MAP returned code %d.", mcRet);
    485         return MAKE_MC_DRV_MCP_ERROR(mcRet);
    486     }
    487 
    488     *secureVirtualAdr = mcpMessage->rspMap.secureVirtualAdr;
    489     return MC_DRV_OK;
    490 }
    491 
    492 
    493 //------------------------------------------------------------------------------
    494 mcResult_t MobiCoreDevice::unmapBulk(uint32_t sessionId, uint32_t handle,
    495                                      uint32_t secureVirtualAdr, uint32_t lenBulkMem)
    496 {
    497     TrustletSession *ts = getTrustletSession(sessionId);
    498     if (ts == NULL) {
    499         LOG_E("no session found with id=%d", sessionId);
    500         return MC_DRV_ERR_DAEMON_UNKNOWN_SESSION;
    501     }
    502 
    503     // Write MCP unmap command to buffer
    504     mcpMessage->cmdUnmap.cmdHeader.cmdId = MC_MCP_CMD_UNMAP;
    505     mcpMessage->cmdUnmap.sessionId = sessionId;
    506     mcpMessage->cmdUnmap.wsmType = WSM_L2;
    507     mcpMessage->cmdUnmap.secureVirtualAdr = secureVirtualAdr;
    508     mcpMessage->cmdUnmap.lenVirtualBuffer = lenBulkMem;
    509 
    510     // Notify MC about the availability of a new command inside the MCP buffer
    511     notify(SID_MCP);
    512 
    513     // Wait till response from MC is available
    514     if (!waitMcpNotification()) {
    515         return MC_DRV_ERR_DAEMON_MCI_ERROR;
    516     }
    517 
    518     // Check if the command response ID is correct
    519     if (mcpMessage->rspHeader.rspId != (MC_MCP_CMD_UNMAP | FLAG_RESPONSE)) {
    520         LOG_E("CMD_OPEN_SESSION got invalid MCP response");
    521         return MC_DRV_ERR_DAEMON_MCI_ERROR;
    522     }
    523 
    524     uint32_t mcRet = mcpMessage->rspUnmap.rspHeader.result;
    525 
    526     if (mcRet != MC_MCP_RET_OK) {
    527         LOG_E("MCP UNMAP returned code %d.", mcRet);
    528         return MAKE_MC_DRV_MCP_ERROR(mcRet);
    529     } else {
    530         // Just remove the buffer
    531         // TODO-2012-09-06-haenellu: Haven't we removed it already?
    532         if (!ts->removeBulkBuff(handle))
    533             LOG_I("unmapBulk(): no buffer found found with handle=%u", handle);
    534     }
    535 
    536     return MC_DRV_OK;
    537 }
    538 
    539 
    540 //------------------------------------------------------------------------------
    541 void MobiCoreDevice::donateRam(const uint32_t donationSize)
    542 {
    543     // Donate additional RAM to the MobiCore
    544     CWsm_ptr ram = allocateContiguousPersistentWsm(donationSize);
    545     if (NULL == ram) {
    546         LOG_E("Allocation of additional RAM failed");
    547         return;
    548     }
    549     ramType_t ramType = RAM_GENERIC;
    550     addr_t adrBuffer = ram->physAddr;
    551     const uint32_t numPages = donationSize / (4 * 1024);
    552 
    553 
    554     LOG_I("donateRam(): adrBuffer=%p, numPages=%d, ramType=%d",
    555           adrBuffer,
    556           numPages,
    557           ramType);
    558 
    559     do {
    560         // Write MCP open message to buffer
    561         mcpMessage->cmdDonateRam.cmdHeader.cmdId = MC_MCP_CMD_DONATE_RAM;
    562         mcpMessage->cmdDonateRam.adrBuffer = (uint32_t) adrBuffer;
    563         mcpMessage->cmdDonateRam.numPages = numPages;
    564         mcpMessage->cmdDonateRam.ramType = ramType;
    565 
    566         // Notify MC about a new command inside the MCP buffer
    567         notify(SID_MCP);
    568 
    569         // Wait till response from MC is available
    570         if (!waitMcpNotification()) {
    571             break;
    572         }
    573 
    574         // Check if the command response ID is correct
    575         if ((MC_MCP_CMD_DONATE_RAM | FLAG_RESPONSE) != mcpMessage->rspHeader.rspId) {
    576             LOG_E("donateRam(): CMD_DONATE_RAM got invalid MCP response - rspId is: %d",
    577                   mcpMessage->rspHeader.rspId);
    578             break;
    579         }
    580 
    581         uint32_t mcRet = mcpMessage->rspDonateRam.rspHeader.result;
    582         if (MC_MCP_RET_OK != mcRet) {
    583             LOG_E("donateRam(): CMD_DONATE_RAM error %d", mcRet);
    584             break;
    585         }
    586 
    587         LOG_I("donateRam() succeeded.");
    588 
    589     } while (0);
    590 }
    591 
    592 //------------------------------------------------------------------------------
    593 mcResult_t MobiCoreDevice::getMobiCoreVersion(
    594     mcDrvRspGetMobiCoreVersionPayload_ptr pRspGetMobiCoreVersionPayload
    595 )
    596 {
    597     // If MobiCore version info already fetched.
    598     if (mcVersionInfo != NULL) {
    599         pRspGetMobiCoreVersionPayload->versionInfo = *mcVersionInfo;
    600         return MC_DRV_OK;
    601         // Otherwise, fetch it via MCP.
    602     } else {
    603         // Write MCP unmap command to buffer
    604         mcpMessage->cmdGetMobiCoreVersion.cmdHeader.cmdId = MC_MCP_CMD_GET_MOBICORE_VERSION;
    605 
    606         // Notify MC about the availability of a new command inside the MCP buffer
    607         notify(SID_MCP);
    608 
    609         // Wait till response from MC is available
    610         if (!waitMcpNotification()) {
    611             return MC_DRV_ERR_DAEMON_MCI_ERROR;
    612         }
    613 
    614         // Check if the command response ID is correct
    615         if ((MC_MCP_CMD_GET_MOBICORE_VERSION | FLAG_RESPONSE) != mcpMessage->rspHeader.rspId) {
    616             LOG_E("MC_MCP_CMD_GET_MOBICORE_VERSION got invalid MCP response");
    617             return MC_DRV_ERR_DAEMON_MCI_ERROR;
    618         }
    619 
    620         uint32_t  mcRet = mcpMessage->rspGetMobiCoreVersion.rspHeader.result;
    621 
    622         if (mcRet != MC_MCP_RET_OK) {
    623             LOG_E("MC_MCP_CMD_GET_MOBICORE_VERSION error %d", mcRet);
    624             return MAKE_MC_DRV_MCP_ERROR(mcRet);
    625         }
    626 
    627         pRspGetMobiCoreVersionPayload->versionInfo = mcpMessage->rspGetMobiCoreVersion.versionInfo;
    628 
    629         // Store MobiCore info for future reference.
    630         mcVersionInfo = new mcVersionInfo_t();
    631         *mcVersionInfo = pRspGetMobiCoreVersionPayload->versionInfo;
    632         return MC_DRV_OK;
    633     }
    634 }
    635 
    636 //------------------------------------------------------------------------------
    637 void MobiCoreDevice::queueUnknownNotification(
    638     notification_t notification
    639 )
    640 {
    641     notifications.push(notification);
    642 }
    643 
    644 /** @} */
    645