| // clang-format off |
| /* 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 <register/hei_hardware_register.hpp> |
| #include <util/hei_bit_string.hpp> |
| |
| #include <iipchip.h> |
| #include <iipCaptureData.h> |
| #include <string.h> |
| #include <algorithm> // @jl04 a Add this for the Drop function. |
| |
| using namespace TARGETING; |
| |
| namespace libhei |
| { |
| |
| //--------------------------------------------------------------------- |
| // 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, |
| Register & 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 <class T> |
| 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) ) |
| { |
| HEI_ERR( "[CaptureData::Copy] Buffer is full. Some data may have " |
| "been lost" ); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /* CaptureData Format: |
| * capture data -> ( <chip header> <registers> )* |
| * chip header -> ( <chip id:32> <# registers:32> ) |
| * registers -> ( <reg id:16> <reg byte len:16> <bytes>+ ) |
| */ |
| 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 =nullptr; |
| l_chipHuid = ntohl(l_chipHuid); |
| l_pchipHandle = PlatServices::getTarget(l_chipHuid ); |
| if(nullptr ==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(nullptr) |
| { |
| if(d.dataPtr != nullptr) |
| { |
| 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 != nullptr) |
| { |
| delete[]dataPtr; |
| dataPtr = nullptr; |
| } |
| if(d.dataPtr != nullptr) |
| { |
| dataPtr = new uint8_t[dataByteLength]; |
| memcpy(dataPtr, d.dataPtr, dataByteLength); |
| } |
| |
| return *this; |
| } |
| |
| } // end namespace libhei |
| // clang-format on |