14e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park/** @addtogroup MCD_MCDIMPL_DAEMON_DEV
24e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * @{
34e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * @file
44e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park *
54e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park *
64e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
77b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim *
84e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * Redistribution and use in source and binary forms, with or without
94e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * modification, are permitted provided that the following conditions
104e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * are met:
114e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * 1. Redistributions of source code must retain the above copyright
124e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park *    notice, this list of conditions and the following disclaimer.
134e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * 2. Redistributions in binary form must reproduce the above copyright
144e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park *    notice, this list of conditions and the following disclaimer in the
154e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park *    documentation and/or other materials provided with the distribution.
164e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * 3. The name of the author may not be used to endorse or promote
174e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park *    products derived from this software without specific prior
184e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park *    written permission.
194e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park *
204e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
214e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
224e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
244e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
254e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
264e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
274e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
284e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
294e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
304e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
314e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park */
324e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
334e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park#include <cstdlib>
344e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park#include <pthread.h>
354e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park#include "McTypes.h"
364e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
374e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park#include "DeviceScheduler.h"
384e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park#include "DeviceIrqHandler.h"
394e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park#include "ExcDevice.h"
404e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park#include "Connection.h"
414e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park#include "TrustletSession.h"
424e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
434e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park#include "MobiCoreDevice.h"
444e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park#include "Mci/mci.h"
454e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park#include "mcLoadFormat.h"
464e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
474e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
484e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park#include "log.h"
494e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park#include "public/MobiCoreDevice.h"
504e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
514e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
524e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
537b143edf281bed18c8ebd0733465f3af5af327ebJungtae KimMobiCoreDevice::MobiCoreDevice()
547b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim{
557b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    mcFault = false;
564e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
574e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
584e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
597b143edf281bed18c8ebd0733465f3af5af327ebJungtae KimMobiCoreDevice::~MobiCoreDevice()
607b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim{
617b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    delete mcVersionInfo;
627b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    mcVersionInfo = NULL;
634e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
644e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
654e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
667b143edf281bed18c8ebd0733465f3af5af327ebJungtae KimTrustletSession *MobiCoreDevice::getTrustletSession(uint32_t sessionId)
677b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim{
687b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    for (trustletSessionIterator_t session = trustletSessions.begin();
697b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            session != trustletSessions.end();
707b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            ++session) {
717b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        TrustletSession *tsTmp = *session;
727b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if (tsTmp->sessionId == sessionId) {
737b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            return tsTmp;
747b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
757b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
767b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    return NULL;
774e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
784e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
794e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
807b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kimvoid MobiCoreDevice::cleanSessionBuffers(TrustletSession *session)
817b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim{
827b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    CWsm_ptr pWsm = session->popBulkBuff();
837b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
847b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    while (pWsm) {
857b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        unlockWsmL2(pWsm->handle);
867b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        pWsm = session->popBulkBuff();
877b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
887b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim}
897b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim//------------------------------------------------------------------------------
907b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kimvoid MobiCoreDevice::removeTrustletSession(uint32_t sessionId)
917b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim{
927b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    for (trustletSessionIterator_t session = trustletSessions.begin();
937b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            session != trustletSessions.end();
947b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            ++session) {
957b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if ((*session)->sessionId == sessionId) {
967b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            cleanSessionBuffers(*session);
977b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            trustletSessions.erase(session);
987b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            return;
997b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
1007b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
1017b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim}
1024e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
1037b143edf281bed18c8ebd0733465f3af5af327ebJungtae KimConnection *MobiCoreDevice::getSessionConnection(uint32_t sessionId, notification_t *notification)
1047b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim{
1057b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    Connection *con = NULL;
1067b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    TrustletSession *ts = NULL;
1077b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
1087b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    ts = getTrustletSession(sessionId);
1097b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (ts == NULL) {
1107b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return NULL;
1117b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
1127b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
1137b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    con = ts->notificationConnection;
1147b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (con == NULL) {
1157b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        ts->queueNotification(notification);
1167b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return NULL;
1177b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
1187b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
1197b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    return con;
1204e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
1214e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1224e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1234e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
1247b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kimbool MobiCoreDevice::open(Connection *connection)
1257b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim{
1267b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Link this device to the connection
1277b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    connection->connectionData = this;
1287b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    return true;
1294e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
1304e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1314e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1324e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
1334e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park/**
1344e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * Close device.
1354e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park *
1364e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * Removes all sessions to a connection. Though, clientLib rejects the closeDevice()
1374e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * command if still sessions connected to the device, this is needed to clean up all
1384e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * sessions if client dies.
1394e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park */
1407b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kimvoid MobiCoreDevice::close(Connection *connection)
1417b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim{
1427b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    trustletSessionList_t::reverse_iterator interator;
1437b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    static CMutex mutex;
1447b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // 1. Iterate through device session to find connection
1457b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // 2. Decide what to do with open Trustlet sessions
1467b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // 3. Remove & delete deviceSession from vector
1477b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
1487b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Enter critical section
1497b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    mutex.lock();
1507b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    for (interator = trustletSessions.rbegin();
1517b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            interator != trustletSessions.rend();
1527b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            interator++) {
1537b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        TrustletSession *ts = *interator;
1547b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
1557b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if (ts->deviceConnection == connection) {
1567b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            closeSession(connection, ts->sessionId);
1577b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
1587b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
1597b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Leave critical section
1607b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    mutex.unlock();
1617b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
1627b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // After the trustlet is done make sure to tell the driver to cleanup
1637b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // all the orphaned drivers
1647b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    cleanupWsmL2();
1657b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
1667b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    connection->connectionData = NULL;
1674e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
1684e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1694e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1704e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
1717b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kimvoid MobiCoreDevice::start(void)
1727b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim{
1737b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Call the device specific initialization
1747b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    //  initDevice();
1757b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
1767b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    LOG_I("Starting DeviceIrqHandler...");
1777b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Start the irq handling thread
1787b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    DeviceIrqHandler::start();
1797b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
1807b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (schedulerAvailable()) {
1817b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_I("Starting DeviceScheduler...");
1827b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // Start the scheduling handling thread
1837b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        DeviceScheduler::start();
1847b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    } else {
1857b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_I("No DeviceScheduler available.");
1867b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
1874e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
1884e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1894e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1904e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
1917b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kimvoid MobiCoreDevice::signalMcpNotification(void)
1927b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim{
1937b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    mcpSessionNotification.signal();
1944e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
1954e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1964e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1974e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
1987b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kimbool MobiCoreDevice::waitMcpNotification(void)
1997b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim{
2007b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    int counter = 5;
2017b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    while (1) {
2027b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // In case of fault just return, nothing to do here
2037b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if (mcFault) {
2047b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            return false;
2057b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
2067b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // Wait 10 seconds for notification
2077b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if (mcpSessionNotification.wait(10) == false) {
2087b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            // No MCP answer received and mobicore halted, dump mobicore status
2097b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            // then throw exception
2107b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            LOG_I("No MCP answer received in 2 seconds.");
2117b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            if (getMobicoreStatus() == MC_STATUS_HALT) {
2127b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim                dumpMobicoreStatus();
2137b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim                mcFault = true;
2147b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim                return false;
2157b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            } else {
2167b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim                counter--;
2177b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim                if (counter < 1) {
2187b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim                    mcFault = true;
2197b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim                    return false;
2207b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim                }
2217b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            }
2227b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        } else {
2237b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            break;
2247b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
2257b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
2267b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
2277b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Check healthiness state of the device
2287b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (DeviceIrqHandler::isExiting()) {
2297b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_I("waitMcpNotification(): IrqHandler thread died! Joining");
2307b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        DeviceIrqHandler::join();
2317b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_I("waitMcpNotification(): Joined");
2327b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_E("IrqHandler thread died!");
2337b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return false;
2347b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
2357b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
2367b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (DeviceScheduler::isExiting()) {
2377b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_I("waitMcpNotification(): Scheduler thread died! Joining");
2387b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        DeviceScheduler::join();
2397b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_I("waitMcpNotification(): Joined");
2407b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_E("Scheduler thread died!");
2417b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return false;
2427b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
2437b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    return true;
2444e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
2454e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
2464e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
2474e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
2487b143edf281bed18c8ebd0733465f3af5af327ebJungtae KimmcResult_t MobiCoreDevice::openSession(
2497b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    Connection                      *deviceConnection,
2507b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    loadDataOpenSession_ptr         pLoadDataOpenSession,
2517b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    MC_DRV_CMD_OPEN_SESSION_struct  *cmdOpenSession,
2527b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    mcDrvRspOpenSessionPayload_ptr  pRspOpenSessionPayload
2537b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim)
2547b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim{
2557b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    do {
2567b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        addr_t tci;
2577b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        uint32_t len;
2587b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        uint32_t handle = cmdOpenSession->handle;
2597b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
2607b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if (!findContiguousWsm(handle, &tci, &len)) {
2617b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            LOG_E("Failed to find contiguous WSM %u", handle);
2627b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            return MC_DRV_ERR_DAEMON_WSM_HANDLE_NOT_FOUND;
2637b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
2647b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
2657b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if (!lockWsmL2(handle)) {
2667b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            LOG_E("Failed to lock contiguous WSM %u", handle);
2677b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            return MC_DRV_ERR_DAEMON_WSM_HANDLE_NOT_FOUND;
2687b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
2697b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
2707b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // Write MCP open message to buffer
2717b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        mcpMessage->cmdOpen.cmdHeader.cmdId = MC_MCP_CMD_OPEN_SESSION;
2727b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        mcpMessage->cmdOpen.uuid = cmdOpenSession->uuid;
2737b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        mcpMessage->cmdOpen.wsmTypeTci = WSM_CONTIGUOUS;
2747b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        mcpMessage->cmdOpen.adrTciBuffer = (uint32_t)(tci);
2757b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        mcpMessage->cmdOpen.ofsTciBuffer = 0;
2767b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        mcpMessage->cmdOpen.lenTciBuffer = len;
2777b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
2787b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_I(" Using phys=%p, len=%d as TCI buffer",
2797b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim              (addr_t)(cmdOpenSession->tci),
2807b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim              cmdOpenSession->len);
2817b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
2827b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // check if load data is provided
2837b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        mcpMessage->cmdOpen.wsmTypeLoadData = WSM_L2;
2847b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        mcpMessage->cmdOpen.adrLoadData = (uint32_t)pLoadDataOpenSession->baseAddr;
2857b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        mcpMessage->cmdOpen.ofsLoadData = pLoadDataOpenSession->offs;
2867b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        mcpMessage->cmdOpen.lenLoadData = pLoadDataOpenSession->len;
2877b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        memcpy(&mcpMessage->cmdOpen.tlHeader, pLoadDataOpenSession->tlHeader, sizeof(*pLoadDataOpenSession->tlHeader));
2887b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
2897b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // Clear the notifications queue. We asume the race condition we have
2907b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // seen in openSession never happens elsewhere
2917b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        notifications = std::queue<notification_t>();
2927b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // Notify MC about a new command inside the MCP buffer
2937b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        notify(SID_MCP);
2947b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
2957b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // Wait till response from MC is available
2967b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if (!waitMcpNotification()) {
2977b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            // Here Mobicore can be considered dead.
2987b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            unlockWsmL2(handle);
2997b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            return MC_DRV_ERR_DAEMON_MCI_ERROR;
3007b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
3017b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
3027b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // Check if the command response ID is correct
3037b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if ((MC_MCP_CMD_OPEN_SESSION | FLAG_RESPONSE) != mcpMessage->rspHeader.rspId) {
3047b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            LOG_E("CMD_OPEN_SESSION got invalid MCP command response(0x%X)", mcpMessage->rspHeader.rspId);
3057b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            // Something is messing with our MCI memory, we cannot know if the Trustlet was loaded.
3067b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            // Had in been loaded, we are loosing track of it here.
3077b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            unlockWsmL2(handle);
3087b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            return MC_DRV_ERR_DAEMON_MCI_ERROR;
3097b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
3107b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
3117b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        uint32_t mcRet = mcpMessage->rspOpen.rspHeader.result;
3127b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
3137b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if (mcRet != MC_MCP_RET_OK) {
3147b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            LOG_E("MCP OPEN returned code %d.", mcRet);
3157b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            unlockWsmL2(handle);
3167b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            return MAKE_MC_DRV_MCP_ERROR(mcRet);
3177b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
3187b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
3197b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_I(" After MCP OPEN, we have %d queued notifications",
3207b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim              notifications.size());
3217b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // Read MC answer from MCP buffer
3227b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        TrustletSession *trustletSession = new TrustletSession(
3237b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            deviceConnection,
3247b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            mcpMessage->rspOpen.sessionId);
3257b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
3267b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        pRspOpenSessionPayload->sessionId = trustletSession->sessionId;
3277b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        pRspOpenSessionPayload->deviceSessionId = (uint32_t)trustletSession;
3287b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        pRspOpenSessionPayload->sessionMagic = trustletSession->sessionMagic;
3297b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
3307b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        trustletSessions.push_back(trustletSession);
3317b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
3327b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        trustletSession->addBulkBuff(new CWsm((void *)pLoadDataOpenSession->offs, pLoadDataOpenSession->len, handle, 0));
3337b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
3347b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // We have some queued notifications and we need to send them to them
3357b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // trustlet session
3367b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        while (!notifications.empty()) {
3377b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            trustletSession->queueNotification(&notifications.front());
3387b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            notifications.pop();
3397b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
3407b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
3417b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    } while (0);
3427b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    return MC_DRV_OK;
3434e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
3444e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
3454e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
3464e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
3474e9e8c9c0169b40318386436d762c3d73cf4c328DongJin ParkTrustletSession *MobiCoreDevice::registerTrustletConnection(
3487b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    Connection                    *connection,
3497b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    MC_DRV_CMD_NQ_CONNECT_struct *cmdNqConnect
3507b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim)
3517b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim{
3527b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    LOG_I(" Registering notification socket with Service session %d.",
3537b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim          cmdNqConnect->sessionId);
3549081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kim    LOG_V("  Searching sessionId %d with sessionMagic %d",
3557b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim          cmdNqConnect->sessionId,
3567b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim          cmdNqConnect->sessionMagic);
3574e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
3587b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    for (trustletSessionIterator_t iterator = trustletSessions.begin();
3597b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            iterator != trustletSessions.end();
3607b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            ++iterator) {
3617b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        TrustletSession *ts = *iterator;
3624e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
3637b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if (ts != (TrustletSession *) (cmdNqConnect->deviceSessionId)) {
3647b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            continue;
3657b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
3664e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
3677b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if ( (ts->sessionMagic != cmdNqConnect->sessionMagic)
3687b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim                || (ts->sessionId != cmdNqConnect->sessionId)) {
3697b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            continue;
3707b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
3714e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
3727b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        ts->notificationConnection = connection;
3739081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kim
3747b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_I(" Found Service session, registered connection.");
3759081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kim
3769081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kim        return ts;
3777b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
3784e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
3797b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    LOG_I("registerTrustletConnection(): search failed");
3807b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    return NULL;
3814e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
3824e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
3834e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
3844e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
3857b143edf281bed18c8ebd0733465f3af5af327ebJungtae KimmcResult_t MobiCoreDevice::closeSession(uint32_t sessionId)
3867b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim{
3877b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    LOG_I(" Write MCP CLOSE message to MCI, notify and wait");
3887b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
3897b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Write MCP close message to buffer
3907b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    mcpMessage->cmdClose.cmdHeader.cmdId = MC_MCP_CMD_CLOSE_SESSION;
3917b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    mcpMessage->cmdClose.sessionId = sessionId;
3927b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
3937b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Notify MC about the availability of a new command inside the MCP buffer
3947b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    notify(SID_MCP);
3957b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
3967b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Wait till response from MSH is available
3977b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (!waitMcpNotification()) {
3987b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return MC_DRV_ERR_DAEMON_MCI_ERROR;
3997b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
4007b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
4017b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Check if the command response ID is correct
4027b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if ((MC_MCP_CMD_CLOSE_SESSION | FLAG_RESPONSE) != mcpMessage->rspHeader.rspId) {
4037b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_E("CMD_CLOSE_SESSION got invalid MCP response");
4047b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return MC_DRV_ERR_DAEMON_MCI_ERROR;
4057b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
4067b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
4077b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Read MC answer from MCP buffer
4087b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    uint32_t mcRet = mcpMessage->rspOpen.rspHeader.result;
4097b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
4107b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (mcRet != MC_MCP_RET_OK) {
4117b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_E("CMD_CLOSE_SESSION error %d", mcRet);
4127b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return MAKE_MC_DRV_MCP_ERROR(mcRet);
4137b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
4147b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
4157b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    return MC_DRV_OK;
4167b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim}
4177b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
4187b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim//------------------------------------------------------------------------------
4194e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park/**
4207b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim * TODO-2012-09-19-haenellu: Do some more checks here, otherwise rogue clientLib
4217b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim * can close sessions from different TLCs. That is, deviceConnection is ignored below.
4227b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim *
4234e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * Need connection as well as according session ID, so that a client can not
4244e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * close sessions not belonging to him.
4254e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park */
4267b143edf281bed18c8ebd0733465f3af5af327ebJungtae KimmcResult_t MobiCoreDevice::closeSession(Connection *deviceConnection, uint32_t sessionId)
4277b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim{
4287b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    TrustletSession *ts = getTrustletSession(sessionId);
4297b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (ts == NULL) {
4307b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_E("no session found with id=%d", sessionId);
4317b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return MC_DRV_ERR_DAEMON_UNKNOWN_SESSION;
4327b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
4337b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
4347b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    uint32_t mcRet = closeSession(sessionId);
4357b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (mcRet != MC_DRV_OK) {
4367b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return mcRet;
4377b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
4387b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
4397b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // remove objects
4407b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    removeTrustletSession(sessionId);
4417b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    delete ts;
4427b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
4437b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    return MC_DRV_OK;
4444e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
4454e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
4464e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
4474e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
4487b143edf281bed18c8ebd0733465f3af5af327ebJungtae KimmcResult_t MobiCoreDevice::mapBulk(uint32_t sessionId, uint32_t handle, uint32_t pAddrL2,
4497b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim                                   uint32_t offsetPayload, uint32_t lenBulkMem, uint32_t *secureVirtualAdr)
4507b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim{
4517b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    TrustletSession *ts = getTrustletSession(sessionId);
4527b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (ts == NULL) {
4537b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_E("no session found with id=%d", sessionId);
4547b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return MC_DRV_ERR_DAEMON_UNKNOWN_SESSION;
4557b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
4567b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
4577b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // TODO-2012-09-06-haenellu: Think about not ignoring the error case, ClientLib does not allow this.
4587b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    ts->addBulkBuff(new CWsm((void *)offsetPayload, lenBulkMem, handle, (void *)pAddrL2));
4597b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Write MCP map message to buffer
4607b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    mcpMessage->cmdMap.cmdHeader.cmdId = MC_MCP_CMD_MAP;
4617b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    mcpMessage->cmdMap.sessionId = sessionId;
4627b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    mcpMessage->cmdMap.wsmType = WSM_L2;
4637b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    mcpMessage->cmdMap.adrBuffer = (uint32_t)(pAddrL2);
4647b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    mcpMessage->cmdMap.ofsBuffer = offsetPayload;
4657b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    mcpMessage->cmdMap.lenBuffer = lenBulkMem;
4667b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
4677b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Notify MC about the availability of a new command inside the MCP buffer
4687b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    notify(SID_MCP);
4697b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
4707b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Wait till response from MC is available
4717b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (!waitMcpNotification()) {
4727b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return MC_DRV_ERR_DAEMON_MCI_ERROR;
4737b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
4747b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
4757b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Check if the command response ID is correct
4767b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (mcpMessage->rspHeader.rspId != (MC_MCP_CMD_MAP | FLAG_RESPONSE)) {
4777b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_E("CMD_MAP got invalid MCP response");
4787b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return MC_DRV_ERR_DAEMON_MCI_ERROR;
4797b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
4807b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
4817b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    uint32_t mcRet = mcpMessage->rspMap.rspHeader.result;
4827b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
4837b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (mcRet != MC_MCP_RET_OK) {
4847b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_E("MCP MAP returned code %d.", mcRet);
4857b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return MAKE_MC_DRV_MCP_ERROR(mcRet);
4867b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
4877b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
4887b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    *secureVirtualAdr = mcpMessage->rspMap.secureVirtualAdr;
4897b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    return MC_DRV_OK;
4904e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
4914e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
4924e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
4934e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
4947b143edf281bed18c8ebd0733465f3af5af327ebJungtae KimmcResult_t MobiCoreDevice::unmapBulk(uint32_t sessionId, uint32_t handle,
4957b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim                                     uint32_t secureVirtualAdr, uint32_t lenBulkMem)
4967b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim{
4977b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    TrustletSession *ts = getTrustletSession(sessionId);
4987b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (ts == NULL) {
4997b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_E("no session found with id=%d", sessionId);
5007b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return MC_DRV_ERR_DAEMON_UNKNOWN_SESSION;
5017b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
5027b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
5037b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Write MCP unmap command to buffer
5047b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    mcpMessage->cmdUnmap.cmdHeader.cmdId = MC_MCP_CMD_UNMAP;
5057b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    mcpMessage->cmdUnmap.sessionId = sessionId;
5067b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    mcpMessage->cmdUnmap.wsmType = WSM_L2;
5077b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    mcpMessage->cmdUnmap.secureVirtualAdr = secureVirtualAdr;
5087b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    mcpMessage->cmdUnmap.lenVirtualBuffer = lenBulkMem;
5097b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
5107b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Notify MC about the availability of a new command inside the MCP buffer
5117b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    notify(SID_MCP);
5127b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
5137b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Wait till response from MC is available
5147b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (!waitMcpNotification()) {
5157b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return MC_DRV_ERR_DAEMON_MCI_ERROR;
5167b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
5177b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
5187b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Check if the command response ID is correct
5197b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (mcpMessage->rspHeader.rspId != (MC_MCP_CMD_UNMAP | FLAG_RESPONSE)) {
5207b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_E("CMD_OPEN_SESSION got invalid MCP response");
5217b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return MC_DRV_ERR_DAEMON_MCI_ERROR;
5227b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
5237b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
5247b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    uint32_t mcRet = mcpMessage->rspUnmap.rspHeader.result;
5257b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
5267b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (mcRet != MC_MCP_RET_OK) {
5277b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_E("MCP UNMAP returned code %d.", mcRet);
5287b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return MAKE_MC_DRV_MCP_ERROR(mcRet);
5297b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    } else {
5307b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // Just remove the buffer
5317b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // TODO-2012-09-06-haenellu: Haven't we removed it already?
5327b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if (!ts->removeBulkBuff(handle))
5337b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            LOG_I("unmapBulk(): no buffer found found with handle=%u", handle);
5347b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
5357b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
5367b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    return MC_DRV_OK;
5374e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
5384e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
5394e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
5404e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
5417b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kimvoid MobiCoreDevice::donateRam(const uint32_t donationSize)
5427b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim{
5437b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Donate additional RAM to the MobiCore
5447b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    CWsm_ptr ram = allocateContiguousPersistentWsm(donationSize);
5457b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (NULL == ram) {
5467b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_E("Allocation of additional RAM failed");
5477b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return;
5487b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
5497b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    ramType_t ramType = RAM_GENERIC;
5507b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    addr_t adrBuffer = ram->physAddr;
5517b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    const uint32_t numPages = donationSize / (4 * 1024);
5527b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
5537b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
5547b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    LOG_I("donateRam(): adrBuffer=%p, numPages=%d, ramType=%d",
5557b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim          adrBuffer,
5567b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim          numPages,
5577b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim          ramType);
5587b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
5597b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    do {
5607b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // Write MCP open message to buffer
5617b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        mcpMessage->cmdDonateRam.cmdHeader.cmdId = MC_MCP_CMD_DONATE_RAM;
5627b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        mcpMessage->cmdDonateRam.adrBuffer = (uint32_t) adrBuffer;
5637b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        mcpMessage->cmdDonateRam.numPages = numPages;
5647b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        mcpMessage->cmdDonateRam.ramType = ramType;
5657b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
5667b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // Notify MC about a new command inside the MCP buffer
5677b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        notify(SID_MCP);
5687b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
5697b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // Wait till response from MC is available
5707b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if (!waitMcpNotification()) {
5717b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            break;
5727b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
5737b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
5747b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // Check if the command response ID is correct
5757b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if ((MC_MCP_CMD_DONATE_RAM | FLAG_RESPONSE) != mcpMessage->rspHeader.rspId) {
5767b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            LOG_E("donateRam(): CMD_DONATE_RAM got invalid MCP response - rspId is: %d",
5777b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim                  mcpMessage->rspHeader.rspId);
5787b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            break;
5797b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
5807b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
5817b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        uint32_t mcRet = mcpMessage->rspDonateRam.rspHeader.result;
5827b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if (MC_MCP_RET_OK != mcRet) {
5837b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            LOG_E("donateRam(): CMD_DONATE_RAM error %d", mcRet);
5847b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            break;
5857b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
5867b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
5877b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        LOG_I("donateRam() succeeded.");
5887b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
5897b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    } while (0);
5904e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
5914e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
5924e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
5937b143edf281bed18c8ebd0733465f3af5af327ebJungtae KimmcResult_t MobiCoreDevice::getMobiCoreVersion(
5944e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park    mcDrvRspGetMobiCoreVersionPayload_ptr pRspGetMobiCoreVersionPayload
5957b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim)
5967b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim{
5977b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // If MobiCore version info already fetched.
5987b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (mcVersionInfo != NULL) {
5997b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        pRspGetMobiCoreVersionPayload->versionInfo = *mcVersionInfo;
6007b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return MC_DRV_OK;
6017b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // Otherwise, fetch it via MCP.
6027b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    } else {
6037b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // Write MCP unmap command to buffer
6047b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        mcpMessage->cmdGetMobiCoreVersion.cmdHeader.cmdId = MC_MCP_CMD_GET_MOBICORE_VERSION;
6057b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
6067b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // Notify MC about the availability of a new command inside the MCP buffer
6077b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        notify(SID_MCP);
6087b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
6097b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // Wait till response from MC is available
6107b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if (!waitMcpNotification()) {
6117b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            return MC_DRV_ERR_DAEMON_MCI_ERROR;
6127b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
6137b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
6147b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // Check if the command response ID is correct
6157b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if ((MC_MCP_CMD_GET_MOBICORE_VERSION | FLAG_RESPONSE) != mcpMessage->rspHeader.rspId) {
6167b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            LOG_E("MC_MCP_CMD_GET_MOBICORE_VERSION got invalid MCP response");
6177b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            return MC_DRV_ERR_DAEMON_MCI_ERROR;
6187b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
6197b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
6207b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        uint32_t  mcRet = mcpMessage->rspGetMobiCoreVersion.rspHeader.result;
6217b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
6227b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if (mcRet != MC_MCP_RET_OK) {
6237b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            LOG_E("MC_MCP_CMD_GET_MOBICORE_VERSION error %d", mcRet);
6247b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            return MAKE_MC_DRV_MCP_ERROR(mcRet);
6257b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
6267b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
6277b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        pRspGetMobiCoreVersionPayload->versionInfo = mcpMessage->rspGetMobiCoreVersion.versionInfo;
6287b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
6297b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // Store MobiCore info for future reference.
6307b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        mcVersionInfo = new mcVersionInfo_t();
6317b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        *mcVersionInfo = pRspGetMobiCoreVersionPayload->versionInfo;
6327b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return MC_DRV_OK;
6337b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
6344e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
6354e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
6364e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
6374e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Parkvoid MobiCoreDevice::queueUnknownNotification(
6387b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    notification_t notification
6397b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim)
6407b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim{
6417b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    notifications.push(notification);
6424e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
6434e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
6444e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park/** @} */
645