示例#1
0
//------------------------------------------------------------------------------
// Hardware callout
ErrlUserDetailsCallout::ErrlUserDetailsCallout(
        const void *i_pTargetData,
        uint32_t i_targetDataLength,
        const HWAS::callOutPriority i_priority,
        const HWAS::DeconfigEnum i_deconfigState,
        const HWAS::GARD_ErrorType i_gardErrorType)
{
    TRACDCOMP(g_trac_errl, "HWCallout entry");

    // Set up ErrlUserDetails instance variables
    iv_CompId = ERRL_COMP_ID;
    iv_Version = 1;
    iv_SubSection = ERRL_UDT_CALLOUT;

    //iv_merge = false; // use the default of false

    uint32_t pDataLength = sizeof(HWAS::callout_ud_t) + i_targetDataLength;
    HWAS::callout_ud_t *pData;
    pData = reinterpret_cast<HWAS::callout_ud_t *>
                (reallocUsrBuf(pDataLength));
    pData->type = HWAS::HW_CALLOUT;
    pData->priority = i_priority;
#ifndef __HOSTBOOT_RUNTIME
    pData->cpuid = task_getcpuid();
#else
    pData->cpuid = (uint32_t)(-1);
#endif
    pData->deconfigState = i_deconfigState;
    pData->gardErrorType = i_gardErrorType;
    memcpy(pData + 1, i_pTargetData, i_targetDataLength);

    TRACDCOMP(g_trac_errl, "HWCallout exit; pDataLength %d", pDataLength);

} // Hardware callout
示例#2
0
文件: xscom.C 项目: AmesianX/hostboot
/**
 * @brief Get the Virtual Address of the XSCOM space for the processor
 *  associated with this thread (the source chip)
 *
 * @return uint64_t* virtualAddress
 */
uint64_t* getCpuIdVirtualAddress()
{
    uint64_t* o_virtAddr = 0;

    // Get the CPU core this thread is running on
    uint32_t cpuid = task_getcpuid();

    //NNNCCCPPPPTTT format fot the cpuid..
    //  N = node, C = chip, P = proc, T = thread
    uint32_t chipId = (cpuid & 0x0380)>>7;
    uint32_t nodeId = (cpuid & 0x1C00)>>10;

    // Can change the above hardcoded values to either a macro or use
    // the info below to do the masking and shifting.
    // uint64_t max_threads = cpu_thread_count();
    // for the number of Chips  - use  g_xscomMaxChipsPerNode instead..
    // For the number of Procs.. MAX_PROCS_RSV = P8_MAX_PROCS*2
    // P8_MAX_PROCS = 8 -- space left for 2* that.

    XSComBase_t l_systemBaseAddr = MASTER_PROC_XSCOM_BASE_ADDR;

    // Target's XSCOM Base address
    XSComBase_t l_XSComBaseAddr = l_systemBaseAddr +
      ( ( (g_xscomMaxChipsPerNode * nodeId) +
          chipId ) * THIRTYTWO_GB);

    // Target's virtual address
    o_virtAddr = static_cast<uint64_t*>
      (mmio_dev_map(reinterpret_cast<void*>(l_XSComBaseAddr),
                    THIRTYTWO_GB));

    TRACDCOMP(g_trac_xscom, "getCpuIdVirtualAddress: o_Virtual Address   =  0x%llX\n",o_virtAddr);

    return o_virtAddr;

}
示例#3
0
文件: drtm.C 项目: wghoffa/hostboot
errlHndl_t initiateDrtm()
{
    SB_ENTER("initiateDrtm");

    errlHndl_t pError = nullptr;

    // For DRTM, the thread has to be pinned to a core (and therefore pinned to
    // a chip)
    task_affinity_pin();

    void* drtmPayloadVirtAddr = nullptr;

    do
    {
        const std::vector<SECUREBOOT::ProcSecurity> LLP {
            SECUREBOOT::ProcSecurity::LLPBit,
        };

        const std::vector<SECUREBOOT::ProcSecurity> LLS {
            SECUREBOOT::ProcSecurity::LLSBit,
        };

        // Determine which fabric group and chip this task is executing on and
        // create a filter to find the matching chip target
        auto cpuId = task_getcpuid();
        auto groupId = PIR_t::groupFromPir(cpuId);
        auto chipId = PIR_t::chipFromPir(cpuId);
        TARGETING::PredicateAttrVal<TARGETING::ATTR_FABRIC_GROUP_ID>
            matchesGroup(groupId);
        TARGETING::PredicateAttrVal<TARGETING::ATTR_FABRIC_CHIP_ID>
            matchesChip(chipId);
        TARGETING::PredicatePostfixExpr matchesGroupAndChip;
        matchesGroupAndChip.push(&matchesGroup).push(&matchesChip).And();

        // Get all the functional proc chips and find the chip we're running on
        TARGETING::TargetHandleList funcProcChips;
        TARGETING::getAllChips(funcProcChips,
                               TARGETING::TYPE_PROC);
        if(funcProcChips.empty())
        {
            // TODO: RTC 167205: GA error handling
            assert(false,"initiateDrtm: BUG! Functional proc chips is empty, "
                "yet this code is running on a functional chip!");
            break;
        }

        // NOTE: std::find_if requires predicates to be copy constructable, but
        // predicates are not; hence use a wrapper lambda function to bypass
        // that limitation
        auto pMatch =
            std::find_if(funcProcChips.begin(),funcProcChips.end(),
                [&matchesGroupAndChip] ( TARGETING::Target* pTarget )
                {
                    return matchesGroupAndChip(pTarget);
                } );

        if(pMatch == funcProcChips.end())
        {
            // TODO: RTC 167205: GA error handling
            assert(false, "initiateDrtm: BUG! No functional chip found "
                "to be running this code");
            break;
        }

        // Move the matching target to the end of the list.
        // NOTE: If reverse iterators were supported, we could have verified the
        // last element of the container is not the match, and done a
        // std::iter_swap of the match and the last element
        TARGETING::Target* const pMatchTarget = *pMatch;
        funcProcChips.erase(pMatch);
        funcProcChips.push_back(pMatchTarget);

        // Map to the DRTM payload area in mainstore
        const uint32_t drtmPayloadPhysAddrMb = DRTM_RIT_PAYLOAD_PHYS_ADDR_MB;
        drtmPayloadVirtAddr = mm_block_map(
            reinterpret_cast<void*>(drtmPayloadPhysAddrMb*BYTES_PER_MEGABYTE),
            PAGESIZE);
        if(drtmPayloadVirtAddr == nullptr)
        {
            // TODO: RTC 167205: GA error handling
            assert(false, "initiateDrtm: BUG! Failed in call to mm_block_map "
                "to map the DRTM payload.");
            break;
        }

        // Copy the DRTM payload to the DRTM payload area
        memcpy(
            reinterpret_cast<uint32_t*>(drtmPayloadVirtAddr),
            DRTM_RIT_PAYLOAD,
            sizeof(DRTM_RIT_PAYLOAD));

        // The required generic sequencing to initiate DRTM is as follows:
        // 1) Initiating task must pin itself to a core (to ensure it
        //     will not be accidentally queisced by SBE)
        // 2) It must set the DRTM payload information in the master processor
        //     mailbox scratch registers (registers 7 and 8) before it goes
        //     offline
        // 3) It must determine the processor it's currently running on
        // 4) It must set the late launch bit (LL) on all other processors
        //     4a) If the given processor is an active master, it must set
        //         late launch primary (LLP) bit
        //     4b) Otherwise it must set late launch secondary (LLS) bit
        // 5) Finally, it must its own processor's LL bit last, according to the
        //     rules of step 4.
        for(auto &pFuncProc :funcProcChips)
        {
            const auto procMasterType = pFuncProc->getAttr<
                TARGETING::ATTR_PROC_MASTER_TYPE>();

            // If master chip, set the DRTM payload address and validity
            if(procMasterType == TARGETING::PROC_MASTER_TYPE_ACTING_MASTER)
            {
                (void)setDrtmPayloadPhysAddrMb(drtmPayloadPhysAddrMb);
            }

            pError = SECUREBOOT::setSecuritySwitchBits(procMasterType ==
                         TARGETING::PROC_MASTER_TYPE_ACTING_MASTER ?
                            LLP : LLS,
                         pFuncProc);
            if(pError)
            {
                SB_ERR("initiateDrtm: setSecuritySwitchBits() failed for proc "
                    "= 0x%08X. Tried to set LLP or LLS.",
                    get_huid(pFuncProc));
                break;
            }
        }

        if(pError)
        {
            break;
        }


        SB_INF("initiateDrtm: SBE should eventually quiesce all cores; until "
            "then, endlessly yield the task");
        while(1)
        {
            task_yield();
        }

    } while(0);

    // If we -do- come back from this function (on error path only), then we
    // should unpin
    task_affinity_unpin();

    if(drtmPayloadVirtAddr)
    {
        auto rc = mm_block_unmap(const_cast<void*>(drtmPayloadVirtAddr));
        if(rc != 0)
        {
            // TODO: RTC 167205: GA error handling
            assert(false,"initiateDrtm: BUG! mm_block_unmap failed for virtual "
                "address 0x%16llX.",
                drtmPayloadVirtAddr);
        }
    }

    if(pError)
    {
        SB_ERR("initiateDrtm: plid=0x%08X, eid=0x%08X, reason=0x%04X",
               ERRL_GETPLID_SAFE(pError),
               ERRL_GETEID_SAFE(pError),
               ERRL_GETRC_SAFE(pError));
    }

    SB_EXIT("initiateDrtm");

    return pError;
}
示例#4
0
文件: xscom.C 项目: wghoffa/hostboot
/**
 * @brief Get the virtual address of the input target
 *        for an XSCOM access.
 *
 * Logic:
 *
 * If sentinel:
 *      If never XSCOM to sentinel
 *          Calculate virtual addr for sentinel
 *          Save it to g_masterProcVirtAddr for future XSCOM to sentinel
 *      Else
 *          Use virtual addr stored in g_masterProcVirtAddr
 *      End if
 * Else (not sentinel)
 *      If never XSCOM to this chip:
 *          If this is a master processor object
 *              Use virtual addr stored for sentinel (g_masterProcVirtAddr)
 *          Else
 *              Call mmio_dev_map() to get virtual addr for this slave proc
 *          End if
 *          Save virtual addr used to this chip's attribute
 *      Else
 *          Use virtual address stored in this chip's attributes.
 *      End if
 * End if
 *
 * @param[in]   i_target        XSCom target
 * @param[out]  o_virtAddr      Target's virtual address
 *
 * @return errlHndl_t
 */
errlHndl_t getTargetVirtualAddress(TARGETING::Target* i_target,
                                   uint64_t*& o_virtAddr)
{
    errlHndl_t l_err = NULL;
    o_virtAddr = NULL;
    XSComBase_t l_XSComBaseAddr = 0;

    do
    {

        // Find out if the target pointer is the master processor chip
        bool l_isMasterProcChip = false;

        if (i_target == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL)
        {
            // Sentinel pointer representing the master processor chip
            l_isMasterProcChip = true;
        }
        else
        {
            TARGETING::Target* l_pMasterProcChip = NULL;
            TARGETING::targetService().
                masterProcChipTargetHandle(l_pMasterProcChip);

            if (i_target == l_pMasterProcChip)
            {
                // Target Service reports that this is the master processor chip
                l_isMasterProcChip = true;
            }
        }


        // If the target is the master processor chip sentinel
        if (l_isMasterProcChip)
        {

            // This is the master processor chip. The virtual address is
            // g_masterProcVirtAddr. If this is NULL then initialize it

            // Use atomic update instructions here to avoid
            // race condition between different threads.
            // Keep in mind that the mutex used in XSCOM is hardware mutex,
            // not a mutex for the whole XSCOM logic.
            if (__sync_bool_compare_and_swap(&g_masterProcVirtAddr,
                                     NULL, NULL))
            {
                // Note: can't call TARGETING code prior to PNOR being
                // brought up.
                uint64_t l_mmioAddr = 0;
                uint64_t* l_tempVirtAddr = getCpuIdVirtualAddress(l_mmioAddr);
                if (!__sync_bool_compare_and_swap(&g_masterProcVirtAddr,
                                         NULL, l_tempVirtAddr))
                {
                    // If g_masterProcVirtAddr has already been updated by
                    // another thread, we need to unmap the dev_map we just
                    // called above.
                    int rc = 0;
                    rc =  mmio_dev_unmap(reinterpret_cast<void*>
                                        (l_tempVirtAddr));
                    if (rc != 0)
                    {
                        /*@
                         * @errortype
                         * @moduleid     XSCOM_GET_TARGET_VIRT_ADDR
                         * @reasoncode   XSCOM_MMIO_UNMAP_ERR
                         * @userdata1    Return Code
                         * @userdata2    Unmap address
                         * @devdesc      mmio_dev_unmap() returns error
                         * @custdesc     A problem occurred during the IPL
                         *               of the system.
                         */
                        l_err = new ERRORLOG::ErrlEntry(
                                ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                XSCOM_GET_TARGET_VIRT_ADDR,
                                XSCOM_MMIO_UNMAP_ERR,
                                rc,
                                reinterpret_cast<uint64_t>(l_tempVirtAddr),
                                true /*Add HB Software Callout*/);
                        break;
                    }
                }
                else
                {
                    TRACFCOMP(g_trac_xscom,
                              "Master Proc : pir=%.8X, mmio=0x%0.16llX, virt=0x%llX",
                              task_getcpuid(),
                              l_mmioAddr,
                              reinterpret_cast<uint64_t>(l_tempVirtAddr));
                }
            }

            // Set virtual address to sentinel's value
            o_virtAddr = g_masterProcVirtAddr;
        }
        else // This is not the master sentinel
        {

            // Get the virtual addr value of the chip from the virtual address
            // attribute
            o_virtAddr =
              reinterpret_cast<uint64_t*>(
                i_target->getAttr<TARGETING::ATTR_XSCOM_VIRTUAL_ADDR>());


            // If the virtual address equals NULL(default) then this is the
            // first XSCOM to this target so we need to map in the appropriate
            // address
            if (o_virtAddr == NULL)
            {
                uint64_t  xscomGroupId = 0;
                uint64_t  xscomChipId = 0;

                // Get the target Group Id
                xscomGroupId =
                  i_target->getAttr<TARGETING::ATTR_FABRIC_GROUP_ID>();

                // Get the target Chip Id
                xscomChipId =
                  i_target->getAttr<TARGETING::ATTR_FABRIC_CHIP_ID>();

                // Get assigned XSCOM base address
                l_XSComBaseAddr =
                  i_target->getAttr<TARGETING::ATTR_XSCOM_BASE_ADDRESS>();

                TRACFCOMP(g_trac_xscom,
                          "Target %.8X :: Group:%d Chip:%d :: XscomBase:0x%llX",
                          TARGETING::get_huid(i_target),
                          xscomGroupId,
                          xscomChipId,
                          l_XSComBaseAddr);

                // Target's virtual address
                o_virtAddr = static_cast<uint64_t*>
                    (mmio_dev_map(reinterpret_cast<void*>(l_XSComBaseAddr),
                      THIRTYTWO_GB));

                TRACDCOMP(g_trac_xscom, "xscomPerformOp: o_Virtual Address   =  0x%llX\n",o_virtAddr);

                // Implemented the virtual address attribute..

                // Leaving the comments as a discussion point...
                // Technically there is a race condition here. The mutex is
                // a per-hardware thread mutex, not a mutex for the whole XSCOM
                // logic. So there is possibility that this same thread is running
                // on another thread at the exact same time. We can use atomic
                // update instructions here.
                // Future note : This is a good candidate for having a way
                // to return a reference to the attribute instead of requiring
                // to call setAttr. We currently have no way to SMP-safely update
                // this attribute, where as if we had a reference to it we could use
                // the atomic update functions (_sync_bool_compare_and_swap in
                // this case.

                // Save the virtual address attribute.
                i_target->setAttr<TARGETING::ATTR_XSCOM_VIRTUAL_ADDR>(
                                        reinterpret_cast<uint64_t>(o_virtAddr));

            }
        }

    } while (0);

    return l_err;
}