diff options
author | Patrick Williams <iawillia@us.ibm.com> | 2011-09-13 13:26:19 -0500 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2011-09-23 11:21:59 -0500 |
commit | ca6dcccbcd8e234fa6064d334800609141ec1de6 (patch) | |
tree | ff43b4a828f08c9cf347b92d0af91b15fe96b6a4 /src/usr | |
parent | afa3bc7aa8ce1a128b6785907d3e96792b49a4ef (diff) | |
download | talos-hostboot-ca6dcccbcd8e234fa6064d334800609141ec1de6.tar.gz talos-hostboot-ca6dcccbcd8e234fa6064d334800609141ec1de6.zip |
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 <bofferdn@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/usr')
-rw-r--r-- | src/usr/targeting/attrrp.C | 438 | ||||
-rw-r--r-- | src/usr/targeting/attrrp.H | 125 | ||||
-rw-r--r-- | src/usr/targeting/makefile | 7 | ||||
-rw-r--r-- | src/usr/targeting/targetservice.C | 13 | ||||
-rwxr-xr-x | src/usr/targeting/xmltohb/xmltohb.pl | 3 |
5 files changed, 579 insertions, 7 deletions
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 <util/singleton.H> +#include <pnortargeting.H> +#include <pnor/pnorif.H> +#include <sys/mm.h> +#include <errno.h> +#include <string.h> +#include <algorithm> + +#include <targeting/targreasoncodes.H> +#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<AttrRP>::instance().startup(i_taskArgs); + } + + void AttrRP::startMsgServiceTask(void* i_instance) + { + // Call msgServiceTask loop on instance. + assert(i_instance); + static_cast<AttrRP*>(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<void*>(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<void*>( + 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<void*>( + 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<TargetingHeader*>(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<TargetingSection*>( + 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<uint64_t>(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<void*>( + 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<void*>( + 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; + } + +}; diff --git a/src/usr/targeting/attrrp.H b/src/usr/targeting/attrrp.H new file mode 100644 index 000000000..9c338114f --- /dev/null +++ b/src/usr/targeting/attrrp.H @@ -0,0 +1,125 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/targeting/attrrp.H $ +// +// 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 +#ifndef __TARGETING_ATTRRP_H +#define __TARGETING_ATTRRP_H + +#include <initservice/taskargs.H> +#include <sys/msg.h> + +namespace TARGETING +{ + + // Forward declaration of attribute section parsed information structure. + struct AttrRP_Section; + + /** @class AttrRP + * @brief Attribute Resource Provider daemon class. + * + * Provides all the functionality to translate between PNOR and Attribute + * virtual memory spaces. Parses PNOR header for attribute sections, + * allocates virtual memory spaces with the kernel for each section, and + * handles virtual memory request messages from the kernel. + */ + class AttrRP + { + public: + /** @brief Initializes and starts the AttrRP daemon. + * @param[in] i_taskArgs - Pointer to init service arguments. + * + * @note If any error occurs during initialization, it will be + * reported back through the TaskArgs structure to the init + * service. + */ + static void init(INITSERVICE::TaskArgs* i_taskArgs); + + protected: + /** @brief Default constructor. + * Ensures member variables are initialized to sane values. + */ + AttrRP() : + iv_msgQ(NULL), iv_sections(NULL), iv_sectionCount(0) + { }; + + /** @brief Default destructor. + * Frees any memory allocated by the daemon. + * + * @note This should never actually be used because the daemon + * thread and the vmm blocks are unable to be reclaimed. + * Function will assert if called due to leaky behavior. + */ + ~AttrRP(); + + private: + /** @brief Performs the startup of the daemon instance. + * + * init() is a static function that just calls + * Singleton<AttrRP>::instance().startup(). See init for behavior. + */ + void startup(INITSERVICE::TaskArgs* i_taskArgs); + + /** @brief Daemon thread processing function. + * + * Performs a while(1) waiting for messages from the kernel/VMM + * and handles as appropriately. Reads / writes data from / to + * PNOR for the attribute sections. + */ + void msgServiceTask() const; + + /** @brief Parses the attribute section header in PNOR. + * + * Constructs the local attribute section data structures + * (iv_sections / iv_sectionCount). + * + * @return errlHndl_t - Error log if error occurs. + */ + errlHndl_t parseAttrSectHeader(); + + /** @brief Allocates VMM sections for each Attribute section. + * + * Calls to the kernel to create vmm blocks for each attribute + * and initializes permissions appropriately based on section + * type. + * + * @return errlHndl_t - Error log if error occurs. + */ + errlHndl_t createVmmSections(); + + /** @brief Redirect to msgServiceTask on the AttrRP instance. + * + * This function, being static, can be called from task_create + * and is used to enter the daemon thread's msgServiceTask loop. + * + * @param[in] i_instance - The AttrRP to call msgServiceTask on. + */ + static void startMsgServiceTask(void* i_instance); + + /** Message Queue for VMM requests. */ + msg_q_t iv_msgQ; + /** Parsed structures of the attribute sections. */ + AttrRP_Section* iv_sections; + /** Count of attribute sections. */ + size_t iv_sectionCount; + }; +}; + +#endif diff --git a/src/usr/targeting/makefile b/src/usr/targeting/makefile index 1c26396f6..ab84a4e05 100644 --- a/src/usr/targeting/makefile +++ b/src/usr/targeting/makefile @@ -39,9 +39,12 @@ ITERATORS_OBJS = \ TARGET_OBJS = \ target.o \ targetservice.o \ - entitypath.o + entitypath.o -OBJS = ${TARGET_OBJS} ${PREDICATES_OBJS} ${ITERATORS_OBJS} +ATTR_RP_OBJS = \ + attrrp.o + +OBJS = ${TARGET_OBJS} ${PREDICATES_OBJS} ${ITERATORS_OBJS} ${ATTR_RP_OBJS} SUBDIRS = test.d xmltohb.d diff --git a/src/usr/targeting/targetservice.C b/src/usr/targeting/targetservice.C index 497807348..166fb34f8 100644 --- a/src/usr/targeting/targetservice.C +++ b/src/usr/targeting/targetservice.C @@ -47,6 +47,7 @@ #include "trace.H" #include <targeting/predicates/predicatebase.H> #include <pnortargeting.H> +#include "attrrp.H" //****************************************************************************** // targetService @@ -84,8 +85,12 @@ void _start(void* io_pArgs) TARG_ENTER(); - TargetService& l_targetService = targetService(); - (void)l_targetService.init(); + AttrRP::init(pTaskArgs); + if (( pTaskArgs ) && (!pTaskArgs->getErrorLog())) + { + TargetService& l_targetService = targetService(); + (void)l_targetService.init(); + } TARG_EXIT(); @@ -172,7 +177,7 @@ void TargetService::init() iv_associationMappings.push_back(a6); // Get+save pointer to beginning of targeting's swappable config in - // PNOR. + // PNOR. //@TODO Fully account for the attribute resource provider PNOR::SectionInfo_t l_sectionInfo; errlHndl_t l_pElog = PNOR::getSectionInfo( @@ -187,7 +192,7 @@ void TargetService::init() TargetingHeader* l_pHdr = reinterpret_cast<TargetingHeader*>( l_sectionInfo.vaddr); assert(l_pHdr->eyeCatcher == PNOR_TARG_EYE_CATCHER); - + iv_pPnor = reinterpret_cast<uint32_t*>( (reinterpret_cast<char*>(l_pHdr) + l_pHdr->headerSize)); diff --git a/src/usr/targeting/xmltohb/xmltohb.pl b/src/usr/targeting/xmltohb/xmltohb.pl index c971aa832..ddb621b45 100755 --- a/src/usr/targeting/xmltohb/xmltohb.pl +++ b/src/usr/targeting/xmltohb/xmltohb.pl @@ -501,6 +501,7 @@ sub writeHeaderFormatHeaderFile { //****************************************************************************** // STD +#include <builtins.h> #include <stdint.h> // Targeting component @@ -1959,7 +1960,7 @@ sub writeTargetingImage { # PNOR/heap sections #@TODO Need the final value of the base address after full host boot support # is implemented. - my $pnorRoBaseAddress = 0x8007E690; + my $pnorRoBaseAddress = 0xC0000000; # 3GB - See vmmconst.H. my $pnorRwBaseAddress = $pnorRoBaseAddress + $vmmSectionOffset; my $heapPnorInitBaseAddr = $pnorRwBaseAddress + $vmmSectionOffset; my $heapZeroInitBaseAddr = $heapPnorInitBaseAddr + $vmmSectionOffset; |