diff options
author | Prachi Gupta <pragupta@us.ibm.com> | 2014-10-28 15:41:49 -0500 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2015-01-16 12:34:43 -0600 |
commit | c068f50829ec46e4e5b056064dcbe9d786d549a4 (patch) | |
tree | 36c5fd8f2f6b5d420644ed83b877f6d0d8657f42 /src/usr/pnor/runtime | |
parent | 5412ba2270945edcfb23f60c34de01dccd44c098 (diff) | |
download | talos-hostboot-c068f50829ec46e4e5b056064dcbe9d786d549a4.tar.gz talos-hostboot-c068f50829ec46e4e5b056064dcbe9d786d549a4.zip |
hbrt interface for PNOR access
RTC:108836
Change-Id: I49e568e7f4fcad13fcd75dfdfa4aee8a263c5001
Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/14307
Reviewed-by: STEPHEN M. CPREK <smcprek@us.ibm.com>
Tested-by: Jenkins Server
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/usr/pnor/runtime')
-rw-r--r-- | src/usr/pnor/runtime/makefile | 36 | ||||
-rw-r--r-- | src/usr/pnor/runtime/rt_pnor.C | 634 | ||||
-rw-r--r-- | src/usr/pnor/runtime/rt_pnor.H | 153 | ||||
-rw-r--r-- | src/usr/pnor/runtime/test/makefile | 31 | ||||
-rw-r--r-- | src/usr/pnor/runtime/test/testpnor_rt.H | 257 |
5 files changed, 1111 insertions, 0 deletions
diff --git a/src/usr/pnor/runtime/makefile b/src/usr/pnor/runtime/makefile new file mode 100644 index 000000000..0556af9e4 --- /dev/null +++ b/src/usr/pnor/runtime/makefile @@ -0,0 +1,36 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/usr/pnor/runtime/makefile $ +# +# OpenPOWER HostBoot Project +# +# Contributors Listed Below - COPYRIGHT 2014,2015 +# [+] International Business Machines Corp. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. See the License for the specific language governing +# permissions and limitations under the License. +# +# IBM_PROLOG_END_TAG +HOSTBOOT_RUNTIME = 1 +ROOTPATH = ../../../.. +MODULE = pnor_rt + +OBJS += rt_pnor.o +OBJS += pnor_common.o +OBJS += ecc.o + +SUBDIRS += test.d + +VPATH += ../ +include $(ROOTPATH)/config.mk diff --git a/src/usr/pnor/runtime/rt_pnor.C b/src/usr/pnor/runtime/rt_pnor.C new file mode 100644 index 000000000..c43160f44 --- /dev/null +++ b/src/usr/pnor/runtime/rt_pnor.C @@ -0,0 +1,634 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/pnor/runtime/rt_pnor.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014,2015 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#include <stdlib.h> +#include <targeting/common/targetservice.H> +#include <initservice/taskargs.H> + +#include <runtime/rt_targeting.H> +#include <runtime/interface.h> + +#include <pnor/pnorif.H> +#include <pnor/ecc.H> +#include <pnor/pnor_reasoncodes.H> +#include "rt_pnor.H" + +#include "../ffs.h" +#include "../common/ffs_hb.H" + +// Trace definition +extern trace_desc_t* g_trac_pnor; + +/** + * Eyecatcher strings for PNOR TOC entries + */ +extern const char* cv_EYECATCHER[]; + +/** + * @brief set up _start() task entry procedure for PNOR daemon + */ +TASK_ENTRY_MACRO( RtPnor::init ); + + +/** + * @brief Return the size and address of a given section of PNOR data + */ +errlHndl_t PNOR::getSectionInfo( PNOR::SectionId i_section, + PNOR::SectionInfo_t& o_info ) +{ + return Singleton<RtPnor>::instance().getSectionInfo(i_section,o_info); +} + +/** + * @brief Write the data for a given sectino into PNOR + */ +errlHndl_t PNOR::flush( PNOR::SectionId i_section) +{ + return Singleton<RtPnor>::instance().flush(i_section); +} + +/****************Public Methods***************************/ +/** + * STATIC + * @brief Static Initializer + */ +void RtPnor::init(errlHndl_t &io_taskRetErrl) +{ + TRACFCOMP(g_trac_pnor, "RtPnor::init> " ); + io_taskRetErrl = Singleton<RtPnor>::instance().readTOC(); + TRACFCOMP(g_trac_pnor, "<RtPnor::init" ); +} +/**************************************************************/ +errlHndl_t RtPnor::getSectionInfo(PNOR::SectionId i_section, + PNOR::SectionInfo_t& o_info) +{ + TRACFCOMP(g_trac_pnor, ENTER_MRK"RtPnor::getSectionInfo"); + errlHndl_t l_err = NULL; + do + { + if (i_section == PNOR::INVALID_SECTION) + { + TRACFCOMP(g_trac_pnor, "RtPnor::getSectionInfo: Invalid Section" + " %d", (int)i_section); + /*@ + * @errortype + * @moduleid PNOR::MOD_RTPNOR_GETSECTIONINFO + * @reasoncode PNOR::RC_RTPNOR_INVALID_SECTION + * @userdata1 PNOR::SectionId + * @devdesc invalid section passed to getSectionInfo + */ + l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_RTPNOR_GETSECTIONINFO, + PNOR::RC_RTPNOR_INVALID_SECTION, + i_section, 0,true); + break; + } + + //size of the section + uint64_t l_sizeBytes = iv_TOC[i_section].size; + if (l_sizeBytes == 0) + { + TRACFCOMP(g_trac_pnor,"RtPnor::getSectionInfo: Section %d" + " size is 0", (int)i_section); + /*@ + * @errortype + * @moduleid PNOR::MOD_RTPNOR_GETSECTIONINFO + * @reasoncode PNOR::RC_SECTION_SIZE_IS_ZERO + * @userdata1 PNOR::SectionId + * @devdesc section size is zero + */ + l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_RTPNOR_GETSECTIONINFO, + PNOR::RC_SECTION_SIZE_IS_ZERO, + i_section, 0,true); + break; + } + //find proc id + uint64_t l_procId; + TARGETING::Target* l_masterProc = NULL; + TARGETING::targetService().masterProcChipTargetHandle( l_masterProc ); + l_err = RT_TARG::getRtTarget (l_masterProc, l_procId); + if (l_err) + { + TRACFCOMP(g_trac_pnor, "RtPnor::getSectionInfo: getRtTarget failed"); + break; + } + + //ecc + bool l_ecc = (iv_TOC[i_section].integrity&FFS_INTEG_ECC_PROTECT) ? + true : false; + + void* l_pWorking = NULL; + void* l_pClean = NULL; + + //find the section in the map first + if(iv_pnorMap.find(i_section) != iv_pnorMap.end()) + { + //get the addresses from the map + PnorAddrPair_t l_addrPair = iv_pnorMap[i_section]; + l_pWorking = l_addrPair.first; + l_pClean = l_addrPair.second; + } + else + { + //malloc twice -- one working copy and one clean copy + //So, we can diff and write only the dirty bytes + l_pWorking = malloc(l_sizeBytes); + l_pClean = malloc(l_sizeBytes); + + //offset = 0 : read the entire section + l_err = readFromDevice(l_procId, i_section, 0, l_sizeBytes, l_ecc, + l_pWorking); + if(l_err) + { + TRACFCOMP(g_trac_pnor, "RtPnor::getSectionInfo:readFromDevice" + " failed"); + break; + } + + //copy data to another pointer to save a clean copy of data + memcpy(l_pClean, l_pWorking, l_sizeBytes); + + //save it in the map + iv_pnorMap [i_section] = PnorAddrPair_t(l_pWorking, l_pClean); + } + //return the data in the struct + o_info.id = i_section; + o_info.name = cv_EYECATCHER[i_section]; + o_info.vaddr = (uint64_t)l_pWorking; + o_info.flashAddr = iv_TOC[i_section].flashAddr; + o_info.size = l_sizeBytes; + o_info.eccProtected = l_ecc; + o_info.sha512Version= + (iv_TOC[i_section].version & FFS_VERS_SHA512) ? true : false; + o_info.sha512perEC = + (iv_TOC[i_section].version & FFS_VERS_SHA512_PER_EC) ? true : false; + } while (0); + + TRACFCOMP(g_trac_pnor, EXIT_MRK"RtPnor::getSectionInfo"); + return l_err; +} + +/**************************************************************/ +errlHndl_t RtPnor::flush( PNOR::SectionId i_section) +{ + TRACFCOMP(g_trac_pnor, ENTER_MRK"RtPnor::flush"); + errlHndl_t l_err = NULL; + do + { + if (i_section == PNOR::INVALID_SECTION) + { + TRACFCOMP(g_trac_pnor,"RtPnor::flush: Invalid Section: %d", + (int)i_section); + /*@ + * @errortype + * @moduleid PNOR::MOD_RTPNOR_FLUSH + * @reasoncode PNOR::RC_INVALID_SECTION + * @userdata1 PNOR::SectionId + * @devdesc invalid section passed to flush + */ + l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_RTPNOR_FLUSH, + PNOR::RC_INVALID_SECTION, + i_section, 0,true); + break; + } + size_t l_sizeBytes = iv_TOC[i_section].size; + if (l_sizeBytes == 0) + { + TRACFCOMP(g_trac_pnor,"RtPnor::flush: Section %d" + " size is 0", (int)i_section); + + /*@ + * @errortype + * @moduleid PNOR::MOD_RTPNOR_FLUSH + * @reasoncode PNOR::RC_SECTION_SIZE_IS_ZERO + * @userdata1 PNOR::SectionId + * @devdesc section size is zero + */ + l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_RTPNOR_FLUSH, + PNOR::RC_SECTION_SIZE_IS_ZERO, + i_section, 0,true); + break; + } + + //get the saved pointers for the partitionName + PnorAddrMap_t::iterator l_it = iv_pnorMap.find(i_section); + if(l_it == iv_pnorMap.end()) + { + TRACFCOMP(g_trac_pnor,"RtPnor::flush: section %d has not been read before", + i_section); + break; + } + PnorAddrPair_t l_addrPair = l_it->second; + uint8_t* l_pWorking = reinterpret_cast<uint8_t*>(l_addrPair.first); + uint8_t* l_pClean = reinterpret_cast<uint8_t*>(l_addrPair.second); + + //ecc + bool l_ecc = (iv_TOC[i_section].integrity&FFS_INTEG_ECC_PROTECT) ? + true : false; + //find proc id + uint64_t l_procId; + TARGETING::Target* l_masterProc = NULL; + TARGETING::targetService().masterProcChipTargetHandle( l_masterProc ); + l_err = RT_TARG::getRtTarget (l_masterProc, l_procId); + if (l_err) + { + TRACFCOMP(g_trac_pnor, "RtPnor::flush: getRtTarget failed"); + break; + } + + //find the diff between each pointer + //write back to pnor what doesn't match + TRACFCOMP(g_trac_pnor, "finding diff between working and clean copy..."); + for (uint64_t i = 0; i < (l_sizeBytes/PAGESIZE); i++) + { + if (0 != memcmp(l_pWorking, l_pClean, PAGESIZE)) + { + TRACFCOMP(g_trac_pnor, "RtPnor::flush: page %d is different," + " writing back to pnor", i); + l_err = writeToDevice(l_procId, i_section, i*PAGESIZE,PAGESIZE, + l_ecc,l_pWorking); + if (l_err) + { + TRACFCOMP(g_trac_pnor, "RtPnor::flush: writeToDevice failed"); + break; + } + //update the clean copy + memcpy(l_pClean, l_pWorking, PAGESIZE); + } + l_pWorking += PAGESIZE; + l_pClean += PAGESIZE; + } + + if (l_err) + { + TRACFCOMP(g_trac_pnor,"RtPnor::flush: error writing section %d" + " back to pnor",(int)i_section); + break; + } + } while (0); + + TRACFCOMP(g_trac_pnor, EXIT_MRK"RtPnor::flush"); + return l_err; +} +/*******Protected Methods**************/ +RtPnor::RtPnor() +:iv_TOC_used(0) +{ + errlHndl_t l_err = readTOC(); + if (l_err) + { + errlCommit(l_err, PNOR_COMP_ID); + } +} + +/*************************/ +RtPnor::~RtPnor() +{ + +} + +/*******************Private Methods*********************/ +errlHndl_t RtPnor::readFromDevice (uint64_t i_procId, + PNOR::SectionId i_section, + uint64_t i_offset, + size_t i_size, + bool i_ecc, + void* o_data) +{ + TRACFCOMP(g_trac_pnor, ENTER_MRK"RtPnor::readFromDevice: i_offset=0x%X, " + "i_procId=%d sec=%d size=0x%X ecc=%d", i_offset, i_procId, i_section, + i_size, i_ecc); + errlHndl_t l_err = NULL; + uint8_t* l_eccBuffer = NULL; + do + { + + const char* l_partitionName = cv_EYECATCHER[i_section]; + void* l_dataToRead = o_data; + size_t l_readSize = i_size; + size_t l_readSizePlusECC = (i_size * 9)/8; + uint64_t l_offset = i_offset; + + // if we need to handle ECC, we need to read more + if( i_ecc ) + { + l_eccBuffer = new uint8_t[l_readSizePlusECC](); + l_dataToRead = l_eccBuffer; + l_readSize = l_readSizePlusECC; + l_offset = (i_offset * 9)/8; + } + + if (g_hostInterfaces && g_hostInterfaces->pnor_read) + { + // get the data from OPAL + int l_rc = g_hostInterfaces->pnor_read(i_procId, l_partitionName, + l_offset, l_dataToRead, l_readSize); + if (l_rc) + { + TRACFCOMP(g_trac_pnor, "RtPnor::readFromDevice: pnor_read" + " failed proc:%d, part:%s, offset:0x%X, size:0x%X," + " dataPt:0x%X, rc:%d", i_procId, l_partitionName, + l_offset, l_readSize, l_dataToRead, l_rc); + /*@ + * @errortype + * @moduleid PNOR::MOD_RTPNOR_READFROMDEVICE + * @reasoncode PNOR::RC_PNOR_READ_FAILED + * @userdata1[00:31] rc returned from pnor_read + * @userdata1[32:63] section ID + * @userdata2[00:31] offset within the section + * @userdata2[32:63] size of data read in bytes + * @devdesc g_hostInterfaces->pnor_read failed + * @custdesc Error accessing system firmware flash + */ + //@todo Add PNOR callout RTC:116145 + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_RTPNOR_READFROMDEVICE, + PNOR::RC_PNOR_READ_FAILED, + TWO_UINT32_TO_UINT64(l_rc, i_section), + TWO_UINT32_TO_UINT64(l_offset, l_readSize), + true); + break; + } + } + else + { + TRACFCOMP(g_trac_pnor,"RtPnor::readFromDevice: This version of" + " OPAL does not support pnor_read"); + /*@ + * @errortype + * @moduleid PNOR::MOD_RTPNOR_READFROMDEVICE + * @reasoncode PNOR::RC_PNOR_READ_NOT_SUPPORTED + * @devdesc g_hostInterfaces->pnor_read not supported + * @custdesc Error accessing system firmware flash + */ + //@todo Add PNOR callout RTC:116145 + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_RTPNOR_READFROMDEVICE, + PNOR::RC_PNOR_READ_NOT_SUPPORTED, + 0,0,true); + break; + } + // remove the ECC data + if( i_ecc ) + { + TRACFCOMP(g_trac_pnor, "RtPnor::readFromDevice: removing ECC..."); + // remove the ECC and fix the original data if it is broken + PNOR::ECC::eccStatus ecc_stat = + PNOR::ECC::removeECC(reinterpret_cast<uint8_t*>(l_dataToRead), + reinterpret_cast<uint8_t*>(o_data), + i_size); + + // create an error if we couldn't correct things + if( ecc_stat == PNOR::ECC::UNCORRECTABLE ) + { + TRACFCOMP(g_trac_pnor,"RtPnor::readFromDevice>" + " Uncorrectable ECC error : chip=%d,offset=0x%.X", + i_procId, i_offset ); + /*@ + * @errortype + * @moduleid PNOR::MOD_RTPNOR_READFROMDEVICE + * @reasoncode PNOR::RC_UNCORRECTABLE_ECC + * @devdesc UNCORRECTABLE ECC + */ + //@todo Add PNOR callout RTC:116145 + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_RTPNOR_READFROMDEVICE, + PNOR::RC_UNCORRECTABLE_ECC, + 0, 0, true); + break; + } + + // found an error so we need to fix something + else if( ecc_stat != PNOR::ECC::CLEAN ) + { + TRACFCOMP(g_trac_pnor,"RtPnor::readFromDevice>" + "Correctable ECC error : chip=%d, offset=0x%.X", + i_procId, i_offset ); + if (g_hostInterfaces && g_hostInterfaces->pnor_write) + { + + //need to write good data back to PNOR + int l_rc = g_hostInterfaces->pnor_write(i_procId, + l_partitionName,l_offset, l_dataToRead,l_readSize); + if (l_rc) + { + TRACFCOMP(g_trac_pnor, "RtPnor::readFromDevice> Error" + " writing corrected data back to device"); + + /*@ + * @errortype + * @moduleid PNOR::MOD_RTPNOR_READFROMDEVICE + * @reasoncode PNOR::RC_PNOR_WRITE_FAILED + * @userdata1 rc returned from pnor_write + * @devdesc error writing corrected data back to PNOR + * @custdesc Error accessing system firmware flash + */ + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_RTPNOR_READFROMDEVICE, + PNOR::RC_PNOR_WRITE_FAILED, + l_rc, 0, true); + errlCommit(l_err, PNOR_COMP_ID); + } + } + } + } + } while(0); + + if( l_eccBuffer ) + { + delete[] l_eccBuffer; + } + + TRACFCOMP(g_trac_pnor, EXIT_MRK"RtPnor::readFromDevice" ); + return l_err; +} + +/*********************************************************************/ +errlHndl_t RtPnor::writeToDevice( uint64_t i_procId, + PNOR::SectionId i_section, + uint64_t i_offset, + size_t i_size, + bool i_ecc, + void* i_src ) +{ + TRACFCOMP(g_trac_pnor, ENTER_MRK"RtPnor::writeToDevice: i_offset=0x%X, " + "i_procId=%d sec=%d size=0x%X ecc=%d", i_offset, i_procId, i_section, + i_size, i_ecc); + errlHndl_t l_err = NULL; + uint8_t* l_eccBuffer = NULL; + + do + { + void* l_dataToWrite = i_src; + size_t l_writeSize = i_size; + size_t l_writeSizePlusECC = (i_size * 9)/8; + uint64_t l_offset = i_offset; + + // apply ECC to data if needed + if( i_ecc ) + { + l_eccBuffer = new uint8_t[l_writeSizePlusECC]; + PNOR::ECC::injectECC( reinterpret_cast<uint8_t*>(i_src), + l_writeSize, + reinterpret_cast<uint8_t*>(l_eccBuffer) ); + l_dataToWrite = reinterpret_cast<void*>(l_eccBuffer); + l_writeSize = l_writeSizePlusECC; + l_offset = (i_offset * 9)/8; + } + + const char* l_partitionName = cv_EYECATCHER[i_section]; + if (g_hostInterfaces && g_hostInterfaces->pnor_write) + { + //make call into opal to write the data + int l_rc = g_hostInterfaces->pnor_write(i_procId, + l_partitionName,l_offset,l_dataToWrite,l_writeSize); + if (l_rc) + { + TRACFCOMP(g_trac_pnor, "RtPnor::writeToDevice: pnor_write failed " + "proc:%d, part:%s, offset:0x%X, size:0x%X, dataPt:0x%X," + " rc:%d", i_procId, l_partitionName, l_offset, l_writeSize, + l_dataToWrite, l_rc); + /*@ + * @errortype + * @moduleid PNOR::MOD_RTPNOR_WRITETODEVICE + * @reasoncode PNOR::RC_PNOR_WRITE_FAILED + * @userdata1[00:31] rc returned from pnor_write + * @userdata1[32:63] section ID + * @userdata2[00:31] offset within the section + * @userdata2[32:63] size of data written in bytes + * @devdesc g_hostInterfaces->pnor_write failed + * @custdesc Error accessing system firmware flash + */ + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_RTPNOR_WRITETODEVICE, + PNOR::RC_PNOR_WRITE_FAILED, + TWO_UINT32_TO_UINT64(l_rc, i_section), + TWO_UINT32_TO_UINT64(l_offset, l_writeSize), + true); + break; + } + } + else + { + TRACFCOMP(g_trac_pnor,"RtPnor::writeToDevice: This version of" + " OPAL does not support pnor_write"); + /*@ + * @errortype + * @moduleid PNOR::MOD_RTPNOR_WRITETODEVICE + * @reasoncode PNOR::RC_PNOR_WRITE_NOT_SUPPORTED + * @devdesc g_hostInterfaces->pnor_write not supported + * @custdesc Error accessing system firmware flash + */ + //@todo Add PNOR callout RTC:116145 + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_RTPNOR_WRITETODEVICE, + PNOR::RC_PNOR_WRITE_NOT_SUPPORTED, + 0,0,true); + break; + + } + } while(0); + + if( l_eccBuffer ) + { + delete[] l_eccBuffer; + } + + TRACFCOMP(g_trac_pnor, EXIT_MRK"RtPnor::writeToDevice" ); + return l_err; +} + +/*****************************************************************/ +errlHndl_t RtPnor::readTOC () +{ + TRACFCOMP(g_trac_pnor, ENTER_MRK"RtPnor::readTOC" ); + errlHndl_t l_err = NULL; + uint8_t* toc0Buffer = new uint8_t[PAGESIZE]; + uint8_t* toc1Buffer = new uint8_t[PAGESIZE]; + do { + //find proc id + uint64_t l_procId; + TARGETING::Target* l_masterProc = NULL; + TARGETING::targetService().masterProcChipTargetHandle( l_masterProc ); + l_err = RT_TARG::getRtTarget (l_masterProc, l_procId); + if (l_err) + { + TRACFCOMP(g_trac_pnor, "RtPnor::readTOC: getRtTarget failed"); + break; + } + + l_err = readFromDevice (l_procId, PNOR::TOC, PNOR::TOC_0_OFFSET, + PAGESIZE,false,toc0Buffer); + if (l_err) + { + TRACFCOMP(g_trac_pnor,"RtPnor::readTOC:readFromDevice failed" + " for TOC0"); + break; + } + l_err = readFromDevice (l_procId, PNOR::TOC, PNOR::TOC_1_OFFSET, + PAGESIZE, false,toc1Buffer); + if (l_err) + { + TRACFCOMP(g_trac_pnor, "RtPnor::readTOC:readFromDevice failed" + " for TOC1"); + break; + } + + l_err = PNOR::parseTOC(toc0Buffer, toc1Buffer, iv_TOC_used, iv_TOC,0); + if (l_err) + { + TRACFCOMP(g_trac_pnor, "RtPnor::readTOC: parseTOC failed"); + break; + } + } while (0); + + if(toc0Buffer != NULL) + { + delete[] toc0Buffer; + } + + if(toc1Buffer != NULL) + { + delete[] toc1Buffer; + } + + TRACFCOMP(g_trac_pnor, EXIT_MRK"RtPnor::readTOC" ); + return l_err; +} + +/***********************************************************/ +RtPnor& RtPnor::getInstance() +{ + return Singleton<RtPnor>::instance(); +} diff --git a/src/usr/pnor/runtime/rt_pnor.H b/src/usr/pnor/runtime/rt_pnor.H new file mode 100644 index 000000000..43041fc3f --- /dev/null +++ b/src/usr/pnor/runtime/rt_pnor.H @@ -0,0 +1,153 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/pnor/runtime/rt_pnor.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014,2015 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef _RT_PNOR_H_ +#define _RT_PNOR_H_ + +#include <pnor/pnorif.H> +#include "../pnor_common.H" +#include <errl/errlentry.H> +#include <map> + +typedef std::pair<void*, void*> PnorAddrPair_t; +typedef std::map<PNOR::SectionId, PnorAddrPair_t> PnorAddrMap_t; + +class RtPnor +{ + public: + + /** + * @brief Static Initializer + * @param[in] ref to errlHndl_t + */ + static void init ( errlHndl_t &io_rtaskRetErrl ); + + /** + * @brief Return the size and address of a given section + * of PNOR data at runtime + * Called by external PNOR::getSectionInfo() + * + * @param[in] i_section PNOR section + * @param[out] o_info Location and size information + * + * @return errlHndl_t Error log if request was invalid + */ + errlHndl_t getSectionInfo ( PNOR::SectionId i_section, + PNOR::SectionInfo_t& o_info); + + /** + * @brief Writes the data back to PNOR of a given section + * of PNOR at runtime + * Called by external PNOR::flush() + * + * @param[in] i_section PNOR section + * @return errlHndl_t Error log if request was invalid + */ + errlHndl_t flush (PNOR::SectionId i_section); + + protected: + /** + * @brief Constructor + */ + RtPnor(); + + /** + * @brief Destructor + */ + ~RtPnor(); + + private: + /** + * Which TOC (0 or 1) is used after verifying both. + */ + uint32_t iv_TOC_used; + + /** + * Cached copy of section data + */ + PNOR::SectionData_t iv_TOC[PNOR::NUM_SECTIONS+1]; + + /** + * Keeps track of the data pointers for different sections in the PNOR + */ + PnorAddrMap_t iv_pnorMap; + + /** + * @brief Reads data from the PNOR device + * and removes ecc if necessary + * + * @param[in] i_procId processor id + * @param[in] i_section section of the pnor to write back + * @param[in] i_offset offset into the pnor + * @param[in] i_size size of data to read in bytes + * @param[in] i_ecc true=verify and strip ECC after reading + * @param[in] o_data Buffer to copy data into + * + * @return Error from device + */ + errlHndl_t readFromDevice (uint64_t i_procId, + PNOR::SectionId i_section, + uint64_t i_offset, + size_t i_size, + bool i_ecc, + void* o_data); + + /** + * @brief Write data back to the PNOR device + * and injects ecc if necessary + * + * @param[in] i_procId processor id + * @param[in] i_section section of the pnor to write back + * @param[in] i_offset offset into the pnor + * @param[in] i_size size of data to read in bytes + * @param[in] i_ecc true=apply ECC before writing + * @param[in] i_src Buffer to copy data from + * + * @return Error from device + */ + errlHndl_t writeToDevice( uint64_t i_procId, + PNOR::SectionId i_section, + uint64_t i_offset, + size_t i_size, + bool i_ecc, + void* i_src ); + + /** + * @brief Verify both TOC's and store section information from one of + * the verified TOC's + * + * @return Error from device + */ + errlHndl_t readTOC(); + + //allow testcases to see inside the class + friend class PnorRtTest; + + /** + * @brief Static instance function for testcase only + */ + static RtPnor& getInstance(); +}; + +#endif diff --git a/src/usr/pnor/runtime/test/makefile b/src/usr/pnor/runtime/test/makefile new file mode 100644 index 000000000..e53d87f15 --- /dev/null +++ b/src/usr/pnor/runtime/test/makefile @@ -0,0 +1,31 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/usr/pnor/runtime/test/makefile $ +# +# OpenPOWER HostBoot Project +# +# Contributors Listed Below - COPYRIGHT 2014,2015 +# [+] International Business Machines Corp. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. See the License for the specific language governing +# permissions and limitations under the License. +# +# IBM_PROLOG_END_TAG +HOSTBOOT_RUNTIME = 1 +ROOTPATH = ../../../../.. + +MODULE = testpnor_rt +TESTS = *.H + +include ${ROOTPATH}/config.mk diff --git a/src/usr/pnor/runtime/test/testpnor_rt.H b/src/usr/pnor/runtime/test/testpnor_rt.H new file mode 100644 index 000000000..5a81ea9ac --- /dev/null +++ b/src/usr/pnor/runtime/test/testpnor_rt.H @@ -0,0 +1,257 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/pnor/runtime/test/testpnor_rt.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014,2015 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#include <cxxtest/TestSuite.H> +#include <errl/errlmanager.H> +#include <errl/errlentry.H> +#include <devicefw/userif.H> + +#include <pnor/pnorif.H> +#include "../../pnor_common.H" +#include "../rt_pnor.H" + +#include <runtime/interface.h> +#include <trace/interface.H> + +#include "../../ffs.h" //Common header file with BuildingBlock. +#include "../../common/ffs_hb.H" //Hostboot def of user data in ffs_entry struct + +extern trace_desc_t* g_trac_pnor; +using namespace TARGETING; + +/* + * these taest cases are turned off as they have dependency on pnorddtest cases + */ +class PnorRtTest : public CxxTest::TestSuite +{ + public: + /** + * @brief: testTOC + * tests that the TOC is read/parsed properly during runtime + */ + void testTOC (void) + { +#if 1 + TRACFCOMP(g_trac_pnor, "PnorRtTest::testTOC - skipping - as it" + " adversly affects pnorddtests"); +#else + TRACFCOMP(g_trac_pnor, "PnorRtTest::testTOC Start" ); + errlHndl_t l_err = NULL; + uint32_t l_proc = 0; + uint64_t offset = 0; + uint8_t* tocHeader = new uint8_t[PAGESIZE]; + uint8_t* tocEntry = new uint8_t[PAGESIZE]; + uint8_t* corruptBuffer = new uint8_t[PAGESIZE]; + + // Corrupt both ffs header and first entry for each TOC + for (uint32_t cur_TOC = 0; cur_TOC < PNOR::NUM_TOCS; ++cur_TOC) + { + uint32_t TOC_used = cur_TOC; + offset = (cur_TOC == 0) ? PNOR::TOC_0_OFFSET : PNOR::TOC_1_OFFSET; + + // Read cur_TOC header data + l_err = RtPnor::getInstance().readFromDevice(l_proc,PNOR::TOC, + offset,PAGESIZE,false,tocHeader); + if (l_err) + { + TS_FAIL("PnorRtTest::testTOC: readFromDevice failed"); + break; + } + + // Corrupt cur_TOC header data + memcpy(corruptBuffer, tocHeader, PAGESIZE); + corruptBuffer[0] = 0xFF; + corruptBuffer[1] = 0xFF; + + l_err = RtPnor::getInstance().writeToDevice(l_proc,PNOR::TOC, + offset,PAGESIZE,false,corruptBuffer); + if (l_err) + { + TS_FAIL("PnorRtTest::testTOC: writeToDevice failed"); + } + + // Check if cur_TOC failed that other TOC is used + l_err = RtPnor::getInstance().readTOC(); + if (l_err) + { + TS_FAIL("PnorRtTest::testTOC: readTOC failed"); + } + + TOC_used = RtPnor::getInstance().iv_TOC_used; + TRACFCOMP(g_trac_pnor, "PnorRtTest::testTOC : TOC %d Corrupt" + " Header, Toc_used = %d", cur_TOC, TOC_used); + + if (TOC_used == cur_TOC) + { + TS_FAIL("PnorRtTest::testTOC>ERROR:TOC %d header is corrupted," + " did not use other TOC"); + break; + } + // Fix cur_TOC header + l_err = RtPnor::getInstance().writeToDevice(l_proc,PNOR::TOC, + offset,PAGESIZE,false,tocHeader); + if (l_err) + { + TS_FAIL("PnorRtTest::testTOC: writeToDevice failed"); + } + + // Read cur_TOC first entry data + l_err = RtPnor::getInstance().readFromDevice(l_proc,PNOR::TOC, + offset+FFS_HDR_SIZE,PAGESIZE,false,tocEntry); + if (l_err) + { + TS_FAIL("PnorRtTest::testTOC: readTOC failed"); + break; + } + + // Corrupt cur_TOC header data + memcpy(corruptBuffer, tocEntry, PAGESIZE); + corruptBuffer[0] = 0xFF; + corruptBuffer[1] = 0xFF; + + l_err = RtPnor::getInstance().writeToDevice(l_proc,PNOR::TOC, + offset+FFS_HDR_SIZE,PAGESIZE,false,corruptBuffer); + if (l_err) + { + TS_FAIL("PnorRtTest::testTOC: writeToDevice failed"); + } + + // Check if cur_TOC failed that other TOC is used + TOC_used = cur_TOC; + l_err = RtPnor::getInstance().readTOC(); + if (l_err) + { + TS_FAIL("PnorRtTest::testTOC: readTOC failed"); + } + TOC_used = RtPnor::getInstance().iv_TOC_used; + TRACFCOMP(g_trac_pnor,"PnorRtTest::testTOC:TOC %d Corrupt" + " Entry, Toc_used = %d", cur_TOC, TOC_used); + + if (TOC_used == cur_TOC) + { + TS_FAIL("PnorRtTest::testTOC>ERROR: TOC %d entry is corrupted," + " did not use other TOC", cur_TOC); + } + + // Fix cur_TOC first entry + l_err = RtPnor::getInstance().writeToDevice(l_proc,PNOR::TOC, + offset+FFS_HDR_SIZE,PAGESIZE,false,tocEntry); + if (l_err) + { + TS_FAIL("PnorRtTest::testTOC: writeToDevice failed"); + } + } + + delete tocHeader; + delete tocEntry; + delete corruptBuffer; + + TRACFCOMP(g_trac_pnor, "PnorRtTest::testTOC End"); +#endif + } + + /** + * @brief RtPnor::testPnorReadWrite + * Compares the values read and written by runtime interfaces and + * IPL interfaces + */ + void testPnorReadWrite(void) + { + TRACFCOMP(g_trac_pnor, ENTER_MRK"testPnorReadWrite"); + do { + errlHndl_t l_err = NULL; + uint32_t l_proc = 0; + uint64_t l_offset = PNOR::pnorTestSec_rt_readwrite_offset; + uint64_t l_writeData = 0x0123456789ABCDEF; + PNOR::SectionId l_id = PNOR::TEST; + PNOR::SectionInfo_t l_info; + + size_t l_sizeBytes = (RtPnor::getInstance().iv_TOC[l_id].size) - + l_offset; + void* l_readData = malloc (l_sizeBytes); + + //read via hostInterfaces + l_err = RtPnor::getInstance().readFromDevice(l_proc,l_id,l_offset, + l_sizeBytes,true,l_readData); + if(l_err) + { + TS_FAIL("testPnorReadWrite: readFromDevice failed"); + break; + } + + //read using getSectionInfo + l_err = PNOR::getSectionInfo(l_id, l_info); + if (l_err) + { + TS_FAIL("testPnorReadWrite: getSectionInfo failed"); + break; + } + + void* l_gData = reinterpret_cast<void*> (l_info.vaddr); + + //verify that data is read correctly + if (0 != memcmp (l_readData, l_gData, l_sizeBytes)) + { + TS_FAIL("testPnorReadWrite: read failed"); + break; + } + TRACFCOMP(g_trac_pnor, "testPnorReadWrite: read successfull"); + + /***********************************************************/ + //make changes to the getSectionInfo pointer and call flush + uint8_t* l_vaddr = reinterpret_cast<uint8_t*>(l_info.vaddr); + + memcpy(l_vaddr, &l_writeData, 4); + memcpy(l_vaddr+PAGESIZE+20, &l_writeData, 4); + + l_err = PNOR::flush(l_id); + if (l_err) + { + TS_FAIL("testPnorReadWrite: flush failed"); + break; + } + + /***********************************************************/ + //calling read again to make sure data was written properly + //using pnor_wirte + l_err = RtPnor::getInstance().readFromDevice(l_proc,l_id,l_offset, + l_sizeBytes,true,l_readData); + if(l_err) + { + TS_FAIL("testPnorReadWrite: readFromDevice failed"); + break; + } + + if (0 != memcmp (l_readData, l_gData, l_sizeBytes)) + { + TS_FAIL("testPnorReadWrite: flush failed"); + break; + } + TRACFCOMP(g_trac_pnor, "testPnorReadWrite: flush passed"); + + } while (0); + TRACFCOMP(g_trac_pnor, EXIT_MRK"testPnorReadWrite"); + } + +}; |