From 6f1adaf68285ef70e1c69d57b01c5c7b6d7fb2e6 Mon Sep 17 00:00:00 2001 From: Nick Bofferding Date: Wed, 9 Nov 2011 18:15:33 -0600 Subject: Support host boot mutex attributes - Prevented mutex attributes from being copied in target APIs - Added target APIs to get/tryGet mutex attribute references - Added testcases to verify mutex attributes - Added mutex attribute type to XML definition - Added test mutex attribute to system target XML definition - Modified attribute compiler to support mutex attributes and restrictions - Replaced 100000 cycle loop in synctest.H with nanosleep for 10 CTX switches - Added context switch time macros to time.h - Removed context switch time macros from taskwaittest.H and renamed existing macro calls - Removed context switch time macros from synctest.H and renamed existing macro calls Change-Id: I93fecfa75e00e509fa442e4dd5c9e3fd67866e98 Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/491 Tested-by: Jenkins Server Reviewed-by: A. Patrick Williams III --- src/usr/targeting/target.C | 39 ++++++++ src/usr/targeting/test/targetingtest.H | 124 ++++++++++++++++++++++++++ src/usr/targeting/xmltohb/attribute_types.xml | 13 +++ src/usr/targeting/xmltohb/target_types.xml | 1 + src/usr/targeting/xmltohb/xmltohb.pl | 104 ++++++++++++++++++--- src/usr/testcore/kernel/taskwaittest.H | 7 +- src/usr/testcore/lib/synctest.H | 7 +- 7 files changed, 271 insertions(+), 24 deletions(-) (limited to 'src/usr') diff --git a/src/usr/targeting/target.C b/src/usr/targeting/target.C index f4950c1e7..d6946e050 100644 --- a/src/usr/targeting/target.C +++ b/src/usr/targeting/target.C @@ -124,6 +124,45 @@ void Target::_getAttrPtr( #undef TARG_FN } +//****************************************************************************** +// Target::_getHbMutexAttr +//****************************************************************************** + +mutex_t* Target::_getHbMutexAttr( + const ATTRIBUTE_ID i_attribute) const +{ + #define TARG_FN "_getHbMutexAttr()" + + void* l_pAttr = NULL; + (void)_getAttrPtr(i_attribute,l_pAttr); + + //@TODO Remove assert once release has stablized + assert(l_pAttr,"TARGETING::Target::_getHbMutexAttr<%d>: _getAttrPtr " + "returned NULL",i_attribute); + + return static_cast(l_pAttr); + + #undef TARG_FN +} + +//****************************************************************************** +// Target::_tryGetHbMutexAttr +//****************************************************************************** + +bool Target::_tryGetHbMutexAttr( + const ATTRIBUTE_ID i_attribute, + mutex_t*& o_pMutex) const +{ + #define TARG_FN "_tryGetHbMutexAttr()" + + void* l_pAttr = NULL; + (void)_getAttrPtr(i_attribute,l_pAttr); + o_pMutex = static_cast(l_pAttr); + return (l_pAttr != NULL); + + #undef TARG_FN +} + //****************************************************************************** // Target::Target //****************************************************************************** diff --git a/src/usr/targeting/test/targetingtest.H b/src/usr/targeting/test/targetingtest.H index a2a25ab34..c6d732cee 100644 --- a/src/usr/targeting/test/targetingtest.H +++ b/src/usr/targeting/test/targetingtest.H @@ -44,6 +44,9 @@ #include #include #include +#include +#include +#include // This component #include @@ -54,6 +57,31 @@ #include #include +/** + * @brief Struct to hold pointers to a mutex / protected value + */ +struct MutexTestData_t +{ + mutex_t* pMutex; // Pointer to mutex + volatile uint32_t* pVar; // Pointer to value protected by mutex +}; + +/** + * @brief Function which attempts to write a protected variable + * + * @param[in] i_pData Pointer to mutex pointer/value pointer structure + * + * @return N/A + */ +void funcTestMutex(void* i_pData) +{ + MutexTestData_t* l_pData = static_cast(i_pData); + mutex_lock(l_pData->pMutex); + *(l_pData->pVar) = 1; + mutex_unlock(l_pData->pMutex); + task_end(); +} + class TargetingTestSuite: public CxxTest::TestSuite { public: @@ -1336,6 +1364,102 @@ class TargetingTestSuite: public CxxTest::TestSuite TS_TRACE(EXIT_MRK "testCentaurs" ); } + + void testHbMutexAttr() + { + TS_TRACE(ENTER_MRK "testHbMutexAttr" ); + + using namespace TARGETING; + using namespace fapi; + + do { + + // Get a reference to the target service + TargetService& l_targetService = targetService(); + + // Get the system target containing the test mutex + TARGETING::Target* l_pTarget = NULL; + (void) l_targetService.getTopLevelTarget(l_pTarget); + if (l_pTarget == NULL) + { + TS_FAIL("Top level target handle is NULL"); + break; + } + + // Get the mutex attribute (actually a mutex_t* which points to + // a mutex) + HB_MUTEX_TEST_LOCK_ATTR l_pLock + = l_pTarget->getHbMutexAttr(); + + // Test: Verify the value pointed to by the mutex_t* is zero + if ( (*reinterpret_cast(l_pLock)) != 0) + { + TS_FAIL("Mutex attribute must be initialized to zero, but got %ld", + *reinterpret_cast(l_pLock)); + break; + } + + // Try to get the attribute, and ensure it's the same + HB_MUTEX_TEST_LOCK_ATTR l_pLockTry = NULL; + if(l_pTarget->tryGetHbMutexAttr + (l_pLockTry)) + { + if(l_pLockTry != l_pLock) + { + TS_FAIL("Mutex attributes should match, but dont. " + "l_pLockTry = %ld, l_pLock = %ld",l_pLockTry, + l_pLock); + break; + } + } + else + { + TS_FAIL("Mutex attribute tryGet failed, even though it exists"); + break; + } + + // Create a structue holding pointers to the mutex and a protected value + volatile uint32_t l_var = 0; + (void)mutex_lock(l_pLock); + MutexTestData_t l_mutexTestData = { l_pLock, &l_var }; + + // Spawn off a function which tries to write the protected value to + // something unexpected. If the mutex is working, the for loop will + // always poll the expected value. + task_create(funcTestMutex, static_cast(&l_mutexTestData)); + + // Guarantee the child process runs and blocks on the mutex prior to + // modifying the protected value. isync to ensure the processor doesn't + // speculatively perform the comparison prior to the sleep completing + nanosleep(0,TEN_CTX_SWITCHES_NS); isync(); + + if(l_var != 0) + { + TS_FAIL("Protected value must be 0, was %d instead",l_var); + break; + } + + // Now unlock the mutex, allowing the other thread to overwrite the + // protected value; which should happen within 100,000 reads of the + // var. This will confirm the other thread was actively trying to + // write the controlled value + (void)mutex_unlock(l_pLock); + + // Guarantee the child process acquires the mutex and modifies the + // protected value; isync to ensure the processor doesn't speculatively + // perform the comparison prior to the sleep completing + nanosleep(0,TEN_CTX_SWITCHES_NS); isync(); + + if(l_var != 1) + { + TS_FAIL("Protected value must now be 1, was %d instead",l_var); + break; + } + + } while(0); + + TS_TRACE(EXIT_MRK "testHbMutexAttr"); + } }; #endif // End __TESTTARGETING_H diff --git a/src/usr/targeting/xmltohb/attribute_types.xml b/src/usr/targeting/xmltohb/attribute_types.xml index 8c0f7dbf8..c7f1d42c9 100644 --- a/src/usr/targeting/xmltohb/attribute_types.xml +++ b/src/usr/targeting/xmltohb/attribute_types.xml @@ -951,5 +951,18 @@ + + HB_MUTEX_TEST_LOCK + Host boot mutex for testing + + + 0 + + + volatile-zeroed + + + + diff --git a/src/usr/targeting/xmltohb/target_types.xml b/src/usr/targeting/xmltohb/target_types.xml index fe44b7970..1b97633c3 100644 --- a/src/usr/targeting/xmltohb/target_types.xml +++ b/src/usr/targeting/xmltohb/target_types.xml @@ -64,6 +64,7 @@ SCRATCH_UINT64_ARRAY_1 SCRATCH_UINT64_ARRAY_2 NUMERIC_POD_TYPE_TEST + HB_MUTEX_TEST_LOCK DUMMY_RW XSCOM_BASE_ADDRESS diff --git a/src/usr/targeting/xmltohb/xmltohb.pl b/src/usr/targeting/xmltohb/xmltohb.pl index b067e0e8e..c4443b0bb 100755 --- a/src/usr/targeting/xmltohb/xmltohb.pl +++ b/src/usr/targeting/xmltohb/xmltohb.pl @@ -1162,6 +1162,18 @@ sub writeTraitFileTraits { $traits .= " $trait,"; } } + + # Mark the attribute as being a host boot mutex or non-host boot mutex + if( (exists $attribute->{simpleType}) + && (exists $attribute->{simpleType}->{hbmutex}) ) + { + $traits .= " hbMutex,"; + } + else + { + $traits .= " notHbMutex,"; + } + chop($traits); # Build value type @@ -1460,6 +1472,34 @@ sub defaultEnum { return $enumerationType->{default}; } +################################################################################ +# Do nothing +################################################################################ + +sub null { + +} + +################################################################################ +# Enforce special host boot mutex restrictions +################################################################################ + +sub enforceHbMutex { + my($attribute,$value) = @_; + + if($value != 0) + { + fatal("HB mutex attribute default must always be 0, " + . "was $value instead."); + } + + if($attribute->{persistency} ne "volatile-zeroed") + { + fatal("HB mutex attribute persistency must be volatile-zeroed, " + . "was $attribute->{persistency} instead"); + } +} + ################################################################################ # Get hash ref to supported simple types and their properties ################################################################################ @@ -1470,15 +1510,16 @@ sub simpleTypeProperties { # Intentionally didn't wrap these to 80 columns to keep them lined up and # more readable/editable - $typesHoH{"int8_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "int8_t" , bytes => 1, bits => 8 , default => \&defaultZero, packfmt => "C" }; - $typesHoH{"int16_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "int16_t" , bytes => 2, bits => 16, default => \&defaultZero, packfmt => "n" }; - $typesHoH{"int32_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "int32_t" , bytes => 4, bits => 32, default => \&defaultZero, packfmt => "N" }; - $typesHoH{"int64_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "int64_t" , bytes => 8, bits => 64, default => \&defaultZero, packfmt =>\&packQuad}; - $typesHoH{"uint8_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "uint8_t" , bytes => 1, bits => 8 , default => \&defaultZero, packfmt => "C" }; - $typesHoH{"uint16_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "uint16_t" , bytes => 2, bits => 16, default => \&defaultZero, packfmt => "n" }; - $typesHoH{"uint32_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "uint32_t" , bytes => 4, bits => 32, default => \&defaultZero, packfmt => "N" }; - $typesHoH{"uint64_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "uint64_t" , bytes => 8, bits => 64, default => \&defaultZero, packfmt =>\&packQuad}; - $typesHoH{"enumeration"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 0, typeName => "XMLTOHB_USE_PARENT_ATTR_ID" , bytes => 0, bits => 0 , default => \&defaultEnum, packfmt => "packEnumeration"}; + $typesHoH{"int8_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "int8_t" , bytes => 1, bits => 8 , default => \&defaultZero, alignment => 1, specialPolicies =>\&null, packfmt => "C" }; + $typesHoH{"int16_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "int16_t" , bytes => 2, bits => 16, default => \&defaultZero, alignment => 1, specialPolicies =>\&null, packfmt => "n" }; + $typesHoH{"int32_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "int32_t" , bytes => 4, bits => 32, default => \&defaultZero, alignment => 1, specialPolicies =>\&null, packfmt => "N" }; + $typesHoH{"int64_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "int64_t" , bytes => 8, bits => 64, default => \&defaultZero, alignment => 1, specialPolicies =>\&null, packfmt =>\&packQuad}; + $typesHoH{"uint8_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "uint8_t" , bytes => 1, bits => 8 , default => \&defaultZero, alignment => 1, specialPolicies =>\&null, packfmt => "C" }; + $typesHoH{"uint16_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "uint16_t" , bytes => 2, bits => 16, default => \&defaultZero, alignment => 1, specialPolicies =>\&null, packfmt => "n" }; + $typesHoH{"uint32_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "uint32_t" , bytes => 4, bits => 32, default => \&defaultZero, alignment => 1, specialPolicies =>\&null, packfmt => "N" }; + $typesHoH{"uint64_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "uint64_t" , bytes => 8, bits => 64, default => \&defaultZero, alignment => 1, specialPolicies =>\&null, packfmt =>\&packQuad}; + $typesHoH{"enumeration"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 0, typeName => "XMLTOHB_USE_PARENT_ATTR_ID" , bytes => 0, bits => 0 , default => \&defaultEnum, alignment => 1, specialPolicies =>\&null, packfmt => "packEnumeration"}; + $typesHoH{"hbmutex"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 0, typeName => "mutex_t*" , bytes => 8, bits => 64, default => \&defaultZero, alignment => 8, specialPolicies =>\&enforceHbMutex, packfmt =>\&packQuad}; return \%typesHoH; } @@ -1959,6 +2000,7 @@ sub packAttribute { my $binaryData; + my $alignment = 1; if(exists $attribute->{simpleType}) { my $simpleType = $attribute->{simpleType}; @@ -1968,6 +2010,8 @@ sub packAttribute { { if(exists $simpleTypeProperties->{$typeName}) { + $alignment = $simpleTypeProperties->{$typeName}{alignment}; + if($typeName eq "enumeration") { my $enumeration = getEnumerationType($attributes,$simpleType->{enumeration}->{id}); @@ -1982,6 +2026,10 @@ sub packAttribute { { $value = unhexify($value); } + + # Apply special policy enforcement, if any + $simpleTypeProperties-> + {$typeName}{specialPolicies}->($attribute,$value); if(ref ($simpleTypeProperties->{$typeName}{packfmt}) eq "CODE") { @@ -2056,7 +2104,7 @@ sub packAttribute { fatal("Serialization failed for attribute ID = $attribute->{id}."); } - return $binaryData; + return ($binaryData,$alignment); } ################################################################################ @@ -2302,8 +2350,15 @@ sub writeTargetingImage { if($section eq "pnor-ro") { - my $rodata = packAttribute($attributes,$attributeDef, + my ($rodata,$alignment) = packAttribute($attributes, + $attributeDef, $attrhash{$attributeId}->{default}); + + # Align the data as necessary + my $pads = ($alignment - ($offset % $alignment)) + % $alignment; + $roAttrBinData .= pack ("@".$pads); + $offset += $pads; $attributePointerBinData .= packQuad( $offset + $pnorRoBaseAddress); @@ -2314,11 +2369,18 @@ sub writeTargetingImage { } elsif($section eq "pnor-rw") { - my $rwdata = packAttribute($attributes,$attributeDef, + my ($rwdata,$alignment) = packAttribute($attributes, + $attributeDef, $attrhash{$attributeId}->{default}); #print "Wrote to pnor-rw value ",$attributeDef->{id}, ", #", $attrhash{$attributeId}->{default}," \n"; + + # Align the data as necessary + my $pads = ($alignment - ($rwOffset % $alignment)) + % $alignment; + $rwAttrBinData .= pack ("@".$pads); + $rwOffset += $pads; $attributePointerBinData .= packQuad( $rwOffset + $pnorRwBaseAddress); @@ -2330,8 +2392,15 @@ sub writeTargetingImage { } elsif($section eq "heap-zero-initialized") { - my $heapZeroInitData = packAttribute($attributes, + my ($heapZeroInitData,$alignment) = packAttribute( + $attributes, $attributeDef,$attrhash{$attributeId}->{default}); + + # Align the data as necessary + my $pads = ($alignment - ($heapZeroInitOffset + % $alignment)) % $alignment; + $heapZeroInitBinData .= pack ("@".$pads); + $heapZeroInitOffset += $pads; $attributePointerBinData .= packQuad( $heapZeroInitOffset + $heapZeroInitBaseAddr); @@ -2343,9 +2412,16 @@ sub writeTargetingImage { } elsif($section eq "heap-pnor-initialized") { - my $heapPnorInitData = packAttribute($attributes, + my ($heapPnorInitData,$alignment) = packAttribute( + $attributes, $attributeDef,$attrhash{$attributeId}->{default}); + # Align the data as necessary + my $pads = ($alignment - ($heapPnorInitOffset + % $alignment)) % $alignment; + $heapPnorInitBinData .= pack ("@".$pads); + $heapPnorInitOffset += $pads; + $attributePointerBinData .= packQuad( $heapPnorInitOffset + $heapPnorInitBaseAddr); diff --git a/src/usr/testcore/kernel/taskwaittest.H b/src/usr/testcore/kernel/taskwaittest.H index 8c59aedc7..0595d2961 100644 --- a/src/usr/testcore/kernel/taskwaittest.H +++ b/src/usr/testcore/kernel/taskwaittest.H @@ -31,9 +31,6 @@ #include #include -#define NS_PER_SEC (1000000ull) -#define TEN_CTX_SWITCHES ((NS_PER_SEC/TimeManager::TIMESLICE_PER_SEC)*10) - class TaskWaitTest : public CxxTest::TestSuite { public: @@ -153,13 +150,13 @@ class TaskWaitTest : public CxxTest::TestSuite static void WaitSomeTime(void* retval) { - nanosleep(0,TEN_CTX_SWITCHES); + nanosleep(0,TEN_CTX_SWITCHES_NS); if (retval) task_end2(retval); } static void WaitSomeLongerTime(void* retval) { - nanosleep(0, 2*TEN_CTX_SWITCHES); + nanosleep(0, 2*TEN_CTX_SWITCHES_NS); if (retval) task_end2(retval); } diff --git a/src/usr/testcore/lib/synctest.H b/src/usr/testcore/lib/synctest.H index e8b0ef1e0..e1de74843 100644 --- a/src/usr/testcore/lib/synctest.H +++ b/src/usr/testcore/lib/synctest.H @@ -35,9 +35,6 @@ #include -#define NS_PER_SEC (1000000ull) -#define TEN_CTX_SWITCHES ((NS_PER_SEC/TimeManager::TIMESLICE_PER_SEC)*10) - class SyncTest: public CxxTest::TestSuite { public: @@ -66,7 +63,7 @@ class SyncTest: public CxxTest::TestSuite mutex_lock(&mutex); task_create(func2, this); task_create(func2, this); - nanosleep(0,TEN_CTX_SWITCHES); + nanosleep(0,TEN_CTX_SWITCHES_NS); mutex_unlock(&mutex); barrier_wait(&barrier); TS_TRACE("ALL THREADS ENDED"); @@ -95,7 +92,7 @@ class SyncTest: public CxxTest::TestSuite barrier_t * barrier = &(my->barrier); mutex_lock(mutex); - for(int i = 0; i < 100000; ++i); + nanosleep(0,TEN_CTX_SWITCHES_NS); TS_TRACE("ME FIRST"); mutex_unlock(mutex); barrier_wait(barrier); -- cgit v1.2.1