Skip to content

Commit

Permalink
Updated the HBRT reserved trace buffer code to compensate for relocation
Browse files Browse the repository at this point in the history
This change fixes an issue where the HBRT reserved trace buffer can
be placed in a new location than it's origination.
When HB crashes, the reserved trace buffer is persisted until next IPL.
With OPAL, the reserved trace buffer may be in a different memory
location than where the buffer was when it crashed, therefore all
internal pointers will be invalid.  This change will detect the change
in buffer location and realign all internal pointers to be valid
once again.  This is not an issue with PHYP, only with OPAL.

Change-Id: I476845550062433fba190294b0bd2bbcf8dad658
RTC: 206137
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/82094
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Christian R Geddes <crgeddes@us.ibm.com>
Reviewed-by: Glenn Miles <milesg@ibm.com>
Reviewed-by: Daniel M Crowell <dcrowell@us.ibm.com>
  • Loading branch information
velozr authored and dcrowell77 committed Aug 28, 2019
1 parent 01ac1b8 commit 4536704
Show file tree
Hide file tree
Showing 4 changed files with 363 additions and 69 deletions.
86 changes: 81 additions & 5 deletions src/usr/trace/runtime/rt_rsvdtracebuffer.C
Expand Up @@ -28,6 +28,18 @@

namespace TRACE
{

/// Some constants to help keep track of the structure of the buffer
/// Have these build on each other
// A pointer of where the reserved memory points to itself. Helps to determine
// if the buffer has been relocated
const uint32_t RESERVED_MEMORY_POINTER_OFFSET = 0;
// The location of the buffer for Entries.
const uint32_t BUFFER_BEGINNINIG_BOUNDARY_OFFSET =
sizeof(uintptr_t) + RESERVED_MEMORY_POINTER_OFFSET;
// Minimum size of the buffer, based on the buffers needs to be functional
const uint32_t MINIMUM_SIZE_OF_BUFFER_IN_BYTES =
BUFFER_BEGINNINIG_BOUNDARY_OFFSET;
/**
* ctor
*/
Expand All @@ -50,21 +62,85 @@ void RsvdTraceBuffer::init(uint32_t i_bufferSize,
{
// If buffer is not already initialized and incoming data is legit
if ( (false == isBufferValid()) &&
(i_bufferSize > 0 ) &&
(i_bufferSize > MINIMUM_SIZE_OF_BUFFER_IN_BYTES ) &&
(i_addressToBuffer > 0) &&
(nullptr != i_addressToHead) )
{
setBeginningBoundary(convertToCharPointer(i_addressToBuffer));
setEndingBoundary(convertToCharPointer(i_addressToBuffer +
i_bufferSize - 1));
// Set the list head pointer. This needs to be set first.
setListHeadPtr(i_addressToHead);

// Set the reserved memory pointer
iv_ptrToRsvdMem = reinterpret_cast<uintptr_t*>
(i_addressToBuffer + RESERVED_MEMORY_POINTER_OFFSET);

setBeginningBoundary(convertToCharPointer
(i_addressToBuffer + BUFFER_BEGINNINIG_BOUNDARY_OFFSET));
setEndingBoundary(convertToCharPointer
(i_addressToBuffer + i_bufferSize - 1));

// Check if buffer has moved and if so, realign the pointers
checkBuffer();

// Now that there is an actual/real buffer to point to, the buffer is
// valid, although it may/may not have any entries associated with it.
setBufferValidity(true);
}
}

/**
* checkBuffer
*/
void RsvdTraceBuffer::checkBuffer()
{
intptr_t l_offset(0);

// If the reserved memory data is not zero, meaning that buffer is being
// revisited again, and the memory does not match the current pointer of
// the reserved memory data, then the buffer has been relocated and the
// pointer info in the buffer needs to be realigned/corrected.
// The buffer gets revisited to pull data when a crash happens. Please
// see the details section for the class in the .H file.
if ((0 != iv_ptrToRsvdMem[0]) &&
(reinterpret_cast<uintptr_t>(iv_ptrToRsvdMem) != iv_ptrToRsvdMem[0]))
{
// Get the difference in memory location
l_offset = reinterpret_cast<uintptr_t>
(iv_ptrToRsvdMem) - iv_ptrToRsvdMem[0];

realignListPointers(l_offset);
}

// Persist the current buffer location
iv_ptrToRsvdMem[0] = reinterpret_cast<uintptr_t>(iv_ptrToRsvdMem);
}

/**
* realignListPointers
*/
void RsvdTraceBuffer::realignListPointers(intptr_t l_offset)
{
// Verify that there is actual data to realign
Entry* l_head = getListHead();
if (l_head)
{
// Update the pointer to the list
*iv_ptrToHead = *iv_ptrToHead + l_offset;

// Get the the head of list to traverse over and correct pointers
Entry* l_entry = l_head = getListHead();
do
{
// Update the pointers of Entry item
l_entry->next = reinterpret_cast<Entry *>(
reinterpret_cast<uintptr_t>(l_entry->next) + l_offset);
l_entry->prev = reinterpret_cast<Entry *>(
reinterpret_cast<uintptr_t>(l_entry->prev) + l_offset);

l_entry = l_entry->next;
} while (l_entry != l_head);
}
}

/**
* insertEntry
*/
Expand Down Expand Up @@ -170,7 +246,7 @@ uint32_t RsvdTraceBuffer::getAvailableSpace(uint32_t i_spaceNeeded,
// space needed, then return that value else return the space
// available at the beginning of the buffer. If the space at the
// end does not have enough of the needed space, then space will
// ultimately be made at the beginning of the
// ultimately be made at the beginning of the buffer.
//
// Right now, you are probably thinking, what if I only need 5 free
// spaces and if the end has 10 available and the beginning has 7
Expand Down
68 changes: 54 additions & 14 deletions src/usr/trace/runtime/rt_rsvdtracebuffer.H
Expand Up @@ -43,9 +43,25 @@ namespace TRACE
*
* @brief Class to manage the Reserved Trace Buffer
*
* This is a utility class to manage the buffer - looking for space
* for an entry, adding entries and removing entries.
*
* @details This is a utility class to manage the buffer - looking
* for space for an entry, adding entries and removing entries.
* When a system crashes, this buffer will persist the last
* few traces. When HB is IPLed again, the persisted data
* will be retrieved for inspection.
* With PHYP, the buffer will be retrieved at the same memory
* location as before the crash. With OPAL, the buffer may be
* relocated to a different location and all the pointers within
* the buffer will be invalid. If the buffer does get relocated,
* this class will correct the pointers.
* To correct the pointers, a section at the beginning of the
* persisted buffer is reserved to save the address of the buffer.
* Such that when the buffer is retrieved after a crash, if that
* data does not match the current buffer address, then we can
* conclude it has been relocated and the pointers in the buffer
* need to be updated/corrected.
* If the data at the beginning of the buffer is 0, then this is
* first time this buffer is being used and therefore no need to
* correct pointers.
*/
class RsvdTraceBuffer
{
Expand Down Expand Up @@ -89,12 +105,12 @@ namespace TRACE
* If o_data is valid and the i_size is greater than
* the size of trace_buf_head_t, then as many trace
* entries will be returned in the o_data buffer that
* i_size will allow.
* i_size will allow, minus size of trace_buf_head_t.
*
* @param[in] o_data - if not null, the buffer area to copy
* @param[out] o_data - if not null, the buffer area to copy
* trace data into
*
* @param[out] i_dataSize - if not 0, the size of the buffer area,
* @param[in] i_dataSize - if not 0, the size of the buffer area,
* which dictates how many trace entries'
* payload (or data the entry contains)
* that can be copied
Expand Down Expand Up @@ -123,7 +139,23 @@ namespace TRACE
*/
uint32_t getNumberOfEntries() const;

// Private methods
private:

/** @brief Checks the buffer to see if it has been relocated and if
* so, realign the pointers within the buffer.
*/
void checkBuffer();


/** @brief When and if buffer has been relocated this method will
* realign the pointers within the buffer.
*
* @param[in] i_offset - the offset the buffer has moved
* within memory
*/
void realignListPointers(intptr_t i_offset);

/** @brief This function will find a contiguous piece of memory that
* is large enough in size to accommodate the space needed.
* If not enough free contiguous memory exists to accommodate
Expand All @@ -147,7 +179,8 @@ namespace TRACE
* requested is not larger in size to the buffer size,
* then an available space will eventually be returned.
*
* @param[in] i_spaceNeeded - @see insertEntry::i_dataSize above
* @param[in] i_spaceNeeded - The size of the contiguous piece
* of memory caller desires
*
* @param[out] o_availableAddress - A pointer to the contiguous
* piece of memory found that satisfies the caller's
Expand All @@ -160,8 +193,8 @@ namespace TRACE
char* &o_availableAddress);

/** @brief Returns a contiguous piece of memory that will satisfy
* the space that is needed if large enough space can be
* had, else returns the size of the largest contiguous
* the space that is needed if a large enough space can be
* found, else return the size of the largest contiguous
* piece of memory.
*
* @algorithm There are three cases to consider:
Expand Down Expand Up @@ -228,13 +261,16 @@ namespace TRACE
* Case 2: Contiguous space desired: 40 bytes
* Return the 30 bytes between Tail and Head.
*
* @param[in] i_spaceNeeded - @see insertEntry::i_dataSize above
* @param[in] i_spaceNeeded - The size of the contiguous piece
* of memory caller desires
*
* @param[out] o_availableAddress - @see makeSpaceForEntry above
* @param[out] o_availableAddress - A pointer to the biggest
* piece of contiguous memory found. May or may
* not satisfy i_spaceNeeded.
*
* @return The minimum size of the space found that meets the
* requested space needed; or the largest size that comes
* close to meeting the space needed
* close to meeting the space needed.
*
*/
uint32_t getAvailableSpace(uint32_t i_spaceNeeded,
Expand All @@ -256,7 +292,7 @@ namespace TRACE
uint32_t getAggregateSizeOfEntries() const;

/** @brief This will return as many data entries that can be
* accommodated by size
* accommodated by i_dataSize
*
* @param[out] o_data - the buffer area to copy trace data into
*
Expand Down Expand Up @@ -447,9 +483,13 @@ namespace TRACE
void clearPtrToHead()
{ iv_ptrToHead = nullptr; }

// Private data members
private:
uintptr_t* iv_ptrToRsvdMem; //< Pointer to Reserved Memory. Used to
// realign pointers if RsvdMem relocates
uintptr_t* iv_ptrToHead; //< Pointer to oldest Entry (time wise)
char *iv_bufferBeginningBoundary; //< Pointer to beginning of buffer
char *iv_bufferEndingBoundary; //< Pointer to end of buffer
uintptr_t* iv_ptrToHead; //< Pointer to oldest Entry (time wise)
bool iv_isBufferValid; //< Indicates an initialized buffer

// For testing purposes only
Expand Down
8 changes: 4 additions & 4 deletions src/usr/trace/runtime/rt_rsvdtracebufservice.C
Expand Up @@ -80,10 +80,10 @@ void RsvdTraceBufService::init()
// If the data is not NULL, then retrieve crashed data
// I want NULL in this case, not nullptr; *l_addressToHead is an int.
// If I use nullptr; compiler complains
//if (*l_addressToHead != NULL)
//{
// retrieveDataFromLastCrash();
//}
if (*l_addressToHead != NULL)
{
retrieveDataFromLastCrash();
}

// After gathering trace info from previous crash, clear buffer data
iv_rsvdTraceBuffer.clearBuffer();
Expand Down

0 comments on commit 4536704

Please sign in to comment.