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
57MC_CHECK_VERSION(MCI, 0, 2);
58MC_CHECK_VERSION(SO, 2, 0);
59MC_CHECK_VERSION(MCLF, 2, 0);
60MC_CHECK_VERSION(CONTAINER, 2, 0);
61
62static void checkMobiCoreVersion(MobiCoreDevice *mobiCoreDevice);
63
64//------------------------------------------------------------------------------
65MobiCoreDriverDaemon::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//------------------------------------------------------------------------------
89MobiCoreDriverDaemon::~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//------------------------------------------------------------------------------
109void 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//------------------------------------------------------------------------------
182MobiCoreDevice *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//------------------------------------------------------------------------------
194void 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//------------------------------------------------------------------------------
210size_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//------------------------------------------------------------------------------
222bool 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//------------------------------------------------------------------------------
350void 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//------------------------------------------------------------------------------
386void 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//------------------------------------------------------------------------------
406void 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//------------------------------------------------------------------------------
476void 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//------------------------------------------------------------------------------
493void 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//------------------------------------------------------------------------------
540void 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//------------------------------------------------------------------------------
584void 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//------------------------------------------------------------------------------
627void 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//------------------------------------------------------------------------------
653void 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//------------------------------------------------------------------------------
667void 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//------------------------------------------------------------------------------
696bool 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
798void 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 */
819void 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 */
830int 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 = sysconf(_SC_OPEN_MAX); 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//------------------------------------------------------------------------------
952static 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