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