summaryrefslogtreecommitdiffstats
path: root/src/usr/trace
diff options
context:
space:
mode:
authorMonte Copeland <copelanm@us.ibm.com>2011-11-16 09:02:17 -0600
committerMIKE J. JONES <mjjones@us.ibm.com>2011-11-21 12:32:19 -0600
commitd4b2086e646ac2444539bac0750af82e5e0b5d7c (patch)
treecf754de98935df10870b5aa96b2ec9cb270e8c8e /src/usr/trace
parent11c80c5abcf203e5a65098ea047fd6d2a6e607cc (diff)
downloadtalos-hostboot-d4b2086e646ac2444539bac0750af82e5e0b5d7c.tar.gz
talos-hostboot-d4b2086e646ac2444539bac0750af82e5e0b5d7c.zip
collectTrace to allow partial trace buffer collection
Change-Id: I06ce6df416f38c4619281180ea8515c90f8f2fab Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/498 Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com> Tested-by: Jenkins Server
Diffstat (limited to 'src/usr/trace')
-rw-r--r--src/usr/trace/trace.C485
1 files changed, 313 insertions, 172 deletions
diff --git a/src/usr/trace/trace.C b/src/usr/trace/trace.C
index 447fad968..221270c48 100644
--- a/src/usr/trace/trace.C
+++ b/src/usr/trace/trace.C
@@ -20,13 +20,19 @@
// Origin: 30
//
// IBM_PROLOG_END
+
+/**
+ * @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
- * - Prolog
- *
*
*/
@@ -43,11 +49,14 @@
#include <stdlib.h>
#include <sys/task.h>
#include <sys/sync.h>
-#include <string.h>
+#include <string_ext.h>
#include <util/align.H>
#include <trace/trace.H>
+
+
+
/******************************************************************************/
// Namespace
/******************************************************************************/
@@ -156,6 +165,9 @@ void Trace::initBuffer(trace_desc_t **o_td, const char* i_comp,
strcpy(l_comp, i_comp);
}
+ // make string upper case
+ strupr(l_comp);
+
// CRITICAL REGION START
mutex_lock(&iv_trac_mutex);
@@ -191,7 +203,7 @@ void Trace::initBuffer(trace_desc_t **o_td, const char* i_comp,
// TODO can't handle i_size yet - everything is coded
// around TRAC_DEFAULT_BUFFER_SIZE
l_td = static_cast<char *>(malloc(TRAC_DEFAULT_BUFFER_SIZE));
-
+
g_desc_array[i].td_entry =
reinterpret_cast<trace_desc_t *>(l_td);
@@ -331,10 +343,15 @@ void Trace::_trace_adal_write_all(trace_desc_t *io_td,
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
+ // 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])
@@ -365,7 +382,8 @@ void Trace::_trace_adal_write_all(trace_desc_t *io_td,
//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));
+ //printk("Trace: l_str_map 0x%16llX\n",
+ // static_cast<long long>(l_str_map));
}
else if ('c' == _fmt[i])
{
@@ -412,6 +430,9 @@ void Trace::_trace_adal_write_all(trace_desc_t *io_td,
}
}
+ va_end( i_args );
+
+
if((num_4byte_args <= TRAC_MAX_ARGS) && (io_td != NULL))
{
// Fill in the entry structure
@@ -427,7 +448,9 @@ void Trace::_trace_adal_write_all(trace_desc_t *io_td,
// Time stamp
convertTime(&l_entry.stamp);
- // Calculate total space needed
+ // 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;
l_entry_size += sizeof(trace_entry_stamp_t);
l_entry_size += sizeof(trace_entry_head_t);
@@ -445,7 +468,9 @@ void Trace::_trace_adal_write_all(trace_desc_t *io_td,
memset(l_buffer, 0, l_data_size);
char * l_ptr = static_cast<char *> (l_buffer);
- // Now copy the arguments to the buffer
+ // Now copy the arguments to the buffer.
+
+
for (size_t i = 0; i < num_args; i++)
{
uint32_t l_strLen = 0;
@@ -654,12 +679,16 @@ void Trace::writeData(trace_desc_t *io_td,
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
@@ -731,277 +760,389 @@ void Trace::convertTime(trace_entry_stamp_t *o_entry)
}
+
+
/******************************************************************************/
-// getTd
+// findTdByName
/******************************************************************************/
-trace_desc_t * Trace::getTd(const char *i_comp)
+trace_desc_t * Trace::findTdByName(const char *i_pName)
{
- /*------------------------------------------------------------------------*/
- /* Local Variables */
- /*------------------------------------------------------------------------*/
- uint32_t i=0;
trace_desc_t * l_td = NULL;
- char l_comp[COMP_NAME_SIZE] = {'\0'};
+ char l_comp[COMP_NAME_SIZE];
- /*------------------------------------------------------------------------*/
- /* Code */
- /*------------------------------------------------------------------------*/
- if (strlen(i_comp) != 0)
+ uint64_t i = strlen(i_pName);
+ if ( i )
{
- // Limit component name to 15 characters.
- if (strlen(i_comp) > (COMP_NAME_SIZE -1))
+ if ( i > (COMP_NAME_SIZE -1))
{
- memcpy(l_comp, i_comp, 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_comp);
+ strcpy( l_comp, i_pName );
}
- // Search all allocated component buffers
+ // Use upper case.
+ strupr( l_comp );
+
+ // Search the buffers array
for(i=0;
(i < (TRAC_MAX_NUM_BUFFERS - 1)) &&
(strlen(g_desc_array[i].comp) != 0);
i++)
{
- if(!strcmp(l_comp, g_desc_array[i].comp))
+ if(0 == strcmp(l_comp, g_desc_array[i].comp))
{
- // Found the component buffer
+ // Return this one.
l_td = g_desc_array[i].td_entry;
break;
}
}
- if (((TRAC_MAX_NUM_BUFFERS - 1) == i) &&
- (strlen(g_desc_array[i].comp) != 0))
-
- {
- // Must be the default buffer
- l_td = g_desc_array[i].td_entry;
- }
}
- return(l_td);
+ return l_td;
}
/*****************************************************************************/
-// getBuffer() called by ErrlEntry.CollectTrace()
-// Return how many bytes copied, or if given a null pointer or zero buffer
-// size, then return the size of the buffer.
+// 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.
+// 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_bufferSize )
+ uint64_t i_size )
{
- int64_t l_rc = 0;
- trace_desc_t * l_pDescriptor = NULL;
+ 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 = getTd( i_pComp );
+ l_pDescriptor = findTdByName( i_pComp );
if( NULL == l_pDescriptor )
{
+ // trace buffer name not found
break;
}
- if( ( NULL == o_data ) || ( 0 == i_bufferSize ))
+ if( (o_data == NULL) || (i_size == 0 ))
{
// return how big is the buffer.
- l_rc = TRAC_DEFAULT_BUFFER_SIZE;
+ l_rc = l_pDescriptor->size;
break;
}
- // Not to exceed buffer size.
- uint64_t l_copyCount = i_bufferSize;
- if( i_bufferSize > TRAC_DEFAULT_BUFFER_SIZE )
+ // Round size down to nearest 4-byte boundary.
+ i_size = ALIGN_DOWN_4(i_size);
+
+
+ if( i_size < sizeof(trace_buf_head_t))
{
- l_copyCount = TRAC_DEFAULT_BUFFER_SIZE;
+ // Need at least enough space for the header.
+ // printk("trace_get_buffer_partial: i_size too small");
+ break;
}
- // Get the lock
- mutex_lock(&iv_trac_mutex);
- // Copy buffer to caller's space
- memcpy( o_data, l_pDescriptor, (size_t)l_copyCount );
+ // Caller's destination buffer starts with a trace_buf_head_t.
+ l_pCallerHeader = static_cast<trace_buf_head_t*>(o_data);
- mutex_unlock(&iv_trac_mutex);
- l_rc = l_copyCount;
- }
- while( 0 );
- return l_rc;
-}
+ 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 );
-#if 0
-/******************************************************************************/
-// getBufferPartial - TODO
-/******************************************************************************/
-// TODO
-int32_t Trace::getBufferPartial(const trace_desc_t *i_td_ptr,
- void *o_data,
- uint32_t *io_size)
-{
- /*------------------------------------------------------------------------*/
- /* Local Variables */
- /*------------------------------------------------------------------------*/
- int32_t l_rc = 0;
- char *l_full_buf = NULL;
- trace_desc_t *l_head = NULL;
- uint32_t l_part_size = 0;
+ mutex_unlock(&iv_trac_mutex);
- /*------------------------------------------------------------------------*/
- /* Code */
- /*------------------------------------------------------------------------*/
+ // Update the header in the output buffer.
+ l_pCallerHeader->size = l_copyCount;
- do
- {
-
- if((i_td_ptr == NULL) || (o_data == NULL) || (io_size == NULL))
- {
- printk("trace_get_buffer_partial: Invalid parameter passed by caller");
- l_rc = TRAC_INVALID_PARM;
- if(io_size != NULL)
- {
- *io_size = 0;
- }
+ l_rc = l_copyCount;
break;
}
- if(*io_size < sizeof(trace_buf_head_t))
- {
- // Need to at least have enough space for the header
- printk("trace_get_buffer_partial: *io_size to small");
- l_rc = TRAC_MEM_BUFF_TO_SMALL;
- *io_size = 0;
- break;
- }
- // First get the full buffer
- l_rc = tx_byte_allocate(&tpmd_trac_debug_byte_pool,
- (void **)&l_full_buf,
- TPMD_TRACE_BUFFER_SIZE,
- TX_NO_WAIT);
- if(l_rc != TX_SUCCESS)
- {
- printk("trace_get_buffer_partial: Failure allocating memory for temp buffer");
- *io_size = 0;
- l_rc = TRAC_MEM_ALLOC_FAIL;
- break;
- }
- l_rc = trace_get_buffer(i_td_ptr,
- l_full_buf);
- if(l_rc != 0)
- {
- printk("trace_get_buffer_partial: Failure in call to TRAC_get_buffer()");
- *io_size = 0;
- break;
- }
+ // Input buffer size is smaller than source buffer size.
- // Now that we have full buffer, adjust it to be requested size
- memset(o_data,0,(size_t)*io_size);
+ mutex_lock(&iv_trac_mutex);
- if(*io_size > TPMD_TRACE_BUFFER_SIZE)
+ if((i_size >= l_pDescriptor->next_free) && (0 == l_pDescriptor->times_wrap))
{
- // It fits
- *io_size = TPMD_TRACE_BUFFER_SIZE;
- memcpy(o_data,l_full_buf,(size_t)*io_size);
- break;
- }
+ // 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 );
- l_head = (trace_desc_t *)l_full_buf;
- memcpy(o_data,l_full_buf,(size_t)(l_head->hdr_len));
- l_head = (trace_desc_t *)o_data;
- l_head->size = *io_size;
+ mutex_unlock(&iv_trac_mutex);
- if((l_head->next_free == l_head->hdr_len) && (l_head->times_wrap == 0))
- {
- // No data in buffer so just return what we have
+ // Update the header in the output buffer.
+ l_pCallerHeader->size = l_rc;
break;
}
- if(l_head->next_free > *io_size)
+
+ // 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
{
- // We can't even fit in first part of buffer
- // Make sure data size is larger than header length
- // Otherwise, we will be accessing beyond memory
- if(*io_size < l_head->hdr_len)
+
+ if(( l_pchEntry == l_pchTraceData ) && (0 == l_pDescriptor->times_wrap))
{
- l_rc = TRAC_DATA_SIZE_LESS_THAN_HEADER_SIZE;
+ // 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;
}
- l_part_size = *io_size - l_head->hdr_len;
- memcpy((UCHAR *)o_data+l_head->hdr_len,
- l_full_buf+l_head->next_free-l_part_size,
- (size_t)l_part_size);
- // Set pointer at beginning because this will be a
- // "just wrapped" buffer.
- l_head->next_free = l_head->hdr_len;
+ // 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;
- // Buffer is now wrapped because we copied max data into it.
- if(!l_head->times_wrap)
+ if( l_pchEntry < l_pchTraceData )
{
- l_head->times_wrap = 1;
+ // Wrap.
+ l_pchEntry += l_cbWrap;
}
+
+ l_cbToFill -= l_cbPrevious;
+ // massert( l_cbToFill >= 0 );
}
- else
+ 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 )
{
- // First part of buffer fits fine
- memcpy((UCHAR *)o_data+l_head->hdr_len,
- l_full_buf+l_head->hdr_len,
- (size_t)(l_head->next_free - l_head->hdr_len));
+ const trace_bin_entry_t * l_pEntry;
+ // Calculate how many bytes make up this entry. Value
+ // goes into l_cbEntry;
+ int l_cbEntry;
- // If it's wrapped then pick up some more data
- if(l_head->times_wrap)
+ if( (l_pchEntry + sizeof(trace_bin_entry_t)) > l_pchTraceEOB )
{
- // Figure out how much room we have left
- l_part_size = *io_size - l_head->next_free;
+ // 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 );
- memcpy((UCHAR *)o_data+l_head->next_free,
- l_full_buf+TPMD_TRACE_BUFFER_SIZE-l_part_size,
- (size_t)l_part_size);
+ // 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
{
- // No more data to get, make buffer look as small
- // as possible
- // add '+4' to avoid the need to mark it as wrapped
- // (if the last byte of the buffer is filled
- // next_free has to pointer to the first byte)
+ // Otherwise, point the entry into the source buffer.
+ l_pEntry = reinterpret_cast<const trace_bin_entry_t*>(l_pchEntry);
+ }
- l_head->size = l_head->next_free + 4;
+ // 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++;
}
- *io_size = l_head->size;
+ // Done looking at source buffer stuff.
+ mutex_unlock(&iv_trac_mutex);
- }while(0);
+ // 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;
- if(l_full_buf != NULL)
- {
- tx_byte_release(l_full_buf);
+ // Return how many bytes written to output buffer.
+ l_rc = l_bytesCopied;
}
+ while(0);
- return(l_rc);
+ return l_rc;
}
-#endif
+
+
+
+
/******************************************************************************/
// resetBuf - TODO
OpenPOWER on IntegriCloud