| #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 |