diff options
author | Jaymes Wilks <mjwilks@us.ibm.com> | 2017-06-29 16:26:06 -0500 |
---|---|---|
committer | Daniel M. Crowell <dcrowell@us.ibm.com> | 2017-07-19 14:18:31 -0400 |
commit | 80631edd1d39c7bc5d0081f8ce0b792903d1955d (patch) | |
tree | 012f705cd9f2a7898534d075acd9f39d8935dec3 /src | |
parent | 48a8ff9008c000ce8b50708448a74f259c01d9d6 (diff) | |
download | talos-hostboot-80631edd1d39c7bc5d0081f8ce0b792903d1955d.tar.gz talos-hostboot-80631edd1d39c7bc5d0081f8ce0b792903d1955d.zip |
Generate range check code for persistent read/write attributes
This change to xmltobh.pl adds support for a new range tag in
attribute_types.xml and generates range checking code when the
new range tag is present for an attribute.
Change-Id: Ib602b80e18d717fccd9cb8512f004c73be891bda
RTC:163084
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/42625
Reviewed-by: Nicholas E. Bofferding <bofferdn@us.ibm.com>
Reviewed-by: Michael Baiocchi <mbaiocch@us.ibm.com>
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Stephen M. Cprek <smcprek@us.ibm.com>
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/include/usr/targeting/common/target.H | 19 | ||||
-rw-r--r-- | src/include/usr/targeting/common/targreasoncodes.H | 2 | ||||
-rw-r--r-- | src/usr/targeting/attrcheck_errl.C | 34 | ||||
-rw-r--r-- | src/usr/targeting/common/xmltohb/attribute_types.xml | 4 | ||||
-rwxr-xr-x | src/usr/targeting/common/xmltohb/xmltohb.pl | 221 |
5 files changed, 273 insertions, 7 deletions
diff --git a/src/include/usr/targeting/common/target.H b/src/include/usr/targeting/common/target.H index bbbfe089d..0681da27f 100644 --- a/src/include/usr/targeting/common/target.H +++ b/src/include/usr/targeting/common/target.H @@ -762,7 +762,7 @@ void setFrequencyAttributes(Target * i_sys, * and halts the IPL. * * @param[in] i_pTarget The target associated with the attribute that failed - * enum value checking. + * enum value checking. Cannot be nullptr. * @param[in] i_attr The attribute id of the attribute that failed enum * value checking. * @param[in] i_invalidValue The invalid value that failed the enum check. @@ -771,6 +771,23 @@ void handleEnumCheckFailure(const Target* i_pTarget, const ATTRIBUTE_ID i_attr, const uint64_t i_invalidValue); +// Function to handle secureboot attribute range check failures +/** + * @brief Creates an error log with target and attribute information + * and halts the IPL. + * + * @param[in] i_pTarget The target associated with the attribute that failed. + * Cannot be nullptr. + * + * @param[in] i_attr The attribute id of the attribute that failed + * + * @param[in] i_outOfRangeValue The value that was out of range + */ +void handleRangeCheckFailure(const Target* i_pTarget, + const ATTRIBUTE_ID i_attr, + const uint64_t i_outOfRangeValue); + + // The following #include ensures that persistent read/write attributes are // value-checked for validity upon calling getAttr. This is done via // autogenerated template specializations for each attribute. External calls diff --git a/src/include/usr/targeting/common/targreasoncodes.H b/src/include/usr/targeting/common/targreasoncodes.H index 18d7c6726..92d9611c4 100644 --- a/src/include/usr/targeting/common/targreasoncodes.H +++ b/src/include/usr/targeting/common/targreasoncodes.H @@ -49,6 +49,7 @@ enum TargetingModuleId TARG_CREATE_VMM_SECTIONS = 0x09, TARG_APPLY_ATTR_OVER = 0x0A, TARG_HANDLE_ENUM_CHECK_FAILURE = 0x0B, + TARG_HANDLE_RANGE_CHECK_FAILURE = 0x0C, }; enum TargetingReasonCode @@ -75,6 +76,7 @@ enum TargetingReasonCode TARG_RC_APPLY_ATTR_OVER_NOT_ALLOWED = TARG_COMP_ID | 0x14, TARG_RC_MM_BLOCK_UNMAP_FAIL = TARG_COMP_ID | 0x15, TARG_RC_ATTRIBUTE_ENUM_CHECK_FAIL = TARG_COMP_ID | 0x16, + TARG_RC_ATTRIBUTE_RANGE_CHECK_FAIL = TARG_COMP_ID | 0x17, }; }; // End TARGETING namespace diff --git a/src/usr/targeting/attrcheck_errl.C b/src/usr/targeting/attrcheck_errl.C index 31a716779..13dd949d0 100644 --- a/src/usr/targeting/attrcheck_errl.C +++ b/src/usr/targeting/attrcheck_errl.C @@ -87,6 +87,40 @@ void handleEnumCheckFailure(const Target* i_pTarget, // is advisable in most cases, including this one. SECUREBOOT::handleSecurebootFailure(err, true); } + +void handleRangeCheckFailure(const Target* i_pTarget, + const ATTRIBUTE_ID i_attr, + const uint64_t i_outOfRangeValue) +{ + TRACFCOMP(g_trac_targeting, + "ATTRIBUTE_ID range check failed! Attribute ID = 0x%x " + "with out of range value 0x%llX", i_attr, i_outOfRangeValue); + + /*@ + * @errortype + * @moduleid TARGETING::TARG_HANDLE_RANGE_CHECK_FAILURE + * @reasoncode TARGETING::TARG_RC_ATTRIBUTE_RANGE_CHECK_FAIL + * @userdata1[00:31] Target's HUID + * @userdata1[32:64] Attribute ID + * @userdata2 Value that was out of range + * @devdesc Invalid range for attribute value. + * @custdesc Unexpected internal firmware error. + */ + auto err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TARGETING::TARG_HANDLE_RANGE_CHECK_FAILURE, + TARGETING::TARG_RC_ATTRIBUTE_RANGE_CHECK_FAIL, + TWO_UINT32_TO_UINT64( + get_huid(i_pTarget), + i_attr), + i_outOfRangeValue, + true); + + // handle the secureboot failure in the normal secureboot way + // The 'true' below indicates that we want to wait for shutdown, which + // is advisable in most cases, including this one. + SECUREBOOT::handleSecurebootFailure(err, true); +} #endif } // End namespace TARGETING diff --git a/src/usr/targeting/common/xmltohb/attribute_types.xml b/src/usr/targeting/common/xmltohb/attribute_types.xml index a13c50817..665bd72c1 100644 --- a/src/usr/targeting/common/xmltohb/attribute_types.xml +++ b/src/usr/targeting/common/xmltohb/attribute_types.xml @@ -2693,6 +2693,10 @@ <default>0</default> </int32_t> </simpleType> + <range> + <min>-100</min> + <max>0</max> + </range> <persistency>non-volatile</persistency> <readable/> <writeable/> diff --git a/src/usr/targeting/common/xmltohb/xmltohb.pl b/src/usr/targeting/common/xmltohb/xmltohb.pl index 75b6183dc..90c4817e4 100755 --- a/src/usr/targeting/common/xmltohb/xmltohb.pl +++ b/src/usr/targeting/common/xmltohb/xmltohb.pl @@ -187,7 +187,7 @@ use Digest::MD5 qw(md5_hex); # NOTE: the attribute list initially contains both real and virtual attributes my $allAttributes = $xml->XMLin($cfgHbXmlFile, forcearray => ['enumerationType','enumerator','attribute','hwpfToHbAttrMap', - 'compileAttribute']); + 'compileAttribute','range']); my $fapiAttributes = {}; if ($cfgFapiAttributesXmlFile ne "") @@ -496,6 +496,19 @@ foreach my $attrs (@{$attributes->{attribute}}) { print $rwAttrFile "$attrs->{id}\n"; push @rwPersistAttrs, $attrs; + + # do a little bit of validation for the range tag + if (exists $attrs->{range}) + { + if (!exists $attrs->{simpleType}) + { + die "Attribute $attrs->{id} must be simpleType to use range tag."; + } + elsif (exists $attrs->{simpleType}->{enumeration}) + { + die "Enumeration and range tags cannot coexist. See $attrs->{id}"; + } + } } } @@ -545,7 +558,6 @@ foreach my $attr (@rwPersistAttrs) { if (exists $attr->{simpleType} && exists $attr->{simpleType}->{enumeration}) - { my $typeId = $attr->{simpleType}->{enumeration}->{id}; if (!exists $attrEnumTypes{$typeId}) @@ -618,9 +630,7 @@ foreach my $attr (@rwPersistAttrs) . "}\n\n"; } } -print $rwAttrHFile "#endif\n"; print $rwAttrCFile "#endif // !__HOSTBOOT_RUNTIME\n"; -close $rwAttrHFile; print $rwAttrCFile <<VERBATIM; @@ -646,6 +656,21 @@ foreach my $attr (@rwPersistAttrs) VERBATIM } } +# throw in any range checked attributes +foreach my $attr (@rwPersistAttrs) +{ + if (exists $attr->{range}) + { + print $rwAttrCFile <<VERBATIM; + case (ATTR_$attr->{id}): + return tryGetAttr<ATTR_$attr->{id}>( + * reinterpret_cast< + typename AttributeTraits<ATTR_$attr->{id}>::Type* + >(io_attrData) + ); +VERBATIM + } +} print $rwAttrCFile <<VERBATIM; default: return _tryGetAttrUnsafe(i_attr, i_size, io_attrData); @@ -655,12 +680,103 @@ print $rwAttrCFile <<VERBATIM; #endif } +#if !defined(__HOSTBOOT_RUNTIME) && defined(__HOSTBOOT_MODULE) +VERBATIM +foreach my $attr (@rwPersistAttrs) +{ + if (exists $attr->{range}) + { + print $rwAttrHFile "template<>\n" + . "bool Target::tryGetAttr<ATTR_$attr->{id}>(" + . "typename AttributeTraits<ATTR_$attr->{id}>::Type& o_attrValue)" + . " const;\n\n"; + print $rwAttrCFile "template<>\n" + . "bool Target::tryGetAttr<ATTR_$attr->{id}>(" + . "typename AttributeTraits<ATTR_$attr->{id}>::Type& o_attrValue)" + . " const\n" + . "{\n" + . " bool l_read = _tryGetAttrUnsafe(ATTR_$attr->{id}," + . "sizeof(o_attrValue),&o_attrValue);\n" + . " if (l_read)\n" + . " {\n"; + my $valueString = ""; + my $extraIndent = ""; + # persence of simpleType tag confirmed previously + my $isArrayType = exists $attr->{simpleType}->{array}; + if ($isArrayType) + { + my $arrayTag = "$attr->{simpleType}->{array}"; + my $arraySize = getArrayTagTotalSize($arrayTag); + my $numDimensions = getArrayNumDimensions($arrayTag); + my $arrayPrefix = ""; + $extraIndent = " "; + for (my $i=0; $i < $numDimensions - 1; $i++) + { + $arrayPrefix = "$arrayPrefix*"; + } + print $rwAttrCFile "" + . " for(int i=0; i<$arraySize; i++)\n" + . " {\n"; + $valueString = "(${arrayPrefix}o_attrValue)[i]"; + } + else + { + $valueString = "o_attrValue"; + } + if (exists $attr->{range}) + { + my @ranges = validateRangeMinsAndMaxes($attr->{range}, $attr->{id}); + print $rwAttrCFile "$extraIndent" + . " do {\n$extraIndent"; + for my $range (@ranges) + { + if (exists $range->{min} || exists $range->{max}) + { + print $rwAttrCFile " if ("; + } + if (exists $range->{min}) + { + print $rwAttrCFile "$valueString >= $range->{min}"; + } + if (exists $range->{min} && exists $range->{max}) + { + print $rwAttrCFile " && "; + } + if (exists $range->{max}) + { + print $rwAttrCFile "$valueString <= $range->{max}"; + } + if (exists $range->{min} || exists $range->{max}) + { + print $rwAttrCFile ")\n$extraIndent" + . " {\n$extraIndent" + . " break;\n$extraIndent" + . " }\n"; + } + } + print $rwAttrCFile "$extraIndent" + . " handleRangeCheckFailure(this,ATTR_$attr->{id}," + . "$valueString);\n$extraIndent" + . " } while(0);\n"; + } + if ($isArrayType) + { + print $rwAttrCFile " }\n"; + } + print $rwAttrCFile "" + . " }\n" + . " return l_read;\n" + . "}\n"; + } +} +print $rwAttrCFile <<VERBATIM; +#endif // !__HOSTBOOT_RUNTIME &&__HOSTBOOT_MODULE } // namespace TARGETING VERBATIM - +print $rwAttrHFile "#endif\n"; +close $rwAttrHFile; close $rwAttrCFile; - } # sub getArrayTagTotalSize @@ -693,6 +809,98 @@ sub getArrayNumDimensions { return $dims; } +# sub validateRangeMinsAndMaxes +# Looks at the supplied range tag to determine if it was authored correctly. +# @param[in] range - The range tag and all of its sub elements +# @param[in] attr_id - The attribute id string used for better error messages. +sub validateRangeMinsAndMaxes { + my ($range, $attr_id) = @_; + + # first check: make sure there is only one unbounded max and only one + # unbounded min + my $unboundedMins = 0; + my $unboundedMaxes = 0; + foreach my $i (@{$range}) + { + if (!exists $i->{min} && exists $i->{max}) + { + $unboundedMaxes++; + } + if (!exists $i->{max} && exists $i->{min}) + { + $unboundedMins++; + } + if (!exists $i->{max} && !exists $i->{min}) + { + die "empty range tag!"; + } + } + if ($unboundedMins > 1) + { + die "$attr_id has > 1 unbounded min in range tag: $unboundedMins"; + } + if ($unboundedMaxes > 1) + { + die "$attr_id has > 1 unbounded max in range tag: $unboundedMaxes"; + } + + # sort by mins + # if an item has no min tag assume lowest number possible + # if an item has no max tag assume highest number possible + # this puts the unbounded max at beginning and unbounded min at the end + my @rangeArray = sort { (!exists $a->{min}? "-inf": + !exists $a->{max}? "inf": $a->{min} ) <=> + (!exists $b->{min}? "-inf": + !exists $b->{max}? "inf": $b->{min} ) + } @$range; + + my $i=0; + # if the first range is an unbounded max then it stands alone + my $prevMax = "-inf"; # default prevMax is negative infinity + if (!exists @rangeArray->[$i]->{min}) + { + if (!exists @rangeArray->[$i]->{max}) + { + die "$attr_id has range tag with no min or max!"; + } + $prevMax = @rangeArray->[$i]->{max}; + $i++; + } + + # go through the list and check for undesired overlap of ranges + while (exists @rangeArray->[$i]->{min} && exists @rangeArray->[$i]->{max}) + { + if (@rangeArray->[$i]->{max} < @rangeArray->[$i]->{min}) + { + print Dumper(@rangeArray[$i]); + die "Min/max pair in <range> tag inverted!"; + } + if ($prevMax > @rangeArray->[$i]->{min}) + { + print "Previous max: $prevMax\n"; + print Dumper(@rangeArray[$i]); + die "Range overlap! Previous <max> tag $prevMax " + . "exceeds <min> tag value! @rangeArray->[$i]->{min}"; + } + $prevMax = @rangeArray->[$i]->{max}; + $i++; + } + + # check for stray min tag at the end + if (exists @rangeArray->[$i]->{min}) + { + # make sure trailing min is greater than previous max + if ($prevMax > @rangeArray->[$i]->{min}) + { + print "Previous max: $prevMax\n"; + print Dumper(@rangeArray[$i]); + die "Range overlap! Previous <max> tag $prevMax " + . "exceeds <min> tag value! @rangeArray->[$i]->{min}"; + } + } + + return @rangeArray; +} sub VALIDATION_FUNCTIONS { } @@ -768,6 +976,7 @@ sub validateAttributes { $elements{"serverwizReadonly"} = { required => 0, isscalar => 0}; $elements{"serverwizShow"} = { required => 0, isscalar => 1}; $elements{"global"} = { required => 0, isscalar => 0}; + $elements{"range"} = { required => 0, isscalar => 0}; foreach my $attribute (@{$attributes->{attribute}}) { |