From ca6dcccbcd8e234fa6064d334800609141ec1de6 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Tue, 13 Sep 2011 13:26:19 -0500 Subject: Attribute Resource Provider. Change-Id: I731b19ea027393e375993136f125fff2f6fb31e9 Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/351 Tested-by: Jenkins Server Reviewed-by: Nicholas E. Bofferding Reviewed-by: Daniel M. Crowell Reviewed-by: A. Patrick Williams III --- src/usr/targeting/attrrp.C | 438 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 438 insertions(+) create mode 100644 src/usr/targeting/attrrp.C (limited to 'src/usr/targeting/attrrp.C') diff --git a/src/usr/targeting/attrrp.C b/src/usr/targeting/attrrp.C new file mode 100644 index 000000000..5de7fafcc --- /dev/null +++ b/src/usr/targeting/attrrp.C @@ -0,0 +1,438 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/targeting/attrrp.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2011 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#include +#include +#include +#include +#include +#include +#include + +#include +#include "attrrp.H" +#include "trace.H" + +using namespace INITSERVICE; +using namespace ERRORLOG; + +namespace TARGETING +{ + /** @struct AttrRP_Section + * @brief Contains parsed information about each attribute section. + */ + struct AttrRP_Section + { + /** Section type. */ + SECTION_TYPE type; + /** Desired address in Attribute virtual address space. */ + uint64_t vmmAddress; + /** Location in PNOR virtual address space. */ + uint64_t pnorAddress; + /** Section size. */ + uint64_t size; + }; + + void AttrRP::init(TaskArgs* i_taskArgs) + { + // Call startup on singleton instance. + Singleton::instance().startup(i_taskArgs); + } + + void AttrRP::startMsgServiceTask(void* i_instance) + { + // Call msgServiceTask loop on instance. + assert(i_instance); + static_cast(i_instance)->msgServiceTask(); + } + + AttrRP::~AttrRP() + { + if (iv_sections) + { + delete[] iv_sections; + } + msg_q_destroy(iv_msgQ); + + assert(false); + } + + void AttrRP::startup(TaskArgs* i_taskArgs) + { + errlHndl_t l_errl = NULL; + + do + { + // Parse PNOR headers. + l_errl = this->parseAttrSectHeader(); + if (l_errl) break; + + // Create corresponding VMM blocks for each section. + l_errl = this->createVmmSections(); + if (l_errl) break; + + // Spawn daemon thread. + task_create(&AttrRP::startMsgServiceTask, this); + + } while (false); + + // If an error occured, post to TaskArgs. + if (l_errl) + { + l_errl->setSev(ERRORLOG::ERRL_SEV_UNRECOVERABLE); + if (i_taskArgs) + { + i_taskArgs->postErrorLog(l_errl); + } + else + { + TRACFCOMP(g_trac_targeting, + ERR_MRK "AttrRP: Critical error in startup and no " + "TaskArgs given by init-service."); + errlCommit(l_errl); + } + } + } + + void AttrRP::msgServiceTask() const + { + TRACFCOMP(g_trac_targeting, ENTER_MRK "AttrRP::msgServiceTask"); + + // Daemon loop. + while(1) + { + int rc = 0; + + // Wait for message. + msg_t* msg = msg_wait(iv_msgQ); + if (!msg) continue; + + // Parse message data members. + uint64_t vAddr = msg->data[0]; + void* pAddr = reinterpret_cast(msg->data[1]); + + TRACFCOMP(g_trac_targeting, INFO_MRK "AttrRP: Message recv'd: " + "%d, %lx %p", msg->type, vAddr, pAddr); + + // Locate corresponding attribute section for message. + ssize_t section = -1; + for (size_t i = 0; i < iv_sectionCount; i++) + { + if ((vAddr >= iv_sections[i].vmmAddress) && + (vAddr < iv_sections[i].vmmAddress + iv_sections[i].size)) + { + section = i; + break; + } + } + + // Return EINVAL if no section was found. Kernel bug? + if (section == -1) + { + rc = -EINVAL; + TRACFCOMP(g_trac_targeting, + ERR_MRK "AttrRP: Address given outside section " + "ranges: %p", + vAddr); + } + else // Process request. + { + + // Determine PNOR offset and page size. + uint64_t offset = vAddr - iv_sections[section].vmmAddress; + uint64_t size = std::min(PAGE_SIZE, + iv_sections[section].vmmAddress + + iv_sections[section].size - + vAddr); + // We could be requested to read/write less than a page + // if the virtual address requested is at the end of the + // section and the section size is not page aligned. + // + // Example: Section size is 6k and vAddr = vmmAddr + 4k, + // we should only operate on 2k of content. + + + // Read / Write message behavior. + switch(msg->type) + { + case MSG_MM_RP_READ: + // HEAP_ZERO_INIT should never be requested for read + // because kernel should automatically get a zero page. + if (iv_sections[section].type == + SECTION_TYPE_HEAP_ZERO_INIT) + { + TRACFCOMP(g_trac_targeting, + ERR_MRK "AttrRP: Read request on " + "HEAP_ZERO section."); + rc = -EINVAL; + break; + } + // Do memcpy from PNOR into physical page. + memcpy(pAddr, + reinterpret_cast( + iv_sections[section].pnorAddress + offset), + size); + break; + + case MSG_MM_RP_WRITE: + // Only PNOR_RW should ever be requested for write-back + // because others are not allowed to be pushed back to + // PNOR. + if (iv_sections[section].type != + SECTION_TYPE_PNOR_RW) + { + TRACFCOMP(g_trac_targeting, + ERR_MRK "AttrRP: Write request on " + "non-PNOR_RW section."); + rc = -EINVAL; + break; + } + // Do memcpy from physical page into PNOR. + memcpy(reinterpret_cast( + iv_sections[section].pnorAddress + offset), + pAddr, + size); + break; + + default: + TRACFCOMP(g_trac_targeting, + ERR_MRK "AttrRP: Unhandled command type %d.", + msg->type); + rc = -EINVAL; + break; + } + } + + // Log an error log if the AttrRP was unable to handle a message + // for any reason. + if (rc != 0) + { + /*@ + * @errortype + * @moduleid TARG_MOD_ATTRRP + * @reasoncode TARG_RC_ATTR_MSG_FAIL + * @userdata1 Virtual Address + * @userdata2 (Msg Type << 32) | Section # + * + * @devdesc The Attribute Resource Provider was unable to + * satisfy a message request from the VMM portion + * of the kernel. This was either due to an + * address outside a valid range or a message + * request that is invalid for the attribute + * section containing the address. + */ + errlHndl_t l_errl = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, + TARG_MOD_ATTRRP, + TARG_RC_ATTR_MSG_FAIL, + vAddr, + TWO_UINT32_TO_UINT64( + msg->type, + section) + ); + errlCommit(l_errl); + + } + + // Respond to kernel request. + msg->data[1] = rc; + rc = msg_respond(iv_msgQ, msg); + if (rc) + { + TRACFCOMP(g_trac_targeting, + ERR_MRK "AttrRP: Bad rc from msg_respond: %d", rc); + } + } + } + + errlHndl_t AttrRP::parseAttrSectHeader() + { + errlHndl_t l_errl = NULL; + + do + { + // Locate attribute section in PNOR. + PNOR::SectionInfo_t l_pnorSectionInfo; + l_errl = PNOR::getSectionInfo(PNOR::HB_DATA, + PNOR::SIDE_A, + l_pnorSectionInfo); + if (l_errl) break; + + // Find attribute section header. + TargetingHeader* l_header = + reinterpret_cast(l_pnorSectionInfo.vaddr); + + // Validate eye catch. + if (l_header->eyeCatcher != PNOR_TARG_EYE_CATCHER) + { + /*@ + * @errortype + * @moduleid TARG_MOD_ATTRRP + * @reasoncode TARG_RC_BAD_EYECATCH + * @userdata1 Observed Header Eyecatch Value + * @userdata2 Expected Eyecatch Value + * + * @devdesc The eyecatch value observed in PNOR does not + * match the expected value of + * PNOR_TARG_EYE_CATCHER and therefore the + * contents of the Attribute PNOR section are + * unable to be parsed. + */ + l_errl = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, + TARG_MOD_ATTRRP, + TARG_RC_BAD_EYECATCH, + l_header->eyeCatcher, + PNOR_TARG_EYE_CATCHER); + break; + } + + // Allocate section structures based on section count in header. + iv_sectionCount = l_header->numSections; + iv_sections = new AttrRP_Section[iv_sectionCount]; + + // Find start to first section: + // (PNOR addr + size of header + offset in header). + TargetingSection* l_section = + reinterpret_cast( + l_pnorSectionInfo.vaddr + sizeof(TargetingHeader) + + l_header->offsetToSections + ); + + // Parse each section. + for (size_t i = 0; i < iv_sectionCount; i++, l_section++) + { + iv_sections[i].type = l_section->sectionType; + iv_sections[i].vmmAddress = + reinterpret_cast(l_header->vmmBaseAddress) + + l_header->vmmSectionOffset*i; + iv_sections[i].pnorAddress = l_pnorSectionInfo.vaddr + + l_section->sectionOffset; + iv_sections[i].size = l_section->sectionSize; + + TRACDCOMP(g_trac_targeting, + "Decoded Attribute Section: %d, %lx %lx %d", + iv_sections[i].type, + iv_sections[i].vmmAddress, + iv_sections[i].pnorAddress, + iv_sections[i].size); + + } + + } while (false); + + return l_errl; + + } + + errlHndl_t AttrRP::createVmmSections() + { + errlHndl_t l_errl = NULL; + + do + { + // Allocate message queue for VMM requests. + iv_msgQ = msg_q_create(); + + // Create VMM block for each section, assign permissions. + for (size_t i = 0; i < iv_sectionCount; i++) + { + int rc = 0; + + rc = mm_alloc_block(iv_msgQ, + reinterpret_cast( + iv_sections[i].vmmAddress), + iv_sections[i].size); + if (rc) + { + /*@ + * @errortype + * @moduleid TARG_MOD_ATTRRP + * @reasoncode TARG_RC_MM_BLOCK_FAIL + * @userdata1 vAddress attempting to allocate. + * @userdata2 RC from kernel. + * + * @devdesc While attempting to allocate a virtual + * memory block for an attribute section, the + * kernel returned an error. + */ + l_errl = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, + TARG_MOD_ATTRRP, + TARG_RC_MM_BLOCK_FAIL, + iv_sections[i].vmmAddress, + rc); + break; + } + + uint64_t l_perm = 0; + switch(iv_sections[i].type) + { + case SECTION_TYPE_PNOR_RO: + l_perm = READ_ONLY; + break; + + case SECTION_TYPE_PNOR_RW: + l_perm = WRITABLE | WRITE_TRACKED; + break; + + case SECTION_TYPE_HEAP_PNOR_INIT: + l_perm = WRITABLE; + break; + + case SECTION_TYPE_HEAP_ZERO_INIT: + l_perm = WRITABLE | ALLOCATE_FROM_ZERO; + break; + } + + rc = mm_set_permission(reinterpret_cast( + iv_sections[i].vmmAddress), + iv_sections[i].size, + l_perm); + + if (rc) + { + /*@ + * @errortype + * @moduleid TARG_MOD_ATTRRP + * @reasoncode TARG_RC_MM_PERM_FAIL + * @userdata1 vAddress attempting to allocate. + * @userdata2 (kernel-rc << 32) | (Permissions) + * + * @devdesc While attempting to set permissions on + * a virtual memory block for an attribute + * section, the kernel returned an error. + */ + l_errl = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, + TARG_MOD_ATTRRP, + TARG_RC_MM_PERM_FAIL, + iv_sections[i].vmmAddress, + TWO_UINT32_TO_UINT64(rc, l_perm)); + break; + } + + } + if (l_errl) break; // Catch errorlog fall-outs from inside for-loop. + + } while (false); + + return l_errl; + } + +}; -- cgit v1.2.1