Add Kaitai-based parser for Dell DVAR store

This commit is contained in:
Nikolaj Schlej 2025-04-26 01:14:13 +07:00
parent c8b7151b9e
commit 73d07cddc3
14 changed files with 870 additions and 16 deletions

View file

@ -36,6 +36,7 @@ SET(PROJECT_SOURCES
../common/bstrlib/bstrwrap.cpp
../common/generated/ami_nvar.cpp
../common/generated/apple_sysf.cpp
../common/generated/dell_dvar.cpp
../common/generated/edk2_vss.cpp
../common/generated/edk2_vss2.cpp
../common/generated/edk2_ftw.cpp

View file

@ -33,6 +33,7 @@ SET(PROJECT_SOURCES
../common/bstrlib/bstrwrap.cpp
../common/generated/ami_nvar.cpp
../common/generated/apple_sysf.cpp
../common/generated/dell_dvar.cpp
../common/generated/edk2_vss.cpp
../common/generated/edk2_vss2.cpp
../common/generated/edk2_ftw.cpp

View file

@ -69,6 +69,7 @@ SET(PROJECT_SOURCES
../common/digest/sm3.c
../common/generated/ami_nvar.cpp
../common/generated/apple_sysf.cpp
../common/generated/dell_dvar.cpp
../common/generated/edk2_vss.cpp
../common/generated/edk2_vss2.cpp
../common/generated/edk2_ftw.cpp

View file

@ -249,6 +249,7 @@ void UEFITool::populateUi(const QModelIndex &current)
|| type == Types::EvsaEntry
|| type == Types::PhoenixFlashMapEntry
|| type == Types::InsydeFlashDeviceMapEntry
|| type == Types::DellDvarEntry
|| type == Types::IfwiHeader
|| type == Types::IfwiPartition
|| type == Types::FptPartition
@ -269,6 +270,7 @@ void UEFITool::populateUi(const QModelIndex &current)
|| type == Types::FtwStore
|| type == Types::PhoenixFlashMapStore
|| type == Types::InsydeFlashDeviceMapStore
|| type == Types::DellDvarStore
|| type == Types::NvarGuidStore
|| type == Types::CmdbStore
|| type == Types::FptStore
@ -914,6 +916,7 @@ void UEFITool::contextMenuEvent(QContextMenuEvent* event)
case Types::FtwStore:
case Types::PhoenixFlashMapStore:
case Types::InsydeFlashDeviceMapStore:
case Types::DellDvarStore:
case Types::NvarGuidStore:
case Types::CmdbStore:
case Types::FptStore:

View file

@ -52,6 +52,7 @@ HEADERS += uefitool.h \
../common/digest/sm3.h \
../common/generated/ami_nvar.h \
../common/generated/apple_sysf.h \
../common/generated/dell_dvar.h \
../common/generated/edk2_vss.h \
../common/generated/edk2_vss2.h \
../common/generated/edk2_ftw.h \
@ -129,6 +130,7 @@ SOURCES += uefitool_main.cpp \
../common/digest/sm3.c \
../common/generated/ami_nvar.cpp \
../common/generated/apple_sysf.cpp \
../common/generated/dell_dvar.cpp \
../common/generated/edk2_vss.cpp \
../common/generated/edk2_vss2.cpp \
../common/generated/edk2_ftw.cpp \

View file

@ -924,6 +924,44 @@ extern const UByteArray INSYDE_FLASH_MAP_REGION_DXE_FV_GUID;
extern const UByteArray INSYDE_FLASH_MAP_REGION_PEI_FV_GUID;
extern const UByteArray INSYDE_FLASH_MAP_REGION_UNSIGNED_FV_GUID;
//
// Dell variables
//
#define DVAR_STORE_SIGNATURE 0x52415644
typedef struct _DVAR_STORE_HEADER {
UINT32 Signature;
UINT32 StoreSizeC;
UINT8 FlagsC;
// DVAR_ENTRY Entries[];
} DVAR_STORE_HEADER;
typedef struct _DVAR_ENTRY_HEADER {
UINT8 StateC; // Values are stored in 2-complement format, can be converted with (Val = 0xFF - ValC)
UINT8 FlagsC;
UINT8 TypeC;
UINT8 AttributesC;
UINT8 NamespaceIdC;
// The rest is variable depending on Flags and Types
// EFI_GUID NamespaceGuid;
// UINT8 or UINT16 NameId;
// UINT8 or UINT16 DataSize;
// UINT8 Data[DataSize];
} DVAR_ENTRY_HEADER;
#define DVAR_ENTRY_STATE_STORING 0x01
#define DVAR_ENTRY_STATE_STORED 0x05
#define DVAR_ENTRY_STATE_DELETING 0x15
#define DVAR_ENTRY_STATE_DELETED 0x55
//#define DVAR_ENTRY_FLAG_NAME_UTF8 0x01 // Haven't seen any samples yet, so this is a guesswork for now
#define DVAR_ENTRY_FLAG_NAME_ID 0x02
#define DVAR_ENTRY_FLAG_NAMESPACE_GUID 0x04 // This kind of variables is used to store namespace guids, the "deleted" state for them is ignored
#define DVAR_ENTRY_TYPE_NAME_ID_8_DATA_SIZE_8 0x00 // Both NameId and DataSize are UINT8
#define DVAR_ENTRY_TYPE_NAME_ID_16_DATA_SIZE_8 0x04 // NameId is UINT16, DataSize is UINT8
#define DVAR_ENTRY_TYPE_NAME_ID_16_DATA_SIZE_16 0x05 // Both NameId and DataSize are UINT16
// Restore previous packing rules
#pragma pack(pop)

View file

@ -39,6 +39,10 @@
#include "kaitai/kaitaistream.h"
#include "generated/insyde_fdm.h"
#ifdef U_ENABLE_NVRAM_PARSING_SUPPORT
#include "generated/dell_dvar.h"
#endif
// Constructor
FfsParser::FfsParser(TreeModel* treeModel) : model(treeModel),
imageBase(0), addressDiff(0x100000000ULL), protectedRegionsBase(0) {
@ -839,6 +843,15 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
UByteArray data = model->body(index);
UINT32 headerSize = (UINT32)model->header(index).size();
// Obtain required information from parent volume, if it exists
UINT8 emptyByte = 0xFF;
UModelIndex parentVolumeIndex = model->findParentOfType(index, Types::Volume);
if (parentVolumeIndex.isValid() && model->hasEmptyParsingData(parentVolumeIndex) == false) {
UByteArray data = model->parsingData(parentVolumeIndex);
const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData();
emptyByte = pdata->emptyByte;
}
USTATUS result;
UString name;
UString info;
@ -922,9 +935,7 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
} else {
// Show messages
if (itemSize != itemAltSize)
msg(usprintf("%s: volume size stored in header %Xh differs from calculated using block map %Xh", __FUNCTION__,
itemSize, itemAltSize),
volumeIndex);
msg(usprintf("%s: volume size stored in header %Xh differs from calculated using block map %Xh", __FUNCTION__, itemSize, itemAltSize), volumeIndex);
}
}
else if (itemType == Types::Microcode) {
@ -966,11 +977,10 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
// Add info
UString name = UString("Insyde H2O FlashDeviceMap");
UString info = usprintf("Signature: HFDM\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nData offset: %Xh\nEntry size: %Xh (%u)\nEntry format: %02Xh\nRevision: %02Xh\nExtension count: %u\nFlash descriptor base address: %08Xh\nChecksum: %02Xh",
UString info = usprintf("Signature: HFDM\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nEntry size: %Xh (%u)\nEntry format: %02Xh\nRevision: %02Xh\nExtension count: %u\nFlash descriptor base address: %08Xh\nChecksum: %02Xh",
storeSize, storeSize,
(UINT32)header.size(), (UINT32)header.size(),
(UINT32)body.size(), (UINT32)body.size(),
parsed.data_offset(),
parsed.entry_size(), parsed.entry_size(),
parsed.entry_format(),
parsed.revision(),
@ -1062,9 +1072,201 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
}
}
catch (...) {
// Parsing failed
// Parsing failed, need to add the candidate as Padding
UByteArray padding = data.mid(itemOffset, itemSize);
// Get info
name = UString("Padding");
info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size());
// Add tree item
model->addItem(headerSize + itemOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
}
}
#ifdef U_ENABLE_NVRAM_PARSING_SUPPORT
else if (itemType == Types::DellDvarStore) {
try {
UByteArray dvar = data.mid(itemOffset, itemSize);
umemstream is(dvar.constData(), dvar.size());
kaitai::kstream ks(&is);
dell_dvar_t parsed(&ks);
UINT32 storeSize = (UINT32)dvar.size();
// Construct header and body
UByteArray header = dvar.left(parsed.data_offset());
UByteArray body = dvar.mid(header.size(), storeSize - header.size());
// Add info
UString name = UString("Dell DVAR Store");
UString info = usprintf("Signature: DVAR\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nFlags: %02Xh",
storeSize, storeSize,
(UINT32)header.size(), (UINT32)header.size(),
(UINT32)body.size(), (UINT32)body.size(),
parsed.flags());
// Add header tree item
UModelIndex headerIndex = model->addItem(headerSize + itemOffset, Types::DellDvarStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, index);
// Add entries
UINT32 entryOffset = parsed.data_offset();
for (const auto & entry : *parsed.entries()) {
// This is the terminating entry, needs special processing
if (entry->_is_null_flags_c()) {
// Add free space or padding after all entries, if needed
if (entryOffset < storeSize) {
UByteArray freeSpace = dvar.mid(entryOffset, storeSize - entryOffset);
// Add info
info = usprintf("Full size: %Xh (%u)", (UINT32)freeSpace.size(), (UINT32)freeSpace.size());
// Check that remaining unparsed bytes are actually empty
if (freeSpace.count(emptyByte) == freeSpace.size()) { // Free space
// Add tree item
model->addItem(entryOffset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), freeSpace, UByteArray(), Fixed, headerIndex);
}
else {
// Add tree item
model->addItem(entryOffset, Types::Padding, getPaddingType(freeSpace), UString("Padding"), UString(), info, UByteArray(), freeSpace, UByteArray(), Fixed, headerIndex);
}
}
break;
}
// This is a normal entry
// Check state to be known
if (entry->state() != DVAR_ENTRY_STATE_STORING &&
entry->state() != DVAR_ENTRY_STATE_STORED &&
entry->state() != DVAR_ENTRY_STATE_DELETING &&
entry->state() != DVAR_ENTRY_STATE_DELETED){
// TODO: Add the rest as padding, as we encountered an unexpected entry and can't guarantee that the rest got parsed correctly
}
// Check flags to be known
if (entry->flags() != DVAR_ENTRY_FLAG_NAME_ID &&
entry->flags() != DVAR_ENTRY_FLAG_NAME_ID + DVAR_ENTRY_FLAG_NAMESPACE_GUID) {
// TODO: Add the rest as padding, as we encountered an unexpected entry and can't guarantee that the rest got parsed correctly
}
// Check type to be known
if (entry->type() != DVAR_ENTRY_TYPE_NAME_ID_8_DATA_SIZE_8 &&
entry->type() != DVAR_ENTRY_TYPE_NAME_ID_16_DATA_SIZE_8 &&
entry->type() != DVAR_ENTRY_TYPE_NAME_ID_16_DATA_SIZE_16) {
// TODO: Add the rest as padding, as we encountered an unexpected entry and can't guarantee that the rest got parsed correctly
}
UINT32 headerSize;
UINT32 bodySize;
UINT32 entrySize;
UINT32 nameId;
UINT8 subtype;
UString text;
// TODO: find a Dell image with NameUtf8 entries
// NamespaceGUID entry
if (entry->flags() == DVAR_ENTRY_FLAG_NAME_ID + DVAR_ENTRY_FLAG_NAMESPACE_GUID) {
// State of this variable only applies to the NameId part, not the NamespaceGuid part
// This kind of variables with deleted state till need to be shown as valid
subtype = Subtypes::NamespaceGuidDvarEntry;
EFI_GUID guid = *(const EFI_GUID*)(entry->namespace_guid().c_str());
headerSize = sizeof(DVAR_ENTRY_HEADER) + sizeof(EFI_GUID);
if (entry->type() == DVAR_ENTRY_TYPE_NAME_ID_8_DATA_SIZE_8) {
nameId = entry->name_id_8();
bodySize = entry->len_data_8();
headerSize += sizeof(UINT8) + sizeof(UINT8);
}
else if (entry->type() == DVAR_ENTRY_TYPE_NAME_ID_16_DATA_SIZE_8) {
nameId = entry->name_id_16();
bodySize = entry->len_data_8();
headerSize += sizeof(UINT16) + sizeof(UINT8);
}
else if (entry->type() == DVAR_ENTRY_TYPE_NAME_ID_16_DATA_SIZE_16) {
nameId = entry->name_id_16();
bodySize = entry->len_data_16();
headerSize += sizeof(UINT16) + sizeof(UINT16);
}
entrySize = headerSize + bodySize;
header = dvar.mid(entryOffset, headerSize);
body = dvar.mid(entryOffset + headerSize, bodySize);
name = usprintf("%X:%X", entry->namespace_id(), nameId);
text = guidToUString(guid);
info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nState: %02Xh\nFlags: %02Xh\nType: %02Xh\nNamespaceId: %Xh\nNameId: %Xh\n",
entrySize, entrySize,
(UINT32)header.size(), (UINT32)header.size(),
(UINT32)body.size(), (UINT32)body.size(),
entry->state(),
entry->flags(),
entry->type(),
entry->namespace_id(),
nameId)
+ UString("NamespaceGuid: ") + guidToUString(guid, false);
}
// NameId entry
else {
subtype = Subtypes::NameIdDvarEntry;
headerSize = sizeof(DVAR_ENTRY_HEADER);
if (entry->type() == DVAR_ENTRY_TYPE_NAME_ID_8_DATA_SIZE_8) {
nameId = entry->name_id_8();
bodySize = entry->len_data_8();
headerSize += sizeof(UINT8) + sizeof(UINT8);
}
else if (entry->type() == DVAR_ENTRY_TYPE_NAME_ID_16_DATA_SIZE_8) {
nameId = entry->name_id_16();
bodySize = entry->len_data_8();
headerSize += sizeof(UINT16) + sizeof(UINT8);
}
else if (entry->type() == DVAR_ENTRY_TYPE_NAME_ID_16_DATA_SIZE_16) {
nameId = entry->name_id_16();
bodySize = entry->len_data_16();
headerSize += sizeof(UINT16) + sizeof(UINT16);
}
entrySize = headerSize + bodySize;
header = dvar.mid(entryOffset, headerSize);
body = dvar.mid(entryOffset + headerSize, bodySize);
name = usprintf("%X:%X", entry->namespace_id(), nameId);
info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nState: %02Xh\nFlags: %02Xh\nType: %02Xh\nNamespaceId: %Xh\nNameId: %Xh\n",
entrySize, entrySize,
(UINT32)header.size(), (UINT32)header.size(),
(UINT32)body.size(), (UINT32)body.size(),
entry->state(),
entry->flags(),
entry->type(),
entry->namespace_id(),
nameId);
}
// Mark NameId entries that are not stored as Invalid
if (entry->flags() != DVAR_ENTRY_FLAG_NAME_ID + DVAR_ENTRY_FLAG_NAMESPACE_GUID &&
(entry->state() == DVAR_ENTRY_STATE_STORING ||
entry->state() == DVAR_ENTRY_STATE_DELETING ||
entry->state() == DVAR_ENTRY_STATE_DELETED)) {
subtype = Subtypes::InvalidDvarEntry;
name = UString("Invalid");
text.clear();
}
// Add tree item
model->addItem(entryOffset, Types::DellDvarEntry, subtype, name, text, info, header, body, UByteArray(), Fixed, headerIndex);
entryOffset += entrySize;
}
}
catch (...) {
// Parsing failed, need to add the candidate as Padding
UByteArray padding = data.mid(itemOffset, itemSize);
// Get info
name = UString("Padding");
info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size());
// Add tree item
model->addItem(headerSize + itemOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
}
}
#endif
else {
return U_UNKNOWN_ITEM_TYPE;
}
@ -1079,7 +1281,7 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
(void)prevItemType;
}
// Padding at the end of RAW area
// Padding at the end of raw area
itemOffset = prevItemOffset + prevItemSize;
if ((UINT32)data.size() > itemOffset) {
UByteArray padding = data.mid(itemOffset);
@ -1112,6 +1314,9 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
case Types::InsydeFlashDeviceMapStore:
// Parsing already done
break;
case Types::DellDvarStore:
// Parsing already done
break;
case Types::Padding:
// No parsing required
break;
@ -1546,6 +1751,25 @@ continue_searching: {}
nextItemOffset = offset;
break;
}
#ifdef U_ENABLE_NVRAM_PARSING_SUPPORT
else if (readUnaligned(currentPos) == DVAR_STORE_SIGNATURE) {
// Check data size
if (restSize < sizeof(DVAR_STORE_HEADER))
continue;
const DVAR_STORE_HEADER *dvarHeader = (const DVAR_STORE_HEADER *)currentPos;
UINT32 storeSize = 0xFFFFFFFF - dvarHeader->StoreSizeC;
if (restSize < storeSize)
continue;
// All checks passed, FDM found
nextItemType = Types::DellDvarStore;
nextItemSize = storeSize;
nextItemAlternativeSize = storeSize;
nextItemOffset = offset;
break;
}
#endif
}
// No more stores found
@ -1567,9 +1791,9 @@ USTATUS FfsParser::parseVolumeNonUefiData(const UByteArray & data, const UINT32
// Add padding tree item
UModelIndex paddingIndex = model->addItem(localOffset, Types::Padding, Subtypes::DataPadding, UString("Non-UEFI data"), UString(), info, UByteArray(), data, UByteArray(), Fixed, index);
msg(usprintf("%s: non-UEFI data found in volume's free space", __FUNCTION__), paddingIndex);
msg(usprintf("%s: non-UEFI data found in volume free space", __FUNCTION__), paddingIndex);
// Parse contents as RAW area
// Parse contents as raw area
return parseRawArea(paddingIndex);
}

View file

@ -0,0 +1,235 @@
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
#include "dell_dvar.h"
dell_dvar_t::dell_dvar_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, dell_dvar_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = this; (void)p__root;
m_entries = nullptr;
f_len_store = false;
f_flags = false;
f_data_offset = false;
_read();
}
void dell_dvar_t::_read() {
m_signature = m__io->read_bytes(4);
m_len_store_c = m__io->read_u4le();
m_flags_c = m__io->read_u1();
m_entries = std::unique_ptr<std::vector<std::unique_ptr<dvar_entry_t>>>(new std::vector<std::unique_ptr<dvar_entry_t>>());
{
int i = 0;
dvar_entry_t* _;
do {
_ = new dvar_entry_t(m__io, this, m__root);
m_entries->push_back(std::move(std::unique_ptr<dvar_entry_t>(_)));
i++;
} while (!(_->state_c() == 255));
}
}
dell_dvar_t::~dell_dvar_t() {
_clean_up();
}
void dell_dvar_t::_clean_up() {
}
dell_dvar_t::dvar_entry_t::dvar_entry_t(kaitai::kstream* p__io, dell_dvar_t* p__parent, dell_dvar_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
f_namespace_id = false;
f_len_data_8 = false;
f_state = false;
f_len_data_16 = false;
f_attributes = false;
f_flags = false;
f_name_id_8 = false;
f_name_id_16 = false;
f_type = false;
_read();
}
void dell_dvar_t::dvar_entry_t::_read() {
m_state_c = m__io->read_u1();
n_flags_c = true;
if (state_c() != 255) {
n_flags_c = false;
m_flags_c = m__io->read_u1();
}
n_type_c = true;
if (state_c() != 255) {
n_type_c = false;
m_type_c = m__io->read_u1();
}
n_attributes_c = true;
if (state_c() != 255) {
n_attributes_c = false;
m_attributes_c = m__io->read_u1();
}
n_namespace_id_c = true;
if ( ((state_c() != 255) && ( ((flags() == 2) || (flags() == 6)) )) ) {
n_namespace_id_c = false;
m_namespace_id_c = m__io->read_u1();
}
n_namespace_guid = true;
if ( ((state_c() != 255) && (flags() == 6)) ) {
n_namespace_guid = false;
m_namespace_guid = m__io->read_bytes(16);
}
n_name_id_8_c = true;
if ( ((state_c() != 255) && (type() == 0)) ) {
n_name_id_8_c = false;
m_name_id_8_c = m__io->read_u1();
}
n_name_id_16_c = true;
if ( ((state_c() != 255) && ( ((type() == 4) || (type() == 5)) )) ) {
n_name_id_16_c = false;
m_name_id_16_c = m__io->read_u2le();
}
n_len_data_8_c = true;
if ( ((state_c() != 255) && ( ((type() == 0) || (type() == 4)) )) ) {
n_len_data_8_c = false;
m_len_data_8_c = m__io->read_u1();
}
n_len_data_16_c = true;
if ( ((state_c() != 255) && (type() == 5)) ) {
n_len_data_16_c = false;
m_len_data_16_c = m__io->read_u2le();
}
n_data_8 = true;
if ( ((state_c() != 255) && ( ((type() == 0) || (type() == 4)) )) ) {
n_data_8 = false;
m_data_8 = m__io->read_bytes(len_data_8());
}
n_data_16 = true;
if ( ((state_c() != 255) && (type() == 5)) ) {
n_data_16 = false;
m_data_16 = m__io->read_bytes(len_data_16());
}
}
dell_dvar_t::dvar_entry_t::~dvar_entry_t() {
_clean_up();
}
void dell_dvar_t::dvar_entry_t::_clean_up() {
if (!n_flags_c) {
}
if (!n_type_c) {
}
if (!n_attributes_c) {
}
if (!n_namespace_id_c) {
}
if (!n_namespace_guid) {
}
if (!n_name_id_8_c) {
}
if (!n_name_id_16_c) {
}
if (!n_len_data_8_c) {
}
if (!n_len_data_16_c) {
}
if (!n_data_8) {
}
if (!n_data_16) {
}
}
int32_t dell_dvar_t::dvar_entry_t::namespace_id() {
if (f_namespace_id)
return m_namespace_id;
m_namespace_id = (255 - namespace_id_c());
f_namespace_id = true;
return m_namespace_id;
}
int32_t dell_dvar_t::dvar_entry_t::len_data_8() {
if (f_len_data_8)
return m_len_data_8;
m_len_data_8 = (255 - len_data_8_c());
f_len_data_8 = true;
return m_len_data_8;
}
int32_t dell_dvar_t::dvar_entry_t::state() {
if (f_state)
return m_state;
m_state = (255 - state_c());
f_state = true;
return m_state;
}
int32_t dell_dvar_t::dvar_entry_t::len_data_16() {
if (f_len_data_16)
return m_len_data_16;
m_len_data_16 = (65535 - len_data_16_c());
f_len_data_16 = true;
return m_len_data_16;
}
int32_t dell_dvar_t::dvar_entry_t::attributes() {
if (f_attributes)
return m_attributes;
m_attributes = (255 - attributes_c());
f_attributes = true;
return m_attributes;
}
int32_t dell_dvar_t::dvar_entry_t::flags() {
if (f_flags)
return m_flags;
m_flags = (255 - flags_c());
f_flags = true;
return m_flags;
}
int32_t dell_dvar_t::dvar_entry_t::name_id_8() {
if (f_name_id_8)
return m_name_id_8;
m_name_id_8 = (255 - name_id_8_c());
f_name_id_8 = true;
return m_name_id_8;
}
int32_t dell_dvar_t::dvar_entry_t::name_id_16() {
if (f_name_id_16)
return m_name_id_16;
m_name_id_16 = (65535 - name_id_16_c());
f_name_id_16 = true;
return m_name_id_16;
}
int32_t dell_dvar_t::dvar_entry_t::type() {
if (f_type)
return m_type;
m_type = (255 - type_c());
f_type = true;
return m_type;
}
int32_t dell_dvar_t::len_store() {
if (f_len_store)
return m_len_store;
m_len_store = (4294967295UL - len_store_c());
f_len_store = true;
return m_len_store;
}
int32_t dell_dvar_t::flags() {
if (f_flags)
return m_flags;
m_flags = (255 - flags_c());
f_flags = true;
return m_flags;
}
int8_t dell_dvar_t::data_offset() {
if (f_data_offset)
return m_data_offset;
m_data_offset = 9;
f_data_offset = true;
return m_data_offset;
}

View file

@ -0,0 +1,239 @@
#pragma once
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
#include "../kaitai/kaitaistruct.h"
#include <stdint.h>
#include <memory>
#include <vector>
#if KAITAI_STRUCT_VERSION < 9000L
#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required"
#endif
class dell_dvar_t : public kaitai::kstruct {
public:
class dvar_entry_t;
dell_dvar_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, dell_dvar_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~dell_dvar_t();
class dvar_entry_t : public kaitai::kstruct {
public:
dvar_entry_t(kaitai::kstream* p__io, dell_dvar_t* p__parent = nullptr, dell_dvar_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~dvar_entry_t();
private:
bool f_namespace_id;
int32_t m_namespace_id;
public:
int32_t namespace_id();
private:
bool f_len_data_8;
int32_t m_len_data_8;
public:
int32_t len_data_8();
private:
bool f_state;
int32_t m_state;
public:
int32_t state();
private:
bool f_len_data_16;
int32_t m_len_data_16;
public:
int32_t len_data_16();
private:
bool f_attributes;
int32_t m_attributes;
public:
int32_t attributes();
private:
bool f_flags;
int32_t m_flags;
public:
int32_t flags();
private:
bool f_name_id_8;
int32_t m_name_id_8;
public:
int32_t name_id_8();
private:
bool f_name_id_16;
int32_t m_name_id_16;
public:
int32_t name_id_16();
private:
bool f_type;
int32_t m_type;
public:
int32_t type();
private:
uint8_t m_state_c;
uint8_t m_flags_c;
bool n_flags_c;
public:
bool _is_null_flags_c() { flags_c(); return n_flags_c; };
private:
uint8_t m_type_c;
bool n_type_c;
public:
bool _is_null_type_c() { type_c(); return n_type_c; };
private:
uint8_t m_attributes_c;
bool n_attributes_c;
public:
bool _is_null_attributes_c() { attributes_c(); return n_attributes_c; };
private:
uint8_t m_namespace_id_c;
bool n_namespace_id_c;
public:
bool _is_null_namespace_id_c() { namespace_id_c(); return n_namespace_id_c; };
private:
std::string m_namespace_guid;
bool n_namespace_guid;
public:
bool _is_null_namespace_guid() { namespace_guid(); return n_namespace_guid; };
private:
uint8_t m_name_id_8_c;
bool n_name_id_8_c;
public:
bool _is_null_name_id_8_c() { name_id_8_c(); return n_name_id_8_c; };
private:
uint16_t m_name_id_16_c;
bool n_name_id_16_c;
public:
bool _is_null_name_id_16_c() { name_id_16_c(); return n_name_id_16_c; };
private:
uint8_t m_len_data_8_c;
bool n_len_data_8_c;
public:
bool _is_null_len_data_8_c() { len_data_8_c(); return n_len_data_8_c; };
private:
uint16_t m_len_data_16_c;
bool n_len_data_16_c;
public:
bool _is_null_len_data_16_c() { len_data_16_c(); return n_len_data_16_c; };
private:
std::string m_data_8;
bool n_data_8;
public:
bool _is_null_data_8() { data_8(); return n_data_8; };
private:
std::string m_data_16;
bool n_data_16;
public:
bool _is_null_data_16() { data_16(); return n_data_16; };
private:
dell_dvar_t* m__root;
dell_dvar_t* m__parent;
public:
uint8_t state_c() const { return m_state_c; }
uint8_t flags_c() const { return m_flags_c; }
uint8_t type_c() const { return m_type_c; }
uint8_t attributes_c() const { return m_attributes_c; }
uint8_t namespace_id_c() const { return m_namespace_id_c; }
std::string namespace_guid() const { return m_namespace_guid; }
uint8_t name_id_8_c() const { return m_name_id_8_c; }
uint16_t name_id_16_c() const { return m_name_id_16_c; }
uint8_t len_data_8_c() const { return m_len_data_8_c; }
uint16_t len_data_16_c() const { return m_len_data_16_c; }
std::string data_8() const { return m_data_8; }
std::string data_16() const { return m_data_16; }
dell_dvar_t* _root() const { return m__root; }
dell_dvar_t* _parent() const { return m__parent; }
};
private:
bool f_len_store;
int32_t m_len_store;
public:
int32_t len_store();
private:
bool f_flags;
int32_t m_flags;
public:
int32_t flags();
private:
bool f_data_offset;
int8_t m_data_offset;
public:
int8_t data_offset();
private:
std::string m_signature;
uint32_t m_len_store_c;
uint8_t m_flags_c;
std::unique_ptr<std::vector<std::unique_ptr<dvar_entry_t>>> m_entries;
dell_dvar_t* m__root;
kaitai::kstruct* m__parent;
public:
std::string signature() const { return m_signature; }
uint32_t len_store_c() const { return m_len_store_c; }
uint8_t flags_c() const { return m_flags_c; }
std::vector<std::unique_ptr<dvar_entry_t>>* entries() const { return m_entries.get(); }
dell_dvar_t* _root() const { return m__root; }
kaitai::kstruct* _parent() const { return m__parent; }
};

91
common/ksy/dell_dvar.ksy Normal file
View file

@ -0,0 +1,91 @@
meta:
id: dell_dvar
title: Dell DVAR Storage
application: Dell UEFI firmware
file-extension: dvar
tags:
- firmware
license: CC0-1.0
ks-version: 0.9
endian: le
seq:
- id: signature
size: 4
- id: len_store_c
type: u4
- id: flags_c
type: u1
- id: entries
type: dvar_entry
repeat: until
repeat-until: _.state_c == 0xFF
instances:
len_store:
value: 0xFFFFFFFF - len_store_c
flags:
value: 0xFF - flags_c
data_offset:
value: 9
#TODO: find samples with different flags and types to make them flags insead of immediates
types:
dvar_entry:
seq:
- id: state_c
type: u1
- id: flags_c
type: u1
if: state_c != 0xFF
- id: type_c
type: u1
if: state_c != 0xFF
- id: attributes_c
type: u1
if: state_c != 0xFF
- id: namespace_id_c
type: u1
if: state_c != 0xFF and (flags == 2 or flags == 6)
- id: namespace_guid
size: 16
if: state_c != 0xFF and flags == 6
- id: name_id_8_c
type: u1
if: state_c != 0xFF and type == 0
- id: name_id_16_c
type: u2
if: state_c != 0xFF and (type == 4 or type == 5)
- id: len_data_8_c
type: u1
if: state_c != 0xFF and (type == 0 or type == 4)
- id: len_data_16_c
type: u2
if: state_c != 0xFF and type == 5
- id: data_8
size: len_data_8
if: state_c != 0xFF and (type == 0 or type == 4)
- id: data_16
size: len_data_16
if: state_c != 0xFF and type == 5
instances:
state:
value: 0xFF - state_c
flags:
value: 0xFF - flags_c
type:
value: 0xFF - type_c
attributes:
value: 0xFF - attributes_c
namespace_id:
value: 0xFF - namespace_id_c
name_id_8:
value: 0xFF - name_id_8_c
name_id_16:
value: 0xFFFF - name_id_16_c
len_data_8:
value: 0xFF - len_data_8_c
len_data_16:
value: 0xFFFF - len_data_16_c

View file

@ -34,6 +34,7 @@ uefitoolcommon = static_library('uefitoolcommon',
'ustring.cpp',
'generated/ami_nvar.cpp',
'generated/apple_sysf.cpp',
'generated/dell_dvar.cpp',
'generated/edk2_vss.cpp',
'generated/edk2_vss2.cpp',
'generated/edk2_ftw.cpp',

View file

@ -60,6 +60,7 @@ UString itemTypeToUString(const UINT8 type)
case Types::CmdbStore: return UString("CMDB store");
case Types::PhoenixFlashMapStore: return UString("FlashMap store");
case Types::InsydeFlashDeviceMapStore: return UString("FlashDeviceMap store");
case Types::DellDvarStore: return UString("DVAR store");
case Types::NvarGuidStore: return UString("NVAR GUID store");
case Types::NvarEntry: return UString("NVAR entry");
case Types::VssEntry: return UString("VSS entry");
@ -67,6 +68,7 @@ UString itemTypeToUString(const UINT8 type)
case Types::EvsaEntry: return UString("EVSA entry");
case Types::PhoenixFlashMapEntry: return UString("FlashMap entry");
case Types::InsydeFlashDeviceMapEntry: return UString("FlashDeviceMap entry");
case Types::DellDvarEntry: return UString("DVAR entry");
case Types::Microcode: return UString("Microcode");
case Types::SlicData: return UString("SLIC data");
case Types::FptStore: return UString("FPT store");
@ -146,6 +148,12 @@ UString itemSubtypeToUString(const UINT8 type, const UINT8 subtype)
else if (subtype == Subtypes::DataFlashMapEntry) return UString("Data");
else if (subtype == Subtypes::UnknownFlashMapEntry) return UString("Unknown");
break;
case Types::DellDvarEntry:
if (subtype == Subtypes::InvalidDvarEntry) return UString("Invalid");
else if (subtype == Subtypes::NamespaceGuidDvarEntry) return UString("NamespaceGuid");
else if (subtype == Subtypes::NameIdDvarEntry) return UString("NameId");
else if (subtype == Subtypes::UnknownDvarEntry) return UString("Unknown");
break;
case Types::Microcode:
if (subtype == Subtypes::IntelMicrocode) return UString("Intel");
else if (subtype == Subtypes::AmdMicrocode) return UString("AMD");

View file

@ -51,6 +51,7 @@ namespace Types {
EvsaStore,
PhoenixFlashMapStore,
InsydeFlashDeviceMapStore,
DellDvarStore,
CmdbStore,
NvarGuidStore,
NvarEntry,
@ -59,6 +60,7 @@ namespace Types {
EvsaEntry,
PhoenixFlashMapEntry,
InsydeFlashDeviceMapEntry,
DellDvarEntry,
Microcode,
SlicData,
IfwiHeader,
@ -159,42 +161,49 @@ namespace Subtypes {
UnknownFlashMapEntry,
};
enum DvarEntrySubtypes {
InvalidDvarEntry = 180,
NamespaceGuidDvarEntry,
NameIdDvarEntry,
UnknownDvarEntry
};
enum MicrocodeSubtypes {
IntelMicrocode = 180,
IntelMicrocode = 190,
AmdMicrocode,
};
enum SlicDataSubtypes {
PubkeySlicData = 190,
PubkeySlicData = 200,
MarkerSlicData,
};
// ME-specific
enum IfwiPartitionSubtypes {
DataIfwiPartition = 200,
DataIfwiPartition = 210,
BootIfwiPartition,
};
enum FptEntrySubtypes {
ValidFptEntry = 210,
ValidFptEntry = 220,
InvalidFptEntry,
};
enum FptPartitionSubtypes {
CodeFptPartition = 220,
CodeFptPartition = 230,
DataFptPartition,
GlutFptPartition,
};
enum CpdPartitionSubtypes {
ManifestCpdPartition = 230,
ManifestCpdPartition = 240,
MetadataCpdPartition,
KeyCpdPartition,
CodeCpdPartition,
};
enum StartupApDataEntrySubtypes {
x86128kStartupApDataEntry = 240,
x86128kStartupApDataEntry = 250,
};
}

View file

@ -33,6 +33,7 @@ SET(PROJECT_SOURCES
../common/ustring.cpp
../common/generated/ami_nvar.cpp
../common/generated/apple_sysf.cpp
../common/generated/dell_dvar.cpp
../common/generated/edk2_vss.cpp
../common/generated/edk2_vss2.cpp
../common/generated/edk2_ftw.cpp