//------------------------------------------------------------------------------ //TODO Schedulerthread to be switched off if MC is idle. Will be woken up when // driver is called again. void TrustZoneDevice::schedule(void) { uint32_t timeslice = SCHEDULING_FREQ; // loop forever for (;;) { // Scheduling decision if (MC_FLAG_SCHEDULE_IDLE == mcFlags->schedule) { // MobiCore is IDLE // Prevent unnecessary consumption of CPU cycles -> Wait until S-SIQ received schedSync.wait(); } else { // MobiCore is not IDLE (anymore) // Check timeslice if (timeslice == 0) { // Slice expired, so force MC internal scheduling decision timeslice = SCHEDULING_FREQ; if (!nsiq()) { break; } } else { // Slice not used up, simply hand over control to the MC timeslice--; if (!yield()) { break; } } } } //for (;;) }
//------------------------------------------------------------------------------ void TrustZoneDevice::notify( uint32_t sessionId ) { // Check if it is MCP session - handle openSession() command if (sessionId != SID_MCP) { // Check if session ID exists to avoid flooding of nq by clients TrustletSession *ts = getTrustletSession(sessionId); if (ts == NULL) { LOG_E("no session with id=%d", sessionId); return; } LOG_I(" Sending notification for session %d to MobiCore", sessionId); } else { LOG_I(" Sending MCP notification to MobiCore"); } // Notify MobiCore about new data notification_t notification = { .sessionId = sessionId, .payload = 0 }; nq->putNotification(¬ification); //IMPROVEMENT-2012-03-07-maneaval What happens when/if nsiq fails? //In the old days an exception would be thrown but it was uncertain //where it was handled, some server(sock or Netlink). In that case //the server would just die but never actually signaled to the client //any error condition nsiq(); } //------------------------------------------------------------------------------ uint32_t TrustZoneDevice::getMobicoreStatus(void) { uint32_t status; pMcKMod->fcInfo(1, &status, NULL); return status; }
//------------------------------------------------------------------------------ void TrustZoneDevice::notify( uint32_t sessionId ) { do { // Check if it is MCP session - handle openSession() command if (SID_MCP != sessionId) { // Check if session ID exists to avoid flooding of nq by clients TrustletSession* ts = getTrustletSession(sessionId); if (NULL == ts) { LOG_E("notify(): no session with id=%d", sessionId); break; } } LOG_I("notify(): Send notification for id=%d", sessionId); // Notify MobiCore about new data notification_t notification = { // C++ does not support C99 designated initializers /* .sessionId = */ sessionId, /* .payload = */ 0 }; nq->putNotification(¬ification); //IMPROVEMENT-2012-03-07-maneaval What happens when/if nsiq fails? //In the old days an exception would be thrown but it was uncertain //where it was handled, some server(sock or Netlink). In that case //the server would just die but never actually signaled to the client //any error condition nsiq(); } 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; }
/** * 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; }