summaryrefslogtreecommitdiffstats
path: root/src/usr/trace/runtime/rt_rsvdtracebuffer.C
diff options
context:
space:
mode:
Diffstat (limited to 'src/usr/trace/runtime/rt_rsvdtracebuffer.C')
-rw-r--r--src/usr/trace/runtime/rt_rsvdtracebuffer.C154
1 files changed, 123 insertions, 31 deletions
diff --git a/src/usr/trace/runtime/rt_rsvdtracebuffer.C b/src/usr/trace/runtime/rt_rsvdtracebuffer.C
index b9d21b774..175850ff8 100644
--- a/src/usr/trace/runtime/rt_rsvdtracebuffer.C
+++ b/src/usr/trace/runtime/rt_rsvdtracebuffer.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2017,2018 */
+/* Contributors Listed Below - COPYRIGHT 2017,2019 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -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
*/
@@ -48,17 +60,27 @@ void RsvdTraceBuffer::init(uint32_t i_bufferSize,
uintptr_t i_addressToBuffer,
uintptr_t* i_addressToHead)
{
- // If buffer is not already initilaized and incoming data is legit
+ // 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);
@@ -66,6 +88,60 @@ void RsvdTraceBuffer::init(uint32_t i_bufferSize,
}
/**
+ * 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
*/
Entry* RsvdTraceBuffer::insertEntry(uint32_t i_dataSize)
@@ -83,9 +159,11 @@ Entry* RsvdTraceBuffer::insertEntry(uint32_t i_dataSize)
// (Alignment is needed so that Entry's members can be atomically
// updated).
uint32_t l_entrySize = getAlignedSizeOfEntry(i_dataSize);
- if (makeSpaceForEntry(l_entrySize, l_availableAddress) && l_availableAddress)
+ if (makeSpaceForEntry(l_entrySize, l_availableAddress) &&
+ l_availableAddress)
{
- // Set entry if space was created and an avilable address is returned
+ // Set entry if space was created and an available address
+ // is returned
l_entry = reinterpret_cast<Entry*>(l_availableAddress);
setListTail(l_entry);
@@ -104,7 +182,8 @@ uint32_t RsvdTraceBuffer::makeSpaceForEntry(uint32_t i_spaceNeeded,
o_availableAddress = nullptr;
uint32_t l_spaceAvailable = 0;
- // Only look for space if requested space is less or equal to buffer size
+ // Only look for space if requested space is less than
+ // or equal to buffer size
if (i_spaceNeeded <= getBufferSize())
{
l_spaceAvailable = getAvailableSpace(i_spaceNeeded, o_availableAddress);
@@ -112,7 +191,7 @@ uint32_t RsvdTraceBuffer::makeSpaceForEntry(uint32_t i_spaceNeeded,
// Keep requesting for space until we get the space that is asked for
while (l_spaceAvailable < i_spaceNeeded)
{
- // If we can't remove any entries, then we exhausted all efforts
+ // If we can't remove any entries, then we exhausted all efforts.
// Should not happen, because the space requested should be less
// than or equal to buffer size
if (!removeOldestEntry())
@@ -167,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
@@ -215,7 +294,7 @@ bool RsvdTraceBuffer::removeOldestEntry()
if (!isListEmpty())
{
// Get a handle to the head
- Entry* l_head = getListHead();
+ Entry* l_head(getListHead());
// Is there only one entry?
if (l_head->next == l_head)
@@ -252,12 +331,17 @@ uint32_t RsvdTraceBuffer::getTrace(void* o_data, uint32_t i_dataSize) const
// Before continuing, make sure the buffer is valid
if (isBufferValid())
{
+ // If caller passed in a nullptr for the data or zero for the data size,
+ // then that signals the user only wants to ascertain the size
+ // requirement to hold all the data associated with the entries.
if ((nullptr == o_data) || (0 == i_dataSize))
{
+ // Caller wants to ascertain size requirements for data
l_sizeOfBufferExtracted = getAggregateSizeOfEntries();
}
else
{
+ // Caller wants to collect data - enough data to fill data size
l_sizeOfBufferExtracted = getTraceEntries(o_data, i_dataSize);
}
}
@@ -273,7 +357,7 @@ uint32_t RsvdTraceBuffer::getAggregateSizeOfEntries() const
uint32_t l_aggregatedSize(0);
// Get a handle to the head
- Entry* l_head = getListHead();
+ Entry* l_head(getListHead());
// Make sure the list is not null
if (l_head)
@@ -283,8 +367,8 @@ uint32_t RsvdTraceBuffer::getAggregateSizeOfEntries() const
{
// Need to add to the size, the size of an uint32_t. The uint32_t
// will hold the size of the data that is to be returned along
- // with the returned data. This is why it is added.
- l_aggregatedSize += l_entry->size + sizeof(uint32_t);
+ // with the returned data.
+ l_aggregatedSize += ALIGN_8(l_entry->size) + sizeof(uint32_t);
l_entry = l_entry->next;
} while (l_entry != l_head);
}
@@ -304,12 +388,12 @@ uint32_t RsvdTraceBuffer::getTraceEntries(void* o_data, uint32_t i_dataSize) con
if ((nullptr != o_data) &&
(i_dataSize >= sizeof(trace_buf_head_t)) )
{
+ // Clear the outgoing data before populating it
+ memset(o_data, 0, i_dataSize);
+
// Get a useful "trace buffer head" handle to the data buffer passed in
trace_buf_head_t* l_header =reinterpret_cast<trace_buf_head_t*>(o_data);
- // Now that we have an easy handle to the data, let's clear it for now
- memset(l_header, '\0', sizeof(trace_buf_head_t));
-
// Now populate the trace buffer header with some useful info
l_header->ver = TRACE_BUF_VERSION;
l_header->hdr_len = l_header->size = sizeof(trace_buf_head_t);
@@ -318,35 +402,42 @@ uint32_t RsvdTraceBuffer::getTraceEntries(void* o_data, uint32_t i_dataSize) con
l_header->endian_flg = 'B'; // Big Endian.
// Get a handle to the head
- Entry* l_head = getListHead();
+ Entry* l_head(getListHead());
// Extract the trace info from this class' internal buffer
// If the list is not empty and have data then extract the trace info
if (l_head)
{
- // Keep a tally of the size of the data that can be copied over
- uint32_t l_totalSize(l_head->size);
+ // Keep a tally of the size of the data that can be copied over.
+ // Also account for the trace_buf_head_t that is at the beginning
+ // of buffer o_data.
+ uint32_t l_totalSize(sizeof(trace_buf_head_t));
// Keep a tally of the number of entries that can be extracted
uint32_t l_entriesToExtract(0);
// The entry size as data type uint32_t; for code up keep
uint32_t l_entrySize(0);
// Get a handle on the last entry on the list
- Entry* l_entry = l_head->prev;
+ Entry* l_entry(l_head->prev);
- // Calculate the number of entries that can be stuffed into data buffer
- // starting with newest entry (tail) to oldest entry (head)
+ // Calculate the number of entries that can be stuffed into the data
+ // buffer - starting with newest entry (tail) to oldest entry (head)
do
{
- // Calculate the size: add the size of the data, that will be
- // copied over, plus the size of the type of the entry size,
- // that will hold the size of the data being copied over.
- if ((l_totalSize + l_entry->size + sizeof(l_entrySize)) <= i_dataSize)
+ // Calculate the size: add the size of the data (that will be
+ // copied over) plus the size of the type of the entry size
+ // (that will hold the size of the data being copied over).
+ if ((l_totalSize + ALIGN_8(l_entry->size) + sizeof(l_entrySize))
+ <= i_dataSize)
{
- l_totalSize += l_entry->size + sizeof(l_entrySize);
+ l_totalSize += ALIGN_8(l_entry->size) + sizeof(l_entrySize);
++l_entriesToExtract;
}
else // Can't retrieve this entry; it breaks the size limitation
{
+ // Although we are done here, we still need to point to
+ // the previous item. The continuation of this algorithm
+ // depends on it (expects to be one behind the needed data)
+ l_entry = l_entry->prev;
break;
}
@@ -368,17 +459,18 @@ uint32_t RsvdTraceBuffer::getTraceEntries(void* o_data, uint32_t i_dataSize) con
// Copy entry data.
memcpy(&l_data[l_header->size], l_entry->data, l_entry->size);
- l_header->size += l_entry->size;
+ l_header->size += ALIGN_8(l_entry->size);
// Copy entry size.
l_entrySize = l_entry->size + sizeof(l_entrySize);
memcpy(&l_data[l_header->size], &l_entrySize, sizeof(l_entrySize));
l_header->size += sizeof(l_entrySize);
+ // increment/decrements our counters
++l_header->te_count;
--l_entriesToExtract;
} // end while (l_entriesToExtract)
- } // end if (!isListEmpty())
+ } // end if (l_head)
// Update the size of the entries retrieved and the
// next free memory location in header trace buffer
OpenPOWER on IntegriCloud