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 //------------------------------------------------------------------------------
MobiCoreDriverDaemon(bool enableScheduler,bool loadMobicore,std::string mobicoreImage,unsigned int donateRamSize,bool loadDriver,std::string driverPath)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 //------------------------------------------------------------------------------
~MobiCoreDriverDaemon(void)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 //------------------------------------------------------------------------------
run(void)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 //------------------------------------------------------------------------------
getDevice(uint32_t deviceId)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 //------------------------------------------------------------------------------
dropConnection(Connection * connection)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 //------------------------------------------------------------------------------
writeResult(Connection * connection,mcResult_t code)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 //------------------------------------------------------------------------------
loadDeviceDriver(std::string driverPath)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 //------------------------------------------------------------------------------
processOpenDevice(Connection * connection)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 //------------------------------------------------------------------------------
processCloseDevice(Connection * connection)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 //------------------------------------------------------------------------------
processOpenSession(Connection * connection)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 //------------------------------------------------------------------------------
processCloseSession(Connection * connection)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 //------------------------------------------------------------------------------
processNqConnect(Connection * connection)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 //------------------------------------------------------------------------------
processNotify(Connection * connection)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 //------------------------------------------------------------------------------
processMapBulkBuf(Connection * connection)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 //------------------------------------------------------------------------------
processUnmapBulkBuf(Connection * connection)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 //------------------------------------------------------------------------------
processGetVersion(Connection * connection)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 //------------------------------------------------------------------------------
processGetMobiCoreVersion(Connection * connection)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 //------------------------------------------------------------------------------
handleConnection(Connection * connection)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 
printUsage(int argc,char * args[])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  */
terminateDaemon(int signum)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  */
main(int argc,char * args[])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 = 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 //------------------------------------------------------------------------------
checkMobiCoreVersion(MobiCoreDevice * mobiCoreDevice)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