//------------------------------------------------------------------------------
void MobiCoreDevice::donateRam(const uint32_t donationSize)
{
    // Donate additional RAM to the MobiCore
    CWsm_ptr ram = allocateContiguousPersistentWsm(donationSize);
    if (NULL == ram) {
        LOG_E("Allocation of additional RAM failed");
        return;
    }
    ramType_t ramType = RAM_GENERIC;
    addr_t adrBuffer = ram->physAddr;
    const uint32_t numPages = donationSize / (4 * 1024);


    LOG_I("donateRam(): adrBuffer=%p, numPages=%d, ramType=%d",
          adrBuffer,
          numPages,
          ramType);

    do {
        // Write MCP open message to buffer
        mcpMessage->cmdDonateRam.cmdHeader.cmdId = MC_MCP_CMD_DONATE_RAM;
        mcpMessage->cmdDonateRam.adrBuffer = (uint32_t) adrBuffer;
        mcpMessage->cmdDonateRam.numPages = numPages;
        mcpMessage->cmdDonateRam.ramType = ramType;

        // Notify MC about a new command inside the MCP buffer
        notify(SID_MCP);

        // Wait till response from MC is available
        if (!waitMcpNotification()) {
            break;
        }

        // Check if the command response ID is correct
        if ((MC_MCP_CMD_DONATE_RAM | FLAG_RESPONSE) != mcpMessage->rspHeader.rspId) {
            LOG_E("donateRam(): CMD_DONATE_RAM got invalid MCP response - rspId is: %d",
                  mcpMessage->rspHeader.rspId);
            break;
        }

        uint32_t mcRet = mcpMessage->rspDonateRam.rspHeader.result;
        if (MC_MCP_RET_OK != mcRet) {
            LOG_E("donateRam(): CMD_DONATE_RAM error %d", mcRet);
            break;
        }

        LOG_I("donateRam() succeeded.");

    } while (0);
}
/**
 * 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;
}