summaryrefslogtreecommitdiffstats
path: root/src/usr/trace
diff options
context:
space:
mode:
authorPatrick Williams <iawillia@us.ibm.com>2012-10-31 16:01:11 -0500
committerA. Patrick Williams III <iawillia@us.ibm.com>2012-12-14 10:18:59 -0600
commitda3888270ff596441bf78535c26dee0a7d923145 (patch)
tree019b88ce38e87b8346e0ef659f058556e26dec42 /src/usr/trace
parent6d7290eca2b0e753d1b954a56e2c82284dd23eb9 (diff)
downloadtalos-hostboot-da3888270ff596441bf78535c26dee0a7d923145.tar.gz
talos-hostboot-da3888270ff596441bf78535c26dee0a7d923145.zip
Lockless trace implementation
RTC: 35396 Change-Id: I96ea0d95606f04abb4dc2b0470345ca475b53912 Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/2520 Tested-by: Jenkins Server Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com> Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/usr/trace')
-rw-r--r--src/usr/trace/buffer.C588
-rw-r--r--src/usr/trace/buffer.H197
-rw-r--r--src/usr/trace/bufferpage.C79
-rw-r--r--src/usr/trace/bufferpage.H73
-rw-r--r--src/usr/trace/compdesc.C98
-rw-r--r--src/usr/trace/compdesc.H146
-rw-r--r--src/usr/trace/daemon/complist.C51
-rw-r--r--src/usr/trace/daemon/daemon.C578
-rw-r--r--src/usr/trace/daemon/daemon.H121
-rw-r--r--src/usr/trace/daemon/makefile30
-rw-r--r--src/usr/trace/daemonif.C67
-rw-r--r--src/usr/trace/daemonif.H99
-rw-r--r--src/usr/trace/entry.H127
-rw-r--r--src/usr/trace/interface.C115
-rw-r--r--src/usr/trace/makefile33
-rw-r--r--src/usr/trace/service.C271
-rw-r--r--src/usr/trace/service.H161
-rw-r--r--src/usr/trace/test/testbuffer.H92
-rw-r--r--src/usr/trace/test/testcomplist.H61
-rw-r--r--src/usr/trace/test/tracetest.H306
-rw-r--r--src/usr/trace/trace.C1555
-rw-r--r--src/usr/trace/tracebuffer.C77
-rw-r--r--src/usr/trace/tracebuffer.H73
-rw-r--r--src/usr/trace/tracedaemon.C124
-rw-r--r--src/usr/trace/tracedaemon.H92
25 files changed, 2971 insertions, 2243 deletions
diff --git a/src/usr/trace/buffer.C b/src/usr/trace/buffer.C
new file mode 100644
index 000000000..921b5f2a4
--- /dev/null
+++ b/src/usr/trace/buffer.C
@@ -0,0 +1,588 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/buffer.C $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+#include "buffer.H"
+#include "bufferpage.H"
+#include "entry.H"
+#include "compdesc.H"
+#include "daemonif.H"
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+#include <util/align.H>
+
+namespace TRACE
+{
+ Buffer::Buffer(DaemonIf* i_daemon, size_t i_maxPages) :
+ iv_pagesAlloc(0), iv_pagesMax(i_maxPages),
+ iv_firstPage(NULL), iv_daemon(i_daemon)
+ {
+ iv_counters.totals = 0;
+ assert(i_maxPages > 0);
+ }
+
+ void Buffer::_producerEnter()
+ {
+ locklessCounter value;
+ do
+ {
+ // Read current count.
+ value = iv_counters;
+
+ // If there is a consumer (daemon) present, must wait.
+ while (value.consumerCount != 0)
+ {
+ futex_wait(&iv_counters.totals, value.totals);
+ value = iv_counters;
+ }
+
+ // No consumers currently present, increment the producer count
+ // (to include us).
+ locklessCounter newValue = value;
+ newValue.producerCount++;
+
+ // Attempt to atomically update the count.
+ if (__sync_bool_compare_and_swap(&iv_counters.totals,
+ value.totals,
+ newValue.totals)
+ )
+ {
+ // Successful at atomic update, we're included in the count
+ // so we can exit the loop.
+ break;
+ }
+
+ // Failed to update count, so try again.
+ } while(1);
+ }
+
+ void Buffer::_producerExit()
+ {
+ locklessCounter value;
+ do
+ {
+ // Read current count.
+ value = iv_counters;
+
+ // Decrement count to remove us.
+ locklessCounter newValue = value;
+ newValue.producerCount--;
+
+ // Attempt to atomically update count.
+ if (!__sync_bool_compare_and_swap(&iv_counters.totals,
+ value.totals,
+ newValue.totals))
+ {
+ // Failed, try again.
+ continue;
+ }
+
+ // If we're the last producer and there is a consumer waiting,
+ // signal the consumer.
+ if((newValue.producerCount == 0) && (newValue.consumerCount != 0))
+ {
+ futex_wake(&iv_counters.totals, UINT64_MAX);
+ }
+
+ // If we're here, we are successful, so exit the loop.
+ break;
+
+ } while(1);
+ }
+
+ void Buffer::_consumerEnter()
+ {
+ locklessCounter value;
+ do
+ {
+ // Read current count.
+ value = iv_counters;
+
+ // Set us up as a pending consumer.
+ locklessCounter newValue = value;
+ newValue.consumerCount = 1;
+
+ // Attempt to atomically update counts.
+ if (!__sync_bool_compare_and_swap(&iv_counters.totals,
+ value.totals,
+ newValue.totals))
+ {
+ // Failed, try again.
+ continue;
+ }
+
+ // If there were producers waiting, we need to wait for them
+ // to clear out.
+ if (0 != newValue.producerCount)
+ {
+ do
+ {
+ futex_wait(&iv_counters.totals, newValue.totals);
+ newValue = iv_counters;
+
+ } while(newValue.producerCount != 0);
+ }
+
+ // If we're here, we are successful, so exit the loop.
+ break;
+
+ } while(1);
+ }
+
+ void Buffer::_consumerExit()
+ {
+ locklessCounter value;
+ do
+ {
+ // Read current count.
+ value = iv_counters;
+
+ // Remove ourself as the consumer.
+ locklessCounter newValue = value;
+ newValue.consumerCount = 0;
+
+ // Atomically update the count.
+ if (!__sync_bool_compare_and_swap(&iv_counters.totals,
+ value.totals,
+ newValue.totals))
+ {
+ // Failed, try again.
+ continue;
+ }
+
+ // Successful. Signal any producers that might be waiting and
+ // exit the loop.
+ futex_wake(&iv_counters.totals, UINT64_MAX);
+ break;
+
+ } while(1);
+ }
+
+
+ Entry* Buffer::claimEntry(ComponentDesc* i_comp, size_t i_size)
+ {
+ // 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).
+ i_size = ALIGN_8(i_size + sizeof(Entry));
+
+ // If an entry is bigger than this amount, it can never be satisfied.
+ if (i_size > (PAGESIZE - sizeof(BufferPage)))
+ {
+ return NULL;
+ }
+
+ // During the process of claiming an entry, the daemon must be
+ // blocked out from tampering with the pages.
+ _producerEnter();
+
+ Entry* l_entry = NULL;
+
+ // No we begin the search for an entry.
+ do
+ {
+ BufferPage* first = iv_firstPage;
+
+ // Attempt to claim from the current page first.
+ if (first)
+ {
+ l_entry = first->claimEntry(i_size);
+ if (l_entry)
+ {
+ // Found one, great! We're done.
+ break;
+ }
+
+ // If there is a "next" page, another thread has already
+ // allocated a new page, so just wait for it to show up.
+ // (as in, some other thread is going to update iv_firstPage)
+ if (first->next)
+ {
+ continue;
+ }
+ }
+
+ // Wasn't enough space, so try to allocate a new page.
+ uint64_t pagesAllocated = iv_pagesAlloc;
+ if (pagesAllocated >= iv_pagesMax)
+ {
+ // Not enough pages. Wait until someone frees one.
+ _producerExit();
+ iv_daemon->signal();
+ futex_wait(reinterpret_cast<uint64_t*>(
+ const_cast<BufferPage**>(&iv_firstPage)),
+ reinterpret_cast<uint64_t>(first));
+ _producerEnter();
+ // A page might be allocated now, start over.
+ continue;
+ }
+
+ // Atomically update page count.
+ uint64_t newPagesAllocated = pagesAllocated + 1;
+ if (!__sync_bool_compare_and_swap(&iv_pagesAlloc,
+ pagesAllocated,
+ newPagesAllocated))
+ {
+ // Someone beat us to updating the count, so start over.
+ // (another thread is also trying to allocate a page, let them
+ // do it).
+ continue;
+ }
+
+ // Successfully updated the count so allocate the new page.
+ BufferPage* newPage = BufferPage::allocate();
+ newPage->prev = first;
+
+ // If there is a page already, update its next pointer to point
+ // back at this new page.
+ if (first)
+ {
+ if (!__sync_bool_compare_and_swap(&first->next,
+ NULL,
+ newPage))
+ {
+ // Someone beat us to allocating the page, release it.
+ BufferPage::deallocate(newPage);
+ do
+ {
+ pagesAllocated = iv_pagesAlloc;
+ newPagesAllocated = pagesAllocated - 1;
+ }
+ while (!__sync_bool_compare_and_swap(&iv_pagesAlloc,
+ pagesAllocated,
+ newPagesAllocated));
+ continue;
+ }
+ }
+
+ // Now we have a page allocated, claim our entry first and then
+ // hook it up to master list.
+ l_entry = newPage->claimEntry(i_size);
+
+ if (!__sync_bool_compare_and_swap(&iv_firstPage,
+ first,
+ newPage))
+ {
+ // We got beat adding page to the master list, so release it
+ // and use that page.
+ BufferPage::deallocate(newPage);
+ do
+ {
+ pagesAllocated = iv_pagesAlloc;
+ newPagesAllocated = pagesAllocated - 1;
+ }
+ while (!__sync_bool_compare_and_swap(&iv_pagesAlloc,
+ pagesAllocated,
+ newPagesAllocated));
+
+ // The entry we claimed out of the "new" page is no longer
+ // valid since we've freed it.
+ l_entry = NULL;
+ continue;
+ }
+
+ // Since we allocated a page, signal any other tasks that might be
+ // blocked waiting for a page to show up.
+ futex_wake(reinterpret_cast<uint64_t*>(
+ const_cast<BufferPage**>(&iv_firstPage)),
+ UINT64_MAX);
+
+ // And since we allocated a page, wake up the daemon if we
+ // allocated the last page or if there are more than 4 pages
+ // and we are an infinite buffer. (4 pages is arbitrary).
+ static const size_t SIGNAL_AFTER_N_PAGES_ALLOCATED = 4;
+ if ((pagesAllocated == iv_pagesMax) ||
+ ((pagesAllocated >= SIGNAL_AFTER_N_PAGES_ALLOCATED) &&
+ (iv_pagesMax == UNLIMITED)))
+ {
+ iv_daemon->signal();
+ }
+
+
+ } while(!l_entry);
+
+ // Update component name and entry size.
+ l_entry->comp = i_comp;
+ l_entry->size = i_size - sizeof(Entry);
+
+ // Leave critical section.
+ _producerExit();
+
+ return l_entry;
+ }
+
+ BufferPage* Buffer::claimPages()
+ {
+ // Enter critical daemon section.
+ _consumerEnter();
+
+ // Take page(s) from buffer.
+ BufferPage* page = iv_firstPage;
+ iv_firstPage = NULL;
+ iv_pagesAlloc = 0;
+
+ // Rewind to beginning of buffer.
+ if (page)
+ {
+ while(page->prev) { page = page->prev; }
+ }
+
+ // Signal producers that might be waiting for pages to free up.
+ futex_wake(reinterpret_cast<uint64_t*>(
+ const_cast<BufferPage**>(&iv_firstPage)),
+ UINT64_MAX);
+
+ // Exit critical daemon section.
+ _consumerExit();
+
+ return page;
+ }
+
+ void Buffer::commitEntry(Entry* i_entry)
+ {
+ // Prevent daemon from making updates while we're in here.
+ _producerEnter();
+
+ // Read the component from the entry itself (added as part of claiming).
+ ComponentDesc* l_comp = i_entry->comp;
+
+ // Lockless loop to update component linked-list.
+ do
+ {
+ // Update our entry's "next" pointer.
+ i_entry->next = l_comp->iv_first;
+
+ // If there is an entry, update its "prev" pointer to this entry.
+ if (i_entry->next)
+ {
+ if (!__sync_bool_compare_and_swap(&i_entry->next->prev,
+ NULL,
+ i_entry))
+ {
+ // Failed lockless update, try again.
+ continue;
+ }
+ }
+ // Otherwise, we need to update the component list since this is
+ // the first entry.
+ else
+ {
+ if (!__sync_bool_compare_and_swap(&l_comp->iv_last,
+ NULL,
+ i_entry))
+ {
+ // Failed lockless update, try again.
+ continue;
+ }
+ }
+
+ // Successful at our updates, break out.
+ break;
+
+ } while(1);
+
+ // We just added the newest entry, so update component list.
+ //
+ // It is possible that the committer of the preceeding entry was
+ // "slow", so we need to keep trying to update until the current
+ // compoment "first" points at the preceeding entry and then make
+ // it point at this entry.
+ //
+ while (!__sync_bool_compare_and_swap(&l_comp->iv_first,
+ i_entry->next,
+ i_entry));
+
+
+ // Atomically increment component size.
+ __sync_add_and_fetch(&l_comp->iv_curSize, i_entry->size);
+
+ // Mark entry as committed.
+ i_entry->committed = 1;
+
+ // All done, release for daemon.
+ _producerExit();
+
+ }
+
+ size_t Buffer::getTrace(ComponentDesc* i_comp, void* o_data, size_t i_size)
+ {
+ char* l_data = reinterpret_cast<char*>(o_data);
+ size_t l_size = 0;
+ size_t l_entries = 0;
+
+ // If either the pointer is null or the buffer is 0, we're just trying
+ // to determine the size of the buffer.
+ bool determineSize = ((o_data == NULL) || (i_size == 0));
+
+ if (determineSize)
+ {
+ i_size = UINT64_MAX;
+ }
+
+ trace_buf_head_t* header = NULL;
+
+ // If we're actually extracting, add the fsp-trace buffer header.
+ if(!determineSize)
+ {
+ if (i_size < sizeof(trace_buf_head_t))
+ return 0;
+
+ header = reinterpret_cast<trace_buf_head_t*>(&l_data[l_size]);
+ memset(header, '\0', sizeof(trace_buf_head_t));
+
+ header->ver = TRACE_BUF_VERSION;
+ header->hdr_len = sizeof(trace_buf_head_t);
+ header->time_flg = TRACE_TIME_REAL;
+ header->endian_flg = 'B'; // Big Endian.
+ memcpy(&header->comp[0], &i_comp->iv_compName, TRAC_COMP_SIZE);
+ }
+ l_size += sizeof(trace_buf_head_t);
+
+ // Prevent daemon from changing things while we're extracting.
+ _producerEnter();
+
+ size_t l_totalSize = l_size;
+ Entry* entry = i_comp->iv_first;
+ Entry* orig_entry = entry;
+
+ do
+ {
+ if ((!entry) || (!entry->comp))
+ {
+ break;
+ }
+
+ // First walk the list backwards to find everything that will fit.
+ while(1)
+ {
+ // fsp-trace buffer entries have an extra word of size at the
+ // end. That is where the sizeof(uint32_t) comes from...
+
+ if ((l_totalSize + entry->size + sizeof(uint32_t)) <= i_size)
+ {
+ l_totalSize += entry->size + sizeof(uint32_t);
+
+ if ((entry->next) &&
+ (entry->next->comp))
+ {
+ entry = entry->next;
+ continue;
+ }
+ }
+ break;
+ }
+
+ // If we didn't find anything that fit, leave.
+ if (l_totalSize == l_size)
+ {
+ break;
+ }
+
+ // If we're just trying to find the size, we're done.
+ if(determineSize)
+ {
+ l_size = l_totalSize;
+ break;
+ }
+
+ // Now we can actually copy all the entries...
+ while(1)
+ {
+ // Copy entry data.
+ memcpy(&l_data[l_size], &entry->data[0],entry->size);
+ l_size += entry->size;
+
+ // Copy entry size.
+ uint32_t entry_size = entry->size + sizeof(uint32_t);
+ memcpy(&l_data[l_size], &entry_size, sizeof(uint32_t));
+ l_size += sizeof(uint32_t);
+
+ l_entries++;
+
+ if (entry == orig_entry)
+ {
+ break;
+ }
+ else
+ {
+ entry = entry->prev;
+ }
+ };
+
+ }
+ while(0);
+
+ // Unlock for daemon.
+ _producerExit();
+
+ // Update header.
+ if (header)
+ {
+ header->size = l_size;
+ header->next_free = l_size;
+ header->te_count = l_entries;
+ }
+
+ return l_size;
+ }
+
+ bool Buffer::consumerOp(Entry** i_condAddr, Entry* i_condVal,
+ Entry** i_condActAddr,
+ Entry* i_condActVal,
+ Entry** i_addr, Entry* i_val)
+ {
+ bool rc = true;
+
+ // Get consumer lock.
+ _consumerEnter();
+
+ // Primative #1.
+ if (NULL != i_condAddr)
+ {
+ if (i_condVal == *i_condAddr)
+ {
+ if (NULL != i_condActAddr)
+ {
+ *i_condActAddr = i_condActVal;
+ }
+ }
+ else
+ {
+ rc = false;
+ }
+ }
+
+ // Primative #2.
+ if (NULL != i_addr)
+ {
+ *i_addr = i_val;
+ }
+
+ // Release consumer lock.
+ _consumerExit();
+
+ return rc;
+ }
+
+}
diff --git a/src/usr/trace/buffer.H b/src/usr/trace/buffer.H
new file mode 100644
index 000000000..04cb6f672
--- /dev/null
+++ b/src/usr/trace/buffer.H
@@ -0,0 +1,197 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/buffer.H $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __TRACE_BUFFER_H
+#define __TRACE_BUFFER_H
+
+/** @file buffer.H
+ * Declarations for the buffer class.
+ */
+
+#include <trace/interface.H>
+#include <sys/sync.h>
+
+namespace TRACEDAEMON { class Daemon; } // Forward declaration.
+
+namespace TRACE
+{
+ // Forward declarations.
+ class BufferPage;
+ class Entry;
+ class DaemonIf;
+
+ /** @class Buffer
+ * @brief Class to manage the front-side (client) buffers
+ *
+ * Provides interfaces for getting an entry to write trace data to and
+ * committing that entry as well as extracting the component trace.
+ *
+ * Private interfaces for the daemon to ensure lockless ordering is
+ * maintained.
+ */
+ class Buffer
+ {
+ public:
+
+ enum
+ {
+ /** Used as a parameter to the constructor to indicate that
+ * the buffer should never block (and could instead run
+ * the system out of memory). */
+ UNLIMITED = UINT32_MAX
+ };
+
+ /** Constructor.
+ *
+ * @param[in] i_daemon - Daemon interface for this buffer.
+ * @param[in] i_maxPages - Maximum number of pages to consume
+ * before 'claimEntry' blocks.
+ */
+ Buffer(DaemonIf* i_daemon, size_t i_maxPages = 4);
+
+ /** @brief Claim an entry from the buffer to write data to.
+ *
+ * @param[in] i_comp - Component which will own entry.
+ * @param[in] i_size - Size of data portion of entry.
+ *
+ * @return An entry to write to.
+ *
+ * If pages allocated is at max pages and there is no room to
+ * create an entry, this function may block. For components
+ * which cannot block, it is expected that the buffer will be
+ * constructed large enough that we run out of memory before
+ * we block.
+ */
+ Entry* claimEntry(ComponentDesc* i_comp, size_t i_size);
+
+ /** @brief Commit entry to buffer and component linked-list.
+ *
+ * @param[in] i_entry - Entry to commit.
+ */
+ void commitEntry(Entry* i_entry);
+
+ /** @brief Extract component trace.
+ *
+ * See service::getBuffer. Defined here due to lockless ordering
+ * needs.
+ */
+ size_t getTrace(ComponentDesc* i_comp, void* o_data, size_t i_size);
+
+ private:
+ volatile uint64_t iv_pagesAlloc; //< Number of pages allocated.
+ uint64_t iv_pagesMax; //< Maximum pages allowed.
+
+ BufferPage* volatile iv_firstPage; //< Most recent page.
+
+ /** @union locklessCounter
+ *
+ * This class is mostly lockless in that multiple trace entries
+ * can be created at the same time along with buffer extraction.
+ * This means that all client operations are lockless.
+ *
+ * There are minor operations that the daemon must do to ensure
+ * that a client is not in the middle of another operation, such
+ * as when the daemon removes the pages from the front-end to
+ * merge them into the backend. During this time, the daemon
+ * will obtain the equivalent of a write-lock, which will block
+ * all clients.
+ *
+ * It is required that all times where the write-lock is held
+ * are short and cannot cause page-faults that might deadlock
+ * components such as VFS and PNOR. This means that all code
+ * inside the write-lock is in the base image.
+ *
+ * This read/write lock is modeled here as "producers" (clients)
+ * and a "consumer" (daemon). The active counts of each are
+ * recorded with this structure and unioned to a single uint64_t
+ * so that they can be atomically updated as one entity.
+ */
+ union locklessCounter
+ {
+ struct
+ {
+ uint32_t producerCount;
+ uint32_t consumerCount;
+ };
+ uint64_t totals;
+ };
+
+ locklessCounter iv_counters; //< The producer/consumer counts.
+
+ DaemonIf* iv_daemon; //< Daemon interface.
+
+ /** @brief Claim front-side buffer pages to be merged into the
+ * common buffer.
+ *
+ * @return Pointer to the first page (most recent) from this
+ * buffer.
+ *
+ * Gives ownership of all the current pages to the caller and
+ * resets this buffer's allocated page counts.
+ */
+ BufferPage* claimPages();
+
+ /** @brief Perform operations with the consumer lock held.
+ *
+ * These operations cannot be done in the daemon code directly
+ * because the daemon code is swappable and we cannot block
+ * producers.
+ *
+ * This function gives a set of primatives to the daemon to
+ * manipulate Entry pointers while secured under the consumer lock.
+ *
+ * The primatives that can be done are:
+ * 1) if (condAddr == condVal) { condActAddr = condActVal }
+ * 2) addr = val
+ *
+ * If any of the address parameters are NULL, their action will
+ * not be performed. So, just calling consumerOp() has the
+ * side-effect of simply toggling the consumer lock on and off.
+ *
+ * The return value indicates if primative #1 failed.
+ *
+ * @param[in] i_condAddr - The address to read for primative 1.
+ * @param[in] i_condVal - The value to expect for primative 1.
+ * @param[in] i_condActAddr - The address to store for primative 1.
+ * @param[in] i_condActVal - The value to store for primative 1.
+ *
+ * @param[in] i_addr - The address to store for primative 2.
+ * @param[in] i_val - The value to store for primative 2.
+ *
+ * @return bool - false if condAddr != condVal, true otherwise.
+ */
+ bool consumerOp(Entry** i_condAddr = NULL, Entry* i_condVal = NULL,
+ Entry** i_condActAddr = NULL,
+ Entry* i_condActVal = NULL,
+ Entry** i_addr = NULL, Entry* i_val = NULL);
+
+ void _producerEnter(); //< Enter client section.
+ void _producerExit(); //< Exit client section.
+ void _consumerEnter(); //< Enter daemon section.
+ void _consumerExit(); //< Exit daemon section.
+
+ friend class BufferTest;
+ friend class TRACEDAEMON::Daemon;
+ };
+}
+
+#endif
diff --git a/src/usr/trace/bufferpage.C b/src/usr/trace/bufferpage.C
new file mode 100644
index 000000000..b4e655980
--- /dev/null
+++ b/src/usr/trace/bufferpage.C
@@ -0,0 +1,79 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/bufferpage.C $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#include "bufferpage.H"
+
+#include <limits.h>
+#include <stdlib.h>
+#include <kernel/pagemgr.H>
+
+namespace TRACE
+{
+
+ Entry* BufferPage::claimEntry(size_t i_size)
+ {
+ uint64_t l_usedSize = this->usedSize;
+
+ // Verify there is enough space.
+ while ((usedSize + i_size) < (PAGESIZE - sizeof(BufferPage)))
+ {
+ // Atomically attempt to claim i_size worth.
+ uint64_t newSize = l_usedSize + i_size;
+ if (!__sync_bool_compare_and_swap(&this->usedSize,
+ l_usedSize,
+ newSize))
+ {
+ // Failed race to atomically update.
+ // Re-read size, try again.
+ l_usedSize = this->usedSize;
+ continue;
+ }
+
+ // Successful at claiming an entry, return pointer to it.
+ return reinterpret_cast<Entry*>(&this->data[0] + l_usedSize);
+ }
+
+ return NULL;
+ }
+
+ BufferPage* BufferPage::allocate(bool i_common)
+ {
+ BufferPage* page = NULL;
+
+ page = reinterpret_cast<BufferPage*>(PageManager::allocatePage());
+ memset(page, '\0', PAGESIZE);
+
+ if (i_common)
+ {
+ page->commonPage = 1;
+ }
+
+ return page;
+ }
+
+ void BufferPage::deallocate(BufferPage* i_page)
+ {
+ PageManager::freePage(i_page);
+ }
+
+}
diff --git a/src/usr/trace/bufferpage.H b/src/usr/trace/bufferpage.H
new file mode 100644
index 000000000..7493fc512
--- /dev/null
+++ b/src/usr/trace/bufferpage.H
@@ -0,0 +1,73 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/bufferpage.H $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __TRACE_BUFFERPAGE_H
+#define __TRACE_BUFFERPAGE_H
+
+#include <trace/interface.H>
+
+namespace TRACE
+{
+ class Entry;
+
+ /** @struct BufferPage
+ *
+ * A structure which can be overlaid onto a page of memory to allocate
+ * entries within the page.
+ */
+ struct BufferPage
+ {
+ BufferPage* next; //< Linked-list 'next' ptr.
+ BufferPage* prev; //< Linked-list 'prev' ptr.
+
+ uint32_t commonPage; //< Status used by daemon pages.
+ uint32_t usedSize; //< Size already allocated for entries.
+
+ char data[0]; //< Data for entries.
+
+ /** @brief Lockless-ly claim an entry from the page.
+ *
+ * @param[in] i_size - Size in bytes.
+ *
+ * @return Entry* or NULL, if not enough space.
+ */
+ Entry* claimEntry(size_t i_size);
+
+ /** @brief Utility function to allocate a page.
+ *
+ * @param[in] i_common - Page is "common" from a daemon perspective.
+ *
+ * @return Pointer to page.
+ */
+ static BufferPage* allocate(bool i_common = false);
+
+ /** @brief Utility function to free a page.
+ *
+ * @param[in] i_page - Page to deallocate.
+ */
+ static void deallocate(BufferPage* i_page);
+
+ };
+}
+
+#endif
+
diff --git a/src/usr/trace/compdesc.C b/src/usr/trace/compdesc.C
new file mode 100644
index 000000000..92b306949
--- /dev/null
+++ b/src/usr/trace/compdesc.C
@@ -0,0 +1,98 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/compdesc.C $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+#include "compdesc.H"
+#include "service.H"
+#include <assert.h>
+#include <string.h>
+#include <string_ext.h>
+
+namespace TRACE
+{
+ ComponentDesc::ComponentDesc(const char* i_comp, uint32_t i_size,
+ uint8_t i_bufferType) :
+ iv_bufferType(i_bufferType), iv_debugEnabled(false),
+ iv_maxSize(i_size), iv_curSize(0),
+ iv_first(NULL), iv_last(NULL)
+ {
+ assert(iv_bufferType < BUFFER_COUNT);
+
+ memset(iv_compName, '\0', sizeof(iv_compName));
+ strcpy(iv_compName, i_comp); // No buffer overrun because of assert
+ // in ComponentList::getDescriptor.
+ strupr(iv_compName);
+
+ iv_compNameLen = strlen(iv_compName) + 1;
+ }
+
+ ComponentList::ComponentList() :
+ iv_components()
+ {
+ mutex_init(&iv_mutex);
+ };
+
+ ComponentList::~ComponentList()
+ {
+ mutex_destroy(&iv_mutex);
+ };
+
+ ComponentDesc* ComponentList::getDescriptor(const char* i_comp,
+ uint32_t i_size,
+ uint8_t i_bufferType)
+ {
+ ComponentDesc* l_rc = NULL;
+
+ assert(strlen(i_comp) < ComponentDesc::COMP_SIZE);
+
+ // Fix up the component name to be upper case.
+ char l_compName[ComponentDesc::COMP_SIZE];
+ memset(l_compName, '\0', sizeof(l_compName));
+ strcpy(l_compName, i_comp);
+ strupr(l_compName);
+
+ mutex_lock(&iv_mutex);
+
+ // Look for existing descriptor.
+ for(List::iterator i = iv_components.begin();
+ i != iv_components.end();
+ ++i)
+ {
+ if (0 == memcmp(&i->iv_compName, l_compName, sizeof(l_compName)))
+ {
+ l_rc = &(*i);
+ break;
+ }
+ }
+
+ // Insert new descriptor if none found.
+ if ((NULL == l_rc) && (i_size > 0))
+ {
+ iv_components.push_back(ComponentDesc(l_compName, i_size,
+ i_bufferType));
+ l_rc = &iv_components.back();
+ }
+
+ mutex_unlock(&iv_mutex);
+ return l_rc;
+ }
+
+};
diff --git a/src/usr/trace/compdesc.H b/src/usr/trace/compdesc.H
new file mode 100644
index 000000000..48270add0
--- /dev/null
+++ b/src/usr/trace/compdesc.H
@@ -0,0 +1,146 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/compdesc.H $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __TRACE_COMPDESC_H
+#define __TRACE_COMPDESC_H
+
+/** @file compdesc.H
+ *
+ * @brief Defines the classes for component descriptors and a singleton list
+ * of descriptors.
+ */
+
+#include <trace/interface.H>
+#include <sys/sync.h>
+#include <list>
+
+namespace TRACEDAEMON { class Daemon; } // Forward declaration.
+
+namespace TRACE
+{
+
+ class Entry; // Forward declaration.
+
+ /** @class ComponentDesc
+ *
+ * @brief The descriptor for a particular component.
+ *
+ * @note These should not be created directly, but by the ComponentList
+ * interfaces.
+ */
+ class ComponentDesc
+ {
+ public:
+ friend class ComponentList;
+ friend class Service;
+ friend class Buffer;
+ friend class TRACEDAEMON::Daemon;
+
+ private:
+ /** Constructor
+ *
+ * @param[in] i_comp - Component name.
+ * @param[in] i_size - Size limit of buffer.
+ * @param[in] i_bufferType - Type of buffer this component is
+ * assigned to.
+ */
+ ComponentDesc(const char* i_comp, uint32_t i_size,
+ uint8_t i_bufferType = BUFFER_FAST);
+
+ /** Max ength of component names. */
+ enum { COMP_SIZE = TRAC_COMP_SIZE };
+
+ char iv_compName[COMP_SIZE]; //< Component name.
+ uint8_t iv_compNameLen; //< Length in bytes of name.
+
+ uint8_t iv_bufferType; //< Buffer type.
+ bool iv_debugEnabled; //< Debug or Field-only traces.
+
+ uint32_t iv_maxSize; //< Size limit.
+ uint32_t iv_curSize; //< Current size.
+
+ Entry* iv_first; //< First (newest) trace entry.
+ Entry* iv_last; //< Last (oldest) trace entry.
+ };
+
+ /** @class ComponentList
+ *
+ * @brief Maintains the global list of component trace descriptors.
+ *
+ * It is expected that a singleton instance of this exists and all
+ * trace descriptors are allocated from it.
+ */
+ class ComponentList
+ {
+ public:
+ typedef std::list<ComponentDesc> List;
+
+ /** Default constructor */
+ ComponentList();
+
+ /** Default destructor */
+ ~ComponentList();
+
+ /** Get descriptor for a component
+ *
+ * @param[in] i_comp - Name of the component.
+ * @param[in] i_size - Size limit of buffer.
+ * @param[in] i_bufferType - Buffer type.
+ *
+ * If i_size is 0, that implies this is not "creating" a buffer
+ * but "requesting" the buffer, for instance to pass to the
+ * buffer-extract functions. In that case, if the buffer does
+ * not currently exist we don't know what size-limit to use
+ * when creating the buffer, so the function will return NULL.
+ *
+ * @return Descriptor or NULL.
+ */
+ ComponentDesc* getDescriptor(const char* i_comp, uint32_t i_size,
+ uint8_t i_bufferType = BUFFER_FAST);
+
+ /* Thread-safe iterator functions (for daemon). */
+ /** Get the first component descriptor
+ *
+ * @param[out] o_comp - Iterator to first component.
+ *
+ * @return bool - True if empty-list.
+ */
+ bool first(List::iterator& o_comp);
+ /** Get the next component descriptor
+ *
+ * @param[in,out] io_comp - Iterator to increment.
+ *
+ * @return bool - True if iterator was the last descriptor.
+ *
+ * Ex. "if (io_comp->next == iv_components.end()) return true"
+ */
+ bool next(List::iterator& io_comp);
+
+ private:
+ /** List of component descriptors. */
+ List iv_components;
+ /** Mutex for thread-safety. */
+ mutex_t iv_mutex;
+ };
+}
+
+#endif
diff --git a/src/usr/trace/daemon/complist.C b/src/usr/trace/daemon/complist.C
new file mode 100644
index 000000000..95f2128d3
--- /dev/null
+++ b/src/usr/trace/daemon/complist.C
@@ -0,0 +1,51 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/daemon/complist.C $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+#include "../compdesc.H"
+
+namespace TRACE
+{
+ bool ComponentList::first(ComponentList::List::iterator& o_comp)
+ {
+ bool l_rc = true;
+
+ mutex_lock(&iv_mutex);
+ o_comp = iv_components.begin();
+ l_rc = (o_comp != iv_components.end());
+ mutex_unlock(&iv_mutex);
+
+ return l_rc;
+ }
+
+ bool ComponentList::next(ComponentList::List::iterator& io_comp)
+ {
+ bool l_rc = true;
+
+ mutex_lock(&iv_mutex);
+ io_comp++;
+ l_rc = (io_comp != iv_components.end());
+ mutex_unlock(&iv_mutex);
+
+ return l_rc;
+ }
+
+}
diff --git a/src/usr/trace/daemon/daemon.C b/src/usr/trace/daemon/daemon.C
new file mode 100644
index 000000000..2a98f70b5
--- /dev/null
+++ b/src/usr/trace/daemon/daemon.C
@@ -0,0 +1,578 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/daemon/daemon.C $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+#include "daemon.H"
+#include "../daemonif.H"
+#include "../service.H"
+#include "../buffer.H"
+#include "../bufferpage.H"
+#include "../entry.H"
+#include "../compdesc.H"
+
+#include <initservice/taskargs.H>
+#include <initservice/initserviceif.H>
+
+#include <sys/msg.h>
+#include <kernel/console.H>
+#include <util/align.H>
+
+#include <targeting/common/commontargeting.H>
+#include <devicefw/userif.H>
+
+namespace TRACE
+{
+ // Functions from DaemonIf that are only used by the daemon itself,
+ // so implemented here to decrease size of base module.
+
+ void DaemonIf::start()
+ {
+ iv_running = true;
+ }
+
+ void DaemonIf::clearSignal()
+ {
+ // Atomically reset signal.
+ __sync_lock_test_and_set(&iv_signalled, 0);
+ }
+}
+
+namespace TRACEDAEMON
+{
+ using namespace TRACE;
+
+ Daemon::Daemon() : iv_service(NULL), iv_totalPruned(0)
+ {
+ iv_first = iv_last = BufferPage::allocate(true);
+ }
+
+ Daemon::~Daemon()
+ {
+ assert(0);
+ }
+
+ void Daemon::execute()
+ {
+ // Mark the daemon as started in the interface.
+ iv_service = Service::getGlobalInstance();
+ iv_service->iv_daemon->start();
+
+ // Register shutdown events with init service.
+ // Do one at the "beginning" and "end" of shutdown processesing.
+ // The one at the beginning will flush out everything prior to
+ // the shutdown sequencing and get it out the mailbox.
+ //
+ // The one at the end will only be useful in non-FSP environments
+ // for continuous trace, because the mailbox is already shutdown.
+ //
+ INITSERVICE::registerShutdownEvent(iv_service->iv_daemon->iv_queue,
+ DaemonIf::TRACE_DAEMON_SIGNAL,
+ INITSERVICE::HIGHEST_PRIORITY);
+ INITSERVICE::registerShutdownEvent(iv_service->iv_daemon->iv_queue,
+ DaemonIf::TRACE_DAEMON_SIGNAL,
+ INITSERVICE::LOWEST_PRIORITY);
+
+ // Clear scratch register.
+ writeScratchReg(0);
+
+ // Loop handling messages.
+ while (msg_t* msg = iv_service->iv_daemon->wait())
+ {
+ switch (msg->type)
+ {
+ // Signal from client.
+ case DaemonIf::TRACE_DAEMON_SIGNAL:
+ {
+ // Collect trace entries from client.
+ collectTracePages();
+
+ // Reduce buffer space in daemon-side buffer.
+ pruneTraceEntries();
+ coalescePages();
+
+ break;
+ }
+
+ // Shutdown message.
+ case DaemonIf::TRACE_DAEMON_SHUTDOWN:
+ {
+ // The main daemon should never shut down.
+ assert(0);
+ break;
+ }
+
+
+ default:
+ {
+ assert(0);
+ break;
+ }
+ }
+
+ // Delete or respond as appropriate.
+ if (msg_is_async(msg))
+ {
+ msg_free(msg);
+ }
+ else
+ {
+ msg_respond(iv_service->iv_daemon->iv_queue, msg);
+ }
+ }
+ }
+
+ void* Daemon::start(void* unused)
+ {
+ Singleton<Daemon>::instance().execute();
+ return NULL;
+ }
+
+ void daemonProcess(errlHndl_t& o_errl)
+ {
+ task_create(&Daemon::start, NULL);
+ }
+
+
+ void Daemon::collectTracePages()
+ {
+ // Clear indication from clients.
+ iv_service->iv_daemon->clearSignal();
+
+ // Collect buffer pages from front-end.
+ BufferPage* srcPages[BUFFER_COUNT];
+ for (size_t i = 0; i < BUFFER_COUNT; i++)
+ {
+ iv_curPages[i] = srcPages[i] =
+ iv_service->iv_buffers[i]->claimPages();
+
+ iv_curOffset[i] = 0;
+ }
+
+ char* contBuffer = NULL;
+ size_t contBufferSize = 0;
+
+ // Process buffer pages.
+ do
+ {
+ size_t whichBuffer = BUFFER_COUNT;
+ Entry* whichEntry = NULL;
+ uint64_t minTimeStamp = UINT64_MAX;
+
+ // Find the entry with the earliest timestamp.
+ for (size_t i = 0; i < BUFFER_COUNT; i++)
+ {
+ if (NULL == iv_curPages[i]) continue;
+
+ Entry* entry =
+ reinterpret_cast<Entry*>(
+ &((&(iv_curPages[i]->data[0]))[iv_curOffset[i]])
+ );
+
+ trace_bin_entry_t* binEntry =
+ reinterpret_cast<trace_bin_entry_t*>(
+ &(entry->data[0])
+ );
+
+ // Wait for entry to be committed.
+ while(unlikely(entry->committed == 0))
+ {
+ task_yield();
+ }
+ isync();
+
+ uint64_t curTimeStamp =
+ TWO_UINT32_TO_UINT64(binEntry->stamp.tbh,
+ binEntry->stamp.tbl);
+
+ if (curTimeStamp < minTimeStamp)
+ {
+ whichBuffer = i;
+ whichEntry = entry;
+ minTimeStamp = curTimeStamp;
+ }
+ }
+
+ // Did not find another entry, our work is done.
+ if (whichBuffer == BUFFER_COUNT)
+ {
+ break;
+ }
+
+ // Increment pointers to next buffer entry.
+ iv_curOffset[whichBuffer] += whichEntry->size + sizeof(Entry);
+ if (iv_curOffset[whichBuffer] >= iv_curPages[whichBuffer]->usedSize)
+ {
+ iv_curPages[whichBuffer] = iv_curPages[whichBuffer]->next;
+ iv_curOffset[whichBuffer] = 0;
+ }
+
+ // Calculate the sizes of the entry.
+ size_t contEntryDataLength =
+ reinterpret_cast<trace_bin_entry_t*>(&whichEntry->data[0])
+ ->head.length + sizeof(trace_bin_entry_t);
+
+ size_t contEntrySize = whichEntry->comp->iv_compNameLen +
+ contEntryDataLength;
+
+ // Allocate a new continuous trace page if needed.
+ if ((NULL == contBuffer) ||
+ ((contBufferSize + contEntrySize) >= PAGESIZE))
+ {
+ if (NULL != contBuffer)
+ {
+ sendContBuffer(contBuffer, contBufferSize);
+ }
+
+ contBuffer = reinterpret_cast<char*>(malloc(PAGESIZE));
+ memset(contBuffer, '\0', PAGESIZE);
+ contBuffer[0] = TRACE_BUF_CONT;
+ contBufferSize = 1;
+ }
+
+ // Add entry to continous trace.
+ memcpy(&contBuffer[contBufferSize],
+ whichEntry->comp->iv_compName,
+ whichEntry->comp->iv_compNameLen);
+ contBufferSize += whichEntry->comp->iv_compNameLen;
+
+ memcpy(&contBuffer[contBufferSize],
+ &whichEntry->data[0],
+ contEntryDataLength);
+ contBufferSize += contEntryDataLength;
+
+ // Allocate a new back-end entry.
+ Entry* mainBuffEntry = NULL;
+ while (NULL ==
+ (mainBuffEntry =
+ iv_last->claimEntry(whichEntry->size + sizeof(Entry))))
+ {
+ BufferPage* n = BufferPage::allocate(true);
+
+ n->next = iv_last;
+ iv_last->prev = n;
+ iv_last = n;
+ }
+
+ // Move entry from front-end buffer to back-end.
+ replaceEntry(whichEntry, mainBuffEntry);
+
+ } while(1);
+
+ // Send remainder of continous trace buffer.
+ if (NULL != contBuffer)
+ {
+ if (contBufferSize > 1)
+ {
+ sendContBuffer(contBuffer, contBufferSize);
+ }
+ else
+ {
+ free(contBuffer);
+ }
+ }
+
+ // Release pages.
+ for (size_t i = 0; i < BUFFER_COUNT; i++)
+ {
+ // Toggle lock to ensure no trace extract currently going on.
+ iv_service->iv_buffers[i]->consumerOp();
+
+ while(srcPages[i])
+ {
+ BufferPage* tmp = srcPages[i]->next;
+ BufferPage::deallocate(srcPages[i]);
+ srcPages[i] = tmp;
+ }
+ }
+
+ }
+
+
+ void Daemon::sendContBuffer(void* i_buffer, size_t i_size)
+ {
+ // Write scratch register indicating continuous trace is available.
+ writeScratchReg(1ull << 32);
+
+ // Signal for simics.
+ asm volatile("mr 4, %0; mr 5, %1" ::
+ "r" (i_buffer), "r" (i_size) : "4", "5");
+ MAGIC_INSTRUCTION(MAGIC_CONTINUOUS_TRACE);
+
+ TARGETING::Target* sys = NULL;
+ TARGETING::targetService().getTopLevelTarget(sys);
+
+ TARGETING::SpFunctions spFunctions =
+ sys->getAttr<TARGETING::ATTR_SP_FUNCTIONS>();
+
+ if (!spFunctions.traceContinuous)
+ {
+ // Trace isn't enabled so just discard the buffer.
+ free(i_buffer);
+ }
+ else
+ {
+ if (spFunctions.mailboxEnabled)
+ {
+ // TODO: Send message to FSP.
+ free(i_buffer);
+ }
+ else
+ {
+ // Wait for tools to extract the buffer.
+ while(0 != readScratchReg())
+ {
+ task_yield();
+ }
+ }
+ }
+ }
+
+ void Daemon::replaceEntry(Entry* from, Entry* to)
+ {
+ do
+ {
+ // Copy entry content to new entry.
+ memcpy(to,
+ from,
+ from->size + sizeof(Entry));
+
+ // Update next object's pointer.
+ if (to->next)
+ {
+ to->next->prev = to;
+ }
+ else
+ {
+ to->comp->iv_last = to;
+ }
+ lwsync(); // Ensure pointer update is globally visible
+ // (to order before 'prev' object updates).
+
+ // Update prev object's pointer.
+ // Buffer ensures that an entries "next" is written before
+ // the "next->prev", so we can be certain that if to->prev
+ // then to->prev->next is finalized.
+ if (to->prev)
+ {
+ to->prev->next = to;
+ }
+ else // If there is no previous, this is the first (most recent)
+ // for the component, so update the component object.
+ {
+ Buffer* b =
+ iv_service->iv_buffers[to->comp->iv_bufferType];
+
+ // Need to toggle the consumer lock on this one, so use
+ // the consumerOp to move the compoment->first from
+ // 'from' to 'to'.
+ //
+ // If it fails (first != from anymore) then retry this
+ // whole sequence.
+ if (!b->consumerOp(&to->comp->iv_first, from,
+ &to->comp->iv_first, to))
+ {
+ continue;
+ }
+ }
+
+ // Successfully updated everything, break from loop.
+ break;
+
+ } while (1);
+ }
+
+ void Daemon::pruneTraceEntries()
+ {
+ ComponentList::List::iterator component;
+
+ size_t pruned = 0;
+
+ // Iterate through the components...
+ bool more = iv_service->iv_compList->first(component);
+ while(more)
+ {
+ Entry* entry = component->iv_last;
+ Entry* orig_entry = entry;
+
+ // Invalidate entries until the component is small enough.
+ while((entry) && (component->iv_curSize > component->iv_maxSize))
+ {
+ if (!reinterpret_cast<BufferPage*>(
+ ALIGN_PAGE_DOWN(
+ reinterpret_cast<uint64_t>(entry)))->commonPage)
+ {
+ break;
+ }
+
+ entry->comp = NULL; // Invalidate entry.
+
+ __sync_sub_and_fetch(&component->iv_curSize, entry->size);
+ pruned += entry->size;
+
+ entry = entry->prev;
+ }
+
+ if (entry != orig_entry)
+ {
+ printkd("%s,", component->iv_compName);
+
+ // Break chain of linked list.
+ if (entry != NULL)
+ {
+ entry->next = NULL;
+ }
+
+ // Update component pointers.
+ Buffer* b =
+ iv_service->iv_buffers[component->iv_bufferType];
+
+ // consumerOp pseudo-code:
+ // if (entry == NULL) component->first = NULL;
+ // component->last = entry;
+ b->consumerOp(&entry, NULL,
+ &component->iv_first, NULL,
+ &component->iv_last, entry);
+ }
+
+ // Get next component.
+ more = iv_service->iv_compList->next(component);
+ }
+
+ // Record size of pruned entries in a global.
+ if (pruned)
+ {
+ printkd(": pruned %ld\n", pruned);
+ iv_totalPruned += pruned;
+ }
+ }
+
+ void Daemon::coalescePages()
+ {
+ // Skip if there hasn't been enough entries pruned to make this
+ // worth our while.
+ if (iv_totalPruned < PAGESIZE) { return; }
+
+
+ iv_totalPruned = 0;
+
+ // Allocate a new back-end page for the coalesced entries.
+ BufferPage* outputPage = BufferPage::allocate(true);
+ BufferPage* originalOutputPage = outputPage;
+
+ // Get the first page from the original back-end buffer.
+ BufferPage* currentPage = iv_first;
+
+ // Iterate through the back-end pages.
+ while(currentPage != NULL)
+ {
+
+ // Look at all the entries on the back-end pages.
+ size_t offset = 0;
+ while (offset < currentPage->usedSize)
+ {
+ Entry* entry =
+ reinterpret_cast<Entry*>(&currentPage->data[offset]);
+
+ if (NULL != entry->comp) // Ensure entry is valid.
+ {
+ Entry* newEntry = NULL;
+
+ // Allocate space on new back-end pages.
+ while (NULL == (newEntry =
+ outputPage->claimEntry(entry->size + sizeof(Entry))))
+ {
+ BufferPage* newPage = BufferPage::allocate(true);
+
+ newPage->next = outputPage;
+ outputPage->prev = newPage;
+ outputPage = newPage;
+ }
+
+ // Move entry to new back-end page.
+ replaceEntry(entry, newEntry);
+ }
+
+ offset += entry->size + sizeof(Entry);
+ }
+
+ currentPage = currentPage->prev;
+ }
+
+ BufferPage* oldPage = iv_first;
+
+ // Update back-end buffer pointers to point to new back-end pages.
+ iv_last = outputPage;
+ iv_first = originalOutputPage;
+
+ // Toggle client buffers to ensure no trace extract is going on
+ // on the old back-end pages.
+ for (size_t i = 0; i < BUFFER_COUNT; i++)
+ {
+ iv_service->iv_buffers[i]->consumerOp();
+ }
+
+ // Delete the old back-end pages.
+ while(oldPage)
+ {
+ BufferPage* temp = oldPage->prev;
+ BufferPage::deallocate(oldPage);
+ oldPage = temp;
+ }
+
+ }
+
+ void Daemon::writeScratchReg(uint64_t i_value)
+ {
+ size_t l_size = sizeof(uint64_t);
+
+ errlHndl_t l_errl =
+ deviceWrite(TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &i_value, l_size,
+ DEVICE_SCOM_ADDRESS(MB_SCRATCH_REGISTER_1));
+
+ if (l_errl)
+ {
+ errlCommit(l_errl, HBTRACE_COMP_ID);
+ }
+ }
+
+ uint64_t Daemon::readScratchReg()
+ {
+ size_t l_size = sizeof(uint64_t);
+ uint64_t value = 0;
+
+ errlHndl_t l_errl =
+ deviceRead(TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &value, l_size,
+ DEVICE_SCOM_ADDRESS(MB_SCRATCH_REGISTER_1));
+
+ if (l_errl)
+ {
+ errlCommit(l_errl, HBTRACE_COMP_ID);
+ }
+
+ return value;
+ }
+
+}
+
+// Define an entry point for the trace daemon module.
+TASK_ENTRY_MACRO( TRACEDAEMON::daemonProcess );
diff --git a/src/usr/trace/daemon/daemon.H b/src/usr/trace/daemon/daemon.H
new file mode 100644
index 000000000..e6d2f5606
--- /dev/null
+++ b/src/usr/trace/daemon/daemon.H
@@ -0,0 +1,121 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/daemon/daemon.H $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __TRACE_DAEMON_DAEMON_H
+#define __TRACE_DAEMON_DAEMON_H
+
+/** @file daemon.H
+ * Declarations for the daemon class.
+ */
+
+#include <stdint.h>
+#include "../service.H"
+
+ // Forward declarations.
+namespace TRACE
+{
+ class BufferPage;
+ class Entry;
+}
+
+namespace TRACEDAEMON
+{
+ /** @class Daemon
+ *
+ * @brief Class to handle trace background ops and mailbox messages.
+ */
+ class Daemon
+ {
+ public:
+ /** Default constructor.
+ *
+ * Initializes class.
+ *
+ */
+ Daemon();
+ /** Destructor.
+ *
+ * Not currently supported, asserts.
+ */
+ ~Daemon();
+
+ /** @fn start
+ *
+ * Thread entry-point for daemon. Calls 'execute'.
+ */
+ static void* start(void*);
+
+ private:
+
+ /** @fn execute
+ *
+ * Performs daemon work.
+ */
+ void execute();
+
+ /** Gather trace pages from client-side buffers. */
+ void collectTracePages();
+ /** Send continuous trace buffer to SP. */
+ void sendContBuffer(void* i_buffer, size_t i_size);
+ /** Reduce component trace buffers if exceeded max size. */
+ void pruneTraceEntries();
+ /** Combine trace buffer pages to remove pruned entries. */
+ void coalescePages();
+
+ /** Locklessly move a trace entry from one location to another. */
+ void replaceEntry(TRACE::Entry* from, TRACE::Entry* to);
+
+ /** Write mailbox scratch register to a value. */
+ void writeScratchReg(uint64_t i_value);
+ /** Read mailbox scratch register. */
+ uint64_t readScratchReg();
+
+ /** Client-service object. */
+ TRACE::Service* iv_service;
+
+ /** First (oldest) combined-buffer page. */
+ TRACE::BufferPage* iv_first;
+ /** Last (newested) combined-buffer page. */
+ TRACE::BufferPage* iv_last;
+
+ // These are kept as class variables rather than function variables
+ // so that they can be extraced by the debug tools, since we might
+ // be in the middle of the 'collectTracePages' function when the
+ // debug tools try to extract the trace.
+ /** Intermediate pages
+ * After collection from client-side, before combining. */
+ TRACE::BufferPage* iv_curPages[TRACE::BUFFER_COUNT];
+ /** Current offset into intermediate page. */
+ size_t iv_curOffset[TRACE::BUFFER_COUNT];
+
+ /** Current size of trace entries pruned. */
+ size_t iv_totalPruned;
+
+ /** Address of scratch register. */
+ static const uint32_t MB_SCRATCH_REGISTER_1 = 0x00050038;
+
+ };
+
+
+}
+
+#endif
diff --git a/src/usr/trace/daemon/makefile b/src/usr/trace/daemon/makefile
new file mode 100644
index 000000000..325810b77
--- /dev/null
+++ b/src/usr/trace/daemon/makefile
@@ -0,0 +1,30 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/usr/trace/daemon/makefile $
+#
+# IBM CONFIDENTIAL
+#
+# COPYRIGHT International Business Machines Corp. 2011,2012
+#
+# p1
+#
+# Object Code Only (OCO) source materials
+# Licensed Internal Code Source Materials
+# IBM HostBoot Licensed Internal Code
+#
+# The source code for this program is not published or otherwise
+# divested of its trade secrets, irrespective of what has been
+# deposited with the U.S. Copyright Office.
+#
+# Origin: 30
+#
+# IBM_PROLOG_END_TAG
+ROOTPATH = ../../../..
+MODULE = tracedaemon
+
+OBJS = daemon.o complist.o
+
+#SUBDIRS = test.d
+
+include ${ROOTPATH}/config.mk
diff --git a/src/usr/trace/daemonif.C b/src/usr/trace/daemonif.C
new file mode 100644
index 000000000..c03014086
--- /dev/null
+++ b/src/usr/trace/daemonif.C
@@ -0,0 +1,67 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/daemonif.C $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+#include "daemonif.H"
+
+namespace TRACE
+{
+
+ DaemonIf::DaemonIf() :
+ iv_queue(msg_q_create()), iv_signalled(0), iv_running(false)
+ {
+ }
+
+ DaemonIf::~DaemonIf()
+ {
+ if (iv_running)
+ {
+ msg_t* msg = msg_allocate();
+ msg->type = TRACE_DAEMON_SHUTDOWN;
+ msg_sendrecv(iv_queue, msg);
+ msg_free(msg);
+ }
+
+ msg_q_destroy(iv_queue);
+ }
+
+ void DaemonIf::signal(bool i_blocking)
+ {
+ // Atomically increment the signal count.
+ uint16_t count = __sync_fetch_and_add(&iv_signalled, 1);
+
+ // Send a message if this is the first, or requested to be blocking.
+ if ((count == 0) || (i_blocking))
+ {
+ msg_t* msg = msg_allocate();
+ msg->type = TRACE_DAEMON_SIGNAL;
+ if (i_blocking)
+ {
+ msg_sendrecv(iv_queue, msg); // sync message due to 'blocking'.
+ }
+ else
+ {
+ msg_send(iv_queue, msg); // async message request.
+ }
+ }
+ }
+
+}
diff --git a/src/usr/trace/daemonif.H b/src/usr/trace/daemonif.H
new file mode 100644
index 000000000..9e59fe58a
--- /dev/null
+++ b/src/usr/trace/daemonif.H
@@ -0,0 +1,99 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/daemonif.H $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __TRACE_DAEMON_H
+#define __TRACE_DAEMON_H
+
+#include <sys/msg.h>
+#include <mbox/mbox_queues.H>
+
+ // Forward declaration of Daemon class.
+namespace TRACEDAEMON { class Daemon; }
+
+namespace TRACE
+{
+ /** @class DaemonIf
+ *
+ * Defines the interface between the client (front-end) interfaces and
+ * the daemon.
+ *
+ * Since the daemon is in a separate extended module the client won't
+ * know when the daemon process is actually available. This small
+ * interface class is used to provide an abstraction in the base module
+ * for clients.
+ *
+ */
+ class DaemonIf
+ {
+ public:
+ /** Default constructor.
+ *
+ * Initializes class and sets daemon as not-running.
+ */
+ DaemonIf();
+ /** Default destructor.
+ *
+ * Ensures the daemon is shutdown if running.
+ */
+ ~DaemonIf();
+
+ /** Allows the client to signal the daemon that work is ready.
+ *
+ * @param[in] i_blocking - Indicates if this function should
+ * block until the daemon satisfies the
+ * request.
+ */
+ void signal(bool i_blocking = false);
+
+ friend class BufferTest;
+ friend class TRACEDAEMON::Daemon;
+
+ private:
+ /** Queue to send messages to daemon on. */
+ msg_q_t iv_queue;
+ /** Indication if the daemon has already been signalled. */
+ uint16_t iv_signalled;
+ /** State of daemon process. */
+ bool iv_running;
+
+ enum MSG_TYPES
+ {
+ /** Client work is ready to be performed; flush buffers. */
+ TRACE_DAEMON_SIGNAL = MBOX::FIRST_SECURE_MSG | 0,
+ /** Daemon should shutdown. */
+ TRACE_DAEMON_SHUTDOWN = MBOX::FIRST_UNSECURE_MSG | 1,
+ };
+
+ // Since the below functions are only used by the daemon, they
+ // are only implemented in the daemon module.
+
+ /** Mark the daemon as 'running'. */
+ void start();
+ /** Block the daemon until a message is available. */
+ msg_t* wait() { return msg_wait(iv_queue); }
+ /** Clear the client signal. */
+ void clearSignal();
+
+ };
+}
+
+#endif
diff --git a/src/usr/trace/entry.H b/src/usr/trace/entry.H
new file mode 100644
index 000000000..1bd47ce18
--- /dev/null
+++ b/src/usr/trace/entry.H
@@ -0,0 +1,127 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/entry.H $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __TRACE_ENTRY_H
+#define __TRACE_ENTRY_H
+
+/** @file entry.H
+ *
+ * Definition of both the Hostboot-unique "entry" structure and the
+ * fsp-trace common entry structures.
+ */
+
+#include <trace/interface.H>
+
+namespace TRACE
+{
+ /** @struct Entry
+ *
+ * @brief Maintains the data for an entry in the Hostboot trace buffers.
+ *
+ * In order to allow easy traversal of component trace buffers when they
+ * are in a common buffer, this entry maintains a linked-list of entries
+ * within the same buffer.
+ *
+ * Important conventions:
+ * * (comp == NULL) - Entry is "expired" and no longer valid.
+ * * (committed == 0) - Entry is still in the process of being created
+ * by a client.
+ *
+ * If we wished to reduce the size of this structure in the future, to
+ * reduce the memory impact of tracing, we could turn the pointers here
+ * into a "short pointer" which is only 32bits since all Hostboot heap
+ * addresses are under 4GB.
+ */
+ struct Entry
+ {
+ ComponentDesc* comp; //< Component Descriptor for this Entry.
+ Entry* next; //< Linked-list 'next' ptr.
+ Entry* prev; //< Linked-list 'prev' ptr.
+ uint16_t committed; //< Committed status.
+ uint16_t size; //< Size of data portion.
+ char data[0]; //< Start of 'fsp-trace' style structure.
+ };
+
+ //----- Below are structures directly from FSP for fsp-trace ------//
+
+ const uint32_t TRACE_BUF_VERSION = 0x01; // Trace buffer version
+ const uint32_t TRACE_COMP_TRACE = 0x434F; // Component Field Trace - "CO"
+ const uint32_t TRACE_FIELDTRACE = 0x4654; // Field Trace - "FT"
+ const uint32_t TRACE_FIELDBIN = 0x4644; // Binary Field Trace - "FD"
+ const uint32_t TRACE_TIME_REAL = 0; // upper 32 = secs,
+ // lower 32 = microsecs
+ const uint32_t TRACE_BUF_CONT = 2; // Trace buffer is continuous
+ // trace style.
+
+ /*!
+ * @brief Timestamp and thread id for each trace entry.
+ */
+ struct trace_entry_stamp_t
+ {
+ uint32_t tbh; /*!< timestamp upper part */
+ uint32_t tbl; /*!< timestamp lower part */
+ uint32_t tid; /*!< process/thread id */
+ };
+
+ /*
+ * @brief Structure is used by adal app. layer to fill in trace info.
+ */
+ struct trace_entry_head_t
+ {
+ uint16_t length; /*!< size of trace entry */
+ uint16_t tag; /*!< type of entry: xTRACE xDUMP, (un)packed */
+ uint32_t hash; /*!< a value for the (format) string */
+ uint32_t line; /*!< source file line number of trace call */
+ };
+
+ /*
+ * @brief Binary first writes header and time stamp.
+ */
+ struct trace_bin_entry_t {
+ trace_entry_stamp_t stamp;
+ trace_entry_head_t head;
+ char data[0];
+ };
+
+ /*
+ * @brief Structure is put at beginning of all trace buffers
+ */
+ struct trace_buf_head_t {
+ unsigned char ver; /*!< version of this struct (1) */
+ unsigned char hdr_len; /*!< size of this struct in bytes */
+ unsigned char time_flg; /*!< meaning of timestamp entry field */
+ unsigned char endian_flg; /*!< flag for big ('B') or little
+ ('L') endian */
+ char comp[TRAC_COMP_SIZE]; /*!< the buffer name as specified in
+ init call*/
+ uint32_t size; /*!< size of buffer, including this struct*/
+ uint32_t times_wrap; /*!< how often the buffer wrapped */
+ uint32_t next_free; /*!< offset of the byte behind the latest
+ entry*/
+ uint32_t te_count; /*!< Updated each time a trace is done */
+ uint32_t extracted; /*!< Not currently used */
+ };
+
+
+
+}
+#endif
diff --git a/src/usr/trace/interface.C b/src/usr/trace/interface.C
new file mode 100644
index 000000000..659179233
--- /dev/null
+++ b/src/usr/trace/interface.C
@@ -0,0 +1,115 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/interface.C $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+/** @file interface.C
+ * @brief Implementation of the trace interfaces.
+ *
+ * Most of the functions in this file are simply redirections to the
+ * appropriate class/instance that handles this functionality.
+ */
+
+#include <trace/interface.H>
+#include <util/singleton.H>
+#include <stdarg.h>
+#include <limits.h>
+
+#include "compdesc.H"
+#include "service.H"
+
+namespace TRACE
+{
+ TracInit::TracInit(trace_desc_t** o_td,
+ const char * i_comp,
+ const size_t i_size,
+ uint8_t i_bufferType)
+ {
+ initBuffer(o_td, i_comp, i_size, i_bufferType);
+ }
+
+ TracInit::~TracInit() {}
+
+
+
+ void initBuffer(ComponentDesc** o_td,
+ const char* i_comp,
+ size_t i_size,
+ uint8_t i_bufferType)
+ {
+
+ if (i_size == 0)
+ {
+ i_size = KILOBYTE;
+ }
+
+ (*o_td) =
+ Singleton<ComponentList>::instance().getDescriptor(i_comp,
+ i_size,
+ i_bufferType);
+ }
+
+ void trace_adal_write_all(ComponentDesc * io_td,
+ const trace_hash_val i_hash,
+ const char * i_fmt,
+ const uint32_t i_line,
+ const int32_t i_type, ...)
+ {
+ va_list args;
+ va_start(args, i_type);
+
+ Singleton<Service>::instance().writeEntry(io_td, i_hash, i_fmt,
+ i_line, i_type, args);
+
+ va_end(args);
+ }
+
+ void trace_adal_write_bin(ComponentDesc * io_td,
+ const trace_hash_val i_hash,
+ const uint32_t i_line,
+ const void * i_ptr,
+ const uint32_t i_size,
+ const int32_t i_type)
+ {
+ Singleton<Service>::instance().writeBinEntry(io_td, i_hash, i_line,
+ i_ptr, i_size, i_type);
+ }
+
+ size_t getBuffer(const char * i_comp,
+ void * o_data,
+ size_t i_bufferSize )
+ {
+ ComponentDesc* l_comp =
+ Singleton<ComponentList>::instance().getDescriptor(i_comp, 0);
+
+ if (NULL == l_comp)
+ {
+ return 0;
+ }
+ return Singleton<Service>::instance().getBuffer(l_comp,
+ o_data, i_bufferSize);
+ }
+
+ void flushBuffers()
+ {
+ Singleton<Service>::instance().flushBuffers();
+ }
+};
diff --git a/src/usr/trace/makefile b/src/usr/trace/makefile
index fe7cf2d92..38de606aa 100644
--- a/src/usr/trace/makefile
+++ b/src/usr/trace/makefile
@@ -1,30 +1,31 @@
-# IBM_PROLOG_BEGIN_TAG
-# This is an automatically generated prolog.
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
#
-# $Source: src/usr/trace/makefile $
+# $Source: src/usr/trace/makefile $
#
-# IBM CONFIDENTIAL
+# IBM CONFIDENTIAL
#
-# COPYRIGHT International Business Machines Corp. 2011
+# COPYRIGHT International Business Machines Corp. 2011,2012
#
-# p1
+# p1
#
-# Object Code Only (OCO) source materials
-# Licensed Internal Code Source Materials
-# IBM HostBoot Licensed Internal Code
+# Object Code Only (OCO) source materials
+# Licensed Internal Code Source Materials
+# IBM HostBoot Licensed Internal Code
#
-# The source code for this program is not published or other-
-# wise divested of its trade secrets, irrespective of what has
-# been deposited with the U.S. Copyright Office.
+# The source code for this program is not published or otherwise
+# divested of its trade secrets, irrespective of what has been
+# deposited with the U.S. Copyright Office.
#
-# Origin: 30
+# Origin: 30
#
-# IBM_PROLOG_END
+# IBM_PROLOG_END_TAG
ROOTPATH = ../../..
MODULE = trace
-OBJS = trace.o tracedaemon.o assert.o
+OBJS = interface.o service.o compdesc.o buffer.o bufferpage.o daemonif.o \
+ assert.o
-SUBDIRS = test.d
+SUBDIRS = daemon.d test.d
include ${ROOTPATH}/config.mk
diff --git a/src/usr/trace/service.C b/src/usr/trace/service.C
new file mode 100644
index 000000000..6c52efb18
--- /dev/null
+++ b/src/usr/trace/service.C
@@ -0,0 +1,271 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/service.C $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+#include "service.H"
+#include "buffer.H"
+#include "entry.H"
+#include "compdesc.H"
+#include "daemonif.H"
+
+#include <sys/time.h>
+#include <sys/task.h>
+#include <util/align.H>
+#include <string.h>
+#include <util/singleton.H>
+#include <assert.h>
+#include <time.h>
+
+namespace TRACE
+{
+ Service::Service()
+ {
+ iv_daemon = new DaemonIf();
+ iv_buffers[BUFFER_SLOW] = new Buffer(iv_daemon, Buffer::UNLIMITED);
+ iv_buffers[BUFFER_FAST] = new Buffer(iv_daemon);
+ iv_compList = &(Singleton<ComponentList>::instance());
+ }
+
+ Service::~Service()
+ {
+ // No need to destruct the service.
+ assert(0);
+ }
+
+ void Service::writeEntry(ComponentDesc* i_td,
+ trace_hash_val i_hash,
+ const char * i_fmt,
+ uint32_t i_line,
+ int32_t i_type,
+ va_list i_args)
+ {
+ do
+ {
+ // Get the right buffer for this component.
+ Buffer* l_buffer = iv_buffers[i_td->iv_bufferType];
+
+ // Copy the current time.
+ trace_entry_stamp_t l_time;
+ _createTimeStamp(&l_time);
+
+ // Sizes for trace entry.
+ uint32_t l_size = 0;
+ uint32_t l_num_args = 0;
+ uint32_t l_num_words = 0;
+
+ // Maps of arguments to special types.
+ uint64_t l_str_map = 0, l_char_map = 0, l_double_map = 0;
+
+ va_list l_args;
+ va_copy(l_args, i_args);
+
+ // Parse the fmt list to determine the types/sizes of each
+ // argument.
+ while(NULL != (i_fmt = strchr(i_fmt, '%')))
+ {
+ i_fmt++;
+
+ switch (*i_fmt)
+ {
+ case '%':
+ break;
+
+ case 's': // string.
+ l_str_map |= (1 << l_num_args);
+ l_num_args++;
+ l_num_words++;
+ l_size += ALIGN_4(strlen(va_arg(l_args, char*)) + 1);
+ break;
+
+ case 'c': // character.
+ l_char_map |= (1 << l_num_args);
+ l_num_args++;
+ l_num_words++;
+ va_arg(l_args, uint32_t);
+ l_size += sizeof(uint32_t);
+ break;
+
+ case 'e': // doubles.
+ case 'f':
+ case 'g':
+ l_double_map |= (1 << l_num_args);
+ l_num_args++;
+ l_num_words += 2;
+ va_arg(l_args, double);
+ l_size += sizeof(double);
+ break;
+
+ default: // uint64_t-sized argument.
+ l_num_args++;
+ l_num_words += 2;
+ va_arg(l_args, uint64_t);
+ l_size += sizeof(uint64_t);
+ break;
+ }
+ i_fmt++;
+ }
+
+ va_end(l_args);
+
+ // Ensure we don't have too many arguments.
+ if (l_num_args > TRAC_MAX_ARGS)
+ {
+ // Simply reducing the number of arguments and continuing
+ // causes FSP trace to crash. See defect 864438.
+ //l_num_args = TRAC_MAX_ARGS;
+ break;
+ }
+
+ // Claim an entry from the buffer.
+ uint32_t l_realSize = ALIGN_4(sizeof(trace_bin_entry_t) + l_size);
+ Entry* l_entry = l_buffer->claimEntry(i_td, l_realSize);
+ if (NULL == l_entry)
+ {
+ break;
+ }
+
+ // Copy contents into the 'fsp-trace'-style structure.
+ trace_bin_entry_t* l_binEntry =
+ reinterpret_cast<trace_bin_entry_t*>(&l_entry->data[0]);
+
+ l_binEntry->stamp = l_time;
+ l_binEntry->head.length = l_size;
+ l_binEntry->head.tag = TRACE_COMP_TRACE;
+ l_binEntry->head.hash = i_hash;
+ l_binEntry->head.line = i_line;
+
+
+ // Copy arguments into the 'fsp-trace' entry's data section.
+ char* l_dataOut = reinterpret_cast<char*>(&l_binEntry->data[0]);
+ for (size_t i = 0; i < l_num_args; i++)
+ {
+ // String.
+ if (l_str_map & (1 << i))
+ {
+ char* str = va_arg(i_args, char*);
+ uint32_t strSize = strlen(str);
+
+ memcpy(l_dataOut, str, strSize+1);
+ l_dataOut += ALIGN_4(strSize + 1);
+ }
+ // Single character.
+ else if (l_char_map & (1 << i))
+ {
+ *(reinterpret_cast<uint32_t*>(l_dataOut)) =
+ va_arg(i_args, uint32_t);
+ l_dataOut += sizeof(uint32_t);
+ }
+ // Doubles.
+ else if (l_double_map & (1 << i))
+ {
+ *(reinterpret_cast<double*>(l_dataOut)) =
+ va_arg(i_args, double);
+ l_dataOut += sizeof(double);
+ }
+ // All others (as uint64_t's).
+ else
+ {
+ *(reinterpret_cast<uint64_t*>(l_dataOut)) =
+ va_arg(i_args, uint64_t);
+ l_dataOut += sizeof(uint64_t);
+ }
+ }
+
+ // "Commit" entry to buffer.
+ l_buffer->commitEntry(l_entry);
+
+ } while(0);
+ }
+
+ void Service::writeBinEntry(ComponentDesc* i_td,
+ trace_hash_val i_hash,
+ uint32_t i_line,
+ const void* i_ptr,
+ uint32_t i_size,
+ int32_t i_type)
+ {
+ do
+ {
+ // Get the right buffer for this component.
+ Buffer* l_buffer = iv_buffers[i_td->iv_bufferType];
+
+ // Copy the current time.
+ trace_entry_stamp_t l_time;
+ _createTimeStamp(&l_time);
+
+ // Claim an entry from the buffer.
+ uint32_t l_realSize = ALIGN_4(sizeof(trace_bin_entry_t) + i_size);
+ Entry* l_entry = l_buffer->claimEntry(i_td, l_realSize);
+ if (NULL == l_entry)
+ {
+ break;
+ }
+
+ // Copy contents into the 'fsp-trace'-style structure.
+ trace_bin_entry_t* l_binEntry =
+ reinterpret_cast<trace_bin_entry_t*>(&l_entry->data[0]);
+
+ l_binEntry->stamp = l_time;
+ l_binEntry->head.length = i_size;
+ l_binEntry->head.tag = TRACE_FIELDBIN;
+ l_binEntry->head.hash = i_hash;
+ l_binEntry->head.line = i_line;
+
+ // Copy bin-data into the 'fsp-trace' entry's data section.
+ memcpy(&l_binEntry->data[0], i_ptr, i_size);
+
+ // "Commit" entry to buffer.
+ l_buffer->commitEntry(l_entry);
+
+ } while(0);
+ }
+
+ size_t Service::getBuffer(ComponentDesc* i_comp,
+ void * o_data,
+ size_t i_size)
+ {
+ return
+ iv_buffers[i_comp->iv_bufferType]->getTrace(i_comp,o_data,i_size);
+ }
+
+ void Service::flushBuffers()
+ {
+ iv_daemon->signal(true);
+ }
+
+ Service* Service::getGlobalInstance()
+ {
+ return &(Singleton<Service>::instance());
+ }
+
+ void Service::_createTimeStamp(trace_entry_stamp_t *o_entry)
+ {
+ timespec_t curTime;
+
+ clock_gettime(CLOCK_MONOTONIC, &curTime);
+
+ o_entry->tbh = curTime.tv_sec;
+ o_entry->tbl = curTime.tv_nsec;
+ o_entry->tid = task_gettid();
+ }
+
+
+}
diff --git a/src/usr/trace/service.H b/src/usr/trace/service.H
new file mode 100644
index 000000000..2a5218cab
--- /dev/null
+++ b/src/usr/trace/service.H
@@ -0,0 +1,161 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/service.H $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __TRACE_SERVICE_H
+#define __TRACE_SERVICE_H
+
+/** @file service.H
+ *
+ * @brief Facade class for the front-side (client) end of trace.
+ *
+ * For the lock-less trace design, clients have visibility to two entities:
+ * Component-Descriptors and Buffers.
+ *
+ * The Descriptors contain information such as component name, debug on/off
+ * state, and associated buffer type as well as a linked-list of trace
+ * entries associated with the component. Since the trace entries are
+ * maintained as a linked-list, extracting the traces is simply walking
+ * the linked-list and copying data into the extract buffer.
+ *
+ * The Buffers are where new entries go when they are first created. The
+ * buffers allow us to rate-limit entries by segregating components which
+ * can block and those which cannot block. (Anything related to sending
+ * traces down to FSP via mailbox cannot block while adding a new trace)
+ *
+ *
+ * As the buffers start to fill up, a daemon is periodically triggered to
+ * harvest the trace entries and combine them into a single common buffer
+ * within the daemon. As entries are harvested from the front end buffers
+ * they are copied into "continuous trace" buffers and sent to the FSP
+ * (and/or VPO and simics debug scripts).
+ *
+ * The daemon is also responsible for ensuring that components do not
+ * exceed their trace size limit. Since component descriptors contain
+ * a linked list of entries, the daemon can expire entries from the end of
+ * the list until the size limit is no longer exceeded for a component.
+ * Periodically, along with expiring trace entries, the daemon will
+ * coalesce back-end buffer pages to fill holes caused by expired entries.
+ *
+ */
+
+#include <trace/interface.H>
+#include <stdarg.h>
+
+namespace TRACEDAEMON { class Daemon; } // Forward declaration.
+
+namespace TRACE
+{
+ // Forward declarations.
+ class Buffer;
+ class DaemonIf;
+ class ComponentList;
+ class trace_entry_stamp_t;
+
+ /** @class Service
+ *
+ * @brief Front-end interfaces for trace.
+ *
+ * There should be a singleton instance of this class.
+ */
+ class Service
+ {
+ public:
+ /** Default constructor */
+ Service();
+ /** Default destructor */
+ ~Service();
+
+ /** @brief Write a normal entry to a trace buffer.
+ *
+ * @param[in] i_td - Component Descriptor to write to.
+ *
+ * @param[in] i_hash - Hash value.
+ * @param[in] i_fmt - Printf-style format string.
+ * @param[in] i_line - Line number.
+ * @param[in] i_type - TRACE_DEBUG / TRACE_FIELD
+ *
+ * @param[in] i_args - Arguments corresponding to i_fmt.
+ */
+ void writeEntry(ComponentDesc* i_td,
+ trace_hash_val i_hash,
+ const char * i_fmt,
+ uint32_t i_line,
+ int32_t i_type,
+ va_list i_args);
+
+ /** @brief Write a binary entry to a trace buffer.
+ *
+ * @param[in] i_td - Component Descriptor to write to.
+ *
+ * @param[in] i_hash - Hash value.
+ * @param[in] i_line - Line number.
+ * @param[in] i_ptr - Data to write.
+ * @param[in] i_size - Bytes to write.
+ * @param[in] i_type - TRACE_DEBUG / TRACE_FIELD
+ */
+ void writeBinEntry(ComponentDesc* i_td,
+ trace_hash_val i_hash,
+ uint32_t i_line,
+ const void* i_ptr,
+ uint32_t i_size,
+ int32_t i_type);
+
+ /** @brief Extract a component's trace buffer.
+ *
+ * @param[in] i_comp - Component to extract.
+ *
+ * @param[out] o_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
+ * copying into the buffer, the function will calculate the size
+ * of the buffer needed to save all of the data currently in the
+ * component's trace.
+ */
+ size_t getBuffer(ComponentDesc* i_comp,
+ void * o_data,
+ size_t i_size);
+
+ /** @brief Flushes the front-side buffers out to continuous trace.
+ */
+ void flushBuffers();
+
+ friend class TRACEDAEMON::Daemon;
+
+ private:
+ /** Front-size buffers */
+ Buffer* iv_buffers[BUFFER_COUNT]; // slow / fast buffers.
+ /** Interface to signal daemon. */
+ DaemonIf* iv_daemon;
+ /** List of component descriptors. */
+ ComponentList* iv_compList;
+
+ /** Get the singleton instance. */
+ static Service* getGlobalInstance();
+ /** Copy the current time into the timestamp. */
+ void _createTimeStamp(trace_entry_stamp_t* o_entry);
+ };
+}
+
+#endif
diff --git a/src/usr/trace/test/testbuffer.H b/src/usr/trace/test/testbuffer.H
new file mode 100644
index 000000000..d63a24ab3
--- /dev/null
+++ b/src/usr/trace/test/testbuffer.H
@@ -0,0 +1,92 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/test/testbuffer.H $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+#include "../buffer.H"
+#include "../bufferpage.H"
+#include "../compdesc.H"
+#include "../entry.H"
+#include "../daemonif.H"
+
+#include <cxxtest/TestSuite.H>
+#include <limits.h>
+#include <sys/task.h>
+#include <sys/time.h>
+#include <kernel/pagemgr.H>
+
+namespace TRACE
+{
+
+class BufferTest : public CxxTest::TestSuite
+{
+ public:
+ void testClaimEntry()
+ {
+ DaemonIf d;
+ Buffer b(&d, 1);
+
+ tid_t child = task_create(testClaimEntryThread, &b);
+ msg_free(d.wait());
+
+ BufferPage* page = b.claimPages();
+ PageManager::freePage(page);
+
+ task_wait_tid(child, NULL, NULL);
+
+ page = b.claimPages();
+ if (NULL == page)
+ {
+ TS_FAIL("Not enough pages created in trace buffer.\n");
+ }
+ PageManager::freePage(page);
+
+ page = b.claimPages();
+ if (NULL != page)
+ {
+ TS_FAIL("Too many pages created in trace buffer.\n");
+ }
+
+ }
+
+ static void* testClaimEntryThread(void* _buffer)
+ {
+ Buffer* b = reinterpret_cast<Buffer*>(_buffer);
+
+ ComponentList l;
+ ComponentDesc* t = l.getDescriptor("TEST", 2048);
+
+ static const size_t ALLOC_SIZE = 128;
+
+ for(size_t i = 0; i < PAGESIZE/ALLOC_SIZE; i++)
+ {
+ Entry* e = b->claimEntry(t, ALLOC_SIZE - sizeof(Entry));
+ if (e->comp != t)
+ {
+ TS_FAIL("Component ID is not updated in entry.");
+ }
+ }
+
+ return NULL;
+
+ }
+};
+
+}
diff --git a/src/usr/trace/test/testcomplist.H b/src/usr/trace/test/testcomplist.H
new file mode 100644
index 000000000..1bee55cc8
--- /dev/null
+++ b/src/usr/trace/test/testcomplist.H
@@ -0,0 +1,61 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/test/testcomplist.H $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+#include "../compdesc.H"
+
+#include <cxxtest/TestSuite.H>
+
+using namespace TRACE;
+
+class ComponentListTest : public CxxTest::TestSuite
+{
+ public:
+ void testGetDescriptor()
+ {
+ ComponentList l;
+
+ ComponentDesc* t = l.getDescriptor("TEST", 2048);
+
+ if (NULL == t)
+ {
+ TS_FAIL("Component descriptor was NULL.");
+ }
+
+ ComponentDesc* t2 = l.getDescriptor("teST", 2048);
+ if (t2 != t)
+ {
+ TS_FAIL("Component descriptor failed case-insensitive test.");
+ }
+
+ ComponentDesc* t3 = l.getDescriptor("TEST2", 0);
+ if (NULL != t3)
+ {
+ TS_FAIL("Component descriptor failed non-existance test.");
+ }
+
+ t3 = l.getDescriptor("TEST2", 2048);
+ if (t3 == t)
+ {
+ TS_FAIL("Component descriptor failed uniqueness test.");
+ }
+ }
+};
diff --git a/src/usr/trace/test/tracetest.H b/src/usr/trace/test/tracetest.H
deleted file mode 100644
index e574f55c5..000000000
--- a/src/usr/trace/test/tracetest.H
+++ /dev/null
@@ -1,306 +0,0 @@
-// IBM_PROLOG_BEGIN_TAG
-// This is an automatically generated prolog.
-//
-// $Source: src/usr/trace/test/tracetest.H $
-//
-// IBM CONFIDENTIAL
-//
-// COPYRIGHT International Business Machines Corp. 2011
-//
-// p1
-//
-// Object Code Only (OCO) source materials
-// Licensed Internal Code Source Materials
-// IBM HostBoot Licensed Internal Code
-//
-// The source code for this program is not published or other-
-// wise divested of its trade secrets, irrespective of what has
-// been deposited with the U.S. Copyright Office.
-//
-// Origin: 30
-//
-// IBM_PROLOG_END
-#ifndef __TEST_TRACETEST_H
-#define __TEST_TRACETEST_H
-
-/**
- * @file tracetest.H
- *
- * @brief All unit tests for the trace module in host boot.
-*/
-
-#include <cxxtest/TestSuite.H>
-//#include <trace/interface.H>
-#include <tracinterface.H>
-#include <stdio.h>
-
-class TraceTest : public CxxTest::TestSuite
-{
-public:
-
- /**
- * @test Test Component Trace Interfaces
- */
- void testTracComp(void)
- {
- trace_desc_t *g_trac_test = NULL;
- TRAC_INIT_BUFFER(&g_trac_test, "EXAMPLE", 4096);
-
- if(g_trac_test == NULL)
- {
- TS_FAIL("g_trac_test was returned as NULL!");
- }
- else
- {
- // Component trace tests - There is no easy way to validate these
- // are working but we can at least ensure we don't cause host boot
- // to crash when running them.
-
- for(uint32_t i=0;i<100;i++)
- {
- TRACFCOMP(g_trac_test, "Thread ID: %d", task_gettid());
- TRACFCOMP(g_trac_test, "Validate all number types (c,u,X,d): %c %u 0x%X %d",
- 'a',i,i+1,i+2);
-
- TRACFCOMP(g_trac_test, "Validate pointer type (p): %p",
- g_trac_test);
-
- TRACFCOMP(g_trac_test, "64 Bit Value Test - 0x123456789ABCDEF0: 0x%X",
- 0x123456789ABCDEF0);
-
- // Do a debug trace
- TRACDCOMP(g_trac_test,"This is a debug trace");
-
- // Do an strace
- TRACSCOMP(g_trac_test, "STRACE: Testing all number types (c,u,X,d,s): %c %u 0x%X %d %s",
- 'b',i,i+1,i+2,"Hostboot");
-
- // Test formatting
- TRACFCOMP(g_trac_test, "Test width.precision formatting (u,x,X,d): %8u 0x%.06x 0x%16X %01.01d",
- 0xABCD,0x1234,0x123456789ABCDEF0,0x12345678);
-
- TRACFCOMP(g_trac_test, "Test width.precision.length formatting (u,x,X,d): %8hu 0x%.06lx 0x%16LX %01.01lld",
- 0xABCD,0x1234,0x123456789ABCDEF0,0x12345678);
-
- TRACFCOMP(g_trac_test, "Test width.precision.length formatting (u,x,X,i): %8hu 0x%.06lx 0x%16LX %01.01lli",
- 0xABCD,0x1234,0x123456789ABCDEF0,0x12345678AB);
- }
-
- // Be sure a NULL trace descriptor does not cause a failure
- TRACFCOMP(NULL,"This trace should never show up");
-
- }
- }
-
- /**
- * @test Test Binary Trace Interface
- */
- void testTracBinary(void)
- {
- trace_desc_t *g_trac_test = NULL;
- TRAC_INIT_BUFFER(&g_trac_test, "EXAMPLEBIN", 4096);
-
- if(g_trac_test == NULL)
- {
- TS_FAIL("g_trac_test was returned as NULL!");
- }
- else
- {
- // Binary trace tests - There is no easy way to validate these
- // are working but we can at least ensure we don't cause host boot
- // to crash when running them.
- TRACFBIN(g_trac_test,"Binary dump of trace descriptor",
- g_trac_test,sizeof(trace_desc_t));
-
- TRACDBIN(g_trac_test,"Unaligned Debug binary trace of the trace descriptor",
- g_trac_test,9);
-
- // Be sure a NULL trace descriptor does not cause a failure
- TRACFBIN(NULL,"This trace should never show up",
- g_trac_test,sizeof(trace_desc_t));
-
- // Be sure it handles a size of 0
- TRACFBIN(NULL,"This trace should never show up - 0 size",
- g_trac_test,0);
- }
- }
-
- /**
- * @test Test a mix of traces
- */
- void testTracMix(void)
- {
- trace_desc_t *g_trac_test = NULL;
- TRAC_INIT_BUFFER(&g_trac_test, "EXAMPLEMIX", 4096);
-
- if(g_trac_test == NULL)
- {
- TS_FAIL("g_trac_test was returned as NULL!");
- }
- else
- {
- uint32_t l_size = 0;
-
- for(uint32_t i=0;i<100;i++)
- {
-
- TRACFCOMP(g_trac_test, INFO_MRK"Validate all number types (c,u,X,d): %c %u 0x%X %d",
- 'a',i,i+1,i+2);
-
- l_size = i % sizeof(trace_desc_t);
-
- TRACFBIN(g_trac_test,"Unaligned Binary dump of trace descriptor",
- g_trac_test,l_size);
-
- TRACFCOMP(g_trac_test, "64 Bit Value Test - 0x123456789ABCDEF0: 0x%X",
- 0x123456789ABCDEF0);
-
- }
- }
- }
-
- /**
- * @test Test max component name size
- */
- void testTracCompName(void)
- {
- trace_desc_t *g_trac_test = NULL;
- char l_comp[] = "EXAMPLE89ABCDEFGHI";
-
- TRAC_INIT_BUFFER(&g_trac_test, l_comp, 4096);
-
- if(g_trac_test == NULL)
- {
- TS_FAIL("g_trac_test was returned as NULL!");
- }
- else
- {
- TRACFCOMP(g_trac_test, INFO_MRK"Testing max component name");
- }
- }
-
- /**
- * @test Test trace macros
- */
- void testTracMacros(void)
- {
- trace_desc_t *g_trac_test = NULL;
- char l_comp[] = "TEST";
-
- #define __COMP_TD__ g_trac_test
- #define __COMP_NAMESPACE__ "TRACE"
- #define __COMP_CLASS__ "TraceTest"
- #define __COMP_FN__ "testTracMacros"
-
- TRAC_INIT_BUFFER(&g_trac_test, l_comp, 4096);
-
- if(g_trac_test == NULL)
- {
- TS_FAIL("g_trac_test was returned as NULL!");
- }
- else
- {
- TRAC_ENTER("testTracMacros");
- TRAC_ENTER_();
- TRAC_INF("Testing Info Mark");
- TRAC_ERR("Testing Error Mark");
- TRAC_EXIT("testTracMacros");
- TRAC_EXIT_();
-
- DTRAC_ENTER("testTracMacros - Debug Trace");
- DTRAC_ENTER_(" - Debug Trace");
- DTRAC_INF("Testing Debug Info Mark");
- DTRAC_ERR("Testing Debug Error Mark");
- DTRAC_EXIT("testTracMacros - Debug Trace");
- DTRAC_EXIT_(" - Debug Trace");
-
- STRAC_ENTER("testTracMacros - Strace");
- STRAC_ENTER_(" - Strace");
- STRAC_INF("Testing Strace Info Mark");
- STRAC_ERR("Testing Strace Error Mark");
- STRAC_EXIT("testTracMacros - Strace");
- STRAC_EXIT_(" - Strace");
-
- }
-
- #undef __COMP_FN__
- #undef __COMP_CLASS__
- #undef __COMP_NAMESPACE__
- #undef __COMP_TD__
- }
-
- /**
- * @test Test String Trace Interface
- */
- void testTracString(void)
- {
- trace_desc_t *g_trac_test = NULL;
- TRAC_INIT_BUFFER(&g_trac_test, "STRING", 4096);
-
- if(g_trac_test == NULL)
- {
- TS_FAIL("g_trac_test was returned as NULL!");
- }
- else
- {
- TRACFCOMP(g_trac_test,"String at end '%s'", "Last");
- TRACFCOMP(g_trac_test,"%s: String at beginning", "FIRST");
- TRACFCOMP(g_trac_test,"Test '%s' string", "middle");
-
- const char * str = "This is a \tlong string\nwith horizontal tab and newline.";
- TRACFCOMP(g_trac_test,"Testing (c,u,s,X): %c, %u, %s 0x%X", 'b',0x11,str,10);
-
- TRACFCOMP(g_trac_test,"Testing string len 1: %s, %s, %s", "A", "B", "C");
- TRACFCOMP(g_trac_test,"Testing NULL string: %s", "");
-
- TRACFCOMP(g_trac_test,"Testing string alignment: %s %s", "hello", "world");
- TRACFCOMP(g_trac_test,"Testing string alignment: %s %s", "Hostboot", "Software");
- TRACFCOMP(g_trac_test,"Testing string alignment: %s %s", "Hostboot2", "Software3");
-
- TRACFCOMP(g_trac_test,"%s %s %s %s", "Four", "strings", "by", "themselves");
-
- TRACFCOMP(g_trac_test,"Testing special characters: %s",
- "?!@#$%^&*()\"/\'\\<>.,:;");
-
- TRACFCOMP(g_trac_test,"Testing percent: %% %%%d %%%s 100%%", 50, "hello");
-
- TRACFCOMP(g_trac_test, INFO_MRK"Testing all number types (s,c,u,X,d): %s, %c %u 0x%X %d",
- "hello",'a',10,11,12);
- TRACFCOMP(g_trac_test, "Testing all number types (c,u,s,X,d): %c %u %s 0x%X %d",
- 'b',13,"world!",14,15);
- TRACFCOMP(g_trac_test, "Testing all number types (c,u,X,d,s): %c %u 0x%X %d %s",
- 'c',16,17,18,"Hostboot");
- TRACFCOMP(g_trac_test, "Testing all number types (s,c,s,u,s,X): %s %c %s %u %s 0x%X",
- "Astring",'d',"Bstring12",19,"Cstring123",20);
- }
- }
-
- /**
- * @test Test max number of buffers
- */
- void testTracMaxBuffers(void)
- {
- trace_desc_t *g_trac_test = NULL;
- char l_comp[8] = "TRACE";
-
- for (uint32_t i=0; i < 26; i++)
- {
- sprintf (l_comp, "TRACE%d", i);
-
- g_trac_test = NULL;
- TRAC_INIT_BUFFER(&g_trac_test, l_comp, 4096);
-
- if(g_trac_test == NULL)
- {
- TS_FAIL("g_trac_test was returned as NULL!");
- }
- else
- {
- TRACFCOMP(g_trac_test, INFO_MRK"Testing max buffers %u", i);
- }
- }
- }
-};
-
-#endif
-
diff --git a/src/usr/trace/trace.C b/src/usr/trace/trace.C
deleted file mode 100644
index 8ef760533..000000000
--- a/src/usr/trace/trace.C
+++ /dev/null
@@ -1,1555 +0,0 @@
-/* IBM_PROLOG_BEGIN_TAG */
-/* This is an automatically generated prolog. */
-/* */
-/* $Source: src/usr/trace/trace.C $ */
-/* */
-/* IBM CONFIDENTIAL */
-/* */
-/* COPYRIGHT International Business Machines Corp. 2011,2012 */
-/* */
-/* p1 */
-/* */
-/* Object Code Only (OCO) source materials */
-/* Licensed Internal Code Source Materials */
-/* IBM HostBoot Licensed Internal Code */
-/* */
-/* The source code for this program is not published or otherwise */
-/* divested of its trade secrets, irrespective of what has been */
-/* deposited with the U.S. Copyright Office. */
-/* */
-/* Origin: 30 */
-/* */
-/* IBM_PROLOG_END_TAG */
-/**
- * @file trace.C
- *
- * @brief Implementation of class Trace
- */
-
-
-/* TODO
- * - Add support in for debug trace enable/disable
- * - FORMAT_PRINTF support
- * - %s support
- * - Multiple buffer support
- *
- */
-
-/******************************************************************************/
-// Includes
-/******************************************************************************/
-#include <trace/interface.H>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <arch/ppc.H>
-#include <kernel/console.H>
-#include <kernel/pagemgr.H>
-#include <limits.h>
-#include <stdlib.h>
-#include <sys/task.h>
-#include <sys/sync.h>
-#include <string_ext.h>
-#include <util/align.H>
-#include <assert.h>
-
-#include <trace/trace.H>
-#include "tracedaemon.H"
-
-
-/******************************************************************************/
-// Namespace
-/******************************************************************************/
-namespace TRACE
-{
-
-/******************************************************************************/
-// Globals/Constants
-/******************************************************************************/
-
-const uint32_t TRAC_TIME_REAL = 0; // upper 32 = secs, lower 32 = microsecs
-const uint32_t TRAC_TIME_50MHZ = 1;
-const uint32_t TRAC_TIME_200MHZ = 2;
-const uint32_t TRAC_TIME_167MHZ = 3; // 166666667Hz
-
-
-
-
-// WARNING: Changing the size of the trace buffer name string requires a
-// changing OFFSET_BUFFER_ADDRESS in src/build/debug/Hostboot/Trace.pm.
-const uint32_t COMP_NAME_SIZE = 16; // includes NULL terminator, so 15 max
-
-
-// Settings for the default buffer. Name must be upper case.
-const char * const TRAC_DEFAULT_BUFFER_NAME = "DEFAULT";
-const uint64_t TRAC_DEFAULT_BUFFER_SIZE = 0x0800; //2KB
-
-
-// The number of trace buffers.
-// NOTE: This constant should only be changed to an even number for now.
-// WARNING: Changing the count of buffers requires a co-req change
-// in src/build/debug/Hostboot/Trace.pm which has this count hard coded.
-const uint64_t TRAC_MAX_NUM_BUFFERS = 48;
-
-// An array of these structs accounts for all the trace buffers in Hostboot.
-// WARNING: Changing the size of trace_desc_array requires a co-req change
-// in src/build/debug/Hostboot/Trace.pm which has hard-coded the size of
-// this structure.
-typedef struct trace_desc_array
-{
- char comp[COMP_NAME_SIZE]; // the buffer name
- trace_desc_t * td_entry; // pointer to the buffer
-}trace_desc_array_t;
-
-// Global: found in syms file and thus the dump.
-trace_desc_array_t g_desc_array[TRAC_MAX_NUM_BUFFERS];
-
-
-// Set up a structure to hold information about the mixed-trace
-// or continuous-trace buffer, aka tracBINARY.
-
-// WARNING: Changes to this structure will require co-req changes to
-// src/build/debug/simics-debug-framework.py which contains the simics
-// hap handler for extracting this buffer.
-struct mixed_trace_info
-{
- char * pBuffer;
- uint64_t cbUsed;
- uint32_t TriggerActive;
- uint32_t LostTraceCount;
-};
-typedef struct mixed_trace_info mixed_trace_info_t;
-const uint64_t TRAC_BINARY_SIZE = 4096;
-mixed_trace_info_t g_tracBinaryInfo[2];
-
-struct vpo_con_trigger_t
-{
- volatile uint64_t trig; // bit0 = trig signalling bit1:63 = trace buff addr
- uint32_t len; // length of trace buffer with valid trace data.
- uint32_t seq;
-};
-
-struct vpo_cont_support_t
-{
- vpo_con_trigger_t triggers[2];
- uint64_t enable; // VPO script sets it to 2
- // SIMICS hap handler sets it to 0
- // Compiler sets it to 1 for Mbox
-};
-
-// This structure is monitored by VPO script. The enable variable is set
-// at compile time to 1. The VPO script set the enable variable at the
-// start to enable the continuous trace support for VPO. It then montiors the
-// trigger active bit of each buffer and take action.
-vpo_cont_support_t g_cont_trace_trigger_info = { { {0,0,0}, {0,0,1} }, 1 };
-
-const uint64_t TRIGGER_ACTIVE_BIT = 0x8000000000000000;
-
-/******************************************************************************/
-// TracInit::TracInit()
-/******************************************************************************/
-TracInit::TracInit(trace_desc_t **o_td, const char *i_comp,const size_t i_size)
-{
- TRAC_INIT_BUFFER(o_td,i_comp,i_size);
-}
-
-/******************************************************************************/
-// TracInit::~TracInit()
-/******************************************************************************/
-TracInit::~TracInit()
-{
-}
-
-
-/******************************************************************************/
-// Trace::getTheInstance
-/******************************************************************************/
-Trace& Trace::getTheInstance()
-{
- return Singleton<Trace>::instance();
-}
-
-/******************************************************************************/
-// Trace::Trace
-/******************************************************************************/
-Trace::Trace()
-{
- mutex_init(&iv_trac_mutex);
-
- // compiler inits global vars to zero
- // memset(g_desc_array, 0, sizeof(g_desc_array));
-
- // fsp-trace convention expects a 2 in the first byte of tracBINARY
- for (size_t i = 0; i < 2; i++)
- {
- g_tracBinaryInfo[i].pBuffer =
- static_cast<char*>(malloc(TRAC_BINARY_SIZE));
- g_tracBinaryInfo[i].pBuffer[0] = 2;
- g_tracBinaryInfo[i].cbUsed = 1;
- g_tracBinaryInfo[i].TriggerActive = 0;
- g_tracBinaryInfo[i].LostTraceCount = 0;
- g_cont_trace_trigger_info.triggers[i].trig =
- reinterpret_cast<uint64_t>(g_tracBinaryInfo[i].pBuffer);
- }
-
- // if this code is running under simics, call the hap handler to set
- // g_cont_trace_trigger_info.enable to 0. Otherwise, this will be noop
- MAGIC_INSTRUCTION(MAGIC_CONTINUOUS_TRACE);
-
- // tracBINARY buffer appending is always on.
- // TODO figure a way to control continuous trace on/off, perhaps
- // unregister the hap handler for it.
- iv_ContinuousTrace = 1;
-
- // select buffer0 initially
- iv_CurBuf = 0;
- // initialize seq number
- iv_seqNum = 0;
-
- // Create the daemon.
- iv_daemon = new TraceDaemon();
-}
-
-/******************************************************************************/
-// Trace::~Trace
-/******************************************************************************/
-Trace::~Trace()
-{
- // Delete the daemon.
- delete iv_daemon;
-}
-
-
-/******************************************************************************/
-// trace_adal_init_buffer
-/******************************************************************************/
-void Trace::initBuffer( trace_desc_t **o_td,
- const char* i_comp,
- size_t i_size )
-{
- /*------------------------------------------------------------------------*/
- /* Local Variables */
- /*------------------------------------------------------------------------*/
- unsigned int i = 0;
- char l_comp[COMP_NAME_SIZE] = {'\0'};
-
- /*------------------------------------------------------------------------*/
- /* Code */
- /*------------------------------------------------------------------------*/
-
-
- // Limit buffer sizes to 2KB
- if( i_size > TRAC_DEFAULT_BUFFER_SIZE )
- {
- i_size = TRAC_DEFAULT_BUFFER_SIZE;
- }
-
- // Limit component name to 15 characters.
- if (strlen(i_comp) > (COMP_NAME_SIZE -1))
- {
- memcpy(l_comp, i_comp, COMP_NAME_SIZE - 1);
- }
- else
- {
- strcpy(l_comp, i_comp);
- }
-
- // Store buffer name internally in upper case
- strupr(l_comp);
-
- // The page containing the trace-descriptor destination might not be
- // loaded yet, so we write to it outside of the mutex to force a page
- // fault to bring the page in. If we don't do this, we can end up with
- // a dead-lock where this code is blocked due to a page-fault while
- // holding the trace mutex, which in turn blocks the code that handles
- // page faults.
- *o_td = NULL;
-
- // CRITICAL REGION START
- mutex_lock(&iv_trac_mutex);
-
- // Search through the descriptor array for the first unallocated buffer.
- // The last buffer is the reserved default buffer for any component
- // which didn't get its own buffer.
- for (i = 0; i < (TRAC_MAX_NUM_BUFFERS - 1); i++)
- {
- if( 0 == strcmp(l_comp, g_desc_array[i].comp))
- {
- // Buffer is already allocated for the given buffer name.
- // Return the pointer to the buffer.
- *o_td = g_desc_array[i].td_entry;
- break;
- }
- else if ( '\0' == g_desc_array[i].comp[0] )
- {
- // Found an unallocated buffer; use this one.
- // Set the component name for the buffer
- strcpy(g_desc_array[i].comp, l_comp);
-
- // Allocate memory for the trace buffer.
- *o_td = g_desc_array[i].td_entry =
- reinterpret_cast<trace_desc_t *>(malloc(i_size));
-
- // Initialize the trace buffer.
- initValuesBuffer( g_desc_array[i].td_entry,
- g_desc_array[i].comp,
- i_size );
-
- break;
- }
- }
-
-
- if ((TRAC_MAX_NUM_BUFFERS - 1) == i)
- {
- // We're out of buffers to allocate.
- // Use the default buffer reserved for everyone else.
- // Initialize only once
- if ( '\0' == g_desc_array[i].comp[0] )
- {
- // Set the component name for the buffer
- strcpy(g_desc_array[i].comp, TRAC_DEFAULT_BUFFER_NAME);
-
- // Allocate memory for buffer
- g_desc_array[i].td_entry =
- reinterpret_cast<trace_desc_t *>(malloc(TRAC_DEFAULT_BUFFER_SIZE));
-
- // Initialize the buffer header
- initValuesBuffer(g_desc_array[i].td_entry,
- g_desc_array[i].comp,
- TRAC_DEFAULT_BUFFER_SIZE);
- }
-
- // Return the default buffer
- *o_td = g_desc_array[i].td_entry;
- }
-
- mutex_unlock(&iv_trac_mutex);
- // CRITICAL REGION END
-
- return;
-}
-
-/******************************************************************************/
-// initValuesBuffer
-/******************************************************************************/
-void Trace::initValuesBuffer( trace_desc_t *o_buf,
- const char *i_comp,
- size_t i_size )
-{
- // Initialize it to all 0's
- memset(o_buf,0,i_size);
-
- o_buf->ver = TRACE_BUF_VERSION;
- o_buf->hdr_len = sizeof(trace_buf_head_t);
- o_buf->time_flg = TRAC_TIME_REAL;
- o_buf->endian_flg = 'B'; // Big Endian
- strcpy(o_buf->comp,i_comp);
- o_buf->size = i_size;
- o_buf->times_wrap = 0;
- o_buf->next_free = sizeof(trace_buf_head_t);
-
- return;
-}
-
-/******************************************************************************/
-// ManageContTraceBuffers
-// This function manages the usage of the two ping-pong buffers for handling
-// the continuous trace support.
-//
-// 1) Under VPO/VBU (g_cont_trace_trigger_info.enable = 2)
-// The handshake between Hostboot code and VPO/VBU script is shown belows
-// _______________________
-// Trigger_Avtive ____/ \__________
-// _________________________
-// ScomReg_Active _______/ \______
-//
-// Hostboot code (this function) sets Trigger_Active, then ScomReg_Active,
-// VPO/VBU script detects ScomReg_Active active, off-load the trigger buffer,
-// and clears Trigger_Active. Hostboot code detects a trigger-state buffer
-// with Trigger_Active cleared, reset ScomReg_Active. Two-level trigger is
-// desired. The ScomReg trigger allows VPO script to sample at no expense
-// of simclocks, thus avoiding spending extra simclocks associated with the
-// flushing of L2/L3 to read the memory trigger.
-//
-// 2) Under Simics with hap handler (g_cont_trace_trigger_info.enable = 0)
-// The handshake between Hostboot code and the hap handler is shown belows
-// _______________________
-// Trigger_Avtive ____/ \__________
-//
-// Hostboot code (this function) sets Trigger_Active, then invokes the hap
-// handler. The hap handler off-loads the trigger buffer, and clears the
-// Trigger_Active.
-//
-// 3) Under Simics/HW with FSP mbox (g_cont_trace_trigger_info.enable = 1)
-// _______________________
-// Trigger_Avtive ____/ \__________
-//
-// Hostboot code (this function) sets Trigger_Active, then schedule a thread
-// to use mbox DMA MSG to off-load the trigger buffer to FSP, and clears the
-// Trigger_Active.
-//
-/******************************************************************************/
-void Trace::ManageContTraceBuffers(uint64_t i_cbRequired)
-{
- uint8_t l_AltBuf = (iv_CurBuf + 1) % 2;
- bool needScomReset = false;
-
- // Reset TriggerActive if the buffer has been offloaded by VPO
- // script when running under VBU Awan environment
- for (size_t i = 0; (g_cont_trace_trigger_info.enable > 1) && (i < 2); i++)
- {
- if ((g_tracBinaryInfo[i].TriggerActive != 0) &&
- (!(g_cont_trace_trigger_info.triggers[i].trig &
- TRIGGER_ACTIVE_BIT)))
- {
- g_tracBinaryInfo[i].TriggerActive = 0;
- needScomReset = true;
- }
- }
-
- if (needScomReset)
- {
- msg_t* l_msg = msg_allocate();
- l_msg->type = TraceDaemon::UPDATE_SCRATCH_REG;
- l_msg->data[0] = 0;
- msg_send(iv_daemon->iv_msgQ, l_msg);
- }
-
- // we should never have the current buffer in the trigger state
- assert (g_tracBinaryInfo[iv_CurBuf].TriggerActive == 0);
-
- // current buffer is not in trigger state
- // and adding this trace will exceed the size
- if ((g_tracBinaryInfo[iv_CurBuf].cbUsed + i_cbRequired)
- > TRAC_BINARY_SIZE)
- {
- // current buffer entering trigger state
- g_tracBinaryInfo[iv_CurBuf].TriggerActive = 1;
-
- if (g_cont_trace_trigger_info.enable > 1)
- {
- if (g_tracBinaryInfo[l_AltBuf].TriggerActive == 1)
- {
- // If the alternate buffer's trigger is active, wait for a
- // chance to get offloaded before it is reused.
- uint64_t l_wait = 0x100000;
- while (g_cont_trace_trigger_info.triggers[l_AltBuf].trig &
- TRIGGER_ACTIVE_BIT)
- {
- if (--l_wait == 0)
- {
- break;
- }
- }
- // If alternate buffer has been offloaded, exit trigger state.
- if (l_wait != 0)
- {
- g_tracBinaryInfo[l_AltBuf].TriggerActive = 0;
- }
- }
-
- g_cont_trace_trigger_info.triggers[iv_CurBuf].seq = iv_seqNum++;
- g_cont_trace_trigger_info.triggers[l_AltBuf].seq = iv_seqNum;
- // Turn on the current buffer's trigger
- g_cont_trace_trigger_info.triggers[iv_CurBuf].trig |=
- TRIGGER_ACTIVE_BIT;
-
- msg_t* l_msg = msg_allocate();
- l_msg->type = TraceDaemon::UPDATE_SCRATCH_REG;
- l_msg->data[0] = 0x13579BDF00000000;
- l_msg->data[0] += (iv_seqNum * 0x100000000);
- msg_send(iv_daemon->iv_msgQ, l_msg);
- }
-
- // If the alternate buffer is in trigger state, move it out of
- // the trigger state and keep track of lost trace count.
- if (g_tracBinaryInfo[l_AltBuf].TriggerActive == 1)
- {
- g_tracBinaryInfo[l_AltBuf].LostTraceCount++;
- g_tracBinaryInfo[l_AltBuf].TriggerActive = 0;
- }
- // Now switching to alternate buffer and reset the usage count
- uint8_t l_cur = iv_CurBuf;
- uint64_t l_len = g_tracBinaryInfo[l_cur].cbUsed;
- iv_CurBuf = l_AltBuf;
- g_tracBinaryInfo[iv_CurBuf].cbUsed = 1;
-
- // For FSP mbox method.
- if (g_cont_trace_trigger_info.enable == 1)
- {
- msg_t* l_msg = msg_allocate();
- l_msg->type = TraceDaemon::SEND_TRACE_BUFFER;
- l_msg->data[1] = TRAC_BINARY_SIZE;
- l_msg->extra_data = malloc(TRAC_BINARY_SIZE);
- memcpy( l_msg->extra_data, g_tracBinaryInfo[l_cur].pBuffer, l_len );
- msg_send(iv_daemon->iv_msgQ, l_msg);
- g_tracBinaryInfo[l_cur].TriggerActive = 0;
- }
-
- MAGIC_INSTRUCTION(MAGIC_CONTINUOUS_TRACE);
- }
-}
-
-
-/******************************************************************************/
-// trace_adal_write_all
-/******************************************************************************/
-void Trace::trace_adal_write_all(trace_desc_t *io_td,
- const trace_hash_val i_hash,
- const char * i_fmt,
- const uint32_t i_line,
- const int32_t i_type, ...)
-{
- va_list args;
- va_start(args, i_type);
-
- getTheInstance()._trace_adal_write_all(io_td,
- i_hash,
- i_fmt,
- i_line,
- i_type, args);
-
- va_end(args);
-}
-
-/******************************************************************************/
-// trace_adal_write_all
-/******************************************************************************/
-void Trace::_trace_adal_write_all(trace_desc_t *io_td,
- const trace_hash_val i_hash,
- const char * i_fmt,
- const uint32_t i_line,
- const int32_t i_type, va_list i_args)
-{
- /*------------------------------------------------------------------------*/
- /* Local Variables */
- /*------------------------------------------------------------------------*/
- uint32_t l_entry_size = 0;
- uint32_t l_data_size= 0;
- //trace_entire_entry_t l_entry;
- trace_bin_entry_t l_entry;
- uint64_t l_str_map = 0;
- uint64_t l_char_map = 0;
- uint64_t l_double_map = 0;
-
-
- /*------------------------------------------------------------------------*/
- /* Code */
- /*------------------------------------------------------------------------*/
-
- uint32_t num_args = 0;
- uint32_t num_4byte_args = 0; //fsp-trace counts 8-byte args as 2 4-byte args
- const char* _fmt = i_fmt;
-
- // Save a copy of input args because calling
- // va_arg() on a va_list is a one-shot.
- va_list l_args;
- va_copy (l_args, i_args);
-
-
- // Sum the sizes of the items in i_args in order to know how big to
- // allocate the entry.
-
- for (size_t i = 0; i <= strlen(_fmt); i++)
- {
- if ('%' == _fmt[i])
- {
- i++;
-
- if ('%' == _fmt[i])
- {
- continue;
- }
- else if ('s' == _fmt[i])
- {
- // Set flag to indicate argument is a string
- l_str_map = l_str_map | (1 << num_args);
-
- // String counts as one 4-byte arg
- num_args++;
- num_4byte_args++;
-
- char * l_str = va_arg(i_args, char *);
- size_t l_strLen = strlen(l_str);
-
- // Add to total size of number of arguments we're tracing
- // and account for word alignment
- l_data_size += l_strLen + 1;
- l_data_size = ALIGN_4(l_data_size);
-
- //printk("Trace: STRING %s: strlen %d num_args %d l_data_size %d\n",
- // l_str, static_cast<uint32_t>(l_strLen),
- // num_args, l_data_size);
- //printk("Trace: l_str_map 0x%16llX\n",
- // static_cast<long long>(l_str_map));
- }
- else if ('c' == _fmt[i])
- {
- // Set flag to indicate argument is a char
- l_char_map = l_char_map | (1 << num_args);
-
- // Increment arg counts
- num_args++;
- num_4byte_args++;
-
- // Retrieve the argument to increment to next one
- uint32_t l_tmpData = va_arg(i_args, uint32_t);
-
- // Add to total size; data is word aligned
- l_data_size += sizeof(l_tmpData);
- }
- else if (('e' == _fmt[i]) || ('f' == _fmt[i]) || ('g' == _fmt[i]))
- {
- // Set flag to indicate argument is a double
- l_double_map = l_double_map | (1 << num_args);
-
- // Numbers count as two 4-byte arg
- num_args++;
- num_4byte_args += 2;
-
- // Retrieve the argument to increment to next one
- double l_tmpData = va_arg(i_args,double);
-
- // Add to total size; data is word aligned
- l_data_size += sizeof(l_tmpData);
- }
- else
- {
- // Numbers count as two 4-byte arg
- num_args++;
- num_4byte_args += 2;
-
- // Retrieve the argument to increment to next one
- uint64_t l_tmpData = va_arg(i_args, uint64_t);
-
- // Add to total size; data is word aligned
- l_data_size += sizeof(l_tmpData);
- }
- }
- }
-
-
- if((num_4byte_args <= TRAC_MAX_ARGS) && (io_td != NULL))
- {
- // Fill in the entry structure
- l_entry.stamp.tid = static_cast<uint32_t>(task_gettid());
-
- // Length is equal to size of data
- l_entry.head.length = l_data_size;
- //l_entry.head.tag = TRACE_FIELDTRACE;
- l_entry.head.tag = TRACE_COMP_TRACE;
- l_entry.head.hash = i_hash;
- l_entry.head.line = i_line;
-
-
- // Calculate total space needed for the entry, which is a
- // combination of the data size from above, the entry
- // headers, and an overall length field.
- l_entry_size = l_data_size +
- sizeof(trace_entry_stamp_t) +
- sizeof(trace_entry_head_t) +
- // Allow for a uint32 at the end of the trace entry
- // so parsers may walk the trace buffer backwards
- sizeof(uint32_t);
-
- // Round up the size to the next word boundary
- l_entry_size = ALIGN_4(l_entry_size);
-
- // Allocate buffer for the arguments we're tracing
- void * l_buffer = NULL;
- if (l_data_size)
- {
- l_buffer = malloc(l_data_size);
- memset(l_buffer, 0, l_data_size);
- }
- char * l_ptr = static_cast<char *> (l_buffer);
-
- // Now copy the arguments to the buffer.
-
-
- for (size_t i = 0; i < num_args; i++)
- {
- uint32_t l_strLen = 0;
-
- if (l_str_map & (1 << i))
- {
- // Save string to buffer
- strcpy(l_ptr, va_arg(l_args, char *));
-
- //printk("Trace: Saved String %s Arg[%d]\n", l_ptr, static_cast<uint32_t>(i));
-
- // Length = string length + NULL termination
- l_strLen += (strlen(l_ptr) + 1);
-
- // Increment pointer to next word alignment
- l_ptr += l_strLen;
- l_ptr = reinterpret_cast<char *>(
- ALIGN_4(reinterpret_cast<uint64_t>(l_ptr)) );
-
- //printk("Trace::trace_adal_write_all - l_buffer %p l_ptr %p l_strLen %d\n",
- // l_buffer, l_ptr, l_strLen);
- //printk("Trace::trace_adal_write_all - num_args %d l_data_size %d l_entry_size %d\n",
- // num_args, l_data_size, l_entry_size);
- }
- else if (l_char_map & (1 << i))
- {
- // Save char to buffer & increment pointer (no need to align)
- *(reinterpret_cast<uint32_t *>(l_ptr)) = va_arg(l_args, uint32_t);
- l_ptr += sizeof(uint32_t);
-
- }
- else if (l_double_map & (1 << i))
- {
- // Save number to buffer & increment pointer (no need to align)
- *(reinterpret_cast<double *>(l_ptr)) = va_arg(l_args, double);
-
- l_ptr += sizeof(double);
- }
- else
- {
- // Save number to buffer & increment pointer (no need to align)
- *(reinterpret_cast<uint64_t *>(l_ptr)) = va_arg(l_args, uint64_t);
- l_ptr += sizeof(uint64_t);
- }
- }
-
- va_end(l_args);
-
- // Write entry to the trace buffer.
-
- // CRITICAL REGION START
- mutex_lock(&iv_trac_mutex);
-
- // time stamp the entry with time-base register
- convertTime(&l_entry.stamp);
-
- // Update the entry count
- io_td->te_count++;
-
- // First write the header
- writeData(io_td,
- static_cast<void *>(&l_entry),
- sizeof(l_entry));
-
- // Now write the actual data
- if (l_data_size)
- {
- writeData(io_td,
- l_buffer,
- l_data_size);
- }
-
- // Now write the size at the end
- // Note that fsp-trace assumes this to be a 32 bit long word
- writeData(io_td,
- static_cast<void *>(&l_entry_size),
- sizeof(l_entry_size));
-
-
-
- // Write to the combined trace buffer, a stream of traces.
- while (iv_ContinuousTrace)
- {
- // This entry requires this many bytes to fit.
- uint64_t l_cbCompName = 1 + strlen( io_td->comp );
- uint64_t l_cbRequired = l_cbCompName + sizeof(l_entry) +
- l_data_size;
-
- if (l_cbRequired > TRAC_BINARY_SIZE)
- {
- // caller is logging more binary data than the
- // maximum size of the current tracBinary buffer.
- // TODO need to increase the buffer size, or else
- // document its limits.
- break;
- }
-
- ManageContTraceBuffers(l_cbRequired);
-
- // Copy the entry piecemeal to the destination.
- char * l_pchDest = g_tracBinaryInfo[iv_CurBuf].pBuffer +
- g_tracBinaryInfo[iv_CurBuf].cbUsed;
-
- // component name and its trailing nil byte
- strcpy( l_pchDest, io_td->comp );
- l_pchDest += l_cbCompName;
-
- // trace entry
- memcpy( l_pchDest, &l_entry, sizeof(l_entry));
- l_pchDest += sizeof(l_entry);
-
- // trace entry data
- memcpy( l_pchDest, l_buffer, l_data_size );
-
- // adjust for next time
- g_tracBinaryInfo[iv_CurBuf].cbUsed += l_cbRequired;
-
- // maintain the buffer's actually used bytes for VPO script
- if (g_cont_trace_trigger_info.enable > 1)
- {
- g_cont_trace_trigger_info.triggers[iv_CurBuf].len =
- g_tracBinaryInfo[iv_CurBuf].cbUsed;
- }
-
- // break from while() which was used much like an if()
- break;
- }
-
-
- mutex_unlock(&iv_trac_mutex);
- // CRITICAL REGION END
-
- // Free allocated memory
- free(l_buffer);
- }
-
- return;
-}
-
-/******************************************************************************/
-// trace_adal_write_bin
-/******************************************************************************/
-void Trace::trace_adal_write_bin(trace_desc_t *io_td,const trace_hash_val i_hash,
- const uint32_t i_line,
- const void *i_ptr,
- const uint32_t i_size,
- const int32_t type)
-{
- getTheInstance()._trace_adal_write_bin(io_td, i_hash,
- i_line,
- i_ptr,
- i_size,
- type);
-}
-
-/******************************************************************************/
-// trace_adal_write_bin
-/******************************************************************************/
-void Trace::_trace_adal_write_bin(trace_desc_t *io_td,const trace_hash_val i_hash,
- const uint32_t i_line,
- const void *i_ptr,
- const uint32_t i_size,
- const int32_t type)
-{
- /*------------------------------------------------------------------------*/
- /* Local Variables */
- /*------------------------------------------------------------------------*/
- uint32_t l_entry_size = 0;
- trace_bin_entry_t l_entry;
-
- /*---------------------------------------------------------------------- --*/
- /* Code */
- /*------------------------------------------------------------------------*/
- do
- {
-
- if((io_td == NULL) || (i_ptr == NULL) || (i_size == 0))
- {
- break;
- }
-
- // Calculate total space needed
- l_entry_size = sizeof(trace_entry_stamp_t);
- l_entry_size += sizeof(trace_entry_head_t);
-
- // We always add the size of the entry at the end of the trace entry
- // so the parsing tool can easily walk the trace buffer stack so we
- // need to add that on to total size
- l_entry_size += sizeof(uint32_t);
-
- // Now add on size for actual size of the binary data
- l_entry_size += i_size;
-
- // Word align the entry
- l_entry_size = ALIGN_4(l_entry_size);
-
- // Fill in the entry structure
- l_entry.stamp.tid = static_cast<uint32_t>(task_gettid());
-
- // Length is equal to size of data
- l_entry.head.length = i_size;
- l_entry.head.tag = TRACE_FIELDBIN;
- l_entry.head.hash = i_hash;
- l_entry.head.line = i_line;
-
- // We now have total size and need to reserve a part of the trace
- // buffer for this
-
- // CRITICAL REGION START
- mutex_lock(&iv_trac_mutex);
-
-
- // time stamp the entry with time-base register
- convertTime(&l_entry.stamp);
-
- // Increment trace counter
- io_td->te_count++;
-
- // First write the header
- writeData(io_td,
- static_cast<void *>(&l_entry),
- sizeof(l_entry));
-
- // Now write the actual binary data
- writeData(io_td,
- i_ptr,
- i_size);
-
- // Now write the size at the end
- writeData(io_td,
- static_cast<void *>(&l_entry_size),
- sizeof(l_entry_size));
-
- // Write to the combined trace buffer, a stream of traces.
- // A while() here affords use of break to break out on
- // an error condition.
- while( iv_ContinuousTrace )
- {
- // This entry requires this many bytes to fit.
- uint64_t l_cbCompName = 1 + strlen( io_td->comp );
- uint64_t l_cbRequired = l_cbCompName + sizeof( l_entry ) + i_size;
-
- if( l_cbRequired > TRAC_BINARY_SIZE )
- {
- // caller is logging more binary data than the
- // maximum size of the current tracBinary buffer.
- // TODO need to increase the buffer size, or else
- // document its limits.
- break;
- }
-
- ManageContTraceBuffers(l_cbRequired);
-
- // Copy the entry piecemeal to the destination.
- char * l_pchDest = g_tracBinaryInfo[iv_CurBuf].pBuffer +
- g_tracBinaryInfo[iv_CurBuf].cbUsed;
-
- // component name and its trailing nil byte
- strcpy( l_pchDest, io_td->comp );
- l_pchDest += l_cbCompName;
-
- // trace entry
- memcpy( l_pchDest, &l_entry, sizeof(l_entry));
- l_pchDest += sizeof(l_entry);
-
- // trace entry data
- memcpy( l_pchDest, i_ptr, i_size );
-
- // adjust for next time
- g_tracBinaryInfo[iv_CurBuf].cbUsed += l_cbRequired;
-
- // maintain the buffer's actually used bytes for VPO script
- if (g_cont_trace_trigger_info.enable > 1)
- {
- g_cont_trace_trigger_info.triggers[iv_CurBuf].len =
- g_tracBinaryInfo[iv_CurBuf].cbUsed;
- }
-
- // break from while() which was used much like an if()
- break;
- }
-
-
- // CRITICAL REGION END
- mutex_unlock(&iv_trac_mutex);
-
- }while(0);
-
- return;
-}
-
-/******************************************************************************/
-// writeData
-/******************************************************************************/
-void Trace::writeData(trace_desc_t *io_td,
- const void *i_ptr,
- const uint32_t i_size)
-{
- /*------------------------------------------------------------------------*/
- /* Local Variables */
- /*------------------------------------------------------------------------*/
- uint32_t l_total_size = i_size;
- void *l_buf_ptr = NULL;
- uint32_t l_offset = 0;
- uint64_t l_align = 0;
-
- /*------------------------------------------------------------------------*/
- /* Code */
- /*------------------------------------------------------------------------*/
-
- do
- {
-
- if(i_size > (io_td->size-sizeof(trace_buf_head_t)))
- {
- // unreasonable size, caller is asking to write something
- // that is very nearly the size of the entire buffer
- break;
- }
-
-
- if((io_td->next_free + l_total_size) > io_td->size)
- {
- // Does not fit entirely, write what fits, and wrap the buffer.
-
- // Get the pointer to current location in buffer
- l_buf_ptr = reinterpret_cast<char *>(io_td) + io_td->next_free;
- // Figure out the alignment
- l_align = ALIGN_4(reinterpret_cast<uint64_t>(l_buf_ptr)) -
- reinterpret_cast<uint64_t>(l_buf_ptr);
- // Add on the alignment
- l_buf_ptr = reinterpret_cast<void *>(reinterpret_cast<uint64_t>
- (l_buf_ptr) + l_align);
- // Ensure offset accounts for the alignment
- l_offset = io_td->size-io_td->next_free - l_align;
- // Copy in what fits
- memcpy(l_buf_ptr,i_ptr,static_cast<size_t>(l_offset));
-
- l_total_size -= l_offset;
-
- // Now adjust the main header of buffer
- io_td->times_wrap++;
- io_td->next_free = io_td->hdr_len;
- }
-
- // Get the pointer to current location in buffer
- l_buf_ptr = reinterpret_cast<char *>(io_td) + io_td->next_free;
- // Figure out the alignment
- l_align = ALIGN_4(reinterpret_cast<uint64_t>(l_buf_ptr)) -
- reinterpret_cast<uint64_t>(l_buf_ptr);
- // Add on the alignment
- l_buf_ptr = reinterpret_cast<void *>(reinterpret_cast<uint64_t>
- (l_buf_ptr) + l_align);
-
- memcpy(l_buf_ptr,reinterpret_cast<const char *>(i_ptr) + l_offset,
- l_total_size);
-
- // Make sure size is correct for word alignment
- // Note that this works with binary trace because only the binary data
- // has the potential to be un-word aligned. If two parts of the binary
- // trace had this problem then this code would not work.
- // Note that fsp-trace will ignore garbage data in the unaligned areas.
- l_total_size = ALIGN_4(l_total_size);
- io_td->next_free += l_total_size;
-
- }while(0);
-
- return;
-
-}
-
-/******************************************************************************/
-// convertTime
-/******************************************************************************/
-void Trace::convertTime(trace_entry_stamp_t *o_entry)
-{
- /*------------------------------------------------------------------------*/
- /* Local Variables */
- /*------------------------------------------------------------------------*/
-
- /*------------------------------------------------------------------------*/
- /* Code */
- /*------------------------------------------------------------------------*/
-
- // TODO - Future Sprint will collect proc frequency and correctly
- // calculate this.
- uint64_t l_time = getTB();
- //o_entry->tbh = l_time && 0xFFFFFFFF00000000;
- //o_entry->tbl = l_time && 0x00000000FFFFFFFF;
-
- // This basically supports SIMICS, but will look weird on real hw
- o_entry->tbh = (l_time / 512000000);
- o_entry->tbl = ((l_time - (o_entry->tbh * 512000000)) / 512);
-
-}
-
-
-
-
-/******************************************************************************/
-// findTdByName
-/******************************************************************************/
-trace_desc_t * Trace::findTdByName(const char *i_pName)
-{
- trace_desc_t * l_td = NULL;
- char l_comp[COMP_NAME_SIZE];
-
-
- uint64_t i = strlen(i_pName);
- if ( i )
- {
- if ( i > (COMP_NAME_SIZE -1))
- {
- // Limit component name.
- memcpy(l_comp, i_pName, COMP_NAME_SIZE - 1);
- l_comp[ COMP_NAME_SIZE - 1 ] = 0;
- }
- else
- {
- strcpy( l_comp, i_pName );
- }
-
- // Use upper case.
- strupr( l_comp );
-
- // Lock critical section to access g_desc_array
- mutex_lock(&iv_trac_mutex);
-
- // Search the buffers array
- for(i=0;
- (i < (TRAC_MAX_NUM_BUFFERS - 1)) &&
- (strlen(g_desc_array[i].comp) != 0);
- i++)
- {
- if(0 == strcmp(l_comp, g_desc_array[i].comp))
- {
- // Return this one.
- l_td = g_desc_array[i].td_entry;
- break;
- }
- }
-
- // Unlock critical section
- mutex_unlock(&iv_trac_mutex);
-
- }
-
- return l_td;
-}
-
-
-
-
-/*****************************************************************************/
-// getBuffer() called by ErrlEntry.collectTrace()
-// Return how many bytes copied to output buffer.
-// If given a null pointer or zero buffer then return the full size
-// of the buffer.
-//
-// Otherwise return zero on error; perhaps the component name/trace buffer
-// name is not found, or maybe the size of buffer given is too small to even
-// hold a trace buffer header.
-
-uint64_t Trace::getBuffer( const char * i_pComp,
- void * o_data,
- uint64_t i_size )
-{
- const char * l_pchEntry = NULL; // use this to walk the entries
- const char * l_pchEntryEOL = NULL; // end of list of entries
- const char * l_pchTraceBuffer = NULL; // source buffer, including header
- const char * l_pchTraceData = NULL; // source data, just past header
- const char * l_pchTraceEOB = NULL; // end of source buffer
- trace_buf_head_t * l_pCallerHeader = NULL; // output buffer, including header
- trace_desc_t * l_pDescriptor = NULL;
- uint64_t l_cbWrap = 0;
- uint64_t l_rc = 0;
-
- do
- {
- l_pDescriptor = findTdByName( i_pComp );
- if( NULL == l_pDescriptor )
- {
- // trace buffer name not found
- break;
- }
-
- if( (o_data == NULL) || (i_size == 0 ))
- {
- // return how big is the buffer.
- l_rc = l_pDescriptor->size;
- break;
- }
-
- // Round size down to nearest 4-byte boundary.
- i_size = ALIGN_DOWN_4(i_size);
-
-
- if( i_size < sizeof(trace_buf_head_t))
- {
- // Need at least enough space for the header.
- // printk("trace_get_buffer_partial: i_size too small");
- break;
- }
-
-
- // Caller's destination buffer starts with a trace_buf_head_t.
- l_pCallerHeader = static_cast<trace_buf_head_t*>(o_data);
-
-
-
- if( i_size >= l_pDescriptor->size )
- {
- // Caller's buffer is big enough to hold the whole buffer.
- uint64_t l_copyCount = l_pDescriptor->size;
-
- // Get the lock
- mutex_lock(&iv_trac_mutex);
-
- // If the buffer is not full, then the unused
- // portion is just zeroes. Avoid copying the zeroes.
- if( 0 == l_pDescriptor->times_wrap )
- {
- // Buffer has never wrapped, so copy the
- // data up to the next-free offset.
- l_copyCount = l_pDescriptor->next_free;
- }
-
- // Copy source buffer to caller's destination buffer
- memcpy( o_data, l_pDescriptor, l_copyCount );
-
- mutex_unlock(&iv_trac_mutex);
-
- // Update the header in the output buffer.
- l_pCallerHeader->size = l_copyCount;
-
- l_rc = l_copyCount;
- break;
- }
-
-
-
- // Input buffer size is smaller than source buffer size.
-
- mutex_lock(&iv_trac_mutex);
-
- if((i_size >= l_pDescriptor->next_free) && (0 == l_pDescriptor->times_wrap))
- {
- // The source buffer has not wrapped,
- // and what is there fits into caller's buffer.
- l_rc = l_pDescriptor->next_free;
- memcpy( o_data, l_pDescriptor, l_rc );
-
- mutex_unlock(&iv_trac_mutex);
-
- // Update the header in the output buffer.
- l_pCallerHeader->size = l_rc;
- break;
- }
-
-
- // Otherwise, walk the entries backwards because the word
- // just prior to any entry is the length of the previous entry.
- // Subtract this length from the current entry pointer to
- // point to the previous entry. Wrap around as required.
-
-
- // Trace descriptor points to base of source trace buffer.
- l_pchTraceBuffer = reinterpret_cast<const char*>(l_pDescriptor);
-
- // Source trace data resides just past the header.
- l_pchTraceData = reinterpret_cast<const char *>(l_pDescriptor+1);
-
- // EOB (end of buffer) of source trace buffer
- l_pchTraceEOB = l_pchTraceBuffer + l_pDescriptor->size;
-
- // useful when calculating locations of wrapped data
- l_cbWrap = l_pDescriptor->size - sizeof(trace_buf_head_t);
-
- // This is how much trace data caller's buffer can hold.
- int l_cbToFill = i_size - sizeof(trace_buf_head_t);
-
-
-
- // Start at next_free, which is not an actual entry.
- // It is where the next entry write will go when it comes.
- // It also marks the end of the list (EOL).
- l_pchEntryEOL = l_pchTraceBuffer + l_pDescriptor->next_free;
-
-
- // Walk backwards through the entries, looking for a point
- // such that when walking the source entries from that
- // point forward, those entries will fit into the
- // destination buffer. Because of the cases handled above,
- // this walking will not loop around back to where we started
- // within the source buffer. Otherwise there would have to be
- // tests made for wrapping and sensing when l_pchEntry passes
- // l_pchEntryEOL. Note that trace entry structures and payload
- // data may be wrapped anywhere on a 4-byte bound.
-
-
- // Start here and work backwards.
- l_pchEntry = l_pchEntryEOL;
-
-
- do
- {
-
- if(( l_pchEntry == l_pchTraceData ) && (0 == l_pDescriptor->times_wrap))
- {
- // Exit from this do loop with l_pchEntry the starting point.
- // Probably not going to happen, because the non-wrap short
- // buffer case was handled above.
- // massert( 0 );
- break;
- }
-
-
- // Determine the size of the entry prior to l_pchEntry. Normally,
- // this length is found in the 4-byte word just before the start of any
- // entry. However, trace code may wrap any given trace entry
- // anywhere on a 4-byte word.
-
- // massert( l_pchEntry >= l_pchTraceData );
- // massert( l_pchEntry < l_pchTraceEOB );
- // massert( 0 == (((uint64_t)(l_pchEntry)) & 3) );
-
- // Length of previous entry is in prior 32-bit word.
- const char * l_pchPreviousLength = l_pchEntry - sizeof(uint32_t);
-
- if( l_pchPreviousLength < l_pchTraceData )
- {
- // I am at the start of the source data. Apply wrap byte count
- // to find length up at the end of the buffer.
- l_pchPreviousLength += l_cbWrap;
-
- // Source buffer must have wrapped.
- // massert( l_pDescriptor->times_wrap );
- }
-
- // Dereference and get the length of previous entry.
- const uint32_t * l_p32;
- l_p32 = reinterpret_cast<const uint32_t*>(l_pchPreviousLength);
- int l_cbPrevious = *l_p32;
-
-
-
- if(( l_cbToFill - l_cbPrevious ) < 0 )
- {
- // This one is too much. l_pchEntry is the starting point.
- // This is the regular exit point from this loop.
- break;
- }
-
-
- // Given the length of the previous one,
- // assign a new value to l_pchEntry
- l_pchEntry -= l_cbPrevious;
-
- if( l_pchEntry < l_pchTraceData )
- {
- // Wrap.
- l_pchEntry += l_cbWrap;
- }
-
- l_cbToFill -= l_cbPrevious;
- // massert( l_cbToFill >= 0 );
- }
- while( 1 );
-
-
-
- // Having walked backwards, l_pchEntry is the starting point,
- // All the entries forward of this point are supposed to fit
- // into caller's data buffer.
-
- // Count how many copied from source to destination buffer.
- int l_entriesCopied = 0;
- int l_bytesCopied = sizeof( trace_buf_head_t );
-
- // Set up destination header.
- memcpy( l_pCallerHeader, l_pDescriptor, sizeof(trace_buf_head_t));
-
- // Caller's destination area for trace entry data, just past the
- // buffer header.
- char * l_pchDest = reinterpret_cast<char*>(l_pCallerHeader+1);
-
-
- while( l_pchEntry != l_pchEntryEOL )
- {
- const trace_bin_entry_t * l_pEntry;
-
- // Calculate how many bytes make up this entry. Value
- // goes into l_cbEntry;
- int l_cbEntry;
-
- if( (l_pchEntry + sizeof(trace_bin_entry_t)) > l_pchTraceEOB )
- {
- // This entry wraps. Copy this split-up
- // trace_bin_entry_t to the callers destination buffer
- // (save a malloc) then reference entry->head.length.
-
- // Copy this much from the end of the source trace buffer.
- int l_cb = l_pchTraceEOB - l_pchEntry;
- memcpy( l_pchDest, l_pchEntry, l_cb );
-
- // Copy the rest from the start of data in the trace buffer.
- int l_cbTheRest = sizeof( trace_bin_entry_t ) - l_cb;
- memcpy( l_pchDest+l_cb, l_pchTraceData, l_cbTheRest );
-
- // I just copied one of these into callers destination buffer.
- l_pEntry = reinterpret_cast<trace_bin_entry_t*>(l_pchDest);
- }
- else
- {
- // Otherwise, point the entry into the source buffer.
- l_pEntry = reinterpret_cast<const trace_bin_entry_t*>(l_pchEntry);
- }
-
- // Compute length of this entry. entry->head.length is the actual
- // length of the trace data, and has to rounded up to next 4-byte
- // boundary. The extra uint32 is where the size is stored.
- l_cbEntry = ALIGN_4(l_pEntry->head.length) +
- sizeof( trace_bin_entry_t ) +
- sizeof( uint32_t );
-
-
- if( (l_pchEntry + l_cbEntry) > l_pchTraceEOB )
- {
- // It wraps. Copy this split-up entry to the
- // callers buffer.
- int l_cb = l_pchTraceEOB - l_pchEntry;
- memcpy( l_pchDest, l_pchEntry, l_cb );
-
- // Copy the rest
- int l_cbTheRest = l_cbEntry - l_cb;
- memcpy( l_pchDest + l_cb, l_pchTraceData, l_cbTheRest );
-
- // Assign l_pchEntry to next entry
- l_pchEntry = l_pchTraceData + l_cbTheRest;
- }
- else
- {
- // Copy to destination buffer in one go.
- memcpy( l_pchDest, l_pchEntry, l_cbEntry );
-
- // Assign l_pchEntry to next entry
- l_pchEntry += l_cbEntry;
- }
-
- l_bytesCopied += l_cbEntry;
- // massert( 0 == ( l_bytesCopied & 3 ));
-
- // massert( l_pchEntry >= l_pchTraceData );
- // massert( l_pchEntry < l_pchTraceEOB );
- // massert( 0 == (((uint64_t)(l_pchEntry)) & 3) );
-
-
- // Increment new data destination pointer.
- l_pchDest += l_cbEntry;
- // massert( l_pchDest <= ((char*)l_pCallerHeader) + i_size );
-
- // This will eventually go into destination header.
- l_entriesCopied++;
-
- }
-
- // Done looking at source buffer stuff.
- mutex_unlock(&iv_trac_mutex);
-
- // Finish the caller's trace buffer header.
- l_pCallerHeader->times_wrap = 0;
- l_pCallerHeader->te_count = l_entriesCopied;
- l_pCallerHeader->next_free = l_bytesCopied;
- l_pCallerHeader->size = l_bytesCopied;
-
- // Return how many bytes written to output buffer.
- l_rc = l_bytesCopied;
- }
- while(0);
-
- return l_rc;
-}
-
-
-/******************************************************************************/
-// clearAllBuffers()
-/******************************************************************************/
-void Trace::clearAllBuffers()
-{
-
- // obtain the big trace lock
- mutex_lock(&iv_trac_mutex);
-
- // Walk the buffers array
- for( unsigned int i=0; i < TRAC_MAX_NUM_BUFFERS; i++ )
- {
- if( g_desc_array[i].comp[0] )
- {
- // Named, thus in use.
-
- // Buffer sizes are variable, save the size of it.
- uint32_t l_saveSize = g_desc_array[i].td_entry->size;
-
- initValuesBuffer( g_desc_array[i].td_entry,
- g_desc_array[i].comp,
- l_saveSize );
- }
- }
-
- // release the lock
- mutex_unlock(&iv_trac_mutex);
-}
-
-
-/******************************************************************************/
-// flushContBuffers()
-/******************************************************************************/
-void Trace::flushContBuffers()
-{
- getTheInstance()._flushContBuffers();
-}
-
-/******************************************************************************/
-// _flushContBuffers()
-/******************************************************************************/
-void Trace::_flushContBuffers()
-{
- mutex_lock(&iv_trac_mutex);
- MAGIC_INSTRUCTION(MAGIC_CONTINUOUS_TRACE);
- mutex_unlock(&iv_trac_mutex);
-}
-
-
-#if 0
-/******************************************************************************/
-// resetBuf - TODO
-/******************************************************************************/
-int32_t Trace::resetBuf()
-{
- /*------------------------------------------------------------------------*/
- /* Local Variables */
- /*------------------------------------------------------------------------*/
- int64_t l_rc = 0;
- //uint32_t l_num_des = 0;
- //uint32_t i=0;
-
- /*------------------------------------------------------------------------*/
- /* Code */
- /*------------------------------------------------------------------------*/
-
- // Get mutex so no one traces
-
- // TODO
- l_rc = UTIL_MUTEX_GET(&iv_trac_mutex,TRAC_INTF_MUTEX_TIMEOUT);
- if(l_rc != TX_SUCCESS)
- {
- printk("trace_reset_buf: Failure trying to get mutex");
- // Badness
- }
- else
- {
- l_num_des = sizeof(g_des_array) / sizeof(trace_descriptor_array_t);
-
- for(i=0;i<l_num_des;i++)
- {
- // Initialize the buffer
- l_rc = trace_init_values_buffer(g_des_array[i].entry,
- g_des_array[i].comp);
- if(l_rc)
- {
- printk("trace_reset_buf: Failure in call to trace_init_values_buffer()");
- break;
- }
- }
- }
-
-
- // Always try to release even if fail above
- // TODO - mutex
- //UTIL_MUTEX_PUT(&iv_trac_mutex);
-
- return(l_rc);
-}
-#endif
-
-} // namespace
diff --git a/src/usr/trace/tracebuffer.C b/src/usr/trace/tracebuffer.C
deleted file mode 100644
index 7eda6ae25..000000000
--- a/src/usr/trace/tracebuffer.C
+++ /dev/null
@@ -1,77 +0,0 @@
-// IBM_PROLOG_BEGIN_TAG
-// This is an automatically generated prolog.
-//
-// $Source: src/usr/trace/tracebuffer.C $
-//
-// IBM CONFIDENTIAL
-//
-// COPYRIGHT International Business Machines Corp. 2011
-//
-// p1
-//
-// Object Code Only (OCO) source materials
-// Licensed Internal Code Source Materials
-// IBM HostBoot Licensed Internal Code
-//
-// The source code for this program is not published or other-
-// wise divested of its trade secrets, irrespective of what has
-// been deposited with the U.S. Copyright Office.
-//
-// Origin: 30
-//
-// IBM_PROLOG_END
-#include <limits.h>
-#include "tracebuffer.H"
-
-TracePage* TracePage::setNext(TracePage* new_next)
-{
- return __sync_val_compare_and_swap(&this->next, NULL, new_next);
-}
-
-traceEntry* TracePage::claimEntry(size_t size)
-{
- // this->size will eventually wrap and it will suddenly look like there
- // is free space?
- size_t position = __sync_fetch_and_add(&this->size, size);
- if (position > (PAGE_SIZE - sizeof(TracePage)))
- {
- return NULL;
- }
- else
- {
- return (traceEntry*)&((uint8_t*)this)[sizeof(TracePage) + position];
- }
-}
-
-traceEntry* TraceBuffer::claimEntry(size_t size)
-{
- traceEntry* result = NULL;
- TracePage* page = last;
-
- while (result == NULL)
- {
- result = page->claimEntry(size);
-
- if (NULL == result)
- {
- if (NULL != page->getNext())
- {
- __sync_bool_compare_and_swap(&this->last,
- page, page->getNext());
- page = page->getNext();
- }
- else
- {
- TracePage* new_page = new (malloc(PAGE_SIZE)) TracePage();
- TracePage* prev = page;
-
- while(prev != NULL)
- {
- prev = prev->setNext(new_page);
- }
- }
- }
- }
-
- return result;
-}
diff --git a/src/usr/trace/tracebuffer.H b/src/usr/trace/tracebuffer.H
deleted file mode 100644
index 90cc80f75..000000000
--- a/src/usr/trace/tracebuffer.H
+++ /dev/null
@@ -1,73 +0,0 @@
-// IBM_PROLOG_BEGIN_TAG
-// This is an automatically generated prolog.
-//
-// $Source: src/usr/trace/tracebuffer.H $
-//
-// IBM CONFIDENTIAL
-//
-// COPYRIGHT International Business Machines Corp. 2011
-//
-// p1
-//
-// Object Code Only (OCO) source materials
-// Licensed Internal Code Source Materials
-// IBM HostBoot Licensed Internal Code
-//
-// The source code for this program is not published or other-
-// wise divested of its trade secrets, irrespective of what has
-// been deposited with the U.S. Copyright Office.
-//
-// Origin: 30
-//
-// IBM_PROLOG_END
-#ifndef __TRACE_TRACEBUFFER_H
-#define __TRACE_TRACEBUFFER_H
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <new>
-#include <limits.h>
-#include <sys/task.h>
-
-struct traceEntry
-{
- uint64_t component;
- tid_t tid;
- uint16_t length;
- uint32_t hash;
- uint64_t timestamp;
- uint32_t line;
- uint64_t values[0];
-};
-
-
-class TracePage
-{
- public:
- TracePage() : next(NULL), size(0) {};
-
- TracePage* setNext(TracePage*);
- TracePage* getNext() { return next; };
- traceEntry* claimEntry(size_t size);
-
- private:
- TracePage* volatile next;
- uint64_t size;
-};
-
-class TraceBuffer
-{
- public:
- TraceBuffer()
- {
- first = last = new (malloc(PAGE_SIZE)) TracePage();
- }
-
- traceEntry* claimEntry(size_t size);
-
- private:
- TracePage* first;
- TracePage* volatile last;
-};
-
-#endif
diff --git a/src/usr/trace/tracedaemon.C b/src/usr/trace/tracedaemon.C
deleted file mode 100644
index cbbb73e85..000000000
--- a/src/usr/trace/tracedaemon.C
+++ /dev/null
@@ -1,124 +0,0 @@
-/* IBM_PROLOG_BEGIN_TAG */
-/* This is an automatically generated prolog. */
-/* */
-/* $Source: src/usr/trace/tracedaemon.C $ */
-/* */
-/* IBM CONFIDENTIAL */
-/* */
-/* COPYRIGHT International Business Machines Corp. 2012 */
-/* */
-/* p1 */
-/* */
-/* Object Code Only (OCO) source materials */
-/* Licensed Internal Code Source Materials */
-/* IBM HostBoot Licensed Internal Code */
-/* */
-/* The source code for this program is not published or otherwise */
-/* divested of its trade secrets, irrespective of what has been */
-/* deposited with the U.S. Copyright Office. */
-/* */
-/* Origin: 30 */
-/* */
-/* IBM_PROLOG_END_TAG */
-#include "tracedaemon.H"
-#include <sys/task.h>
-#include <targeting/common/commontargeting.H>
-#include <vfs/vfs.H>
-#include <devicefw/driverif.H>
-#include <errl/errlentry.H>
-#include <errl/errlmanager.H>
-
-namespace TRACE
-{
-
-TraceDaemon::TraceDaemon() :
- iv_pMaster(TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL)
-{
- iv_msgQ = msg_q_create();
- task_create(TraceDaemon::start, this);
-}
-
-TraceDaemon::~TraceDaemon()
-{
- // Send message to shutdown daemon thread.
- msg_t* l_msg = msg_allocate();
- l_msg->type = DAEMON_SHUTDOWN;
- msg_sendrecv(iv_msgQ, l_msg);
- msg_free(l_msg);
-
- // Release message queue.
- msg_q_destroy(iv_msgQ);
-}
-
-void* TraceDaemon::start(void* i_self)
-{
- reinterpret_cast<TraceDaemon *>(i_self)->run();
- return NULL;
-};
-
-void TraceDaemon::run()
-{
- msg_t* l_msg = NULL;
-
- // Main daemon loop.
- while(1)
- {
- // Get message from client.
- l_msg = msg_wait(iv_msgQ);
-
- // Switch based on message type.
- switch(l_msg->type)
- {
- case UPDATE_SCRATCH_REG:
- updateScratchReg(l_msg->data[0]);
- break;
-
- case SEND_TRACE_BUFFER: // TODO.
- // Delete buffer for now.
- free(l_msg->extra_data);
- break;
-
- case DAEMON_SHUTDOWN:
- // Respond to message and exit.
- msg_respond(iv_msgQ, l_msg);
- return;
- };
-
- if (msg_is_async(l_msg))
- {
- // Delete async messages.
- msg_free(l_msg);
- }
- else
- {
- // Respond to sync messages.
- msg_respond(iv_msgQ, l_msg);
- }
- }
-
-}
-
-void TraceDaemon::updateScratchReg(uint64_t i_value)
-{
- // Find master processor target.
- if (iv_pMaster == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL)
- {
- if (VFS::module_is_loaded("libtargeting.so") &&
- TARGETING::targetService().isInitialized())
- {
- TARGETING::targetService().masterProcChipTargetHandle(iv_pMaster);
- }
- }
-
- // Write scratch register to requested value.
- size_t l_size = sizeof(uint64_t);
- errlHndl_t l_errl = deviceWrite(iv_pMaster, &i_value, l_size,
- DEVICE_SCOM_ADDRESS(MB_SCRATCH_REGISTER_0));
-
- if (l_errl)
- {
- errlCommit(l_errl, HBTRACE_COMP_ID);
- }
-}
-
-};
diff --git a/src/usr/trace/tracedaemon.H b/src/usr/trace/tracedaemon.H
deleted file mode 100644
index 1dbc0935a..000000000
--- a/src/usr/trace/tracedaemon.H
+++ /dev/null
@@ -1,92 +0,0 @@
-/* IBM_PROLOG_BEGIN_TAG */
-/* This is an automatically generated prolog. */
-/* */
-/* $Source: src/usr/trace/tracedaemon.H $ */
-/* */
-/* IBM CONFIDENTIAL */
-/* */
-/* COPYRIGHT International Business Machines Corp. 2012 */
-/* */
-/* p1 */
-/* */
-/* Object Code Only (OCO) source materials */
-/* Licensed Internal Code Source Materials */
-/* IBM HostBoot Licensed Internal Code */
-/* */
-/* The source code for this program is not published or otherwise */
-/* divested of its trade secrets, irrespective of what has been */
-/* deposited with the U.S. Copyright Office. */
-/* */
-/* Origin: 30 */
-/* */
-/* IBM_PROLOG_END_TAG */
-
-#ifndef __TRACE_DAEMON_H
-#define __TRACE_DAEMON_H
-
-#include <sys/msg.h>
-#include <targeting/common/target.H>
-
-namespace TRACE
-{
- /** @class TraceDaemon
- * @brief Encapsulates the daemon functionality of trace.
- *
- * The main-line trace paths can send messages to this code to request
- * actions, such as buffer offload (by mailbox or signalling a scratch
- * register), to be done or (TODO) the FSP can send messages to it.
- */
- class TraceDaemon
- {
- public:
- /** Default Constructor
- *
- * Initializes class and starts daemon thread.
- */
- TraceDaemon();
-
- /** Default Destructor
- *
- * Shuts down daemon thread and releases mailbox queue.
- */
- ~TraceDaemon();
-
- /** Message types supported by the trace daemon. */
- enum SUPPORTED_MSG_TYPES
- {
- UPDATE_SCRATCH_REG, //< Update cont-trace scratch reg.
- SEND_TRACE_BUFFER, //< Send buffer to FSP.
-
- DAEMON_SHUTDOWN, //< Shutdown daemon thread.
- };
-
- // Make trace class a friend so it can get the message queue.
- friend class Trace;
-
- protected:
- /** Message Queue */
- msg_q_t iv_msgQ;
-
- private:
- /** Target for master processor */
- TARGETING::Target* iv_pMaster;
-
- /** SCOM address of scratch register. */
- static const uint32_t MB_SCRATCH_REGISTER_0 = 0x00050038;
-
- /** @brief Function to start daemon thread (using task_create).
- * @param[in] Pointer to self.
- */
- static void* start(void*);
-
- /** @brief Main daemon loop. */
- void run();
-
- /** @brief Update a scratch register with the desired value.
- * @param[in] i_value - Value to write to scratch register.
- */
- void updateScratchReg(uint64_t i_value);
- };
-};
-
-#endif
OpenPOWER on IntegriCloud