summaryrefslogtreecommitdiffstats
path: root/src/usr/trace
diff options
context:
space:
mode:
authorRoland Veloz <rveloz@us.ibm.com>2018-05-30 11:18:42 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2018-06-19 17:24:07 -0400
commit0189e34d3bbc3ce77e1242c94750f99ef0d58d90 (patch)
tree943b04e2a17cf81bd902b99ce862a7b41e69a027 /src/usr/trace
parent1ec6201b896c5cbc22fef03df1a063faa8cd6411 (diff)
downloadtalos-hostboot-0189e34d3bbc3ce77e1242c94750f99ef0d58d90.tar.gz
talos-hostboot-0189e34d3bbc3ce77e1242c94750f99ef0d58d90.zip
Create a utility to add/remove entries from a link list within a given buffer
This buffer is designed to be used in a runtime environment. I am laying the ground work for an over arching story that will save traces in a buffer for future consumption. For this commit, I have created the methods necessary to add, remove and find available space (for an Entry) in a buffer bound region of memory using a circular, doubly linked list. Change-Id: I259bb0f6051611a17b7b919bf026919ffdb12eb1 RTC: 191303 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/59575 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> Reviewed-by: Prachi Gupta <pragupta@us.ibm.com> Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/usr/trace')
-rw-r--r--src/usr/trace/runtime/makefile4
-rw-r--r--src/usr/trace/runtime/rt_rsvdtracebuffer.C413
-rw-r--r--src/usr/trace/runtime/rt_rsvdtracebuffer.H461
-rw-r--r--src/usr/trace/runtime/rt_rsvdtracebufservice.C214
-rw-r--r--src/usr/trace/runtime/rt_rsvdtracebufservice.H122
-rw-r--r--src/usr/trace/runtime/test/makefile2
-rw-r--r--src/usr/trace/runtime/test/testrsvdtracebuf.H1593
7 files changed, 2808 insertions, 1 deletions
diff --git a/src/usr/trace/runtime/makefile b/src/usr/trace/runtime/makefile
index 8974e15c0..7e23a1e71 100644
--- a/src/usr/trace/runtime/makefile
+++ b/src/usr/trace/runtime/makefile
@@ -26,7 +26,7 @@ HOSTBOOT_RUNTIME = 1
ROOTPATH = ../../../..
MODULE = trace_rt
-SUBDIRS += test.d
+EXTRAINCDIR +=${ROOTPATH}/src/usr
OBJS += interface.o
OBJS += assert.o
@@ -43,4 +43,6 @@ OBJS += rt_rsvdtracebufservice.o
VPATH += ..
VPATH += ../daemon
+SUBDIRS += test.d
+
include $(ROOTPATH)/config.mk
diff --git a/src/usr/trace/runtime/rt_rsvdtracebuffer.C b/src/usr/trace/runtime/rt_rsvdtracebuffer.C
new file mode 100644
index 000000000..b9d21b774
--- /dev/null
+++ b/src/usr/trace/runtime/rt_rsvdtracebuffer.C
@@ -0,0 +1,413 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/runtime/rt_rsvdtracebuffer.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2017,2018 */
+/* [+] 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 */
+
+#include "rt_rsvdtracebuffer.H"
+#include <string.h> // memset
+
+namespace TRACE
+{
+/**
+ * ctor
+ */
+RsvdTraceBuffer::RsvdTraceBuffer()
+{
+ // The buffer is not valid - there is no actual/real buffer to point to.
+ // With no actual/real buffer to point to, all internal data is NULL/0.
+ setBufferValidity(false);
+ clearPtrToHead();
+ setBeginningBoundary(nullptr);
+ setEndingBoundary(nullptr);
+}
+
+/**
+ * init
+ */
+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 ( (false == isBufferValid()) &&
+ (i_bufferSize > 0 ) &&
+ (i_addressToBuffer > 0) &&
+ (nullptr != i_addressToHead) )
+ {
+ setBeginningBoundary(convertToCharPointer(i_addressToBuffer));
+ setEndingBoundary(convertToCharPointer(i_addressToBuffer +
+ i_bufferSize - 1));
+ setListHeadPtr(i_addressToHead);
+
+ // 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);
+ }
+}
+
+/**
+ * insertEntry
+ */
+Entry* RsvdTraceBuffer::insertEntry(uint32_t i_dataSize)
+{
+ // Create a handle to an Entry
+ Entry* l_entry(nullptr);
+
+ // Before continuing, make sure the buffer is valid
+ if (isBufferValid())
+ {
+ char* l_availableAddress(nullptr);
+
+ // Bump up the needed size to include the entry itself and
+ // necessary alignment.
+ // (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)
+ {
+ // Set entry if space was created and an avilable address is returned
+ l_entry = reinterpret_cast<Entry*>(l_availableAddress);
+
+ setListTail(l_entry);
+ }
+ }
+
+ return l_entry;
+}
+
+/**
+ * makeSpaceForEntry
+ */
+uint32_t RsvdTraceBuffer::makeSpaceForEntry(uint32_t i_spaceNeeded,
+ char* &o_availableAddress)
+{
+ o_availableAddress = nullptr;
+ uint32_t l_spaceAvailable = 0;
+
+ // Only look for space if requested space is less or equal to buffer size
+ if (i_spaceNeeded <= getBufferSize())
+ {
+ l_spaceAvailable = getAvailableSpace(i_spaceNeeded, o_availableAddress);
+
+ // 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
+ // Should not happen, because the space requested should be less
+ // than or equal to buffer size
+ if (!removeOldestEntry())
+ {
+ l_spaceAvailable = 0;
+ break;
+ }
+
+ l_spaceAvailable = getAvailableSpace(i_spaceNeeded,
+ o_availableAddress);
+ }
+ }
+
+ return l_spaceAvailable;
+}
+
+/**
+ * getAvailableSpace
+ */
+uint32_t RsvdTraceBuffer::getAvailableSpace(uint32_t i_spaceNeeded,
+ char* &o_availableAddress)
+{
+ o_availableAddress = nullptr;
+ uint32_t l_availableSpace(0);
+
+ // If the list is empty, then the full buffer is available
+ if (isListEmpty())
+ {
+ l_availableSpace = getBufferSize();
+ o_availableAddress = iv_bufferBeginningBoundary;
+ }
+ // The list is not empty; must find available space
+ else
+ {
+ // Cache some useful data for easy calculations later on
+ uintptr_t l_bufferBeginningBoundary = getAddressOfPtr(iv_bufferBeginningBoundary);
+ uintptr_t l_bufferEndingBoundary = getAddressOfPtr(iv_bufferEndingBoundary);
+ Entry* l_head = getListHead();
+ uintptr_t l_headAddr = getAddressOfPtr(l_head);
+ uintptr_t l_tailAddrEnd = getEndingAddressOfEntry(l_head->prev);
+
+ // If address of the tail is greater or equal to the head then the tail
+ // will be at the end of the buffer or, in other words, ahead of the head.
+ if (l_tailAddrEnd >= l_headAddr)
+ {
+ // Get available space between the tail and buffer ending boundary
+ size_t l_spaceAtEnd = l_bufferEndingBoundary - l_tailAddrEnd;
+ // Get available space between the buffer beginning boundary and head
+ size_t l_spaceAtBeginning = l_headAddr - l_bufferBeginningBoundary;
+
+ // If the space available at end of buffer is enough to satisfy the
+ // 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
+ //
+ // 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
+ // available, why not return the space at the beginning, the
+ // minimum needed to satisfy our needs. I believe we still would
+ // want to "fill out" the end, before starting with beginning.
+ //
+ // Side note: We want to return contiguous memory only. Although
+ // l_spaceAtEnd + l_spaceAtBeginning may satisfy the space needed,
+ // it is not contiguous.
+ if (l_spaceAtEnd >= i_spaceNeeded)
+ {
+ // There is more available space at the end of the buffer
+ l_availableSpace = l_spaceAtEnd;
+ o_availableAddress = convertToCharPointer(l_tailAddrEnd + 1);
+ }
+ // Just return the space available at beginning and hopefully
+ // that will satisfy our needs
+ else
+ {
+ // There is more available space at the beginning of the buffer
+ l_availableSpace = l_spaceAtBeginning;
+ o_availableAddress = iv_bufferBeginningBoundary;
+ }
+ }
+ // The tail is behind the head in the buffer
+ else
+ {
+ // Get available space between the head and tail
+ l_availableSpace = l_headAddr - l_tailAddrEnd + 1;
+ o_availableAddress = convertToCharPointer(l_tailAddrEnd + 1);
+ }
+ }
+ return l_availableSpace;
+}
+
+/**
+ * removeOldestEntry
+ */
+bool RsvdTraceBuffer::removeOldestEntry()
+{
+ bool l_oldestEntryRemoved(false);
+
+ // If the list is not empty, then remove oldest entry - the head
+ if (!isListEmpty())
+ {
+ // Get a handle to the head
+ Entry* l_head = getListHead();
+
+ // Is there only one entry?
+ if (l_head->next == l_head)
+ {
+ // Yes, just set the head to nullptr and we are done
+ l_head = nullptr;
+ }
+ // There is more than one entry, so remove head (the oldest entry)
+ else
+ {
+ // Point head's next entry to head's previous entry
+ l_head->next->prev = l_head->prev;
+ // Point head's previous entry to head's next entry
+ l_head->prev->next = l_head->next;
+ // Now set head to the next entry
+ l_head = l_head->next;
+ }
+
+ // Update the head of the list
+ setListHead(l_head);
+ l_oldestEntryRemoved = true;
+ }
+
+ return l_oldestEntryRemoved;
+}
+
+/**
+ * getTrace
+ */
+uint32_t RsvdTraceBuffer::getTrace(void* o_data, uint32_t i_dataSize) const
+{
+ uint32_t l_sizeOfBufferExtracted(0);
+
+ // Before continuing, make sure the buffer is valid
+ if (isBufferValid())
+ {
+ if ((nullptr == o_data) || (0 == i_dataSize))
+ {
+ l_sizeOfBufferExtracted = getAggregateSizeOfEntries();
+ }
+ else
+ {
+ l_sizeOfBufferExtracted = getTraceEntries(o_data, i_dataSize);
+ }
+ }
+
+ return l_sizeOfBufferExtracted;
+}
+
+/**
+ * aggregateSizeOfEntries
+ */
+uint32_t RsvdTraceBuffer::getAggregateSizeOfEntries() const
+{
+ uint32_t l_aggregatedSize(0);
+
+ // Get a handle to the head
+ Entry* l_head = getListHead();
+
+ // Make sure the list is not null
+ if (l_head)
+ {
+ Entry* l_entry = l_head;
+ do
+ {
+ // 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);
+ l_entry = l_entry->next;
+ } while (l_entry != l_head);
+ }
+
+ // Add size of trace_buf_head_t to get the true size requirements
+ return (l_aggregatedSize + sizeof(trace_buf_head_t));
+}
+
+/**
+ * getTraceEntries
+ */
+uint32_t RsvdTraceBuffer::getTraceEntries(void* o_data, uint32_t i_dataSize) const
+{
+ uint32_t l_sizeOfEntries(0);
+
+ // Before proceeding, make sure the incoming data is valid
+ if ((nullptr != o_data) &&
+ (i_dataSize >= sizeof(trace_buf_head_t)) )
+ {
+ // 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);
+ l_header->time_flg = TRACE_TIME_REAL;
+ strncpy(l_header->comp, "RSVD_MEM_TRACE", TRAC_COMP_SIZE);
+ l_header->endian_flg = 'B'; // Big Endian.
+
+ // Get a handle to the head
+ 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 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;
+
+ // Calculate the number of entries that can be stuffed into 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)
+ {
+ l_totalSize += l_entry->size + sizeof(l_entrySize);
+ ++l_entriesToExtract;
+ }
+ else // Can't retrieve this entry; it breaks the size limitation
+ {
+ break;
+ }
+
+ l_entry = l_entry->prev;
+ } while (l_entry != l_head->prev);
+
+ // Get a useful "char *" handle to the data buffer passed in,
+ // for easy data injection
+ char* l_data = reinterpret_cast<char*>(o_data);
+
+ // Retrieve the data, going forwards in the list: Want to retrieve
+ // the entries in chronological order
+ // Currently pointing one entry behind the starting entry (starting
+ // entry, meaning the first entry to start gathering data from)
+ while (l_entriesToExtract)
+ {
+ // Get next entry
+ l_entry = l_entry->next;
+
+ // Copy entry data.
+ memcpy(&l_data[l_header->size], l_entry->data, l_entry->size);
+ l_header->size += 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);
+
+ ++l_header->te_count;
+ --l_entriesToExtract;
+ } // end while (l_entriesToExtract)
+ } // end if (!isListEmpty())
+
+ // Update the size of the entries retrieved and the
+ // next free memory location in header trace buffer
+ l_sizeOfEntries = l_header->next_free = l_header->size;
+ }
+
+ return l_sizeOfEntries;
+}
+
+/**
+ * getNumberOfEntries
+ */
+uint32_t RsvdTraceBuffer::RsvdTraceBuffer::getNumberOfEntries() const
+{
+ uint32_t l_numberOfEntries(0);
+
+ // If the list is not empty, count the entries
+ if (!isListEmpty())
+ {
+ // Get a handle to the head
+ Entry* l_head = getListHead();
+ do
+ {
+ ++l_numberOfEntries;
+ l_head = l_head->next;
+ } while (l_head != getListHead());
+ }
+
+ return l_numberOfEntries;
+}
+
+} // end namespace TRACE
diff --git a/src/usr/trace/runtime/rt_rsvdtracebuffer.H b/src/usr/trace/runtime/rt_rsvdtracebuffer.H
new file mode 100644
index 000000000..24c9204cf
--- /dev/null
+++ b/src/usr/trace/runtime/rt_rsvdtracebuffer.H
@@ -0,0 +1,461 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/runtime/rt_rsvdtracebuffer.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2012,2018 */
+/* [+] 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 */
+#ifndef __RSVD_TRACE_BUFFER_H
+#define __RSVD_TRACE_BUFFER_H
+
+/** @file rt_rsvdtracebuffer.H
+ * Declarations for the RsvdTraceBuffer (Reserved Trace Buffer) class.
+ */
+
+#include <stdint.h> // uint32_t
+#include <trace/entry.H> // Entry
+#include <util/align.H> // ALIGN_8
+
+// Forward declaration of the test suite
+class RsvdTraceBuffTestSuite;
+
+namespace TRACE
+{
+
+ /** @class RsvdTraceBuffer
+ *
+ * @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.
+ *
+ */
+ class RsvdTraceBuffer
+ {
+ public:
+
+ /** Constructor.
+ */
+ RsvdTraceBuffer();
+
+ /** Initializes the buffer, if previously not done.
+ *
+ * @param[in] i_bufferSize - Size of the buffer.
+ *
+ * @param[in] i_addressToBuffer - Where the buffer begins
+ *
+ * @param[in] i_addressToHead - A pointer to a ponter to the first
+ * Entry, cannot be a nullptr
+ */
+ void init(uint32_t i_bufferSize,
+ uintptr_t i_addressToBuffer,
+ uintptr_t* i_addressToHead);
+
+ /** @brief This function will insert an Entry to the buffer
+ *
+ * @param[in] i_dataSize - The size of the contiguous piece
+ * of memory caller desires
+ *
+ * @return A valid Entry pointer if space found for an Entry;
+ * nullptr otherwise
+ */
+ Entry* insertEntry(uint32_t i_dataSize);
+
+ /** @brief Extract the trace info or return aggregated size of the
+ * traces
+ *
+ * @algorithm If o_data is null or i_dataSize is 0, then this
+ * method will return all the trace sizes, this class
+ * contains, aggregated together.
+ * If o_data is valid and the i_size is less than
+ * the size of trace_buf_head_t, then 0 is returned.
+ * 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.
+ *
+ * @param[in] 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,
+ * which dictates how many trace entries'
+ * payload (or data the entry contains)
+ * that can be copied
+ *
+ * @return the size of the trace data being returned, or the
+ * aggregated size of the traces, or 0
+ */
+ uint32_t getTrace(void* o_data, uint32_t i_dataSize) const;
+
+
+ /** @brief Return the state of buffer
+ *
+ * @return true if buffer has been initialized properly,
+ * false otherwise
+ *
+ */
+ bool isBufferValid() const
+ { return iv_isBufferValid; }
+
+ /** @brief Clears the buffer of all entries
+ */
+ void clearBuffer()
+ { setListHead(reinterpret_cast<TRACE::Entry*>(NULL)); }
+
+ /** @brief Retrieve the number of entries in buffer
+ */
+ uint32_t getNumberOfEntries() const;
+
+ private:
+ /** @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
+ * the space needed, then space will be created that will be
+ * large enough for the space needed with one caveat - if
+ * the space requested is greater than the size of the
+ * buffer, then no attempt will be made to accommodate the
+ * space needed but instead 0 will be returned and
+ * o_availableAddress will be set to nullptr.
+ *
+ * @algorithm Call the method getAvailableSpace (below) to get
+ * the largest contiguous piece of memory, whether it
+ * satisfies our needs or not. If it does satisfy our
+ * needs, then return the size of the space found and a
+ * pointer to the beginning of that space. If it does
+ * not satisfy our spatial needs, then remove the head
+ * entry from the list and check again. We remove the
+ * head because the head entry will be the oldest entry
+ * (time wise). Repeat until we get the space needed
+ * or until all entries are removed. Unless the space
+ * 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[out] o_availableAddress - A pointer to the contiguous
+ * piece of memory found that satisfies the caller's
+ * request. If not found, then nullptr
+ *
+ * @return the size of the space found/created; 0 if none
+ * found/created
+ */
+ uint32_t makeSpaceForEntry(uint32_t i_spaceNeeded,
+ 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
+ * piece of memory.
+ *
+ * @algorithm There are three cases to consider:
+ * 1) Tail is in front of the head (address wise, not
+ * logical wise) and the space between tail and end
+ * of buffer satisfies our spatial needs then return the
+ * space between tail and buffer end.
+ * Example 1:
+ * --- Beginning of Buffer End of Buffer ---
+ * | |
+ * V V
+ * ---------------------------------------------------------
+ * | < - 10 bytes -> | Head | .....| Tail | <- 20 bytes -> |
+ * ---------------------------------------------------------
+ * scenario 1: Contigous space desired: 15 bytes
+ * Return the 20 bytes after the Tail
+ * scenario 2: Contiguous space desired: 10 bytes
+ * Return the 20 bytes after the Tail
+ * Here we can return the 10 bytes or
+ * 20 bytes - both satisfy the condition.
+ * In this case, return the 20 bytes to
+ * take full advantage of the buffer.
+ *
+ * 2) Tail is in front of the head and case 1 above cannot
+ * be satisfied then return the space between the
+ * beginning of buffer and head.
+ * Example 2.1:
+ * --- Beginning of Buffer End of Buffer ---
+ * | |
+ * V V
+ * ---------------------------------------------------------
+ * | < - 30 bytes -> | Head | .....| Tail | <- 15 bytes -> |
+ * ---------------------------------------------------------
+ * scenario 1: Contiguous space desired: 25 bytes
+ * Return the 30 bytes before the Head
+ * scenario 2: Contiguous space desired: 40 bytes
+ * Return the 30 bytes before the Head
+ *
+ * Example 2.2:
+ * --- Beginning of Buffer End of Buffer ---
+ * | |
+ * V V
+ * ---------------------------------------------------------
+ * | < - 5 bytes -> | Head | .....| Tail | <- 15 bytes -> |
+ * ---------------------------------------------------------
+ * scenario 1: Contiguous space desired: 20 bytes
+ * Return the 5 bytes before the Head
+ * The reason for returning 5 bytes, even
+ * though 15 bytes is greater is because,
+ * ultimately space will be created at
+ * the beginning of the buffer.
+ *
+ * 3) Tail is behind head, then simply return the
+ * available space between the two.
+ * Example 3:
+ * --- Beginning of Buffer End of Buffer ---
+ * | |
+ * V V
+ * ---------------------------------------------------------
+ * | .... | Tail | < - 30 bytes -> | Head | ....
+ * ---------------------------------------------------------
+ * Case 1: Contigous space desired: 25 bytes
+ * Return the 30 bytes between Tail and Head.
+ * Case 2: Contigous space desired: 40 bytes
+ * Return the 30 bytes between Tail and Head.
+ *
+ * @param[in] i_spaceNeeded - @see insertEntry::i_dataSize above
+ *
+ * @param[out] o_availableAddress - @see makeSpaceForEntry above
+ *
+ * @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
+ *
+ */
+ uint32_t getAvailableSpace(uint32_t i_spaceNeeded,
+ char* &o_availableAddress);
+
+ /** @brief Remove the head of the list, because the head is the
+ * oldest entry
+ *
+ * @return Returns true if oldest entry is removed; false otherwise
+ */
+ bool removeOldestEntry();
+
+ /** @brief This will aggregate all the entries' data size and
+ * return it
+ *
+ * @return Returns all the entries' data size plus the size of
+ * an uint32_t for each one.
+ */
+ uint32_t getAggregateSizeOfEntries() const;
+
+ /** @brief This will return as many data entries that can be
+ * accommodated by size
+ *
+ * @param[out] o_data - the buffer area to copy trace data into
+ *
+ * @param[in] i_dataSize - the size of the buffer area, which
+ * dictates how many trace data can be
+ * copied
+ *
+ * @return Returns all the entries' data size plus the size of
+ * an uint32_t for each one, that can be accommodated
+ */
+ uint32_t getTraceEntries(void* o_data, uint32_t i_dataSize) const;
+
+
+ /** @brief Return true if list empty
+ *
+ * @return true if list empty; false otherwise
+ */
+ bool isListEmpty() const
+ { return (nullptr == getListHead()); }
+
+ /** @brief Return the address of a pointer
+ *
+ * @param[in] i_entry - a pointer to data type;
+ * void pointer for our purposes
+ *
+ * @return The address of the supplied pointer
+ *
+ * @pre i_entry is NOT a nullptr
+ */
+ uintptr_t getAddressOfPtr(const void *i_entry) const
+ { return reinterpret_cast<uintptr_t>(i_entry); };
+
+ /** @brief Get the address at the end of an Entry, which is the
+ * size of the Entry plus any padding for memory alignment
+ *
+ * @param[in] i_entry - a pointer to an Entry data type
+ *
+ * @return The address at the end of an Entry
+ *
+ * @pre i_entry is NOT a nullptr
+ */
+ uintptr_t getEndingAddressOfEntry(const Entry *i_entry) const
+ { return (getAddressOfPtr(i_entry) +
+ getAlignedSizeOfEntry(i_entry->size) -1); };
+
+ /** @brief Converts an address to a character pointer
+ *
+ * @param[in] i_addressOfPtr - a legitimate address
+ *
+ * @return A character pointer to the address supplied
+ *
+ * @pre i_addressOfPtr is a a legitimate address of a memory
+ * location
+ */
+ char* convertToCharPointer(uintptr_t i_addressOfPtr) const
+ { return reinterpret_cast<char*>(i_addressOfPtr); };
+
+ /** @brief Save away the beginning boundary of the buffer
+ *
+ * @param[in] i_bufferBeginningBoundary - a pointer to the
+ * beginning of the buffer
+ *
+ */
+ void setBeginningBoundary(char* i_bufferBeginningBoundary)
+ { iv_bufferBeginningBoundary = i_bufferBeginningBoundary; };
+
+ /** @brief Save away the ending boundary of the buffer
+ *
+ * @param[in] i_bufferEndingBoundary - a pointer to the
+ * end of the buffer
+ *
+ */
+ void setEndingBoundary(char * i_bufferEndingBoundary)
+ { iv_bufferEndingBoundary = i_bufferEndingBoundary; }
+
+ /** @brief Set the head of the list
+ *
+ * @param[in] i_addressToHead - pointer to an area outside
+ * the controlled buffer that stays updated with
+ * the head of the list; OK to be a nullptr
+ *
+ */
+ void setListHeadPtr(uintptr_t* i_addressToHead)
+ { iv_ptrToHead = i_addressToHead; };
+
+ /** @brief Set the head of the list
+ *
+ * @param[in] i_head - a pointer to an Entry data type;
+ * OK to be a nullptr
+ *
+ */
+ void setListHead(Entry* i_entry)
+ {
+ if (nullptr != i_entry)
+ {
+ i_entry->next = i_entry->prev = i_entry;
+ }
+ // Sanity check, make sure the pointer to head is valid
+ if (nullptr != iv_ptrToHead)
+ {
+ *iv_ptrToHead = getAddressOfPtr(i_entry);
+ }
+ };
+
+ /** @brief Get the head of the list
+ *
+ * @return return the head of the list as an Entry pointer
+ */
+ Entry* getListHead() const
+ {
+ Entry* l_entry = nullptr;
+ // Make sure the pointer is valid before de-referencing it
+ if (nullptr != iv_ptrToHead)
+ {
+ l_entry = reinterpret_cast<Entry*>(*iv_ptrToHead);
+ };
+ return l_entry;
+ }
+
+ /** @brief Append an entry to the end of the list
+ *
+ * @param[in] i_tail - a pointer to an Entry data type;
+ * OK to be a nullptr
+ *
+ */
+ void setListTail(Entry* i_newEntry)
+ {
+ Entry* l_head = getListHead();
+
+ // If there is a head and user passed in a legitimate tail
+ // then add the tail at the end of the list
+ if (l_head && i_newEntry)
+ {
+ // Get a handle to old tail
+ Entry* l_tail = l_head->prev;
+ // Point new entry's (new tail) next entry to head
+ i_newEntry->next = l_head;
+ // Point new entry's (new tail) previous entry to tail (old tail)
+ i_newEntry->prev = l_tail;
+ // Point head's previous to the new entry (new tail)
+ l_head->prev = i_newEntry;
+ // Point tail (old tail) to the new entry (new tail)
+ l_tail->next = i_newEntry;
+ }
+ // Else, head is a nullptr and user passed in a
+ // legitimate new Entry, then set head to new Entry
+ else if (i_newEntry)
+ {
+ setListHead(i_newEntry);
+ }
+ // else tail is not legit, so let's get out of here,
+ // nothing to do
+ }
+
+
+ /** @brief Get the size of the buffer; the buffer that is available
+ * for Entries.
+ *
+ * @return Size of buffer
+ */
+ uint32_t getBufferSize() const
+ { return (iv_bufferEndingBoundary -
+ iv_bufferBeginningBoundary + 1); };
+
+ /** @brief Get the size of an Entry plus the bytes needed to memory
+ * align the Entry.
+ *
+ * @param[in] i_dataSize - the size of the data that extends beyond
+ * the Entry data type
+ *
+ * @return The total size of Entry; includes size of the Entry
+ * itself, size of the data that is associated with Entry
+ * and extras size so as to be properly aligned
+ *
+ */
+ uint32_t getAlignedSizeOfEntry(uint32_t i_dataSize) const
+ { return ALIGN_8(sizeof(Entry) + i_dataSize); }
+
+ /** @brief Set the buffer state
+ *
+ * @param[in] i_state - the new state of the buffer; false or true
+ *
+ */
+ void setBufferValidity(bool i_state)
+ { iv_isBufferValid = i_state; }
+
+ /** @brief Clears the the pointer that points to the head
+ */
+ void clearPtrToHead()
+ { iv_ptrToHead = nullptr; }
+
+ 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
+ friend class ::RsvdTraceBuffTestSuite;
+};
+}
+
+#endif
diff --git a/src/usr/trace/runtime/rt_rsvdtracebufservice.C b/src/usr/trace/runtime/rt_rsvdtracebufservice.C
new file mode 100644
index 000000000..44d76096f
--- /dev/null
+++ b/src/usr/trace/runtime/rt_rsvdtracebufservice.C
@@ -0,0 +1,214 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/runtime/rt_rsvdtracebufservice.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2013,2018 */
+/* [+] 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 */
+
+#include "rt_rsvdtracebufservice.H"
+#include <trace/compdesc.H> // ComponentDes
+#include <trace/entry.H> // Entry
+#include <util/runtime/util_rt.H> // hb_get_rt_rsvd_mem
+#include <errl/errlmanager.H> // errlCommit
+#include <runtime/interface.h> // g_hostInterfaces, postInitCalls_t
+#include <runtime/runtime_reasoncodes.H> // RUNTIME::MOD_INIT_RT_RES_MEM_TRACE_BUF
+
+namespace TRACE
+{
+
+/**
+ * ctor
+ */
+RsvdTraceBufService::RsvdTraceBufService( )
+: iv_errl(nullptr)
+{
+}
+
+/**
+ * init
+ */
+void RsvdTraceBufService::init()
+{
+ g_hostInterfaces->puts( " >> RsvdTraceBufService::init\n");
+
+ // Get the size and location of the reserved trace buffer section
+ uint64_t l_bufferSize(0);
+ uint64_t l_reservedMemory = hb_get_rt_rsvd_mem(Util::HBRT_MEM_LABEL_TRACEBUF,
+ 0, l_bufferSize);
+
+ // The first part of buffer is where the head of a link list will reside.
+ // It needs to reside here so if we go down in flames, we can pick
+ // up where we left off
+ if ( (l_reservedMemory != 0) && (l_bufferSize > sizeof(uintptr_t)) )
+ {
+ // Get a pointer to where the head of the data is
+ uintptr_t *l_addressToHead =
+ reinterpret_cast<uintptr_t *>(l_reservedMemory);
+
+ // The RsvdTraceBuffer is only concerned with the part of the buffer
+ // that it will maintain. Therefore, send the buffer size minus the
+ // size of an uintptr_t which is set aside for the first entry of the
+ // buffer. Then add the size of an uintptr_t to the l_reservedMemory
+ // (the beginning address of buffer) to get the beginning address of
+ // which the RsvdTraceBuffer will be responsible for.
+ iv_rsvdTraceBuffer.init(l_bufferSize - sizeof(uintptr_t),
+ l_reservedMemory + sizeof(uintptr_t),
+ l_addressToHead);
+
+ // 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();
+ }
+
+ // After gathering trace info from previous crash, clear buffer data
+ iv_rsvdTraceBuffer.clearBuffer();
+ }
+
+ g_hostInterfaces->puts(" << RsvdTraceBufService::init\n");
+}
+
+/**
+ * retrieveDataFromLastCrash
+ */
+void RsvdTraceBufService::retrieveDataFromLastCrash()
+{
+ g_hostInterfaces->puts(
+ " >> RsvdTraceBufService::retrieveDataFromLastCrash\n");
+
+ iv_errl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_INFORMATIONAL,
+ RUNTIME::MOD_INIT_RT_RES_MEM_TRACE_BUF,
+ RUNTIME::RC_RT_RES_TRACE_BUF_DUMPED,
+ 0,0,true);
+
+ // Note: Set the iv_rsvdTraceBuffer before calling collectTrace()
+ iv_errl->collectTrace("RSVD_MEM_TRACE",0);
+
+ // Can not commit the errl until the ErrlManager gets initialized.
+ // Committing will be done in commitRsvdMemTraceErrl() after
+ // ErrlManager gets initialized
+ g_hostInterfaces->puts(
+ " << RsvdTraceBufService::retrieveDataFromLastCrash\n");
+}
+
+
+/**
+ * commitRsvdMemTraceErrl
+ */
+bool RsvdTraceBufService::commitRsvdMemTraceErrl()
+{
+ g_hostInterfaces->puts(" >> RsvdTraceBufService::commitRsvdMemTraceErrl\n");
+
+ bool l_errlCommitted = false;
+
+ // Commit the iv_errl, if valid
+ if (iv_errl)
+ {
+ errlCommit(iv_errl, RUNTIME_COMP_ID);
+ l_errlCommitted = true;
+ }
+
+ g_hostInterfaces->puts(" << RsvdTraceBufService::commitRsvdMemTraceErrl\n");
+
+ return l_errlCommitted;
+}
+
+/**
+ * writeEntry
+ */
+void RsvdTraceBufService::writeEntry(ComponentDesc* i_componentDesc,
+ char* i_data,
+ uint32_t i_dataSize)
+{
+ // Sanity check, make sure user passed in legit data
+ if ((nullptr != i_componentDesc) && (nullptr != i_data) && (i_dataSize > 0))
+ {
+ // Add an entry into the reserved trace buffer
+ Entry* l_entry = iv_rsvdTraceBuffer.insertEntry(i_dataSize);
+ if (nullptr != l_entry)
+ {
+ // Assign the component description and entry size.
+ l_entry->comp = i_componentDesc;
+ l_entry->size = i_dataSize;
+
+ //copy the contents in to the entry's data section
+ memcpy(&l_entry->data[0], i_data, i_dataSize);
+
+ // "Commit" entry to buffer.
+ l_entry->committed = 1;
+ }
+ }
+}
+
+/**
+ * getBuffer
+ */
+uint32_t RsvdTraceBufService::getBuffer(void* o_data, uint32_t i_dataSize) const
+{
+ return iv_rsvdTraceBuffer.getTrace(o_data, i_dataSize);
+}
+
+} //end of namespace
+
+/**
+ * initRsvdTraceBufService
+ */
+void initRsvdTraceBufService()
+{
+ g_hostInterfaces->puts(" >> RsvdTraceBufService::initRsvdTraceBufService\n");
+
+ //get the reserved memory and initialize
+ Singleton<TRACE::RsvdTraceBufService>::instance().init();
+
+ g_hostInterfaces->puts(" << RsvdTraceBufService::initRsvdTraceBufService\n");
+
+}
+
+/**
+ * commitRsvdTraceBufErrl
+ */
+void commitRsvdTraceBufErrl()
+{
+ g_hostInterfaces->puts(" >> RsvdTraceBufService::commitRsvdTraceBufErrl\n");
+
+ // Commit the errl with traces from previous boot, if buffer is valid
+ Singleton<TRACE::RsvdTraceBufService>::instance().commitRsvdMemTraceErrl();
+
+ g_hostInterfaces->puts(" << RsvdTraceBufService::commitRsvdTraceBufErrl\n");
+}
+
+struct register_initRsvdTraceBufService
+{
+ register_initRsvdTraceBufService()
+ {
+ // Register interface for Host to call
+ postInitCalls_t * rt_post = getPostInitCalls();
+ rt_post->callInitRsvdTraceBufService = &initRsvdTraceBufService;
+ rt_post->callCommitRsvdTraceBufErrl = &commitRsvdTraceBufErrl;
+ }
+};
+
+
+//create a global object to force initialize the Service & RsvdTraceBufService objects
+register_initRsvdTraceBufService g_register_initRsvdTraceBufService;
+
diff --git a/src/usr/trace/runtime/rt_rsvdtracebufservice.H b/src/usr/trace/runtime/rt_rsvdtracebufservice.H
new file mode 100644
index 000000000..727ab8dae
--- /dev/null
+++ b/src/usr/trace/runtime/rt_rsvdtracebufservice.H
@@ -0,0 +1,122 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/runtime/rt_rsvdtracebufservice.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2012,2018 */
+/* [+] 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 */
+#ifndef __RSVD_TRACE_SERVICE_H
+#define __RSVD_TRACE_SERVICE_H
+
+/** @file rt_rsvdtracebufservice.H
+ *
+ * @brief class with functions to write HBRT traces in to Reserved Trace Buffer
+ *
+ * In the constructor, this will get the reserved memory section through
+ * hb_get_rt_rsvd_mem(Util::HBRT_MEM_LABEL_TRACEBUF) and uses the buffer
+ * to write the HBRT traces of all components serially.
+ * Writing to Reserved Trace Buffer is serialized in this class via Mutex
+ *
+ * Reserved Trace Buffer is a wrappable circular buffer, oldest entries
+ * are deleted to write the new trace entries
+ *
+ */
+
+#include "rt_rsvdtracebuffer.H" // RsvdTraceBuffer
+#include <errl/errlentry.H> // errlHndl_t
+
+// Forward declaration of the test suite
+class RsvdTraceBuffTestSuite;
+
+namespace TRACE
+{
+ // Forward declarations
+ class ComponentDesc;
+
+ /** @class RsvdTraceBufService
+ *
+ * @brief Front-end interfaces for reserved trace buffer.
+ *
+ * There should be a single instance(a singleton) of this class with
+ * delayed construction. Constructed when needed not at start up.
+ */
+ class RsvdTraceBufService
+ {
+ public:
+ /** Default constructor */
+ RsvdTraceBufService();
+
+ /** Initializes the buffer, if previously not done.*/
+ void init();
+
+ /** Commits the iv_errl with Trace from previous boot,
+ * if created in init()
+ *
+ * @return true if iv_errl is valid, otherwise false.
+ */
+ bool commitRsvdMemTraceErrl();
+
+ /** @brief Write a Normal/Binary entry to a trace buffer
+ *
+ * @param[in] i_componentDesc - Component Descriptor to write to.
+ *
+ * @param[in] i_data - pointer to the FSP formatted trace data.
+ * @param[in] i_size - size of the data
+ */
+ void writeEntry(ComponentDesc* i_componentDesc,
+ char* i_data,
+ uint32_t i_dataSize);
+
+
+ /** @brief Extracts Reserved Trace buffer.
+ *
+ * @param[out] o_data - Data buffer to copy to.
+ * @param[in] i_size - Size of buffer.
+ *
+ * @return Size of buffer extracted.
+ *
+ * If either (o_data == NULL) or (i_size == 0), rather than
+ * copy data from the internal buffer, the function will calculate
+ * the size of the data buffer needed to save all of the data
+ * currently in the internal buffer.
+ */
+ uint32_t getBuffer(void * o_data, uint32_t i_dataSize) const;
+
+ private:
+
+ /** @brief Retrieve the trace info left behind in
+ * buffer from last crash
+ */
+ void retrieveDataFromLastCrash();
+
+ /** The reserved trace buffer section,
+ * which contains the runtime traces
+ */
+ RsvdTraceBuffer iv_rsvdTraceBuffer;
+
+ /** errlHandl to hold the trace from the previous boot, if any */
+ errlHndl_t iv_errl;
+
+ // For testing purposes only
+ friend class ::RsvdTraceBuffTestSuite;
+ };
+}
+
+#endif
diff --git a/src/usr/trace/runtime/test/makefile b/src/usr/trace/runtime/test/makefile
index b0ad1841c..b7f134d82 100644
--- a/src/usr/trace/runtime/test/makefile
+++ b/src/usr/trace/runtime/test/makefile
@@ -25,6 +25,8 @@
HOSTBOOT_RUNTIME = 1
ROOTPATH = ../../../../..
+EXTRAINCDIR +=${ROOTPATH}/src/usr
+
MODULE = testrsvdtracebuf_rt
TESTS = testrsvdtracebuf.H
diff --git a/src/usr/trace/runtime/test/testrsvdtracebuf.H b/src/usr/trace/runtime/test/testrsvdtracebuf.H
new file mode 100644
index 000000000..148df5d07
--- /dev/null
+++ b/src/usr/trace/runtime/test/testrsvdtracebuf.H
@@ -0,0 +1,1593 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/runtime/test/testrsvdtracebuf.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2013,2018 */
+/* [+] 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 */
+#include <cxxtest/TestSuite.H>
+
+#include <trace/runtime/rt_rsvdtracebuffer.H> // TRACE::RsvdTraceBuffer
+#include <trace/runtime/rt_rsvdtracebufservice.H> // TRACE::RsvdTraceBufService
+#include <trace/entry.H> // TRACE::Entry
+#include <trace/compdesc.H> // TRACE::ComponentDesc
+#include <util/runtime/util_rt.H> // hb_get_rt_rsvd_mem
+
+#include <stdint.h> // uint32_t
+#include <stdlib.h> // malloc
+#include <string.h> // memset
+
+
+class RsvdTraceBuffTestSuite : public CxxTest::TestSuite
+{
+public:
+
+// Let's start with some simple tests - the constructor
+void testRsvdTraceBuffConstructor()
+{
+ TRACFCOMP(g_trac_test, ENTER_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+
+ TRACE::RsvdTraceBuffer l_rsvd;
+
+ if (nullptr != l_rsvd.iv_bufferBeginningBoundary)
+ {
+ TS_FAIL("%s:%s: beginning buffer boundary is not null",
+ __FILE__, __func__);
+ }
+
+ if (nullptr != l_rsvd.iv_bufferEndingBoundary)
+ {
+ TS_FAIL("%s:%s: ending buffer boundary is not null",__FILE__, __func__);
+ }
+
+ if (nullptr != l_rsvd.iv_ptrToHead)
+ {
+ TS_FAIL("%s:%s: list head is not null", __FILE__, __func__);
+ }
+
+ if (nullptr != l_rsvd.getListHead())
+ {
+ TS_FAIL("%s:%s: list head is not null", __FILE__, __func__);
+ }
+
+ if (false != l_rsvd.iv_isBufferValid)
+ {
+ TS_FAIL("%s:%s: buffer validity is not false", __FILE__, __func__);
+ }
+
+ if (false != l_rsvd.isBufferValid())
+ {
+ TS_FAIL("%s:%s: buffer validity is not false", __FILE__, __func__);
+ }
+
+ if (true != l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is NOT empty", __FILE__, __func__);
+ }
+
+ TRACFCOMP(g_trac_test, EXIT_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+} // void testRsvdTraceBuffConstructor()
+
+// Some more simple tests - the initializer
+void testRsvdTraceBuffInit()
+{
+ TRACFCOMP(g_trac_test, ENTER_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+
+ // Create a buffer
+ uint32_t l_bufferSize = 40;
+ char *l_buffer = reinterpret_cast<char*>(malloc(l_bufferSize));
+ memset(l_buffer, 0 , l_bufferSize);
+
+ // Get the address of buffer; just like we would get in "real life"
+ uintptr_t l_bufferAddr = reinterpret_cast<uintptr_t>(l_buffer);
+
+ // Get a pointer to where the HEAD needs to reside in the buffer
+ uintptr_t *l_addressToHead = reinterpret_cast<uintptr_t *>(l_bufferAddr);
+
+ // Initialize the buffer
+ TRACE::RsvdTraceBuffer l_rsvd;
+ l_rsvd.init(l_bufferSize - sizeof(uintptr_t),
+ l_bufferAddr + sizeof(uintptr_t),
+ l_addressToHead);
+
+ char* l_bufferBegin = reinterpret_cast<char*>(l_bufferAddr +
+ sizeof(uintptr_t));
+ char* l_bufferEnd = reinterpret_cast<char*>(l_bufferAddr +
+ l_bufferSize - 1);
+
+ if (l_bufferBegin != l_rsvd.iv_bufferBeginningBoundary)
+ {
+ TS_FAIL("%s:%s: beginning buffer boundary is not null",
+ __FILE__, __func__);
+ }
+
+ if (l_bufferEnd != l_rsvd.iv_bufferEndingBoundary)
+ {
+ TS_FAIL("%s:%s: ending buffer boundary not set properly",
+ __FILE__, __func__);
+ }
+
+ if (true != l_rsvd.iv_isBufferValid)
+ {
+ TS_FAIL("%s:%s: buffer validity is not true", __FILE__, __func__);
+ }
+
+ if (true != l_rsvd.isBufferValid())
+ {
+ TS_FAIL("%s:%s: buffer validity is not true", __FILE__, __func__);
+ }
+
+ if (nullptr == l_rsvd.iv_ptrToHead)
+ {
+ TS_FAIL("%s:%s: list head is Null", __FILE__, __func__);
+ }
+
+ if (nullptr != l_rsvd.getListHead())
+ {
+ TS_FAIL("%s:%s: list head is NOT NULL", __FILE__, __func__);
+ }
+
+ if (l_bufferAddr != reinterpret_cast<uintptr_t>(l_rsvd.iv_ptrToHead))
+ {
+ TS_FAIL("%s:%s: Pointer to list is not correct", __FILE__, __func__);
+ }
+
+ if (true != l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is not empty", __FILE__, __func__);
+ }
+
+ TRACFCOMP(g_trac_test, EXIT_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+} // end void testRsvdTraceBuffInit()
+
+// Test where buffer is too small to accommodate any Entry size
+void testRsvdTraceBuffBufferToSmall()
+{
+ TRACFCOMP(g_trac_test, ENTER_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+
+ uint32_t l_bufferSize = ALIGN_8(sizeof(TRACE::Entry)) -1;
+ TRACE::RsvdTraceBuffer l_rsvd;
+ char *l_buffer = initializeRsvdBuffer(l_bufferSize, l_rsvd);
+
+ if (l_rsvd.getBufferSize() != l_bufferSize)
+ {
+ TS_FAIL("%s:%s: buffer size is not correct", __FILE__, __func__);
+ }
+
+ TRACE::Entry* l_entry = l_rsvd.insertEntry(0);
+ if (nullptr != l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is NOT null", __FILE__, __func__);
+ }
+
+ if (true != l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is not empty", __FILE__, __func__);
+ }
+
+ if (reinterpret_cast<uintptr_t>(l_buffer) !=
+ reinterpret_cast<uintptr_t>(l_rsvd.iv_ptrToHead))
+ {
+ TS_FAIL("%s:%s: Pointer to list is not correct", __FILE__, __func__);
+ }
+
+ l_entry = l_rsvd.insertEntry(1);
+ if (nullptr != l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is NOT null", __FILE__, __func__);
+ }
+
+ if (true != l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is not empty", __FILE__, __func__);
+ }
+
+ if (reinterpret_cast<uintptr_t>(l_buffer) !=
+ reinterpret_cast<uintptr_t>(l_rsvd.iv_ptrToHead))
+ {
+ TS_FAIL("%s:%s: Pointer to list is not correct", __FILE__, __func__);
+ }
+
+ l_entry = l_rsvd.insertEntry(sizeof(TRACE::Entry));
+ if (nullptr != l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is NOT null", __FILE__, __func__);
+ }
+
+ if (true != l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is not empty", __FILE__, __func__);
+ }
+
+ if (reinterpret_cast<uintptr_t>(l_buffer) !=
+ reinterpret_cast<uintptr_t>(l_rsvd.iv_ptrToHead))
+ {
+ TS_FAIL("%s:%s: Pointer to list is not correct", __FILE__, __func__);
+ }
+
+ free(l_buffer);
+
+ TRACFCOMP(g_trac_test, EXIT_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+} // end void testRsvdTraceBuffBufferToSmall()
+
+// Test where buffer is just the right size to fit a single Entry
+void testRsvdTraceBuffOnlyAccommodateOneItem()
+{
+ TRACFCOMP(g_trac_test, ENTER_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+
+ TRACE::RsvdTraceBuffer l_rsvd;
+ uint32_t l_bufferSize = ALIGN_8(sizeof(TRACE::Entry));
+ uint32_t l_entrySize = l_bufferSize - sizeof(TRACE::Entry);
+ char *l_buffer = initializeRsvdBuffer(l_bufferSize,
+ l_rsvd);
+
+ if (l_rsvd.getBufferSize() != l_bufferSize)
+ {
+ TS_FAIL("%s:%s: buffer size is not correct", __FILE__, __func__);
+ }
+
+ TRACE::Entry* l_entry = l_rsvd.insertEntry(l_entrySize);
+ char* l_entryCharPtr = reinterpret_cast<char*>(l_entry);
+ uint32_t l_endingPos = ALIGN_8(sizeof(TRACE::Entry) + l_entrySize) - 1;
+ char* l_entryEndCharPtr = l_entryCharPtr + l_endingPos;
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is null", __FILE__, __func__);
+ }
+
+ if (true == l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is empty", __FILE__, __func__);
+ }
+
+ if (l_entryCharPtr != l_rsvd.iv_bufferBeginningBoundary)
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != l_rsvd.iv_bufferEndingBoundary)
+ {
+ TS_FAIL("%s:%s: entry ending position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != l_rsvd.convertToCharPointer
+ (l_rsvd.
+ getEndingAddressOfEntry(l_entry)))
+ {
+ TS_FAIL("%s:%s: entry ending position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (reinterpret_cast<uintptr_t>(l_buffer) !=
+ reinterpret_cast<uintptr_t>(l_rsvd.iv_ptrToHead))
+ {
+ TS_FAIL("%s:%s: Pointer to list is not correct", __FILE__, __func__);
+ }
+
+ if (true != runSelfDiagnostics(l_rsvd))
+ {
+ TS_FAIL("%s:%s: self diagnostics discovered an error",
+ __FILE__, __func__);
+ }
+
+ // Add another item with same size
+ l_entry = l_rsvd.insertEntry(l_entrySize);
+ l_entryCharPtr = reinterpret_cast<char*>(l_entry);
+ l_entryEndCharPtr = l_entryCharPtr + l_endingPos;
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr IS null", __FILE__, __func__);
+ }
+
+ if (true == l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is empty", __FILE__, __func__);
+ }
+
+ if (l_entryCharPtr != l_rsvd.iv_bufferBeginningBoundary)
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != l_rsvd.convertToCharPointer
+ (l_rsvd.
+ getEndingAddressOfEntry(l_entry)))
+ {
+ TS_FAIL("%s:%s: entry ending position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != l_rsvd.iv_bufferEndingBoundary)
+ {
+ TS_FAIL("%s:%s: entry ending position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (reinterpret_cast<uintptr_t>(l_buffer) !=
+ reinterpret_cast<uintptr_t>(l_rsvd.iv_ptrToHead))
+ {
+ TS_FAIL("%s:%s: Pointer to list is not correct", __FILE__, __func__);
+ }
+
+ if (true != runSelfDiagnostics(l_rsvd))
+ {
+ TS_FAIL("%s:%s: self diagnostics discovered an error",
+ __FILE__, __func__);
+ }
+
+ // Add another item with size+
+ l_entry = l_rsvd.insertEntry(10);
+ l_entryCharPtr = reinterpret_cast<char*>(l_entry);
+ if (nullptr != l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is not NULL", __FILE__, __func__);
+ }
+
+ if (true == l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is empty", __FILE__, __func__);
+ }
+
+ if (reinterpret_cast<uintptr_t>(l_buffer) !=
+ reinterpret_cast<uintptr_t>(l_rsvd.iv_ptrToHead))
+ {
+ TS_FAIL("%s:%s: Pointer to list is not correct", __FILE__, __func__);
+ }
+
+ if (true != runSelfDiagnostics(l_rsvd))
+ {
+ TS_FAIL("%s:%s: self diagnostics discovered an error",
+ __FILE__, __func__);
+ }
+
+ free(l_buffer);
+
+ TRACFCOMP(g_trac_test, EXIT_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+} // end void testRsvdTraceBuffOnlyAccommodateOneItem()
+
+// Test where buffer is just the right size to fit a single Entry plus size
+void testRsvdTraceBuffOnlyAccommodateOneItemPlusSize()
+{
+ TRACFCOMP(g_trac_test, ENTER_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+
+ TRACE::RsvdTraceBuffer l_rsvd;
+ uint32_t l_bufferSize = ALIGN_8(sizeof(TRACE::Entry) + 20);
+ uint32_t l_entrySize = l_bufferSize - sizeof(TRACE::Entry);
+
+ char *l_fullBuffer = initializeRsvdBuffer(l_bufferSize,
+ l_rsvd);
+
+ // Adjust buffer to the area we are interested in
+ char* l_buffer = l_fullBuffer + sizeof(uintptr_t);
+
+ if (l_rsvd.getBufferSize() != l_bufferSize)
+ {
+ TS_FAIL("%s:%s: buffer size is not correct", __FILE__, __func__);
+ }
+
+ // Add first entry - will be at beginning of buffer
+ TRACE::Entry* l_entry = l_rsvd.insertEntry(l_entrySize);
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ l_entry->size = l_entrySize;
+ char* l_entryCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getAddressOfPtr(l_entry));
+ char* l_entryEndCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getEndingAddressOfEntry(l_entry));
+ if (true == l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is empty", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ if (reinterpret_cast<TRACE::Entry*>(*l_rsvd.iv_ptrToHead) != l_entry)
+ {
+ TS_FAIL("%s:%s: head pointer is not pointing first Entry",
+ __FILE__, __func__);
+ }
+
+ if (l_entryCharPtr != l_buffer)
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryCharPtr != l_rsvd.iv_bufferBeginningBoundary)
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != (l_buffer + l_bufferSize - 1))
+ {
+ TS_FAIL("%s:%s: entry ending position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != l_rsvd.iv_bufferEndingBoundary)
+ {
+ TS_FAIL("%s:%s: entry ending position is not correct",
+ __FILE__, __func__);
+ }
+
+
+ if (true != runSelfDiagnostics(l_rsvd))
+ {
+ TS_FAIL("%s:%s: self diagnostics discovered an error",
+ __FILE__, __func__);
+ }
+
+ // Add another entry - will be at beginning of buffer
+ l_entry = l_rsvd.insertEntry(l_entrySize);
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ l_entry->size = l_entrySize;
+ l_entryCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getAddressOfPtr(l_entry));
+ l_entryEndCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getEndingAddressOfEntry(l_entry));
+ if (true == l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is empty", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ if (reinterpret_cast<TRACE::Entry*>(*l_rsvd.iv_ptrToHead) != l_entry)
+ {
+ TS_FAIL("%s:%s: head pointer is not pointing first Entry",
+ __FILE__, __func__);
+ }
+
+ if (l_entryCharPtr != l_buffer)
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryCharPtr != l_rsvd.iv_bufferBeginningBoundary)
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != (l_buffer + l_bufferSize - 1))
+ {
+ TS_FAIL("%s:%s: entry ending position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != l_rsvd.iv_bufferEndingBoundary)
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ // Add a third item - with 0 size
+ l_entry = l_rsvd.insertEntry(0);
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ l_entry->size = 0;
+ l_entryCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getAddressOfPtr(l_entry));
+ l_entryEndCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getEndingAddressOfEntry(l_entry));
+ if (true == l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is empty", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ if (reinterpret_cast<TRACE::Entry*>(*l_rsvd.iv_ptrToHead) != l_entry)
+ {
+ TS_FAIL("%s:%s: head pointer is not pointing first Entry",
+ __FILE__, __func__);
+ }
+
+ if (l_entryCharPtr != l_buffer)
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryCharPtr != l_rsvd.iv_bufferBeginningBoundary)
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != (l_buffer + ALIGN_8(sizeof(TRACE::Entry)) - 1))
+ {
+ TS_FAIL("%s:%s: entry ending position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (true != runSelfDiagnostics(l_rsvd))
+ {
+ TS_FAIL("%s:%s: self diagnostics discovered an error",
+ __FILE__, __func__);
+ }
+
+ l_rsvd.clearBuffer();
+ if (true != l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is NOT empty", __FILE__, __func__);
+ }
+
+ if (l_rsvd.iv_ptrToHead == nullptr)
+ {
+ TS_FAIL("%s:%s: pointer to head is NULL", __FILE__, __func__);
+ }
+
+ if (*l_rsvd.iv_ptrToHead != NULL)
+ {
+ TS_FAIL("%s:%s: pointer to head is pointing an item",__FILE__,__func__);
+ }
+
+ if (false == l_rsvd.isBufferValid())
+ {
+ TS_FAIL("%s:%s: buffer is not valid", __FILE__, __func__);
+ }
+
+ // Add a "first" item - with 0 size
+ l_entry = l_rsvd.insertEntry(0);
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ l_entry->size = 0;
+ l_entryCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getAddressOfPtr(l_entry));
+ l_entryEndCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getEndingAddressOfEntry(l_entry));
+ if (true == l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is empty", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ if (reinterpret_cast<TRACE::Entry*>(*l_rsvd.iv_ptrToHead) != l_entry)
+ {
+ TS_FAIL("%s:%s: head pointer is not pointing first Entry",
+ __FILE__, __func__);
+ }
+
+ if (l_entryCharPtr != l_buffer)
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryCharPtr != l_rsvd.iv_bufferBeginningBoundary)
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != (l_buffer + ALIGN_8(sizeof(TRACE::Entry)) - 1))
+ {
+ TS_FAIL("%s:%s: entry ending position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (true != runSelfDiagnostics(l_rsvd))
+ {
+ TS_FAIL("%s:%s: self diagnostics discovered an error",
+ __FILE__, __func__);
+ }
+
+ l_rsvd.clearBuffer();
+ if (true != l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is NOT empty", __FILE__, __func__);
+ }
+
+ if (l_rsvd.iv_ptrToHead == nullptr)
+ {
+ TS_FAIL("%s:%s: pointer to head is NULL", __FILE__, __func__);
+ }
+
+ if (*l_rsvd.iv_ptrToHead != NULL)
+ {
+ TS_FAIL("%s:%s: pointer to head is pointing an item",__FILE__,__func__);
+ }
+
+ if (false == l_rsvd.isBufferValid())
+ {
+ TS_FAIL("%s:%s: buffer is not valid", __FILE__, __func__);
+ }
+
+ // Add another entry - will be at beginning of buffer
+ l_entry = l_rsvd.insertEntry(l_entrySize);
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ l_entry->size = l_entrySize;
+ l_entryCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getAddressOfPtr(l_entry));
+ l_entryEndCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getEndingAddressOfEntry(l_entry));
+ if (true == l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is empty", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ if (reinterpret_cast<TRACE::Entry*>(*l_rsvd.iv_ptrToHead) != l_entry)
+ {
+ TS_FAIL("%s:%s: head pointer is not pointing first Entry",
+ __FILE__, __func__);
+ }
+
+ if (l_entryCharPtr != l_buffer)
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryCharPtr != l_rsvd.iv_bufferBeginningBoundary)
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != (l_buffer + l_bufferSize - 1))
+ {
+ TS_FAIL("%s:%s: entry ending position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != l_rsvd.iv_bufferEndingBoundary)
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ free(l_fullBuffer);
+
+ TRACFCOMP(g_trac_test, EXIT_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+} // end void testRsvdTraceBuffOnlyAccommodateOneItemPlusSize()
+
+// Test where buffer is just the right size to fit two Entries
+void testRsvdTraceBuffOnlyAccommodateTwoItems()
+{
+ TRACFCOMP(g_trac_test, ENTER_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+
+ TRACE::RsvdTraceBuffer l_rsvd;
+ uint32_t l_bufferSize = 2 * ALIGN_8(sizeof(TRACE::Entry));
+ uint32_t l_entrySize = (l_bufferSize/2) - sizeof(TRACE::Entry);
+
+ char *l_fullBuffer = initializeRsvdBuffer(l_bufferSize,
+ l_rsvd);
+
+ // Adjust buffer to the area we are interested in
+ char* l_buffer = l_fullBuffer + sizeof(uintptr_t);
+
+ if (l_rsvd.getBufferSize() != l_bufferSize)
+ {
+ TS_FAIL("%s:%s: buffer size is not correct",
+ __FILE__, __func__);
+ }
+
+ // Add first entry - will be at beginning of buffer
+ TRACE::Entry* l_entry = l_rsvd.insertEntry(l_entrySize);
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ l_entry->size = l_entrySize;
+ char* l_entryCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getAddressOfPtr(l_entry));
+ char* l_entryEndCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getEndingAddressOfEntry(l_entry));
+ if (true == l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is empty", __FILE__, __func__);
+ }
+
+ if (reinterpret_cast<TRACE::Entry*>(*l_rsvd.iv_ptrToHead) != l_entry)
+ {
+ TS_FAIL("%s:%s: head pointer is not pointing first Entry",
+ __FILE__, __func__);
+ }
+
+ if (l_entryCharPtr != l_buffer)
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != (l_buffer + (l_bufferSize/2) - 1))
+ {
+ TS_FAIL("%s:%s: entry ending position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (true != runSelfDiagnostics(l_rsvd))
+ {
+ TS_FAIL("%s:%s: self diagnostics discovered an error",
+ __FILE__, __func__);
+ }
+
+ // Add second item, should take up the rest of the space
+ l_entry = l_rsvd.insertEntry(l_entrySize);
+ TRACE::Entry *l_soonToBeHead = l_entry;
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ l_entry->size = l_entrySize;
+ l_entryCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getAddressOfPtr(l_entry));
+ l_entryEndCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getEndingAddressOfEntry(l_entry));
+ if (true == l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is empty", __FILE__, __func__);
+ }
+
+ if (l_entryCharPtr != (l_buffer + (l_bufferSize/2)))
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryCharPtr != (l_rsvd.iv_bufferBeginningBoundary + l_bufferSize/2))
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != (l_buffer + l_bufferSize -1))
+ {
+ TS_FAIL("%s:%s: entry ending position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != l_rsvd.iv_bufferEndingBoundary)
+ {
+ TS_FAIL("%s:%s: entry ending position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (true != runSelfDiagnostics(l_rsvd))
+ {
+ TS_FAIL("%s:%s: self diagnostics discovered an error",
+ __FILE__, __func__);
+ }
+
+ // Add third item, should go to the front of the buffer
+ l_entry = l_rsvd.insertEntry(l_entrySize);
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ l_entry->size = l_entrySize;
+ l_entryCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getAddressOfPtr(l_entry));
+ l_entryEndCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getEndingAddressOfEntry(l_entry));
+ if (true == l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is empty", __FILE__, __func__);
+ }
+
+ if (reinterpret_cast<TRACE::Entry*>(*l_rsvd.iv_ptrToHead) != l_soonToBeHead)
+ {
+ TS_FAIL("%s:%s: head pointer is not pointing first Entry",
+ __FILE__, __func__);
+ }
+ l_soonToBeHead = l_entry;
+
+ if (l_entryCharPtr != l_buffer)
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != (l_buffer + (l_bufferSize/2) - 1))
+ {
+ TS_FAIL("%s:%s: entry ending position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (true != runSelfDiagnostics(l_rsvd))
+ {
+ TS_FAIL("%s:%s: self diagnostics discovered an error",
+ __FILE__, __func__);
+ }
+
+ // Add fourth item, should take up the rest of the space
+ l_entry = l_rsvd.insertEntry(l_entrySize);
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ l_entry->size = l_entrySize;
+ l_entryCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getAddressOfPtr(l_entry));
+ l_entryEndCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getEndingAddressOfEntry(l_entry));
+ if (true == l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is empty", __FILE__, __func__);
+ }
+
+ if (reinterpret_cast<TRACE::Entry*>(*l_rsvd.iv_ptrToHead) != l_soonToBeHead)
+ {
+ TS_FAIL("%s:%s: head pointer is not pointing first Entry",
+ __FILE__, __func__);
+ }
+
+ if (l_entryCharPtr != (l_buffer + (l_bufferSize/2)))
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryCharPtr != (l_rsvd.iv_bufferBeginningBoundary + l_bufferSize/2))
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != (l_buffer + l_bufferSize -1))
+ {
+ TS_FAIL("%s:%s: entry ending position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != l_rsvd.iv_bufferEndingBoundary)
+ {
+ TS_FAIL("%s:%s: entry ending position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (true != runSelfDiagnostics(l_rsvd))
+ {
+ TS_FAIL("%s:%s: self diagnostics discovered an error",
+ __FILE__, __func__);
+ }
+
+ free(l_fullBuffer);
+
+ TRACFCOMP(g_trac_test, EXIT_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+} // end void testRsvdTraceBuffOnlyAccommodateTwoItems
+
+// Test when adding items at the ends of the buffer
+void testRsvdTraceBuffTestTheEnds()
+{
+ TRACFCOMP(g_trac_test, ENTER_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+
+ TRACE::RsvdTraceBuffer l_rsvd;
+ uint32_t l_bufferSize = ALIGN_8(sizeof(TRACE::Entry) + 20);
+ uint32_t l_entrySize = l_bufferSize - sizeof(TRACE::Entry);
+ l_bufferSize *= 3;
+
+ char *l_fullBuffer = initializeRsvdBuffer(l_bufferSize,
+ l_rsvd);
+
+ // Adjust buffer to the area we are interested in
+ char* l_buffer = l_fullBuffer + sizeof(uintptr_t);
+
+ if (l_rsvd.getBufferSize() != l_bufferSize)
+ {
+ TS_FAIL("%s:%s: buffer size is not correct",
+ __FILE__, __func__);
+ }
+
+ // A few needed vars
+ TRACE::Entry* l_entry(nullptr);
+ char* l_entryCharPtr(nullptr);
+ char* l_entryEndCharPtr(nullptr);
+ bool l_itemRemoved(false);
+
+
+ // Add first entry - will be at beginning of buffer
+ l_entry = l_rsvd.insertEntry(l_entrySize);
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+ l_entry->size = l_entrySize;
+
+ if (true == l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is empty", __FILE__, __func__);
+ }
+
+ // Add second entry - will be at beginning of buffer
+ l_entry = l_rsvd.insertEntry(l_entrySize);
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+ l_entry->size = l_entrySize;
+
+ if (true == l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is empty", __FILE__, __func__);
+ }
+
+ l_itemRemoved = l_rsvd.removeOldestEntry();
+ if (true != l_itemRemoved)
+ {
+ TS_FAIL("%s:%s: unable to remove oldest item", __FILE__, __func__);
+ }
+
+ if (true == l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is empty", __FILE__, __func__);
+ }
+
+
+ l_entry = l_rsvd.getListHead();
+ l_entryCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getAddressOfPtr(l_entry));
+ l_entryEndCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getEndingAddressOfEntry(l_entry));
+ if (reinterpret_cast<TRACE::Entry*>(*l_rsvd.iv_ptrToHead) != l_entry)
+ {
+ TS_FAIL("%s:%s: head pointer is not pointing first Entry",
+ __FILE__, __func__);
+ }
+
+ if (l_entryCharPtr != (l_buffer + l_entrySize + sizeof(TRACE::Entry)))
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != (l_buffer + (2 *
+ (l_entrySize + sizeof(TRACE::Entry))) - 1))
+ {
+ TS_FAIL("%s:%s: entry ending position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (true != runSelfDiagnostics(l_rsvd))
+ {
+ TS_FAIL("%s:%s: self diagnostics discovered an error",
+ __FILE__, __func__);
+ }
+
+ // Add third item, should go to the end of buffer
+ l_entry = l_rsvd.insertEntry(l_entrySize);
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ l_entry->size = l_entrySize;
+ l_entryCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getAddressOfPtr(l_entry));
+ l_entryEndCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getEndingAddressOfEntry(l_entry));
+ if (true == l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is empty", __FILE__, __func__);
+ }
+
+ if (l_entryCharPtr != (l_buffer + (2 *
+ (l_entrySize + sizeof(TRACE::Entry)))))
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != l_rsvd.iv_bufferEndingBoundary)
+ {
+ TS_FAIL("%s:%s: entry ending position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (true != runSelfDiagnostics(l_rsvd))
+ {
+ TS_FAIL("%s:%s: self diagnostics discovered an error",
+ __FILE__, __func__);
+ }
+
+ // Add fourth item, should go to the beginning of buffer
+ l_entry = l_rsvd.insertEntry(l_entrySize);
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ l_entry->size = l_entrySize;
+ l_entryCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getAddressOfPtr(l_entry));
+ l_entryEndCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getEndingAddressOfEntry(l_entry));
+ if (true == l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is empty", __FILE__, __func__);
+ }
+
+ if (l_entryCharPtr != l_rsvd.iv_bufferBeginningBoundary)
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != (l_buffer + l_entrySize + sizeof(TRACE::Entry) -1))
+ {
+ TS_FAIL("%s:%s: entry ending position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (true != runSelfDiagnostics(l_rsvd))
+ {
+ TS_FAIL("%s:%s: self diagnostics discovered an error",
+ __FILE__, __func__);
+ }
+
+ free(l_fullBuffer);
+
+ TRACFCOMP(g_trac_test, EXIT_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+} // end void testRsvdTraceBuffTestTheEnds
+
+// Test reentrant of buffer
+// Create a buffer and an item
+void testRsvdTraceBuffTestReentrant ()
+{
+ TRACFCOMP(g_trac_test, ENTER_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+
+ TRACE::RsvdTraceBuffer l_rsvd;
+ iv_bufferSize = ALIGN_8(sizeof(TRACE::Entry) + 20);
+ iv_entrySize = iv_bufferSize - sizeof(TRACE::Entry);
+ iv_bufferSize *= 3;
+
+ iv_buffer = initializeRsvdBuffer(iv_bufferSize,
+ l_rsvd);
+
+ iv_bufferBeginningBoundary = l_rsvd.iv_bufferBeginningBoundary;
+ iv_bufferEndingBoundary = l_rsvd.iv_bufferEndingBoundary;
+
+ // Adjust buffer to the area we are interested in
+ char* l_buffer = iv_buffer + sizeof(uintptr_t);
+
+ if (l_rsvd.getBufferSize() != iv_bufferSize)
+ {
+ TS_FAIL("%s:%s: buffer size is not correct",
+ __FILE__, __func__);
+ }
+
+ if (true != l_rsvd.isBufferValid())
+ {
+ TS_FAIL("%s:%s: buffer is not valid", __FILE__, __func__);
+ }
+
+ // A few needed vars
+ TRACE::Entry* l_entry(nullptr);
+ char* l_entryCharPtr(nullptr);
+ char* l_entryEndCharPtr(nullptr);
+
+ // Add first entry - will be at beginning of buffer
+ l_entry = l_rsvd.insertEntry(iv_entrySize);
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+ l_entry->size = iv_entrySize;
+ l_entryCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getAddressOfPtr(l_entry));
+ l_entryEndCharPtr =
+ l_rsvd.convertToCharPointer(l_rsvd.getEndingAddressOfEntry(l_entry));
+ memset(l_entry->data, 'A', l_entry->size);
+
+ if (true == l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is empty", __FILE__, __func__);
+ }
+
+ if (reinterpret_cast<TRACE::Entry*>(*l_rsvd.iv_ptrToHead) != l_entry)
+ {
+ TS_FAIL("%s:%s: head pointer is not pointing to first Entry",
+ __FILE__, __func__);
+ }
+
+ if (l_entryCharPtr != l_buffer)
+ {
+ TS_FAIL("%s:%s: entry starting position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_entryEndCharPtr != (l_buffer + iv_entrySize +
+ sizeof(TRACE::Entry) - 1))
+ {
+ TS_FAIL("%s:%s: entry ending position is not correct",
+ __FILE__, __func__);
+ }
+
+ if (true != runSelfDiagnostics(l_rsvd))
+ {
+ TS_FAIL("%s:%s: self diagnostics discovered an error",
+ __FILE__, __func__);
+ }
+
+ TRACFCOMP(g_trac_test, EXIT_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+} // end void testRsvdTraceBuffTestReentrant
+
+// Test reentrant of buffer
+// See if we can get a a hold of the buffer and check item previously added
+// add another item
+void testRsvdTraceBuffTestReentrant2()
+{
+ TRACFCOMP(g_trac_test, ENTER_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+
+ TRACE::RsvdTraceBuffer l_rsvd;
+ initializeRsvdBufferForReentrant(l_rsvd);
+
+ if (l_rsvd.getBufferSize() != iv_bufferSize)
+ {
+ TS_FAIL("%s:%s: buffer size is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_rsvd.iv_bufferEndingBoundary != iv_bufferEndingBoundary)
+ {
+ TS_FAIL("%s:%s: buffer not properly initialized",
+ __FILE__, __func__);
+ }
+
+ if (l_rsvd.iv_bufferBeginningBoundary != iv_bufferBeginningBoundary)
+ {
+ TS_FAIL("%s:%s: buffer not properly initialized",
+ __FILE__, __func__);
+ }
+
+ if (true == l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is empty", __FILE__, __func__);
+ }
+
+ if (true != l_rsvd.isBufferValid())
+ {
+ TS_FAIL("%s:%s: buffer is not valid", __FILE__, __func__);
+ }
+
+ if (true != runSelfDiagnostics(l_rsvd))
+ {
+ TS_FAIL("%s:%s: self diagnostics discovered an error",
+ __FILE__, __func__);
+ }
+
+ // A few needed vars
+ TRACE::Entry* l_entry(nullptr);
+
+ // Get first entry - will be at beginning of buffer
+ l_entry = l_rsvd.getListHead();
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ if ('A' != l_entry->data[0])
+ {
+ TS_FAIL("%s:%s: Entry data is corrupt",
+ __FILE__, __func__);
+ }
+
+ if ('A' != l_entry->data[l_entry->size - 1])
+ {
+ TS_FAIL("%s:%s: Entry data is corrupt",
+ __FILE__, __func__);
+ }
+
+ // Add second entry - will be at beginning of buffer
+ l_entry = l_rsvd.insertEntry(iv_entrySize);
+ l_entry->size = iv_entrySize;
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+ memset(l_entry->data, 'B', l_entry->size);
+ if ('B' != l_entry->data[0])
+ {
+ TS_FAIL("%s:%s: Entry data is corrupt",
+ __FILE__, __func__);
+ }
+
+ if ('B' != l_entry->data[iv_entrySize - 1])
+ {
+ TS_FAIL("%s:%s: Entry data is corrupt",
+ __FILE__, __func__);
+ }
+
+ TRACFCOMP(g_trac_test, EXIT_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+} // end void testRsvdTraceBuffTestReentrant2
+
+// Test reentrant of buffer
+// See if we can get a a hold of the buffer and verify items added;
+// remove all items
+void testRsvdTraceBuffTestReentrant3()
+{
+ TRACFCOMP(g_trac_test, ENTER_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+
+ TRACE::RsvdTraceBuffer l_rsvd;
+ initializeRsvdBufferForReentrant(l_rsvd);
+
+ if (l_rsvd.getBufferSize() != iv_bufferSize)
+ {
+ TS_FAIL("%s:%s: buffer size is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_rsvd.iv_bufferEndingBoundary != iv_bufferEndingBoundary)
+ {
+ TS_FAIL("%s:%s: buffer not properly initialized",
+ __FILE__, __func__);
+ }
+
+ if (l_rsvd.iv_bufferBeginningBoundary != iv_bufferBeginningBoundary)
+ {
+ TS_FAIL("%s:%s: buffer not properly initialized",
+ __FILE__, __func__);
+ }
+
+ if (true != l_rsvd.isBufferValid())
+ {
+ TS_FAIL("%s:%s: buffer is not valid", __FILE__, __func__);
+ }
+
+ // A few needed vars
+ TRACE::Entry* l_entry(nullptr);
+
+ // Get first entry
+ l_entry = l_rsvd.getListHead();
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ if ('A' != l_entry->data[0])
+ {
+ TS_FAIL("%s:%s: Entry data is corrupt",
+ __FILE__, __func__);
+ }
+
+ if ('A' != l_entry->data[l_entry->size - 1])
+ {
+ TS_FAIL("%s:%s: Entry data is corrupt",
+ __FILE__, __func__);
+ }
+
+ // Remove first
+ l_rsvd.removeOldestEntry();
+
+ // Get first entry
+ l_entry = l_rsvd.getListHead();
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ if ('B' != l_entry->data[0])
+ {
+ TS_FAIL("%s:%s: Entry data is corrupt",
+ __FILE__, __func__);
+ }
+
+ if ('B' != l_entry->data[l_entry->size - 1])
+ {
+ TS_FAIL("%s:%s: Entry data is corrupt",
+ __FILE__, __func__);
+ }
+
+ l_rsvd.clearBuffer();
+ l_entry = l_rsvd.getListHead();
+ if (nullptr != l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is NOT null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ if (true != l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is NOT empty", __FILE__, __func__);
+ }
+
+ TRACFCOMP(g_trac_test, EXIT_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+} // end void testRsvdTraceBuffTestReentrant3
+
+// Test reentrant of buffer
+// See if we can get a a hold of the buffer and add an item
+void testRsvdTraceBuffTestReentrant4()
+{
+ TRACFCOMP(g_trac_test, ENTER_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+
+ TRACE::RsvdTraceBuffer l_rsvd;
+ initializeRsvdBufferForReentrant(l_rsvd);
+
+ if (l_rsvd.getBufferSize() != iv_bufferSize)
+ {
+ TS_FAIL("%s:%s: buffer size is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_rsvd.iv_bufferEndingBoundary != iv_bufferEndingBoundary)
+ {
+ TS_FAIL("%s:%s: buffer not properly initialized",
+ __FILE__, __func__);
+ }
+
+ if (l_rsvd.iv_bufferBeginningBoundary != iv_bufferBeginningBoundary)
+ {
+ TS_FAIL("%s:%s: buffer not properly initialized",
+ __FILE__, __func__);
+ }
+
+ if (true != l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is NOT empty", __FILE__, __func__);
+ }
+
+ if (true != l_rsvd.isBufferValid())
+ {
+ TS_FAIL("%s:%s: buffer is not valid", __FILE__, __func__);
+ }
+
+ TRACE::Entry* l_entry(nullptr);
+ l_entry = l_rsvd.getListHead();
+ if (nullptr != l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is NOT null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ // Add an entry
+ l_entry = l_rsvd.insertEntry(iv_entrySize);
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+ l_entry->size = iv_entrySize;
+ memset(l_entry->data, 'C', l_entry->size);
+ if ('C' != l_entry->data[0])
+ {
+ TS_FAIL("%s:%s: Entry data is corrupt",
+ __FILE__, __func__);
+ }
+
+ if ('C' != l_entry->data[l_entry->size - 1])
+ {
+ TS_FAIL("%s:%s: Entry data is corrupt",
+ __FILE__, __func__);
+ }
+
+ TRACFCOMP(g_trac_test, EXIT_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+} // end void testRsvdTraceBuffTestReentrant4
+
+
+// Test reentrant of buffer
+// Finally see if we can get item
+void testRsvdTraceBuffTestReentrant5()
+{
+ TRACFCOMP(g_trac_test, ENTER_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+
+ TRACE::RsvdTraceBuffer l_rsvd;
+ initializeRsvdBufferForReentrant(l_rsvd);
+
+ if (l_rsvd.getBufferSize() != iv_bufferSize)
+ {
+ TS_FAIL("%s:%s: buffer size is not correct",
+ __FILE__, __func__);
+ }
+
+ if (l_rsvd.iv_bufferEndingBoundary != iv_bufferEndingBoundary)
+ {
+ TS_FAIL("%s:%s: buffer not properly initialized",
+ __FILE__, __func__);
+ }
+
+ if (l_rsvd.iv_bufferBeginningBoundary != iv_bufferBeginningBoundary)
+ {
+ TS_FAIL("%s:%s: buffer not properly initialized",
+ __FILE__, __func__);
+ }
+
+ if (true == l_rsvd.isListEmpty())
+ {
+ TS_FAIL("%s:%s: list is empty", __FILE__, __func__);
+ }
+
+ if (true != l_rsvd.isBufferValid())
+ {
+ TS_FAIL("%s:%s: buffer is not valid", __FILE__, __func__);
+ }
+
+ TRACE::Entry* l_entry(nullptr);
+ l_entry = l_rsvd.getListHead();
+ if (nullptr == l_entry)
+ {
+ TS_FAIL("%s:%s: Entry ptr is null", __FILE__, __func__);
+ return; // Need to quit or die
+ }
+
+ if ('C' != l_entry->data[0])
+ {
+ TS_FAIL("%s:%s: Entry data is corrupt",
+ __FILE__, __func__);
+ }
+
+ if ('C' != l_entry->data[l_entry->size - 1])
+ {
+ TS_FAIL("%s:%s: Entry data is corrupt",
+ __FILE__, __func__);
+ }
+
+ TRACFCOMP(g_trac_test, EXIT_MRK"RsvdTraceBuffTestSuite:%s", __func__);
+} // end void testRsvdTraceBuffTestReentrant5
+
+private:
+// Helpful methods to help in testing
+char* initializeRsvdBuffer(uint32_t i_bufferSize,
+ TRACE::RsvdTraceBuffer& i_rsvd)
+{
+ // Create a buffer
+ uint32_t l_realBufferSize = i_bufferSize + sizeof(uintptr_t);
+ char *l_buffer = reinterpret_cast<char*>(malloc(l_realBufferSize));
+ memset(l_buffer, 0, l_realBufferSize);
+
+ // Get the address of buffer; just like we would get in "real life"
+ uintptr_t l_bufferAddr = reinterpret_cast<uintptr_t>(l_buffer);
+
+ // Get a pointer to where the HEAD needs to reside in the buffer
+ uintptr_t *l_addressToHead = reinterpret_cast<uintptr_t *>(l_bufferAddr);
+
+ // Initialize the buffer
+ i_rsvd.init(i_bufferSize,
+ l_bufferAddr + sizeof(uintptr_t),
+ l_addressToHead);
+
+ return l_buffer;
+}
+
+void initializeRsvdBufferForReentrant(TRACE::RsvdTraceBuffer& i_rsvd)
+{
+ // Get the address of buffer; just like we would get in "real life"
+ uintptr_t l_bufferAddr = reinterpret_cast<uintptr_t>(iv_buffer);
+
+ // Get a pointer to where the HEAD is
+ uintptr_t *l_addressToHead = reinterpret_cast<uintptr_t *>(iv_buffer);
+
+ // Initialize the buffer
+ i_rsvd.init(iv_bufferSize,
+ l_bufferAddr + sizeof(uintptr_t),
+ l_addressToHead);
+}
+
+
+bool runSelfDiagnostics(TRACE::RsvdTraceBuffer& l_rsvd)
+{
+ bool l_everythingChecksOut = true;
+ uintptr_t l_bufferBeginningBoundary = l_rsvd.getAddressOfPtr
+ (l_rsvd.iv_bufferBeginningBoundary);
+ uintptr_t l_bufferEndingBoundary = l_rsvd.getAddressOfPtr
+ (l_rsvd.iv_bufferEndingBoundary);
+
+ if (!l_rsvd.isListEmpty())
+ {
+ uint32_t l_itemCount(0);
+
+ TRACE::Entry* l_entry = l_rsvd.getListHead();
+ TRACE::Entry* l_head = l_entry;
+ do
+ {
+ ++l_itemCount;
+ uintptr_t l_entryAddr = l_rsvd.getAddressOfPtr(l_entry);
+ uintptr_t l_entryAddrEnd =
+ l_rsvd.getEndingAddressOfEntry(l_entry);
+
+ if (l_entryAddr < l_bufferBeginningBoundary)
+ {
+ TS_FAIL("Item [%d] at address (0x%X) precedes the "
+ "allocated memory location at address "
+ "(0x%X) by %d byte(s)",
+ l_itemCount, l_entryAddr, l_bufferBeginningBoundary,
+ (l_bufferBeginningBoundary - l_entryAddr));
+ l_everythingChecksOut = false;
+ }
+ else if (l_entryAddr > l_bufferEndingBoundary)
+ {
+ TS_FAIL("Item [%d] at address (0x%X) is beyond the "
+ "ending allocated memory location at address "
+ "(0x%X) by %d byte(s)",
+ l_itemCount, l_entryAddr, l_bufferEndingBoundary,
+ (l_entryAddr - l_bufferEndingBoundary));
+ l_everythingChecksOut = false;
+ }
+ else if (l_entryAddrEnd > l_bufferEndingBoundary)
+ {
+ TS_FAIL("Item [%d] at address (0x%X) overruns the "
+ "ending allocated memory location at address "
+ "(0x%X) by %d byte(s)",
+ l_itemCount, l_entryAddr, l_bufferEndingBoundary,
+ (l_entryAddrEnd - l_bufferEndingBoundary));
+ l_everythingChecksOut = false;
+ }
+ else
+ {
+ uintptr_t l_entryNextAddr = l_rsvd.
+ getAddressOfPtr(l_entry->next);
+ if ((l_entryNextAddr > l_entryAddr) &&
+ (l_entryAddrEnd >= l_entryNextAddr) )
+ {
+ TS_FAIL("Item [%d] at address (0x%X) overruns the "
+ "next item at address (0x%X) by %d byte(s)",
+ l_itemCount, l_entryAddr, l_entryNextAddr,
+ (l_entryAddrEnd - l_entryNextAddr + 1));
+ l_everythingChecksOut = false;
+ }
+ } // end if ... else
+
+ l_entry = l_entry->next;
+ }
+ while(l_entry != l_head);
+ } // end if (!l_rsvd.isListEmpty())
+
+ return l_everythingChecksOut;
+}
+
+ char* iv_buffer;
+ uint32_t iv_bufferSize;
+ uint32_t iv_entrySize;
+ char *iv_bufferBeginningBoundary; //< Pointer to beginning of buffer
+ char *iv_bufferEndingBoundary; //< Pointer to end of buffer
+ TRACE::ComponentDesc *iv_compDesc;
+};
OpenPOWER on IntegriCloud