Esempio n. 1
0
bool Service::intrTaskWait(msg_t * & o_msg)
{
    // wait for a shutdown message
    // or an interrupt

    bool shutdown = false;
    msg_q_t q = iv_intrTaskQ;

    o_msg = msg_wait(q);

    ATTN_FAST("...intr task woke up");

    shutdown = o_msg->type == SHUTDOWN;

    if(shutdown)
    {
        // this was a shutdown message.
        // ack the message and tell the
        // task loop to exit

        iv_intrTaskQ = 0;
        iv_shutdownPrdTask = true;

        msg_respond(q, o_msg);

        ATTN_FAST("interrupt task shutting down");
    }

    return shutdown;
}
Esempio n. 2
0
    void SyncMessage::response(msg_q_t i_msgQ)
    {
        errlHndl_t err = NULL;
        // Send the response to the original caller of sendrecv()
        int rc = msg_respond(i_msgQ, iv_msg);
        if (rc)
        {
            TRACFCOMP( g_trac_trustedboot,
                       ERR_MRK "SyncMessage::response msg_respond failure %d",
                       rc);
            /*@
             * @errortype       ERRL_SEV_UNRECOVERABLE
             * @moduleid        MOD_TPM_SYNCRESPONSE
             * @reasoncode      RC_MSGRESPOND_FAIL
             * @userdata1       rc from msq_respond()
             * @devdesc         msg_respond() failed
             * @custdesc        Firmware error during system boot
             */
            err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                          MOD_TPM_SYNCRESPONSE,
                                          RC_MSGRESPOND_FAIL,
                                          rc,
                                          0,
                                          true);
            err->collectTrace(SECURE_COMP_NAME);
            err->collectTrace(TRBOOT_COMP_NAME);

            // Log this failure here since we can't reply to caller
            errlCommit(err, TRBOOT_COMP_ID);

        }
    }
Esempio n. 3
0
    ///
    /// @brief sync handle response
    ///
    void BTSyncMessage::response(msg_q_t i_msgQ)
    {
        // Send the response to the original caller of sendrecv()
        int rc = msg_respond(i_msgQ, iv_msg);
        if (rc)
        {
            // Not much we're going to do here, so lets commit an error and
            // the original request will timeout.
            IPMI_TRAC(ERR_MRK "msg_respond() i/o error (response) %d", rc);

            /*@
             * @errortype       ERRL_SEV_UNRECOVERABLE
             * @moduleid        IPMI::MOD_IPMISRV_REPLY
             * @reasoncode      IPMI::RC_INVALID_QRESPONSE
             * @userdata1       rc from msg_respond()
             * @devdesc         msg_respond() failed
             * @custdesc        Firmware error during system boot
             */
            errlHndl_t err = new ERRORLOG::ErrlEntry(
                ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                IPMI::MOD_IPMISRV_REPLY,
                IPMI::RC_INVALID_QRESPONSE,
                rc,
                0,
                true);

            err->collectTrace(IPMI_COMP_NAME);
            errlCommit(err, IPMI_COMP_ID);

            // Frotz the response data
            delete[] iv_data;
            iv_data = NULL;
        }
    }
Esempio n. 4
0
    ///
    /// @brief sync msg transmit
    ///
    bool BTSyncMessage::xmit(void)
    {
        errlHndl_t err = BTMessage::phy_xmit();

        if (err)
        {
            // Something went wrong, so we need to respond back with the error
            iv_errl = err;

            msg_q_t mq = Singleton<IpmiRP>::instance().msgQueue();
            int rc = msg_respond(mq, iv_msg);
            if (rc)
            {
                // Yuk. We can't respond back to our caller with that error. So,
                // we'll commit it. I don't see much sense in creating another
                // error log, so we'll just trace the msg_respond() failure.
                IPMI_TRAC(ERR_MRK "msg_respond() i/o error (transmit) %d", rc);
                err->collectTrace(IPMI_COMP_NAME);
                errlCommit(err, IPMI_COMP_ID);
                iv_errl = NULL;
            }
        }

        // If we had an i/o error we want the idle loop to stop
        // If we got EAGAIN we want the idle loop to stop as we just
        // put a message on the queue which couldn't be sent.
        return (iv_state != 0);
    }
Esempio n. 5
0
    void* consoleDaemon(void* unused)
    {
        // Detach and register daemon with shutdown path.
        task_detach();
        INITSERVICE::registerShutdownEvent(g_msgq, SYNC,
                                           INITSERVICE::CONSOLE_PRIORITY);

        // Create a default output UART device if there isn't already one.
        //    - Some devices are registered via the CONSOLE_UART_DEFINE_DEVICE
        //      macro and therefore don't need this.
        if (NULL == Uart::g_device)
        {
            Uart::g_device = new Uart();
            Uart::g_device->initialize();
        }

        while(1)
        {
            msg_t* msg = msg_wait(g_msgq);

            switch (msg->type)
            {
                case DISPLAY:
                {
                    if (NULL != msg->extra_data)
                    {
                        char timestamp[11];
                        sprintf(timestamp, "%3d.%05d|",
                                msg->data[0],
                                    // 5 Digits worth of ns.
                                (msg->data[1]*100000)/NS_PER_SEC);
                        _display(timestamp);

                        _display(
                            static_cast<const char*>(msg->extra_data));
                        free(msg->extra_data);
                    }
                    msg_free(msg);
                    break;
                }

                case SYNC:
                {
                    msg_respond(g_msgq, msg);
                    break;
                }
            }

        }

        return NULL;
    }
Esempio n. 6
0
//@todo: RTC 119832
void IpmiSEL::execute(void)
{
    //Mark as an independent daemon so if it crashes we terminate.
    task_detach();

    // Register shutdown events with init service.
    //      Done at the "end" of shutdown processesing.
    //      This will flush out any IPMI messages which were sent as
    //      part of the shutdown processing. We chose MBOX priority
    //      as we don't want to accidentally get this message after
    //      interrupt processing has stopped in case we need intr to
    //      finish flushing the pipe.
    INITSERVICE::registerShutdownEvent(iv_msgQ, IPMISEL::MSG_STATE_SHUTDOWN,
                                       INITSERVICE::MBOX_PRIORITY);

    barrier_wait(&iv_sync_start);

    while(true)
    {
        msg_t* msg = msg_wait(iv_msgQ);

        const IPMISEL::msg_type msg_type =
            static_cast<IPMISEL::msg_type>(msg->type);

        // Invert the "default" by checking here. This allows the compiler
        // to warn us if the enum has an unhadled case but still catch
        // runtime errors where msg_type is set out of bounds.
        assert(msg_type <= IPMISEL::MSG_LAST_TYPE,
               "msg_type %d not handled", msg_type);

        switch(msg_type)
        {
            case IPMISEL::MSG_SEND_ESEL:
                IPMISEL::process_esel(msg);
                //done with msg
                msg_free(msg);
                break;

            case IPMISEL::MSG_STATE_SHUTDOWN:
                IPMI_TRAC(INFO_MRK "ipmisel shutdown event");

                //Respond that we are done shutting down.
                msg_respond(iv_msgQ, msg);
                break;
        }
    } // while(1)
    IPMI_TRAC(EXIT_MRK "message loop");
    return;
} // execute
Esempio n. 7
0
///////////////////////////////////////////////////////////////////////////////
// ErrlManager::errlogMsgHndlr()
///////////////////////////////////////////////////////////////////////////////
void ErrlManager::errlogMsgHndlr ()
{
    TRACFCOMP( g_trac_errl, ENTER_MRK "Enter ErrlManager::errlogMsgHndlr" );

    while( 1 )
    {
        msg_t * theMsg = msg_wait( iv_msgQ );
        TRACFCOMP( g_trac_errl, INFO_MRK"Got an error log Msg - Type: 0x%08x",
                                                               theMsg->type );
        //Process message just received
        switch( theMsg->type )
        {
            case ERRLOG_ACCESS_PNOR_TYPE:
                {
                    // PNOR is up and running now.

                    setupPnorInfo();

                    //We are done with the msg
                    msg_free(theMsg);

                    // go back and wait for a next msg
                    break;
                }
            case ERRLOG_ACCESS_TARG_TYPE:
                {
                    // TARGETING is up and running now.

                    //  do we NOT need to send the error?
                    TARGETING::Target * sys = NULL;
                    TARGETING::targetService().getTopLevelTarget( sys );
                    TARGETING::SpFunctions spfn;

                    if (!(sys &&
                          sys->tryGetAttr<TARGETING::ATTR_SP_FUNCTIONS>(spfn) &&
                          spfn.baseServices))
                    {
                        iv_isSpBaseServices = false;

                        // if there are queued errors, clear the Mbox flag
                        // since they will never be sent, which will delete
                        // the errors that have been fully processed
                        ErrlListItr_t it = iv_errlList.begin();
                        while(it != iv_errlList.end())
                        {
                            // Mark MBOX processing complete
                            _clearFlag(*it, MBOX_FLAG);
                            _updateErrlListIter(it);
                        }
                    }

                    //We are done with the msg
                    msg_free(theMsg);

                    // go back and wait for a next msg
                    break;
                }
            case ERRLOG_ACCESS_MBOX_TYPE:
                {
                    // MBOX is up and running now.

                    // do we need to send the errorlog
                    TARGETING::Target * sys = NULL;
                    TARGETING::targetService().getTopLevelTarget( sys );
                    TARGETING::SpFunctions spfn;

                    if (sys &&
                        sys->tryGetAttr<TARGETING::ATTR_SP_FUNCTIONS>(spfn) &&
                        spfn.mailboxEnabled)
                    {
                        iv_isMboxEnabled = true;
                    }

                    // if we're supposed to and can now send msgs, do it.
                    if (iv_isSpBaseServices && iv_isMboxEnabled)
                    {
                        // Register messageQ with Mailbox to receive message.
                        errlHndl_t l_err =
                                MBOX::msgq_register( MBOX::HB_ERROR_MSGQ,
                                                    iv_msgQ );
                        if( l_err )
                        {
                            TRACFCOMP(g_trac_errl, ERR_MRK "Msg queue already registered");

                            delete( l_err );
                            l_err = NULL;

                            //If we got an error then it means the message queue
                            //is registered with mailbox.
                            //This should not happen. So assert here.
                            assert(0);
                        }

                        // if errors came in before MBOX was ready,
                        // the errors would be on this list. send them now.
                        ErrlListItr_t it = iv_errlList.begin();
                        while(it != iv_errlList.end())
                        {
                            // Check if MBOX processing is needed
                            if (_isFlagSet(*it, MBOX_FLAG))
                            {
                                // send errlog
                                sendErrLogToFSP(it->first);
                                // Mark MBOX processing complete
                                _clearFlag(*it, MBOX_FLAG);
                            }
                            _updateErrlListIter(it);
                        }
                    }
                    else
                    {
                        // Delete errors that have been completely processed
                        ErrlListItr_t it = iv_errlList.begin();
                        while(it != iv_errlList.end())
                        {
                            // Mark MBOX processing complete
                            _clearFlag(*it, MBOX_FLAG);
                            _updateErrlListIter(it);
                        }
                    }

                    //We are done with the msg
                    msg_free(theMsg);

                    // go back and wait for a next msg
                    break;
                }
            case ERRLOG_ACCESS_IPMI_TYPE:
                {
#ifdef CONFIG_BMC_IPMI
                    // IPMI is up and running now.
                    iv_isIpmiEnabled = true;

                    // if we can now send msgs, do it.
                    // if errors came in before IPMI was ready,
                    // the errors would be on this list. send them now.
                    ErrlListItr_t it = iv_errlList.begin();
                    while(it != iv_errlList.end())
                    {
                        // Check if IPMI processing is needed
                        if (_isFlagSet(*it, IPMI_FLAG))
                        {
                            // send errorlog
                            sendErrLogToBmc(it->first);
                            // Mark IPMI processing complete
                            _clearFlag(*it, IPMI_FLAG);
                        }
                        _updateErrlListIter(it);
                    }
#endif

                    //We are done with the msg
                    msg_free(theMsg);

                    // go back and wait for a next msg
                    break;
                }
            case ERRLOG_ACCESS_ERRLDISP_TYPE:
                {
#ifdef CONFIG_CONSOLE_OUTPUT_ERRORDISPLAY
                    // Errldisplay now ready
                    iv_isErrlDisplayEnabled = true;

                    CONSOLE::displayf("ERRL",
                        "Dumping errors reported prior to registration");

                    // Display errlogs to errldisplay
                    ErrlListItr_t it = iv_errlList.begin();
                    while(it != iv_errlList.end())
                    {
                        // Check if ERRLDISP processing is needed
                        if (_isFlagSet(*it, ERRLDISP_FLAG))
                        {
                            ERRORLOGDISPLAY::errLogDisplay().msgDisplay
                                        (it->first,
                                        ((it->first->reasonCode()) & 0xFF00));
                            // Mark ERRLDISP processing complete
                            _clearFlag(*it, ERRLDISP_FLAG);
                        }
                        _updateErrlListIter(it);
                    }
#endif
                    //We are done with the msg
                    msg_free(theMsg);

                    break;
                }
            case ERRLOG_NEEDS_TO_BE_COMMITTED_TYPE:
                {
                    // Extract error log handle from the message. We need the
                    // error log handle to pass along
                    errlHndl_t l_err = (errlHndl_t) theMsg->extra_data;

                    // Ask the ErrlEntry to assign commit component, commit time
                    l_err->commit( (compId_t) theMsg->data[0] );

                    // Pair with all flags set to add to the errlList
                    ErrlFlagPair_t l_pair(l_err, ALL_FLAGS);

#ifdef CONFIG_CONSOLE_OUTPUT_ERRORDISPLAY
                    // Display errl to errldisplay
                    if (iv_isErrlDisplayEnabled)
                    {
                        ERRORLOGDISPLAY::errLogDisplay().msgDisplay
                                            (l_err,
                                            ( (l_err->reasonCode()) & 0xFF00));
                        // Mark ERRLDISP processing complete on this error
                        _clearFlag(l_pair, ERRLDISP_FLAG);
                    }
#endif
                    //Save the error log to PNOR
                    bool l_savedToPnor = saveErrLogToPnor(l_err);

                    // Check if we actually saved the msg to PNOR
                    if (l_savedToPnor)
                    {
                        // Mark PNOR processing complete on this error
                        _clearFlag(l_pair, PNOR_FLAG);
                    }

#ifdef STORE_ERRL_IN_L3
                    //Write the error log to L3 memory
                    //useful ONLY for the hb-errl tool
                    saveErrLogEntry ( l_err );
#endif

                    //Try to send the error log if someone is there to receive
                    if (!iv_isSpBaseServices)
                    {
                        // Mark MBOX processing complete on this error
                        _clearFlag(l_pair, MBOX_FLAG);
                    }
                    else if (iv_isSpBaseServices && iv_isMboxEnabled)
                    {
                        sendErrLogToFSP(l_err);

                        // Mark MBOX processing complete on this error
                        _clearFlag(l_pair, MBOX_FLAG);
                    }

#ifdef CONFIG_BMC_IPMI
                    if (iv_isIpmiEnabled)
                    {
                        // convert to SEL/eSEL and send to BMC over IPMI
                        sendErrLogToBmc(l_err);

                        // Mark IPMI processing complete on this error
                        _clearFlag(l_pair, IPMI_FLAG);
                    }
#endif

                    //Ask the ErrlEntry to process any callouts
                    l_err->processCallout();

                    //Ask if it is a terminating log
                    if( l_err->isTerminateLog() )
                    {
                        TRACFCOMP( g_trac_errl, INFO_MRK
                                   "Terminating error was committed"
                                   " errlmanager is reqesting a shutdown.");

                        INITSERVICE::doShutdown(l_err->plid(), true);

                        TRACDCOMP( g_trac_errl,
                                INFO_MRK"shutdown in progress" );
                    }

                    // If l_errl has not been fully proccessed delete it
                    // otherwise add to list
                    if (l_pair.second == 0)
                    {
                        delete l_err;
                        l_err = NULL;
                    }
                    else
                    {
                        iv_errlList.push_back(l_pair);
                    }

                    //We are done with the msg
                    msg_free(theMsg);

                    // else go back and wait for a next msg
                    break;
                }
            case ERRLOG_COMMITTED_ACK_RESPONSE_TYPE:
                {
                    //Hostboot must keep track and clean up hostboot error
                    //logs in PNOR after it is committed by FSP.
                    uint32_t l_tmpPlid = theMsg->data[0]>>32;
                    TRACFCOMP( g_trac_errl, INFO_MRK"ack: %.8x", l_tmpPlid);

                    bool didAck = ackErrLogInPnor(l_tmpPlid);
                    if (!didAck)
                    {
                        // couldn't find that errlog in PNOR, look in our
                        // errlMsgList - maybe it's there waiting
                        ErrlListItr_t it = std::find_if(iv_errlList.begin(),
                                        iv_errlList.end(),
                                        std::bind1st(ptr_fun(&compareEidToPlid)
                                                             ,l_tmpPlid));
                        // Check if such errl was found
                        if (it != iv_errlList.end())
                        {
                            // We found the errlog
                            // Mark PNOR processing complete
                            _clearFlag(*it, PNOR_FLAG);
                            _updateErrlListIter(it);
                        }
                    }

                    msg_free(theMsg);

                    // We didn't have room before in PNOR to save an
                    // error log, so try now since we just ACKed one.
                    ErrlListItr_t it = std::find_if(iv_errlList.begin(),
                                        iv_errlList.end(),
                                        bind2nd(ptr_fun(_isFlagSet),
                                        PNOR_FLAG));

                    // Check if such errl was found
                    if (it != iv_errlList.end())
                    {
                        bool l_savedToPnor = saveErrLogToPnor(it->first);

                        // check if we actually saved the msg to PNOR
                        if (l_savedToPnor)
                        {
                            // Mark PNOR processing complete
                            _clearFlag(*it, PNOR_FLAG);
                            _updateErrlListIter(it);
                        }
                        // else, still couldn't save it (for some reason) so
                        // it's still on the list.
                    }
                    break;
                }
            case ERRLOG_SHUTDOWN_TYPE:
                TRACFCOMP( g_trac_errl, INFO_MRK "Shutdown event received" );

                //Start shutdown process for error log
                errlogShutdown();

                // Respond that we are done shutting down.
                msg_respond ( iv_msgQ, theMsg );

                TRACFCOMP( g_trac_errl, INFO_MRK "Shutdown event processed" );

                break;

            default:
                // Default Message
                TRACFCOMP( g_trac_errl, ERR_MRK "Unexpected message type 0x%08x",
                                                                  theMsg->type );

                msg_free(theMsg);
                break;
        } // switch
    }

    //The errlogMsgHndlr should run all the time. It only
    //exits when error log message thread is killed.
    TRACFCOMP( g_trac_errl, EXIT_MRK "Exit ErrlManager::errlogMsgHndlr" );
    return;
}
Esempio n. 8
0
    errlHndl_t AttributeSync::syncSectionFromFsp(
                                    TARGETING::SECTION_TYPE i_section_to_sync,
                                    msg_q_t i_pMsgQ )
    {
        TARG_INF( ENTER_MRK "AttributeSync::syncSectionFromFsp" );

        errlHndl_t l_errl    = NULL;
        bool l_sync_complete = false;
        ATTR_SYNC_RC l_rc    = ATTR_SYNC_FAILURE;
        TARGETING::sectionRefData l_page;

        iv_section_to_sync = i_section_to_sync;
        memset( &l_page, 0, sizeof(TARGETING::sectionRefData) );

        do{
            if (!SECUREBOOT::allowAttrOverrides())
            {
                TARG_INF("AttributeSync::syncSectionFromFsp(): skipping since "
                         "attribute overrides are not allowed and we don't "
                         "trust the FSP");
                break;
            }

            // send a request to FSP to sync to Hostboot
            l_errl = sendSyncToHBRequestMessage();
            if (l_errl)
            {
                break;
            }

            do{

                // wait for FSP to send the section's attribute data
                TARG_DBG( "Wait for message from FSP");
                msg_t * l_pMsg = msg_wait(i_pMsgQ);

                // process message just received
                if ( ATTR_SYNC_SECTION_TO_HB == l_pMsg->type )
                {
                    TARG_DBG( "HB Attribute Sync Section message type received "
                        "from the FSP");

                    // get the section id
                    l_page.sectionId = ATTR_SYNC_GET_SECTION_ID(l_pMsg->data[0]);

                    // get the page number
                    l_page.pageNumber = ATTR_SYNC_GET_PAGE_NUMBER(l_pMsg->data[0]);

                    // save a pointer to the page
                    l_page.dataPtr =
                        reinterpret_cast<uint8_t *> (l_pMsg->extra_data);

                    // Validate the data received.  Ignore page if
                    // section id or page size is incorrect or if
                    // there are no page received since we cannot send
                    // an error back to the FSP at this point.  We will
                    // check later whether the correct number of valid
                    // pages for the section was received when FSP send
                    // us the sync complete message.

                    // if no page received
                    if ( NULL == l_page.dataPtr)
                    {
                        TARG_ERR("WARNING: "
                            "no attribute page received from FSP");
                    }
                    // if it's not the requested section
                    else if ( iv_section_to_sync != l_page.sectionId )
                    {
                        TARG_ERR("WARNING: "
                            "section type received from FSP = %u, expecting %u",
                            l_page.sectionId, iv_section_to_sync);

                        //Free the memory
                        free(l_pMsg->extra_data);
                        l_pMsg->extra_data = NULL;
                    }
                    // page size should always be 4K
                    else if ( PAGESIZE != l_pMsg->data[1] )
                    {
                        TARG_ERR("WARNING: "
                            "page size received from FSP = %u, expecting 4K",
                            l_pMsg->data[1]);

                        free(l_pMsg->extra_data);
                        l_pMsg->extra_data = NULL;
                    }
                    else
                    {
                        iv_pages.push_back(l_page);
                    }

                    // Free memory allocated for message
                    msg_free( l_pMsg );
                    l_pMsg = NULL;
                }
                else if ( ATTR_SYNC_COMPLETE_TO_HB == l_pMsg->type )
                {
                    TARG_DBG( "HB Attribute Sync Complete message type "
                        "received from the FSP");

                    l_sync_complete = true;

                    iv_total_pages = ATTR_SYNC_GET_PAGE_COUNT( l_pMsg->data[0] );

                    // check that the total # of valid pages received is correct
                    if ( iv_pages.size() == iv_total_pages )
                    {
                        // write the section to the Attribute virtual address
                        // space
                        l_rc = updateSectionData();

                        if (l_rc)
                        {
                            TARG_ERR(
                                "HB failed in writing the attribute section" );
                        }
                    }
                    else
                    {
                        TARG_ERR( "total # of valid pages received = %u, "
                            "expecting %u", iv_pages.size(), iv_total_pages);

                        l_rc = ATTR_SYNC_FAILURE;
                    }

                    if (l_rc)
                    {
                        /*@
                         *   @errortype
                         *   @moduleid      TARG_MOD_ATTR_SYNC
                         *   @reasoncode    TARG_RC_ATTR_SYNC_TO_HB_FAIL
                         *   @userdata1     return code
                         *   @userdata2     section to sync
                         *   @devdesc       The attribute synchronization from
                         *                  the FSP failed.
                         */
                         l_errl = new ErrlEntry(ERRL_SEV_UNRECOVERABLE,
                                                TARG_MOD_ATTR_SYNC,
                                                TARG_RC_ATTR_SYNC_TO_HB_FAIL,
                                                l_rc,
                                                iv_section_to_sync);
                    }

                    // send a msg back to FSP indicating success/failure
                    l_pMsg->data[0] = 0;
                    ATTR_SYNC_ADD_RC( l_rc, l_pMsg->data[0] );
                    int l_respond_rc = msg_respond(i_pMsgQ, l_pMsg);
                    if (l_respond_rc)
                    {
                        // Just output a trace here since FSP should
                        // handle error case where it doesn't receive
                        // a response from HB.
                        TARG_ERR( "WARNING: Bad rc from msg_respond: %d",
                            l_respond_rc);
                        msg_free( l_pMsg );
                        l_pMsg = NULL;
                    }
                }
                else
                {
                    TARG_ERR( "WARNING: Invalid message type [0x%x] received "
                        "from the FSP, ignoring...", l_pMsg->type);
                    msg_free( l_pMsg );
                    l_pMsg = NULL;
                }

            }while (false == l_sync_complete);

            // free memory
            if ( iv_pages.size() )
            {
                for ( size_t i = 0; i < iv_pages.size(); i++ )
                {
                    free( iv_pages[i].dataPtr );
                }

                iv_pages.clear();
            }

        }while (0);

        TARG_INF( EXIT_MRK "AttributeSync::syncSectionFromFsp" );
        return l_errl;
    }
Esempio n. 9
0
/**
 * @brief  Message receiver
 */
void PnorRP::waitForMessage()
{
    TRACFCOMP(g_trac_pnor, "PnorRP::waitForMessage>" );

    errlHndl_t l_errhdl = NULL;
    msg_t* message = NULL;
    uint8_t* user_addr = NULL;
    uint8_t* eff_addr = NULL;
    uint64_t dev_offset = 0;
    uint64_t chip_select = 0xF;
    bool needs_ecc = false;
    int rc = 0;
    uint64_t status_rc = 0;
    uint64_t fatal_error = 0;

    while(1)
    {
        status_rc = 0;
        TRACUCOMP(g_trac_pnor, "PnorRP::waitForMessage> waiting for message" );
        message = msg_wait( iv_msgQ );
        if( message )
        {
            /*  data[0] = virtual address requested
             *  data[1] = address to place contents
             */
            eff_addr = (uint8_t*)message->data[0];
            user_addr = (uint8_t*)message->data[1];

            //figure out the real pnor offset
            l_errhdl = computeDeviceAddr( eff_addr, dev_offset, chip_select, needs_ecc );
            if( l_errhdl )
            {
                status_rc = -EFAULT; /* Bad address */
            }
            else
            {
                switch(message->type)
                {
                    case( MSG_MM_RP_READ ):
                        l_errhdl = readFromDevice( dev_offset,
                                                   chip_select,
                                                   needs_ecc,
                                                   user_addr,
                                                   fatal_error );
                        if( l_errhdl || ( 0 != fatal_error ) )
                        {
                            status_rc = -EIO; /* I/O error */
                        }
                        break;
                    case( MSG_MM_RP_WRITE ):
                        l_errhdl = writeToDevice( dev_offset, chip_select, needs_ecc, user_addr );
                        if( l_errhdl )
                        {
                            status_rc = -EIO; /* I/O error */
                        }
                        break;
                    default:
                        TRACFCOMP( g_trac_pnor, "PnorRP::waitForMessage> Unrecognized message type : user_addr=%p, eff_addr=%p, msgtype=%d", user_addr, eff_addr, message->type );
                        /*@
                         * @errortype
                         * @moduleid     PNOR::MOD_PNORRP_WAITFORMESSAGE
                         * @reasoncode   PNOR::RC_INVALID_MESSAGE_TYPE
                         * @userdata1    Message type
                         * @userdata2    Requested Virtual Address
                         * @devdesc      PnorRP::waitForMessage> Unrecognized
                         *               message type
                         * @custdesc     A problem occurred while accessing
                         *               the boot flash.
                         */
                        l_errhdl = new ERRORLOG::ErrlEntry(
                                           ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                           PNOR::MOD_PNORRP_WAITFORMESSAGE,
                                           PNOR::RC_INVALID_MESSAGE_TYPE,
                                           TO_UINT64(message->type),
                                           (uint64_t)eff_addr,
                                           true /*Add HB SW Callout*/);
                        l_errhdl->collectTrace(PNOR_COMP_NAME);
                        status_rc = -EINVAL; /* Invalid argument */
                }
            }

            if( !l_errhdl && msg_is_async(message) )
            {
                TRACFCOMP( g_trac_pnor, "PnorRP::waitForMessage> Unsupported Asynchronous Message  : user_addr=%p, eff_addr=%p, msgtype=%d", user_addr, eff_addr, message->type );
                /*@
                 * @errortype
                 * @moduleid     PNOR::MOD_PNORRP_WAITFORMESSAGE
                 * @reasoncode   PNOR::RC_INVALID_ASYNC_MESSAGE
                 * @userdata1    Message type
                 * @userdata2    Requested Virtual Address
                 * @devdesc      PnorRP::waitForMessage> Unrecognized message
                 *               type
                 * @custdesc     A problem occurred while accessing the boot
                 *               flash.
                 */
                l_errhdl = new ERRORLOG::ErrlEntry(
                                         ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                         PNOR::MOD_PNORRP_WAITFORMESSAGE,
                                         PNOR::RC_INVALID_ASYNC_MESSAGE,
                                         TO_UINT64(message->type),
                                         (uint64_t)eff_addr,
                                         true /*Add HB SW Callout*/);
                l_errhdl->collectTrace(PNOR_COMP_NAME);
                status_rc = -EINVAL; /* Invalid argument */
            }

            if( l_errhdl )
            {
                errlCommit(l_errhdl,PNOR_COMP_ID);
            }


            /*  Expected Response:
             *      data[0] = virtual address requested
             *      data[1] = rc (0 or negative errno value)
             *      extra_data = Specific reason code.
             */
            message->data[1] = status_rc;
            message->extra_data = reinterpret_cast<void*>(fatal_error);
            rc = msg_respond( iv_msgQ, message );
            if( rc )
            {
                TRACFCOMP(g_trac_pnor, "PnorRP::waitForMessage> Error from msg_respond, giving up : rc=%d", rc );
                break;
            }
        }
    }


    TRACFCOMP(g_trac_pnor, "< PnorRP::waitForMessage" );
}