#!/usr/bin/perl # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # $Source: src/usr/fapi2/platCreateHwpErrParser.pl $ # # OpenPOWER HostBoot Project # # Contributors Listed Below - COPYRIGHT 2015,2019 # [+] Google Inc. # [+] 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: This perl script will parse HWP Error XML files and create a # file containing functions that parses the return code and FFDC # data in HWP error logs # # Author: Thi Tran # use strict; #------------------------------------------------------------------------------ # Print Command Line Help #------------------------------------------------------------------------------ my $numArgs = $#ARGV + 1; if ($numArgs < 2) { print ("Usage: platCreateHwpErrParser.pl ...\n"); print (" This perl script will parse HWP Error XML files and create\n"); print (" two files hbfwPlatHwpErrParser.H and hbfwPlatHwpErrParserFFDC.H that\n"); print (" parse the return code and FFDC data in HWP error logs\n"); exit(1); } #------------------------------------------------------------------------------ # Specify perl modules to use #------------------------------------------------------------------------------ use Digest::MD5 qw(md5_hex); use XML::Simple; my $xml = new XML::Simple (KeyAttr=>[]); # Uncomment to enable debug output #use Data::Dumper; #------------------------------------------------------------------------------ # Open output files for writing #------------------------------------------------------------------------------ my $rcFile = $ARGV[0]; $rcFile .= "/"; my $eDisFile = $rcFile; $rcFile .= "hbfwPlatHwpErrParser.H"; open(TGFILE, ">", $rcFile); $eDisFile .= "hbfwErrDisplayPlatHwpErr.H"; open(EDISFILE, ">", $eDisFile); #------------------------------------------------------------------------------ # Print start of file information #------------------------------------------------------------------------------ print TGFILE "// hbfwPlatHwpErrParser.H\n"; print TGFILE "// This file is generated by perl script platCreateHwpErrParser.pl\n\n"; print TGFILE "#ifndef HBFWPLATHWPERRPARSER_H_\n"; print TGFILE "#define HBFWPLATHWPERRPARSER_H_\n\n"; print TGFILE "#if defined(PARSER) || defined(LOGPARSER)\n\n"; print TGFILE "namespace fapi2\n"; print TGFILE "{\n\n"; print TGFILE "void hbfwParseHwpRc(ErrlUsrParser & i_parser,\n"; print TGFILE " void * i_pBuffer,\n"; print TGFILE " const uint32_t i_buflen)\n"; print TGFILE "{\n"; print TGFILE " uint32_t l_rc = ntohl(*(static_cast(i_pBuffer)));\n"; print TGFILE " switch(l_rc)\n"; print TGFILE " {\n"; print EDISFILE "// hbfwErrDisplayPlatHwpErr.H\n"; print EDISFILE "// This file is generated by perl script platCreateHwpErrParser.pl\n\n"; print EDISFILE "#ifndef HBFWERRDISPLAYPLATHWPERR_H_\n"; print EDISFILE "#define HBFWERRDISPLAYPLATHWPERR_H_\n\n"; print EDISFILE "namespace fapi2\n"; print EDISFILE "{\n\n"; print EDISFILE "void hbfwErrLookupHwpRc(const uint32_t i_hwpRc, const char *& o_rcStr, const char *& o_descStr)\n"; print EDISFILE "{\n"; print EDISFILE " static const struct {\n"; print EDISFILE " const uint32_t hwp_rc;\n"; print EDISFILE " const char * const rc_str;\n"; print EDISFILE " const char * const desc;\n"; print EDISFILE " } hwpDescMap[] = {\n"; #------------------------------------------------------------------------------ # For each XML file #------------------------------------------------------------------------------ foreach my $argnum (1 .. $#ARGV) { #-------------------------------------------------------------------------- # Read XML file #-------------------------------------------------------------------------- my $infile = $ARGV[$argnum]; my $errors = $xml->XMLin($infile, ForceArray => ['hwpError']); # Uncomment to get debug output of all errors #print "\nFile: ", $infile, "\n", Dumper($errors), "\n"; #-------------------------------------------------------------------------- # For each Error #-------------------------------------------------------------------------- foreach my $err (@{$errors->{hwpError}}) { #---------------------------------------------------------------------- # Get the description, remove newlines, leading and trailing spaces and # multiple spaces #---------------------------------------------------------------------- my $desc = $err->{description}; $desc =~ s/\n/ /g; $desc =~ s/^ +//g; $desc =~ s/ +$//g; $desc =~ s/ +/ /g; $desc =~ s/\"//g; #---------------------------------------------------------------------- # Print the RC description # Note that this uses the same code to calculate the error enum value # as fapiParseErrorInfo.pl. This code must be kept in sync #---------------------------------------------------------------------- my $errHash128Bit = md5_hex($err->{rc}); my $errHash24Bit = substr($errHash128Bit, 0, 6); print TGFILE " case 0x$errHash24Bit:\n"; print TGFILE " i_parser.PrintString(\"HwpReturnCode\", \"$err->{rc}\");\n"; print TGFILE " i_parser.PrintString(\"HWP Error description\", \"$desc\");\n"; print TGFILE " break;\n"; print EDISFILE " { 0x$errHash24Bit, \"$err->{rc}\", \"$desc\" },\n"; } } #------------------------------------------------------------------------------ # Print end of fapiParseHwpRc function #------------------------------------------------------------------------------ print TGFILE " default:\n"; print TGFILE " i_parser.PrintNumber(\"Unrecognized Error ID\", \"0x%x\", l_rc);\n"; print TGFILE " if (i_buflen) {i_parser.PrintHexDump(i_pBuffer, i_buflen);}\n"; print TGFILE " }\n"; print TGFILE "}\n\n"; print EDISFILE " };\n\n"; print EDISFILE " o_rcStr = NULL;\n"; print EDISFILE " o_descStr = NULL;\n"; print EDISFILE " for (size_t i = 0; i < sizeof(hwpDescMap)/sizeof(hwpDescMap[0]); ++i) {\n"; print EDISFILE " if (hwpDescMap[i].hwp_rc == i_hwpRc) {\n"; print EDISFILE " o_rcStr = hwpDescMap[i].rc_str;\n"; print EDISFILE " o_descStr = hwpDescMap[i].desc;\n"; print EDISFILE " break;\n"; print EDISFILE " }\n"; print EDISFILE " }\n"; print EDISFILE "}\n\n"; #------------------------------------------------------------------------------ # Print end of file info #------------------------------------------------------------------------------ print TGFILE "}\n\n"; print TGFILE "#endif\n"; print TGFILE "#endif\n"; print EDISFILE "}\n\n"; print EDISFILE "#endif\n"; #------------------------------------------------------------------------------ # Close output file #------------------------------------------------------------------------------ close(TGFILE); close(EDISFILE); #------------------------------------------------------------------------------ # Open output files for writing #------------------------------------------------------------------------------ my $rcFile = $ARGV[0]; $rcFile .= "/"; my $eDisFile = $rcFile; $rcFile .= "hbfwPlatHwpErrParserFFDC.H"; open(TGFILE, ">", $rcFile); $eDisFile .= "hbfwErrDisplayPlatHwpFFDC.H"; open(EDISFILE, ">", $eDisFile); #------------------------------------------------------------------------------ # Print start of file information #------------------------------------------------------------------------------ print TGFILE "// hbfwPlatHwpErrParserFFDC.H\n"; print TGFILE "// This file is generated by perl script platCreateHwpErrParser.pl\n\n"; print TGFILE "#ifndef HBFWPLATHWPERRPARSERFFDC_H_\n"; print TGFILE "#define HBFWPLATHWPERRPARSERFFDC_H_\n\n"; print TGFILE "#if defined(PARSER) || defined(LOGPARSER)\n\n"; print TGFILE "#include \n\n"; print TGFILE "namespace fapi2\n"; print TGFILE "{\n\n"; print EDISFILE "// hbfwErrDisplayPlatHwpFFDC.H\n"; print EDISFILE "// This file is generated by perl script platCreateHwpErrParser.pl\n\n"; print EDISFILE "#ifndef HBFWERRDISPLAYPLATHWPFFDC_H_\n"; print EDISFILE "#define HBFWERRDISPLAYPLATHWPFFDC_H_\n\n"; print EDISFILE "#include \n\n"; print EDISFILE "#include \n"; print EDISFILE "#include \n"; print EDISFILE "#include \n"; print EDISFILE "#include \n"; print EDISFILE "#include \n"; print EDISFILE "#include \n"; print EDISFILE "#include \n"; print EDISFILE "#include \n"; print EDISFILE "#include \n"; print EDISFILE "#include \n"; print EDISFILE "namespace fapi2\n"; print EDISFILE "{\n\n"; #------------------------------------------------------------------------------ # Print start of hbfwParseHwpFfdc function #------------------------------------------------------------------------------ print TGFILE "void hbfwParseHwpFfdc(ErrlUsrParser & i_parser,\n"; print TGFILE " void * i_pBuffer,\n"; print TGFILE " const uint32_t i_buflen)\n"; print TGFILE "{\n"; print TGFILE " const uint32_t CFAM_DATA_LEN = 4;\n"; print TGFILE " const uint32_t SCOM_DATA_LEN = 8;\n"; print TGFILE " const uint32_t POS_LEN = 4;\n"; print TGFILE " uint8_t * l_pBuffer = static_cast(i_pBuffer);\n"; print TGFILE " uint32_t l_buflen = i_buflen;\n\n"; print TGFILE " // The first uint32_t is the FFDC ID\n"; print TGFILE " uint32_t * l_pFfdcId = static_cast(i_pBuffer);\n"; print TGFILE " uint32_t l_ffdcId = ntohl(*l_pFfdcId);\n"; print TGFILE " l_pBuffer += sizeof(l_ffdcId);\n"; print TGFILE " l_buflen -= sizeof(l_ffdcId);\n"; print TGFILE " switch(l_ffdcId)\n"; print TGFILE " {\n"; print EDISFILE "enum hbfwFfdcType : uint8_t {\n"; print EDISFILE " HBFW_FFDC_TYPE_HWP_RC_FFDC,\n"; print EDISFILE " HBFW_FFDC_TYPE_SCOM_FAIL,\n"; print EDISFILE " HBFW_FFDC_TYPE_PIB_RC,\n"; print EDISFILE " HBFW_FFDC_TYPE_REGISTER_SET,\n"; print EDISFILE " HBFW_FFDC_TYPE_CHIP_POSITION,\n"; print EDISFILE " HBFW_FFDC_TYPE_CFAM_REG,\n"; print EDISFILE " HBFW_FFDC_TYPE_SCOM_REG,\n"; print EDISFILE "};\n"; print EDISFILE "\n"; print EDISFILE "int hbfwErrLookupHwpRcFFDC(const uint32_t i_ffdcId,\n"; print EDISFILE " int i_index,\n"; print EDISFILE " hbfwFfdcType &o_ffdcType,\n"; print EDISFILE " uint64_t &o_value,\n"; print EDISFILE " const char * & o_str)\n"; print EDISFILE "{\n"; print EDISFILE " static const struct {\n"; print EDISFILE " const uint32_t ffdc_id;\n"; print EDISFILE " hbfwFfdcType type;\n"; print EDISFILE " uint64_t value;\n"; print EDISFILE " const char * const str;\n"; print EDISFILE " } __attribute__((packed)) hwpRcFfdcMap[] = {\n"; #------------------------------------------------------------------------------ # For each XML file #------------------------------------------------------------------------------ foreach my $argnum (1 .. $#ARGV) { #-------------------------------------------------------------------------- # Read XML file #-------------------------------------------------------------------------- my $infile = $ARGV[$argnum]; my $errors = $xml->XMLin($infile, ForceArray => ['hwpError', 'ffdc', 'registerFfdc', 'cfamRegister', 'scomRegister']); # Uncomment to get debug output of all errors #print "\nFile: ", $infile, "\n", Dumper($errors), "\n"; #-------------------------------------------------------------------------- # If it is an FFDC section resulting from a element, print # out the FFDC name and hexdump the data #-------------------------------------------------------------------------- foreach my $err (@{$errors->{hwpError}}) { if ($err->{platScomFail}) { my $ffdcName = $err->{rc} . "_address"; my $ffdcHash128Bit = md5_hex($ffdcName); my $ffdcHash32Bit = substr($ffdcHash128Bit, 0, 8); print TGFILE " case 0x$ffdcHash32Bit:\n"; print TGFILE " { uint64_t l_Address =\n"; print TGFILE " be64toh(*(reinterpret_cast(l_pBuffer)));\n"; print TGFILE " i_parser.PrintNumber(\"Failed SCOM address\",\"%#016lX\",l_Address);}\n"; print TGFILE " break;\n"; print EDISFILE " { 0x$ffdcHash32Bit, HBFW_FFDC_TYPE_SCOM_FAIL, 0, NULL},\n"; $ffdcName = $err->{rc} . "_pcb_pib_rc"; $ffdcHash128Bit = md5_hex($ffdcName); $ffdcHash32Bit = substr($ffdcHash128Bit, 0, 8); print TGFILE " case 0x$ffdcHash32Bit:\n"; print TGFILE " {uint32_t l_PibRc = be32toh(*(reinterpret_cast(l_pBuffer)));\n"; print TGFILE " i_parser.PrintNumber(\"PIB RC:\",\"%#08lX\",l_PibRc);}\n"; print TGFILE " break;\n"; print EDISFILE " { 0x$ffdcHash32Bit, HBFW_FFDC_TYPE_PIB_RC, 0, NULL},\n"; } foreach my $ffdc (@{$err->{ffdc}}) { #------------------------------------------------------------------ # Figure out the FFDC ID stored in the data. This is calculated in # the same way as fapiParseErrorInfo.pl. This code must be kept in # sync #------------------------------------------------------------------ my $ffdcName = $err->{rc} . "_" . $ffdc; my $ffdcHash128Bit = md5_hex($ffdcName); my $ffdcHash32Bit = substr($ffdcHash128Bit, 0, 8); print TGFILE " case 0x$ffdcHash32Bit:\n"; print TGFILE " i_parser.PrintString(\"HwpReturnCode\", \"$err->{rc}\");\n"; print TGFILE " i_parser.PrintString(\"FFDC:\", \"$ffdc\");\n"; print TGFILE " if (l_buflen) "; print TGFILE "{i_parser.PrintHexDump(l_pBuffer, l_buflen);}\n"; print TGFILE " break;\n"; my $errHash128Bit = md5_hex($err->{rc}); my $errHash24Bit = substr($errHash128Bit, 0, 6); print EDISFILE " { 0x$ffdcHash32Bit, HBFW_FFDC_TYPE_HWP_RC_FFDC, 0x$errHash24Bit, \"$ffdc\"},\n"; } } #-------------------------------------------------------------------------- # If it is an FFDC section resulting from a element, print # out the ID and walk through the registers, printing each out #-------------------------------------------------------------------------- foreach my $registerFfdc (@{$errors->{registerFfdc}}) { #---------------------------------------------------------------------- # Figure out the FFDC ID stored in the data. This is calculated in the # same way as fapiParseErrorInfo.pl. This code must be kept in sync #---------------------------------------------------------------------- my $ffdcName = $registerFfdc->{id}; my $ffdcHash128Bit = md5_hex($ffdcName); my $ffdcHash32Bit = substr($ffdcHash128Bit, 0, 8); print TGFILE " case 0x$ffdcHash32Bit:\n"; print TGFILE " i_parser.PrintString(\"Register FFDC:\", \"$ffdcName\");\n"; print TGFILE " while (l_buflen > 0)\n"; print TGFILE " {\n"; print TGFILE " if (l_buflen >= POS_LEN)\n"; print TGFILE " {\n"; print TGFILE " uint32_t * l_pBufferTemp = reinterpret_cast(l_pBuffer);\n"; print TGFILE " i_parser.PrintNumber(\"Chip Position:\",\"%X\",ntohl(*l_pBufferTemp));\n"; print TGFILE " l_pBufferTemp = NULL;\n"; print TGFILE " l_pBuffer+= POS_LEN;\n"; print TGFILE " l_buflen -= POS_LEN;\n"; print TGFILE " }\n"; print EDISFILE " { 0x$ffdcHash32Bit, HBFW_FFDC_TYPE_REGISTER_SET, 0, \"$ffdcName\"},\n"; print EDISFILE " { 0x$ffdcHash32Bit, HBFW_FFDC_TYPE_CHIP_POSITION, 0, NULL},\n"; foreach my $cfamRegister (@{$registerFfdc->{cfamRegister}}) { print TGFILE " if (l_buflen >= CFAM_DATA_LEN)\n"; print TGFILE " {\n"; print TGFILE " i_parser.PrintString(\"CFAM Register:\", \"$cfamRegister\");\n"; print TGFILE " i_parser.PrintHexDump(l_pBuffer, CFAM_DATA_LEN);\n"; print TGFILE " l_pBuffer+= CFAM_DATA_LEN;\n"; print TGFILE " l_buflen -= CFAM_DATA_LEN;\n"; print TGFILE " }\n"; print EDISFILE " { 0x$ffdcHash32Bit, HBFW_FFDC_TYPE_CFAM_REG, $cfamRegister, \"$cfamRegister\"},\n"; } foreach my $scomRegister (@{$registerFfdc->{scomRegister}}) { print TGFILE " if (l_buflen >= SCOM_DATA_LEN)\n"; print TGFILE " {\n"; print TGFILE " i_parser.PrintString(\"SCOM Register:\", \"$scomRegister\");\n"; print TGFILE " i_parser.PrintHexDump(l_pBuffer, SCOM_DATA_LEN);\n"; print TGFILE " l_pBuffer+= SCOM_DATA_LEN;\n"; print TGFILE " l_buflen -= SCOM_DATA_LEN;\n"; print TGFILE " }\n"; print EDISFILE " { 0x$ffdcHash32Bit, HBFW_FFDC_TYPE_SCOM_REG, $scomRegister, \"$scomRegister\"},\n"; } print TGFILE " }\n"; print TGFILE " break;\n"; } } #------------------------------------------------------------------------------ # Print end of parseHwpFfdc function #------------------------------------------------------------------------------ print TGFILE " default:\n"; print TGFILE " i_parser.PrintNumber(\"Unrecognized FFDC\", \"0x%x\", l_ffdcId);\n"; print TGFILE " if (l_buflen) "; print TGFILE "{i_parser.PrintHexDump(l_pBuffer, l_buflen);}\n"; print TGFILE " }\n\n"; print TGFILE "}\n\n"; print EDISFILE " };\n\n"; print EDISFILE " for (size_t i = 0; i < sizeof(hwpRcFfdcMap)/sizeof(hwpRcFfdcMap[0]); ++i) {\n"; print EDISFILE " if (hwpRcFfdcMap[i].ffdc_id == i_ffdcId) {\n"; print EDISFILE " if (i_index == 0) {\n"; print EDISFILE " o_ffdcType = hwpRcFfdcMap[i].type;\n"; print EDISFILE " o_value = hwpRcFfdcMap[i].value;\n"; print EDISFILE " o_str = hwpRcFfdcMap[i].str;\n"; print EDISFILE " return 1;\n"; print EDISFILE " } else {\n"; print EDISFILE " i_index--;\n"; print EDISFILE " }\n"; print EDISFILE " }\n"; print EDISFILE " }\n"; print EDISFILE " return 0;\n"; print EDISFILE "}\n\n"; #------------------------------------------------------------------------------ # Print end of file info #------------------------------------------------------------------------------ print TGFILE "}\n\n"; print TGFILE "#endif\n"; print TGFILE "#endif\n"; print EDISFILE "}\n\n"; print EDISFILE "#endif\n"; #------------------------------------------------------------------------------ # Close output file #------------------------------------------------------------------------------ close(TGFILE); close(EDISFILE);