/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* $Source: src/usr/diag/prdf/common/framework/register/prdfCaptureData.C $ */ /* */ /* OpenPOWER HostBoot Project */ /* */ /* Contributors Listed Below - COPYRIGHT 2012,2019 */ /* [+] 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 */ /** @file prdfCaptureData.C @brief Squadrons implementation of capture data */ //---------------------------------------------------------------------- // Includes //---------------------------------------------------------------------- #include #include // dg06a #include #include #include #include #include // @jl04 a Add this for the Drop function. using namespace TARGETING; namespace PRDF { //--------------------------------------------------------------------- // Member Function Specifications //--------------------------------------------------------------------- CaptureData::CaptureData(void):data() { // data.reserve(INITIAL_DATA_COUNT); } // dg05d CaptureData::~CaptureData(void) // dg05d { // dg05d if(!data.empty()) // dg05d { // dg05d Clear(); // dg05d } // dg05d } void CaptureData::Clear(void) { if(!data.empty()) { // dg05d for(DataContainerType::iterator i = data.begin();i != data.end();i++) // dg05d { // dg05d delete [] (*i).dataPtr; // dg05d } data.erase(data.begin(), data.end()); } /* if not empty */ } //------------------------------------------------------------------------------ void CaptureData::AddDataElement( TargetHandle_t i_trgt, int i_scomId, const BitString * i_bs, Place i_place, RegType i_type ) { // Initial values of the bit string buffer if i_bs has a zero value. uint8_t * buf = nullptr; size_t sz_buf = 0; // Add buffer only if the value is non-zero. if ( !i_bs->isZero() ) { // Get the size of i_bs and ensure byte alignment. sz_buf = (i_bs->getBitLen() + 8-1) / 8; // Since we are using a BitString below, which does everything on a // CPU_WORD boundary, we must make sure the buffer is CPU_WORD aligned. const size_t sz_word = sizeof(CPU_WORD); sz_buf = ((sz_buf + sz_word-1) / sz_word) * sz_word; // Allocate memory for the buffer. buf = new uint8_t[sz_buf]; memset( buf, 0x00, sz_buf ); // Use a BitString to copy i_bs to the buffer. BitString bs ( i_bs->getBitLen(), (CPU_WORD *)buf ); bs.setString( *i_bs ); // Create the new data element. Data element( i_trgt, i_scomId, sz_buf, buf ); element.registerType = i_type; // Add the new element to the data. if ( FRONT == i_place ) data.insert( data.begin(), element ); else data.push_back( element ); } } //------------------------------------------------------------------------------ void CaptureData::Add( TargetHandle_t i_trgt, int32_t i_scomId, SCAN_COMM_REGISTER_CLASS & io_scr, Place i_place, RegType i_type ) { if ( SUCCESS == io_scr.Read() ) { AddDataElement( i_trgt, i_scomId, io_scr.GetBitString(), i_place, i_type ); } } //------------------------------------------------------------------------------ void CaptureData::Add( TargetHandle_t i_trgt, int i_scomId, const BitString & i_bs, Place i_place ) { AddDataElement( i_trgt, i_scomId, &i_bs, i_place ); } //------------------------------------------------------------------------------ // start jl04a void CaptureData::Drop(RegType i_type) { // Function below requires a predicate function above to Drop // a data element from the capture data if it is // defined as secondary data instead of primary data in the rule files. // This predicate has to exist within the CaptureData Class because the // class "Data" is defined within CaptureData class. data.erase( std::remove_if(data.begin(),data.end(), prdfCompareCaptureDataType(i_type)), data.end() ); } // end jl04a //------------------------------------------------------------------------------ template void __bufferAdd( uint8_t* & i_idx, T i_val ) { memcpy( i_idx, &i_val, sizeof(i_val) ); i_idx += sizeof(i_val); } bool __bufferFull( uint8_t * i_buf, size_t i_bufSize, uint8_t * i_idx, size_t i_idxSize ) { if ( (i_buf + i_bufSize) < (i_idx + i_idxSize) ) { PRDF_ERR( "[CaptureData::Copy] Buffer is full. Some data may have " "been lost" ); return true; } return false; } /* CaptureData Format: * capture data -> ( )* * chip header -> ( <# registers:32> ) * registers -> ( + ) */ uint32_t CaptureData::Copy( uint8_t * i_buffer, uint32_t i_bufferSize ) const { TargetHandle_t curTrgt = nullptr; uint32_t * regCntPtr = nullptr; uint8_t * curIdx = i_buffer; for ( auto & entry : data ) { // We only need the target data when the target for this entry does not // match the previous entry. if ( entry.chipHandle != curTrgt ) { // Ensure we have enough space for the entry header. if ( __bufferFull( i_buffer, i_bufferSize, curIdx, (sizeof(HUID) + sizeof(uint32_t)) ) ) { break; } // Update current target. curTrgt = entry.chipHandle; // Add HUID to buffer. __bufferAdd( curIdx, htonl(PlatServices::getHuid(curTrgt)) ); // Update the current count pointer. regCntPtr = (uint32_t *)curIdx; // Zero out the register count. __bufferAdd( curIdx, htonl(0) ); } // Go to next entry if the data byte length is 0. if ( 0 == entry.dataByteLength ) continue; // Ensure we have enough space for the entry header. if ( __bufferFull( i_buffer, i_bufferSize, curIdx, (2 * sizeof(uint16_t) + entry.dataByteLength) ) ) { break; } // Write register ID. __bufferAdd( curIdx, htons(entry.address) ); // Write data length. __bufferAdd( curIdx, htons(entry.dataByteLength) ); // Write the data. // >>> TODO: RTC 199045 The data should already be in network format. // However, that is not the case. Instead, the data is // converted here, which would be is fine if we were only // adding registers, but we have additional capture data, // especially in the memory subsytem, that are actually stored // in the network format, but swizzled before adding to the // capture data. Which means we are doing too much. // Unfortunately, it currently works and will take some time // to actually do it right. Therefore, we will leave this // as-is and try to make the appropriate fix later. uint32_t l_dataWritten = 0; while ((l_dataWritten + 4) <= entry.dataByteLength) { uint32_t l_temp32; memcpy(&l_temp32, &entry.dataPtr[l_dataWritten], sizeof(l_temp32)); l_temp32 = htonl(l_temp32); memcpy(curIdx, &l_temp32, 4); l_dataWritten += 4; curIdx += 4; } if (l_dataWritten != entry.dataByteLength) { // TODO: RTC 199045 This is actually pretty bad because it will read // four bytes of memory, sizzle the four bytes, then write // less than four bytes to the buffer. This could cause a // buffer overrun exception if we were at the end of memory. // Also, how can we trust the right most bytes to be correct // since they technically should not be part of the entry // data? Again, we don't seem to be hitting this bug and it // will take time to fix it (see note above). Therefore, we // will leave it for now and fix it when we have time. uint32_t l_temp32; memcpy(&l_temp32, &entry.dataPtr[l_dataWritten], sizeof(l_temp32)); l_temp32 = htonl(l_temp32); memcpy(curIdx, &l_temp32, entry.dataByteLength - l_dataWritten); curIdx += entry.dataByteLength - l_dataWritten; } // <<< TODO: RTC 199045 // Update entry count. It is important to update the buffer just in // case we happen to run out of room in the buffer and need to exit // early. *regCntPtr = htonl( ntohl(*regCntPtr) + 1 ); } return curIdx - i_buffer; } // dg08a --> CaptureData & CaptureData::operator=(const uint8_t *i_flatdata) { uint32_t l_tmp32 = 0; uint16_t l_tmp16 = 0; HUID l_chipHuid = INVALID_HUID; const size_t l_huidSize = sizeof(l_chipHuid); // Read size. memcpy(&l_tmp32, i_flatdata, sizeof(uint32_t)); uint32_t size = ntohl(l_tmp32); i_flatdata += sizeof(uint32_t); Clear(); // Calculate end of buffer. const uint8_t *eptr = i_flatdata + size; while(i_flatdata < eptr) { // Read chip Handle. memcpy(&l_chipHuid , i_flatdata,l_huidSize ); i_flatdata += l_huidSize ; TargetHandle_t l_pchipHandle =NULL; l_chipHuid = ntohl(l_chipHuid); l_pchipHandle = PlatServices::getTarget(l_chipHuid ); if(NULL ==l_pchipHandle) { continue; } // Read # of entries. memcpy(&l_tmp32, i_flatdata, sizeof(uint32_t)); i_flatdata += sizeof(l_tmp32); uint32_t entries = ntohl(l_tmp32); // Input each entry. for(uint32_t i = 0; i < entries; ++i) { // Read register id. memcpy(&l_tmp16, i_flatdata, sizeof(uint16_t)); i_flatdata += sizeof(uint16_t); int regid = ntohs(l_tmp16); // Read byte count. memcpy(&l_tmp16, i_flatdata, sizeof(uint16_t)); i_flatdata += sizeof(uint16_t); uint32_t bytecount = ntohs(l_tmp16); // Read data for register. BitStringBuffer bs(bytecount * 8); for(uint32_t bc = 0; bc < bytecount; ++bc) { bs.setFieldJustify(bc*8,8,(CPU_WORD)(*(i_flatdata+bc))); //mp01a } i_flatdata += bytecount; // Add to capture data. Add(l_pchipHandle, regid, bs); } } return *this; } // <-- dg08a void CaptureData::mergeData(CaptureData & i_cd) { DataContainerType l_data = *(i_cd.getData()); if( !l_data.empty() ) { // Remove duplicate entries from secondary capture data for (ConstDataIterator i = data.begin(); i != data.end(); i++) { l_data.remove_if(prdfCompareCaptureDataEntry(i->chipHandle, i->address) ); } // Add secondary capture data to primary one data.insert( data.end(), l_data.begin(), l_data.end() ); } } // copy ctor for Data class CaptureData::Data::Data(const Data & d): chipHandle(d.chipHandle), address(d.address), dataByteLength(d.dataByteLength), dataPtr(NULL) { if(d.dataPtr != NULL) { dataPtr = new uint8_t[dataByteLength]; memcpy(dataPtr, d.dataPtr, dataByteLength); } } CaptureData::Data & CaptureData::Data::operator=(const Data & d) { chipHandle = d.chipHandle; address = d.address; dataByteLength = d.dataByteLength; if(dataPtr != NULL) { delete[]dataPtr; dataPtr = NULL; } if(d.dataPtr != NULL) { dataPtr = new uint8_t[dataByteLength]; memcpy(dataPtr, d.dataPtr, dataByteLength); } return *this; } } // end of namespace PRDF