Skip to content

Commit 72c8aa0

Browse files
dcao-ampereThuBaNguyen
authored andcommitted
oem-ampere: eventManager: Add CPER Event class handler
Add Ampere OEM CPER event handler to decode CPER data to get TypeID and SubTypeID. Then logs those info to Ampere IPMI OEM sel logs. Change-Id: I4ff1cd3c0ba8a2471afb1c8ee61a8caaf30596b8 Signed-off-by: Dung Cao <[email protected]> Signed-off-by: Thu Nguyen <[email protected]>
1 parent 6dce7d1 commit 72c8aa0

File tree

8 files changed

+372
-14
lines changed

8 files changed

+372
-14
lines changed

meson.build

+8-6
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,6 @@ conf_data.set(
138138
)
139139
conf_data.set('SENSOR_POLLING_TIME', get_option('sensor-polling-time'))
140140

141-
oem_files = []
142-
if get_option('oem-ampere').enabled()
143-
add_project_arguments('-DOEM_AMPERE', language : 'cpp')
144-
subdir('oem/ampere')
145-
endif
146-
147141
configure_file(output: 'config.h', configuration: conf_data)
148142

149143
add_project_arguments(
@@ -197,6 +191,9 @@ libpldm_dep = dependency(
197191
include_type: 'system',
198192
)
199193

194+
if get_option('oem-ampere').enabled()
195+
add_project_arguments('-DOEM_AMPERE', language : 'cpp')
196+
endif
200197

201198
libpldmutils_headers = ['.']
202199
libpldmutils = library(
@@ -231,6 +228,11 @@ deps = [
231228
stdplus,
232229
]
233230

231+
oem_files = []
232+
if get_option('oem-ampere').enabled()
233+
subdir('oem/ampere')
234+
endif
235+
234236
if get_option('libpldmresponder').allowed()
235237
subdir('libpldmresponder')
236238
deps += [libpldmresponder_dep]

oem/ampere/event/cper.cpp

+258
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
#include "cper.hpp"
2+
3+
#include "libcper/Cper.h"
4+
5+
#include "common/utils.hpp"
6+
7+
#include <phosphor-logging/lg2.hpp>
8+
9+
#include <cstring>
10+
#include <ranges>
11+
#include <vector>
12+
13+
PHOSPHOR_LOG2_USING;
14+
15+
namespace pldm
16+
{
17+
namespace oem_ampere
18+
{
19+
20+
// Returns one if two EFI GUIDs are equal, zero otherwise.
21+
int guid_equal(EFI_GUID* a, EFI_GUID* b)
22+
{
23+
// Check top base 3 components.
24+
if (a->Data1 != b->Data1 || a->Data2 != b->Data2 || a->Data3 != b->Data3)
25+
{
26+
return 0;
27+
}
28+
29+
// Check Data4 array for equality.
30+
for (int i = 0; i < 8; i++)
31+
{
32+
if (a->Data4[i] != b->Data4[i])
33+
{
34+
return 0;
35+
}
36+
}
37+
38+
return 1;
39+
}
40+
41+
static void decodeSecAmpere(void* section, EFI_AMPERE_ERROR_DATA* ampSpecHdr)
42+
{
43+
std::memcpy(ampSpecHdr, section, sizeof(EFI_AMPERE_ERROR_DATA));
44+
}
45+
46+
static void decodeSecArm(void* section, EFI_AMPERE_ERROR_DATA* ampSpecHdr)
47+
{
48+
int len;
49+
EFI_ARM_ERROR_RECORD* proc;
50+
EFI_ARM_ERROR_INFORMATION_ENTRY* errInfo;
51+
EFI_ARM_CONTEXT_INFORMATION_HEADER* ctxInfo;
52+
53+
proc = reinterpret_cast<EFI_ARM_ERROR_RECORD*>(section);
54+
errInfo = reinterpret_cast<EFI_ARM_ERROR_INFORMATION_ENTRY*>(proc + 1);
55+
56+
len = proc->SectionLength -
57+
(sizeof(EFI_ARM_ERROR_RECORD) +
58+
proc->ErrInfoNum * (sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY)));
59+
if (len < 0)
60+
{
61+
lg2::error("Section length is too small, section_length {LENGTH}",
62+
"LENGTH", static_cast<int>(proc->SectionLength));
63+
return;
64+
}
65+
66+
ctxInfo = reinterpret_cast<EFI_ARM_CONTEXT_INFORMATION_HEADER*>(
67+
errInfo + proc->ErrInfoNum);
68+
69+
for ([[maybe_unused]] const auto& i :
70+
std::views::iota(0, static_cast<int>(proc->ContextInfoNum)))
71+
{
72+
int size = sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER) +
73+
ctxInfo->RegisterArraySize;
74+
len -= size;
75+
ctxInfo = reinterpret_cast<EFI_ARM_CONTEXT_INFORMATION_HEADER*>(
76+
(long)ctxInfo + size);
77+
}
78+
79+
if (len > 0)
80+
{
81+
/* Get Ampere Specific header data */
82+
std::memcpy(ampSpecHdr, (void*)ctxInfo, sizeof(EFI_AMPERE_ERROR_DATA));
83+
}
84+
}
85+
86+
static void decodeSecPlatformMemory(void* section,
87+
EFI_AMPERE_ERROR_DATA* ampSpecHdr)
88+
{
89+
EFI_PLATFORM_MEMORY_ERROR_DATA* mem =
90+
reinterpret_cast<EFI_PLATFORM_MEMORY_ERROR_DATA*>(section);
91+
if (mem->ErrorType == MEM_ERROR_TYPE_PARITY)
92+
{
93+
/* IP Type from bit 0 to 11 of TypeId */
94+
ampSpecHdr->TypeId = (ampSpecHdr->TypeId & 0xf800) + ERROR_TYPE_ID_MCU;
95+
ampSpecHdr->SubtypeId = SUBTYPE_ID_PARITY;
96+
}
97+
}
98+
99+
static void decodeSecPcie(void* section, EFI_AMPERE_ERROR_DATA* ampSpecHdr)
100+
{
101+
EFI_PCIE_ERROR_DATA* pcieErr =
102+
reinterpret_cast<EFI_PCIE_ERROR_DATA*>(section);
103+
if (pcieErr->ValidFields & CPER_PCIE_VALID_PORT_TYPE)
104+
{
105+
if (pcieErr->PortType == CPER_PCIE_PORT_TYPE_ROOT_PORT)
106+
{
107+
ampSpecHdr->SubtypeId = ERROR_SUBTYPE_PCIE_AER_ROOT_PORT;
108+
}
109+
else
110+
{
111+
ampSpecHdr->SubtypeId = ERROR_SUBTYPE_PCIE_AER_DEVICE;
112+
}
113+
}
114+
}
115+
116+
static void decodeCperSection(const uint8_t* data, long basePos,
117+
EFI_AMPERE_ERROR_DATA* ampSpecHdr,
118+
EFI_ERROR_SECTION_DESCRIPTOR* secDesc)
119+
{
120+
long pos = basePos + secDesc->SectionOffset;
121+
char* section = new char[secDesc->SectionLength];
122+
std::memcpy(section, &data[pos], secDesc->SectionLength);
123+
pos += secDesc->SectionLength;
124+
EFI_GUID* ptr = reinterpret_cast<EFI_GUID*>(&secDesc->SectionType);
125+
if (guid_equal(ptr, &gEfiAmpereErrorSectionGuid))
126+
{
127+
lg2::info("RAS Section Type : Ampere Specific");
128+
decodeSecAmpere(section, ampSpecHdr);
129+
}
130+
else if (guid_equal(ptr, &gEfiArmProcessorErrorSectionGuid))
131+
{
132+
lg2::info("RAS Section Type : ARM");
133+
decodeSecArm(section, ampSpecHdr);
134+
}
135+
else if (guid_equal(ptr, &gEfiPlatformMemoryErrorSectionGuid))
136+
{
137+
lg2::info("RAS Section Type : Memory");
138+
decodeSecPlatformMemory(section, ampSpecHdr);
139+
}
140+
else if (guid_equal(ptr, &gEfiPcieErrorSectionGuid))
141+
{
142+
lg2::info("RAS Section Type : PCIE");
143+
decodeSecPcie(section, ampSpecHdr);
144+
}
145+
else
146+
{
147+
lg2::error("Section Type is not supported");
148+
}
149+
150+
delete[] section;
151+
}
152+
153+
void decodeCperRecord(const uint8_t* data, size_t /* eventDataSize */,
154+
EFI_AMPERE_ERROR_DATA* ampSpecHdr)
155+
{
156+
EFI_COMMON_ERROR_RECORD_HEADER cperHeader;
157+
long pos = sizeof(CommonEventData);
158+
long basePos = sizeof(CommonEventData);
159+
160+
std::memcpy(&cperHeader, &data[pos],
161+
sizeof(EFI_COMMON_ERROR_RECORD_HEADER));
162+
pos += sizeof(EFI_COMMON_ERROR_RECORD_HEADER);
163+
164+
EFI_ERROR_SECTION_DESCRIPTOR* secDesc =
165+
new EFI_ERROR_SECTION_DESCRIPTOR[cperHeader.SectionCount];
166+
for ([[maybe_unused]] const auto& i :
167+
std::views::iota(0, static_cast<int>(cperHeader.SectionCount)))
168+
{
169+
std::memcpy(&secDesc[i], &data[pos],
170+
sizeof(EFI_ERROR_SECTION_DESCRIPTOR));
171+
pos += sizeof(EFI_ERROR_SECTION_DESCRIPTOR);
172+
}
173+
174+
for ([[maybe_unused]] const auto& i :
175+
std::views::iota(0, static_cast<int>(cperHeader.SectionCount)))
176+
{
177+
decodeCperSection(data, basePos, ampSpecHdr, &secDesc[i]);
178+
}
179+
180+
delete[] secDesc;
181+
}
182+
183+
void addCperSELLog(pldm_tid_t tid, uint16_t eventID, EFI_AMPERE_ERROR_DATA* p)
184+
{
185+
std::vector<uint8_t> evtData;
186+
std::string message = "PLDM RAS SEL Event";
187+
uint8_t recordType;
188+
uint8_t evtData1, evtData2, evtData3, evtData4, evtData5, evtData6;
189+
uint8_t socket;
190+
191+
/*
192+
* OEM IPMI SEL Recode Format for RAS event:
193+
* evtData1:
194+
* Bit [7:4]: eventClass
195+
* 0xF: oemEvent for RAS
196+
* Bit [3:1]: Reserved
197+
* Bit 0: SocketID
198+
* 0x0: Socket 0 0x1: Socket 1
199+
* evtData2:
200+
* Event ID, indicates RAS PLDM sensor ID.
201+
* evtData3:
202+
* Error Type ID high byte - Bit [15:8]
203+
* evtData4:
204+
* Error Type ID low byte - Bit [7:0]
205+
* evtData5:
206+
* Error Sub Type ID high byte
207+
* evtData6:
208+
* Error Sub Type ID low byte
209+
*/
210+
socket = (tid == 1) ? 0 : 1;
211+
recordType = 0xD0;
212+
evtData1 = SENSOR_TYPE_OEM | socket;
213+
evtData2 = eventID;
214+
evtData3 = p->TypeId >> 8;
215+
evtData4 = p->TypeId;
216+
evtData5 = p->SubtypeId >> 8;
217+
evtData6 = p->SubtypeId;
218+
/*
219+
* OEM data bytes
220+
* Ampere IANA: 3 bytes [0x3a 0xcd 0x00]
221+
* event data: 9 bytes [evtData1 evtData2 evtData3
222+
* evtData4 evtData5 evtData6
223+
* 0x00 0x00 0x00 ]
224+
* sel type: 1 byte [0xC0]
225+
*/
226+
evtData.push_back(0x3a);
227+
evtData.push_back(0xcd);
228+
evtData.push_back(0);
229+
evtData.push_back(evtData1);
230+
evtData.push_back(evtData2);
231+
evtData.push_back(evtData3);
232+
evtData.push_back(evtData4);
233+
evtData.push_back(evtData5);
234+
evtData.push_back(evtData6);
235+
evtData.push_back(0);
236+
evtData.push_back(0);
237+
evtData.push_back(0);
238+
auto& bus = pldm::utils::DBusHandler::getBus();
239+
try
240+
{
241+
auto method =
242+
bus.new_method_call(logBusName, logPath, logIntf, "IpmiSelAddOem");
243+
method.append(message, evtData, recordType);
244+
245+
auto selReply = bus.call(method);
246+
if (selReply.is_method_error())
247+
{
248+
lg2::error("addCperSELLog: add SEL log error");
249+
}
250+
}
251+
catch (const std::exception& e)
252+
{
253+
lg2::error("call addCperSELLog error - {ERROR}", "ERROR", e);
254+
}
255+
}
256+
257+
} // namespace oem_ampere
258+
} // namespace pldm

oem/ampere/event/cper.hpp

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include "libcper/Cper.h"
2+
3+
#include <stdint.h>
4+
#include <stdio.h>
5+
#include <unistd.h>
6+
7+
#include <fstream>
8+
#include <vector>
9+
10+
namespace pldm
11+
{
12+
namespace oem_ampere
13+
{
14+
constexpr auto logBusName = "xyz.openbmc_project.Logging.IPMI";
15+
constexpr auto logPath = "/xyz/openbmc_project/Logging/IPMI";
16+
constexpr auto logIntf = "xyz.openbmc_project.Logging.IPMI";
17+
#define SENSOR_TYPE_OEM 0xF0
18+
19+
/* Memory definitions */
20+
#define MEM_ERROR_TYPE_PARITY 8
21+
#define ERROR_TYPE_ID_MCU 1
22+
#define SUBTYPE_ID_PARITY 9
23+
24+
/* PCIe definitions */
25+
#define ERROR_SUBTYPE_PCIE_AER_ROOT_PORT 0
26+
#define ERROR_SUBTYPE_PCIE_AER_DEVICE 1
27+
#define CPER_PCIE_VALID_PORT_TYPE 0x0001
28+
#define CPER_PCIE_PORT_TYPE_ROOT_PORT 4
29+
30+
typedef struct
31+
{
32+
uint8_t formatVersion;
33+
uint8_t formatType;
34+
uint16_t length;
35+
} __attribute__((packed)) CommonEventData;
36+
37+
void decodeCperRecord(const uint8_t* data, size_t eventDataSize,
38+
EFI_AMPERE_ERROR_DATA* ampSpecHdr);
39+
void addCperSELLog(uint8_t TID, uint16_t eventID, EFI_AMPERE_ERROR_DATA* p);
40+
41+
} // namespace oem_ampere
42+
} // namespace pldm

oem/ampere/event/meson.build

+7-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,7 @@
1-
oem_files += files('oem_event_manager.cpp',)
1+
oem_files += files(
2+
'oem_event_manager.cpp',
3+
'cper.cpp',
4+
)
5+
6+
libcper_dep = dependency('libcper', include_type: 'system')
7+
deps += [libcper_dep]

oem/ampere/event/oem_event_manager.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
#include "oem_event_manager.hpp"
22

3+
#include "libcper/Cper.h"
4+
5+
#include "cper.hpp"
36
#include "requester/handler.hpp"
47
#include "requester/request.hpp"
58

@@ -905,5 +908,18 @@ void OemEventManager::handleNumericWatchdogEvent(
905908
sendJournalRedfish(description, logLevel);
906909
}
907910

911+
int OemEventManager::processOemMsgPollEvent(pldm_tid_t tid, uint16_t eventId,
912+
const uint8_t* eventData,
913+
size_t eventDataSize)
914+
{
915+
EFI_AMPERE_ERROR_DATA ampHdr;
916+
917+
decodeCperRecord(eventData, eventDataSize, &ampHdr);
918+
919+
addCperSELLog(tid, eventId, &ampHdr);
920+
921+
return PLDM_SUCCESS;
922+
}
923+
908924
} // namespace oem_ampere
909925
} // namespace pldm

oem/ampere/event/oem_event_manager.hpp

+12
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,18 @@ class OemEventManager
253253
uint8_t /* formatVersion */, pldm_tid_t tid,
254254
size_t eventDataOffset);
255255

256+
/** @brief Handle the polled CPER (0x07, 0xFA) event class.
257+
*
258+
* @param[in] tid - terminus ID
259+
* @param[out] eventId - Event ID
260+
* @param[in] eventData - event data
261+
* @param[in] eventDataSize - size of event data
262+
*
263+
* @return int - PLDM completion code
264+
*/
265+
int processOemMsgPollEvent(pldm_tid_t tid, uint16_t eventId,
266+
const uint8_t* eventData, size_t eventDataSize);
267+
256268
protected:
257269
/** @brief Create prefix string for logging message.
258270
*

0 commit comments

Comments
 (0)