1 /*
2 // Copyright (c) 2019 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 
17 #include <boost/beast/core/span.hpp>
18 #include <ipmi_to_redfish_hooks.hpp>
19 #include <me_to_redfish_hooks.hpp>
20 #include <storagecommands.hpp>
21 
22 #include <iomanip>
23 #include <sstream>
24 #include <string_view>
25 
26 namespace intel_oem::ipmi::sel
27 {
28 
29 namespace redfish_hooks
30 {
toHexStr(const boost::beast::span<uint8_t> bytes,std::string & hexStr)31 static void toHexStr(const boost::beast::span<uint8_t> bytes,
32                      std::string& hexStr)
33 {
34     std::stringstream stream;
35     stream << std::hex << std::uppercase << std::setfill('0');
36     for (const uint8_t& byte : bytes)
37     {
38         stream << std::setw(2) << static_cast<int>(byte);
39     }
40     hexStr = stream.str();
41 }
42 
43 // Record a BIOS message as a Redfish message instead of a SEL record
biosMessageHook(const SELData & selData,const std::string & ipmiRaw)44 static bool biosMessageHook(const SELData& selData, const std::string& ipmiRaw)
45 {
46     // This is a BIOS message, so record it as a Redfish message instead
47     // of a SEL record
48 
49     // Walk through the SEL request record to build the appropriate Redfish
50     // message
51     static constexpr std::string_view openBMCMessageRegistryVersion = "0.1";
52     std::string messageID =
53         "OpenBMC." + std::string(openBMCMessageRegistryVersion);
54     std::vector<std::string> messageArgs;
55     BIOSSensors sensor = static_cast<BIOSSensors>(selData.sensorNum);
56     BIOSEventTypes eventType = static_cast<BIOSEventTypes>(selData.eventType);
57     switch (sensor)
58     {
59         case BIOSSensors::memoryRASConfigStatus:
60             switch (eventType)
61             {
62                 case BIOSEventTypes::digitalDiscrete:
63                 {
64                     switch (selData.offset)
65                     {
66                         case 0x00:
67                             messageID += ".MemoryRASConfigurationDisabled";
68                             break;
69                         case 0x01:
70                             messageID += ".MemoryRASConfigurationEnabled";
71                             break;
72                         default:
73                             return defaultMessageHook(ipmiRaw);
74                             break;
75                     }
76                     // Get the message data from eventData2 and eventData3
77 
78                     // error = eventData2 bits [3:0]
79                     int error = selData.eventData2 & 0x0F;
80 
81                     // mode = eventData3 bits [3:0]
82                     int mode = selData.eventData3 & 0x0F;
83 
84                     // Save the messageArgs
85                     switch (error)
86                     {
87                         case 0x00:
88                             messageArgs.push_back("None");
89                             break;
90                         case 0x03:
91                             messageArgs.push_back("Invalid DIMM Config");
92                             break;
93                         default:
94                             messageArgs.push_back(std::to_string(error));
95                             break;
96                     }
97                     switch (mode)
98                     {
99                         case 0x00:
100                             messageArgs.push_back("None");
101                             break;
102                         case 0x01:
103                             messageArgs.push_back("Mirroring");
104                             break;
105                         case 0x02:
106                             messageArgs.push_back("Lockstep");
107                             break;
108                         case 0x04:
109                             messageArgs.push_back("Rank Sparing");
110                             break;
111                         default:
112                             messageArgs.push_back(std::to_string(mode));
113                             break;
114                     }
115 
116                     break;
117                 }
118                 default:
119                     return defaultMessageHook(ipmiRaw);
120                     break;
121             }
122             break;
123         case BIOSSensors::biosPOSTError:
124             switch (eventType)
125             {
126                 case BIOSEventTypes::sensorSpecificOffset:
127                 {
128                     switch (selData.offset)
129                     {
130                         case 0x00:
131                             messageID += ".BIOSPOSTError";
132                             break;
133                         default:
134                             return defaultMessageHook(ipmiRaw);
135                             break;
136                     }
137                     // Get the message data from eventData2 and eventData3
138 
139                     std::array<uint8_t, 2> post;
140                     // post LSB = eventData2 bits [7:0]
141                     post[1] = selData.eventData2;
142                     // post MSB = eventData3 bits [7:0]
143                     post[0] = selData.eventData3;
144 
145                     // Save the messageArgs
146                     messageArgs.emplace_back();
147                     std::string& postStr = messageArgs.back();
148                     toHexStr(boost::beast::span<uint8_t>(post), postStr);
149 
150                     break;
151                 }
152                 default:
153                     return defaultMessageHook(ipmiRaw);
154                     break;
155             }
156             break;
157         case BIOSSensors::intelUPILinkWidthReduced:
158             switch (eventType)
159             {
160                 case BIOSEventTypes::oemDiscrete7:
161                 {
162                     switch (selData.offset)
163                     {
164                         case 0x01:
165                             messageID += ".IntelUPILinkWidthReducedToHalf";
166                             break;
167                         case 0x02:
168                             messageID += ".IntelUPILinkWidthReducedToQuarter";
169                             break;
170                         default:
171                             return defaultMessageHook(ipmiRaw);
172                             break;
173                     }
174                     // Get the message data from eventData2
175 
176                     // Node ID = eventData2 bits [7:0]
177                     int node = selData.eventData2;
178 
179                     // Save the messageArgs
180                     messageArgs.push_back(std::to_string(node + 1));
181 
182                     break;
183                 }
184                 default:
185                     return defaultMessageHook(ipmiRaw);
186                     break;
187             }
188             break;
189         case BIOSSensors::memoryRASModeSelect:
190             switch (eventType)
191             {
192                 case BIOSEventTypes::digitalDiscrete:
193                 {
194                     switch (selData.offset)
195                     {
196                         case 0x00:
197                             messageID += ".MemoryRASModeDisabled";
198                             break;
199                         case 0x01:
200                             messageID += ".MemoryRASModeEnabled";
201                             break;
202                         default:
203                             return defaultMessageHook(ipmiRaw);
204                             break;
205                     }
206                     // Get the message data from eventData2 and eventData3
207 
208                     // prior mode = eventData2 bits [3:0]
209                     int priorMode = selData.eventData2 & 0x0F;
210 
211                     // selected mode = eventData3 bits [3:0]
212                     int selectedMode = selData.eventData3 & 0x0F;
213 
214                     // Save the messageArgs
215                     switch (priorMode)
216                     {
217                         case 0x00:
218                             messageArgs.push_back("None");
219                             break;
220                         case 0x01:
221                             messageArgs.push_back("Mirroring");
222                             break;
223                         case 0x02:
224                             messageArgs.push_back("Lockstep");
225                             break;
226                         case 0x04:
227                             messageArgs.push_back("Rank Sparing");
228                             break;
229                         default:
230                             messageArgs.push_back(std::to_string(priorMode));
231                             break;
232                     }
233                     switch (selectedMode)
234                     {
235                         case 0x00:
236                             messageArgs.push_back("None");
237                             break;
238                         case 0x01:
239                             messageArgs.push_back("Mirroring");
240                             break;
241                         case 0x02:
242                             messageArgs.push_back("Lockstep");
243                             break;
244                         case 0x04:
245                             messageArgs.push_back("Rank Sparing");
246                             break;
247                         default:
248                             messageArgs.push_back(std::to_string(selectedMode));
249                             break;
250                     }
251 
252                     break;
253                 }
254                 default:
255                     return defaultMessageHook(ipmiRaw);
256                     break;
257             }
258             break;
259         case BIOSSensors::bootEvent:
260             switch (eventType)
261             {
262                 case BIOSEventTypes::sensorSpecificOffset:
263                 {
264                     switch (selData.offset)
265                     {
266                         case 0x01:
267                             messageID += ".BIOSBoot";
268                             break;
269                         case 0x09:
270                             messageID += ".BIOSAttributesChanged";
271                             break;
272                         default:
273                             return defaultMessageHook(ipmiRaw);
274                             break;
275                     }
276                     break;
277                 }
278                 default:
279                     return defaultMessageHook(ipmiRaw);
280                     break;
281             }
282             break;
283         default:
284             return defaultMessageHook(ipmiRaw);
285             break;
286     }
287 
288     // Log the Redfish message to the journal with the appropriate metadata
289     std::string journalMsg = "BIOS POST IPMI event: " + ipmiRaw;
290     if (messageArgs.empty())
291     {
292         phosphor::logging::log<phosphor::logging::level::INFO>(
293             journalMsg.c_str(),
294             phosphor::logging::entry("REDFISH_MESSAGE_ID=%s",
295                                      messageID.c_str()));
296     }
297     else
298     {
299         std::string messageArgsString =
300             boost::algorithm::join(messageArgs, ",");
301         phosphor::logging::log<phosphor::logging::level::INFO>(
302             journalMsg.c_str(),
303             phosphor::logging::entry("REDFISH_MESSAGE_ID=%s",
304                                      messageID.c_str()),
305             phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s",
306                                      messageArgsString.c_str()));
307     }
308 
309     return true;
310 }
311 
312 // Record a BIOS SMI message as a Redfish message instead of a SEL record
biosSMIMessageHook(const SELData & selData,const std::string & ipmiRaw)313 static bool biosSMIMessageHook(const SELData& selData,
314                                const std::string& ipmiRaw)
315 {
316     // This is a BIOS SMI message, so record it as a Redfish message instead
317     // of a SEL record
318 
319     // Walk through the SEL request record to build the appropriate Redfish
320     // message
321     static constexpr std::string_view openBMCMessageRegistryVersion = "0.1";
322     std::string messageID =
323         "OpenBMC." + std::string(openBMCMessageRegistryVersion);
324     std::vector<std::string> messageArgs;
325     BIOSSMISensors sensor = static_cast<BIOSSMISensors>(selData.sensorNum);
326     BIOSEventTypes eventType = static_cast<BIOSEventTypes>(selData.eventType);
327     switch (sensor)
328     {
329         case BIOSSMISensors::mirroringRedundancyState:
330             switch (eventType)
331             {
332                 case BIOSEventTypes::discreteRedundancyStates:
333                 {
334                     switch (selData.offset)
335                     {
336                         case 0x00:
337                             messageID += ".MirroringRedundancyFull";
338                             break;
339                         case 0x02:
340                             messageID += ".MirroringRedundancyDegraded";
341                             break;
342                         default:
343                             return defaultMessageHook(ipmiRaw);
344                             break;
345                     }
346                     // Get the message data from eventData2 and eventData3
347 
348                     // pair = eventData2 bits [7:4]
349                     int pair = selData.eventData2 >> 4 & 0x0F;
350                     // rank = eventData2 bits [1:0]
351                     int rank = selData.eventData2 & 0x03;
352 
353                     // Socket ID = eventData3 bits [7:5]
354                     int socket = selData.eventData3 >> 5 & 0x07;
355                     // Channel = eventData3 bits [4:2]
356                     int channel = selData.eventData3 >> 2 & 0x07;
357                     char channelLetter[4] = {'A'};
358                     channelLetter[0] += channel;
359                     // DIMM = eventData3 bits [1:0]
360                     int dimm = selData.eventData3 & 0x03;
361 
362                     // Save the messageArgs
363                     messageArgs.push_back(std::to_string(socket + 1));
364                     messageArgs.push_back(std::string(channelLetter));
365                     messageArgs.push_back(std::to_string(dimm + 1));
366                     messageArgs.push_back(std::to_string(pair));
367                     messageArgs.push_back(std::to_string(rank));
368 
369                     break;
370                 }
371                 default:
372                     return defaultMessageHook(ipmiRaw);
373                     break;
374             }
375             break;
376         case BIOSSMISensors::memoryECCError:
377             switch (eventType)
378             {
379                 case BIOSEventTypes::sensorSpecificOffset:
380                 {
381                     switch (selData.offset)
382                     {
383                         case 0x00:
384                             messageID += ".MemoryECCCorrectable";
385                             break;
386                         case 0x01:
387                             messageID += ".MemoryECCUncorrectable";
388                             break;
389                         default:
390                             return defaultMessageHook(ipmiRaw);
391                             break;
392                     }
393                     // Get the message data from eventData2 and eventData3
394 
395                     // dimm = eventData2 bits [7:4]
396                     int dimm = selData.eventData2 >> 4 & 0x0F;
397                     // rank = eventData2 bits [3:0]
398                     int rank = selData.eventData2 & 0x0F;
399 
400                     // Socket ID = eventData3 bits [7:4]
401                     int socket = selData.eventData3 >> 4 & 0x0F;
402                     // Channel = eventData3 bits [3:0]
403                     int channel = selData.eventData3 & 0x0F;
404                     char channelLetter[4] = {'A'};
405                     channelLetter[0] += channel;
406 
407                     // Save the messageArgs
408                     messageArgs.push_back(std::to_string(socket + 1));
409                     messageArgs.push_back(std::string(channelLetter));
410                     messageArgs.push_back(std::to_string(dimm));
411                     messageArgs.push_back(std::to_string(rank));
412 
413                     break;
414                 }
415                 default:
416                     return defaultMessageHook(ipmiRaw);
417                     break;
418             }
419             break;
420         case BIOSSMISensors::legacyPCIError:
421             switch (eventType)
422             {
423                 case BIOSEventTypes::sensorSpecificOffset:
424                 {
425                     switch (selData.offset)
426                     {
427                         case 0x04:
428                             messageID += ".LegacyPCIPERR";
429                             break;
430                         case 0x05:
431                             messageID += ".LegacyPCISERR";
432                             break;
433                         default:
434                             return defaultMessageHook(ipmiRaw);
435                             break;
436                     }
437                     // Get the message data from eventData2 and eventData3
438 
439                     // Bus = eventData2 bits [7:0]
440                     int bus = selData.eventData2;
441                     // Device = eventData3 bits [7:3]
442                     int device = selData.eventData3 >> 3 & 0x1F;
443                     // Function = eventData3 bits [2:0]
444                     int function = selData.eventData3 >> 0x07;
445 
446                     // Save the messageArgs
447                     messageArgs.push_back(std::to_string(bus));
448                     messageArgs.push_back(std::to_string(device));
449                     messageArgs.push_back(std::to_string(function));
450 
451                     break;
452                 }
453                 default:
454                     return defaultMessageHook(ipmiRaw);
455                     break;
456             }
457             break;
458         case BIOSSMISensors::pcieFatalError:
459             switch (eventType)
460             {
461                 case BIOSEventTypes::oemDiscrete0:
462                 {
463                     switch (selData.offset)
464                     {
465                         case 0x00:
466                             messageID += ".PCIeFatalDataLinkLayerProtocol";
467                             break;
468                         case 0x01:
469                             messageID += ".PCIeFatalSurpriseLinkDown";
470                             break;
471                         case 0x02:
472                             messageID += ".PCIeFatalCompleterAbort";
473                             break;
474                         case 0x03:
475                             messageID += ".PCIeFatalUnsupportedRequest";
476                             break;
477                         case 0x04:
478                             messageID += ".PCIeFatalPoisonedTLP";
479                             break;
480                         case 0x05:
481                             messageID += ".PCIeFatalFlowControlProtocol";
482                             break;
483                         case 0x06:
484                             messageID += ".PCIeFatalCompletionTimeout";
485                             break;
486                         case 0x07:
487                             messageID += ".PCIeFatalReceiverBufferOverflow";
488                             break;
489                         case 0x08:
490                             messageID += ".PCIeFatalACSViolation";
491                             break;
492                         case 0x09:
493                             messageID += ".PCIeFatalMalformedTLP";
494                             break;
495                         case 0x0a:
496                             messageID += ".PCIeFatalECRCError";
497                             break;
498                         case 0x0b:
499                             messageID +=
500                                 ".PCIeFatalReceivedFatalMessageFromDownstream";
501                             break;
502                         case 0x0c:
503                             messageID += ".PCIeFatalUnexpectedCompletion";
504                             break;
505                         case 0x0d:
506                             messageID += ".PCIeFatalReceivedErrNonFatalMessage";
507                             break;
508                         case 0x0e:
509                             messageID += ".PCIeFatalUncorrectableInternal";
510                             break;
511                         case 0x0f:
512                             messageID += ".PCIeFatalMCBlockedTLP";
513                             break;
514                         default:
515                             return defaultMessageHook(ipmiRaw);
516                             break;
517                     }
518                     // Get the message data from eventData2 and eventData3
519 
520                     // Bus = eventData2 bits [7:0]
521                     int bus = selData.eventData2;
522                     // Device = eventData3 bits [7:3]
523                     int device = selData.eventData3 >> 3 & 0x1F;
524                     // Function = eventData3 bits [2:0]
525                     int function = selData.eventData3 >> 0x07;
526 
527                     // Save the messageArgs
528                     messageArgs.push_back(std::to_string(bus));
529                     messageArgs.push_back(std::to_string(device));
530                     messageArgs.push_back(std::to_string(function));
531 
532                     break;
533                 }
534                 default:
535                     return defaultMessageHook(ipmiRaw);
536                     break;
537             }
538             break;
539         case BIOSSMISensors::pcieCorrectableError:
540             switch (eventType)
541             {
542                 case BIOSEventTypes::oemDiscrete1:
543                 {
544                     switch (selData.offset)
545                     {
546                         case 0x00:
547                             messageID += ".PCIeCorrectableReceiverError";
548                             break;
549                         case 0x01:
550                             messageID += ".PCIeCorrectableBadDLLP";
551                             break;
552                         case 0x02:
553                             messageID += ".PCIeCorrectableBadTLP";
554                             break;
555                         case 0x03:
556                             messageID += ".PCIeCorrectableReplayNumRollover";
557                             break;
558                         case 0x04:
559                             messageID += ".PCIeCorrectableReplayTimerTimeout";
560                             break;
561                         case 0x05:
562                             messageID += ".PCIeCorrectableAdvisoryNonFatal";
563                             break;
564                         case 0x06:
565                             messageID += ".PCIeCorrectableLinkBWChanged";
566                             break;
567                         case 0x07:
568                             messageID += ".PCIeCorrectableInternal";
569                             break;
570                         case 0x08:
571                             messageID += ".PCIeCorrectableHeaderLogOverflow";
572                             break;
573                         case 0x0f:
574                             messageID += ".PCIeCorrectableUnspecifiedAERError";
575                             break;
576                         default:
577                             return defaultMessageHook(ipmiRaw);
578                             break;
579                     }
580                     // Get the message data from eventData2 and eventData3
581 
582                     // Bus = eventData2 bits [7:0]
583                     int bus = selData.eventData2;
584                     // Device = eventData3 bits [7:3]
585                     int device = selData.eventData3 >> 3 & 0x1F;
586                     // Function = eventData3 bits [2:0]
587                     int function = selData.eventData3 >> 0x07;
588 
589                     // Save the messageArgs
590                     messageArgs.push_back(std::to_string(bus));
591                     messageArgs.push_back(std::to_string(device));
592                     messageArgs.push_back(std::to_string(function));
593 
594                     break;
595                 }
596                 default:
597                     return defaultMessageHook(ipmiRaw);
598                     break;
599             }
600             break;
601         case BIOSSMISensors::sparingRedundancyState:
602             switch (eventType)
603             {
604                 case BIOSEventTypes::discreteRedundancyStates:
605                 {
606                     switch (selData.offset)
607                     {
608                         case 0x00:
609                             messageID += ".SparingRedundancyFull";
610                             break;
611                         case 0x02:
612                             messageID += ".SparingRedundancyDegraded";
613                             break;
614                         default:
615                             return defaultMessageHook(ipmiRaw);
616                             break;
617                     }
618                     // Get the message data from eventData2 and eventData3
619 
620                     // domain = eventData2 bits [7:4]
621                     int domain = selData.eventData2 >> 4 & 0x0F;
622                     char domainLetter[4] = {'A'};
623                     domainLetter[0] += domain;
624                     // rank = eventData2 bits [1:0]
625                     int rank = selData.eventData2 & 0x03;
626 
627                     // Socket ID = eventData3 bits [7:5]
628                     int socket = selData.eventData3 >> 5 & 0x07;
629                     // Channel = eventData3 bits [4:2]
630                     int channel = selData.eventData3 >> 2 & 0x07;
631                     char channelLetter[4] = {'A'};
632                     channelLetter[0] += channel;
633                     // DIMM = eventData3 bits [1:0]
634                     int dimm = selData.eventData3 & 0x03;
635 
636                     // Save the messageArgs
637                     messageArgs.push_back(std::to_string(socket + 1));
638                     messageArgs.push_back(std::string(channelLetter));
639                     messageArgs.push_back(std::to_string(dimm + 1));
640                     messageArgs.push_back(std::string(domainLetter));
641                     messageArgs.push_back(std::to_string(rank));
642 
643                     break;
644                 }
645                 default:
646                     return defaultMessageHook(ipmiRaw);
647                     break;
648             }
649             break;
650         case BIOSSMISensors::memoryParityError:
651             switch (eventType)
652             {
653                 case BIOSEventTypes::sensorSpecificOffset:
654                 {
655                     switch (selData.offset)
656                     {
657                         case 0x03:
658                         {
659                             // type = eventData2 bits [2:0]
660                             int type = selData.eventData2 & 0x07;
661                             switch (type)
662                             {
663                                 case 0x00:
664                                     messageID += ".MemoryParityNotKnown";
665                                     break;
666                                 case 0x03:
667                                     messageID +=
668                                         ".MemoryParityCommandAndAddress";
669                                     break;
670                                 default:
671                                     return defaultMessageHook(ipmiRaw);
672                                     break;
673                             }
674                             break;
675                         }
676                         default:
677                             return defaultMessageHook(ipmiRaw);
678                             break;
679                     }
680                     // Get the message data from eventData2 and eventData3
681 
682                     // channelValid = eventData2 bit [4]
683                     int channelValid = selData.eventData2 >> 4 & 0x01;
684                     // dimmValid = eventData2 bit [3]
685                     int dimmValid = selData.eventData2 >> 3 & 0x01;
686 
687                     // Socket ID = eventData3 bits [7:5]
688                     int socket = selData.eventData3 >> 5 & 0x07;
689                     // Channel = eventData3 bits [4:2]
690                     int channel = selData.eventData3 >> 2 & 0x07;
691                     char channelLetter[4] = {'A'};
692                     channelLetter[0] += channel;
693                     // DIMM = eventData3 bits [1:0]
694                     int dimm = selData.eventData3 & 0x03;
695 
696                     // Save the messageArgs
697                     messageArgs.push_back(std::to_string(socket + 1));
698                     messageArgs.push_back(std::string(channelLetter));
699                     messageArgs.push_back(std::to_string(dimm + 1));
700                     messageArgs.push_back(std::to_string(channelValid));
701                     messageArgs.push_back(std::to_string(dimmValid));
702 
703                     break;
704                 }
705                 default:
706                     return defaultMessageHook(ipmiRaw);
707                     break;
708             }
709             break;
710         case BIOSSMISensors::pcieFatalError2:
711             switch (eventType)
712             {
713                 case BIOSEventTypes::oemDiscrete6:
714                 {
715                     switch (selData.offset)
716                     {
717                         case 0x00:
718                             messageID += ".PCIeFatalAtomicEgressBlocked";
719                             break;
720                         case 0x01:
721                             messageID += ".PCIeFatalTLPPrefixBlocked";
722                             break;
723                         case 0x0f:
724                             messageID +=
725                                 ".PCIeFatalUnspecifiedNonAERFatalError";
726                             break;
727                         default:
728                             return defaultMessageHook(ipmiRaw);
729                             break;
730                     }
731                     // Get the message data from eventData2 and eventData3
732 
733                     // Bus = eventData2 bits [7:0]
734                     int bus = selData.eventData2;
735                     // Device = eventData3 bits [7:3]
736                     int device = selData.eventData3 >> 3 & 0x1F;
737                     // Function = eventData3 bits [2:0]
738                     int function = selData.eventData3 >> 0x07;
739 
740                     // Save the messageArgs
741                     messageArgs.push_back(std::to_string(bus));
742                     messageArgs.push_back(std::to_string(device));
743                     messageArgs.push_back(std::to_string(function));
744 
745                     break;
746                 }
747                 default:
748                     return defaultMessageHook(ipmiRaw);
749                     break;
750             }
751             break;
752         case BIOSSMISensors::biosRecovery:
753             switch (eventType)
754             {
755                 case BIOSEventTypes::oemDiscrete0:
756                 {
757                     switch (selData.offset)
758                     {
759                         case 0x01:
760                             messageID += ".BIOSRecoveryStart";
761                             break;
762                         default:
763                             return defaultMessageHook(ipmiRaw);
764                             break;
765                     }
766                     break;
767                 }
768                 case BIOSEventTypes::reservedF0:
769                 {
770                     switch (selData.offset)
771                     {
772                         case 0x01:
773                             messageID += ".BIOSRecoveryComplete";
774                             break;
775                         default:
776                             return defaultMessageHook(ipmiRaw);
777                             break;
778                     }
779                     break;
780                 }
781                 default:
782                     return defaultMessageHook(ipmiRaw);
783                     break;
784             }
785             break;
786         case BIOSSMISensors::adddcError:
787             switch (eventType)
788             {
789                 case BIOSEventTypes::reservedA0:
790                 {
791                     messageID += ".ADDDCCorrectable";
792 
793                     // Get the message data from eventData2 and eventData3
794 
795                     // dimm = eventData2 bits [7:4]
796                     int dimm = selData.eventData2 >> 4 & 0x0F;
797                     // rank = eventData2 bits [3:0]
798                     int rank = selData.eventData2 & 0x0F;
799 
800                     // Socket ID = eventData3 bits [7:4]
801                     int socket = selData.eventData3 >> 4 & 0x0F;
802                     // Channel = eventData3 bits [3:0]
803                     int channel = selData.eventData3 & 0x0F;
804                     char channelLetter[4] = {'A'};
805                     channelLetter[0] += channel;
806 
807                     // Save the messageArgs
808                     messageArgs.push_back(std::to_string(socket + 1));
809                     messageArgs.push_back(std::string(channelLetter));
810                     messageArgs.push_back(std::to_string(dimm));
811                     messageArgs.push_back(std::to_string(rank));
812 
813                     break;
814                 }
815                 default:
816                     return defaultMessageHook(ipmiRaw);
817                     break;
818             }
819             break;
820         default:
821             return defaultMessageHook(ipmiRaw);
822             break;
823     }
824 
825     // Log the Redfish message to the journal with the appropriate metadata
826     std::string journalMsg = "BIOS SMI IPMI event: " + ipmiRaw;
827     std::string messageArgsString = boost::algorithm::join(messageArgs, ",");
828     phosphor::logging::log<phosphor::logging::level::INFO>(
829         journalMsg.c_str(),
830         phosphor::logging::entry("REDFISH_MESSAGE_ID=%s", messageID.c_str()),
831         phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s",
832                                  messageArgsString.c_str()));
833 
834     return true;
835 }
836 
startRedfishHook(const SELData & selData,const std::string & ipmiRaw)837 static bool startRedfishHook(const SELData& selData, const std::string& ipmiRaw)
838 {
839     uint8_t generatorIDLowByte = static_cast<uint8_t>(selData.generatorID);
840     // Generator ID is 7 bit and LS Bit contains '1' or '0' depending on the
841     // source. Refer IPMI SPEC, Table 32, SEL Event Records.
842     switch (generatorIDLowByte)
843     {
844         case 0x01: // Check if this message is from the BIOS Generator ID
845             // Let the BIOS hook handle this request
846             return biosMessageHook(selData, ipmiRaw);
847             break;
848 
849         case 0x33: // Check if this message is from the BIOS SMI Generator ID
850             // Let the BIOS SMI hook handle this request
851             return biosSMIMessageHook(selData, ipmiRaw);
852             break;
853 
854         case 0x2C: // Message from Intel ME
855             return me::messageHook(selData, ipmiRaw);
856             break;
857     }
858 
859     // No hooks handled the request, so let it go to default
860     return defaultMessageHook(ipmiRaw);
861 }
862 } // namespace redfish_hooks
863 
checkRedfishHooks(uint16_t recordID,uint8_t recordType,uint32_t timestamp,uint16_t generatorID,uint8_t evmRev,uint8_t sensorType,uint8_t sensorNum,uint8_t eventType,uint8_t eventData1,uint8_t eventData2,uint8_t eventData3)864 bool checkRedfishHooks(uint16_t recordID, uint8_t recordType,
865                        uint32_t timestamp, uint16_t generatorID, uint8_t evmRev,
866                        uint8_t sensorType, uint8_t sensorNum, uint8_t eventType,
867                        uint8_t eventData1, uint8_t eventData2,
868                        uint8_t eventData3)
869 {
870     // Save the raw IPMI string of the request
871     std::string ipmiRaw;
872     std::array selBytes = {
873         static_cast<uint8_t>(recordID),
874         static_cast<uint8_t>(recordID >> 8),
875         recordType,
876         static_cast<uint8_t>(timestamp),
877         static_cast<uint8_t>(timestamp >> 8),
878         static_cast<uint8_t>(timestamp >> 16),
879         static_cast<uint8_t>(timestamp >> 24),
880         static_cast<uint8_t>(generatorID),
881         static_cast<uint8_t>(generatorID >> 8),
882         evmRev,
883         sensorType,
884         sensorNum,
885         eventType,
886         eventData1,
887         eventData2,
888         eventData3};
889     redfish_hooks::toHexStr(boost::beast::span<uint8_t>(selBytes), ipmiRaw);
890 
891     // First check that this is a system event record type since that
892     // determines the definition of the rest of the data
893     if (recordType != ipmi::sel::systemEvent)
894     {
895         // OEM record type, so let it go to the SEL
896         return redfish_hooks::defaultMessageHook(ipmiRaw);
897     }
898 
899     // Extract the SEL data for the hook
900     redfish_hooks::SELData selData = {
901         .generatorID = generatorID,
902         .sensorNum = sensorNum,
903         .eventType = eventType,
904         .offset = eventData1 & 0x0F,
905         .eventData2 = eventData2,
906         .eventData3 = eventData3};
907 
908     return redfish_hooks::startRedfishHook(selData, ipmiRaw);
909 }
910 
checkRedfishHooks(uint16_t generatorID,uint8_t evmRev,uint8_t sensorType,uint8_t sensorNum,uint8_t eventType,uint8_t eventData1,uint8_t eventData2,uint8_t eventData3)911 bool checkRedfishHooks(uint16_t generatorID, uint8_t evmRev, uint8_t sensorType,
912                        uint8_t sensorNum, uint8_t eventType, uint8_t eventData1,
913                        uint8_t eventData2, uint8_t eventData3)
914 {
915     // Save the raw IPMI string of the selData
916     std::string ipmiRaw;
917     std::array selBytes = {
918         static_cast<uint8_t>(generatorID),
919         static_cast<uint8_t>(generatorID >> 8),
920         evmRev,
921         sensorType,
922         sensorNum,
923         eventType,
924         eventData1,
925         eventData2,
926         eventData3};
927     redfish_hooks::toHexStr(boost::beast::span<uint8_t>(selBytes), ipmiRaw);
928 
929     // Extract the SEL data for the hook
930     redfish_hooks::SELData selData = {
931         .generatorID = generatorID,
932         .sensorNum = sensorNum,
933         .eventType = eventType,
934         .offset = eventData1 & 0x0F,
935         .eventData2 = eventData2,
936         .eventData3 = eventData3};
937 
938     return redfish_hooks::startRedfishHook(selData, ipmiRaw);
939 }
940 
941 } // namespace intel_oem::ipmi::sel
942