diff --git a/shared/source/device_binary_format/device_binary_format_zebin.cpp b/shared/source/device_binary_format/device_binary_format_zebin.cpp index 55295b0564..df8501b842 100644 --- a/shared/source/device_binary_format/device_binary_format_zebin.cpp +++ b/shared/source/device_binary_format/device_binary_format_zebin.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Intel Corporation + * Copyright (C) 2020-2021 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -10,6 +10,7 @@ #include "shared/source/device_binary_format/elf/elf_decoder.h" #include "shared/source/device_binary_format/elf/elf_encoder.h" #include "shared/source/device_binary_format/elf/zebin_elf.h" +#include "shared/source/device_binary_format/zebin_decoder.h" #include "shared/source/program/program_info.h" #include @@ -23,7 +24,8 @@ bool isDeviceBinaryFormat(const ArrayReftype == NEO::Elf::ET_ZEBIN_EXE; + return header->type == NEO::Elf::ET_REL || + header->type == NEO::Elf::ET_ZEBIN_EXE; } template <> @@ -40,14 +42,22 @@ SingleDeviceBinary unpackSingleDeviceBinary(cons return {}; case NEO::Elf::ET_ZEBIN_EXE: break; + case NEO::Elf::ET_REL: + break; } - const auto &flags = reinterpret_cast(elf.elfFileHeader->flags); - bool validForTarget = flags.machineEntryUsesGfxCoreInsteadOfProductFamily + bool validForTarget = true; + if (elf.elfFileHeader->machine == Elf::ELF_MACHINE::EM_INTELGT) { + validForTarget &= validateTargetDevice(elf, requestedTargetDevice); + } else { + const auto &flags = reinterpret_cast(elf.elfFileHeader->flags); + validForTarget &= flags.machineEntryUsesGfxCoreInsteadOfProductFamily ? (requestedTargetDevice.coreFamily == static_cast(elf.elfFileHeader->machine)) : (requestedTargetDevice.productFamily == static_cast(elf.elfFileHeader->machine)); - validForTarget &= (requestedTargetDevice.maxPointerSizeInBytes == 8U); - validForTarget &= (0 == flags.validateRevisionId) | ((requestedTargetDevice.stepping >= flags.minHwRevisionId) & (requestedTargetDevice.stepping <= flags.maxHwRevisionId)); + validForTarget &= (0 == flags.validateRevisionId) | ((requestedTargetDevice.stepping >= flags.minHwRevisionId) & (requestedTargetDevice.stepping <= flags.maxHwRevisionId)); + validForTarget &= (8U == requestedTargetDevice.maxPointerSizeInBytes); + } + if (false == validForTarget) { outErrReason = "Unhandled target device"; return {}; diff --git a/shared/source/device_binary_format/elf/elf.h b/shared/source/device_binary_format/elf/elf.h index 313c4b397e..b6ef78e0a4 100644 --- a/shared/source/device_binary_format/elf/elf.h +++ b/shared/source/device_binary_format/elf/elf.h @@ -32,7 +32,8 @@ enum ELF_IDENTIFIER_DATA : uint8_t { // Target machine enum ELF_MACHINE : uint16_t { - EM_NONE = 0, // No specific instrution set + EM_NONE = 0, // No specific instruction set + EM_INTELGT = 205, }; // Elf version @@ -315,6 +316,13 @@ struct ElfFileHeader { static_assert(sizeof(ElfFileHeader) == 0x34, ""); static_assert(sizeof(ElfFileHeader) == 0x40, ""); +struct ElfNoteSection { + uint32_t nameSize; + uint32_t descSize; + uint32_t type; +}; +static_assert(sizeof(ElfNoteSection) == 0xC, ""); + template struct ElfSymbolEntryTypes; diff --git a/shared/source/device_binary_format/elf/zebin_elf.h b/shared/source/device_binary_format/elf/zebin_elf.h index 8d741987de..38a93c6d63 100644 --- a/shared/source/device_binary_format/elf/zebin_elf.h +++ b/shared/source/device_binary_format/elf/zebin_elf.h @@ -8,6 +8,7 @@ #pragma once #include "shared/source/device_binary_format/elf/elf.h" +#include "shared/source/device_binary_format/elf/elf_decoder.h" #include "shared/source/utilities/const_stringref.h" #include @@ -40,8 +41,21 @@ static constexpr ConstStringRef spv = ".spv"; static constexpr ConstStringRef debugInfo = ".debug_info"; static constexpr ConstStringRef zeInfo = ".ze_info"; static constexpr ConstStringRef gtpinInfo = ".gtpin_info"; +static constexpr ConstStringRef noteIntelGT = ".note.intelgt.compat"; } // namespace SectionsNamesZebin +static constexpr ConstStringRef IntelGtNoteOwnerName = "IntelGT"; +struct IntelGTNote : ElfNoteSection { + char ownerName[8]; + uint32_t desc; +}; +static_assert(sizeof(IntelGTNote) == 0x18, ""); +enum IntelGTSectionType : uint32_t { + ProductFamily = 1, + GfxCore = 2, + TargetMetadata = 3 +}; + struct ZebinTargetFlags { union { struct { @@ -75,13 +89,57 @@ struct ZebinTargetFlags { uint8_t generatorId : 3; // bit[31:24]: MBZ, reserved for future use - uint8_t reserved : 8; }; uint32_t packed = 0U; }; }; static_assert(sizeof(ZebinTargetFlags) == sizeof(uint32_t), ""); +struct ZebinTargetMetadata { + // bit[7:0]: dedicated for specific generator (meaning based on generatorId) + enum GeneratorSpecificFlags : uint8_t { + NONE = 0 + }; + // bit[22:20]: generator of this device binary + enum GeneratorId : uint8_t { + UNREGISTERED = 0, + IGC = 1 + }; + + union { + struct { + // bit[7:0]: dedicated for specific generator (meaning based on generatorId) + uint8_t generatorSpecificFlags : 8; + + // bit[12:8]: values [0-31], min compatbile device revision Id (stepping) + uint8_t minHwRevisionId : 5; + + // bit[13:13]: + // 0 - full validation during decoding (safer decoding) + // 1 - no validation (faster decoding - recommended for known generators) + bool validateRevisionId : 1; + + // bit[14:14]: + // 0 - ignore minHwRevisionId and maxHwRevisionId + // 1 - underlying device must match specified revisionId info + bool disableExtendedValidation : 1; + + // bit[19:15]: max compatbile device revision Id (stepping) + uint8_t maxHwRevisionId : 5; + + // bit[22:20]: generator of this device binary + // 0 - Unregistered + // 1 - IGC + uint8_t generatorId : 3; + + // bit[31:23]: MBZ, reserved for future use + uint8_t reserved : 8; + }; + uint32_t packed = 0U; + }; +}; +static_assert(sizeof(ZebinTargetMetadata) == sizeof(uint32_t), ""); + namespace ZebinKernelMetadata { namespace Tags { static constexpr ConstStringRef kernels("kernels"); diff --git a/shared/source/device_binary_format/zebin_decoder.cpp b/shared/source/device_binary_format/zebin_decoder.cpp index 348d231297..bfa162d2f4 100644 --- a/shared/source/device_binary_format/zebin_decoder.cpp +++ b/shared/source/device_binary_format/zebin_decoder.cpp @@ -24,6 +24,57 @@ namespace NEO { +bool validateTargetDevice(const Elf::Elf &elf, const TargetDevice &targetDevice) { + GFXCORE_FAMILY gfxCore = IGFX_UNKNOWN_CORE; + PRODUCT_FAMILY productFamily = IGFX_UNKNOWN; + Elf::ZebinTargetMetadata targetMetadata = {}; + auto intelGTNotes = getIntelGTNotes(elf); + for (const auto &intelGTNote : intelGTNotes) { + switch (intelGTNote->type) { + case Elf::IntelGTSectionType::ProductFamily: + productFamily = static_cast(intelGTNote->desc); + break; + case Elf::IntelGTSectionType::GfxCore: + gfxCore = static_cast(intelGTNote->desc); + break; + case Elf::IntelGTSectionType::TargetMetadata: + targetMetadata.packed = intelGTNote->desc; + break; + default: + return false; + } + } + bool validForTarget = (gfxCore != IGFX_UNKNOWN_CORE) | (productFamily != IGFX_UNKNOWN); + validForTarget &= (gfxCore != IGFX_UNKNOWN_CORE) ? targetDevice.coreFamily == gfxCore : true; + validForTarget &= (productFamily != IGFX_UNKNOWN) ? targetDevice.productFamily == productFamily : true; + validForTarget &= (0 == targetMetadata.validateRevisionId) | ((targetDevice.stepping >= targetMetadata.minHwRevisionId) & (targetDevice.stepping <= targetMetadata.maxHwRevisionId)); + validForTarget &= (8U == targetDevice.maxPointerSizeInBytes); + return validForTarget; +} + +std::vector getIntelGTNotes(const Elf::Elf &elf) { + std::vector intelGTNotes; + for (size_t i = 0; i < elf.sectionHeaders.size(); i++) { + auto section = elf.sectionHeaders[i]; + if (Elf::SHT_NOTE == section.header->type && Elf::SectionsNamesZebin::noteIntelGT == elf.getSectionName(static_cast(i))) { + auto numEntries = elf.sectionHeaders[i].header->size / sizeof(Elf::IntelGTNote); + for (uint32_t i = 0; i < numEntries; ++i) { + auto intelGTNote = reinterpret_cast(section.data.begin() + i * sizeof(Elf::IntelGTNote)); + + bool isValidGTNote = sizeof(uint32_t) == intelGTNote->descSize; + isValidGTNote &= Elf::IntelGtNoteOwnerName.size() + 1 == intelGTNote->nameSize; + isValidGTNote &= Elf::IntelGtNoteOwnerName == ConstStringRef(intelGTNote->ownerName); + if (isValidGTNote) { + intelGTNotes.push_back(intelGTNote); + } else { + continue; + } + } + } + } + return intelGTNotes; +} + DecodeError extractZebinSections(NEO::Elf::Elf &elf, ZebinSections &out, std::string &outErrReason, std::string &outWarning) { if ((elf.elfFileHeader->shStrNdx >= elf.sectionHeaders.size()) || (NEO::Elf::SHN_UNDEF == elf.elfFileHeader->shStrNdx)) { outErrReason.append("DeviceBinaryFormat::Zebin : Invalid or missing shStrNdx in elf header\n"); @@ -63,6 +114,13 @@ DecodeError extractZebinSections(NEO::Elf::Elf &elf, ZebinSect case NEO::Elf::SHT_ZEBIN_SPIRV: out.spirvSections.push_back(&elfSectionHeader); break; + case NEO::Elf::SHT_NOTE: + if (sectionName == NEO::Elf::SectionsNamesZebin::noteIntelGT) { + out.noteIntelGTSections.push_back(&elfSectionHeader); + } else { + outWarning.append("DeviceBinaryFormat::Zebin : Unhandled SHT_NOTE section : " + sectionName.str() + " currently supports only : " + NEO::Elf::SectionsNamesZebin::noteIntelGT.str() + ".\n"); + } + break; case NEO::Elf::SHT_STRTAB: // ignoring intentionally - section header names continue; @@ -108,6 +166,7 @@ DecodeError validateZebinSectionsCount(const ZebinSections §ions, std::strin valid &= validateZebinSectionsCountAtMost(sections.constDataSections, NEO::Elf::SectionsNamesZebin::dataConst, 1U, outErrReason, outWarning); valid &= validateZebinSectionsCountAtMost(sections.symtabSections, NEO::Elf::SectionsNamesZebin::symtab, 1U, outErrReason, outWarning); valid &= validateZebinSectionsCountAtMost(sections.spirvSections, NEO::Elf::SectionsNamesZebin::spv, 1U, outErrReason, outWarning); + valid &= validateZebinSectionsCountAtMost(sections.noteIntelGTSections, NEO::Elf::SectionsNamesZebin::noteIntelGT, 1U, outErrReason, outWarning); return valid ? DecodeError::Success : DecodeError::InvalidBinary; } diff --git a/shared/source/device_binary_format/zebin_decoder.h b/shared/source/device_binary_format/zebin_decoder.h index 951270593f..36f20dc58f 100644 --- a/shared/source/device_binary_format/zebin_decoder.h +++ b/shared/source/device_binary_format/zebin_decoder.h @@ -28,6 +28,7 @@ struct ZebinSections { StackVec constDataSections; StackVec symtabSections; StackVec spirvSections; + StackVec noteIntelGTSections; }; using UniqueNode = StackVec; @@ -41,6 +42,9 @@ struct ZeInfoKernelSections { UniqueNode experimentalPropertiesNd; }; +bool validateTargetDevice(const Elf::Elf &elf, const TargetDevice &targetDevice); +std::vector getIntelGTNotes(const Elf::Elf &elf); + DecodeError extractZebinSections(NEO::Elf::Elf &elf, ZebinSections &out, std::string &outErrReason, std::string &outWarning); DecodeError validateZebinSectionsCount(const ZebinSections §ions, std::string &outErrReason, std::string &outWarning); void extractZeInfoKernelSections(const NEO::Yaml::YamlParser &parser, const NEO::Yaml::Node &kernelNd, ZeInfoKernelSections &outZeInfoKernelSections, ConstStringRef context, std::string &outWarning); diff --git a/shared/test/unit_test/device_binary_format/device_binary_format_zebin_tests.cpp b/shared/test/unit_test/device_binary_format/device_binary_format_zebin_tests.cpp index 268cf80d00..88dd907d88 100644 --- a/shared/test/unit_test/device_binary_format/device_binary_format_zebin_tests.cpp +++ b/shared/test/unit_test/device_binary_format/device_binary_format_zebin_tests.cpp @@ -8,16 +8,24 @@ #include "shared/source/device_binary_format/device_binary_formats.h" #include "shared/source/device_binary_format/elf/elf.h" #include "shared/source/device_binary_format/elf/zebin_elf.h" +#include "shared/source/helpers/string.h" #include "shared/source/program/program_info.h" +#include "shared/test/unit_test/device_binary_format/zebin_tests.h" #include "test.h" -TEST(IsDeviceBinaryFormatZebin, GivenValidBinaryThenReturnTrue) { +TEST(IsDeviceBinaryFormatZebin, GivenValidExecutableTypeBinaryThenReturnTrue) { NEO::Elf::ElfFileHeader zebin; zebin.type = NEO::Elf::ET_ZEBIN_EXE; EXPECT_TRUE(NEO::isDeviceBinaryFormat(ArrayRef::fromAny(&zebin, 1U))); } +TEST(IsDeviceBinaryFormatZebin, GivenValidRelocatableTypeBinaryThenReturnTrue) { + NEO::Elf::ElfFileHeader zebin; + zebin.type = NEO::Elf::ET_REL; + EXPECT_TRUE(NEO::isDeviceBinaryFormat(ArrayRef::fromAny(&zebin, 1U))); +} + TEST(IsDeviceBinaryFormatZebin, GivenInvalidBinaryThenReturnFalse) { NEO::Elf::ElfFileHeader someElf; EXPECT_FALSE(NEO::isDeviceBinaryFormat(ArrayRef::fromAny(&someElf, 1U))); @@ -300,3 +308,54 @@ TEST(UnpackSingleDeviceBinaryZebin, WhenRequestedThenValidateRevision) { EXPECT_TRUE(unpackWarnings.empty()); EXPECT_TRUE(unpackErrors.empty()); } + +TEST(UnpackSingleDeviceBinaryZebin, WhenMachineIsIntelGTAndIntelGTNoteSectionIsValidThenReturnSelf) { + ZebinTestData::ValidEmptyProgram zebin; + zebin.elfHeader->type = NEO::Elf::ET_REL; + zebin.elfHeader->machine = NEO::Elf::ELF_MACHINE::EM_INTELGT; + + NEO::TargetDevice targetDevice; + targetDevice.maxPointerSizeInBytes = 8; + targetDevice.productFamily = IGFX_SKYLAKE; + targetDevice.coreFamily = IGFX_GEN9_CORE; + targetDevice.stepping = 6; + + NEO::Elf::IntelGTNote notes[3]; + for (int i = 0; i < 3; ++i) { + notes[i].nameSize = 8; + notes[i].descSize = 4; + strcpy_s(notes[i].ownerName, notes[i].nameSize, NEO::Elf::IntelGtNoteOwnerName.str().c_str()); + } + + notes[0].type = NEO::Elf::IntelGTSectionType::ProductFamily; + notes[0].desc = targetDevice.productFamily; + + notes[1].type = NEO::Elf::IntelGTSectionType::GfxCore; + notes[1].desc = targetDevice.coreFamily; + + NEO::Elf::ZebinTargetMetadata targetMetadata; + targetMetadata.validateRevisionId = true; + targetMetadata.minHwRevisionId = targetDevice.stepping - 1; + targetMetadata.maxHwRevisionId = targetDevice.stepping + 1; + notes[2].type = NEO::Elf::IntelGTSectionType::TargetMetadata; + notes[2].desc = targetMetadata.packed; + + zebin.appendSection(NEO::Elf::SHT_NOTE, NEO::Elf::SectionsNamesZebin::noteIntelGT, ArrayRef::fromAny(notes, 3)); + + std::string unpackErrors; + std::string unpackWarnings; + auto unpackResult = NEO::unpackSingleDeviceBinary(zebin.storage, "", targetDevice, unpackErrors, unpackWarnings); + EXPECT_EQ(NEO::DeviceBinaryFormat::Zebin, unpackResult.format); + EXPECT_EQ(targetDevice.productFamily, unpackResult.targetDevice.productFamily); + EXPECT_EQ(targetDevice.coreFamily, unpackResult.targetDevice.coreFamily); + EXPECT_EQ(targetDevice.stepping, unpackResult.targetDevice.stepping); + EXPECT_EQ(targetDevice.maxPointerSizeInBytes, unpackResult.targetDevice.maxPointerSizeInBytes); + EXPECT_FALSE(unpackResult.deviceBinary.empty()); + EXPECT_EQ(zebin.storage.data(), unpackResult.deviceBinary.begin()); + EXPECT_EQ(zebin.storage.size(), unpackResult.deviceBinary.size()); + EXPECT_TRUE(unpackResult.debugData.empty()); + EXPECT_TRUE(unpackResult.intermediateRepresentation.empty()); + EXPECT_TRUE(unpackResult.buildOptions.empty()); + EXPECT_TRUE(unpackWarnings.empty()); + EXPECT_TRUE(unpackErrors.empty()); +} diff --git a/shared/test/unit_test/device_binary_format/zebin_decoder_tests.cpp b/shared/test/unit_test/device_binary_format/zebin_decoder_tests.cpp index 7864c312e5..43ecef7f9b 100644 --- a/shared/test/unit_test/device_binary_format/zebin_decoder_tests.cpp +++ b/shared/test/unit_test/device_binary_format/zebin_decoder_tests.cpp @@ -5,9 +5,11 @@ * */ +#include "shared/source/device_binary_format/device_binary_formats.h" #include "shared/source/device_binary_format/elf/zebin_elf.h" #include "shared/source/device_binary_format/zebin_decoder.h" #include "shared/source/helpers/ptr_math.h" +#include "shared/source/helpers/string.h" #include "shared/source/program/program_info.h" #include "shared/test/common/helpers/debug_manager_state_restore.h" #include "shared/test/unit_test/device_binary_format/zebin_tests.h" @@ -227,6 +229,17 @@ TEST(ValidateZebinSectionsCount, GivenTwoSpirvSectionsThenFail) { EXPECT_TRUE(warnings.empty()) << warnings; } +TEST(ValidateZebinSectionsCount, GivenTwoIntelGTNoteSectionsThenFail) { + NEO::ZebinSections sections; + std::string errors; + std::string warnings; + sections.noteIntelGTSections.resize(2); + auto err = NEO::validateZebinSectionsCount(sections, errors, warnings); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, err); + EXPECT_STREQ("DeviceBinaryFormat::Zebin : Expected at most 1 of .note.intelgt.compat section, got : 2\n", errors.c_str()); + EXPECT_TRUE(warnings.empty()) << warnings; +} + TEST(PopulateZeInfoVersion, GivenValidVersionFormatThenParsesItProperly) { { NEO::ConstStringRef yaml = R"===(--- @@ -1955,6 +1968,58 @@ TEST(DecodeSingleDeviceBinaryZebin, GivenConstDataSectionThenSetsUpInitDataAndSi EXPECT_EQ(nullptr, programInfo.globalVariables.initData); } +TEST(DecodeSingleDeviceBinaryZebin, GivenIntelGTNoteSectionThenAddsItToZebinSections) { + ZebinTestData::ValidEmptyProgram zebin; + NEO::Elf::IntelGTNote note = {}; + note.nameSize = 8; + note.descSize = 4; + note.type = NEO::Elf::IntelGTSectionType::GfxCore; + strcpy_s(const_cast(note.ownerName), note.nameSize, NEO::Elf::IntelGtNoteOwnerName.str().c_str()); + note.desc = GFXCORE_FAMILY::IGFX_GEN9_CORE; + zebin.appendSection(NEO::Elf::SHT_NOTE, NEO::Elf::SectionsNamesZebin::noteIntelGT, ArrayRef::fromAny(¬e, 1)); + + NEO::ProgramInfo programInfo; + NEO::SingleDeviceBinary singleBinary; + singleBinary.deviceBinary = zebin.storage; + std::string errors, warnings; + auto elf = NEO::Elf::decodeElf(zebin.storage, errors, warnings); + ASSERT_NE(nullptr, elf.elfFileHeader) << errors << " " << warnings; + + NEO::ZebinSections zebinSections; + auto extractErr = NEO::extractZebinSections(elf, zebinSections, errors, warnings); + ASSERT_EQ(NEO::DecodeError::Success, extractErr) << errors << " " << warnings; + EXPECT_EQ(1u, zebinSections.noteIntelGTSections.size()); +} + +TEST(DecodeSingleDeviceBinaryZebin, GivenNoteSectionDifferentThanIntelGTThenEmitsWarningAndSkipsIt) { + ZebinTestData::ValidEmptyProgram zebin; + struct NoteSection : NEO::Elf::ElfNoteSection { + const char ownerName[4] = "xxx"; + uint32_t desc = 0x12341234; + } note; + note.nameSize = 4; + note.descSize = 4; + note.type = 0; + ConstStringRef sectionName = ".note.example"; + zebin.appendSection(NEO::Elf::SHT_NOTE, sectionName, ArrayRef::fromAny(¬e, 1)); + + NEO::ProgramInfo programInfo; + NEO::SingleDeviceBinary singleBinary; + singleBinary.deviceBinary = zebin.storage; + std::string errors, warnings; + auto elf = NEO::Elf::decodeElf(zebin.storage, errors, warnings); + ASSERT_NE(nullptr, elf.elfFileHeader) << errors << " " << warnings; + + NEO::ZebinSections zebinSections; + auto extractErr = NEO::extractZebinSections(elf, zebinSections, errors, warnings); + ASSERT_EQ(NEO::DecodeError::Success, extractErr); + EXPECT_EQ(0u, zebinSections.noteIntelGTSections.size()); + EXPECT_TRUE(errors.empty()); + EXPECT_FALSE(warnings.empty()); + auto expectedWarning = "DeviceBinaryFormat::Zebin : Unhandled SHT_NOTE section : " + sectionName.str() + " currently supports only : " + NEO::Elf::SectionsNamesZebin::noteIntelGT.str() + ".\n"; + EXPECT_STREQ(expectedWarning.c_str(), warnings.c_str()); +} + TEST(DecodeSingleDeviceBinaryZebin, GivenSymtabSectionThenEmitsWarningAndSkipsIt) { ZebinTestData::ValidEmptyProgram zebin; const uint8_t data[] = {2, 3, 5, 7, 11, 13, 17, 19}; @@ -4290,3 +4355,167 @@ TEST(PopulateArgDescriptorCrossthreadPayload, GivenArgTypePrintfBufferWhenOffset ASSERT_EQ(32U, printfSurfaceAddress.stateless); EXPECT_EQ(8U, printfSurfaceAddress.pointerSize); } +class IntelGTNotesFixture : public ::testing::Test { + protected: + void SetUp() override { + zebin.elfHeader->type = Elf::ET_REL; + zebin.elfHeader->machine = Elf::ELF_MACHINE::EM_INTELGT; + + for (int i = 0; i < 3; ++i) { + notes[i].nameSize = 8; + notes[i].descSize = 4; + strcpy_s(notes[i].ownerName, notes[i].nameSize, Elf::IntelGtNoteOwnerName.str().c_str()); + } + } + ZebinTestData::ValidEmptyProgram zebin; + Elf::IntelGTNote notes[3]; +}; + +TEST_F(IntelGTNotesFixture, WhenGettingIntelGTNotesGivenValidIntelGTNotesSectionThenReturnsIntelGTNotes) { + notes[0].type = Elf::IntelGTSectionType::ProductFamily; + notes[0].desc = IGFX_SKYLAKE; + + notes[1].type = Elf::IntelGTSectionType::GfxCore; + notes[1].desc = IGFX_GEN9_CORE; + + Elf::ZebinTargetMetadata targetMetadata; + targetMetadata.validateRevisionId = true; + targetMetadata.minHwRevisionId = 5; + targetMetadata.maxHwRevisionId = 7; + notes[2].type = Elf::IntelGTSectionType::TargetMetadata; + notes[2].desc = targetMetadata.packed; + + zebin.appendSection(Elf::SHT_NOTE, Elf::SectionsNamesZebin::noteIntelGT, ArrayRef::fromAny(notes, 3)); + + std::string outErrReason, outWarning; + auto elf = Elf::decodeElf(zebin.storage, outErrReason, outWarning); + ASSERT_TRUE(outWarning.empty()); + ASSERT_TRUE(outErrReason.empty()); + + auto intelGTNotesRead = getIntelGTNotes(elf); + EXPECT_EQ(3U, intelGTNotesRead.size()); + + auto validNotes = true; + for (size_t i = 0; i < intelGTNotesRead.size(); ++i) { + validNotes &= (0 == memcmp(intelGTNotesRead[i], ¬es[i], sizeof(Elf::IntelGTNote))); + } + EXPECT_TRUE(validNotes); +} + +TEST_F(IntelGTNotesFixture, WhenGettingIntelGTNotesGivenInvalidIntelGTNotesSectionNameThenSectionsIsSkipped) { + zebin.appendSection(Elf::SHT_NOTE, ".note.wrong.name", ArrayRef::fromAny(notes, 3)); + + std::string outErrReason, outWarning; + auto elf = Elf::decodeElf(zebin.storage, outErrReason, outWarning); + ASSERT_TRUE(outWarning.empty()); + ASSERT_TRUE(outErrReason.empty()); + + auto intelGTNotesRead = getIntelGTNotes(elf); + EXPECT_EQ(0U, intelGTNotesRead.size()); +} + +TEST_F(IntelGTNotesFixture, WhenGettingIntelGTNotesGivenInvalidIntelGTNotesThenTheNoteIsSkipped) { + notes[0].nameSize = 0xbad; + notes[1].descSize = 0xbad; + strcpy_s(notes[2].ownerName, notes[2].nameSize, "badName"); + zebin.appendSection(Elf::SHT_NOTE, Elf::SectionsNamesZebin::noteIntelGT, ArrayRef::fromAny(notes, 3)); + + std::string outErrReason, outWarning; + auto elf = Elf::decodeElf(zebin.storage, outErrReason, outWarning); + ASSERT_TRUE(outWarning.empty()); + ASSERT_TRUE(outErrReason.empty()); + + auto intelGTNotesRead = getIntelGTNotes(elf); + EXPECT_EQ(0U, intelGTNotesRead.size()); +} + +TEST_F(IntelGTNotesFixture, WhenValidatingTargetDeviceGivenValidTargetDeviceAndValidNotesThenReturnTrue) { + TargetDevice targetDevice; + targetDevice.productFamily = IGFX_SKYLAKE; + targetDevice.coreFamily = IGFX_GEN9_CORE; + targetDevice.maxPointerSizeInBytes = 8; + targetDevice.stepping = 6; + notes[0].type = Elf::IntelGTSectionType::ProductFamily; + notes[0].desc = targetDevice.productFamily; + + notes[1].type = Elf::IntelGTSectionType::GfxCore; + notes[1].desc = targetDevice.coreFamily; + + Elf::ZebinTargetMetadata targetMetadata; + targetMetadata.validateRevisionId = true; + targetMetadata.minHwRevisionId = targetDevice.stepping - 1; + targetMetadata.maxHwRevisionId = targetDevice.stepping + 1; + notes[2].type = Elf::IntelGTSectionType::TargetMetadata; + notes[2].desc = targetMetadata.packed; + + zebin.appendSection(Elf::SHT_NOTE, Elf::SectionsNamesZebin::noteIntelGT, ArrayRef::fromAny(notes, 3)); + + std::string outErrReason, outWarning; + auto elf = Elf::decodeElf(zebin.storage, outErrReason, outWarning); + ASSERT_TRUE(outWarning.empty()); + ASSERT_TRUE(outErrReason.empty()); + + EXPECT_TRUE(validateTargetDevice(elf, targetDevice)); +} + +TEST_F(IntelGTNotesFixture, WhenValidatingTargetDeviceGivenValidTargetDeviceAndNoNotesThenReturnFalse) { + TargetDevice targetDevice; + targetDevice.productFamily = IGFX_SKYLAKE; + targetDevice.coreFamily = IGFX_GEN9_CORE; + targetDevice.maxPointerSizeInBytes = 8; + targetDevice.stepping = 6; + + std::string outErrReason, outWarning; + auto elf = Elf::decodeElf(zebin.storage, outErrReason, outWarning); + ASSERT_TRUE(outWarning.empty()); + ASSERT_TRUE(outErrReason.empty()); + + EXPECT_FALSE(validateTargetDevice(elf, targetDevice)); +} + +TEST_F(IntelGTNotesFixture, WhenValidatingTargetDeviceGivenInvalidTargetDeviceAndValidNotesThenReturnFalse) { + TargetDevice targetDevice; + targetDevice.productFamily = IGFX_SKYLAKE; + targetDevice.coreFamily = IGFX_GEN9_CORE; + targetDevice.maxPointerSizeInBytes = 8; + targetDevice.stepping = 6; + notes[0].type = Elf::IntelGTSectionType::ProductFamily; + notes[0].desc = targetDevice.productFamily + 2; + + notes[1].type = Elf::IntelGTSectionType::GfxCore; + notes[1].desc = targetDevice.coreFamily + 2; + + Elf::ZebinTargetMetadata targetMetadata; + targetMetadata.validateRevisionId = true; + targetMetadata.minHwRevisionId = targetDevice.stepping + 1; + targetMetadata.maxHwRevisionId = targetDevice.stepping + 3; + notes[2].type = Elf::IntelGTSectionType::TargetMetadata; + notes[2].desc = targetMetadata.packed; + + zebin.appendSection(Elf::SHT_NOTE, Elf::SectionsNamesZebin::noteIntelGT, ArrayRef::fromAny(notes, 3)); + + std::string outErrReason, outWarning; + auto elf = Elf::decodeElf(zebin.storage, outErrReason, outWarning); + ASSERT_TRUE(outWarning.empty()); + ASSERT_TRUE(outErrReason.empty()); + + EXPECT_FALSE(validateTargetDevice(elf, targetDevice)); +} + +TEST_F(IntelGTNotesFixture, WhenValidatingTargetDeviceGivenValidTargetDeviceAndInvalidNoteTypeThenReturnFalse) { + TargetDevice targetDevice; + targetDevice.productFamily = IGFX_SKYLAKE; + targetDevice.coreFamily = IGFX_GEN9_CORE; + targetDevice.maxPointerSizeInBytes = 8; + targetDevice.stepping = 6; + notes[0].type = 4; + notes[0].desc = 0; + zebin.appendSection(Elf::SHT_NOTE, Elf::SectionsNamesZebin::noteIntelGT, ArrayRef::fromAny(¬es[0], 1)); + + std::string outErrReason, outWarning; + auto elf = Elf::decodeElf(zebin.storage, outErrReason, outWarning); + ASSERT_TRUE(outWarning.empty()); + ASSERT_TRUE(outErrReason.empty()); + + EXPECT_FALSE(validateTargetDevice(elf, targetDevice)); +}