blob: d6777aaaefe3f84ac2910978d356e125d831ee74 [file] [log] [blame]
// 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