//------------------------------------------------------------------------------
bool MobiCoreDevice::waitMcpNotification(void)
{
    int counter = 5;
    while (1) {
        // In case of fault just return, nothing to do here
        if (mcFault) {
            return false;
        }
        // Wait 10 seconds for notification
        if (mcpSessionNotification.wait(10) == false) {
            // No MCP answer received and mobicore halted, dump mobicore status
            // then throw exception
            LOG_I("No MCP answer received in 2 seconds.");
            if (getMobicoreStatus() == MC_STATUS_HALT) {
                dumpMobicoreStatus();
                mcFault = true;
                return false;
            } else {
                counter--;
                if (counter < 1) {
                    mcFault = true;
                    return false;
                }
            }
        } else {
            break;
        }
    }

    // Check healthiness state of the device
    if (DeviceIrqHandler::isExiting()) {
        LOG_I("waitMcpNotification(): IrqHandler thread died! Joining");
        DeviceIrqHandler::join();
        LOG_I("waitMcpNotification(): Joined");
        LOG_E("IrqHandler thread died!");
        return false;
    }

    if (DeviceScheduler::isExiting()) {
        LOG_I("waitMcpNotification(): Scheduler thread died! Joining");
        DeviceScheduler::join();
        LOG_I("waitMcpNotification(): Joined");
        LOG_E("Scheduler thread died!");
        return false;
    }
    return true;
}
/**
 * Set up MCI and wait till MC is initialized
 * @return true if mobicore is already initialized
 */
bool TrustZoneDevice::initDevice(
	const char	*devFile,
	bool		loadMobiCore,
	const char  *mobicoreImage,
	bool		enableScheduler
) throw (ExcDevice) {

    notificationQueue_t* nqStartOut;
	notificationQueue_t* nqStartIn;
	addr_t mciBuffer;

    pMcKMod = new CMcKMod();
    if (!pMcKMod->open(devFile))
    {
        LOG_E("open() kernel module device failed");
        return false;
    }
    if (!pMcKMod->checkKmodVersionOk())
    {
        LOG_E("kernel module version mismatch");
        return false;
    }

    // Start MobiCore from DDRAM
    if (loadMobiCore) {
        // 1. Allocate DDRAM as pseudo IRAM
        mobicoreInDDR = allocateContiguousPersistentWsm(SIZE_DDRAM);
        if (NULL == mobicoreInDDR) {
            LOG_E("Allocation of additional RAM failed");
            return false;
        }
        memset(mobicoreInDDR->virtAddr,0xCC,SIZE_DDRAM);

        int ret = loadMobiCoreImage(mobicoreInDDR->virtAddr, SIZE_DDRAM,
					mobicoreImage);
        if (0 != ret) {
            LOG_E("loading Mobicore file failed: %d", ret);
            return false;
        }

        ret = pMcKMod->fcExecute(
                mobicoreInDDR->physAddr,
                MCP_BUFFER_SIZE);
        if (0 != ret) {
            LOG_E("pMcKMod->fcExecute() failed : %d", ret);
            return false;
        }
    }
    this->schedulerEnabled = enableScheduler;

    // Init MC with NQ and MCP buffer addresses

	// Set up MCI buffer
	if(!getMciInstance(MCI_BUFFER_SIZE, &pWsmMcp, &mciReused)) {
		return false;
	}
	mciBuffer = pWsmMcp->virtAddr;

	if(!checkMciVersion()) {
		return false;
	}

	// Only do a fastcall if MCI has not been reused (MC already initialized)
	if (!mciReused)
	{
		// Wipe memory before first usage
		bzero(mciBuffer, MCI_BUFFER_SIZE);

		// Init MC with NQ and MCP buffer addresses
		int ret = pMcKMod->fcInit(
							pWsmMcp->physAddr,
							0,
							NQ_BUFFER_SIZE,
							NQ_BUFFER_SIZE,
							MCP_BUFFER_SIZE);
		if (0 != ret)
		{
			LOG_E("pMcKMod->fcInit() failed");
			return false;
		}

		// First empty N-SIQ which results in set up of the MCI structure
		if(!nsiq()) {
			return false;
		}

		// Wait until MobiCore state switches to MC_STATUS_INITIALIZED
		// It is assumed that MobiCore always switches state at a certain point in time.
		while(1)
		{
			uint32_t status = getMobicoreStatus();
			
			if (MC_STATUS_INITIALIZED == status)
			{
				break;
			}
			else if (MC_STATUS_NOT_INITIALIZED == status)
			{
				// Switch to MobiCore to give it more CPU time.
				if(!yield()) {
					return false;
				}
			}
			else if (MC_STATUS_HALT == status)
			{
				dumpMobicoreStatus();
				LOG_E("MobiCore halted during init !!!, state is 0x%x", status);
				return false;
			}
			else // MC_STATUS_BAD_INIT or anything else
			{
				LOG_E("MCI buffer init failed, state is 0x%x", status);
				return false;
			}
		}
	}

	nqStartOut = (notificationQueue_t *) mciBuffer;
	nqStartIn = (notificationQueue_t *) ((uint8_t *) nqStartOut
			+ sizeof(notificationQueueHeader_t) + NQ_NUM_ELEMS
			* sizeof(notification_t));

	// Set up the NWd NQ
	nq = new NotificationQueue(nqStartIn, nqStartOut, NQ_NUM_ELEMS);

	mcpBuffer_t *mcpBuf = (mcpBuffer_t*) ((uint8_t *) mciBuffer + NQ_BUFFER_SIZE);

	// Set up the MC flags
	mcFlags = &(mcpBuf->mcFlags);

	// Set up the MCP message
	mcpMessage = &(mcpBuf->mcpMessage);

	// convert virtual address of mapping to physical address for the init.
	LOG_I("MCP: virt=%p, phys=%p, reused=%s",
			pWsmMcp->virtAddr,
			pWsmMcp->physAddr,
			mciReused ? "true" : "false");
	return true;
}
/**
 * Set up MCI and wait till MC is initialized
 * @return true if mobicore is already initialized
 */
bool TrustZoneDevice::initDevice(
    const char  *devFile,
    bool        loadMobiCore,
    const char  *mobicoreImage,
    bool        enableScheduler)
{
    notificationQueue_t *nqStartOut;
    notificationQueue_t *nqStartIn;
    addr_t mciBuffer;

    pMcKMod = new CMcKMod();
    mcResult_t ret = pMcKMod->open(devFile);
    if (ret != MC_DRV_OK) {
        LOG_W(" Opening kernel module device failed");
        return false;
    }
    if (!pMcKMod->checkVersion()) {
        LOG_E("kernel module version mismatch");
        return false;
    }

    this->schedulerEnabled = enableScheduler;

    // Init MC with NQ and MCP buffer addresses

    // Set up MCI buffer
    if (!getMciInstance(MCI_BUFFER_SIZE, &pWsmMcp, &mciReused)) {
        return false;
    }
    mciBuffer = pWsmMcp->virtAddr;

    if (!checkMciVersion()) {
        return false;
    }

    // Only do a fastcall if MCI has not been reused (MC already initialized)
    if (!mciReused) {
        // Wipe memory before first usage
        bzero(mciBuffer, MCI_BUFFER_SIZE);

        // Init MC with NQ and MCP buffer addresses
        int ret = pMcKMod->fcInit(0, NQ_BUFFER_SIZE, NQ_BUFFER_SIZE, MCP_BUFFER_SIZE);
        if (ret != 0) {
            LOG_E("pMcKMod->fcInit() failed");
            return false;
        }

        // First empty N-SIQ which results in set up of the MCI structure
        if (!nsiq()) {
            return false;
        }

        // Wait until MobiCore state switches to MC_STATUS_INITIALIZED
        // It is assumed that MobiCore always switches state at a certain point in time.
        while (1) {
            uint32_t status = getMobicoreStatus();

            if (MC_STATUS_INITIALIZED == status) {
                break;
            } else if (MC_STATUS_NOT_INITIALIZED == status) {
                // Switch to MobiCore to give it more CPU time.
                if (!yield())
                    return false;
		::sleep(1);
            } else if (MC_STATUS_HALT == status) {
                dumpMobicoreStatus();
                LOG_E("MobiCore halted during init !!!, state is 0x%x", status);
                return false;
            } else { // MC_STATUS_BAD_INIT or anything else
                LOG_E("MCI buffer init failed, state is 0x%x", status);
                return false;
            }
        }
    }

    nqStartOut = (notificationQueue_t *) mciBuffer;
    nqStartIn = (notificationQueue_t *) ((uint8_t *) nqStartOut
                                         + sizeof(notificationQueueHeader_t) + NQ_NUM_ELEMS
                                         * sizeof(notification_t));

    // Set up the NWd NQ
    nq = new NotificationQueue(nqStartIn, nqStartOut, NQ_NUM_ELEMS);

    mcpBuffer_t *mcpBuf = (mcpBuffer_t *) ((uint8_t *) mciBuffer + NQ_BUFFER_SIZE);

    // Set up the MC flags
    mcFlags = &(mcpBuf->mcFlags);

    // Set up the MCP message
    mcpMessage = &(mcpBuf->mcpMessage);

    // convert virtual address of mapping to physical address for the init.
    LOG_I("MCI established, at %p, phys=%p, reused=%s",
          pWsmMcp->virtAddr,
          pWsmMcp->physAddr,
          mciReused ? "true" : "false");
    return true;
}