diff options
author | Roland Veloz <rveloz@us.ibm.com> | 2019-08-12 14:10:06 -0500 |
---|---|---|
committer | Daniel M Crowell <dcrowell@us.ibm.com> | 2019-08-28 12:44:04 -0500 |
commit | 4536704918f346016d5e2d6091dd8f5c33f8c4b1 (patch) | |
tree | a2eec8528891532a1167eebce9c8a84a3516d998 /src/usr | |
parent | 01ac1b8dc22e3cba20a194fee7d741b749658223 (diff) | |
download | talos-hostboot-4536704918f346016d5e2d6091dd8f5c33f8c4b1.tar.gz talos-hostboot-4536704918f346016d5e2d6091dd8f5c33f8c4b1.zip |
Updated the HBRT reserved trace buffer code to compensate for relocation
This change fixes an issue where the HBRT reserved trace buffer can
be placed in a new location than it's origination.
When HB crashes, the reserved trace buffer is persisted until next IPL.
With OPAL, the reserved trace buffer may be in a different memory
location than where the buffer was when it crashed, therefore all
internal pointers will be invalid. This change will detect the change
in buffer location and realign all internal pointers to be valid
once again. This is not an issue with PHYP, only with OPAL.
Change-Id: I476845550062433fba190294b0bd2bbcf8dad658
RTC: 206137
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/82094
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Christian R Geddes <crgeddes@us.ibm.com>
Reviewed-by: Glenn Miles <milesg@ibm.com>
Reviewed-by: Daniel M Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/usr')
-rw-r--r-- | src/usr/trace/runtime/rt_rsvdtracebuffer.C | 86 | ||||
-rw-r--r-- | src/usr/trace/runtime/rt_rsvdtracebuffer.H | 68 | ||||
-rw-r--r-- | src/usr/trace/runtime/rt_rsvdtracebufservice.C | 8 | ||||
-rw-r--r-- | src/usr/trace/runtime/test/testrsvdtracebuf.H | 270 |
4 files changed, 363 insertions, 69 deletions
diff --git a/src/usr/trace/runtime/rt_rsvdtracebuffer.C b/src/usr/trace/runtime/rt_rsvdtracebuffer.C index 346cfc3e0..175850ff8 100644 --- a/src/usr/trace/runtime/rt_rsvdtracebuffer.C +++ b/src/usr/trace/runtime/rt_rsvdtracebuffer.C @@ -28,6 +28,18 @@ namespace TRACE { + +/// Some constants to help keep track of the structure of the buffer +/// Have these build on each other +// A pointer of where the reserved memory points to itself. Helps to determine +// if the buffer has been relocated +const uint32_t RESERVED_MEMORY_POINTER_OFFSET = 0; +// The location of the buffer for Entries. +const uint32_t BUFFER_BEGINNINIG_BOUNDARY_OFFSET = + sizeof(uintptr_t) + RESERVED_MEMORY_POINTER_OFFSET; +// Minimum size of the buffer, based on the buffers needs to be functional +const uint32_t MINIMUM_SIZE_OF_BUFFER_IN_BYTES = + BUFFER_BEGINNINIG_BOUNDARY_OFFSET; /** * ctor */ @@ -50,15 +62,25 @@ void RsvdTraceBuffer::init(uint32_t i_bufferSize, { // If buffer is not already initialized and incoming data is legit if ( (false == isBufferValid()) && - (i_bufferSize > 0 ) && + (i_bufferSize > MINIMUM_SIZE_OF_BUFFER_IN_BYTES ) && (i_addressToBuffer > 0) && (nullptr != i_addressToHead) ) { - setBeginningBoundary(convertToCharPointer(i_addressToBuffer)); - setEndingBoundary(convertToCharPointer(i_addressToBuffer + - i_bufferSize - 1)); + // Set the list head pointer. This needs to be set first. setListHeadPtr(i_addressToHead); + // Set the reserved memory pointer + iv_ptrToRsvdMem = reinterpret_cast<uintptr_t*> + (i_addressToBuffer + RESERVED_MEMORY_POINTER_OFFSET); + + setBeginningBoundary(convertToCharPointer + (i_addressToBuffer + BUFFER_BEGINNINIG_BOUNDARY_OFFSET)); + setEndingBoundary(convertToCharPointer + (i_addressToBuffer + i_bufferSize - 1)); + + // Check if buffer has moved and if so, realign the pointers + checkBuffer(); + // Now that there is an actual/real buffer to point to, the buffer is // valid, although it may/may not have any entries associated with it. setBufferValidity(true); @@ -66,6 +88,60 @@ void RsvdTraceBuffer::init(uint32_t i_bufferSize, } /** + * checkBuffer + */ +void RsvdTraceBuffer::checkBuffer() +{ + intptr_t l_offset(0); + + // If the reserved memory data is not zero, meaning that buffer is being + // revisited again, and the memory does not match the current pointer of + // the reserved memory data, then the buffer has been relocated and the + // pointer info in the buffer needs to be realigned/corrected. + // The buffer gets revisited to pull data when a crash happens. Please + // see the details section for the class in the .H file. + if ((0 != iv_ptrToRsvdMem[0]) && + (reinterpret_cast<uintptr_t>(iv_ptrToRsvdMem) != iv_ptrToRsvdMem[0])) + { + // Get the difference in memory location + l_offset = reinterpret_cast<uintptr_t> + (iv_ptrToRsvdMem) - iv_ptrToRsvdMem[0]; + + realignListPointers(l_offset); + } + + // Persist the current buffer location + iv_ptrToRsvdMem[0] = reinterpret_cast<uintptr_t>(iv_ptrToRsvdMem); +} + +/** + * realignListPointers + */ +void RsvdTraceBuffer::realignListPointers(intptr_t l_offset) +{ + // Verify that there is actual data to realign + Entry* l_head = getListHead(); + if (l_head) + { + // Update the pointer to the list + *iv_ptrToHead = *iv_ptrToHead + l_offset; + + // Get the the head of list to traverse over and correct pointers + Entry* l_entry = l_head = getListHead(); + do + { + // Update the pointers of Entry item + l_entry->next = reinterpret_cast<Entry *>( + reinterpret_cast<uintptr_t>(l_entry->next) + l_offset); + l_entry->prev = reinterpret_cast<Entry *>( + reinterpret_cast<uintptr_t>(l_entry->prev) + l_offset); + + l_entry = l_entry->next; + } while (l_entry != l_head); + } +} + +/** * insertEntry */ Entry* RsvdTraceBuffer::insertEntry(uint32_t i_dataSize) @@ -170,7 +246,7 @@ uint32_t RsvdTraceBuffer::getAvailableSpace(uint32_t i_spaceNeeded, // space needed, then return that value else return the space // available at the beginning of the buffer. If the space at the // end does not have enough of the needed space, then space will - // ultimately be made at the beginning of the + // ultimately be made at the beginning of the buffer. // // Right now, you are probably thinking, what if I only need 5 free // spaces and if the end has 10 available and the beginning has 7 diff --git a/src/usr/trace/runtime/rt_rsvdtracebuffer.H b/src/usr/trace/runtime/rt_rsvdtracebuffer.H index b1a8000d0..e804a41ed 100644 --- a/src/usr/trace/runtime/rt_rsvdtracebuffer.H +++ b/src/usr/trace/runtime/rt_rsvdtracebuffer.H @@ -43,9 +43,25 @@ namespace TRACE * * @brief Class to manage the Reserved Trace Buffer * - * This is a utility class to manage the buffer - looking for space - * for an entry, adding entries and removing entries. - * + * @details This is a utility class to manage the buffer - looking + * for space for an entry, adding entries and removing entries. + * When a system crashes, this buffer will persist the last + * few traces. When HB is IPLed again, the persisted data + * will be retrieved for inspection. + * With PHYP, the buffer will be retrieved at the same memory + * location as before the crash. With OPAL, the buffer may be + * relocated to a different location and all the pointers within + * the buffer will be invalid. If the buffer does get relocated, + * this class will correct the pointers. + * To correct the pointers, a section at the beginning of the + * persisted buffer is reserved to save the address of the buffer. + * Such that when the buffer is retrieved after a crash, if that + * data does not match the current buffer address, then we can + * conclude it has been relocated and the pointers in the buffer + * need to be updated/corrected. + * If the data at the beginning of the buffer is 0, then this is + * first time this buffer is being used and therefore no need to + * correct pointers. */ class RsvdTraceBuffer { @@ -89,12 +105,12 @@ namespace TRACE * If o_data is valid and the i_size is greater than * the size of trace_buf_head_t, then as many trace * entries will be returned in the o_data buffer that - * i_size will allow. + * i_size will allow, minus size of trace_buf_head_t. * - * @param[in] o_data - if not null, the buffer area to copy + * @param[out] o_data - if not null, the buffer area to copy * trace data into * - * @param[out] i_dataSize - if not 0, the size of the buffer area, + * @param[in] i_dataSize - if not 0, the size of the buffer area, * which dictates how many trace entries' * payload (or data the entry contains) * that can be copied @@ -123,7 +139,23 @@ namespace TRACE */ uint32_t getNumberOfEntries() const; + // Private methods private: + + /** @brief Checks the buffer to see if it has been relocated and if + * so, realign the pointers within the buffer. + */ + void checkBuffer(); + + + /** @brief When and if buffer has been relocated this method will + * realign the pointers within the buffer. + * + * @param[in] i_offset - the offset the buffer has moved + * within memory + */ + void realignListPointers(intptr_t i_offset); + /** @brief This function will find a contiguous piece of memory that * is large enough in size to accommodate the space needed. * If not enough free contiguous memory exists to accommodate @@ -147,7 +179,8 @@ namespace TRACE * requested is not larger in size to the buffer size, * then an available space will eventually be returned. * - * @param[in] i_spaceNeeded - @see insertEntry::i_dataSize above + * @param[in] i_spaceNeeded - The size of the contiguous piece + * of memory caller desires * * @param[out] o_availableAddress - A pointer to the contiguous * piece of memory found that satisfies the caller's @@ -160,8 +193,8 @@ namespace TRACE char* &o_availableAddress); /** @brief Returns a contiguous piece of memory that will satisfy - * the space that is needed if large enough space can be - * had, else returns the size of the largest contiguous + * the space that is needed if a large enough space can be + * found, else return the size of the largest contiguous * piece of memory. * * @algorithm There are three cases to consider: @@ -228,13 +261,16 @@ namespace TRACE * Case 2: Contiguous space desired: 40 bytes * Return the 30 bytes between Tail and Head. * - * @param[in] i_spaceNeeded - @see insertEntry::i_dataSize above + * @param[in] i_spaceNeeded - The size of the contiguous piece + * of memory caller desires * - * @param[out] o_availableAddress - @see makeSpaceForEntry above + * @param[out] o_availableAddress - A pointer to the biggest + * piece of contiguous memory found. May or may + * not satisfy i_spaceNeeded. * * @return The minimum size of the space found that meets the * requested space needed; or the largest size that comes - * close to meeting the space needed + * close to meeting the space needed. * */ uint32_t getAvailableSpace(uint32_t i_spaceNeeded, @@ -256,7 +292,7 @@ namespace TRACE uint32_t getAggregateSizeOfEntries() const; /** @brief This will return as many data entries that can be - * accommodated by size + * accommodated by i_dataSize * * @param[out] o_data - the buffer area to copy trace data into * @@ -447,9 +483,13 @@ namespace TRACE void clearPtrToHead() { iv_ptrToHead = nullptr; } + // Private data members + private: + uintptr_t* iv_ptrToRsvdMem; //< Pointer to Reserved Memory. Used to + // realign pointers if RsvdMem relocates + uintptr_t* iv_ptrToHead; //< Pointer to oldest Entry (time wise) char *iv_bufferBeginningBoundary; //< Pointer to beginning of buffer char *iv_bufferEndingBoundary; //< Pointer to end of buffer - uintptr_t* iv_ptrToHead; //< Pointer to oldest Entry (time wise) bool iv_isBufferValid; //< Indicates an initialized buffer // For testing purposes only diff --git a/src/usr/trace/runtime/rt_rsvdtracebufservice.C b/src/usr/trace/runtime/rt_rsvdtracebufservice.C index 3d0c1bb95..21316e6f6 100644 --- a/src/usr/trace/runtime/rt_rsvdtracebufservice.C +++ b/src/usr/trace/runtime/rt_rsvdtracebufservice.C @@ -80,10 +80,10 @@ void RsvdTraceBufService::init() // If the data is not NULL, then retrieve crashed data // I want NULL in this case, not nullptr; *l_addressToHead is an int. // If I use nullptr; compiler complains - //if (*l_addressToHead != NULL) - //{ - // retrieveDataFromLastCrash(); - //} + if (*l_addressToHead != NULL) + { + retrieveDataFromLastCrash(); + } // After gathering trace info from previous crash, clear buffer data iv_rsvdTraceBuffer.clearBuffer(); diff --git a/src/usr/trace/runtime/test/testrsvdtracebuf.H b/src/usr/trace/runtime/test/testrsvdtracebuf.H index 148df5d07..0b6374ba7 100644 --- a/src/usr/trace/runtime/test/testrsvdtracebuf.H +++ b/src/usr/trace/runtime/test/testrsvdtracebuf.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2013,2018 */ +/* Contributors Listed Below - COPYRIGHT 2013,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -25,10 +25,8 @@ #include <cxxtest/TestSuite.H> #include <trace/runtime/rt_rsvdtracebuffer.H> // TRACE::RsvdTraceBuffer -#include <trace/runtime/rt_rsvdtracebufservice.H> // TRACE::RsvdTraceBufService -#include <trace/entry.H> // TRACE::Entry -#include <trace/compdesc.H> // TRACE::ComponentDesc -#include <util/runtime/util_rt.H> // hb_get_rt_rsvd_mem +#include <trace/entry.H> // TRACE::Entry +#include <trace/compdesc.H> // TRACE::ComponentDesc #include <stdint.h> // uint32_t #include <stdlib.h> // malloc @@ -83,7 +81,7 @@ void testRsvdTraceBuffConstructor() } TRACFCOMP(g_trac_test, EXIT_MRK"RsvdTraceBuffTestSuite:%s", __func__); -} // void testRsvdTraceBuffConstructor() +} // end void testRsvdTraceBuffConstructor // Some more simple tests - the initializer void testRsvdTraceBuffInit() @@ -108,7 +106,7 @@ void testRsvdTraceBuffInit() l_addressToHead); char* l_bufferBegin = reinterpret_cast<char*>(l_bufferAddr + - sizeof(uintptr_t)); + (2 * sizeof(uintptr_t))); char* l_bufferEnd = reinterpret_cast<char*>(l_bufferAddr + l_bufferSize - 1); @@ -155,7 +153,7 @@ void testRsvdTraceBuffInit() } TRACFCOMP(g_trac_test, EXIT_MRK"RsvdTraceBuffTestSuite:%s", __func__); -} // end void testRsvdTraceBuffInit() +} // end void testRsvdTraceBuffInit // Test where buffer is too small to accommodate any Entry size void testRsvdTraceBuffBufferToSmall() @@ -225,7 +223,7 @@ void testRsvdTraceBuffBufferToSmall() free(l_buffer); TRACFCOMP(g_trac_test, EXIT_MRK"RsvdTraceBuffTestSuite:%s", __func__); -} // end void testRsvdTraceBuffBufferToSmall() +} // end void testRsvdTraceBuffBufferToSmall // Test where buffer is just the right size to fit a single Entry void testRsvdTraceBuffOnlyAccommodateOneItem() @@ -283,7 +281,8 @@ void testRsvdTraceBuffOnlyAccommodateOneItem() TS_FAIL("%s:%s: Pointer to list is not correct", __FILE__, __func__); } - if (true != runSelfDiagnostics(l_rsvd)) + uint32_t l_itemCount(0); + if (true != runSelfDiagnostics(l_rsvd, l_itemCount)) { TS_FAIL("%s:%s: self diagnostics discovered an error", __FILE__, __func__); @@ -329,7 +328,8 @@ void testRsvdTraceBuffOnlyAccommodateOneItem() TS_FAIL("%s:%s: Pointer to list is not correct", __FILE__, __func__); } - if (true != runSelfDiagnostics(l_rsvd)) + l_itemCount = 0; + if (true != runSelfDiagnostics(l_rsvd, l_itemCount)) { TS_FAIL("%s:%s: self diagnostics discovered an error", __FILE__, __func__); @@ -354,7 +354,8 @@ void testRsvdTraceBuffOnlyAccommodateOneItem() TS_FAIL("%s:%s: Pointer to list is not correct", __FILE__, __func__); } - if (true != runSelfDiagnostics(l_rsvd)) + l_itemCount = 0; + if (true != runSelfDiagnostics(l_rsvd, l_itemCount)) { TS_FAIL("%s:%s: self diagnostics discovered an error", __FILE__, __func__); @@ -363,7 +364,7 @@ void testRsvdTraceBuffOnlyAccommodateOneItem() free(l_buffer); TRACFCOMP(g_trac_test, EXIT_MRK"RsvdTraceBuffTestSuite:%s", __func__); -} // end void testRsvdTraceBuffOnlyAccommodateOneItem() +} // end void testRsvdTraceBuffOnlyAccommodateOneItem // Test where buffer is just the right size to fit a single Entry plus size void testRsvdTraceBuffOnlyAccommodateOneItemPlusSize() @@ -378,7 +379,7 @@ void testRsvdTraceBuffOnlyAccommodateOneItemPlusSize() l_rsvd); // Adjust buffer to the area we are interested in - char* l_buffer = l_fullBuffer + sizeof(uintptr_t); + char* l_buffer = l_fullBuffer + (2 * sizeof(uintptr_t)); if (l_rsvd.getBufferSize() != l_bufferSize) { @@ -434,8 +435,8 @@ void testRsvdTraceBuffOnlyAccommodateOneItemPlusSize() __FILE__, __func__); } - - if (true != runSelfDiagnostics(l_rsvd)) + uint32_t l_itemCount(0); + if (true != runSelfDiagnostics(l_rsvd, l_itemCount)) { TS_FAIL("%s:%s: self diagnostics discovered an error", __FILE__, __func__); @@ -533,7 +534,8 @@ void testRsvdTraceBuffOnlyAccommodateOneItemPlusSize() __FILE__, __func__); } - if (true != runSelfDiagnostics(l_rsvd)) + l_itemCount = 0; + if (true != runSelfDiagnostics(l_rsvd, l_itemCount)) { TS_FAIL("%s:%s: self diagnostics discovered an error", __FILE__, __func__); @@ -603,7 +605,8 @@ void testRsvdTraceBuffOnlyAccommodateOneItemPlusSize() __FILE__, __func__); } - if (true != runSelfDiagnostics(l_rsvd)) + l_itemCount = 0; + if (true != runSelfDiagnostics(l_rsvd, l_itemCount)) { TS_FAIL("%s:%s: self diagnostics discovered an error", __FILE__, __func__); @@ -682,7 +685,7 @@ void testRsvdTraceBuffOnlyAccommodateOneItemPlusSize() free(l_fullBuffer); TRACFCOMP(g_trac_test, EXIT_MRK"RsvdTraceBuffTestSuite:%s", __func__); -} // end void testRsvdTraceBuffOnlyAccommodateOneItemPlusSize() +} // end void testRsvdTraceBuffOnlyAccommodateOneItemPlusSize // Test where buffer is just the right size to fit two Entries void testRsvdTraceBuffOnlyAccommodateTwoItems() @@ -697,7 +700,7 @@ void testRsvdTraceBuffOnlyAccommodateTwoItems() l_rsvd); // Adjust buffer to the area we are interested in - char* l_buffer = l_fullBuffer + sizeof(uintptr_t); + char* l_buffer = l_fullBuffer + (2 * sizeof(uintptr_t)); if (l_rsvd.getBufferSize() != l_bufferSize) { @@ -741,7 +744,8 @@ void testRsvdTraceBuffOnlyAccommodateTwoItems() __FILE__, __func__); } - if (true != runSelfDiagnostics(l_rsvd)) + uint32_t l_itemCount(0); + if (true != runSelfDiagnostics(l_rsvd, l_itemCount)) { TS_FAIL("%s:%s: self diagnostics discovered an error", __FILE__, __func__); @@ -790,7 +794,8 @@ void testRsvdTraceBuffOnlyAccommodateTwoItems() __FILE__, __func__); } - if (true != runSelfDiagnostics(l_rsvd)) + l_itemCount = 0; + if (true != runSelfDiagnostics(l_rsvd, l_itemCount)) { TS_FAIL("%s:%s: self diagnostics discovered an error", __FILE__, __func__); @@ -833,7 +838,8 @@ void testRsvdTraceBuffOnlyAccommodateTwoItems() __FILE__, __func__); } - if (true != runSelfDiagnostics(l_rsvd)) + l_itemCount = 0; + if (true != runSelfDiagnostics(l_rsvd, l_itemCount)) { TS_FAIL("%s:%s: self diagnostics discovered an error", __FILE__, __func__); @@ -887,7 +893,8 @@ void testRsvdTraceBuffOnlyAccommodateTwoItems() __FILE__, __func__); } - if (true != runSelfDiagnostics(l_rsvd)) + l_itemCount = 0; + if (true != runSelfDiagnostics(l_rsvd, l_itemCount)) { TS_FAIL("%s:%s: self diagnostics discovered an error", __FILE__, __func__); @@ -912,7 +919,7 @@ void testRsvdTraceBuffTestTheEnds() l_rsvd); // Adjust buffer to the area we are interested in - char* l_buffer = l_fullBuffer + sizeof(uintptr_t); + char* l_buffer = l_fullBuffer + (2 * sizeof(uintptr_t)); if (l_rsvd.getBufferSize() != l_bufferSize) { @@ -991,7 +998,8 @@ void testRsvdTraceBuffTestTheEnds() __FILE__, __func__); } - if (true != runSelfDiagnostics(l_rsvd)) + uint32_t l_itemCount(0); + if (true != runSelfDiagnostics(l_rsvd, l_itemCount)) { TS_FAIL("%s:%s: self diagnostics discovered an error", __FILE__, __func__); @@ -1028,7 +1036,8 @@ void testRsvdTraceBuffTestTheEnds() __FILE__, __func__); } - if (true != runSelfDiagnostics(l_rsvd)) + l_itemCount = 0; + if (true != runSelfDiagnostics(l_rsvd, l_itemCount)) { TS_FAIL("%s:%s: self diagnostics discovered an error", __FILE__, __func__); @@ -1064,7 +1073,8 @@ void testRsvdTraceBuffTestTheEnds() __FILE__, __func__); } - if (true != runSelfDiagnostics(l_rsvd)) + l_itemCount = 0; + if (true != runSelfDiagnostics(l_rsvd, l_itemCount)) { TS_FAIL("%s:%s: self diagnostics discovered an error", __FILE__, __func__); @@ -1089,16 +1099,18 @@ void testRsvdTraceBuffTestReentrant () iv_buffer = initializeRsvdBuffer(iv_bufferSize, l_rsvd); + iv_bufferBeginningBoundary = l_rsvd.iv_bufferBeginningBoundary; iv_bufferEndingBoundary = l_rsvd.iv_bufferEndingBoundary; // Adjust buffer to the area we are interested in - char* l_buffer = iv_buffer + sizeof(uintptr_t); + char* l_buffer = iv_buffer + (2 * sizeof(uintptr_t)); - if (l_rsvd.getBufferSize() != iv_bufferSize) + if (l_rsvd.getBufferSize() != (iv_bufferSize - sizeof(uintptr_t))) { - TS_FAIL("%s:%s: buffer size is not correct", - __FILE__, __func__); + TS_FAIL("%s:%s: buffer size is not correct %d %d", + __FILE__, __func__, l_rsvd.getBufferSize(), + (iv_bufferSize - sizeof(uintptr_t))); } if (true != l_rsvd.isBufferValid()) @@ -1149,7 +1161,8 @@ void testRsvdTraceBuffTestReentrant () __FILE__, __func__); } - if (true != runSelfDiagnostics(l_rsvd)) + uint32_t l_itemCount(0); + if (true != runSelfDiagnostics(l_rsvd, l_itemCount)) { TS_FAIL("%s:%s: self diagnostics discovered an error", __FILE__, __func__); @@ -1168,7 +1181,7 @@ void testRsvdTraceBuffTestReentrant2() TRACE::RsvdTraceBuffer l_rsvd; initializeRsvdBufferForReentrant(l_rsvd); - if (l_rsvd.getBufferSize() != iv_bufferSize) + if (l_rsvd.getBufferSize() != (iv_bufferSize - sizeof(uintptr_t))) { TS_FAIL("%s:%s: buffer size is not correct", __FILE__, __func__); @@ -1196,7 +1209,8 @@ void testRsvdTraceBuffTestReentrant2() TS_FAIL("%s:%s: buffer is not valid", __FILE__, __func__); } - if (true != runSelfDiagnostics(l_rsvd)) + uint32_t l_itemCount(0); + if (true != runSelfDiagnostics(l_rsvd, l_itemCount)) { TS_FAIL("%s:%s: self diagnostics discovered an error", __FILE__, __func__); @@ -1259,7 +1273,7 @@ void testRsvdTraceBuffTestReentrant3() TRACE::RsvdTraceBuffer l_rsvd; initializeRsvdBufferForReentrant(l_rsvd); - if (l_rsvd.getBufferSize() != iv_bufferSize) + if (l_rsvd.getBufferSize() != (iv_bufferSize - sizeof(uintptr_t))) { TS_FAIL("%s:%s: buffer size is not correct", __FILE__, __func__); @@ -1353,7 +1367,7 @@ void testRsvdTraceBuffTestReentrant4() TRACE::RsvdTraceBuffer l_rsvd; initializeRsvdBufferForReentrant(l_rsvd); - if (l_rsvd.getBufferSize() != iv_bufferSize) + if (l_rsvd.getBufferSize() != (iv_bufferSize - sizeof(uintptr_t))) { TS_FAIL("%s:%s: buffer size is not correct", __FILE__, __func__); @@ -1423,7 +1437,7 @@ void testRsvdTraceBuffTestReentrant5() TRACE::RsvdTraceBuffer l_rsvd; initializeRsvdBufferForReentrant(l_rsvd); - if (l_rsvd.getBufferSize() != iv_bufferSize) + if (l_rsvd.getBufferSize() != (iv_bufferSize - sizeof(uintptr_t))) { TS_FAIL("%s:%s: buffer size is not correct", __FILE__, __func__); @@ -1474,11 +1488,175 @@ void testRsvdTraceBuffTestReentrant5() TRACFCOMP(g_trac_test, EXIT_MRK"RsvdTraceBuffTestSuite:%s", __func__); } // end void testRsvdTraceBuffTestReentrant5 +// Test when the buffer has been relocated +// To simulate that the buffer has been relocated in memory and the pointers +// within the buffer corrected, I create a buffer and divided it into +// 3 sections. I populate the middle section with data and verify that it +// is valid. Then I copy the middle buffer data over to the top section, +// basically a memory location before the middle buffer. Zero out the middle +// section to keep myself honest, then hand that buffer over to the +// RsvdTraceBuffer class, which should detect that the buffer has been relocated +// and correct the pointers. Once the RsvdTraceBuffer class has worked it's +// magic, the buffer is tested for correctness. I repeat this process by +// moving the buffer data to the bottom buffer, basically a memory location +// after the top and repeat this test. +void testRsvdTraceBuffTestBufferRelocation() +{ + TRACFCOMP(g_trac_test, ENTER_MRK"RsvdTraceBuffTestSuite:%s", __func__); + + // Size of each buffer segment (top buffer, middle buffer, bottom buffer) + const uint32_t SEGMENT_BUFFER_SIZE = 1024; + const uint32_t NUM_SEGMENTS = 3; + // Aggregate the size of the 3 buffer segments. + uint32_t l_bufferSize = NUM_SEGMENTS * SEGMENT_BUFFER_SIZE; + // Create the buffer of all combined segments and 'zero' out + char l_buffer[l_bufferSize]; + memset(l_buffer, 0, l_bufferSize); + + // Segment the buffer into 3 sections, top, middle, bottom + char * l_niflheim = l_buffer; + char * l_midgard = &(l_buffer[1 * SEGMENT_BUFFER_SIZE]); + char * l_muspelheim = &(l_buffer[2 * SEGMENT_BUFFER_SIZE]); + + uint32_t l_itemCount(0); + uint32_t l_expectedItemCount(3); + TRACE::RsvdTraceBuffer l_rsvd; + + // Populate middle buffer with data and verify it is correct + // This is just setting up the data before simulating a relocation + { + // Get the address of buffer + uintptr_t l_bufferAddr = reinterpret_cast<uintptr_t>(l_midgard); + + // Get a pointer to where the list head needs to reside in the buffer + uintptr_t *l_addressToListHead = reinterpret_cast<uintptr_t *>(l_bufferAddr); + + + l_rsvd.init(SEGMENT_BUFFER_SIZE - sizeof(uintptr_t), // subtract list head pointer + l_bufferAddr + sizeof(uintptr_t), // 'hop' over list head pointer + l_addressToListHead); + + // populate the middle buffer (l_midgard) with data + l_rsvd.insertEntry(sizeof(TRACE::Entry) + 20); + l_rsvd.insertEntry(sizeof(TRACE::Entry) + 5); + l_rsvd.insertEntry(sizeof(TRACE::Entry) + 30); + + // Validate the buffer + l_itemCount = 0; + if (true != runSelfDiagnostics(l_rsvd, l_itemCount)) + { + TS_FAIL("%s:%s: Entry datas in midgard are corrupt", + __FILE__, __func__); + } + + if (l_itemCount != l_expectedItemCount) + { + TS_FAIL("%s:%s: The number of items found in midgard is incorrect, " + " expected %d, but got back %d", + __FILE__, __func__, l_expectedItemCount, l_itemCount); + } + } + + // Copy data over to the top buffer and clear out the middle buffer + // Simulate a relocation of the buffer to a memory address that precedes + // the original buffer's memory location + memcpy(l_niflheim, l_midgard, SEGMENT_BUFFER_SIZE); + memset(l_midgard, 0, SEGMENT_BUFFER_SIZE); + + // Test the top buffer + { + // Get the address of buffer + uintptr_t l_bufferAddr = reinterpret_cast<uintptr_t>(l_niflheim); + + // Get a pointer to where the list head needs to reside in the buffer + uintptr_t *l_addressToListHead = reinterpret_cast<uintptr_t *>(l_bufferAddr); + + // First invalidate buffer + // We need to invalidate the buffer before using it again. Saying + // it is invalid is probably a misnomer here, it really should be + // 'buffer is not initialized'. In a real situation, HB would have + // crashed and restarted. The validity of the buffer would be false + // since that info is not persisted. The buffer gets initialized with + // buffer data, which may or may not be empty. During the + // initialization the buffer gets evaluated to see if there is crash + // data to retrieve and a buffer that may or may not need the pointers + // corrected. + l_rsvd.iv_isBufferValid = false; + l_rsvd.init(SEGMENT_BUFFER_SIZE - sizeof(uintptr_t), // subtract list head pointer + l_bufferAddr + sizeof(uintptr_t), // 'hop' over list head pointer + l_addressToListHead); + + // Validate the buffer + l_itemCount = 0; + if (true != runSelfDiagnostics(l_rsvd, l_itemCount)) + { + TS_FAIL("%s:%s: Entry datas in niflheim are corrupt", + __FILE__, __func__); + } + + if (l_itemCount != l_expectedItemCount) + { + TS_FAIL("%s:%s: The number of items found in niflheim is incorrect, " + " expected %d, but got back %d", + __FILE__, __func__, l_expectedItemCount, l_itemCount); + + } + } + + // Copy data over to the bottom buffer and clear out the top buffer + // Simulate a relocation of the buffer to a memory address that succeeds + // the original buffer's memory location + memcpy(l_muspelheim, l_niflheim, SEGMENT_BUFFER_SIZE); + memset(l_niflheim, 0, SEGMENT_BUFFER_SIZE); + + // Test the bottom buffer + { + // Get the address of buffer + uintptr_t l_bufferAddr = reinterpret_cast<uintptr_t>(l_muspelheim); + + // Get a pointer to where the list head needs to reside in the buffer + uintptr_t *l_addressToListHead = reinterpret_cast<uintptr_t *>(l_bufferAddr); + + // First invalidate buffer + // We need to invalidate the buffer before using it again. Saying + // it is invalid is probably a misnomer here, it really should be + // 'buffer is not initialized'. In a real situation, HB would have + // crashed and restarted. The validity of the buffer would be false + // since that info is not persisted. The buffer gets initialized with + // buffer data, which may or may not be empty. During the + // initialization the buffer gets evaluated to see if there is crash + // data to retrieve and a buffer that may or may not need the pointers + // corrected. + l_rsvd.iv_isBufferValid = false; + l_rsvd.init(SEGMENT_BUFFER_SIZE - sizeof(uintptr_t), // subtract list head pointer + l_bufferAddr + sizeof(uintptr_t), // 'hop' over list head pointer + l_addressToListHead); + + // Validate the buffer + l_itemCount = 0; + if (true != runSelfDiagnostics(l_rsvd, l_itemCount)) + { + TS_FAIL("%s:%s: Entry datas in muspelheim are corrupt", + __FILE__, __func__); + } + + if (l_itemCount != l_expectedItemCount) + { + TS_FAIL("%s:%s: The number of items found in muspelheim is incorrect, " + " expected %d, but got back %d", + __FILE__, __func__, l_expectedItemCount, l_itemCount); + } + } + TRACFCOMP(g_trac_test, EXIT_MRK"RsvdTraceBuffTestSuite:%s", __func__); +} // end void testRsvdTraceBuffTestBufferRelocation + private: // Helpful methods to help in testing char* initializeRsvdBuffer(uint32_t i_bufferSize, TRACE::RsvdTraceBuffer& i_rsvd) { + i_bufferSize += sizeof(uintptr_t); + iv_bufferSize = i_bufferSize; // Create a buffer uint32_t l_realBufferSize = i_bufferSize + sizeof(uintptr_t); char *l_buffer = reinterpret_cast<char*>(malloc(l_realBufferSize)); @@ -1513,7 +1691,7 @@ void initializeRsvdBufferForReentrant(TRACE::RsvdTraceBuffer& i_rsvd) } -bool runSelfDiagnostics(TRACE::RsvdTraceBuffer& l_rsvd) +bool runSelfDiagnostics(TRACE::RsvdTraceBuffer& l_rsvd, uint32_t & o_itemCount) { bool l_everythingChecksOut = true; uintptr_t l_bufferBeginningBoundary = l_rsvd.getAddressOfPtr @@ -1521,15 +1699,15 @@ bool runSelfDiagnostics(TRACE::RsvdTraceBuffer& l_rsvd) uintptr_t l_bufferEndingBoundary = l_rsvd.getAddressOfPtr (l_rsvd.iv_bufferEndingBoundary); + o_itemCount = 0; + if (!l_rsvd.isListEmpty()) { - uint32_t l_itemCount(0); - TRACE::Entry* l_entry = l_rsvd.getListHead(); TRACE::Entry* l_head = l_entry; do { - ++l_itemCount; + ++o_itemCount; uintptr_t l_entryAddr = l_rsvd.getAddressOfPtr(l_entry); uintptr_t l_entryAddrEnd = l_rsvd.getEndingAddressOfEntry(l_entry); @@ -1539,7 +1717,7 @@ bool runSelfDiagnostics(TRACE::RsvdTraceBuffer& l_rsvd) TS_FAIL("Item [%d] at address (0x%X) precedes the " "allocated memory location at address " "(0x%X) by %d byte(s)", - l_itemCount, l_entryAddr, l_bufferBeginningBoundary, + o_itemCount, l_entryAddr, l_bufferBeginningBoundary, (l_bufferBeginningBoundary - l_entryAddr)); l_everythingChecksOut = false; } @@ -1548,7 +1726,7 @@ bool runSelfDiagnostics(TRACE::RsvdTraceBuffer& l_rsvd) TS_FAIL("Item [%d] at address (0x%X) is beyond the " "ending allocated memory location at address " "(0x%X) by %d byte(s)", - l_itemCount, l_entryAddr, l_bufferEndingBoundary, + o_itemCount, l_entryAddr, l_bufferEndingBoundary, (l_entryAddr - l_bufferEndingBoundary)); l_everythingChecksOut = false; } @@ -1557,7 +1735,7 @@ bool runSelfDiagnostics(TRACE::RsvdTraceBuffer& l_rsvd) TS_FAIL("Item [%d] at address (0x%X) overruns the " "ending allocated memory location at address " "(0x%X) by %d byte(s)", - l_itemCount, l_entryAddr, l_bufferEndingBoundary, + o_itemCount, l_entryAddr, l_bufferEndingBoundary, (l_entryAddrEnd - l_bufferEndingBoundary)); l_everythingChecksOut = false; } @@ -1570,7 +1748,7 @@ bool runSelfDiagnostics(TRACE::RsvdTraceBuffer& l_rsvd) { TS_FAIL("Item [%d] at address (0x%X) overruns the " "next item at address (0x%X) by %d byte(s)", - l_itemCount, l_entryAddr, l_entryNextAddr, + o_itemCount, l_entryAddr, l_entryNextAddr, (l_entryAddrEnd - l_entryNextAddr + 1)); l_everythingChecksOut = false; } |