#!/usr/bin/perl # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # $Source: src/usr/targeting/common/xmltohb/xmltohb.pl $ # # OpenPOWER HostBoot Project # # Contributors Listed Below - COPYRIGHT 2012,2017 # [+] International Business Machines Corp. # # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. See the License for the specific language governing # permissions and limitations under the License. # # IBM_PROLOG_END_TAG # # Purpose: # Author: Nick Bofferding # Last Updated: 09/09/2011 # # Version: 1.0 # # Change Log ********************************************************** # # End Change Log ****************************************************** use strict; ################################################################################ # Use of the following packages ################################################################################ use Getopt::Long; use Pod::Usage; use XML::Simple; use Text::Wrap; use Data::Dumper; use POSIX; use Env; use XML::LibXML; # Provides object deep copy capability to support virtual # attribute removal use Storable 'dclone'; ################################################################################ # Set PREFERRED_PARSER to XML::Parser. Otherwise it uses XML::SAX which contains # bugs that result in XML parse errors that can be fixed by adjusting white- # space (i.e. parse errors that do not make sense). ################################################################################ $XML::Simple::PREFERRED_PARSER = 'XML::Parser'; ################################################################################ # Process command line parameters, issue help text if needed ################################################################################ sub main{ } my $cfgSrcOutputDir = "."; my $cfgImgOutputDir = "."; my $cfgHbXmlFile = "./hb.xml"; my $cfgVmmConstsFile = "../../../include/usr/vmmconst.h"; my $cfgFapiAttributesXmlFile = ""; my $cfgImgOutputFile = "./targeting.bin"; my $cfgHelp = 0; my $cfgMan = 0; my $cfgVerbose = 0; my $cfgShortEnums = 0; my $cfgBigEndian = 1; my $cfgIncludeFspAttributes = 0; my $CfgSMAttrFile = ""; my $cfgAddVersionPage = 0; my $cfgBiosXmlFile = undef; my $cfgBiosSchemaFile = undef; my $cfgBiosOutputFile = undef; GetOptions("hb-xml-file:s" => \$cfgHbXmlFile, "src-output-dir:s" => \$cfgSrcOutputDir, "img-output-dir:s" => \$cfgImgOutputDir, "fapi-attributes-xml-file:s" => \$cfgFapiAttributesXmlFile, "img-output-file:s" => \$cfgImgOutputFile, "vmm-consts-file:s" => \$cfgVmmConstsFile, "short-enums!" => \$cfgShortEnums, "big-endian!" => \$cfgBigEndian, "smattr-output-file:s" => \$CfgSMAttrFile, "include-fsp-attributes!" => \$cfgIncludeFspAttributes, "version-page!" => \$cfgAddVersionPage, "bios-xml-file:s" => \$cfgBiosXmlFile, "bios-schema-file:s" => \$cfgBiosSchemaFile, "bios-output-file:s" => \$cfgBiosOutputFile, "help" => \$cfgHelp, "man" => \$cfgMan, "verbose" => \$cfgVerbose ) || pod2usage(-verbose => 0); pod2usage(-verbose => 1) if $cfgHelp; pod2usage(-verbose => 2) if $cfgMan; # Remove extraneous '/' from end of path names; use temporary version of $/ for # the chomp { local $/ = '/'; chomp($cfgSrcOutputDir); $cfgSrcOutputDir .= "/"; chomp($cfgImgOutputDir); $cfgImgOutputDir .= "/"; } if($cfgVerbose) { print STDOUT "Host boot intemediate XML model = $cfgHbXmlFile\n"; print STDOUT "Fapi attributes XML file = $cfgFapiAttributesXmlFile\n"; print STDOUT "Source output dir = $cfgSrcOutputDir\n"; print STDOUT "Image output dir = $cfgImgOutputDir\n"; print STDOUT "VMM constants file = $cfgVmmConstsFile\n"; print STDOUT "Short enums = $cfgShortEnums\n"; print STDOUT "Big endian = $cfgBigEndian\n"; print STDOUT "include-fsp-attributes = $cfgIncludeFspAttributes\n", print STDOUT "version-page = $cfgAddVersionPage\n", print STDOUT "bios-schema-file = $cfgBiosSchemaFile\n"; print STDOUT "bios-xml-file = $cfgBiosXmlFile\n"; print STDOUT "bios-output-file = $cfgBiosOutputFile\n"; } ################################################################################ # Initialize some globals ################################################################################ use constant INVALID_HUID=>0xffffffff; use constant PEER_HUID_NOT_PRESENT=>0xfffffffe; # When computing associations between targets, always store the association list # pointers in this exact order within each target object. It also must be the # case that the ASSOCIATION_TYPE enum in the target service header must declare # the corresponding enum values in this order as well use constant PARENT_BY_CONTAINMENT => "ParentByContainment"; use constant CHILD_BY_CONTAINMENT => "ChildByContainment"; use constant PARENT_BY_AFFINITY => "ParentByAffinity"; use constant CHILD_BY_AFFINITY => "ChildByAffinity"; use constant PERVASIVE_CHILD => "PervasiveChild"; use constant PARENT_PERVASIVE => "ParentPervasive"; my @associationTypes = ( PARENT_BY_CONTAINMENT, CHILD_BY_CONTAINMENT, PARENT_BY_AFFINITY, CHILD_BY_AFFINITY, PERVASIVE_CHILD, PARENT_PERVASIVE ); # Constants for attribute names (minus ATTR_ prefix) use constant ATTR_PARENT_PERVASIVE => "PARENT_PERVASIVE"; use constant ATTR_PHYS_PATH => "PHYS_PATH"; use constant ATTR_AFFINITY_PATH => "AFFINITY_PATH"; use constant ATTR_UNKNOWN => "UnknownAttributeName"; use constant ATTR_POSITION => "POSITION"; use constant ATTR_CHIP_UNIT => "CHIP_UNIT"; use constant ATTR_CLASS => "CLASS"; use constant ATTR_TYPE => "TYPE"; use constant ATTR_MODEL => "MODEL"; # Data manipulation constants use constant BITS_PER_BYTE => 8; use constant LOW_BYTE_MASK => 0xFF; use constant BYTE_RIGHT_BIT_INDEX => BITS_PER_BYTE - 1; use constant BYTES_PER_ABSTRACT_POINTER => 8; # This is the maximum total sum of (compute nodes + control nodes) possible for # any known system using this attribute compiler. It is used to reserve # space in each system target's CHILD + CHILD_BY_AFFINITY association lists # so that FSP can link a system target to multiple nodes use constant MAX_COMPUTE_AND_CONTROL_NODE_SUM => 5; my $xml = new XML::Simple (KeyAttr=>[]); use Digest::MD5 qw(md5_hex); # Until full machine parseable workbook parsing splits out all the input files, # use the intermediate representation containing the full host boot model. # Aborts application if file name not found. # NOTE: the attribute list initially contains both real and virtual attributes my $allAttributes = $xml->XMLin($cfgHbXmlFile, forcearray => ['enumerationType','enumerator','attribute','hwpfToHbAttrMap', 'compileAttribute']); my $fapiAttributes = {}; if ($cfgFapiAttributesXmlFile ne "") { $fapiAttributes = $xml->XMLin($cfgFapiAttributesXmlFile, forcearray => ['attribute']); } # save attributes defined as Target_t type my %Target_t = (); # Perform some sanity validation of the model (so we don't have to later) # Subject virtual attributes to same sanity checks validateAttributes($allAttributes); validateTargetInstances($allAttributes); validateTargetTypes($allAttributes); validateTargetTypesExtension($allAttributes); # Clone the attributes and strip out any references to virtual # attributes, then continue forward using the result as the typical # working attribute set. The original set containing virtual attributes # will be used for very specific tasks, like computing associations my $attributes = dclone $allAttributes; my %virtualAttrIds = (); for my $attr (reverse 0..((scalar @{$attributes->{attribute}})-1) ) { if(exists $attributes->{attribute}[$attr]->{virtual}) { # Found a virtual attribute; note it and remove $virtualAttrIds{$attributes->{attribute}[$attr]->{id}} = 1; splice @{$attributes->{attribute}}, $attr, 1; } } foreach my $targetType (@{$attributes->{targetType}}) { if(exists $targetType->{attribute}) { for my $attr (reverse 0..((scalar @{$targetType->{attribute}})-1)) { my $currentAttr = $targetType->{attribute}[$attr]; if( exists $currentAttr->{id} && exists $virtualAttrIds{$currentAttr->{id}} ) { # A targetType refers to the virtual attribute # so remove it splice @{$targetType->{attribute}}, $attr, 1; } } } } if($cfgIncludeFspAttributes) { handleTgtPtrAttributesFsp(\$attributes, \%Target_t); } else { handleTgtPtrAttributesHb(\$attributes, \%Target_t); } # Open the output files and write them if( !($cfgSrcOutputDir =~ "none") ) { open(ATTR_TARG_MAP_FILE,">$cfgSrcOutputDir"."targAttrOverrideData.H") or fatal("Target Attribute data file: \"$cfgSrcOutputDir" . "getTargAttrData.C\" could not be opened."); my $targAttrFile = *ATTR_TARG_MAP_FILE; writeTargAttrMap($attributes, $targAttrFile); close $targAttrFile; open(TRAIT_FILE,">$cfgSrcOutputDir"."attributetraits.H") or fatal ("Trait file: \"$cfgSrcOutputDir" . "attributetraits.H\" could not be opened."); my $traitFile = *TRAIT_FILE; writeTraitFileHeader($attributes,$traitFile); writeTraitFileTraits($attributes,$traitFile); writeTraitFileFooter($traitFile); close $traitFile; open(ATTR_FILE,">$cfgSrcOutputDir"."attributeenums.H") or fatal ("Attribute enum file: \"$cfgSrcOutputDir" . "attributeenums.H\" could not be opened."); my $enumFile = *ATTR_FILE; writeEnumFileHeader($enumFile); writeEnumFileAttrIdEnum($attributes,$enumFile); writeEnumFileAttrEnums($attributes,$enumFile); writeEnumFileFooter($enumFile); close $enumFile; open(STRING_HEADER_FILE,">$cfgSrcOutputDir"."attributestrings.H") or fatal ("Attribute string header file: \"$cfgSrcOutputDir" . "attributestrings.H\" could not be opened."); my $stringHeaderFile = *STRING_HEADER_FILE; writeStringHeaderFileHeader($stringHeaderFile); writeStringHeaderFileStrings($attributes,$stringHeaderFile); writeStringHeaderFileFooter($stringHeaderFile); close $stringHeaderFile; open(STRING_IMPLEMENTATION_FILE,">$cfgSrcOutputDir"."attributestrings.C") or fatal ("Attribute string source file: \"$cfgSrcOutputDir" . "attributestrings.C\" could not be opened."); my $stringImplementationFile = *STRING_IMPLEMENTATION_FILE; writeStringImplementationFileHeader($stringImplementationFile); writeStringImplementationFileStrings($attributes,$stringImplementationFile); writeStringImplementationFileFooter($stringImplementationFile); writeTestEntityPath($attributes); close $stringImplementationFile; open(STRUCTS_HEADER_FILE,">$cfgSrcOutputDir"."attributestructs.H") or fatal ("Attribute struct file: \"$cfgSrcOutputDir" . "attributestructs.H\" could not be opened."); my $structFile = *STRUCTS_HEADER_FILE; writeStructFileHeader($structFile); writeStructFileStructs($attributes,$structFile); writeStructFileFooter($structFile); close $structFile; open(PNOR_HEADER_DEF_FILE,">$cfgSrcOutputDir"."pnortargeting.H") or fatal ("Targeting header definition header file: \"$cfgSrcOutputDir" . "pnortargeting.H\" could not be opened."); my $pnorHeaderDefFile = *PNOR_HEADER_DEF_FILE; writeHeaderFormatHeaderFile($pnorHeaderDefFile); close $pnorHeaderDefFile; open(FAPI2_PLAT_ATTR_MACROS_FILE,">$cfgSrcOutputDir"."fapi2platattrmacros.H") or fatal ("FAPI2 platform attribute macro header file: \"$cfgSrcOutputDir" . "fapi2platattrmacros.H\" could not be opened."); my $fapi2PlatAttrMacrosHeaderFile = *FAPI2_PLAT_ATTR_MACROS_FILE; writeFapi2PlatAttrMacrosHeaderFileHeader ($fapi2PlatAttrMacrosHeaderFile); writeFapi2PlatAttrMacrosHeaderFileContent($attributes,$fapiAttributes, $fapi2PlatAttrMacrosHeaderFile); writeFapi2PlatAttrMacrosHeaderFileFooter ($fapi2PlatAttrMacrosHeaderFile); close $fapi2PlatAttrMacrosHeaderFile; open(ATTR_ATTRERRL_C_FILE,">$cfgSrcOutputDir"."errludattribute.C") or fatal ("Attribute errlog C file: \"$cfgSrcOutputDir" . "errludattribute.C\" could not be opened."); my $attrErrlCFile = *ATTR_ATTRERRL_C_FILE; writeAttrErrlCFile($attributes,$attrErrlCFile); close $attrErrlCFile; mkdir("$cfgSrcOutputDir/errl"); open(ATTR_ATTRERRL_H_FILE,">$cfgSrcOutputDir"."errl/errludattribute.H") or fatal ("Attribute errlog H file: \"$cfgSrcOutputDir" . "errl/errludattribute.H\" could not be opened."); my $attrErrlHFile = *ATTR_ATTRERRL_H_FILE; writeAttrErrlHFile($attributes,$attrErrlHFile); close $attrErrlHFile; open(ATTR_TARGETERRL_C_FILE,">$cfgSrcOutputDir"."errludtarget.C") or fatal ("Target errlog C file: \"$cfgSrcOutputDir" . "errludtarget.C\" could not be opened."); my $targetErrlCFile = *ATTR_TARGETERRL_C_FILE; writeTargetErrlCFile($attributes,$targetErrlCFile); close $targetErrlCFile; open(ATTR_TARGETERRL_H_FILE,">$cfgSrcOutputDir"."errl/errludtarget.H") or fatal ("Target errlog H file: \"$cfgSrcOutputDir" . "errl/errludtarget.H\" could not be opened."); my $targetErrlHFile = *ATTR_TARGETERRL_H_FILE; writeTargetErrlHFile($attributes,$targetErrlHFile); close $targetErrlHFile; open(ATTR_INFO_CSV_FILE,">$cfgSrcOutputDir"."targAttrInfo.csv") or fatal ("Attribute info csv file: \"$cfgSrcOutputDir" . "targAttrInfo.csv\" could not be opened."); my $attrInfoCsvFile = *ATTR_INFO_CSV_FILE; writeAttrInfoCsvFile($attributes,$attrInfoCsvFile); close $attrInfoCsvFile; open(MAP_ATTR_METADATA_H_FILE,">$cfgSrcOutputDir"."mapattrmetadata.H") or fatal ("Attribute metadata map file Header: \"$cfgSrcOutputDir" . "mapattrmetadata.H\" could not be opened."); my $attrMetadataMapHFile = *MAP_ATTR_METADATA_H_FILE; writeAttrMetadataMapHFile($attrMetadataMapHFile); close $attrMetadataMapHFile; open(MAP_ATTR_METADATA_C_FILE,">$cfgSrcOutputDir"."mapattrmetadata.C") or fatal ("Attribute metadata map C file: \"$cfgSrcOutputDir" . "mapattrmetadata.C\" could not be opened."); my $attrMetadataMapCFile = *MAP_ATTR_METADATA_C_FILE; writeAttrMetadataMapCFileHeader($attrMetadataMapCFile); writeAttrMetadataMapCFile($attributes,$attrMetadataMapCFile); writeAttrMetadataMapCFileFooter($attrMetadataMapCFile); close $attrMetadataMapCFile; open(MAP_ATTR_SIZE_H_FILE,">$cfgSrcOutputDir"."mapsystemattrsize.H") or fatal ("Attribute size map file Header: \"$cfgSrcOutputDir" . "mapsystemattrsize.H\" could not be opened."); my $attrSizeMapHFile = *MAP_ATTR_SIZE_H_FILE; writeAttrSizeMapHFile($attrSizeMapHFile); close $attrSizeMapHFile; open(MAP_ATTR_SIZE_C_FILE,">$cfgSrcOutputDir"."mapsystemattrsize.C") or fatal ("Attribute size map file: \"$cfgSrcOutputDir" . "mapsystemattrsize.C\" could not be opened."); my $attrSizeMapCFile = *MAP_ATTR_SIZE_C_FILE; writeAttrSizeMapCFileHeader($attrSizeMapCFile); writeAttrSizeMapCFile($attributes,$attrSizeMapCFile); writeAttrSizeMapCFileFooter($attrSizeMapCFile); close $attrSizeMapCFile; } use constant ATTRID => 0; use constant HUID => 1; use constant DATA => 2; use constant SECTION => 3; use constant TARGET => 4; use constant ATTRNAME => 5; my @attrDataforSM = (); #Flag which indicates if the script needs to add the 4096 bytes of version #checksum as first page in the binary file generated. my $addRO_Section_VerPage = 0; if( !($cfgImgOutputDir =~ "none") ) { #Version page will be added only if the script is called in with the flag #--version-page if ($cfgAddVersionPage) { $addRO_Section_VerPage = 1; } #Pass the $addRO_Section_VerPage into the sub rotuine my $Data = generateTargetingImage($cfgVmmConstsFile,$attributes,\%Target_t, $addRO_Section_VerPage,$allAttributes); open(PNOR_TARGETING_FILE,">$cfgImgOutputDir".$cfgImgOutputFile) or fatal ("Targeting image file: \"$cfgImgOutputDir" . "$cfgImgOutputFile\" could not be opened."); binmode(PNOR_TARGETING_FILE); print PNOR_TARGETING_FILE "$Data"; close(PNOR_TARGETING_FILE); if ($CfgSMAttrFile ne "") { generateXMLforSM(); } } exit(0); ################################################################################ # Report a fatal error and quit ################################################################################ sub DEBUG_FUNCTIONS { } sub fatal { my($msg) = @_; print STDERR "[FATAL!] $msg\n"; for(my $caller = 1; ; $caller++) { my ($package, $filename, $callerLine, $subr, $has_args, $wantarray )= caller($caller); my $line = (caller($caller-1))[2]; if(!$line) { last; } print STDERR " $caller: $subr" . "(". $line . ")\n"; } exit(1); } sub VALIDATION_FUNCTIONS { } ################################################################################ # Validates sub-elements of an element against criteria ################################################################################ sub validateSubElements { my($name,$mustBeHash,$element,$criteria) = @_; if($mustBeHash && (ref($element) ne "HASH")) { print "name=$name, mustBeHash=$mustBeHash, element=$element, criteria=$criteria \n"; fatal("$name must be in the form of a hash."); } # print keys %{$element} . "\n"; for my $subElementName (sort(keys %{$element})) { if(!exists $criteria->{$subElementName}) { fatal("$name element cannot have child element of type " . "\"$subElementName\"."); } } for my $subElementName (sort(keys %{$criteria})) { if( ($criteria->{$subElementName}{required} == 1) && (!exists $element->{$subElementName})) { fatal("$name element missing required child element " . "\"$subElementName\"."); } if(exists $element->{$subElementName} && ($criteria->{$subElementName}{isscalar} == 1) && (ref ($element->{$subElementName}) eq "HASH")) { fatal("$name element child element \"$subElementName\" should be " . "scalar, but is a hash."); } } } ################################################################################ # Validates attribute element for correctness ################################################################################ sub validateAttributes { my($attributes) = @_; my %elements = ( ); $elements{"id"} = { required => 1, isscalar => 1}; $elements{"description"} = { required => 1, isscalar => 1}; $elements{"persistency"} = { required => 1, isscalar => 1}; $elements{"fspOnly"} = { required => 0, isscalar => 0}; $elements{"hbOnly"} = { required => 0, isscalar => 0}; $elements{"readable"} = { required => 0, isscalar => 0}; $elements{"simpleType"} = { required => 0, isscalar => 0}; $elements{"complexType"} = { required => 0, isscalar => 0}; $elements{"nativeType"} = { required => 0, isscalar => 0}; $elements{"writeable"} = { required => 0, isscalar => 0}; $elements{"hasStringConversion"} = { required => 0, isscalar => 0}; $elements{"hwpfToHbAttrMap"} = { required => 0, isscalar => 0}; $elements{"display-name"} = { required => 0, isscalar => 1}; $elements{"virtual"} = { required => 0, isscalar => 0}; $elements{"tempAttribute"} = { required => 0, isscalar => 0}; $elements{"serverwizReadonly"} = { required => 0, isscalar => 0}; $elements{"serverwizHide"} = { required => 0, isscalar => 0}; foreach my $attribute (@{$attributes->{attribute}}) { validateSubElements("attribute",1,$attribute,\%elements); } } ################################################################################ # Validates field element for correctness ################################################################################ sub validateFieldElement { my($field) = @_; my %elements = ( ); $elements{"type"} = { required => 1, isscalar => 1}; $elements{"name"} = { required => 1, isscalar => 1}; $elements{"description"} = { required => 1, isscalar => 1}; $elements{"default"} = { required => 1, isscalar => 1}; $elements{"bits"} = { required => 0, isscalar => 1}; validateSubElements("field",1,$field,\%elements); } ################################################################################ # Validates target type extension elements for correctness ################################################################################ sub validateTargetTypesExtension { my($attributes) = @_; my %elements = ( ); $elements{"id"} = { required => 1, isscalar => 1}; $elements{"attribute"} = { required => 1, isscalar => 1}; foreach my $targetTypeExtension (@{$attributes->{targetTypeExtension}}) { validateSubElements("targetTypeExtension",1, $targetTypeExtension,\%elements); } } ################################################################################ # Validates target type elements for correctness ################################################################################ sub validateTargetTypes { my($attributes) = @_; my %elements = ( ); $elements{"id"} = { required => 1, isscalar => 1}; $elements{"parent"} = { required => 0, isscalar => 1}; $elements{"attribute"} = { required => 0, isscalar => 0}; $elements{"fspOnly"} = { required => 0, isscalar => 0}; $elements{"compileAttribute"} = { required => 0, isscalar => 0}; $elements{"parent_type"} = { required => 0, isscalar => 0}; foreach my $targetType (@{$attributes->{targetType}}) { validateSubElements("targetType",1,$targetType,\%elements); } } ################################################################################ # Validates target instance elements for correctness ################################################################################ sub validateTargetInstances{ my($attributes) = @_; my %elements = ( ); $elements{"id"} = { required => 1, isscalar => 1}; $elements{"type"} = { required => 1, isscalar => 1}; $elements{"attribute"} = { required => 0, isscalar => 0}; $elements{"compileAttribute"} = { required => 0, isscalar => 0}; foreach my $targetInstance (@{$attributes->{targetInstance}}) { validateSubElements("targetInstance",1,$targetInstance,\%elements); } } ################################################################################ # Convert Target_t PHYS_PATH into Peer target's HUID - FSP Specific ################################################################################ sub handleTgtPtrAttributesFsp { my($attributes) = @_; # replace PEER_TARGET attribute value with PEER's HUID foreach my $targetInstance (@{${$attributes}->{targetInstance}}) { foreach my $attr (@{$targetInstance->{attribute}}) { if (exists $attr->{default}) { if( ($attr->{default} ne "NULL") && ($attr->{id} eq "PEER_TARGET") ) { my $peerHUID = INVALID_HUID; $peerHUID = getPeerHuid($targetInstance); if($peerHUID == INVALID_HUID) { fatal("HUID for Peer Target not found for " . "Peer Target [$attr->{default}]\n"); } elsif($peerHUID == PEER_HUID_NOT_PRESENT) { # Might require this for debug, so keeping it. #print STDOUT "****PEER HUID Attribut not present for " # . "Peer Target [$attr->{default}]... Skip\n"; $attr->{default} = "NULL"; } else { $attr->{default} = sprintf("0x%X",(hex($peerHUID) << 32)); } } } } } } ################################################################################ # Convert PHYS_PATH into index for Target_t attribute's value ################################################################################ sub handleTgtPtrAttributesHb{ my($attributes, $Target_t) = @_; my $aId = 0; ${$Target_t}{'NULL'} = $aId; foreach my $attribute (@{${$attributes}->{attribute}}) { $aId++; if(exists $attribute->{simpleType} && exists $attribute->{simpleType}->{'Target_t'}) { ${$Target_t}{"$attribute->{id}"} = $aId; } } my %TargetList = (); my $index = 1; # Mapping instance's PHYS_PATH to index (1-base) foreach my $targetInstance (@{${$attributes}->{targetInstance}}) { foreach my $attr (@{$targetInstance->{attribute}}) { if ($attr->{id} eq "PHYS_PATH") { $TargetList{$attr->{default}} = $index++; last; } } } # replace Target_t attribute's value with instance's index foreach my $targetInstance (@{${$attributes}->{targetInstance}}) { foreach my $attr (@{$targetInstance->{attribute}}) { # An instance has a Target_t attribute if(exists ${$Target_t}{$attr->{id}}) { if (exists $TargetList{$attr->{default}}) { $attr->{default} = $TargetList{$attr->{default}}; } else { print STDOUT ("$attr->{id} attribute has an unknown value " . "$attr->{default}\n" . "It must be NULL or a valid PHYS_PATH\n"); $attr->{default} = "NULL"; } } } } } sub getPeerHuid { my($targetInstance) = @_; my $peerHUID = PEER_HUID_NOT_PRESENT; if(exists $targetInstance->{compileAttribute}) { foreach my $compileAttribute (@{$targetInstance->{compileAttribute}}) { if($compileAttribute->{id} eq "PEER_HUID") { $peerHUID = $compileAttribute->{default}; last; } } } return $peerHUID; } sub SOURCE_FILE_GENERATION_FUNCTIONS { } # FAPI2 ATTRIBUTE SUPPORT ################################################################################ # Writes the FAPI2 plat attribute macros header file header ################################################################################ sub writeFapi2PlatAttrMacrosHeaderFileHeader { my($outFile) = @_; print $outFile < HB attribute mappings. This file is autogenerated and * should not be altered. */ //****************************************************************************** // Includes //****************************************************************************** // STD #include //****************************************************************************** // Macros //****************************************************************************** namespace fapiToTargeting { namespace fapi2 { enum { VERBATIM } ################################################################################ # Writes the FAPI2 plat attribute macros ################################################################################ sub writeFapi2PlatAttrMacrosHeaderFileContent { my($attributes,$fapiAttributes,$outFile) = @_; my $macroSection = ""; my $attrSection = ""; my $typeSection = ""; foreach my $attribute (@{$attributes->{attribute}}) { foreach my $hwpfToHbAttrMap (@{$attribute->{hwpfToHbAttrMap}}) { if( !exists $hwpfToHbAttrMap->{id} || !exists $hwpfToHbAttrMap->{macro}) { fatal("id,macro fields required\n"); } my $fapiReadable = 0; my $fapiWriteable = 0; my $instantiated = 0; if ($cfgFapiAttributesXmlFile eq "") { #No FAPI attributes xml file specified if(exists $attribute->{readable}) { $macroSection .= ' #define ' . $hwpfToHbAttrMap->{id} . "_GETMACRO(ID,PTARGET,VAL) \\\n" . " FAPI2_PLAT_ATTR_SVC_GETMACRO_" . $hwpfToHbAttrMap->{macro} . "(ID,PTARGET,VAL)\n"; $instantiated = 1; } if(exists $attribute->{writeable}) { $macroSection .= ' #ifndef ' . $hwpfToHbAttrMap->{id} . "_SETMACRO\n"; $macroSection .= ' #define ' . $hwpfToHbAttrMap->{id} . "_SETMACRO(ID,PTARGET,VAL) \\\n" . " FAPI2_PLAT_ATTR_SVC_SETMACRO_" . $hwpfToHbAttrMap->{macro} . "(ID,PTARGET,VAL)\n"; $macroSection .= " #endif\n"; $instantiated = 1; } } else { #FAPI attribute xml file specified - validate against FAPI attrs foreach my $fapiAttr (@{$fapiAttributes->{attribute}}) { if( (exists $fapiAttr->{id}) && ($fapiAttr->{id} eq $hwpfToHbAttrMap->{id}) ) { # Check that non-platInit attributes are in the # volatile-zeroed section and have a direct mapping if (! exists $fapiAttr->{platInit}) { if ($hwpfToHbAttrMap->{macro} ne "DIRECT") { fatal("FAPI non-platInit attr " . "'$hwpfToHbAttrMap->{id}' is " . "'$hwpfToHbAttrMap->{macro}', " . "it must be DIRECT"); } if ( (exists $fapiAttr->{persistent})) { if ($attribute->{persistency} ne "non-volatile") { fatal("FAPI non-platInit attr " . "'$hwpfToHbAttrMap->{id}' is " . "'$attribute->{persistency}', " . "it must be non-volatile"); } } else { # Check that platInit attributes # have a non-volatile persistency if($attribute->{persistency} ne "volatile-zeroed") { fatal("FAPI non-platInit attr " . "'$hwpfToHbAttrMap->{id}' is " . "'$attribute->{persistency}', " . "it must be volatile-zeroed"); } } } # All FAPI attributes are readable $fapiReadable = 1; if(exists $fapiAttr->{writeable}) { $fapiWriteable = 1; } if(!exists $attribute->{simpleType}->{enumeration}) { $typeSection .= " static_assert(sizeof(TARGETING::ATTR_". $attribute->{id}."_type) == sizeof(fapi2::". $fapiAttr->{id}."_Type), \"Size of attribute ATTR_". $attribute->{id}."_type is not equal to the size of ". $fapiAttr->{id}."_Type , types dont match \" );\n"; } last; } } if($fapiReadable) { if(exists $attribute->{readable}) { $macroSection .= ' #define ' . $hwpfToHbAttrMap->{id} . "_GETMACRO(ID,PTARGET,VAL) \\\n" . " FAPI2_PLAT_ATTR_SVC_GETMACRO_" . $hwpfToHbAttrMap->{macro} . "(ID,PTARGET,VAL)\n"; $instantiated = 1; } else { fatal("FAPI attribute $hwpfToHbAttrMap->{id} requires " . "platform supply readable attribute."); } } if($fapiWriteable) { if(exists $attribute->{writeable}) { $macroSection .= ' #define ' . $hwpfToHbAttrMap->{id} . "_SETMACRO(ID,PTARGET,VAL) \\\n" . " FAPI2_PLAT_ATTR_SVC_SETMACRO_" . $hwpfToHbAttrMap->{macro} . "(ID,PTARGET,VAL)\n"; $instantiated = 1; } else { fatal("FAPI attribute $hwpfToHbAttrMap->{id} requires " . "platform supply writeable attribute."); } } } if($instantiated) { $attrSection .= $hwpfToHbAttrMap->{id} . " = " . " TARGETING::ATTR_" . $attribute->{id} . ",\n"; } } } print $outFile $attrSection; print $outFile "};\n\n"; print $outFile "} // End namespace platAttrSvc\n\n"; print $outFile "} // End namespace fapi2\n\n"; print $outFile $typeSection; print $outFile "\n\n"; print $outFile $macroSection; print $outFile "\n"; } ################################################################################ # Writes the plat attribute macros header file footer ################################################################################ sub writeFapi2PlatAttrMacrosHeaderFileFooter { my($outFile) = @_; print $outFile < #include #include #include // Targeting component //****************************************************************************** // Complex Types //****************************************************************************** namespace TARGETING { const uint32_t PNOR_TARG_EYE_CATCHER = 0x54415247; enum SECTION_TYPE { // Targeting read-only section backed to PNOR. Always the 0th section. SECTION_TYPE_PNOR_RO = 0x00, // Targeting read-write section backed to PNOR SECTION_TYPE_PNOR_RW = 0x01, // Targeting heap section initialized out of PNOR SECTION_TYPE_HEAP_PNOR_INIT = 0x02, // Targeting heap section intialized to zero SECTION_TYPE_HEAP_ZERO_INIT = 0x03, // FSP section // Initialized to zero on Fsp Reset / Obliterate on Fsp Reset or R/R SECTION_TYPE_FSP_P0_ZERO_INIT = 0x4, // Initialized from Flash / Obliterate on Fsp Reset or R/R SECTION_TYPE_FSP_P0_FLASH_INIT = 0x5, // This section remains across fsp power cycle, fixed, never updates SECTION_TYPE_FSP_P3_RO = 0x6, // This section persist changes across Fsp Power cycle SECTION_TYPE_FSP_P3_RW = 0x7, // Initialized to zero on hard reset, else existing P1 memory // copied on R/R SECTION_TYPE_FSP_P1_ZERO_INIT = 0x8, // Intialized to default from P3 on hard reset, else existing P1 // memory copied on R/R SECTION_TYPE_FSP_P1_FLASH_INIT = 0x9, // HOSTBOOT section // Targeting heap section intialized to zero SECTION_TYPE_HB_HEAP_ZERO_INIT = 0x0A, }; struct TargetingSection { // Type of targeting section const SECTION_TYPE sectionType : 8; // Offset of the section within the PNOR targeting image from byte zero // of the targeting header const uint32_t sectionOffset; // Size of the section within the PNOR targeting image const uint32_t sectionSize; } PACKED; struct TargetingHeader { // Eyecatcher to quickly verify correct population of targeting PNOR // data const uint32_t eyeCatcher; // Major version of the PNOR targeting image const uint16_t majorVersion; // Minor version of the PNOR targeting image const uint16_t minorVersion; // Total size of the targeting header (from beginning of header). The // PNOR RO targeting data is located immediately following the header const uint32_t headerSize; // Virtual memory offset from the virtual memory address of the previous // section where the attribute resource provider must load the next // section. If there is no previous section, it will represent the // offset from the virtual memory base address (typically 0) const uint32_t vmmSectionOffset; // Virtual memory base address where the attribute resource provider // must load the 0th (PNOR RO) section AbstractPointer vmmBaseAddress; // Size of each TargetingSection record const uint32_t sizeOfSection; // Number of TargetingSection records const uint32_t numSections; // Offset to the first TargetingSection record, from the end of this // field const uint32_t offsetToSections; // Pad, in bytes, given by "offsetToSections" // const TargetingSection sections[numSections]; } PACKED; } // End namespace TARGETING #endif // TARG_PNORHEADER_H VERBATIM } ################################################################################ # Writes the string implementation file header ################################################################################ sub writeStringImplementationFileHeader { my($outFile) = @_; print $outFile < #include // Targeting component #include namespace TARGETING { VERBATIM } ################################################################################ # Writes test for toString entity path function ################################################################################ sub writeTestEntityPath { my($attributes) = @_; open EP_TEST_FILE, ">", "$cfgSrcOutputDir"."test_ep.H" or die $!; print EP_TEST_FILE "#include \n"; print EP_TEST_FILE "using namespace TARGETING;\n"; print EP_TEST_FILE "EntityPath l_path;\n"; print EP_TEST_FILE "const char * name = NULL;\n"; print(EP_TEST_FILE "const char * test_string = \"Unknown path" . " type\";\n"); print EP_TEST_FILE "size_t size = strlen( test_string );\n"; foreach my $attribute (@{$attributes->{attribute}}) { if(exists $attribute->{simpleType}) { my $simpleType = $attribute->{simpleType}; if(exists $simpleType->{enumeration}) { my $enumeration = $simpleType->{enumeration}; my $enumerationType = getEnumerationType($attributes, $enumeration->{id}); foreach my $enumerator (@{$enumerationType->{enumerator}}) { if( $attribute->{id} eq "TYPE" ) { print(EP_TEST_FILE "name = " . "l_path.pathElementTypeAsString( " . "TYPE_$enumerator->{name} );\n"); print EP_TEST_FILE "size = strlen( name );\n"; if( $enumerator->{name} eq "LAST_IN_RANGE" ) { print(EP_TEST_FILE "if( memcmp( name, " . "test_string, size ))\n{\n"); print(EP_TEST_FILE "TS_FAIL(\"type " . "attribute TYPE_$enumerator->{name}" . " - did not return expected error " . "message. - update entitypath.C\");\n}\n"); } elsif( $enumerator->{name} eq "TEST_FAIL" ) { #TEST_FAIL is not defined in the function #pathElementTypeAsString - validate error string print(EP_TEST_FILE "if( memcmp( name, " . "test_string, size ))\n{\n"); print(EP_TEST_FILE "TS_FAIL(\"type " . "attribute TYPE_$enumerator->{name}" . " - did not return expected error " . "message. - update entitypath.C\");\n}\n"); } else { print(EP_TEST_FILE "if( !memcmp( name, " . "test_string, size ))\n{\n"); print(EP_TEST_FILE "TS_FAIL(\"undefined TYPE " . "attribute TYPE_$enumerator->{name}" . " - update entitypath.C\");\n}\n"); } } } } } } close EP_TEST_FILE; } ################################################################################ # Writes string implementation ################################################################################ sub writeStringImplementationFileStrings { my($attributes,$outFile) = @_; foreach my $attribute (@{$attributes->{attribute}}) { if(exists $attribute->{simpleType}) { my $simpleType = $attribute->{simpleType}; if(exists $simpleType->{enumeration}) { my $enumeration = $simpleType->{enumeration}; print $outFile "//*********************************************" . "*********************************\n"; print $outFile "// attrToString{id}, ">\n"; print $outFile "//*********************************************" . "*********************************\n\n"; print $outFile "template<>\n"; print $outFile "const char* attrToString{id},"> (\n"; print $outFile " AttributeTraits{id}, ">::Type const& i_attrValue)\n"; print $outFile "{\n"; print $outFile " switch(i_attrValue)\n"; print $outFile " {\n"; my $enumerationType = getEnumerationType($attributes, $enumeration->{id}); foreach my $enumerator (@{$enumerationType->{enumerator}}) { print $outFile " case ", $attribute->{id}, "_", $enumerator->{name},":\n"; print $outFile " return \"", $enumerator->{name},"\";\n"; } print $outFile " default:\n"; print $outFile " return \"Cannot decode ", $attribute->{id}, "\";\n"; print $outFile " }\n"; print $outFile "}\n\n"; } } } } ################################################################################ # Locate generic attribute definition, given an enumeration ID ################################################################################ sub getEnumerationType { my($attributes,$id) = @_; my $matchingEnumeration; foreach my $enumerationType (@{$attributes->{enumerationType}}) { if($id eq $enumerationType->{id}) { $matchingEnumeration = $enumerationType; last; } } if(!exists $matchingEnumeration->{id}) { fatal("Could not find enumeration with ID of " . $id . "\n"); } return $matchingEnumeration; } ################################################################################ # Writes the string implementation file footer ################################################################################ sub writeStringImplementationFileFooter { my($outFile) = @_; print $outFile < #include // Targeting component #include #include #include //****************************************************************************** // Complex Types //****************************************************************************** namespace TARGETING { VERBATIM } ################################################################################ # Writes struct header file structs ################################################################################ sub writeStructFileStructs { my($attributes,$outFile) = @_; foreach my $attribute (@{$attributes->{attribute}}) { if(exists $attribute->{complexType}) { my $complexType = $attribute->{complexType}; if(!exists $complexType->{description}) { fatal("ERROR: Complex type requires a 'description'."); } print $outFile "/**\n"; print $outFile wrapBrief($complexType->{description}); print $outFile " */\n"; print $outFile "struct ", calculateStructName($attribute->{id}), "\n"; print $outFile "{\n"; my $complex = $attribute->{complexType}; foreach my $field (@{$complex->{field}}) { validateFieldElement($field); my $bits = ""; if($field->{bits}) { $bits = " : " . $field->{bits}; } print $outFile wrapComment($field->{description}); print $outFile " ", $field->{type}, " ", $field->{name}, $bits, "; \n\n"; } print $outFile "} PACKED;\n\n"; } } } ################################################################################ # Writes the struct file footer ################################################################################ sub writeStructFileFooter { my($outFile) = @_; print $outFile < #include namespace TARGETING { /** * \@brief Class used to clarify compiler error when caller attempts to * stringify an unsupported attribute */ class InvalidAttributeForStringification; /** * \@brief Return attribute as a string * * \@param[in] i_attrValue Value of the attribute * * \@return String which decodes the attribute value */ template const char* attrToString( typename AttributeTraits::Type const& i_attrValue) { // Default behavior is to fail the compile if caller attempt to print an // unsupported string return InvalidAttributeForStringification(); } VERBATIM } ################################################################################ # Writes string interfaces ################################################################################ sub writeStringHeaderFileStrings { my($attributes,$outFile) = @_; foreach my $attribute (@{$attributes->{attribute}}) { if(exists $attribute->{simpleType}) { my $simpleType = $attribute->{simpleType}; if(exists $simpleType->{enumeration}) { my $enumeration = $simpleType->{enumeration}; print $outFile "/**\n"; print $outFile " * \@brief See " . "attrToString\n"; print $outFile " */\n"; print $outFile "template<>\n"; print $outFile "const char* attrToString{id},">(\n"; print $outFile " AttributeTraits{id}, ">::Type const& i_attrValue);\n"; print $outFile "\n"; } } } } ################################################################################ # Writes the string header file footer ################################################################################ sub writeStringHeaderFileFooter { my($outFile) = @_; print $outFile < #include //****************************************************************************** // Enumerations //****************************************************************************** namespace TARGETING { VERBATIM } ################################################################################ # Writes the enum file attribute enumeration ################################################################################ sub writeEnumFileAttrIdEnum { my($attributes,$outFile) = @_; print $outFile < 80 chars for clarity format ATTRENUMFORMAT = ATTR_@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< = @<<<<<<<<<< $attrId, $hexVal ."," . select($outFile); $~ = 'ATTRENUMFORMAT'; my $attributeIdEnumeration = getAttributeIdEnumeration($attributes); foreach my $enumerator (@{$attributeIdEnumeration->{enumerator}}) { $hexVal = $enumerator->{value}; $attrId = $enumerator->{name}; write; } print $outFile "};\n\n"; } ################################################################################ # Writes other enumerations to enumeration file ################################################################################ sub writeEnumFileAttrEnums { my($attributes,$outFile) = @_; my $enumName = ""; my $enumHex = ""; # Format below intentionally > 80 chars for clarity format ENUMFORMAT = @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< = @<<<<<<<<<< $enumName, $enumHex ."," . select($outFile); $~ = 'ENUMFORMAT'; foreach my $enumerationType (@{$attributes->{enumerationType}}) { print $outFile "/**\n"; print $outFile wrapBrief( $enumerationType->{description} ); print $outFile " */\n"; print $outFile "enum ", $enumerationType->{id}, "\n"; print $outFile "{\n"; foreach my $enumerator (@{$enumerationType->{enumerator}}) { $enumHex = sprintf "0x%08X", enumNameToValue($enumerationType,$enumerator->{name}); $enumName = $enumerationType->{id} . "_" . $enumerator->{name}; write; } print $outFile "};\n\n"; } } ################################################################################ # Writes the enum file footer ################################################################################ sub writeEnumFileFooter { my($outFile) = @_; print $outFile <{id} cmp $b->{id} } @{$attributes->{attribute}}) { # Only (initially) support attributes with simple integer types if ((exists $attribute->{simpleType}) && ((exists $attribute->{simpleType}->{uint8_t}) || (exists $attribute->{simpleType}->{uint16_t}) || (exists $attribute->{simpleType}->{uint32_t}) || (exists $attribute->{simpleType}->{uint64_t}))) { foreach my $enum (@{$attributeIdEnum->{enumerator}}) { if($enum->{name} eq $attribute->{id}) { # struct AttributeData print $outFile "\t{\n"; # iv_name print $outFile "\t\t\"ATTR_$attribute->{id}\",\n"; # iv_attrId print $outFile "\t\t$enum->{value},\n"; # iv_attrElemSizeBytes my @sizes = ( "uint8_t", "uint16_t", "uint32_t", "uint64_t" ); foreach my $size (@sizes) { if (exists $attribute->{simpleType}->{$size}) { print $outFile "\t\tsizeof($size),\n"; last; } } # iv_dims my @dims = (); if (exists $attribute->{simpleType}->{array}) { # Remove leading whitespace my $dimText = $attribute->{simpleType}->{array}; $dimText =~ s/^\s+//; # Split on commas or whitespace @dims = split(/\s*,\s*|\s+/, $dimText); } until ($#dims == 3) { push @dims, 1; } print $outFile "\t\t{ ".join(", ",@dims)." } \n"; # end AttributeData print $outFile "\t},\n"; } } } } print $outFile "};\n"; } ################################################################################ # Writes the trait file header ################################################################################ sub writeTraitFileHeader { my($attributes,$outFile) = @_; print $outFile < #include VERBATIM foreach my $attribute (@{$attributes->{attribute}}) { #check if fspmutex is present? if( (exists $attribute->{simpleType}) && (exists $attribute->{simpleType}->{fspmutex}) ) { print $outFile "#include \n"; last; # don't need to look at any others. } } print $outFile < namespace TARGETING { //****************************************************************************** // Attribute Property Mappings //****************************************************************************** /** * \@brief Template associating a specific attribute with a type and other * properties, such as whether it is readable/writable * * This is automatically generated * * enum { * disabled = Special value for the basic, unused wildcard attribute * readable = Attribute is readable * writable = Attribute is writable * hasStringConversion = Attribute has debug string conversion * } * * typedef TYPE // is the Attribute's valid type */ template class AttributeTraits { private: enum { disabled }; typedef void* Type; }; VERBATIM } ################################################################################ # Writes computed traits to trait file ################################################################################ sub writeTraitFileTraits { my($attributes,$outFile) = @_; my $typedefs = ""; my %attrValHash; foreach my $attribute (@{$attributes->{attribute}}) { # Build boolean traits my $traits = ""; foreach my $trait ("writeable","readable","hasStringConversion") { if(exists $attribute->{$trait}) { $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,"; } # Mark the attribute as being a fsp mutex or non-fsp mutex if( (exists $attribute->{simpleType}) && (exists $attribute->{simpleType}->{fspmutex}) ) { $traits .= " fspMutex,"; } else { $traits .= " notFspMutex,"; } chop($traits); # Build value type my $type = ""; my $dimensions = ""; if(exists $attribute->{simpleType}) { my $simpleType = $attribute->{simpleType}; my $simpleTypeProperties = simpleTypeProperties(); for my $typeName (sort(keys %{$simpleType})) { if(exists $simpleTypeProperties->{$typeName}) { if( $simpleTypeProperties->{$typeName}{typeName} eq "XMLTOHB_USE_PARENT_ATTR_ID") { $type = $attribute->{id}; } else { $type = $simpleTypeProperties->{$typeName}{typeName}; } if( (exists $simpleType->{array}) && ($simpleTypeProperties->{$typeName}{supportsArray}) ) { my @bounds = split(/,/,$simpleType->{array}); foreach my $bound (@bounds) { $dimensions .= "[$bound]"; } } elsif(exists $simpleType->{string}) { # Create the string dimension if(exists $simpleType->{string}->{sizeInclNull}) { $dimensions .= "[$simpleType->{string}->{sizeInclNull}]"; } } last; } } if($type eq "") { fatal("Unsupported simpleType child element for " . "attribute $attribute->{id}. Keys are (" . join(',',sort(keys %{$simpleType})) . ")"); } } elsif(exists $attribute->{nativeType}) { $type = $attribute->{nativeType}->{name}; } elsif(exists $attribute->{complexType}) { $type = calculateStructName($attribute->{id}); } else { fatal("Could not determine attribute data type for attribute " . "$attribute->{id}."); } # if it already exists skip it if( !exists($attrValHash{$attribute->{id}})) { # keep track of the ones we add to our file $attrValHash{$attribute->{id}} = 1; # Add traits definition to output print $outFile "template<>\n"; print $outFile "class AttributeTraits{id},">\n"; print $outFile "{\n"; print $outFile " public:\n"; print $outFile " enum {",$traits," };\n"; print $outFile " typedef ", $type, " Type$dimensions;\n"; print $outFile "};\n\n"; $typedefs .= "// Type aliases and/or sizes for ATTR_" . "$attribute->{id} attribute\n"; $typedefs .= "typedef " . $type . " $attribute->{id}" . "_ATTR" . $dimensions . ";\n"; # Append a more friendly type alias for attribute $typedefs .= "typedef " . $type . " ATTR_" . "$attribute->{id}" . "_type" . $dimensions . ";\n"; # If a string, append max # of characters for the string if( (exists $attribute->{simpleType}) && (exists $attribute->{simpleType}->{string})) { my $size = $attribute->{simpleType}->{string}->{sizeInclNull}-1; $typedefs .= "const size_t ATTR_" . "$attribute->{id}" . "_max_chars = " . "$size" . ";\n"; } $typedefs .= "\n"; } }; print $outFile "/**\n"; print $outFile wrapBrief("Mapping of alias type name to underlying type"); print $outFile " */\n"; print $outFile $typedefs ."\n"; } ################################################################################ # Writes the trait file footer ################################################################################ sub writeTraitFileFooter { my($outFile) = @_; print $outFile <\n"; print $outFile "#include \n"; print $outFile "#include \n"; print $outFile "#include \n"; print $outFile "#include \n"; print $outFile "#include \n"; print $outFile "#include \n"; print $outFile "\n"; print $outFile "namespace ERRORLOG\n"; print $outFile "{\n"; print $outFile "using namespace TARGETING;\n"; print $outFile "extern TARG_TD_t g_trac_errl;\n"; # build function that takes adds 1 attribute to the output print $outFile "\n"; print $outFile "void ErrlUserDetailsAttribute::addData(\n"; print $outFile " uint32_t i_attr)\n"; print $outFile "{\n"; print $outFile " char *tmpBuffer = NULL;\n"; print $outFile " uint32_t attrSize = 0;\n"; print $outFile "\n"; print $outFile "#if 0 //\@fixme-RTC:152874\n"; print $outFile " switch (i_attr) {\n"; # loop through every attribute to make the swith/case foreach my $attribute (@{$attributes->{attribute}}) { # things we'll skip: if(!(exists $attribute->{readable}) || # write-only attributes !(exists $attribute->{writeable}) || # read-only attributes (exists $attribute->{simpleType} && ( (exists $attribute->{simpleType}->{hbmutex}) || (exists $attribute->{simpleType}->{fspmutex}))) # mutex attributes ) { print $outFile " case (ATTR_",$attribute->{id},"): { break; }\n"; next; } # any complicated types just get dumped as raw hex binary elsif(exists $attribute->{complexType}) { print $outFile " case (ATTR_",$attribute->{id},"): {\n"; print $outFile " TRACDCOMP( g_trac_errl, \"ErrlUserDetailsAttribute: ",$attribute->{id}," skipped -- complexType\");\n"; print $outFile " attrSize = 0;\n"; print $outFile " break;\n"; print $outFile " }\n"; } # Enums elsif(exists $attribute->{simpleType} && (exists $attribute->{simpleType}->{enumeration}) ) { print $outFile " case (ATTR_",$attribute->{id},"): { // simpleType:enum\n"; print $outFile " //TRACDCOMP( g_trac_errl, \"ErrlUserDetailsAttribute: ",$attribute->{id}," entry\");\n"; print $outFile " AttributeTraits{id},">::Type tmp;\n"; print $outFile " if( iv_pTarget->tryGetAttr{id},">(tmp) ) {\n"; print $outFile " tmpBuffer = new char[sizeof(tmp)];\n"; print $outFile " memcpy(tmpBuffer, &tmp, sizeof(tmp));\n"; print $outFile " attrSize = sizeof(tmp);\n"; print $outFile " }\n"; print $outFile " break;\n"; print $outFile " }\n"; } # signed and unsigned ints elsif(exists $attribute->{simpleType} && ( (exists $attribute->{simpleType}->{uint8_t}) || (exists $attribute->{simpleType}->{uint16_t}) || (exists $attribute->{simpleType}->{uint32_t}) || (exists $attribute->{simpleType}->{uint64_t}) || (exists $attribute->{simpleType}->{int8_t}) || (exists $attribute->{simpleType}->{int16_t}) || (exists $attribute->{simpleType}->{int32_t}) || (exists $attribute->{simpleType}->{int64_t}) ) ) { print $outFile " case (ATTR_",$attribute->{id},"): { //simpleType:uint, :int...\n"; print $outFile " //TRACDCOMP( g_trac_errl, \"ErrlUserDetailsAttribute: ",$attribute->{id}," entry\");\n"; print $outFile " AttributeTraits{id},">::Type tmp;\n"; print $outFile " if( iv_pTarget->tryGetAttr{id},">(tmp) ) {\n"; print $outFile " tmpBuffer = new char[sizeof(tmp)];\n"; print $outFile " memcpy(tmpBuffer, &tmp, sizeof(tmp));\n"; print $outFile " attrSize = sizeof(tmp);\n"; print $outFile " }\n"; print $outFile " break;\n"; print $outFile " }\n"; } # dump the enums for EntityPaths elsif(exists $attribute->{nativeType} && ($attribute->{nativeType}->{name} eq "EntityPath")) { print $outFile " case (ATTR_",$attribute->{id},"): { //nativeType:EntityPath\n"; print $outFile " //TRACDCOMP( g_trac_errl, \"ErrlUserDetailsAttribute: ",$attribute->{id}," entry\");\n"; print $outFile " AttributeTraits{id},">::Type tmp;\n"; print $outFile " if( iv_pTarget->tryGetAttr{id},">(tmp) ) {\n"; print $outFile " // data is PATH_TYPE, Number of elements, [ Element, Instance# ]\n"; print $outFile " EntityPath::PATH_TYPE lPtype = tmp.type();\n"; print $outFile " uint8_t lSize = tmp.size();\n"; print $outFile " tmpBuffer = new char[sizeof(lPtype) + lSize + lSize * sizeof(EntityPath::PathElement)];\n"; print $outFile " memcpy(tmpBuffer + attrSize,&lPtype,sizeof(lPtype));\n"; print $outFile " attrSize += sizeof(lPtype);\n"; print $outFile " memcpy(tmpBuffer + attrSize,&lSize,sizeof(lSize));\n"; print $outFile " attrSize += sizeof(lSize);\n"; print $outFile " for (uint32_t i=0;i{nativeType}) { print $outFile " case (ATTR_",$attribute->{id},"): { nativeType\n"; print $outFile " //TRACDCOMP( g_trac_errl, \"ErrlUserDetailsAttribute: ",$attribute->{id}," entry\");\n"; print $outFile " AttributeTraits{id},">::Type tmp;\n"; print $outFile " if( iv_pTarget->tryGetAttr{id},">(tmp) ) {\n"; print $outFile " tmpBuffer = new char[sizeof(tmp)];\n"; print $outFile " memcpy(tmpBuffer, &tmp, sizeof(tmp));\n"; print $outFile " attrSize = sizeof(tmp);\n"; print $outFile " }\n"; print $outFile " break;\n"; print $outFile " }\n"; } } print $outFile " default: { //Shouldn't be anything here!!\n"; print $outFile " TRACDCOMP( g_trac_errl, \"ErrlUserDetailsAttribute: UNKNOWN i_attr %x\", i_attr);\n"; print $outFile " break;\n"; print $outFile " }\n"; print $outFile " } //switch\n"; print $outFile "\n"; print $outFile "#endif //\@fixme-RTC:152874\n"; print $outFile " // if we generated one, copy the string into the buffer\n"; print $outFile " if (attrSize) { // we have something to output\n"; print $outFile " // resize buffer and copy string into it\n"; print $outFile " uint8_t * pBuf;\n"; print $outFile " pBuf = reinterpret_cast(reallocUsrBuf(iv_dataSize + attrSize + sizeof(i_attr) ));\n"; print $outFile " memcpy(pBuf + iv_dataSize, &i_attr, sizeof(i_attr)); // first dump the attr enum\n"; print $outFile " iv_dataSize += sizeof(i_attr);\n"; print $outFile " memcpy(pBuf + iv_dataSize, tmpBuffer, attrSize); // copy into iv_pBuffer\n"; print $outFile " iv_dataSize += attrSize;\n"; print $outFile " }\n"; print $outFile " delete [] tmpBuffer;\n"; print $outFile "}\n"; print $outFile "\n"; # build constructor that dumps 1 attribute print $outFile "\n"; print $outFile "//------------------------------------------------------------------------------\n"; print $outFile "ErrlUserDetailsAttribute::ErrlUserDetailsAttribute(\n"; print $outFile " const Target * i_pTarget, uint32_t i_attr)\n"; print $outFile " : iv_pTarget(i_pTarget), iv_dataSize(0)\n"; print $outFile "{\n"; print $outFile " // Set up ErrlUserDetails instance variables\n"; print $outFile " iv_CompId = ERRL_COMP_ID;\n"; print $outFile " iv_Version = 1;\n"; print $outFile " iv_SubSection = ERRL_UDT_ATTRIBUTE;\n"; print $outFile " // override the default of false\n"; print $outFile " iv_merge = true;\n"; print $outFile "\n"; print $outFile " // first, write out the HUID\n"; print $outFile " addData(ATTR_HUID);\n"; print $outFile " if (i_attr != ATTR_HUID) {\n"; print $outFile " addData(i_attr);\n"; print $outFile " }\n"; print $outFile "}\n"; print $outFile "\n"; # build constructor that dumps all attributes print $outFile "//------------------------------------------------------------------------------\n"; print $outFile "ErrlUserDetailsAttribute::ErrlUserDetailsAttribute(\n"; print $outFile " const Target * i_pTarget)\n"; print $outFile " : iv_pTarget(i_pTarget), iv_dataSize(0)\n"; print $outFile "{\n"; print $outFile " // Set up ErrlUserDetails instance variables\n"; print $outFile " iv_CompId = ERRL_COMP_ID;\n"; print $outFile " iv_Version = 1;\n"; print $outFile " iv_SubSection = ERRL_UDT_ATTRIBUTE;\n"; print $outFile " // override the default of false\n"; print $outFile " iv_merge = true;\n"; print $outFile "\n"; print $outFile " dumpAll();\n"; print $outFile "}\n"; print $outFile "\n"; # build internal function that dumps all attributes print $outFile "//------------------------------------------------------------------------------\n"; print $outFile "void ErrlUserDetailsAttribute::dumpAll()\n"; print $outFile "{\n"; print $outFile " // write out the HUID first and always\n"; print $outFile " addData(ATTR_HUID);\n"; # loop through every attribute to make the swith/case foreach my $attribute (@{$attributes->{attribute}}) { # skip the HUID that we already added if( $attribute->{id} =~ /HUID/ ) { next; } # things we'll skip: if(!(exists $attribute->{readable}) || # write-only attributes !(exists $attribute->{writeable}) || # read-only attributes (exists $attribute->{simpleType} && ( (exists $attribute->{simpleType}->{hbmutex}) || (exists $attribute->{simpleType}->{fspmutex}))) # mutex attributes ) { next; } print $outFile " addData(ATTR_",$attribute->{id},");\n"; } print $outFile "}\n"; print $outFile "\n"; print $outFile "//------------------------------------------------------------------------------\n"; print $outFile "ErrlUserDetailsAttribute::~ErrlUserDetailsAttribute()\n"; print $outFile "{ }\n"; print $outFile "} // namespace\n"; } # sub writeAttrErrlCFile ###### #Create a .H file to parse attributes out of the errlog ##### sub writeAttrErrlHFile { my($attributes,$outFile) = @_; #First setup the includes and function definition print $outFile "\n"; print $outFile "#ifndef ERRL_UDATTRIBUTE_H\n"; print $outFile "#define ERRL_UDATTRIBUTE_H\n"; print $outFile "\n"; print $outFile "#ifndef PARSER\n"; print $outFile "\n"; print $outFile "#include \n"; print $outFile "\n"; print $outFile "namespace TARGETING // Forward reference\n"; print $outFile "{ class Target; }\n"; print $outFile "\n"; print $outFile "namespace ERRORLOG\n"; print $outFile "{\n"; print $outFile "class ErrlUserDetailsAttribute : public ErrlUserDetails {\n"; print $outFile "public:\n"; print $outFile "\n"; print $outFile " ErrlUserDetailsAttribute(const TARGETING::Target * i_pTarget, uint32_t i_attr);\n"; print $outFile " ErrlUserDetailsAttribute(const TARGETING::Target * i_pTarget);\n"; print $outFile " void addData(uint32_t i_attr);\n"; print $outFile " virtual ~ErrlUserDetailsAttribute();\n"; print $outFile "\n"; print $outFile "private:\n"; print $outFile "\n"; print $outFile " // Disabled\n"; print $outFile " ErrlUserDetailsAttribute(const ErrlUserDetailsAttribute &);\n"; print $outFile " ErrlUserDetailsAttribute & operator=(const ErrlUserDetailsAttribute &);\n"; print $outFile "\n"; print $outFile " // internal function\n"; print $outFile " void dumpAll();\n"; print $outFile "\n"; print $outFile " const TARGETING::Target * iv_pTarget;\n"; print $outFile " uint32_t iv_dataSize;\n"; print $outFile "};\n"; print $outFile "}\n"; print $outFile "#else // if PARSER defined\n"; print $outFile "\n"; print $outFile "#include \"errluserdetails.H\"\n"; print $outFile "\n"; print $outFile "namespace ERRORLOG\n"; print $outFile "{\n"; print $outFile "class ErrlUserDetailsParserAttribute : public ErrlUserDetailsParser {\n"; print $outFile "public:\n"; print $outFile "\n"; print $outFile " ErrlUserDetailsParserAttribute() {}\n"; print $outFile "\n"; print $outFile " virtual ~ErrlUserDetailsParserAttribute() {}\n"; print $outFile " /**\n"; print $outFile " * \@brief Parses Attribute user detail data from an error log\n"; print $outFile " * \@param i_version Version of the data\n"; print $outFile " * \@param i_parse ErrlUsrParser object for outputting information\n"; print $outFile " * \@param i_pBuffer Pointer to buffer containing detail data\n"; print $outFile " * \@param i_buflen Length of the buffer\n"; print $outFile " */\n"; print $outFile " virtual void parse(errlver_t i_version,\n"; print $outFile " ErrlUsrParser & i_parser,\n"; print $outFile " void * i_pBuffer,\n"; print $outFile " const uint32_t i_buflen) const\n"; print $outFile " {\n"; print $outFile " const char *pLabel = NULL;\n"; print $outFile " uint8_t *l_ptr = static_cast(i_pBuffer);\n"; print $outFile " std::vector l_traceEntry(64);\n"; print $outFile " i_parser.PrintString(\"Target Attributes\", NULL);\n"; print $outFile "\n"; print $outFile " for (; (l_ptr + sizeof(uint32_t)) <= ((uint8_t*)i_pBuffer + i_buflen); )\n"; print $outFile " {\n"; print $outFile " // first 4 bytes is the attr enum\n"; print $outFile " uint32_t attrEnum = ntohl(*(uint32_t *)l_ptr);\n"; print $outFile " l_ptr += sizeof(attrEnum);\n"; print $outFile "\n"; print $outFile " switch (attrEnum) {\n"; my $attributeIdEnum = getAttributeIdEnumeration($attributes); # loop through every attribute to make the swith/case foreach my $attribute (@{$attributes->{attribute}}) { my $attrVal; foreach my $enum (@{$attributeIdEnum->{enumerator}}) { if ($enum->{name} eq $attribute->{id}) { $attrVal = $enum->{value}; last; # don't need to look at any others. } } print $outFile " case ",$attrVal,": {\n"; # things we'll skip: if(!(exists $attribute->{readable}) || # write-only attributes !(exists $attribute->{writeable}) || # read-only attributes (exists $attribute->{simpleType} && ( (exists $attribute->{simpleType}->{hbmutex}) || (exists $attribute->{simpleType}->{fspmutex}))) # mutex attributes ) { print $outFile " //not readable\n"; } # Enums have strings defined already, use them elsif(exists $attribute->{simpleType} && (exists $attribute->{simpleType}->{enumeration}) ) { print $outFile " //simpleType:enum\n"; print $outFile " pLabel = \"",$attribute->{id},"\";\n"; foreach my $enumerationType (@{$attributes->{enumerationType}}) { if ($enumerationType->{id} eq $attribute->{id}) { print $outFile " switch (*l_ptr) {\n"; foreach my $enumerator (@{$enumerationType->{enumerator}}) { my $enumName = $attribute->{id} . "_" . $enumerator->{name}; my $enumHex = sprintf "0x%08X", enumNameToValue($enumerationType,$enumerator->{name}); print $outFile " case ",$enumHex,": {\n"; print $outFile " sprintf(&(l_traceEntry[0]), \"",$enumName,"\");\n"; print $outFile " l_ptr += sizeof(uint32_t);\n"; print $outFile " break;\n"; print $outFile " }\n"; } print $outFile " default: break;\n"; print $outFile " }\n"; } } } # makes no sense to dump mutex attributes, so skipping elsif(exists $attribute->{simpleType} && (exists $attribute->{simpleType}->{hbmutex}) ) { print $outFile " //Mutex attributes - skipping\n"; } # makes no sense to dump fsp mutex attributes, so skipping elsif( (exists $attribute->{simpleType}) && (exists $attribute->{simpleType}->{fspmutex}) ) { print $outFile " //Mutex attributes - skipping\n"; } # any complicated types just get dumped as raw hex binary elsif(exists $attribute->{complexType}) { #print $outFile " //complexType\n"; #print $outFile " uint32_t{id},">::Type tmp;\n"; #print $outFile " if( i_pTarget->tryGetAttr{id},">(tmp) ) {\n"; #print $outFile " sprintf(i_buffer, \" \", &tmp, sizeof(tmp));\n"; #print $outFile " }\n"; print $outFile " //complexType - skipping\n"; } # unsigned ints dump as hex, signed as decimals elsif(exists $attribute->{simpleType} && ( (exists $attribute->{simpleType}->{uint8_t}) || (exists $attribute->{simpleType}->{uint16_t}) || (exists $attribute->{simpleType}->{uint32_t}) || (exists $attribute->{simpleType}->{uint64_t}) || (exists $attribute->{simpleType}->{int8_t}) || (exists $attribute->{simpleType}->{int16_t}) || (exists $attribute->{simpleType}->{int32_t}) || (exists $attribute->{simpleType}->{int64_t}) ) ) { print $outFile " //simpleType:uint\n"; print $outFile " pLabel = \"",$attribute->{id},"\";\n"; my @bounds; if(exists $attribute->{simpleType}->{array}) { @bounds = split(/,/,$attribute->{simpleType}->{array}); } else { $bounds[0] = 1; } my $total_count = 1; foreach my $bound (@bounds) { $total_count *= $bound; } my $size = scalar(@bounds); if (($size == 1) && ( $bounds[0] > 1)) { print $outFile " uint32_t offset = sprintf(&(l_traceEntry[0]), \"[$bounds[0]]:\");\n"; } elsif ($size == 2) { print $outFile " uint32_t offset = sprintf(&(l_traceEntry[0]), \"[$bounds[0]][$bounds[1]]:\");\n"; } elsif ($size == 3) { print $outFile " uint32_t offset = sprintf(&(l_traceEntry[0]), \"[$bounds[0]][$bounds[1]][$bounds[2]]:\");\n"; } else { print $outFile " uint32_t offset = 0;\n"; } if (exists $attribute->{simpleType}->{uint8_t}) { print $outFile " l_traceEntry.resize(10+offset + $total_count * 5);\n"; print $outFile " for (uint32_t i = 0;i<$total_count;i++) {\n"; print $outFile " sprintf(&(l_traceEntry[offset+i*5]), \"0x%.2X \", *(((uint8_t *)l_ptr)+i));\n"; print $outFile " }\n"; print $outFile " l_ptr += $total_count * sizeof(uint8_t);\n"; } elsif (exists $attribute->{simpleType}->{uint16_t}) { print $outFile " l_traceEntry.resize(10+offset + $total_count * 7);\n"; print $outFile " for (uint32_t i = 0;i<$total_count;i++) {\n"; print $outFile " sprintf(&(l_traceEntry[offset+i*7]), \"0x%.4X \", ntohs(*(((uint16_t *)l_ptr)+i)));\n"; print $outFile " }\n"; print $outFile " l_ptr += $total_count * sizeof(uint16_t);\n"; } elsif (exists $attribute->{simpleType}->{uint32_t}) { print $outFile " l_traceEntry.resize(10+offset + $total_count * 11);\n"; print $outFile " for (uint32_t i = 0;i<$total_count;i++) {\n"; print $outFile " sprintf(&(l_traceEntry[offset+i*11]), \"0x%.8X \", ntohl(*(((uint32_t *)l_ptr)+i)));\n"; print $outFile " }\n"; print $outFile " l_ptr += $total_count * sizeof(uint32_t);\n"; } elsif (exists $attribute->{simpleType}->{uint64_t}) { print $outFile " l_traceEntry.resize(10+offset + $total_count * 19);\n"; print $outFile " for (uint32_t i = 0;i<$total_count;i++) {\n"; print $outFile " sprintf(&(l_traceEntry[offset+i*19]), \"0x%.16llX \", ntohll(*(((uint64_t *)l_ptr)+i)));\n"; print $outFile " }\n"; print $outFile " l_ptr += $total_count * sizeof(uint64_t);\n"; } elsif (exists $attribute->{simpleType}->{int8_t}) { print $outFile " l_traceEntry.resize(10+offset + $total_count * 5);\n"; print $outFile " for (uint32_t i = 0;i<$total_count;i++) {\n"; print $outFile " sprintf(&(l_traceEntry[offset+i*5]), \"0x%.2X \", *(((int8_t *)l_ptr)+i));\n"; print $outFile " }\n"; print $outFile " l_ptr += $total_count * sizeof(uint8_t);\n"; } elsif (exists $attribute->{simpleType}->{int16_t}) { print $outFile " l_traceEntry.resize(10+offset + $total_count * 7);\n"; print $outFile " for (uint32_t i = 0;i<$total_count;i++) {\n"; print $outFile " sprintf(&(l_traceEntry[offset+i*7]), \"0x%.4X \", ntohs(*(((int16_t *)l_ptr)+i)));\n"; print $outFile " }\n"; print $outFile " l_ptr += $total_count * sizeof(int16_t);\n"; } elsif (exists $attribute->{simpleType}->{int32_t}) { print $outFile " l_traceEntry.resize(10+offset + $total_count * 11);\n"; print $outFile " for (uint32_t i = 0;i<$total_count;i++) {\n"; print $outFile " sprintf(&(l_traceEntry[offset+i*11]), \"0x%.8X \", ntohl(*(((int32_t *)l_ptr)+i)));\n"; print $outFile " }\n"; print $outFile " l_ptr += $total_count * sizeof(int32_t);\n"; } elsif (exists $attribute->{simpleType}->{int64_t}) { print $outFile " l_traceEntry.resize(10+offset + $total_count * 19);\n"; print $outFile " for (uint32_t i = 0;i<$total_count;i++) {\n"; print $outFile " sprintf(&(l_traceEntry[offset+i*19]), \"0x%.16llX \", ntohll(*(((int64_t *)l_ptr)+i)));\n"; print $outFile " }\n"; print $outFile " l_ptr += $total_count * sizeof(int64_t);\n"; } } # EntityPaths elsif(exists $attribute->{nativeType} && ($attribute->{nativeType}->{name} eq "EntityPath")) { print $outFile " //nativeType:EntityPath\n"; print $outFile " pLabel = \"",$attribute->{id},"\";\n"; # data is PATH_TYPE, Number of elements, [ Element, Instance# ] # output is PathType:/ElementInstance/ElementInstance/ElementInstance print $outFile " const char *pathString;\n"; print $outFile " // from targeting/common/entitypath.[CH]\n"; print $outFile " const uint8_t lPtype = *l_ptr; // PATH_TYPE\n"; print $outFile " switch (lPtype) {\n"; print $outFile " case 0x01: pathString = \"Logical:\"; break;\n"; print $outFile " case 0x02: pathString = \"Physical:\"; break;\n"; print $outFile " case 0x03: pathString = \"Device:\"; break;\n"; print $outFile " case 0x04: pathString = \"Power:\"; break;\n"; print $outFile " default: pathString = \"Unknown:\"; break;\n"; print $outFile " }\n"; print $outFile " l_traceEntry.resize(strlen(pathString) + 128);\n"; print $outFile " uint32_t dataSize = sprintf(&(l_traceEntry[0]), \"%s\",pathString);\n"; print $outFile " const uint8_t lSize = *(l_ptr + 1); // number of elements\n"; print $outFile " uint8_t *lElementInstance = (l_ptr + 2);\n"; print $outFile " for (uint32_t i=0;i{enumerationType}}) { if( $enumerationType->{id} eq "TYPE" ) { foreach my $enumerator (@{$enumerationType->{enumerator}}) { my $enumHex = sprintf "0x%02X", enumNameToValue($enumerationType,$enumerator->{name}); my $enumName = $enumerator->{name}; if ($enumName eq "SYS") { $enumName = "Sys"; } elsif ($enumName eq "PROC") { $enumName = "Proc"; } elsif ($enumName eq "NODE") { $enumName = "Node"; } elsif ($enumName eq "CORE") { $enumName = "Core"; } elsif ($enumName eq "MEMBUF") { $enumName = "Membuf"; } print $outFile " case $enumHex: { pathString = \"/$enumName\"; break; }\n"; } } } # enumerationType print $outFile " default: { pathString = \"/UNKNOWN\"; break; }\n"; print $outFile " } // switch\n"; print $outFile " // copy next part in, overwritting previous terminator\n"; print $outFile " dataSize += sprintf(&(l_traceEntry[0]) + dataSize, \"%s%d\",pathString,lElementInstance[i+1]);\n"; print $outFile " l_ptr += 2 * sizeof(uint8_t);\n"; print $outFile " } // for\n"; } # any other nativeTypes are just decimals... (I never saw one) elsif(exists $attribute->{nativeType}) { print $outFile " //nativeType\n"; print $outFile " pLabel = \"",$attribute->{id},"\";\n"; print $outFile " sprintf(&(l_traceEntry[0]), \"%d\", *((int32_t *)l_ptr));\n"; print $outFile " l_ptr += sizeof(uint32_t);\n"; } # just in case, nothing.. else { #print $outFile " //unknown attributes\n"; } print $outFile " break;\n"; print $outFile " }\n"; } print $outFile " default: {\n"; print $outFile " pLabel = \"unknown Attribute\";\n"; print $outFile " break;\n"; print $outFile " }\n"; print $outFile " } // switch\n"; print $outFile "\n"; print $outFile " // pointing to something - print it.\n"; print $outFile " if (pLabel != NULL) {\n"; print $outFile " i_parser.PrintString(pLabel, &(l_traceEntry[0]));\n"; print $outFile " }\n"; print $outFile " } // for\n"; print $outFile " } // parse\n\n"; print $outFile "private:\n"; print $outFile "\n"; print $outFile "// Disabled\n"; print $outFile "ErrlUserDetailsParserAttribute(const ErrlUserDetailsParserAttribute &);\n"; print $outFile "ErrlUserDetailsParserAttribute & operator=(const ErrlUserDetailsParserAttribute &);\n"; print $outFile "};\n"; print $outFile "} // namespace\n"; print $outFile "#endif\n"; print $outFile "#endif\n"; } # sub writeAttrErrlHFile ###### #Create a .csv file to parse attribute overrides/syncs ##### sub writeAttrInfoCsvFile { my($attributes,$outFile) = @_; # Print the file header print $outFile "# targAttrInfo.cvs\n"; print $outFile "# This file is generated by perl script xmltohb.pl\n"; print $outFile "# It lists information about TARG attributes and is used to\n"; print $outFile "# process FAPI Attribute text files (overrides/syncs)\n"; print $outFile "# Format:\n"; print $outFile "# ,,,\n"; my $attributeIdEnum = getAttributeIdEnumeration($attributes); # loop through every attribute foreach my $attribute (@{$attributes->{attribute}}) { # Only (initially) support attributes with simple integer types if ((exists $attribute->{simpleType}) && ((exists $attribute->{simpleType}->{uint8_t}) || (exists $attribute->{simpleType}->{uint16_t}) || (exists $attribute->{simpleType}->{uint32_t}) || (exists $attribute->{simpleType}->{uint64_t}))) { my $fapiId = "NO-FAPI-ID"; if (exists $attribute->{hwpfToHbAttrMap}[0]) { $fapiId = $attribute->{hwpfToHbAttrMap}[0]->{id}; } foreach my $enum (@{$attributeIdEnum->{enumerator}}) { if ($enum->{name} eq $attribute->{id}) { print $outFile "$fapiId,"; print $outFile "ATTR_$attribute->{id}"; print $outFile ",$enum->{value},"; if (exists $attribute->{simpleType}->{uint8_t}) { print $outFile "u8"; } elsif (exists $attribute->{simpleType}->{uint16_t}) { print $outFile "u16"; } elsif (exists $attribute->{simpleType}->{uint32_t}) { print $outFile "u32"; } elsif (exists $attribute->{simpleType}->{uint64_t}) { print $outFile "u64"; } if (exists $attribute->{simpleType}->{array}) { # Remove leading whitespace my $dimText = $attribute->{simpleType}->{array}; $dimText =~ s/^\s+//; # Split on commas or whitespace my @vals = split(/\s*,\s*|\s+/, $dimText); foreach my $val (@vals) { print $outFile "[$val]"; } } print $outFile "\n"; } } } } } # sub writeAttrInfoCsvFile ################################################################################ # Writes the unordered/Ordered map of all target attribute metadata # C file header ################################################################################ sub writeAttrMetadataMapCFileHeader { my($outFile) = @_; print $outFile < //****************************************************************************** // Macros //****************************************************************************** #undef TARG_NAMESPACE #undef TARG_CLASS #undef TARG_FUNC //****************************************************************************** // Implementation //****************************************************************************** namespace TARGETING { #define TARG_NAMESPACE "TARGETING::" #define TARG_CLASS "MapAttrMetadata::" // Persistency defines static const char * P0_PERSISTENCY = "p0"; static const char * P1_PERSISTENCY = "p1"; static const char * P3_PERSISTENCY = "p3"; //****************************************************************************** // TARGETING::mapAttrMetadata //****************************************************************************** TARGETING::MapAttrMetadata& mapAttrMetadata() { #define TARG_FN "mapAttrMetadata()" return TARG_GET_SINGLETON(TARGETING::theMapAttrMetadata); #undef TARG_FN } //****************************************************************************** // TARGETING::MapAttrMetadata::~MapAttrMetadata //****************************************************************************** MapAttrMetadata::~MapAttrMetadata() { #define TARG_FN "~MapAttrMetadata()" #undef TARG_FN } //****************************************************************************** // TARGETING::MapAttrMetadata::getMapMetadataForAllAttributes //****************************************************************************** const AttrMetadataMapper& MapAttrMetadata::getMapMetadataForAllAttributes() const { #define TARG_FN "getMapMetadataForAllAttributes()" TARG_ENTER(); TARG_EXIT(); return iv_mapAttrMetadata; #undef TARG_FN } //****************************************************************************** // TARGETING::MapAttrMetadata::MapAttrMetadata //****************************************************************************** MapAttrMetadata::MapAttrMetadata() { #define TARG_FN "MapAttrMetadata()" VERBATIM } ################################################################################ # Create a .C file to put All Target Attributes along with there respective # Size and read/write properties in a unordered/ordered map variable ################################################################################ sub writeAttrMetadataMapCFile{ my($attributes,$outFile) = @_; my %finalAttrhash = (); # look for all attributes in the XML foreach my $attribute (@{$attributes->{attribute}}) { $finalAttrhash{$attribute->{id}} = $attribute; } print $outFile "\n"; print $outFile " static const Pair_t l_pair[] = {\n"; foreach my $key ( keys %finalAttrhash) { if(!(exists $finalAttrhash{$key}->{hbOnly})) { # Fetch the Size of the attribute my $keySize = "ATTR_"."$key"."_type"; if(exists $finalAttrhash{$key}->{simpleType}) { # Nothing to do } elsif(!(exists $finalAttrhash{$key}->{complexType}) && !(exists $finalAttrhash{$key}->{nativeType})) { print STDOUT "\t// ### Attribute $key is Not Supported\n"; next; } print $outFile " std::make_pair( ATTR_".$key.","; print $outFile " AttrMetadataStr(sizeof($keySize),"; # Fetch Read/Writeable Property if(exists $finalAttrhash{$key}->{writeable}) { print $outFile " true,"; } else { print $outFile " false,"; } if(!(exists $finalAttrhash{$key}->{persistency})) { fatal("Attribute[$key] should have persistency by default"); } if($finalAttrhash{$key}->{persistency} eq "non-volatile") { print $outFile " P3_PERSISTENCY) ),\n"; } elsif(($finalAttrhash{$key}->{persistency} eq "semi-non-volatile-zeroed") || ($finalAttrhash{$key}->{persistency} eq "semi-non-volatile")) { print $outFile " P1_PERSISTENCY) ),\n"; } elsif(($finalAttrhash{$key}->{persistency} eq "volatile") || ($finalAttrhash{$key}->{persistency} eq "volatile-zeroed")) { print $outFile " P0_PERSISTENCY) ),\n"; } else { fatal("Not a defined" . "Persistency[$finalAttrhash{$key}->{persistency}] for" . "attribute [$key]"); } } } print $outFile " };\n"; print $outFile " iv_mapAttrMetadata\.insert( l_pair,\n"; print $outFile " l_pair + (sizeof(l_pair)/sizeof(l_pair[0])) );\n\n"; } ################################################################################ # Writes the map all attr size C file Footer ################################################################################ sub writeAttrMetadataMapCFileFooter { my($outFile) = @_; print $outFile < #else #include #endif // TARG #include #include //****************************************************************************** // Macros //****************************************************************************** #undef TARG_NAMESPACE #undef TARG_CLASS #undef TARG_FUNC //****************************************************************************** // Interface //****************************************************************************** #ifndef __HOSTBOOT_MODULE /* * \@brief Specialized Hash function Template to be inserted with unordered_map */ namespace std { namespace tr1 { template <> struct hash : public unary_function< TARGETING::ATTRIBUTE_ID, size_t> { size_t operator()(const TARGETING::ATTRIBUTE_ID& attrId) const { return attrId; } }; } } #endif namespace TARGETING { /* * \@brief - Data Struct to contain attribute related info * * Field Description * \@field1 - Size: Size of the attribute * \@field2 - readWriteable: true if read and writeable else false only readable * \@field3 - Persistency level of the attribute */ struct attrMetadataStr { uint32_t size; bool readWriteable; const char* persistency; attrMetadataStr() : size(0), readWriteable(false), persistency(NULL) {} attrMetadataStr(uint32_t i_size, bool i_rw, const char* i_persistency) : size(i_size), readWriteable(i_rw), persistency(i_persistency) {} }; /* * \@brief Typedef for struct attrMetadataStr */ typedef struct attrMetadataStr AttrMetadataStr; /* * \@brief Typedef for pair */ typedef std::pair Pair_t; #ifndef __HOSTBOOT_MODULE /* * \@brief Typedef std::tr1::unordered_map */ typedef std::tr1::unordered_map > AttrMetadataMapper; #else /* * \@brief Typedef std::map */ typedef std::map AttrMetadataMapper; #endif class MapAttrMetadata { public: /** * \@brief Destroy the MapAttrMetadata class */ ~MapAttrMetadata(); /** * \@brief Create the MapAttrMetadata class */ MapAttrMetadata(); /* * \@brief returns the unordered/ordered map of all attributes as * key and struct attrMetadataStr as value, which contains the size * of the attribute along with read/writeable properties * * \@return, returns the unordered/ordered map which has the all * attributes as key and struct attrMetadataStr as value pair, * variable */ const AttrMetadataMapper& getMapMetadataForAllAttributes() const; private: /* Unordered/Ordered map variable for All Attribute Ids vs Size & * Read/Write properties */ AttrMetadataMapper iv_mapAttrMetadata; /* Disable Copy constructor and assignment operator */ MapAttrMetadata( const MapAttrMetadata& i_right); MapAttrMetadata& operator = ( const MapAttrMetadata& i_right); }; /** * \@brief Provide singleton access to the MapAttrMetadata */ TARG_DECLARE_SINGLETON(TARGETING::MapAttrMetadata, theMapAttrMetadata); #undef TARG_CLASS #undef TARG_NAMESPACE }// namespace TARGETING #endif // MAPATTRMETADATA_H VERBATIM } ###### #Create a .C file to put target into the errlog ##### sub writeTargetErrlCFile { my($attributes,$outFile) = @_; #First setup the includes and function definition print $outFile "#include \n"; print $outFile "#include \n"; print $outFile "#include \n"; print $outFile "#include \n"; print $outFile "#include \n"; print $outFile "#include \n"; print $outFile "#include \n"; print $outFile "#include \n"; print $outFile "\n"; print $outFile "namespace ERRORLOG\n"; print $outFile "{\n"; print $outFile "using namespace TARGETING;\n"; print $outFile "extern TARG_TD_t g_trac_errl;\n"; print $outFile "//------------------------------------------------------------------------------\n"; print $outFile "ErrlUserDetailsTarget::ErrlUserDetailsTarget(\n"; print $outFile " const Target * i_pTarget,\n"; print $outFile " const char* i_label)\n"; print $outFile "{\n"; print $outFile " // Set up ErrlUserDetails instance variables\n"; print $outFile " iv_CompId = ERRL_COMP_ID;\n"; print $outFile " iv_Version = 1;\n"; print $outFile " iv_SubSection = ERRL_UDT_TARGET;\n"; print $outFile " // override the default of false\n"; print $outFile " iv_merge = true;\n"; print $outFile "\n"; print $outFile " uint8_t* label_buf = NULL;\n"; print $outFile "\n"; print $outFile " if (i_pTarget == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL) {\n"; print $outFile " label_buf = reallocUsrBuf(sizeof(uint32_t)\n"; print $outFile " +sizeof(TargetLabel_t));\n"; print $outFile " uint32_t *pBuffer = reinterpret_cast\n"; print $outFile " (label_buf+sizeof(TargetLabel_t));\n"; print $outFile " // copy 0xFFFFFFFF to indicate MASTER just as gethuid() does\n"; print $outFile " *pBuffer = 0xFFFFFFFF;\n"; print $outFile " } else {\n"; print $outFile " uint32_t bufSize = 0;\n"; print $outFile " uint8_t *pTargetString = i_pTarget->targetFFDC(bufSize);\n"; print $outFile " label_buf = reallocUsrBuf(bufSize+sizeof(TargetLabel_t));\n"; print $outFile " uint8_t* pBuffer = (label_buf+sizeof(TargetLabel_t));\n"; print $outFile " memcpy(pBuffer, pTargetString, bufSize);\n"; print $outFile " free (pTargetString);\n"; print $outFile " }\n"; print $outFile "\n"; print $outFile " // Prepend a label\n"; print $outFile " TargetLabel_t label;\n"; print $outFile " if( i_label )\n"; print $outFile " {\n"; print $outFile " strcpy( label.x, i_label );\n"; print $outFile " }\n"; print $outFile " else // no label, put a generic one in there\n"; print $outFile " {\n"; print $outFile " strcpy( label.x, \"Target\" );\n"; print $outFile " }\n"; print $outFile " memcpy( label_buf, &label, sizeof(label) );\n"; print $outFile "}\n"; print $outFile "\n"; print $outFile "\n"; print $outFile "//------------------------------------------------------------------------------\n"; print $outFile "ErrlUserDetailsTarget::~ErrlUserDetailsTarget()\n"; print $outFile "{ }\n"; print $outFile "} // namespace\n"; } # sub writeTargetErrlCFile ###### #Create a .H file to parse attributes out of the errlog ##### sub writeTargetErrlHFile { my($attributes,$outFile) = @_; #First setup the includes and function definition print $outFile "\n"; print $outFile "#ifndef ERRL_UDTARGET_H\n"; print $outFile "#define ERRL_UDTARGET_H\n"; print $outFile "\n"; print $outFile "namespace ERRORLOG\n"; print $outFile "{\n"; print $outFile "typedef struct TargetLabel_t\n"; print $outFile "{\n"; print $outFile " static const uint32_t LABEL_TAG = 0xEEEEEEEE;\n"; print $outFile " uint32_t tag;\n"; print $outFile " char x[24]; //space to left of divider\n"; print $outFile " TargetLabel_t() : tag(0xEEEEEEEE)\n"; print $outFile " {\n"; print $outFile " memset(x,'\\0',sizeof(x));\n"; print $outFile " };\n"; print $outFile "} TargetLabel_t;\n"; print $outFile "}\n"; print $outFile "#ifndef PARSER\n"; print $outFile "\n"; print $outFile "#include \n"; print $outFile "\n"; print $outFile "namespace TARGETING // Forward reference\n"; print $outFile "{ class Target; }\n"; print $outFile "\n"; print $outFile "namespace ERRORLOG\n"; print $outFile "{\n"; print $outFile "class ErrlUserDetailsTarget : public ErrlUserDetails {\n"; print $outFile "public:\n"; print $outFile "\n"; print $outFile " ErrlUserDetailsTarget(const TARGETING::Target * i_pTarget,\n"; print $outFile " const char* i_label = NULL);\n"; print $outFile " virtual ~ErrlUserDetailsTarget();\n"; print $outFile "\n"; print $outFile "private:\n"; print $outFile "\n"; print $outFile " // Disabled\n"; print $outFile " ErrlUserDetailsTarget(const ErrlUserDetailsTarget &);\n"; print $outFile " ErrlUserDetailsTarget & operator=(const ErrlUserDetailsTarget &);\n"; print $outFile "};\n"; print $outFile "}\n"; print $outFile "#else // if PARSER defined\n"; print $outFile "\n"; print $outFile "#include \"errluserdetails.H\"\n"; print $outFile "#include \n"; print $outFile "\n"; print $outFile "namespace ERRORLOG\n"; print $outFile "{\n"; # local function used by Target and Callout to print the entity path print $outFile " static uint8_t *errlud_parse_entity_path(uint8_t *i_ptr, char *o_ptr)\n"; print $outFile " {\n"; print $outFile " uint8_t *l_ptr = i_ptr;\n"; print $outFile " // from targeting/common/entitypath.[CH]\n"; print $outFile " // entityPath is PATH_TYPE:4, NumberOfElements:4, \n"; print $outFile " // [Element, Instance#]\n"; print $outFile " // PATH_TYPE\n"; print $outFile " const char *pathString;\n"; print $outFile " const uint8_t pathTypeLength = *l_ptr;\n"; print $outFile " l_ptr++;\n"; print $outFile " const uint8_t pathType = (pathTypeLength & 0xF0) >> 4;\n"; print $outFile " switch (pathType) {\n"; print $outFile " case 0x01: pathString = \"Logical:\"; break;\n"; print $outFile " case 0x02: pathString = \"Physical:\"; break;\n"; print $outFile " case 0x03: pathString = \"Device:\"; break;\n"; print $outFile " case 0x04: pathString = \"Power:\"; break;\n"; print $outFile " default: pathString = \"Unknown:\"; break;\n"; print $outFile " }\n"; print $outFile " uint32_t dataSize = sprintf(o_ptr, \"%s\",pathString);\n"; print $outFile " const uint8_t pathSize = (pathTypeLength & 0x0F) * 2;\n"; print $outFile " uint8_t *lElementInstance = l_ptr;\n"; print $outFile " l_ptr += pathSize * sizeof(uint8_t);\n"; print $outFile " for (uint32_t j=0;j{enumerationType}}) { if( $enumerationType->{id} eq "TYPE" ) { foreach my $enumerator (@{$enumerationType->{enumerator}}) { my $enumHex = sprintf "0x%02X", enumNameToValue($enumerationType,$enumerator->{name}); #my $enumName = $enumerationType->{id} . "_" . $enumerator->{name}; my $enumName = $enumerator->{name}; if ($enumName eq "SYS") { $enumName = "Sys"; } elsif ($enumName eq "PROC") { $enumName = "Proc"; } elsif ($enumName eq "NODE") { $enumName = "Node"; } elsif ($enumName eq "CORE") { $enumName = "Core"; } elsif ($enumName eq "MEMBUF") { $enumName = "Membuf"; } print $outFile " case $enumHex: { pathString = \"/$enumName\"; break; }\n"; } } } # enumerationType print $outFile " default: { pathString = \"/UKNOWN\"; break; }\n"; print $outFile " } // switch\n"; print $outFile " // copy next part in, overwritting previous terminator\n"; print $outFile " dataSize += sprintf(o_ptr + dataSize,\n"; print $outFile " \"%s%d\", pathString,\n"; print $outFile " lElementInstance[j+1]);\n"; print $outFile " } // for\n"; print $outFile " return l_ptr;\n"; print $outFile "} // errlud_parse_entity_path \n"; print $outFile "class ErrlUserDetailsParserTarget : public ErrlUserDetailsParser {\n"; print $outFile "public:\n"; print $outFile "\n"; print $outFile " ErrlUserDetailsParserTarget() {}\n"; print $outFile "\n"; print $outFile " virtual ~ErrlUserDetailsParserTarget() {}\n"; print $outFile "/**\n"; print $outFile " * \@brief Parses Target user detail data from an error log\n"; print $outFile " * \@param i_version Version of the data\n"; print $outFile " * \@param i_parse ErrlUsrParser object for outputting information\n"; print $outFile " * \@param i_pBuffer Pointer to buffer containing detail data\n"; print $outFile " * \@param i_buflen Length of the buffer\n"; print $outFile " */\n"; print $outFile " virtual void parse(errlver_t i_version,\n"; print $outFile " ErrlUsrParser & i_parser,\n"; print $outFile " void * i_pBuffer,\n"; print $outFile " const uint32_t i_buflen) const\n"; print $outFile " {\n"; print $outFile " const char *attrData;\n"; print $outFile " char l_label[24];\n"; print $outFile " sprintf(l_label,\"Target\");\n"; print $outFile " uint32_t *l_ptr32 = reinterpret_cast(i_pBuffer);\n"; print $outFile " // while there is still at least 1 word of data left\n"; print $outFile " for (; (l_ptr32 + 1) <= (uint32_t *)((uint8_t*)i_pBuffer + i_buflen); )\n"; print $outFile " {\n"; print $outFile " if (*l_ptr32 == 0xFFFFFFFF) { // special - master\n"; print $outFile " i_parser.PrintString(\"Target\", \"MASTER_PROCESSOR_CHIP_TARGET_SENTINEL\");\n"; print $outFile " l_ptr32++; // past the marker\n"; print $outFile " } else if (*l_ptr32 == TargetLabel_t::LABEL_TAG) {\n"; print $outFile " TargetLabel_t* tmp_label = reinterpret_cast(l_ptr32);\n"; print $outFile " memcpy( l_label, tmp_label->x, sizeof(l_label)-1 );\n"; print $outFile " l_ptr32 += (sizeof(TargetLabel_t)/sizeof(uint32_t));\n"; print $outFile " } else { \n"; print $outFile " // first 4 are always the same\n"; print $outFile " if ((l_ptr32 + 4) <= (uint32_t *)((uint8_t*)i_pBuffer + i_buflen)) {\n"; print $outFile " i_parser.PrintNumber( l_label, \"HUID = 0x%08X\", ntohl(*l_ptr32) );\n"; print $outFile " l_ptr32++;\n"; # find CLASS print $outFile " switch (ntohl(*l_ptr32)) { // CLASS\n"; foreach my $enumerationType (@{$attributes->{enumerationType}}) { if( $enumerationType->{id} eq "CLASS" ) { foreach my $enumerator (@{$enumerationType->{enumerator}}) { my $enumHex = sprintf "0x%02X", enumNameToValue($enumerationType,$enumerator->{name}); my $enumName = $enumerationType->{id} . "_" . $enumerator->{name}; print $outFile " case $enumHex: { attrData = \"$enumName\"; break; }\n"; } } } # enumerationType print $outFile " default: { attrData = \"UNKNOWN_CLASS\"; break; }\n"; print $outFile " } // switch\n"; print $outFile " i_parser.PrintString(\" ATTR_CLASS\", attrData);\n"; print $outFile " l_ptr32++;\n"; # find TYPE print $outFile " switch (ntohl(*l_ptr32)) { // TYPE\n"; foreach my $enumerationType (@{$attributes->{enumerationType}}) { if( $enumerationType->{id} eq "TYPE" ) { foreach my $enumerator (@{$enumerationType->{enumerator}}) { my $enumHex = sprintf "0x%02X", enumNameToValue($enumerationType,$enumerator->{name}); my $enumName = $enumerationType->{id} . "_" . $enumerator->{name}; print $outFile " case $enumHex: { attrData = \"$enumName\"; break; }\n"; } } } # enumerationType print $outFile " default: { attrData = \"UNKNOWN_TYPE\"; break; }\n"; print $outFile " } // switch\n"; print $outFile " i_parser.PrintString(\" ATTR_TYPE\", attrData);\n"; print $outFile " l_ptr32++;\n"; # find MODEL print $outFile " switch (ntohl(*l_ptr32)) { // MODEL\n"; foreach my $enumerationType (@{$attributes->{enumerationType}}) { if( $enumerationType->{id} eq "MODEL" ) { foreach my $enumerator (@{$enumerationType->{enumerator}}) { my $enumHex = sprintf "0x%02X", enumNameToValue($enumerationType,$enumerator->{name}); my $enumName = $enumerationType->{id} . "_" . $enumerator->{name}; print $outFile " case $enumHex: { attrData = \"$enumName\"; break; }\n"; } } } # enumerationType print $outFile " default: { attrData = \"UNKNOWN_MODEL\"; break; }\n"; print $outFile " } // switch\n"; print $outFile " i_parser.PrintString(\" ATTR_MODEL\", attrData);\n"; print $outFile " l_ptr32++;\n"; print $outFile " // 2 Entity Paths next\n"; print $outFile " for (uint32_t k = 0;k < 2; k++)\n"; print $outFile " {\n"; my $attrPhysPath; my $attrAffinityPath; # need the attribute id's for ATTR_PHYS_PATH and ATTR_AFFINITY_PATH: my $attributeIdEnumeration = getAttributeIdEnumeration($attributes); foreach my $enumerator (@{$attributeIdEnumeration->{enumerator}}) { if ($enumerator->{name} eq "PHYS_PATH") { $attrPhysPath = $enumerator->{value}; } elsif ($enumerator->{name} eq "AFFINITY_PATH") { $attrAffinityPath = $enumerator->{value}; } } print $outFile " uint32_t l_pathType = ntohl(*l_ptr32);\n"; print $outFile " if ((l_pathType == $attrPhysPath) || // ATTR_PHYS_PATH\n"; print $outFile " (l_pathType == $attrAffinityPath)) // ATTR_AFFINITY_PATH\n"; print $outFile " {\n"; print $outFile " l_ptr32++;\n"; print $outFile " uint8_t *l_ptr = reinterpret_cast(l_ptr32);\n"; print $outFile " char outString[128];\n"; print $outFile " l_ptr = errlud_parse_entity_path(l_ptr,outString);\n"; print $outFile " if (l_pathType == $attrPhysPath)\n"; print $outFile " {\n"; print $outFile " i_parser.PrintString(\" ATTR_PHYS_PATH\", outString);\n"; print $outFile " }\n"; print $outFile " if (l_pathType == $attrAffinityPath)\n"; print $outFile " {\n"; print $outFile " i_parser.PrintString(\" ATTR_AFFINITY_PATH\", outString);\n"; print $outFile " } // else don't print anything\n"; print $outFile " l_ptr32 = reinterpret_cast(l_ptr);\n"; print $outFile " } else {\n"; print $outFile " l_ptr32++;\n"; print $outFile " }\n"; print $outFile " } // for\n"; print $outFile " } // if\n"; print $outFile " }\n"; print $outFile " } // for\n"; print $outFile " } // parse()\n\n"; print $outFile "private:\n"; print $outFile "\n"; print $outFile "// Disabled\n"; print $outFile "ErrlUserDetailsParserTarget(const ErrlUserDetailsParserTarget &);\n"; print $outFile "ErrlUserDetailsParserTarget & operator=(const ErrlUserDetailsParserTarget &);\n"; print $outFile "};\n"; print $outFile "} // namespace\n"; print $outFile "#endif\n"; print $outFile "#endif\n"; } # sub writeTargetErrlHFile ################################################################################ # Writes the map system attr size C file header ################################################################################ sub writeAttrSizeMapCFileHeader { my($outFile) = @_; print $outFile < // TARG #include //****************************************************************************** // Macros //****************************************************************************** #undef TARG_NAMESPACE #undef TARG_CLASS #undef TARG_FUNC //****************************************************************************** // Implementation //****************************************************************************** namespace TARGETING { #define TARG_NAMESPACE "TARGETING::" #define TARG_CLASS "MapSystemAttrSize::" //****************************************************************************** // TARGETING::mapSystemAttrSize //****************************************************************************** TARGETING::MapSystemAttrSize& mapSystemAttrSize() { #define TARG_FN "mapSystemAttrSize()" return TARG_GET_SINGLETON(TARGETING::theMapSystemAttrSize); #undef TARG_FN } //****************************************************************************** // TARGETING::MapSystemAttrSize::~MapSystemAttrSize //****************************************************************************** MapSystemAttrSize::~MapSystemAttrSize() { #define TARG_FN "~MapSystemAttrSize()" #undef TARG_FN } //****************************************************************************** // TARGETING::MapSystemAttrSize::getMapForWriteableSystemAttributes //****************************************************************************** const AttrSizeMapper& MapSystemAttrSize::getMapForWriteableSystemAttributes() const { #define TARG_FN "getMapForWriteableSystemAttributes()" TARG_ENTER(); TARG_EXIT(); return iv_mapSysAttrSize; #undef TARG_FN } //****************************************************************************** // TARGETING::MapSystemAttrSize::MapSystemAttrSize //****************************************************************************** MapSystemAttrSize::MapSystemAttrSize() { #define TARG_FN "MapSystemAttrSize()" VERBATIM } ###### # Create a .C file to put System Target Attributes along with there respective # Size in a map file ###### sub writeAttrSizeMapCFile{ my($attributes,$outFile) = @_; my %finalAttrhash = (); # look for type sys-sys-power8 and store all attributes associated foreach my $targetType (@{$attributes->{targetType}}) { if($targetType->{id} =~ m/^sys-sys-/) { my %attrhash = (); getTargetAttributes($targetType->{id}, $attributes,\%attrhash); foreach my $key ( keys %attrhash ) { foreach my $attr (@{$attributes->{attribute}}) { if($attr->{id} eq $key) { if((exists $attr->{writeable}) && (!(exists $attr->{hbOnly}))) { # we have the attr here.. calculate the size my $keyVal = "ATTR_"."$key"."_type"; if( (exists $attr->{simpleType}) || (exists $attr->{complexType}) || (exists $attr->{nativeType}) ) { $finalAttrhash{$key} = $keyVal; } else { print STDOUT "\t// Attribute $key is writable " . "& Not Supported \n"; } } } } } } } print $outFile "\n"; foreach my $key ( keys %finalAttrhash) { print $outFile " iv_mapSysAttrSize[ATTR_" . "$key] = sizeof($finalAttrhash{$key});\n"; } print $outFile "\n"; } ################################################################################ # Writes the map system attr size C file Footer ################################################################################ sub writeAttrSizeMapCFileFooter { my($outFile) = @_; print $outFile < // TARG #include #include //****************************************************************************** // Macros //****************************************************************************** #undef TARG_NAMESPACE #undef TARG_CLASS #undef TARG_FUNC //****************************************************************************** // Interface //****************************************************************************** namespace TARGETING { class MapSystemAttrSize; /** * \@brief Return the MapSystemAttrSize singleton instance * * \@return Reference to the MapSystemAttrSize singleton */ TARGETING::MapSystemAttrSize& mapSystemAttrSize(); #define TARG_NAMESPACE "MAPSYSTEMATTRSIZE::" #define TARG_CLASS "MapSystemAttrSize::" /* * \@brief Typedef map */ typedef std::map AttrSizeMapper; class MapSystemAttrSize { public: /** * \@brief Destroy the MapSystemAttrSize class */ ~MapSystemAttrSize(); /** * \@brief Create the MapSystemAttrSize class */ MapSystemAttrSize(); /* * \@brief returns the map of Writeable System attributes as Key and * size of the attributes as value. * * \@return, returns the map which has the Writeable Sytem attributes * as key and size as value pair, variable */ const AttrSizeMapper& getMapForWriteableSystemAttributes() const; private: /* Map variable for System Attribute Ids Vs the Size */ AttrSizeMapper iv_mapSysAttrSize; /* Disable Copy constructor and assignment operator */ MapSystemAttrSize( const MapSystemAttrSize& i_right); MapSystemAttrSize& operator = ( const MapSystemAttrSize& i_right); }; /** * \@brief Provide singleton access to the MapSystemAttrSize */ TARG_DECLARE_SINGLETON(TARGETING::MapSystemAttrSize, theMapSystemAttrSize); #undef TARG_CLASS #undef TARG_NAMESPACE }// namespace TARGETING #endif // MAPSYSTEMATTRSIZE_H VERBATIM } sub UTILITY_FUNCTIONS { } ################################################################################ # Get the hash hex string for an attribute name (ID). ################################################################################ sub getAttributeIdHashStr { my ($attrId) = @_; return substr(md5_hex($attrId),0,7); } ################################################################################ # Get generated enumeration describing attribute IDs ################################################################################ sub getAttributeIdEnumeration { my($attributes) = @_; my $attributeValue = 1; my $enumeration = { } ; my %attrValHash; # add the N/A value $enumeration->{description} = "Internal enum for attribute IDs\n"; $enumeration->{default} = "NA"; $enumeration->{enumerator}->[0]->{name} = "NA"; $enumeration->{enumerator}->[0]->{value} = 0; foreach my $attribute (@{$attributes->{attribute}}) { my $attributeHexVal28bit = getAttributeIdHashStr($attribute->{id}); # check if this Id has already been processed if(exists($attrValHash{$attributeHexVal28bit})) { # fatal error if multiple IDs hash to same value if ( $attribute->{id} ne $attrValHash{$attributeHexVal28bit} ) { fatal( "Error:Duplicate AttributeId hashvalue for $attribute->{id} " . "and $attrValHash{$attributeHexVal28bit}"); } # fatal error if attribute has been defined more than once. # Could be defined twice in same file or defined in two files # that have been merged, such as attributes_types.xml and # attribute_types_hb.xml or attributes_types_fsp. else { fatal("Error: AttributeId $attribute->{id} " . "defined multiple times"); } } else { # add the name here so we can check for duplicate names $attrValHash{$attributeHexVal28bit}= $attribute->{id}; $enumeration->{enumerator}->[$attributeValue]->{name} = $attribute->{id}; $enumeration->{enumerator}->[$attributeValue]->{value} = sprintf "0x%s",$attributeHexVal28bit; $attribute->{value} = $attributeValue; $attributeValue++; } } return $enumeration; } ################################################################################ # If value is hex, convert to regular number ############################################################################### sub unhexify { my($val) = @_; if($val =~ m/^0[xX][01234567890A-Fa-f]+$/) { $val = hex($val); } return $val; } ################################################################################ # Pack 8 byte value into a buffer using configured endianness ################################################################################ sub pack8byte { my($quad) = @_; my $value = unhexify($quad); my $binaryData; if($cfgBigEndian) { $binaryData = pack("NN" , (($value >> 32) & 0xFFFFFFFF), ($value & 0xFFFFFFFF)); } else # Little endian { # Invert the words, then reverse them individually $binaryData = pack("VV" , ($value & 0xFFFFFFFF), (($value >> 32) & 0xFFFFFFFF)); } return $binaryData; } sub pack64bitsDecimal { my($quad) = @_; my $package = unpack("H*", pack8byte($quad)); if(!$cfgBigEndian) { my $val1 = sprintf("%08x", ((hex($package) >> 32) & 0xFFFFFFFF)); my $val2 = sprintf("%08x", (hex($package) & 0xFFFFFFFF)); $package = $val1.$val2; } return hex($package); } ################################################################################ # Pack 4 byte value into a buffer using configured endianness ################################################################################ sub pack4byte { my($value) = @_; my $binaryData; if($cfgBigEndian) { $binaryData = pack("N",$value); } else # Little endian { $binaryData = pack("V",$value); } return $binaryData; } ################################################################################ # Pack 2 byte value into a buffer using configured endianness ################################################################################ sub pack2byte { my($value) = @_; my $binaryData; if($cfgBigEndian) { $binaryData = pack("n",$value); } else # Little endian { $binaryData = pack("v",$value); } return $binaryData; } ################################################################################ # Pack 1 byte value into a buffer using configured endianness ################################################################################ sub pack1byte { my($value) = @_; my $binaryData = pack("C",$value); return $binaryData; } ################################################################################ # Pack string into buffer ################################################################################ sub packString{ my($value,$attribute) = @_; # Proper attribute tags already verified, no need to do checking again my $sizeInclNull = $attribute->{simpleType}->{string}->{sizeInclNull}; # print "String content (before fixup) is [$value]\n"; # For sanity, remove all white space from front and end of string $value =~ s/^\s+//g; $value =~ s/\s+$//g; my $length = length($value); # print "String content (after fixup) is [$value]\n"; # print "String length is $length\n"; # print "String container size is $sizeInclNull\n"; if(($length + 1) > $sizeInclNull) { fatal("ERROR: Supplied string exceeds allows length"); } return pack("Z$sizeInclNull",$value); } ################################################################################ # Get space required to store an enum, based on the max value ################################################################################ sub enumSpace { my($maxEnumVal) = @_; if($maxEnumVal == 0) { # Enum needs at least one byte $maxEnumVal++; } # NOTE: Pass --noshort-enums command line option to force the code generator # to generate 4-byte enums instead of optimized enums. Note there are a few # enumerations (primarily in PNOR header, etc.) that do not change size. # That is intentional in order to make this the single point of control over # binary compatibility. Note that both FSP and Hostboot should always have # this policy in sync. Also note that when Hostboot and FSP use optimized # enums, they must also be compiled with -fshort-enums compile option my $space = ($cfgShortEnums == 1) ? ceil(log($maxEnumVal+1) / (8 * log(2))) : 4; return $space; } ################################################################################ # Get mininum # of bytes, in block size chunks, able to contain the input data ################################################################################ sub sizeBlockAligned { my ($size,$blockSize,$oneBlockMinimum) = @_; if( (!defined $size) || (!defined $blockSize) || (!defined $oneBlockMinimum) ) { fatal("Caller must specify 'size', 'blockSize', 'oneBlockMinimum' " . "args."); } if(!$blockSize) { fatal("'blockSize' arg must be > 0."); } if(($size % $blockSize) || (($size==0) && $oneBlockMinimum) ) { $size += ($blockSize - ($size % $blockSize)); } return $size; } ################################################################################ # Strips off leading and trailing whitespace from a string and returns it ################################################################################ sub stripLeadingAndTrailingWhitespace { my($string) = @_; $string =~ s/^\s+|\s+$//g; return $string; } ################################################################################ # Optimize white space for C++/doxygen documentation ################################################################################ sub optWhiteSpace { my($text) = @_; # Remove leading, trailing white space, then collapse excess internal # whitespace $text =~ s/^\s+|\s+$//g; $text =~ s/\s+/ /g; return $text; } ################################################################################ # Wrap text into a C++/doxygen brief description ################################################################################ sub wrapBrief { my($text) = @_; my $brief_start = " * \@brief "; my $brief_continue = " * "; return wrap($brief_start,$brief_continue, optWhiteSpace($text))."\n"; } ################################################################################ # Wrap text into a C++ style comment ################################################################################ sub wrapComment { my($text) = @_; my $comment_start = " // "; my $comment_continue = " // "; return wrap($comment_start,$comment_continue,optWhiteSpace($text))."\n"; } ################################################################################ # Calculate struct type name for a header file, based on its ID ################################################################################ sub calculateStructName { my($id) = @_; my $type = ""; # Struct name is original ID with underscores removed and first letter of # each word capitalized my @words = split(/_/,$id); foreach my $word (@words) { $type .= ucfirst( lc($word) ); } return $type; } ################################################################################ # Return array containing only distinct target types that are actally in use ################################################################################ sub getInstantiatedTargetTypes { my($attributes) = @_; my %seen = (); my @uniqueTargetTypes = (); my $targetCount = 0; my $moveSysTarget = 0; # To simplify the iterator code, always move a system target that appears as # the first target to the next position foreach my $targetInstance (@{$attributes->{targetInstance}}) { if(($targetInstance->{type} =~ m/^sys-sys-/) && ($targetCount == 0)) { $targetCount = $targetCount + 1; $moveSysTarget = 1; } push (@uniqueTargetTypes, $targetInstance->{type}) unless $seen{$targetInstance->{type}}++; } if($moveSysTarget == 1) { @uniqueTargetTypes[0,1] = @uniqueTargetTypes[1,0]; } return @uniqueTargetTypes; } ################################################################################ # Return default value of zero for an attribute which is a POD numerical type ################################################################################ sub defaultZero { my($attributes,$typeInstance) = @_; # print STDOUT "Attribute's default value is 0\n"; return 0; } ################################################################################ # Return string default (empty string) ################################################################################ sub defaultString { my($attributes,$typeInstance) = @_; return ""; } ################################################################################ # Return default value for an attribute whose type is 'enumeration' ################################################################################ sub defaultEnum { my($attributes,$enumerationInstance) = @_; my $enumerationType = getEnumerationType( $attributes,$enumerationInstance->{id}); # print STDOUT "Attribute enumeration's " . # "(\"$enumerationType->{id}\") default is: " . # $enumerationType->{default} . "\n"; return $enumerationType->{default}; } ################################################################################ # Do nothing ################################################################################ sub null { } ################################################################################ # Enforce special fsp mutex restrictions ################################################################################ sub enforceFspMutex { my($attribute,$value) = @_; if($value != 0) { fatal("FSP mutex attribute default must always be 0, " . "was $value instead."); } if($attribute->{persistency} ne "volatile-zeroed") { fatal("FSP mutex attribute persistency must be volatile-zeroed, " . "was $attribute->{persistency} instead"); } } ################################################################################ # 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"); } } ################################################################################ # Enforce string restrictions ################################################################################ sub enforceString { my($attribute,$value) = @_; if(!exists $attribute->{simpleType}) { fatal("ERROR: Tried to enforce string policies on a non-simple type"); } if(!exists $attribute->{simpleType}->{string}) { fatal("ERROR: Did not find expected string element"); } if(!exists $attribute->{simpleType}->{string}->{sizeInclNull}) { fatal("ERROR: Did not find expected string sizeInclNull element"); } my $size = $attribute->{simpleType}->{string}->{sizeInclNull}; if($size <= 1) { fatal("ERROR: String size must be > 1 (string of size one is " . "only big enough to hold the empty string, which is not " . "useful)"); } } ################################################################################ # Get hash ref to supported simple types and their properties ################################################################################ my $g_simpleTypeProperties_cache = 0; sub simpleTypeProperties { return $g_simpleTypeProperties_cache if ($g_simpleTypeProperties_cache); my %typesHoH = (); # Intentionally didn't wrap these to 80 columns to keep them lined up and # more readable/editable $typesHoH{"string"} = { supportsArray => 0, canBeHex => 0, complexTypeSupport => 0, typeName => "char" , bytes => 1, bits => 8 , default => \&defaultString, alignment => 1, specialPolicies =>\&enforceString, packfmt =>\&packString}; $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 =>\&pack2byte}; $typesHoH{"int32_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "int32_t" , bytes => 4, bits => 32, default => \&defaultZero , alignment => 1, specialPolicies =>\&null, packfmt =>\&pack4byte}; $typesHoH{"int64_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "int64_t" , bytes => 8, bits => 64, default => \&defaultZero , alignment => 1, specialPolicies =>\&null, packfmt =>\&pack8byte}; $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 =>\&pack2byte}; $typesHoH{"uint32_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "uint32_t" , bytes => 4, bits => 32, default => \&defaultZero , alignment => 1, specialPolicies =>\&null, packfmt =>\&pack4byte}; $typesHoH{"uint64_t"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 1, typeName => "uint64_t" , bytes => 8, bits => 64, default => \&defaultZero , alignment => 1, specialPolicies =>\&null, packfmt =>\&pack8byte}; $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 =>\&pack8byte}; $typesHoH{"Target_t"} = { supportsArray => 0, canBeHex => 1, complexTypeSupport => 0, typeName => "TARGETING::Target*" , bytes => 8, bits => 64, default => \&defaultZero , alignment => 8, specialPolicies =>\&null, packfmt =>\&pack8byte}; $typesHoH{"fspmutex"} = { supportsArray => 1, canBeHex => 1, complexTypeSupport => 0, typeName => "util::Mutex*" , bytes => 8, bits => 64, default => \&defaultZero , alignment => 8, specialPolicies =>\&enforceFspMutex, packfmt =>\&pack8byte}; $g_simpleTypeProperties_cache = \%typesHoH; return $g_simpleTypeProperties_cache; } ################################################################################ # Get attribute default ################################################################################ sub getAttributeDefault { my($attributeId,$attributes) = @_; my $default = ""; my $simpleTypeProperties = simpleTypeProperties(); foreach my $attribute (@{$attributes->{attribute}}) { if ($attribute->{id} eq $attributeId) { if(exists $attribute->{simpleType}) { for my $type (sort(keys %{$simpleTypeProperties})) { # Note: must check for 'type' before 'default', otherwise # might add value to the hash if(exists $attribute->{simpleType}->{$type} ) { # If attribute exists, or is not a HASH val (which can # occur if the default element is omitted), then just # grab the supplied value, otherwise use the default for # the type if( (exists $attribute->{simpleType}->{$type}-> {default}) && (ref ($attribute->{simpleType}->{$type}-> {default}) ne "HASH") ) { $default = $attribute->{simpleType}->{$type}->{default}; } else { $default = $simpleTypeProperties->{$type}{default}->( $attributes,$attribute->{simpleType}->{$type} ); } last; } } } elsif(exists $attribute->{complexType}) { my $cplxDefault = { } ; my $i = 0; foreach my $field (@{$attribute->{complexType}->{field}}) { $cplxDefault->{field}->[$i]->{id} = $field->{name}; $cplxDefault->{field}->[$i]->{value} = $field->{default}; $i++; } return $cplxDefault; } elsif(exists $attribute->{nativeType}) { if( exists $attribute->{nativeType}->{name} && ($attribute->{nativeType}->{name} eq "EntityPath")) { if( exists $attribute->{nativeType}->{default} ) { $default = $attribute->{nativeType}->{default}; } else { $default = "MustBeOverriddenByTargetInstance"; } } else { fatal("Cannot provide default for unsupported nativeType."); } } else { fatal("Unrecognized value type."); } last; } } return $default; } ################################################################################ # Get target attributes ################################################################################ sub getTargetAttributes { my($type,$attributes,$attrhasha) = @_; foreach my $targetType (@{$attributes->{targetType}}) { if($targetType->{id} eq $type) { if(exists $targetType->{parent}) { getTargetAttributes($targetType->{parent}, $attributes,$attrhasha); } foreach my $attr (@{$targetType->{attribute}}) { $attrhasha->{ $attr->{id} } = $attr; if(!exists $attrhasha->{ $attr->{id}}->{default}) { my $default = getAttributeDefault($attr->{id},$attributes); $attrhasha->{ $attr->{id}}->{default} = $default; } } last; } } } ################################################################################ # Compute maximum enumerator value for a given enumeration ################################################################################ sub maxEnumValue { my($enumeration) = @_; my $max = 0; my $candidateMax = 0; foreach my $enumerator (@{$enumeration->{enumerator}}) { my $candidateMax = enumNameToValue($enumeration,$enumerator->{name}); if($candidateMax > $max) { $max = $candidateMax; } } return $max; } ################################################################################ # Serialize an enumeration to data buffer ################################################################################ sub packEnumeration { my($enumeration,$value) = @_; my $binaryData; # Determine space required for max enum my $bytes = enumSpace( maxEnumValue($enumeration) ); $value = unhexify($value); # Encode the value for (my $count=$bytes-1; $count >= 0; $count--) { if($cfgBigEndian) { $binaryData .= pack1byte(0xFF & ($value >> (8*$count))); } else # Little endian { $binaryData .= pack1byte( 0xFF & ($value >> (8*($bytes - 1 - $count)))); } } if( (length $binaryData) < 1) { fatal("Failed to write binary data for enumeration."); } #print " Enum description: ", $enumeration->{description}, "\n"; #print "Enum storage space required: ", $bytes, "\n"; #print " Value encoded: ", $value, "\n"; #print " Final length of encode: ", (length $binaryData), "\n"; return $binaryData; } ################################################################################ # Convert enumerator name into equivalent enumerator value for given enumeration ################################################################################ sub enumNameToValue { my ($enumeration,$enumeratorName) = @_; my $nextEnumeratorValue = 0; my $found = 0; my $enumeratorValue; if (defined $enumeration->{__optimized}) { if (defined $enumeration->{__optimized}->{$enumeratorName}) { $found = 1; $enumeratorValue = $enumeration->{__optimized}->{$enumeratorName}; } } else { foreach my $enumerator (@{$enumeration->{enumerator}}) { my $currentEnumeratorValue; if(exists $enumerator->{value} ) { $currentEnumeratorValue = unhexify($enumerator->{value}); $nextEnumeratorValue = $currentEnumeratorValue + 1; } else { $currentEnumeratorValue = $nextEnumeratorValue; $nextEnumeratorValue += 1; } $enumeration->{__optimized}->{$enumerator->{name}} = $currentEnumeratorValue; if($enumerator->{name} eq $enumeratorName) { $found = 1; $enumeratorValue = $currentEnumeratorValue; } } } if(!$found) { my $enumerationName = $enumeration->{id}; print STDOUT $enumeration; fatal("dc99> Could not convert enumerator name \"$enumeratorName\"into " . "enumerator value in \"$enumerationName\". enum="); #dc99 } if($enumeratorValue < 0) { # In C++ enumerations are unsigned, we do not support negative values. fatal("Negative enumeration value found $enumeration->{id}," ." $enumeratorValue"); } return $enumeratorValue; } ################################################################################ # Query if target instance is an FSP target ################################################################################ my %g_fspTargetTypesCache = (); sub isFspTargetInstance { my($attributes,$targetInstance) = @_; my $fspTargetInstance = 0; if(%g_fspTargetTypesCache) { $fspTargetInstance = $g_fspTargetTypesCache{$targetInstance->{type}}; } else { %g_fspTargetTypesCache = map { $_->{id} => exists $_->{fspOnly} ? 1:0 } @{$attributes->{targetType}}; $fspTargetInstance = $g_fspTargetTypesCache{$targetInstance->{type}}; } return $fspTargetInstance; } ################################################################################ # Object which accumulates/flushes bit field data ################################################################################ { package Accumulator; ################################################################################ # Constructor; create a new Accumulator object ################################################################################ sub new { my ($class) = @_; my $self = { _currentType => "", _accumulator => "", _bits => 0 }; bless $self, $class; return $self; } ################################################################################ # Accumulate a new bit field ################################################################################ sub accumulate { my($self,$type,$bits,$value) = @_; my $binaryData; my $simpleTypeProperties = main::simpleTypeProperties(); if($bits > $simpleTypeProperties->{$type}{bits}) { main::fatal("Too many bits ($bits) for type ($type)."); } if($self->{_currentType} eq "") { $self->{_currentType} = $type; $self->{_bits} = $bits; } elsif($self->{_currentType} eq $type) { if($self->{_bits} + $bits > $simpleTypeProperties->{$self->{_currentType}}{bits}) { $binaryData = $self->releaseAndClear(); $self->{_currentType} = $type; $self->{_bits} = $bits; } else { $self->{_bits} += $bits; } } else { $binaryData = $self->releaseAndClear(); $self->{_currentType} = $type; $self->{_bits} = $bits; } for(my $count = 0; $count < $bits; $count++) { if($cfgBigEndian) { if( 1 & ($value >> $bits - $count - 1)) { $self->{_accumulator} .= "1"; } else { $self->{_accumulator} .= "0"; } } else { if( 1 & ($value >> $count)) { $self->{_accumulator} .= "1"; } else { $self->{_accumulator} .= "0"; } } } return $binaryData; } ################################################################################ # Release the accumulator (if non-empty) to the caller and clear ################################################################################ sub releaseAndClear { my($self) = @_; my $binaryData; if($self->{_currentType} ne "") { my $simpleTypeProperties = main::simpleTypeProperties(); if($cfgBigEndian) { $binaryData = pack ("B$simpleTypeProperties->{$self->{_currentType}}{bits}", $self->{_accumulator}); } else # Little endian, inverse order { $binaryData = pack ("b$simpleTypeProperties->{$self->{_currentType}}{bits}", $self->{_accumulator}); } $self->{_accumulator} = ""; $self->{_currentType} = ""; $self->{_bits} = 0; } return $binaryData; } 1; } ################################################################################ # Pack a complex type into a binary data stream ################################################################################ sub packComplexType { my ($attributes,$complexType,$attributeDefault) = @_; my $binaryData; my $simpleTypeProperties = simpleTypeProperties(); my $accumulator = new Accumulator(); # Build using each field foreach my $field (@{$complexType->{field}}) { # print STDERR "Field = ", $field->{name}, "\n"; # print STDERR "Default = ", $field->{default}, "\n"; # print STDERR "Bits = ", $field->{bits}, "\n"; # print STDERR "Type = ", $field->{type}, "\n"; my $found = 0; foreach my $default (@{$attributeDefault->{field}}) { if($default->{id} eq $field->{name}) { $found = 1; if(exists $field->{bits}) { $binaryData .= $accumulator->accumulate( $field->{type},unhexify($field->{bits}), unhexify($default->{value})); } # If non-bitfield else { $binaryData .= $accumulator->releaseAndClear(); # If native "EntityPath" type, process accordingly if($field->{type} eq "EntityPath") { $binaryData .= packEntityPath($attributes, $default->{value}); } # If not a defined simple type, process as an enumeration elsif(!exists $simpleTypeProperties->{$field->{type}}) { my $enumerationType = getEnumerationType( $attributes,$field->{type}); my $enumeratorValue = enumNameToValue($enumerationType, $default->{value}); $binaryData .= packEnumeration($enumerationType, $enumeratorValue); } # Pack easy types using 'pack', otherwise invoke appropriate # (possibly workaround) callback function elsif(exists $simpleTypeProperties->{$field->{type}} && $simpleTypeProperties->{$field->{type}} {complexTypeSupport}) { my $defaultValue = $default->{value}; if($simpleTypeProperties->{$field->{type}}{canBeHex}) { $defaultValue = unhexify($defaultValue); } if(ref ($simpleTypeProperties->{$field->{type}} {packfmt}) eq "CODE") { $binaryData .= $simpleTypeProperties->{$field->{type}} {packfmt}->($defaultValue); } else { $binaryData .= pack( $simpleTypeProperties->{$field->{type}} {packfmt},$defaultValue); } } else { fatal("Field type $field->{type} not supported in " . "complex type."); } } last; } } if(!$found) { fatal("Could not find value for field $field->{name} of type $field->{type}"); } } $binaryData .= $accumulator->releaseAndClear(); return $binaryData; } ################################################################################ # Pack an entity path into a binary data stream ################################################################################ sub packEntityPath { my($attributes,$value) = @_; my $binaryData; my $maxPathElements = 10; my ($typeStr,$path) = split(/:/,$value); my (@paths) = split(/\//,$path); my $type = 0; # Trim whitespace from the type $typeStr =~ s/^\s+|\s+$//g; if($typeStr eq "physical") { $type = 2; } elsif($typeStr eq "affinity") { $type = 1; } else { fatal("Unsupported entity path type of [$value], [$typeStr], [$path]."); } if( (scalar @paths) > $maxPathElements) { fatal("Path elements cannot be greater than $maxPathElements."); } if($cfgBigEndian) { $binaryData .= pack1byte((0xF0 & ($type << 4)) + (0x0F & (scalar @paths))); } else # Little endian { $binaryData .= pack1byte((0x0F & ($type)) + (0xF0 & ((scalar @paths) << 4))); } foreach my $pathElement (@paths) { my ($pathType,$pathInstance) = split(/-/,$pathElement); $pathType = uc($pathType); foreach my $attr (@{$attributes->{attribute}}) { if($attr->{id} eq "TYPE") { $pathType = enumNameToValue( getEnumerationType($attributes, $attr->{simpleType}->{enumeration}->{id}),$pathType); $binaryData .= pack1byte($pathType); $binaryData .= pack1byte($pathInstance); last; } } } if($maxPathElements > (scalar @paths)) { $binaryData .= pack("C".(($maxPathElements - scalar @paths)*2)); } return $binaryData; } ################################################################################ # Pack a single, simple attribute into a binary data stream ################################################################################ sub packSingleSimpleTypeAttribute { my($binaryDataRef,$attributesRef,$attributeRef,$typeName,$value) = @_; my $simpleType = $$attributeRef->{simpleType}; my $simpleTypeProperties = simpleTypeProperties(); if($typeName eq "enumeration") { my $enumeration = getEnumerationType($$attributesRef,$simpleType-> {enumeration}->{id}); #print STDOUT "id=$simpleType->{enumeration}->{id}\n"; #print STDOUT "value=$value\n"; #my %dummy1 = %{$enumeration}; #foreach (sort keys %dummy1) { # print STDOUT "---$_ : $dummy1{$_}\n"; #} # Here $value is the enumerator name my $enumeratorValue = enumNameToValue($enumeration,$value); $$binaryDataRef .= packEnumeration($enumeration,$enumeratorValue); } else { if($simpleTypeProperties->{$typeName}{canBeHex}) { $value = unhexify($value); } # Apply special policy enforcement, if any $simpleTypeProperties->{$typeName}{specialPolicies}->($$attributeRef, $value); my $valueIsNegative = 'false'; if (ref($value) eq "HASH") { # value is a hash ref, XML::Simple represents an empty element with # an empty hash. Map to zero. # TODO RTC 103737. Remove this check. Empty elements should cause # a compile failure. This RTC will resolve a Brazos MFG Targeting # image problem where chip IDs from the MRW are empty elements. $value = 0; } elsif ($value eq 'true') { $value = 1; } elsif ($value eq 'false') { $value = 0; } elsif ($value =~ m/[^0-9]/) { # This section is looking for integer values that are incorrectly # being interpreted as strings because of their negative sign (-). # We ensure that the first thing in the String is a negative sign # and that the rest of the String only contains numbers. my $negSign = substr($value,0,1); my $posVal = substr($value,1); if(($negSign eq '-') && ($posVal =~ m/[0-9]/)) { $valueIsNegative = 'true'; } } if( ($simpleTypeProperties->{$typeName}{complexTypeSupport}) && ($value =~ m/[^0-9]/) && ($valueIsNegative eq 'false')) { # This is a type that supports complex types - i.e. an integer and # the value is a string. Look for an enumeration named after the # attribute id, if one is not found then one of the function calls # below will exit with error my $enumeration = getEnumerationType($$attributesRef, $$attributeRef->{id}); $value = enumNameToValue($enumeration, $value); } if(ref ($simpleTypeProperties->{$typeName}{packfmt}) eq "CODE") { $$binaryDataRef .= $simpleTypeProperties->{$typeName}{packfmt}-> ($value,$$attributeRef); } else { $$binaryDataRef .= pack($simpleTypeProperties->{$typeName}{packfmt}, $value); } } } ################################################################################ # Pack generic attribute into a binary data stream ################################################################################ sub packAttribute { my($attributes,$attribute,$value) = @_; $value = stripLeadingAndTrailingWhitespace($value); my $binaryData; my $alignment = 1; if(exists $attribute->{simpleType}) { my $simpleType = $attribute->{simpleType}; my $simpleTypeProperties = simpleTypeProperties(); for my $typeName (sort(keys %{$simpleType})) { if(exists $simpleTypeProperties->{$typeName}) { $alignment = $simpleTypeProperties->{$typeName}{alignment}; if (($simpleTypeProperties->{$typeName}{supportsArray}) && (exists $simpleType->{array})) { # This is an array attribute, handle the value parameter as # an array, if there are not enough values for the whole # array then use the last value to fill in the remainder # Figure out the array size (possibly multidimensional) my $arraySize = 1; my @bounds = split(/,/,$simpleType->{array}); foreach my $bound (@bounds) { $arraySize *= $bound; } # Split the values into an array my @values = split(/,/,$value); my $valueArraySize = scalar(@values); # Iterate over the entire array creating values my $val = ""; for (my $i = 0; $i < $arraySize; $i++) { if ($i < $valueArraySize) { # Get the value from the value array and strip any # remaining leading/trailing whitespace that # surrounded the value after the original split $val = stripLeadingAndTrailingWhitespace($values[$i]); } # else use the last value packSingleSimpleTypeAttribute(\$binaryData, \$attributes, \$attribute, $typeName, $val); } } else { # Not an array attribute packSingleSimpleTypeAttribute(\$binaryData, \$attributes, \$attribute,$typeName, $value); } last; } } if( (length $binaryData) < 1) { fatal("Error requested simple type not supported. Keys are (" . join(',',sort(keys %{$simpleType})) . ")"); } } elsif(exists $attribute->{complexType}) { if(ref ($value) eq "HASH" ) { $binaryData = packComplexType($attributes,$attribute->{complexType}, $value); } else { fatal("Warning cannot serialize non-hash complex type."); } } elsif(exists $attribute->{nativeType}) { if($attribute->{nativeType}->{name} eq "EntityPath") { $binaryData = packEntityPath($attributes,$value); } else { fatal("Error nativeType not supported on attribute ID = " . "$attribute->{id}."); } } else { fatal("Unsupported attribute type on attribute ID = $attribute->{id}."); } if( (length $binaryData) < 1) { fatal("Serialization failed for attribute ID = $attribute->{id}."); } return ($binaryData,$alignment); } ################################################################################ # Get the PNOR base address from host boot code ################################################################################ sub getPnorBaseAddress { my($vmmConstsFile) = @_; my $pnorBaseAddress = 0; open(VMM_CONSTS_FILE,"<$vmmConstsFile") or fatal ("VMM Constants file: \"$vmmConstsFile\" could not be opened."); foreach my $line () { chomp($line); if( $line =~ /VMM_VADDR_ATTR_RP/) { $line =~ s/[^0-9\*]//g; $pnorBaseAddress = eval $line; last; } } close(VMM_CONSTS_FILE); if($pnorBaseAddress == 0) { fatal("PNOR base address was zero!"); } return $pnorBaseAddress; } ################################################################################ # Given a number, return a decimal/hexidecimal pair (for debug) ################################################################################ sub toDecAndHex { my ($val) = @_; return "$val/" . sprintf("0x%016X",$val); } ################################################################################ # Trace association code entry (for debug) ################################################################################ sub ASSOC_ENTER { if($ENV{"ASSOC_FUNC"} eq "1") { my ($trace) = @_; my ($package, $filename, $line, $undef, $hasargs, $wantarray, $evaltext, $is_require, $hints, $bitmask, $hinthash) = caller (0); my (undef,undef,undef,$subroutine) = caller (1); print STDERR "ENTER>> Function $subroutine, Line: $line\n"; print STDERR " " . $trace . "\n"; } } ################################################################################ # Trace association code exit (for debug) ################################################################################ sub ASSOC_EXIT { if($ENV{"ASSOC_FUNC"} eq "1") { my ($trace) = @_; my ($package, $filename, $line, $undef, $hasargs, $wantarray, $evaltext, $is_require, $hints, $bitmask, $hinthash) = caller (0); my (undef,undef,undef,$subroutine) = caller (1); print STDERR "EXIT>> Function $subroutine, Line: $line\n"; print STDERR " " . $trace . "\n"; } } ################################################################################ # Trace association code debug statements ################################################################################ sub ASSOC_DBG { if($ENV{"ASSOC_DBG"} eq "1") { my ($trace) = @_; my ($package, $filename, $line, $subroutine, $hasargs, $wantarray, $evaltext, $is_require, $hints, $bitmask, $hinthash) = caller (0); print STDERR "DEBUG($line): " . $trace . "\n"; } } ################################################################################ # Trace association code important statements ################################################################################ sub ASSOC_IMP { if($ENV{"ASSOC_IMP"} eq "1") { my ($trace) = @_; my ($package, $filename, $line, $subroutine, $hasargs, $wantarray, $evaltext, $is_require, $hints, $bitmask, $hinthash) = caller (0); print STDERR "IMP($line): " . $trace . "\n"; } } ################################################################################ # Update dummy pointers with real pointers in binary blob of target structs ################################################################################ sub updateTargetAssociationPointers { my ( $targetAddrHashRef, $targetsBinDataRef ) = @_; ASSOC_ENTER(); foreach my $id ( keys %$targetAddrHashRef ) { ASSOC_DBG("Fixing up target with ID = $id"); foreach my $associationType (@associationTypes) { # Seek to pointer location within target object and replace the # dummy value with the real value my $seek = $targetAddrHashRef->{$id}{ "offsetToPtrTo" . $associationType . "Associations"}; my $pointer = $targetAddrHashRef->{$id}{ $associationType . "Ptr" }; ASSOC_DBG("Seeking to offset: $seek"); # Keeping the actual pointer as it is, making a copy of it and # using it for inversion if little endian my $myPointer = pack64bitsDecimal($pointer); ASSOC_IMP("Writing pointer value of: " . toDecAndHex($pointer) ); ASSOC_IMP("Writing myPointer value of: " . toDecAndHex($myPointer)); for(my $pointerByte=0; $pointerByte<8; ++$pointerByte) { my $val = sprintf("%02x",(($myPointer >> ((BYTE_RIGHT_BIT_INDEX-$pointerByte)*BITS_PER_BYTE)) & LOW_BYTE_MASK)); ASSOC_IMP("Writing byte value : $val"); vec($$targetsBinDataRef, $seek+$pointerByte,BITS_PER_BYTE) = hex($val); } } } ASSOC_EXIT(); } ################################################################################ # Serialize association data into a binary blob ################################################################################ sub serializeAssociations { my ($offsetWithinBinary, $targetsAoHRef, $targetAddrHashRef, $associationsBinDataRef ) = @_; ASSOC_ENTER(); foreach my $targetInstance (@$targetsAoHRef) { my $id = $targetInstance->{id}; ASSOC_DBG("Serializing target = $id"); foreach my $associationType (@associationTypes) { $targetAddrHashRef->{$id}{ $associationType . "Ptr" } = $offsetWithinBinary; ASSOC_DBG("Offset within binary = $offsetWithinBinary"); my $pointers = "Association = $associationType, pointers = "; foreach my $pointer ( @ { $targetAddrHashRef->{$id} { $associationType . "Associations"}}) { $$associationsBinDataRef .= pack8byte($pointer); $offsetWithinBinary += BYTES_PER_ABSTRACT_POINTER; $pointers .= toDecAndHex($pointer); $pointers .= ", "; } chomp($pointers); chomp($pointers); ASSOC_DBG($pointers); } } my $associationsBinDataSize = length $$associationsBinDataRef; ASSOC_IMP("Size of association section = $associationsBinDataSize"); ASSOC_EXIT(); } ################################################################################ # Write the PNOR targeting image ################################################################################ sub generateTargetingImage { my($vmmConstsFile, $attributes,$Target_t,$addRO_Section_VerPage, $allAttributes) = @_; # 128 MB virtual memory offset between sections my $vmmSectionOffset = 128 * 1024 * 1024; # 128MB # Virtual memory addresses corresponding to the start of the targeting image # PNOR/heap sections my $pnorRoBaseAddress = getPnorBaseAddress($vmmConstsFile); my $heapPnorInitBaseAddr = $pnorRoBaseAddress + $vmmSectionOffset; my $heapZeroInitBaseAddr = $heapPnorInitBaseAddr + $vmmSectionOffset; my $hbHeapZeroInitBaseAddr = $heapZeroInitBaseAddr + $vmmSectionOffset; my $pnorRwBaseAddress = $hbHeapZeroInitBaseAddr + $vmmSectionOffset; # Split "fsp" into additional sections my $fspP0DefaultedFromZeroBaseAddr = $pnorRwBaseAddress + $vmmSectionOffset; my $fspP0DefaultedFromP3BaseAddr = $fspP0DefaultedFromZeroBaseAddr + $vmmSectionOffset; my $fspP3RoBaseAddr = $fspP0DefaultedFromP3BaseAddr + $vmmSectionOffset; my $fspP3RwBaseAddr = $fspP3RoBaseAddr + $vmmSectionOffset; my $fspP1DefaultedFromZeroBaseAddr = $fspP3RwBaseAddr + $vmmSectionOffset; my $fspP1DefaultedFromP3BaseAddr = $fspP1DefaultedFromZeroBaseAddr + $vmmSectionOffset; # Reserve 256 bytes for the header, then keep track of PNOR RO offset my $headerSize = 256; my $offset = $headerSize; #If the file to be created is the HB targeting binary , then it will contain #first page (4096 bytes) as the read-only data checksum. Need to adjust the #read-only section offset. my $versionSectionSize = 4096; # Reserve space for the pointer to the # of targets, update later; my $numTargetsPointer = 0; my $numTargetsPointerBinData = pack8byte($numTargetsPointer); $offset += (length $numTargetsPointerBinData); ############################################################################ # Build the attribute list for each unique CTM ############################################################################ # Get an array of only the unique types of targets actually used by the # aggregation of target instances. my @targetTypes = getInstantiatedTargetTypes($attributes); my $attributeIdEnumeration = getAttributeIdEnumeration($attributes); my %attributeListTypeHoH = (); my $attributeListBinData; # For each unique type of target modeled, create the attribute list foreach my $targetType (@targetTypes) { # Create the attribute list associated with each target type #@TODO Eventually we'll need criteria to order the attributes # for code update my %attrhash = (); getTargetAttributes($targetType, $attributes,\%attrhash); # Serialize per target type attribute list # Sort the list by attribute ID (hash value) so that we can do a # binary search at runtime. my $perTargetTypeAttrBinData; for my $attributeId (sort { getAttributeIdHashStr($a) cmp getAttributeIdHashStr($b) } (keys %attrhash) ) { $perTargetTypeAttrBinData .= packEnumeration( $attributeIdEnumeration, enumNameToValue($attributeIdEnumeration,$attributeId)); } # Save offset of the attribute list, tied to the type $attributeListTypeHoH{$targetType}{offset} = $offset; $attributeListTypeHoH{$targetType}{elements} = scalar keys %attrhash; $attributeListTypeHoH{$targetType}{size} = (length $perTargetTypeAttrBinData); #print "Target type: $targetType\n"; #print " elements: $attributeListTypeHoH{$targetType}{elements}\n"; #print " offset: $attributeListTypeHoH{$targetType}{offset}\n"; #print " size: $attributeListTypeHoH{$targetType}{size}\n"; # Append attribute data for this part to the attribute list subsection $attributeListBinData .= $perTargetTypeAttrBinData; # Increment the offset $offset += (length $perTargetTypeAttrBinData); } # For each target instance ... #@TODO Eventually we'll need criteria to order the attributes # for code update. At minimum, ensure that we always process at this level # in the given order my @targetsAoH = (); my $targetCount = 0; my $moveSysTarget = 0; my $targetSystemInstance = 0; my $targetNodeInstance = 0; my $targetSysCnt = 0; my $targetNodeCnt = 0; # To support the iterator code, we dont want sys target to be the # first in order. So we have specifically moved system target to second, # and the first place has been reserved by a node target for all binaries. foreach my $targetInstance (@{$attributes->{targetInstance}}) { if(($targetInstance->{type} =~ m/^sys-sys-/) && ($targetSysCnt == 0)) { $targetSysCnt = 1; $targetSystemInstance = $targetInstance; next; } elsif(($targetInstance->{type} eq "enc-node-power8") && ($targetNodeCnt == 0)) { $targetNodeCnt = 1; $targetNodeInstance = $targetInstance; next; } elsif(($targetInstance->{type} eq "enc-node-power9") && ($targetNodeCnt == 0)) { $targetNodeCnt = 1; $targetNodeInstance = $targetInstance; next; } push(@targetsAoH, $targetInstance); } unshift(@targetsAoH, $targetSystemInstance); unshift(@targetsAoH, $targetNodeInstance); my $numTargets = @targetsAoH; my $numAttributes = 0; foreach my $targetInstance (@targetsAoH) { my %attrhash = (); getTargetAttributes($targetInstance->{type}, $attributes,\%attrhash); $numAttributes += keys %attrhash; } # Reserve # pointers * sizeof(pointer) my $startOfAttributePointers = $offset; # print "Total attributes = $numAttributes\n"; $offset += ($numAttributes * (length pack8byte(0) )); # Now we can determine the pointer to the number of targets # Don't increment the offset; already accounted for $numTargetsPointer = $pnorRoBaseAddress + $offset; $numTargetsPointerBinData = pack8byte($numTargetsPointer); my $numTargetsBinData = pack4byte($numTargets); $offset += (length $numTargetsBinData); my $firstTgtPtr = $pnorRoBaseAddress + $offset; my $roAttrBinData; my $heapZeroInitOffset = 0; my $heapZeroInitBinData; my $heapPnorInitOffset = 0; my $heapPnorInitBinData; my $rwAttrBinData; my $rwOffset = 0; # Split into more granular sections my $fspP0DefaultedFromZeroOffset = 0; my $fspP0DefaultedFromZeroBinData; my $fspP0DefaultedFromP3Offset = 0; my $fspP0DefaultedFromP3BinData; my $fspP1DefaultedFromZeroOffset = 0; my $fspP1DefaultedFromZeroBinData; my $fspP1DefaultedFromP3Offset = 0; my $fspP1DefaultedFromP3BinData; my $fspP3RoOffset = 0; my $fspP3RoBinData; my $fspP3RwOffset = 0; my $fspP3RwBinData; # Hostboot specific section my $hbHeapZeroInitOffset = 0; my $hbHeapZeroInitBinData; my $attributePointerBinData; my $targetsBinData; # Ensure consistent ordering of target instances my $attrAddr = $pnorRoBaseAddress + $startOfAttributePointers; # Configure globals for computing associations my %targetAddrHash = (); my $offsetWithinTargets = 0; my @NullPtrArray = ( 0 ) ; foreach my $targetInstance (@targetsAoH) { my $data; # print "TargetInstance: $targetInstance->{id}\n"; # print " Attributes: ", # $attributeListTypeHoH{$targetInstance->{type}}{elements}, "\n" ; # print " offset: ", # $attributeListTypeHoH{$targetInstance->{type}}{offset}, "\n" ; # Keep track of where this target is from start of targets $targetAddrHash{$targetInstance->{id}}{OffsetToTargetWithinTargetList} = $offsetWithinTargets; # Create target record $data .= pack4byte( $attributeListTypeHoH{$targetInstance->{type}}{elements}); $data .= pack8byte( $attributeListTypeHoH{$targetInstance->{type}}{offset} + $pnorRoBaseAddress); $data .= pack8byte($attrAddr); # Make note of the offsets within the blob of targets where each pointer # for each association list is. Also reserve each pointer with an # invalid value for now. use constant INVALID_POINTER => 0; my $ptrToParentByContainmentAssociations = INVALID_POINTER; my $ptrToChildByContainmentAssociations = INVALID_POINTER; my $ptrToParentByAffinityAssociations = INVALID_POINTER; my $ptrToChildByAffinityAssociations = INVALID_POINTER; my $ptrToPervasiveChildAssociations = INVALID_POINTER; my $ptrToParentPervasiveAssociations = INVALID_POINTER; my $id = $targetInstance->{id}; $targetAddrHash{$id}{offsetToPtrToParentByContainmentAssociations} = $offsetWithinTargets + length $data; $data .= pack8byte($ptrToParentByContainmentAssociations); $targetAddrHash{$id}{offsetToPtrToChildByContainmentAssociations} = $offsetWithinTargets + length $data; $data .= pack8byte($ptrToChildByContainmentAssociations); $targetAddrHash{$id}{offsetToPtrToParentByAffinityAssociations} = $offsetWithinTargets + length $data; $data .= pack8byte($ptrToParentByAffinityAssociations); $targetAddrHash{$id}{offsetToPtrToChildByAffinityAssociations} = $offsetWithinTargets + length $data; $data .= pack8byte($ptrToChildByAffinityAssociations); $targetAddrHash{$id}{offsetToPtrToPervasiveChildAssociations} = $offsetWithinTargets + length $data; $data .= pack8byte($ptrToPervasiveChildAssociations); $targetAddrHash{$id}{offsetToPtrToParentPervasiveAssociations} = $offsetWithinTargets + length $data; $data .= pack8byte($ptrToParentPervasiveAssociations); $targetAddrHash{$id}{ParentByContainmentAssociations} = [@NullPtrArray]; $targetAddrHash{$id}{ChildByContainmentAssociations} = [@NullPtrArray]; $targetAddrHash{$id}{ParentByAffinityAssociations} = [@NullPtrArray]; $targetAddrHash{$id}{ChildByAffinityAssociations} = [@NullPtrArray]; $targetAddrHash{$id}{PervasiveChildAssociations} = [@NullPtrArray]; $targetAddrHash{$id}{ParentPervasiveAssociations} = [@NullPtrArray]; if($id =~/^sys\d+$/) { ASSOC_DBG("Found system target of $id, reserving space"); for(my $reserved = 0; $reserved < MAX_COMPUTE_AND_CONTROL_NODE_SUM - 1; ++$reserved) { unshift @ { $targetAddrHash{$id}{ChildByContainmentAssociations} }, 0; unshift @ { $targetAddrHash{$id}{ChildByAffinityAssociations} }, 0; } } ASSOC_DBG("Target ID = $id"); ASSOC_DBG("Offset within targets to ptr to parent containment list = " . "$targetAddrHash{$id}{offsetToPtrToParentByContainmentAssociations}"); ASSOC_DBG("Offset within targets to ptr to child containment list = " . "$targetAddrHash{$id}{offsetToPtrToChildByContainmentAssociations}"); ASSOC_DBG("Offset within targets to ptr to parent affinit list = " . "$targetAddrHash{$id}{offsetToPtrToParentByAffinityAssociations}"); ASSOC_DBG("Offset within targets to ptr to child affinity list = " . "$targetAddrHash{$id}{offsetToPtrToChildByAffinityAssociations}"); ASSOC_DBG("Offset within targets to ptr to pervasive child list = " . "$targetAddrHash{$id}{offsetToPtrToPervasiveChildAssociations}"); ASSOC_DBG("Offset within targets to ptr to parent pervasive list = " . "$targetAddrHash{$id}{offsetToPtrToParentPervasiveAssociations}"); $attrAddr += $attributeListTypeHoH{$targetInstance->{type}}{elements} * (length pack8byte(0)); # Increment the offset $offset += (length $data); $offsetWithinTargets += (length $data); # Add it to the target sub-section $targetsBinData .= $data; } my $pnorRoOffset = $offset; my $attributesWritten = 0; my %biosData = (); # Cache the attribute definitions for all attributes, including virtual my %attributeDefCache = map { $_->{id} => $_} @{$allAttributes->{attribute}}; # Cache separate attribute definitions for all non-virtual attributes my %attributeDefCacheNoVirtual = map { $_->{id} => $_} @{$attributes->{attribute}}; # For the main loop, use all attributes including virtual my $attributeIdEnumerationAll = getAttributeIdEnumeration($allAttributes); foreach my $targetInstance (@targetsAoH) { my $data; my %attrhash = (); my @AoH = (); # Ensure consistent ordering of attributes for each target type # Get the attribute list associated with each target type #@TODO Attributes must eventually be ordered correctly for code update # Use all attributes including virtual for association processing getTargetAttributes($targetInstance->{type}, $allAttributes,\%attrhash); # Update hash with any per-instance overrides, but only if that # attribute has already been defined foreach my $attr (@{$targetInstance->{attribute}}) { if(exists $attrhash{$attr->{id}}) { $attrhash{ $attr->{id} } = $attr; } else { fatal("Target instance \"$targetInstance->{id}\" cannot " . "override attribute \"$attr->{id}\" unless " . "the attribute has already been defined in the target " . "type inheritance chain."); } } my $huidValue = $attrhash{HUID}->{default}; # Flag if target is FSP specific; in that case store all of its # attributes in the FSP section, regardless of whether they are # themselves FSP specific. Only need to do this 1x per target instance my $fspTarget = isFspTargetInstance($attributes,$targetInstance); # Must have the same order as the attribute list from above. for my $attributeId (sort { getAttributeIdHashStr($a) cmp getAttributeIdHashStr($b) } (keys %attrhash) ) { # Save each target's physical + affinity + parent pervasive # path for association processing later on if( ($attributeId eq ATTR_PHYS_PATH) || ($attributeId eq ATTR_AFFINITY_PATH) || ($attributeId eq ATTR_PARENT_PERVASIVE)) { $targetAddrHash{$targetInstance->{id}}{$attributeId} = $attrhash{$attributeId}->{default}; } # Cache these attributes away in the BIOS data structure as # identifying information that will be used to enforce the target # restrictions if( ($attributeId eq ATTR_PHYS_PATH) || ($attributeId eq ATTR_POSITION ) || ($attributeId eq ATTR_CHIP_UNIT) || ($attributeId eq ATTR_CLASS ) || ($attributeId eq ATTR_TYPE ) || ($attributeId eq ATTR_MODEL ) ) { $biosData{$targetInstance->{id}}{_identity_}{$attributeId} = $attrhash{$attributeId}->{default}; } my $attrValue = enumNameToValue($attributeIdEnumerationAll,$attributeId); $attrValue = sprintf ("%0x", $attrValue); my $attributeDef = $attributeDefCache{$attributeId}; if (not defined $attributeDef) { fatal("Attribute $attributeId is not found."); } # Do not lay down virtual attributes into the binary if(exists $attributeDef->{virtual}) { next } my $ifFspOnlyTargetWithCommonAttr = "false"; # Need to separate out the Fsp only target's common attributes if( ($fspTarget) && (!exists $attributeDef->{fspOnly}) && (!exists $attributeDef->{hbOnly})) { if( $attributeDef->{persistency} eq "volatile-zeroed" ) { $ifFspOnlyTargetWithCommonAttr = "true"; } elsif( $attributeDef->{persistency} eq "volatile" ) { $ifFspOnlyTargetWithCommonAttr = "true"; } } my $section; # Split "fsp" into more sections later if( (exists $attributeDef->{fspOnly}) || ($fspTarget)) { if( $attributeDef->{persistency} eq "volatile-zeroed" ) { $section = "fspP0DefaultedFromZero"; } elsif( $attributeDef->{persistency} eq "volatile" ) { $section = "fspP0DefaultedFromP3"; } elsif( !exists $attributeDef->{writeable} && $attributeDef->{persistency} eq "non-volatile" ) { $section = "fspP3Ro"; } elsif( exists $attributeDef->{writeable} && $attributeDef->{persistency} eq "non-volatile" ) { $section = "fspP3Rw"; } elsif( $attributeDef->{persistency} eq "semi-non-volatile-zeroed" ) { $section = "fspP1DefaultedFromZero"; } elsif( $attributeDef->{persistency} eq "semi-non-volatile" ) { $section = "fspP1DefaultedFromP3"; } else { fatal("Persistency '$attributeDef->{persistency}' is not " . "supported for fspOnly attribute '$attributeId'."); } } elsif( exists $attributeDef->{hbOnly} ) { if( $attributeDef->{persistency} eq "volatile-zeroed" ) { $section = "hb-heap-zero-initialized"; } else { fatal("Persistency '$attributeDef->{persistency}' is not " . "supported for hbOnly attribute '$attributeId'."); } } elsif( exists $attributeDef->{writeable} && $attributeDef->{persistency} eq "non-volatile" ) { $section = "pnor-rw"; } elsif ( !exists $attributeDef->{writeable} && $attributeDef->{persistency} eq "non-volatile") { $section = "pnor-ro"; } elsif ($attributeDef->{persistency} eq "volatile" ) { $section = "heap-pnor-initialized"; } elsif($attributeDef->{persistency} eq "volatile-zeroed") { $section = "heap-zero-initialized"; } else { fatal("Persistency '$attributeDef->{persistency}' is not " . "supported for attribute '$attributeId'."); } if($section eq "pnor-ro") { if ((exists ${$Target_t}{$attributeId}) && ($attrhash{$attributeId}->{default} != 0)) { my $index = $attrhash{$attributeId}->{default} - 1; # Each target is 4 bytes # attributes, 8 bytes pointer # to attribute list, 8 bytes pointer to attribute pointer # list, 6 x 8 byte pointers to association lists, for total # of 20 + 48 = 68 bytes per target $index *= (20 + 48); # length(N + quad + quad + 6x quad) $attrhash{$attributeId}->{default} = $index + $firstTgtPtr; } 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 .= pack8byte( $offset + $pnorRoBaseAddress); $offset += (length $rodata); $roAttrBinData .= $rodata; } elsif($section eq "pnor-rw") { my ($rwdata,$alignment) = packAttribute($attributes, $attributeDef, $attrhash{$attributeId}->{default}); #print "Wrote to pnor-rw value ",$attributeDef->{id}, ", #", $attrhash{$attributeId}->{default}," \n"; my $hex = unpack ("H*",$rwdata); push @attrDataforSM, [$attrValue, $huidValue, $hex, $section, $targetInstance->{id}, $attributeId]; # Align the data as necessary my $pads = ($alignment - ($rwOffset % $alignment)) % $alignment; $rwAttrBinData .= pack ("@".$pads); $rwOffset += $pads; $attributePointerBinData .= pack8byte( $rwOffset + $pnorRwBaseAddress); $rwOffset += (length $rwdata); $rwAttrBinData .= $rwdata; } elsif($section eq "heap-zero-initialized") { my ($heapZeroInitData,$alignment) = packAttribute( $attributes, $attributeDef,$attrhash{$attributeId}->{default}); $biosData{$targetInstance->{id}}{$attributeId}{size} = (length $heapZeroInitData); $biosData{$targetInstance->{id}}{$attributeId}{default} = $attrhash{$attributeId}->{default}; my $hex = unpack ("H*",$heapZeroInitData); push @attrDataforSM, [$attrValue, $huidValue, $hex, $section, $targetInstance->{id}, $attributeId]; # Align the data as necessary my $pads = ($alignment - ($heapZeroInitOffset % $alignment)) % $alignment; $heapZeroInitBinData .= pack ("@".$pads); $heapZeroInitOffset += $pads; $attributePointerBinData .= pack8byte( $heapZeroInitOffset + $heapZeroInitBaseAddr); $heapZeroInitOffset += (length $heapZeroInitData); $heapZeroInitBinData .= $heapZeroInitData; } elsif($section eq "heap-pnor-initialized") { my ($heapPnorInitData,$alignment) = packAttribute( $attributes, $attributeDef,$attrhash{$attributeId}->{default}); $biosData{$targetInstance->{id}}{$attributeId}{size} = (length $heapPnorInitData); $biosData{$targetInstance->{id}}{$attributeId}{default} = $attrhash{$attributeId}->{default}; my $hex = unpack ("H*",$heapPnorInitData); push @attrDataforSM, [$attrValue, $huidValue, $hex, $section, $targetInstance->{id}, $attributeId]; # Align the data as necessary my $pads = ($alignment - ($heapPnorInitOffset % $alignment)) % $alignment; $heapPnorInitBinData .= pack ("@".$pads); $heapPnorInitOffset += $pads; $attributePointerBinData .= pack8byte( $heapPnorInitOffset + $heapPnorInitBaseAddr); $heapPnorInitOffset += (length $heapPnorInitData); $heapPnorInitBinData .= $heapPnorInitData; } # Split FSP section into more granular sections elsif($section eq "fspP0DefaultedFromZero") { my ($fspP0ZeroData,$alignment) = packAttribute( $attributes, $attributeDef,$attrhash{$attributeId}->{default}); if($ifFspOnlyTargetWithCommonAttr eq "true") { my $hex = unpack ("H*",$fspP0ZeroData); push @attrDataforSM, [$attrValue, $huidValue, $hex, $section, $targetInstance->{id}, $attributeId]; $ifFspOnlyTargetWithCommonAttr = "false"; } # Align the data as necessary my $pads = ($alignment - ($fspP0DefaultedFromZeroOffset % $alignment)) % $alignment; $fspP0DefaultedFromZeroBinData .= pack ("@".$pads); $fspP0DefaultedFromZeroOffset += $pads; $attributePointerBinData .= pack8byte( $fspP0DefaultedFromZeroOffset + $fspP0DefaultedFromZeroBaseAddr); $fspP0DefaultedFromZeroOffset += (length $fspP0ZeroData); $fspP0DefaultedFromZeroBinData .= $fspP0ZeroData; } elsif($section eq "fspP0DefaultedFromP3") { my ($fspP0FlashData,$alignment) = packAttribute( $attributes, $attributeDef,$attrhash{$attributeId}->{default}); if($ifFspOnlyTargetWithCommonAttr eq "true") { my $hex = unpack ("H*",$fspP0FlashData); push @attrDataforSM, [$attrValue, $huidValue, $hex, $section, $targetInstance->{id}, $attributeId]; $ifFspOnlyTargetWithCommonAttr = "false"; } # Align the data as necessary my $pads = ($alignment - ($fspP0DefaultedFromP3Offset % $alignment)) % $alignment; $fspP0DefaultedFromP3BinData .= pack ("@".$pads); $fspP0DefaultedFromP3Offset += $pads; $attributePointerBinData .= pack8byte( $fspP0DefaultedFromP3Offset + $fspP0DefaultedFromP3BaseAddr); $fspP0DefaultedFromP3Offset += (length $fspP0FlashData); $fspP0DefaultedFromP3BinData .= $fspP0FlashData; } elsif($section eq "fspP3Ro") { my ($fspP3RoData,$alignment) = packAttribute( $attributes, $attributeDef,$attrhash{$attributeId}->{default}); # Align the data as necessary my $pads = ($alignment - ($fspP3RoOffset % $alignment)) % $alignment; $fspP3RoBinData .= pack ("@".$pads); $fspP3RoOffset += $pads; $attributePointerBinData .= pack8byte( $fspP3RoOffset + $fspP3RoBaseAddr); $fspP3RoOffset += (length $fspP3RoData); $fspP3RoBinData .= $fspP3RoData; } elsif($section eq "fspP3Rw") { my ($fspP3RwData,$alignment) = packAttribute( $attributes, $attributeDef,$attrhash{$attributeId}->{default}); my $hex = unpack ("H*",$fspP3RwData); push @attrDataforSM, [$attrValue, $huidValue, $hex, $section, $targetInstance->{id}, $attributeId]; # Align the data as necessary my $pads = ($alignment - ($fspP3RwOffset % $alignment)) % $alignment; $fspP3RwBinData .= pack ("@".$pads); $fspP3RwOffset += $pads; $attributePointerBinData .= pack8byte( $fspP3RwOffset + $fspP3RwBaseAddr); $fspP3RwOffset += (length $fspP3RwData); $fspP3RwBinData .= $fspP3RwData; } elsif($section eq "fspP1DefaultedFromZero") { my ($fspP1ZeroData,$alignment) = packAttribute( $attributes, $attributeDef,$attrhash{$attributeId}->{default}); my $hex = unpack ("H*",$fspP1ZeroData); push @attrDataforSM, [$attrValue, $huidValue, $hex, $section, $targetInstance->{id}, $attributeId]; # Align the data as necessary my $pads = ($alignment - ($fspP1DefaultedFromZeroOffset % $alignment)) % $alignment; $fspP1DefaultedFromZeroBinData .= pack ("@".$pads); $fspP1DefaultedFromZeroOffset += $pads; $attributePointerBinData .= pack8byte( $fspP1DefaultedFromZeroOffset + $fspP1DefaultedFromZeroBaseAddr); $fspP1DefaultedFromZeroOffset += (length $fspP1ZeroData); $fspP1DefaultedFromZeroBinData .= $fspP1ZeroData; } elsif($section eq "fspP1DefaultedFromP3") { my ($fspP1FlashData,$alignment) = packAttribute( $attributes, $attributeDef,$attrhash{$attributeId}->{default}); my $hex = unpack ("H*",$fspP1FlashData); push @attrDataforSM, [$attrValue, $huidValue, $hex, $section, $targetInstance->{id}, $attributeId]; # Align the data as necessary my $pads = ($alignment - ($fspP1DefaultedFromP3Offset % $alignment)) % $alignment; $fspP1DefaultedFromP3BinData .= pack ("@".$pads); $fspP1DefaultedFromP3Offset += $pads; $attributePointerBinData .= pack8byte( $fspP1DefaultedFromP3Offset + $fspP1DefaultedFromP3BaseAddr); $fspP1DefaultedFromP3Offset += (length $fspP1FlashData); $fspP1DefaultedFromP3BinData .= $fspP1FlashData; } # Hostboot specific section elsif($section eq "hb-heap-zero-initialized") { my ($hbHeapZeroInitData,$alignment) = packAttribute( $attributes, $attributeDef,$attrhash{$attributeId}->{default}); $biosData{$targetInstance->{id}}{$attributeId}{size} = (length $hbHeapZeroInitData); $biosData{$targetInstance->{id}}{$attributeId}{default} = $attrhash{$attributeId}->{default}; # Align the data as necessary my $pads = ($alignment - ($hbHeapZeroInitOffset % $alignment)) % $alignment; $hbHeapZeroInitBinData .= pack ("@".$pads); $hbHeapZeroInitOffset += $pads; $attributePointerBinData .= pack8byte( $hbHeapZeroInitOffset + $hbHeapZeroInitBaseAddr); $hbHeapZeroInitOffset += (length $hbHeapZeroInitData); $hbHeapZeroInitBinData .= $hbHeapZeroInitData; } else { fatal("Could not find a suitable section."); } $attributesWritten++; } # End attribute loop } # End target instance loop if($numAttributes != $attributesWritten) { fatal("Number of attributes expected, $numAttributes, does not match " . "what was written to PNOR, $attributesWritten."); } # Build the parent/child relationships for all targets my %targetPhysicalPath = (); my %targetAffinityPath = (); foreach my $id (keys %targetAddrHash) { my $phys_attr = ATTR_PHYS_PATH; my $affn_attr = ATTR_AFFINITY_PATH; $targetPhysicalPath{ $targetAddrHash{$id}{$phys_attr} } = $id; $targetAffinityPath{ $targetAddrHash{$id}{$affn_attr} } = $id; } foreach my $id (keys %targetAddrHash) { my $phys_attr = ATTR_PHYS_PATH; my $affn_attr = ATTR_AFFINITY_PATH; my $parent_pervasive = ATTR_PARENT_PERVASIVE; my $phys_path = $targetAddrHash{$id}{$phys_attr}; my $parent_phys_path = substr $phys_path, 0, (rindex $phys_path, "/"); my $affn_path = $targetAddrHash{$id}{$affn_attr}; my $parent_affn_path = substr $affn_path, 0, (rindex $affn_path, "/"); # If this target has an associated pervasive target, create a # bidirectional relationship between this target and the specified # pervasive target. This target will point to the pervasive target via # a "PARENT_PERVASIVE" association, and the pervasive target will # point to this target via a "PERVASIVE_CHILD" association. if (defined $targetAddrHash{$id}{$parent_pervasive}) { my $parent_pervasive_path = $targetAddrHash{$id}{$parent_pervasive}; if(defined $targetPhysicalPath{$parent_pervasive_path}) { my $parent = $targetPhysicalPath{$parent_pervasive_path}; unshift @ { $targetAddrHash{$id} {ParentPervasiveAssociations} }, $firstTgtPtr + $targetAddrHash{$parent} {OffsetToTargetWithinTargetList}; unshift @ { $targetAddrHash{$parent} {PervasiveChildAssociations} }, $firstTgtPtr + $targetAddrHash{$id} {OffsetToTargetWithinTargetList}; } } if (defined $targetPhysicalPath{$parent_phys_path}) { my $parent = $targetPhysicalPath{$parent_phys_path}; unshift @ { $targetAddrHash{$id} {ParentByContainmentAssociations} }, $firstTgtPtr + $targetAddrHash{$parent} {OffsetToTargetWithinTargetList}; unshift @ { $targetAddrHash{$parent} {ChildByContainmentAssociations} }, $firstTgtPtr + $targetAddrHash{$id} {OffsetToTargetWithinTargetList}; } if (defined $targetAffinityPath{$parent_affn_path}) { my $parent = $targetAffinityPath{$parent_affn_path}; unshift @ { $targetAddrHash{$id} {ParentByAffinityAssociations} }, $firstTgtPtr + $targetAddrHash{$parent} {OffsetToTargetWithinTargetList}; unshift @ { $targetAddrHash{$parent} {ChildByAffinityAssociations} }, $firstTgtPtr + $targetAddrHash{$id} {OffsetToTargetWithinTargetList}; } } # Serialize the association lists into a blob my $associationsBinData; my $offsetToAssociationsFromTargets = (length $targetsBinData) + (length $roAttrBinData); serializeAssociations( $firstTgtPtr + $offsetToAssociationsFromTargets, \@targetsAoH, \%targetAddrHash, \$associationsBinData); my $associationsBinDataSize = length $associationsBinData; ASSOC_IMP("Size of association section, redundant calculation " . "= $associationsBinDataSize"); # Fix up the target bin blob to point to the right association lists updateTargetAssociationPointers(\%targetAddrHash, \$targetsBinData); # Size of PNOR RO increases by size of associations $offset += $associationsBinDataSize; # Build header data my $headerBinData; my $blockSize = 4*1024; my %sectionHoH = (); my $roOffset = 0; if ($addRO_Section_VerPage == 1) { #First section to start after 4096 bytes #as RO version data occupies first page in the binary file $roOffset = $versionSectionSize; } $sectionHoH{ pnorRo }{ offset } = 0; $sectionHoH{ pnorRo }{ type } = 0; $sectionHoH{ pnorRo }{ size } = sizeBlockAligned($offset,$blockSize,1); $sectionHoH{ heapPnorInit }{ offset } = $sectionHoH{pnorRo}{offset} + $sectionHoH{pnorRo}{size}; $sectionHoH{ heapPnorInit }{ type } = 2; $sectionHoH{ heapPnorInit }{ size } = sizeBlockAligned($heapPnorInitOffset,$blockSize,1); $sectionHoH{ heapZeroInit }{ offset } = $sectionHoH{heapPnorInit}{offset} + $sectionHoH{heapPnorInit}{size}; $sectionHoH{ heapZeroInit }{ type } = 3; $sectionHoH{ heapZeroInit }{ size } = sizeBlockAligned($heapZeroInitOffset,$blockSize,1); # zeroInitSection occupies no space in the binary, so set the # Hostboot section address to that of the zeroInitSection $sectionHoH{ hbHeapZeroInit }{ offset } = $sectionHoH{heapZeroInit}{offset}; $sectionHoH{ hbHeapZeroInit }{ type } = 10; $sectionHoH{ hbHeapZeroInit }{ size } = sizeBlockAligned($hbHeapZeroInitOffset,$blockSize,1); $sectionHoH{ pnorRw }{ offset } = $sectionHoH{hbHeapZeroInit}{offset}; $sectionHoH{ pnorRw }{ type } = 1; $sectionHoH{ pnorRw }{ size } = sizeBlockAligned($rwOffset,$blockSize,1); # Split "fsp" into additional sections if($cfgIncludeFspAttributes) { # zeroInitSection occupies no space in the binary, so set the FSP # section address to that of the zeroInitSection $sectionHoH{ fspP0DefaultedFromZero }{ offset } = $sectionHoH{pnorRw}{offset} + $sectionHoH{pnorRw}{size}; $sectionHoH{ fspP0DefaultedFromZero }{ type } = 4; $sectionHoH{ fspP0DefaultedFromZero }{ size } = sizeBlockAligned($fspP0DefaultedFromZeroOffset,$blockSize,1); $sectionHoH{ fspP0DefaultedFromP3 }{ offset } = $sectionHoH{fspP0DefaultedFromZero}{offset} + $sectionHoH{fspP0DefaultedFromZero}{size}; $sectionHoH{ fspP0DefaultedFromP3 }{ type } = 5; $sectionHoH{ fspP0DefaultedFromP3 }{ size } = sizeBlockAligned($fspP0DefaultedFromP3Offset,$blockSize,1); $sectionHoH{ fspP3Ro }{ offset } = $sectionHoH{fspP0DefaultedFromP3}{offset} + $sectionHoH{fspP0DefaultedFromP3}{size}; $sectionHoH{ fspP3Ro }{ type } = 6; $sectionHoH{ fspP3Ro }{ size } = sizeBlockAligned($fspP3RoOffset,$blockSize,1); $sectionHoH{ fspP3Rw }{ offset } = $sectionHoH{fspP3Ro}{offset} + $sectionHoH{fspP3Ro}{size}; $sectionHoH{ fspP3Rw }{ type } = 7; $sectionHoH{ fspP3Rw }{ size } = sizeBlockAligned($fspP3RwOffset,$blockSize,1); $sectionHoH{ fspP1DefaultedFromZero }{ offset } = $sectionHoH{fspP3Rw}{offset} + $sectionHoH{fspP3Rw}{size}; $sectionHoH{ fspP1DefaultedFromZero }{ type } = 8; $sectionHoH{ fspP1DefaultedFromZero }{ size } = sizeBlockAligned($fspP1DefaultedFromZeroOffset,$blockSize,1); $sectionHoH{ fspP1DefaultedFromP3 }{ offset } = $sectionHoH{fspP1DefaultedFromZero}{offset} + $sectionHoH{fspP1DefaultedFromZero}{size}; $sectionHoH{ fspP1DefaultedFromP3 }{ type } = 9; $sectionHoH{ fspP1DefaultedFromP3 }{ size } = sizeBlockAligned($fspP1DefaultedFromP3Offset,$blockSize,1); } my $numSections = keys %sectionHoH; # Version 1.0 to start with my $headerMajorMinorVersion = 0x00010000; my $eyeCatcher = 0x54415247; # TARG my $sizeOfSection = 9; my $offsetToSections = 0; $headerBinData .= pack4byte($eyeCatcher); $headerBinData .= pack4byte($headerMajorMinorVersion); $headerBinData .= pack4byte($headerSize); $headerBinData .= pack4byte($vmmSectionOffset); $headerBinData .= pack8byte($pnorRoBaseAddress); $headerBinData .= pack4byte($sizeOfSection); $headerBinData .= pack4byte($numSections); $headerBinData .= pack4byte($offsetToSections); # Split "fsp" into additional sections my @sections = ("pnorRo","heapPnorInit","heapZeroInit", "hbHeapZeroInit", "pnorRw"); if($cfgIncludeFspAttributes) { push(@sections,"fspP0DefaultedFromZero"); push(@sections,"fspP0DefaultedFromP3"); push(@sections,"fspP3Ro"); push(@sections,"fspP3Rw"); push(@sections,"fspP1DefaultedFromZero"); push(@sections,"fspP1DefaultedFromP3"); } foreach my $section (@sections) { $headerBinData .= pack1byte($sectionHoH{$section}{type}); $headerBinData .= pack4byte($sectionHoH{$section}{offset}); $headerBinData .= pack4byte($sectionHoH{$section}{size}); } # Serialize PNOR RO section to multiple of 4k page size (pad if necessary) # First 256 bytes is RO header (pad if necessary) if((length $headerBinData) > $headerSize) { fatal("Header data of length " . (length $headerBinData) . " is larger " . "than allocated amount of $headerSize."); } my $outFile; #HB Targeting binary file will contain ++ #
... if ($addRO_Section_VerPage == 1) { #Generate the MD5 checksum value for the read-only data and update the #content of the version section my $md5hex = Digest::MD5->new; $md5hex->add($numTargetsPointerBinData); $md5hex->add($attributeListBinData); $md5hex->add($attributePointerBinData); $md5hex->add($numTargetsBinData); $md5hex->add($targetsBinData); $md5hex->add($roAttrBinData); $md5hex->add($associationsBinData); $md5hex->add($heapPnorInitBinData); my $versionHeader = "VERSION"; my $versionHeader .= $md5hex->hexdigest; $outFile .= $versionHeader; my $versionHeaderPadSize = (sizeBlockAligned ((length $versionHeader),$versionSectionSize,1) - (length $versionHeader)); $outFile .= pack ("@".$versionHeaderPadSize); } #Append the 256 bytes header data $outFile .= $headerBinData; my $padSize = sizeBlockAligned((length $headerBinData),$headerSize,1) - (length $headerBinData); $outFile .= pack ("@".$padSize); # Remaining data belongs to targeting $outFile .= $numTargetsPointerBinData; $outFile .= $attributeListBinData; $outFile .= $attributePointerBinData; $outFile .= $numTargetsBinData; my $offsetOfTargets = length $outFile; my $sizeOfTargets = length $targetsBinData; my $offsetToAssociationsFromTargets = (length $targetsBinData) + (length $roAttrBinData); ASSOC_DBG("Offset of targets within targeting binary = $offsetOfTargets"); ASSOC_DBG("Size of targets within targeting binary = $sizeOfTargets"); ASSOC_DBG("Offset to associations from start of targets " . "= $offsetToAssociationsFromTargets"); $outFile .= $targetsBinData; $outFile .= $roAttrBinData; $outFile .= $associationsBinData; $outFile .= pack ("@".($sectionHoH{pnorRo}{size} - $offset)); # Serialize PNOR initiated heap section to multiple of 4k page size (pad if # necessary) $outFile .= $heapPnorInitBinData; $outFile .= pack("@".($sectionHoH{heapPnorInit}{size} - $heapPnorInitOffset)); # Serialize PNOR RW section to multiple of 4k page size (pad if necessary) $outFile .= $rwAttrBinData; $outFile .= pack("@".($sectionHoH{pnorRw}{size} - $rwOffset)); # Serialize FSP section to multiple of 4k page size (pad if # necessary) if($cfgIncludeFspAttributes) { $outFile .= $fspP0DefaultedFromZeroBinData; $outFile .= pack("@".($sectionHoH{fspP0DefaultedFromZero}{size} - $fspP0DefaultedFromZeroOffset)); $outFile .= $fspP0DefaultedFromP3BinData; $outFile .= pack("@".($sectionHoH{fspP0DefaultedFromP3}{size} - $fspP0DefaultedFromP3Offset)); $outFile .= $fspP3RoBinData; $outFile .= pack("@".($sectionHoH{fspP3Ro}{size} - $fspP3RoOffset)); $outFile .= $fspP3RwBinData; $outFile .= pack("@".($sectionHoH{fspP3Rw}{size} - $fspP3RwOffset)); $outFile .= $fspP1DefaultedFromZeroBinData; $outFile .= pack("@".($sectionHoH{fspP1DefaultedFromZero}{size} - $fspP1DefaultedFromZeroOffset)); $outFile .= $fspP1DefaultedFromP3BinData; $outFile .= pack("@".($sectionHoH{fspP1DefaultedFromP3}{size} - $fspP1DefaultedFromP3Offset)); } if(defined $cfgBiosXmlFile) { unless (-e $cfgBiosXmlFile) { fatal("BIOS XML file $cfgBiosXmlFile does not exist.\n"); } unless (defined $cfgBiosSchemaFile) { fatal("BIOS XML file $cfgBiosXmlFile specified, but a BIOS schema " . "file was not.\n"); } unless (-e $cfgBiosSchemaFile) { fatal("BIOS schema file $cfgBiosSchemaFile does not exist.\n"); } unless (defined $cfgBiosOutputFile) { fatal("BIOS output file not specified.\n"); } my $bios = new Bios($cfgBiosXmlFile,$cfgBiosSchemaFile,$cfgBiosOutputFile); $bios->load(); $bios->processBios( \%attributeDefCacheNoVirtual,\$attributes, \%biosData,%targetPhysicalPath); $bios->export(); } return $outFile; } sub generateXMLforSM { open(SM_TARGET_FILE,">".$CfgSMAttrFile) or fatal ("Targeting SM file: $CfgSMAttrFile " . "could not be opened."); my $Count = @attrDataforSM; print SM_TARGET_FILE " "; for (my $i = 0; $i < $Count; $i++) { print SM_TARGET_FILE " 0x$attrDataforSM[$i][ATTRID] $attrDataforSM[$i][HUID] 0x$attrDataforSM[$i][DATA]
$attrDataforSM[$i][SECTION]
$attrDataforSM[$i][TARGET] $attrDataforSM[$i][ATTRNAME]"; print SM_TARGET_FILE "\n
\n"; } print SM_TARGET_FILE"
"; close(SM_TARGET_FILE); } ################################################################################ # BIOS Package # Consumes platform-specific BIOS XML file, validates it, and outputs # extended data on the attributes, which will be transformed (via xslt # stylesheets) and used by 3rd parties (like Petitboot). The BIOS # package validates the input file against a stylesheet to ensure # proper formatting. ################################################################################ { package Bios; ################################################################################ # Constructor; create a new Bios object ################################################################################ sub new { my ($class,$biosInputXmlFile,$biosSchemaXsdFile,$biosOutputXmlFile) = @_; my $self = { _biosInputXmlFile => $biosInputXmlFile, _libXmlParser => XML::LibXML->new(), _biosXmlDoc => undef, _biosSchemaXsdFile => $biosSchemaXsdFile, _biosOutputXmlFile => $biosOutputXmlFile, }; bless $self, $class; return $self; } ################################################################################ # Load and parse the BIOS XML data, then validate it ################################################################################ sub load { my ($self) = @_; my $biosSchemaXsd = undef; eval { $self->{_biosXmlDoc} = $self->{_libXmlParser}->parse_file($self->{_biosInputXmlFile}); }; main::fatal ("Failed to parse BIOS file [$self->{_biosInputXmlFile}].\n" . " Reason: $@") if $@; eval { $biosSchemaXsd = XML::LibXML::Schema->new(location => $self->{_biosSchemaXsdFile} ); }; main::fatal ("Failed to load valid schema [$self->{_biosSchemaXsdFile}].\n" . "Reason: $@") if $@; eval { $biosSchemaXsd->validate($self->{_biosXmlDoc}) }; main::fatal ("Failed to validate [$self->{_biosInputXmlFile}] " . "using schema [$self->{_biosSchemaXsdFile}].\n" . "Reason: $@") if $@; } ################################################################################ # Export the working version of the BIOS document to a file our STDOUT ################################################################################ sub export { my ($self,$forceStdout) = @_; if(defined $forceStdout && ($forceStdout == 1)) { print STDOUT "In-memory BIOS XML dump:\n"; print STDOUT $self->{_biosXmlDoc}->toString(); } else { open(OUTPUT_XML,">$self->{_biosOutputXmlFile}") or main::fatal("Could not open output BIOS XML file " . "[$self->{_biosOutputXmlFile}] for writing.\n" . "Reason: $!"); print OUTPUT_XML $self->{_biosXmlDoc}->toString() or main::fatal ("Failed write output BIOS XML file " . "[$self->{_biosOutputXmlFile}].\n" . "Reason: $!"); close OUTPUT_XML or main::fatal ("Failed to close output BIOS XML file " . "[$self->{_biosOutputXmlFile}].\n" . "Reason: $!"); } } ################################################################################ # Create child element in BIOS XML tree and return it ################################################################################ sub createChildElement() { my ($self,$parent,$name,$value) = @_; my $child = XML::LibXML::Element->new($name); # Value is optional parameter; if not specified, only the child container # element is created if(defined $value) { $child->appendTextNode($value); } $parent->addChild($child); return $child; } ################################################################################ # Validate any constraint not enforced by the schema and amend the XML tree ################################################################################ sub processBios { my($self,$attrMapRef,$attributesRef,$instanceRef,%targetPhysicalPath) = @_; use bigint; my %attrTargAttrSetByBios = (); # Process all attribute elements regardless of tree location foreach my $attribute ($self->{_biosXmlDoc}->findnodes('//attribute')) { my($id) = $attribute->findnodes('./id'); my $attributeId = $id->to_literal; # Attribute must be defined in targeting if(!exists $attrMapRef->{$attributeId}) { main::fatal("BIOS definition specified attribute $attributeId, but " . "that attribute is not defined in targeting.\n"); } # Attribute must have volatile persistency if($attrMapRef->{$attributeId}{persistency} ne "volatile" && $attrMapRef->{$attributeId}{persistency} ne "volatile-zeroed") { main::fatal("BIOS definition specified attribute $attributeId, but " . "that attribute is neither volatile nor volatile-zeroed " . "in targeting. Actual persistency is " . "$attrMapRef->{$attributeId}{persistency}.\n"); } # Attribute must be read only my $readable = exists $attrMapRef->{$attributeId}{readable} ? 1 : 0; my $writeable = exists $attrMapRef->{$attributeId}{writeable} ? 1 : 0; if(!$readable || $writeable) { main::fatal("BIOS definition specified attribute $attributeId, but " . "that attribute is not read-only in targeting. " . "Readable? " . $readable . " writeable? " . $writeable . "\n"); } # Attribute must not be an FSP-only attribute my $fspOnly = exists $attrMapRef->{$attributeId}{fspOnly} ? 1 : 0; if($fspOnly) { main::fatal("BIOS definition specified attribute $attributeId, but " . "that attribute is FSP only in targeting.\n"); } # Attribute must be an allowed type -and- supported by the BIOS code # Current support is for signed/unsigned ints (1,2,4,8 bytes in size) # and enumerations my $simpleType = exists $attrMapRef->{$attributeId}{simpleType} ? 1 : 0; my $complexType = exists $attrMapRef->{$attributeId}{complexType} ? 1 : 0; my $nativeType = exists $attrMapRef->{$attributeId}{nativeType} ? 1 : 0; if(!$simpleType) { main::fatal("BIOS definition specified attribute $attributeId, but " . "that attribute is not a simple type in targeting. " . "Complex type? $complexType, native type? $nativeType.\n"); } # Defines which attributes can be put in the BIOS and provides # associated BIOS type hint for 3rd party consumer my %typeHash = (); $typeHash{"int8_t"} = { generalType => 'signed', min => -128, max => 127, ror => 1, }; $typeHash{"int16_t"} = { generalType => 'signed', min => -32768, max => 32767, ror => 1, }; $typeHash{"int32_t"} = { generalType => 'signed', min => -2147483648, max => 2147483647, ror => 1, }; $typeHash{"int64_t"} = { generalType => 'signed', min => -9223372036854775808, max => 9223372036854775807, ror => 1, }; $typeHash{"uint8_t"} = { generalType => 'unsigned', min => 0, max => 255, ror => 1, }; $typeHash{"uint16_t"} = { generalType => 'unsigned', min => 0, max => 65535, ror => 1, }; $typeHash{"uint32_t"} = { generalType => 'unsigned', min => 0, max => 4294967295, ror => 1, }; $typeHash{"uint64_t"} = { generalType => 'unsigned', min => 0, max => 18446744073709551615, ror => 1, }; $typeHash{"enumeration"} = { generalType => 'unsigned', min => 'na', max => 'na', ror => 1, }; my $validType = 0; my $attrType = "unknown"; # Convert actual type into a generalized type hint for the BIOS consumer # and append to the XML tree foreach my $type (keys %typeHash) { if(exists $attrMapRef->{$attributeId}{simpleType}{$type}) { $self->createChildElement($attribute,"encoding", $typeHash{$type}{generalType}); $attrType = $type; $validType = 1; last; } } if(!$validType) { main::fatal("BIOS definition specified attribute $attributeId, but " . "that attribute's type is not supported in BIOS context. " . "Dump of type:\n" . ::Dumper($attrMapRef->{$attributeId}{simpleType}) . "\n"); } # Simple type must not be array if(exists $attrMapRef->{$attributeId}{simpleType}{array}) { main::fatal("BIOS definition specified attribute $attributeId, but " . "that attribute is an array which is not supported in " . "BIOS context.\n"); } # If attribute definition doesn't have a short name, it must be # overridden by the BIOS config. Add final value to the XML tree my($displayNameNodes) = $attribute->findnodes('./display-name'); if(!$displayNameNodes) { if(exists $attrMapRef->{$attributeId}{'display-name'}) { $self->createChildElement( $attribute,"display-name", $attrMapRef->{$attributeId}{'display-name'}); } else { main::fatal("BIOS definition specified attribute $attributeId, " . "but attribute definition does not give a display name, " . "so BIOS config must (but failed to do so).\n"); } } # If attribute definition doesn't have a description, it must be # overridden by the BIOS config. Add final value to the XML tree my($descriptionNodes) = $attribute->findnodes('./description'); if(!$descriptionNodes) { if(exists $attrMapRef->{$attributeId}{description}) { $self->createChildElement( $attribute,"description", $attrMapRef->{$attributeId}{description}); } else { main::fatal("BIOS definition specified attribute $attributeId, " . "but attribute definition does not give a description, " . "so BIOS config must (but failed to do so).\n"); } } my $default = undef; my $size = undef; my @targetRestrictions = $attribute->findnodes('./targetRestriction'); # Assume all targets have this BIOS attribute to begin with, then prove # otherwise during processing my %filteredTargets = %$instanceRef; foreach my $target (keys %filteredTargets) { $filteredTargets{$target}{_allowed_} = 1; } # Hold the target override data my %restriction = (); $restriction{node} = 0x0F; # FAPI override value = any position $restriction{position} = 0xFFFF; # FAPI override value = any position $restriction{unit} = 0xFF; # FAPI override value = any unit $restriction{symbolicType} = "*"; # Easy to understand target type $restriction{numericType} = 0x0; # FAPI type indicator; 0 = any # Scan target restriction(s). If no restriction, the BIOS attribute # must have same default for all instances. If target restriction, all # attributes that are grouped by the restriction must have the same # default value. if(scalar @targetRestrictions > 0) { my $restrictNode = "*"; my $restrictPos = "*"; # NA except for things with positions # including units my $restrictUnit = "*"; # NA except for units my $restrictType = "*"; # By default, a BIOS setting applies to every target the attribute # is assigned to in targeting. However, a target restriction can # restrict an attribute to one or more subsets of those. The set of # targets tied to same BIOS attribute+restriction cannot intersect # with any other similar grouping. Further, all attributes of # same type tied to same BIOS attribute via the restriction must # have same default value. Only one target restriction allowed by # the schema foreach my $targetRestriction (@targetRestrictions) { # Schema validation doesn't easily force targetRestrictions to # have at least one child, so bail if that's the case my @childElements = $targetRestriction->findnodes('./*'); if(scalar @childElements == 0) { main::fatal("BIOS definition specified attribute " . "$attributeId, but requested targetRestriction with " . "no parameters.\n"); } my @nodeElements = $targetRestriction->findnodes('./node'); my @positionElements = $targetRestriction->findnodes('./position'); my @unitElements = $targetRestriction->findnodes('./unit'); my @typeElements = $targetRestriction->findnodes('./type'); if(scalar @nodeElements) { $restriction{node} = $nodeElements[0]->to_literal; } if(scalar @positionElements) { $restriction{position} = $positionElements[0]->to_literal; } if(scalar @unitElements) { $restriction{unit} = $unitElements[0]->to_literal; } # If any type restriction, verify it is a valid type designator # any hold onto the numeric ID which will end up in the XML tree if(scalar @typeElements) { my $symbolicType = $typeElements[0]->to_literal; my $typeEnumDef = ::getEnumerationType($$attributesRef,"TYPE"); my $numericType = ::enumNameToValue($typeEnumDef,$symbolicType); $restriction{numericType} = $numericType; $restriction{symbolicType} = $symbolicType; } # Compute the affected targets foreach my $target (keys %filteredTargets) { if(scalar @typeElements > 0) { $restrictType = $typeElements[0]->to_literal; # Screen out targets that don't match the given type if($filteredTargets{$target}{_allowed_} == 1) { my $type = $filteredTargets{$target}{_identity_}{TYPE}; if($restrictType ne $type && $filteredTargets{$target}{_allowed_} == 1) { $filteredTargets{$target}{_allowed_} = 0; next; } } } if(scalar @nodeElements > 0) { $restrictNode = $nodeElements[0]->to_literal; # Screen out targets that don't match the given node. # A target matches the node restriction if its physical # path contains the same node ID. my $isInSameNodeExpr = quotemeta "physical:sys-0/node-$restrictNode" ; my $path = $filteredTargets{$target}{_identity_}{PHYS_PATH}; if($path !~ m/^$isInSameNodeExpr/) { $filteredTargets{$target}{_allowed_} = 0; next; } } if(scalar @unitElements > 0) { $restrictUnit = $unitElements[0]->to_literal; my $checkPosition = 0; # Screen out targets that do not have unit attributes, # or which have non-matching unit attributes if( (!exists $filteredTargets{$target}{_identity_}{CHIP_UNIT}) || ($filteredTargets{$target}{_identity_}{CHIP_UNIT} != $restrictUnit) ) { $filteredTargets{$target}{_allowed_} = 0; next; } else { $checkPosition = 1; } # If unit matches, need to make sure it also sits on # chip at requested position, if specified if($checkPosition && ((scalar @positionElements) > 0)) { my $candidatePath = $filteredTargets{$target}{_identity_}{PHYS_PATH}; my $parent_phys_path = substr( $candidatePath, 0,(rindex $candidatePath, "/")); my $foundPosition = 0; # Walk from unit to whatever parent has the position # attribute; Remove this target from consideration # if the position does not match the restriction while( defined $targetPhysicalPath{$parent_phys_path}) { if(defined $filteredTargets{ $targetPhysicalPath{$parent_phys_path} }{_identity_}{POSITION}) { if ($filteredTargets{ $targetPhysicalPath{$parent_phys_path} }{_identity_}{POSITION} == $positionElements[0]->to_literal) { $foundPosition = 1; } last; } $candidatePath = $parent_phys_path; $parent_phys_path = substr( $candidatePath, 0, (rindex $candidatePath, "/")); } if(!$foundPosition) { $filteredTargets{$target}{_allowed_} = 0; next; } } } # If no unit restriction but position restriction, screen # out targets that don't have position attribute or whose # position attribute does not match the restriction if( (scalar @positionElements > 0) && (scalar @unitElements == 0) ) { $restrictPos = $positionElements[0]->to_literal; if( (!exists $filteredTargets{$target}{_identity_}{POSITION}) || ( $filteredTargets{$target}{_identity_}{POSITION} != $restrictPos)) { $filteredTargets{$target}{_allowed_} = 0; } } } } } foreach my $target (keys %filteredTargets) { # Don't bother with any target that is not in play if($filteredTargets{$target}{_allowed_} != 1) { next; } # Candidate is any target having the attribute and a default # value determined if( exists $instanceRef->{$target}{$attributeId} && exists $instanceRef->{$target}{$attributeId}{default} && exists $instanceRef->{$target}{$attributeId}{size}) { # Multiple BIOS directives cannot touch same # target/attribute if(defined $attrTargAttrSetByBios{$target}{$attributeId}) { main::fatal("$target, $attributeId set by multiple BIOS " . "definitions.\n"); } else { $attrTargAttrSetByBios{$target}{$attributeId} = 1; } # If no default set yet if(! (defined $default) ) { $default = $instanceRef->{$target}{$attributeId}{default}; $size = $instanceRef->{$target}{$attributeId}{size}; } # Cannot have different defaults in same group elsif( $instanceRef->{$target}{$attributeId}{default} != $default ) { main::fatal("BIOS definition specified attribute " . "$attributeId, but default values are not same " . "across all qualifying targets. " . "$target/ $attributeId = " . "$instanceRef->{$target}{$attributeId}{default}.\n"); } } } # If no targets had the attribute if(!defined $default || !defined $size) { main::fatal("BIOS definition specified attribute $attributeId, but " . "after considering target restrictions/etc., no " . "valid targets were found.\n"); } # Add the restriction info to the XML tree. This info is useful for 3rd # parties to create Hostboot attribute overrides. my $targetElement = $self->createChildElement($attribute,"target"); $self->createChildElement( $targetElement,"type",sprintf("0x%08X",$restriction{numericType})); $self->createChildElement( $targetElement,"node",sprintf("0x%02X",$restriction{node})); $self->createChildElement( $targetElement,"position",sprintf("0x%04X",$restriction{position})); $self->createChildElement( $targetElement,"unit",sprintf("0x%02X",$restriction{unit})); my @enumerationOverrideElement = $attribute->findnodes('./enumerationOverride'); if($attrType eq "enumeration") { # Get a copy of the enumeration description. Schema requires # enumerator to have only a name (symbolic handle) + value. # Customization allows overriding description + short name # Customization allows specifying subset of values to actually use # Output includes short name, long name, value my $enumType = $attrMapRef->{$attributeId}{simpleType}{enumeration}{id}; my $enumerationType = ::getEnumerationType($$attributesRef,$enumType); my %foundAllowed = (); my $enableRestrictions = 0; if(scalar @enumerationOverrideElement) { # Each enumerator name must tie back to a valid enumeration foreach my $overrideNameElement ( $attribute->findnodes( './enumerationOverride/allowedEnumerators/name')) { my $overrideName = $overrideNameElement->to_literal; my $nameFound = 0; foreach my $enumerator (@{$enumerationType->{enumerator}}) { if($enumerator->{name} eq $overrideName) { # Each allowed value must be different from all the # rest previously found for this attribute if(exists $foundAllowed{$overrideName}) { main::fatal("BIOS definition specified " . "attribute $attributeId, and supplied " . "override to allowed enumeration values, " . "but duplicated a value of " . "$overrideName.\n"); } else { $foundAllowed{$overrideName} = 1; $enumerator->{allowed} = 1; } $enableRestrictions = 1; $nameFound = 1; last; } } if(!$nameFound) { main::fatal("BIOS definition specified attribute " . "$attributeId, and supplied override to allowed " . "enumeration values, but requested enumerator " . "$overrideName is not valid.\n"); } } # Apply any overrides to the enumerator text my %textOverrideAllowed = (); foreach my $enumeratorOverrideElement ( $attribute->findnodes( './enumerationOverride/enumeratorOverride')) { # Each override must have exactly one name element my @name = $enumeratorOverrideElement->findnodes('./name'); # Each override must have 0 or 1 display-name and # descriptions elements my @displayName = $enumeratorOverrideElement->findnodes('./display-name'); my @description = $enumeratorOverrideElement->findnodes('./description'); # Make sure enumerator name is valid my $overrideName = $name[0]->to_literal; my $nameFound = 0; foreach my $enumerator (@{$enumerationType->{enumerator}}) { if($enumerator->{name} eq $overrideName) { # Must not duplicate already overridden enumerator if(exists $textOverrideAllowed{$overrideName}) { main::fatal("BIOS definition specified " . "attribute $attributeId, and supplied " . "override to allowed enumerator, " . "but already overrode this " . "enuemrator.\n"); } # Can only override things that are not restricted elsif( !exists $foundAllowed{$overrideName} && $enableRestrictions) { main::fatal("BIOS definition specified " . "attribute $attributeId, and supplied " . "override to allowed enumerator, but " . "this enumerator $overrideName is " . "restricted.\n"); } else { $textOverrideAllowed{$overrideName} = 1; } if(scalar @displayName) { $enumerator->{'display-name'} = $displayName[0]->to_literal; } if(scalar @description) { $enumerator->{description} = $description[0]->to_literal; } $nameFound = 1; last; } } if(!$nameFound) { main::fatal("BIOS definition specified attribute " . "$attributeId, and supplied override to allowed " . "enumeration, but requested invalid enumerator " . "name to override of $overrideName.\n"); } } } my $enumerationElement = $self->createChildElement($attribute,"enumeration"); foreach my $enumerator (@{$enumerationType->{enumerator}}) { if($enableRestrictions && !exists $enumerator->{allowed}) { # If enumerator is not allowed and is same as attribute # default then can't continue if($default eq $enumerator->{name}) { main::fatal("BIOS definition specified attribute " . "$attributeId as not allowing " . "$enumerator->{name}, but that is the attribute " . "default.\n"); } next; } my $enumeratorElement = $self->createChildElement($enumerationElement,"enumerator"); if(!exists $enumerator->{'display-name'}) { main::fatal("BIOS definition specified attribute " . "$attributeId, and supplied override to enumerator " . "$enumerator->{name}, but there is no " . "display-name.\n"); } $self->createChildElement( $enumeratorElement,"display-name", $enumerator->{'display-name'}); if(!exists $enumerator->{description}) { main::fatal("BIOS definition specified attribute " . "$attributeId, and supplied override to enumerator " . "$enumerator->{name}, but there is no " . "description.\n"); } $self->createChildElement( $enumeratorElement,"description",$enumerator->{description}); $self->createChildElement( $enumeratorElement,"value", sprintf("0x%08X",$enumerator->{value})); } # Translate attribute default to actual value $default = ::enumNameToValue($enumerationType,$default); } # No enums allowed to be specified elsif(scalar @enumerationOverrideElement) { main::fatal("BIOS definition specified attribute $attributeId, " . "and supplied enumerated values, but this is not an " . "enumeration attribute, it is of type $attrType.\n"); } # Can only specify numeric override for signed/unsigned values of # 1,2,4,8 byte values my @numericOverrideElements= $attribute->findnodes('./numericOverride'); # Hash of min(key), max(value) pairs my %allowedRange = (); if(scalar @numericOverrideElements) { # If range override not allowed for this attribute, bail if($typeHash{$attrType}{ror} != 1) { main::fatal("BIOS definition specified attribute $attributeId, " . "and supplied numeric override, but this attribute " . "type does not support such override. Type is " . "$attrType.\n"); } # A numericOverride has exactly one start + end element my @startElements = @numericOverrideElements[0]->findnodes('./start'); my @endElements = @numericOverrideElements[0]->findnodes('./end'); my $min = $typeHash{$attrType}{min}; my $max = $typeHash{$attrType}{max}; # Validate range min if(scalar @startElements) { my $rawMin = @startElements[0]->to_literal; if($rawMin < $min || $rawMin > $max) { main::fatal("BIOS definition specified attribute " . "$attributeId, and supplied valid start or end " . "range, but min out of range. requested " . "min = $rawMin, allowed min = " . "$typeHash{$attrType}{min}, allowed max = " . "$typeHash{$attrType}{max}.\n"); } $min = $rawMin; } # Validate range max if(scalar @endElements) { my $rawMax = @endElements[0]->to_literal; if($rawMax > $max || $rawMax < $min) { main::fatal("BIOS definition specified attribute " . "$attributeId, and supplied valid start or end " . "range, but max out of range. requested " . "max = $rawMax, current min = $min, " . "allowed min = " . "$typeHash{$attrType}{min}, allowed max = " . "$typeHash{$attrType}{max}.\n"); } $max = $rawMax; } # Min must be <= Max if($min > $max) { main::fatal("BIOS definition specified attribute " . "$attributeId, and supplied valid start or end " . "range, but min > max. min = $min, " . "max = $max.\n"); } # To prevent range overlaps, cannot duplicate the same start of # a range if(defined $allowedRange{$min}) { main::fatal("Already range starting at $min.\n"); } $allowedRange{$min} = $max; my $defaultInRange = 0; my $min = undef; my $max = undef; # Ensure default value falls within a defined range. The ranges are # sorted in numerically ascending order according to the start of # each range, so if the start of # range N falls within range N-1, we know there is an illegal range # overlap and fail. foreach my $rangeKey (sort {$a <=> $b} keys %allowedRange) { if( ($default >= $rangeKey) && ($default <= $allowedRange{$rangeKey}) ) { $defaultInRange = 1; } if(!defined $min) { $min = $rangeKey; $max = $allowedRange{$rangeKey}; next; } if($rangeKey <= $max) { main::fatal("Range starting with $rangeKey overlaps " . "range ending at $max.\n"); } $min = $rangeKey; $max = $allowedRange{$rangeKey}; } if(!$defaultInRange) { main::fatal("Default value $default not in any valid range.\n"); } } # Convert attribute ID to numerical value and append to XML tree my $attributeIdEnumeration = ::getAttributeIdEnumeration($$attributesRef); my $attrValue = ::enumNameToValue($attributeIdEnumeration,$attributeId); $attrValue = sprintf ("0x%0X", $attrValue); # Add the remaining metadata to the XML tree $self->createChildElement($attribute,"default",$default); $self->createChildElement($attribute,"numeric-id",$attrValue); $self->createChildElement($attribute,"size",$size); } } 1; } __END__ =head1 NAME xmltohb.pl =head1 SYNOPSIS xmltohb.pl [options] [file ...] =head1 OPTIONS =over 8 =item B<--help> Print a brief help message and exits. =item B<--man> Prints the manual page and exits. =item B<--hb-xml-file> File containing the intermediate representation of the host boot XML just prior to compilation down to images and source files (Default is ./hb.xml) =item B<--fapi-attributes-xml-file> File containing the FAPI HWP attributes, for purposes of configuring the attribute mappings between FAPI and targeting code =item B<--src-output-dir>=DIRECTORY Sets the output directory for generated source files (default is the current directory) =item B<--img-output-dir>=DIRECTORY Sets the output directory for generated binary files (default is the current directory) =item B<--img-output-file>=FILE Sets the file to receive the PNOR targeting image output (default ./targeting.bin). Only used when generating the PNOR targeting image =item B<--vmm-consts-file>=FILE Indicates the file containing the base virtual address of the attributes (default is src/include/usr/vmmconst.h). Only used when generating the PNOR targeting image =item B<--smattr-output-file>=FILE Indicates the file to dump hex representation of attributes that are synced between system model and targeting. Only used by FSP. =item B<--big-endian> Writes data structures to file in big endian format (default) =item B<--nobig-endian> Writes data structures to targeting image in little endian format (override to default). Supports x86 environments. =item B<--short-enums> Writes optimially sized enumerations to binary image (default). Any code which uses the binary image or enumerations from generated header files must also be compiled with short enumeration support. This saves at minimum 0 and at most 3 bytes for each enumeration value. =item B<--noshort-enums> Writes maximum sized enumerations to binary image (default). Any code which uses the binary image or enumerations from generated header files must not be compiled with short enumeration support. Every enumeration will consume 4 bytes by default =item B<--include-fsp-attributes> Emits FSP specific attributes and targets into the generated binaries and generated code. =item B<--noinclude-fsp-attributes> Omits FSP specific attributes and targets from the generated binaries and generated code. This is the default behavior. =item B<--version-page> Adds 4096 bytes of version page as first page in the generated binaries. =item B<--no-version-page> Does not add 4096 bytes of version page as first page in the generated binaries . This is the default behavior. =item B<--bios-xml-file> Path + file name of XML file describing the platform's BIOS configuration. Optional. =item B<--bios-schema-file> Path + file name of XSD schema file used to validate the BIOS XML file. Required if a BIOS XML file is given. =item B<--bios-output-file> Path + filename of output XML file describing the amended BIOS configuration. This output is commonly later modified by 3rd parties via xslt transformation to tailor the output for a given application. Required if a BIOS XML file is given. =item B<--verbose> Prints out some internal workings =back =head1 DESCRIPTION B will process a set of input .xml files and emit source files and a PNOR targeting image binary to facilitate compiling and configuring host boot respectively. =cut