blob: 500cf6e86c12a7cba53bf60d139d5121e861031f [file] [log] [blame] [edit]
#pragma once
#include "guid.hpp"
#include <array>
#include <cstddef>
#include <cstdint>
#include <cstring>
// UEFI CPER specification defined here,
// https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.html#common-platform-error-record-cper
namespace uefi::cper
{
constexpr size_t kRecordSignatureSize = 0x4;
constexpr std::array<uint8_t, kRecordSignatureSize> kRecordSignature = {
'C', 'P', 'E', 'R'};
constexpr uint16_t kRecordRevision = 0x0000;
constexpr uint32_t kRecordSignatureEnd = 0xFFFFFFFF;
enum class ErrorSeverity : uint8_t
{
kRecoverable = 0,
kFatal = 1,
kCorrected = 2,
kInformational = 3,
};
namespace notification_type
{
constexpr guid_t kCMC(0x2DCE8BB1, 0xBDD7, 0x450E,
{0xB9, 0xAD, 0x9C, 0xF4, 0xEB, 0xD4, 0xF8, 0x90});
constexpr guid_t kCPE(0x4E292F96, 0xD843, 0x4A55,
{0xA8, 0xC2, 0xD4, 0x81, 0xF2, 0x7E, 0xBE, 0xEE});
constexpr guid_t kMCE(0xE8F56FFE, 0x919C, 0x4CC5,
{0xBA, 0x88, 0x65, 0xAB, 0xE1, 0x49, 0x13, 0xBB});
constexpr guid_t kPCIE(0xCF93C01F, 0x1A16, 0x4DFC,
{0xB8, 0xBC, 0x9C, 0x4D, 0xAF, 0x67, 0xC1, 0x04});
constexpr guid_t kINIT(0xCC5263E8, 0x9308, 0x454A,
{0x89, 0xD0, 0x34, 0x0B, 0xD3, 0x9B, 0xC9, 0x8E});
constexpr guid_t kNMI(0x5BAD89FF, 0xB7E6, 0x42C9,
{0x81, 0x4A, 0xCF, 0x24, 0x85, 0xD6, 0xE9, 0x8A});
constexpr guid_t kBOOT(0x3D61A466, 0xAB40, 0x409A,
{0xA6, 0x98, 0xF3, 0x62, 0xD4, 0x64, 0xB3, 0x8F});
constexpr guid_t kDMAR(0x667DD791, 0xC6B3, 0x4C27,
{0x8A, 0x6B, 0x0F, 0x8E, 0x72, 0x2D, 0xEB, 0x41});
constexpr guid_t kSEA(0x9A78788A, 0xBBE8, 0x11E4,
{0x80, 0x9E, 0x67, 0x61, 0x1E, 0x5D, 0x46, 0xB0});
constexpr guid_t kSEI(0x5C284C81, 0xB0AE, 0x4E87,
{0xA3, 0x22, 0xB0, 0x4C, 0x85, 0x62, 0x43, 0x23});
constexpr guid_t kPEI(0x09A9D5AC, 0x5204, 0x4214,
{0x96, 0xE5, 0x94, 0x99, 0x2E, 0x75, 0x2B, 0xCD});
constexpr guid_t kCXL(0x69293BC9, 0x41DF, 0x49A3,
{0xB4, 0xBD, 0x4F, 0xB0, 0xDB, 0x30, 0x41, 0xF6});
} // namespace notification_type
namespace section_type
{
constexpr guid_t kProcessorGeneric(0x9876CCAD, 0x47B4, 0x4BDB,
{0xB6, 0x5E, 0x16, 0xF1, 0x93, 0xC4, 0xF3,
0xDB});
constexpr guid_t kIA32(0xDC3EA0B0, 0xA144, 0x4797,
{0xB9, 0x5B, 0x53, 0xFA, 0x24, 0x2B, 0x6E, 0x1D});
constexpr guid_t kIPF(0xE429FAF1, 0x3CB7, 0x11D4,
{0x0B, 0xCA, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81});
constexpr guid_t kARM(0xE19E3D16, 0xBC11, 0x11E4,
{0x9C, 0xAA, 0xC2, 0x05, 0x1D, 0x5D, 0x46, 0xB0});
constexpr guid_t kPlatformMemory(0xA5BC1114, 0x6F64, 0x4EDE,
{0xB8, 0x63, 0x3E, 0x83, 0xED, 0x7C, 0x83,
0xB1});
constexpr guid_t kPCIE(0xD995E954, 0xBBC1, 0x430F,
{0xAD, 0x91, 0xB4, 0x4D, 0xCB, 0x3C, 0x6F, 0x35});
constexpr guid_t kFWError(0x81212A96, 0x09ED, 0x4996,
{0x94, 0x71, 0x8D, 0x72, 0x9C, 0x8E, 0x69, 0xED});
constexpr guid_t kPCIBus(0xC5753963, 0x3B84, 0x4095,
{0xBF, 0x78, 0xED, 0xDA, 0xD3, 0xF9, 0xC9, 0xDD});
constexpr guid_t kPCIDevice(0xEB5E4685, 0xCA66, 0x4769,
{0xB6, 0xA2, 0x26, 0x06, 0x8B, 0x00, 0x13, 0x26});
constexpr guid_t kDMARGeneric(0x5B51FEF7, 0xC79D, 0x4434,
{0x8F, 0x1B, 0xAA, 0x62, 0xDE, 0x3E, 0x2C, 0x64});
constexpr guid_t kIntelVt(0x71761D37, 0x32B2, 0x45CD,
{0xA7, 0xD0, 0xB0, 0xFE, 0xDD, 0x93, 0xE8, 0xCF});
constexpr guid_t kIOMMU(0x036F84E1, 0x7F37, 0x428C,
{0xA7, 0x9E, 0x57, 0x5F, 0xDF, 0xAA, 0x84, 0xEC});
} // namespace section_type
namespace record_flags
{
constexpr uint32_t kRecovered = 0x1;
constexpr uint32_t kPrevError = 0x2;
constexpr uint32_t kSimulated = 0x4;
}; // namespace record_flags
namespace section_flags
{
constexpr uint32_t kPrimary = (0x1 << 0);
constexpr uint32_t kContainmentWarning = (0x1 << 1);
constexpr uint32_t kReset = (0x1 << 2);
constexpr uint32_t kErrorThresholdExceeded = (0x1 << 3);
constexpr uint32_t kResourceNotAccessable = (0x1 << 4);
constexpr uint32_t kLatentError = (0x1 << 5);
constexpr uint32_t kPropagated = (0x1 << 6);
constexpr uint32_t kOverflow = (0x1 << 7);
} // namespace section_flags
struct __attribute__((packed)) Timestamp
{
uint8_t seconds;
uint8_t minutes;
uint8_t hours;
uint8_t isPrecise;
uint8_t day;
uint8_t month;
uint8_t year;
uint8_t century;
};
struct __attribute__((packed)) RecordHeader
{
std::array<uint8_t, kRecordSignatureSize> signature;
uint16_t revision;
uint32_t signatureEnd;
uint16_t sectionCount;
uint32_t errorSeverity;
uint32_t validationBits;
uint32_t recordLength;
uint64_t timestamp;
guid_t platformId;
guid_t partitionId;
guid_t creatorId;
guid_t notificationType;
uint64_t recordId;
uint32_t flags;
uint64_t persistenceInformation;
std::array<uint8_t, 12> reserved;
RecordHeader() :
signature(kRecordSignature), revision(kRecordRevision),
signatureEnd(kRecordSignatureEnd), reserved({0})
{}
RecordHeader(const uint16_t sectionCountIn, const uint32_t errorSeverityIn,
const uint32_t validationBitsIn, const uint32_t recordLengthIn,
const uint64_t timestampIn, const guid_t platformIdIn,
const guid_t partitionIdIn, const guid_t creatorIdIn,
const guid_t notificationTypeIn, uint64_t recordIdIn,
const uint32_t flagsIn,
const uint64_t setPersistenceInformationIn) :
signature(kRecordSignature), revision(kRecordRevision),
signatureEnd(kRecordSignatureEnd), sectionCount(sectionCountIn),
errorSeverity(errorSeverityIn), validationBits(validationBitsIn),
recordLength(recordLengthIn), timestamp(timestampIn),
platformId(platformIdIn), partitionId(partitionIdIn),
creatorId(creatorIdIn), notificationType(notificationTypeIn),
recordId(recordIdIn), flags(flagsIn),
persistenceInformation(setPersistenceInformationIn), reserved({0})
{}
};
constexpr uint64_t kRecordHeaderSizeBytes = sizeof(RecordHeader);
// Ensure the compiler packs the RecordHeader correctly.
static_assert(offsetof(RecordHeader, signature) == 0,
"Incorrect signature offset");
static_assert(offsetof(RecordHeader, revision) == 4,
"Incorrect revision offset");
static_assert(offsetof(RecordHeader, signatureEnd) == 6,
"Incorrect signatureEnd offset");
static_assert(offsetof(RecordHeader, sectionCount) == 10,
"Incorrect sectionCounter offset");
static_assert(offsetof(RecordHeader, errorSeverity) == 12,
"Incorrect errorSeverity offset");
static_assert(offsetof(RecordHeader, validationBits) == 16,
"Incorrect validationBits offset");
static_assert(offsetof(RecordHeader, recordLength) == 20,
"Incorrect recordLength offset");
static_assert(offsetof(RecordHeader, timestamp) == 24,
"Incorrect timestamp offset");
static_assert(offsetof(RecordHeader, platformId) == 32,
"Incorrect platformId offset");
static_assert(offsetof(RecordHeader, partitionId) == 48,
"Incorrect partitionId offset");
static_assert(offsetof(RecordHeader, creatorId) == 64,
"Incorrect creatorId offset");
static_assert(offsetof(RecordHeader, notificationType) == 80,
"Incorrect notificationType offset");
static_assert(offsetof(RecordHeader, recordId) == 96,
"Incorrect recordId offset");
static_assert(offsetof(RecordHeader, flags) == 104, "Incorrect flags offset");
static_assert(offsetof(RecordHeader, persistenceInformation) == 108,
"Incorrect persistenceInformation offset");
static_assert(offsetof(RecordHeader, reserved) == 116,
"Incorrect reserved offset");
struct __attribute__((packed)) SectionDescriptor
{
uint32_t sectionOffset;
uint32_t sectionLength;
uint16_t revision;
uint8_t validationBits;
uint8_t reserved;
uint32_t flags;
guid_t sectionType;
guid_t fruId;
uint32_t sectionSeverity;
std::array<uint8_t, 20> fruText;
SectionDescriptor() = default;
SectionDescriptor(const uint32_t sectionOffsetIn,
const uint32_t sectionLengthIn, const uint16_t revisionIn,
const uint8_t validationBitsIn, const uint32_t flagsIn,
const guid_t sectionTypeIn, const guid_t fruIdIn,
const uint32_t sectionSeverityIn,
const std::array<uint8_t, 20> fruTextIn) :
sectionOffset(sectionOffsetIn), sectionLength(sectionLengthIn),
revision(revisionIn), validationBits(validationBitsIn), reserved(0),
flags(flagsIn), sectionType(sectionTypeIn), fruId(fruIdIn),
sectionSeverity(sectionSeverityIn), fruText(fruTextIn)
{}
};
constexpr uint64_t kSectionDescriptorSizeBytes = sizeof(SectionDescriptor);
// Ensure the compiler packs the SectionDescriptor correctly.
static_assert(offsetof(SectionDescriptor, sectionOffset) == 0,
"Incorrect sectionOffset offset");
static_assert(offsetof(SectionDescriptor, sectionLength) == 4,
"Incorrect sectionLength offset");
static_assert(offsetof(SectionDescriptor, revision) == 8,
"Incorrect revision offset");
static_assert(offsetof(SectionDescriptor, validationBits) == 10,
"Incorrect validationBits offset");
static_assert(offsetof(SectionDescriptor, reserved) == 11,
"Incorrect reserved offset");
static_assert(offsetof(SectionDescriptor, flags) == 12,
"Incorrect flags offset");
static_assert(offsetof(SectionDescriptor, sectionType) == 16,
"Incorrect sectionType offset");
static_assert(offsetof(SectionDescriptor, fruId) == 32,
"Incorrect fruId offset");
static_assert(offsetof(SectionDescriptor, sectionSeverity) == 48,
"Incorrect sectionSeverity offset");
static_assert(offsetof(SectionDescriptor, fruText) == 52,
"Incorrect fruText offset");
} // namespace uefi::cper