From b98edf694424be3ba1a89c99805adb58f6d7e0c7 Mon Sep 17 00:00:00 2001
From: Nikolaj Schlej <schlej@live.de>
Date: Fri, 28 Feb 2025 17:05:24 +0700
Subject: [PATCH] Add Phoenix EVSA parser

---
 common/generated/phoenix_evsa.cpp | 212 ++++++++++++++++++++++++++
 common/generated/phoenix_evsa.h   | 242 ++++++++++++++++++++++++++++++
 common/ksy/phoenix_evsa.ksy       |  99 ++++++++++++
 common/nvramparser.cpp            |   6 +-
 4 files changed, 556 insertions(+), 3 deletions(-)
 create mode 100644 common/generated/phoenix_evsa.cpp
 create mode 100644 common/generated/phoenix_evsa.h
 create mode 100644 common/ksy/phoenix_evsa.ksy

diff --git a/common/generated/phoenix_evsa.cpp b/common/generated/phoenix_evsa.cpp
new file mode 100644
index 0000000..84bdb85
--- /dev/null
+++ b/common/generated/phoenix_evsa.cpp
@@ -0,0 +1,212 @@
+// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
+
+#include "phoenix_evsa.h"
+#include "../kaitai/exceptions.h"
+
+phoenix_evsa_t::phoenix_evsa_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, phoenix_evsa_t* p__root) : kaitai::kstruct(p__io) {
+    m__parent = p__parent;
+    m__root = this; (void)p__root;
+    m_body = nullptr;
+    m__io__raw_body = nullptr;
+    _read();
+}
+
+void phoenix_evsa_t::_read() {
+    m_type = m__io->read_u1();
+    if (!(type() == 236)) {
+        throw kaitai::validation_not_equal_error<uint8_t>(236, type(), _io(), std::string("/seq/0"));
+    }
+    m_checksum = m__io->read_u1();
+    m_size = m__io->read_u2le();
+    if (!(size() == 20)) {
+        throw kaitai::validation_not_equal_error<uint16_t>(20, size(), _io(), std::string("/seq/2"));
+    }
+    m_signature = m__io->read_u4le();
+    if (!(signature() == 1095980613)) {
+        throw kaitai::validation_not_equal_error<uint32_t>(1095980613, signature(), _io(), std::string("/seq/3"));
+    }
+    m_attributes = m__io->read_u4le();
+    m_store_size = m__io->read_u4le();
+    m_reserved = m__io->read_u4le();
+    m__raw_body = m__io->read_bytes((store_size() - 20));
+    m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
+    m_body = std::unique_ptr<evsa_body_t>(new evsa_body_t(m__io__raw_body.get(), this, m__root));
+}
+
+phoenix_evsa_t::~phoenix_evsa_t() {
+    _clean_up();
+}
+
+void phoenix_evsa_t::_clean_up() {
+}
+
+phoenix_evsa_t::evsa_entry_t::evsa_entry_t(kaitai::kstream* p__io, phoenix_evsa_t::evsa_body_t* p__parent, phoenix_evsa_t* p__root) : kaitai::kstruct(p__io) {
+    m__parent = p__parent;
+    m__root = p__root;
+    _read();
+}
+
+void phoenix_evsa_t::evsa_entry_t::_read() {
+    m_type = m__io->read_u1();
+    m_checksum = m__io->read_u1();
+    m_size = m__io->read_u2le();
+    switch (type()) {
+    case 239: {
+        m_body = std::unique_ptr<evsa_data_t>(new evsa_data_t(m__io, this, m__root));
+        break;
+    }
+    case 131: {
+        m_body = std::unique_ptr<evsa_data_t>(new evsa_data_t(m__io, this, m__root));
+        break;
+    }
+    case 227: {
+        m_body = std::unique_ptr<evsa_data_t>(new evsa_data_t(m__io, this, m__root));
+        break;
+    }
+    case 237: {
+        m_body = std::unique_ptr<evsa_guid_t>(new evsa_guid_t(m__io, this, m__root));
+        break;
+    }
+    case 226: {
+        m_body = std::unique_ptr<evsa_name_t>(new evsa_name_t(m__io, this, m__root));
+        break;
+    }
+    case 225: {
+        m_body = std::unique_ptr<evsa_guid_t>(new evsa_guid_t(m__io, this, m__root));
+        break;
+    }
+    case 238: {
+        m_body = std::unique_ptr<evsa_name_t>(new evsa_name_t(m__io, this, m__root));
+        break;
+    }
+    default: {
+        m_body = std::unique_ptr<evsa_unknown_t>(new evsa_unknown_t(m__io, this, m__root));
+        break;
+    }
+    }
+}
+
+phoenix_evsa_t::evsa_entry_t::~evsa_entry_t() {
+    _clean_up();
+}
+
+void phoenix_evsa_t::evsa_entry_t::_clean_up() {
+}
+
+phoenix_evsa_t::evsa_unknown_t::evsa_unknown_t(kaitai::kstream* p__io, phoenix_evsa_t::evsa_entry_t* p__parent, phoenix_evsa_t* p__root) : kaitai::kstruct(p__io) {
+    m__parent = p__parent;
+    m__root = p__root;
+    _read();
+}
+
+void phoenix_evsa_t::evsa_unknown_t::_read() {
+    m_unknown = m__io->read_bytes(0);
+}
+
+phoenix_evsa_t::evsa_unknown_t::~evsa_unknown_t() {
+    _clean_up();
+}
+
+void phoenix_evsa_t::evsa_unknown_t::_clean_up() {
+}
+
+phoenix_evsa_t::evsa_body_t::evsa_body_t(kaitai::kstream* p__io, phoenix_evsa_t* p__parent, phoenix_evsa_t* p__root) : kaitai::kstruct(p__io) {
+    m__parent = p__parent;
+    m__root = p__root;
+    m_entries = nullptr;
+    _read();
+}
+
+void phoenix_evsa_t::evsa_body_t::_read() {
+    m_entries = std::unique_ptr<std::vector<std::unique_ptr<evsa_entry_t>>>(new std::vector<std::unique_ptr<evsa_entry_t>>());
+    {
+        int i = 0;
+        while (!m__io->is_eof()) {
+            m_entries->push_back(std::move(std::unique_ptr<evsa_entry_t>(new evsa_entry_t(m__io, this, m__root))));
+            i++;
+        }
+    }
+}
+
+phoenix_evsa_t::evsa_body_t::~evsa_body_t() {
+    _clean_up();
+}
+
+void phoenix_evsa_t::evsa_body_t::_clean_up() {
+}
+
+phoenix_evsa_t::evsa_name_t::evsa_name_t(kaitai::kstream* p__io, phoenix_evsa_t::evsa_entry_t* p__parent, phoenix_evsa_t* p__root) : kaitai::kstruct(p__io) {
+    m__parent = p__parent;
+    m__root = p__root;
+    _read();
+}
+
+void phoenix_evsa_t::evsa_name_t::_read() {
+    m_var_id = m__io->read_u2le();
+    m_name = m__io->read_bytes((_parent()->size() - 6));
+}
+
+phoenix_evsa_t::evsa_name_t::~evsa_name_t() {
+    _clean_up();
+}
+
+void phoenix_evsa_t::evsa_name_t::_clean_up() {
+}
+
+phoenix_evsa_t::evsa_guid_t::evsa_guid_t(kaitai::kstream* p__io, phoenix_evsa_t::evsa_entry_t* p__parent, phoenix_evsa_t* p__root) : kaitai::kstruct(p__io) {
+    m__parent = p__parent;
+    m__root = p__root;
+    _read();
+}
+
+void phoenix_evsa_t::evsa_guid_t::_read() {
+    m_guid_id = m__io->read_u2le();
+    m_guid = m__io->read_bytes(16);
+}
+
+phoenix_evsa_t::evsa_guid_t::~evsa_guid_t() {
+    _clean_up();
+}
+
+void phoenix_evsa_t::evsa_guid_t::_clean_up() {
+}
+
+phoenix_evsa_t::evsa_data_t::evsa_data_t(kaitai::kstream* p__io, phoenix_evsa_t::evsa_entry_t* p__parent, phoenix_evsa_t* p__root) : kaitai::kstruct(p__io) {
+    m__parent = p__parent;
+    m__root = p__root;
+    _read();
+}
+
+void phoenix_evsa_t::evsa_data_t::_read() {
+    m_guid_id = m__io->read_u2le();
+    m_var_id = m__io->read_u2le();
+    m_attributes = m__io->read_u4le();
+    n_data_size = true;
+    if ((attributes() & 268435456) != 268435456) {
+        n_data_size = false;
+        m_data_size = m__io->read_u4le();
+    }
+    n_data = true;
+    if ((attributes() & 268435456) == 268435456) {
+        n_data = false;
+        m_data = m__io->read_bytes((_parent()->size() - 12));
+    }
+    n_data_ext = true;
+    if ((attributes() & 268435456) != 268435456) {
+        n_data_ext = false;
+        m_data_ext = m__io->read_bytes(data_size());
+    }
+}
+
+phoenix_evsa_t::evsa_data_t::~evsa_data_t() {
+    _clean_up();
+}
+
+void phoenix_evsa_t::evsa_data_t::_clean_up() {
+    if (!n_data_size) {
+    }
+    if (!n_data) {
+    }
+    if (!n_data_ext) {
+    }
+}
diff --git a/common/generated/phoenix_evsa.h b/common/generated/phoenix_evsa.h
new file mode 100644
index 0000000..af94762
--- /dev/null
+++ b/common/generated/phoenix_evsa.h
@@ -0,0 +1,242 @@
+#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 phoenix_evsa_t : public kaitai::kstruct {
+
+public:
+    class evsa_entry_t;
+    class evsa_unknown_t;
+    class evsa_body_t;
+    class evsa_name_t;
+    class evsa_guid_t;
+    class evsa_data_t;
+
+    phoenix_evsa_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, phoenix_evsa_t* p__root = nullptr);
+
+private:
+    void _read();
+    void _clean_up();
+
+public:
+    ~phoenix_evsa_t();
+
+    class evsa_entry_t : public kaitai::kstruct {
+
+    public:
+
+        evsa_entry_t(kaitai::kstream* p__io, phoenix_evsa_t::evsa_body_t* p__parent = nullptr, phoenix_evsa_t* p__root = nullptr);
+
+    private:
+        void _read();
+        void _clean_up();
+
+    public:
+        ~evsa_entry_t();
+
+    private:
+        uint8_t m_type;
+        uint8_t m_checksum;
+        uint16_t m_size;
+        std::unique_ptr<kaitai::kstruct> m_body;
+        phoenix_evsa_t* m__root;
+        phoenix_evsa_t::evsa_body_t* m__parent;
+
+    public:
+        uint8_t type() const { return m_type; }
+        uint8_t checksum() const { return m_checksum; }
+        uint16_t size() const { return m_size; }
+        kaitai::kstruct* body() const { return m_body.get(); }
+        phoenix_evsa_t* _root() const { return m__root; }
+        phoenix_evsa_t::evsa_body_t* _parent() const { return m__parent; }
+    };
+
+    class evsa_unknown_t : public kaitai::kstruct {
+
+    public:
+
+        evsa_unknown_t(kaitai::kstream* p__io, phoenix_evsa_t::evsa_entry_t* p__parent = nullptr, phoenix_evsa_t* p__root = nullptr);
+
+    private:
+        void _read();
+        void _clean_up();
+
+    public:
+        ~evsa_unknown_t();
+
+    private:
+        std::string m_unknown;
+        phoenix_evsa_t* m__root;
+        phoenix_evsa_t::evsa_entry_t* m__parent;
+
+    public:
+        std::string unknown() const { return m_unknown; }
+        phoenix_evsa_t* _root() const { return m__root; }
+        phoenix_evsa_t::evsa_entry_t* _parent() const { return m__parent; }
+    };
+
+    class evsa_body_t : public kaitai::kstruct {
+
+    public:
+
+        evsa_body_t(kaitai::kstream* p__io, phoenix_evsa_t* p__parent = nullptr, phoenix_evsa_t* p__root = nullptr);
+
+    private:
+        void _read();
+        void _clean_up();
+
+    public:
+        ~evsa_body_t();
+
+    private:
+        std::unique_ptr<std::vector<std::unique_ptr<evsa_entry_t>>> m_entries;
+        phoenix_evsa_t* m__root;
+        phoenix_evsa_t* m__parent;
+
+    public:
+        std::vector<std::unique_ptr<evsa_entry_t>>* entries() const { return m_entries.get(); }
+        phoenix_evsa_t* _root() const { return m__root; }
+        phoenix_evsa_t* _parent() const { return m__parent; }
+    };
+
+    class evsa_name_t : public kaitai::kstruct {
+
+    public:
+
+        evsa_name_t(kaitai::kstream* p__io, phoenix_evsa_t::evsa_entry_t* p__parent = nullptr, phoenix_evsa_t* p__root = nullptr);
+
+    private:
+        void _read();
+        void _clean_up();
+
+    public:
+        ~evsa_name_t();
+
+    private:
+        uint16_t m_var_id;
+        std::string m_name;
+        phoenix_evsa_t* m__root;
+        phoenix_evsa_t::evsa_entry_t* m__parent;
+
+    public:
+        uint16_t var_id() const { return m_var_id; }
+        std::string name() const { return m_name; }
+        phoenix_evsa_t* _root() const { return m__root; }
+        phoenix_evsa_t::evsa_entry_t* _parent() const { return m__parent; }
+    };
+
+    class evsa_guid_t : public kaitai::kstruct {
+
+    public:
+
+        evsa_guid_t(kaitai::kstream* p__io, phoenix_evsa_t::evsa_entry_t* p__parent = nullptr, phoenix_evsa_t* p__root = nullptr);
+
+    private:
+        void _read();
+        void _clean_up();
+
+    public:
+        ~evsa_guid_t();
+
+    private:
+        uint16_t m_guid_id;
+        std::string m_guid;
+        phoenix_evsa_t* m__root;
+        phoenix_evsa_t::evsa_entry_t* m__parent;
+
+    public:
+        uint16_t guid_id() const { return m_guid_id; }
+        std::string guid() const { return m_guid; }
+        phoenix_evsa_t* _root() const { return m__root; }
+        phoenix_evsa_t::evsa_entry_t* _parent() const { return m__parent; }
+    };
+
+    class evsa_data_t : public kaitai::kstruct {
+
+    public:
+
+        evsa_data_t(kaitai::kstream* p__io, phoenix_evsa_t::evsa_entry_t* p__parent = nullptr, phoenix_evsa_t* p__root = nullptr);
+
+    private:
+        void _read();
+        void _clean_up();
+
+    public:
+        ~evsa_data_t();
+
+    private:
+        uint16_t m_guid_id;
+        uint16_t m_var_id;
+        uint32_t m_attributes;
+        uint32_t m_data_size;
+        bool n_data_size;
+
+    public:
+        bool _is_null_data_size() { data_size(); return n_data_size; };
+
+    private:
+        std::string m_data;
+        bool n_data;
+
+    public:
+        bool _is_null_data() { data(); return n_data; };
+
+    private:
+        std::string m_data_ext;
+        bool n_data_ext;
+
+    public:
+        bool _is_null_data_ext() { data_ext(); return n_data_ext; };
+
+    private:
+        phoenix_evsa_t* m__root;
+        phoenix_evsa_t::evsa_entry_t* m__parent;
+
+    public:
+        uint16_t guid_id() const { return m_guid_id; }
+        uint16_t var_id() const { return m_var_id; }
+        uint32_t attributes() const { return m_attributes; }
+        uint32_t data_size() const { return m_data_size; }
+        std::string data() const { return m_data; }
+        std::string data_ext() const { return m_data_ext; }
+        phoenix_evsa_t* _root() const { return m__root; }
+        phoenix_evsa_t::evsa_entry_t* _parent() const { return m__parent; }
+    };
+
+private:
+    uint8_t m_type;
+    uint8_t m_checksum;
+    uint16_t m_size;
+    uint32_t m_signature;
+    uint32_t m_attributes;
+    uint32_t m_store_size;
+    uint32_t m_reserved;
+    std::unique_ptr<evsa_body_t> m_body;
+    phoenix_evsa_t* m__root;
+    kaitai::kstruct* m__parent;
+    std::string m__raw_body;
+    std::unique_ptr<kaitai::kstream> m__io__raw_body;
+
+public:
+    uint8_t type() const { return m_type; }
+    uint8_t checksum() const { return m_checksum; }
+    uint16_t size() const { return m_size; }
+    uint32_t signature() const { return m_signature; }
+    uint32_t attributes() const { return m_attributes; }
+    uint32_t store_size() const { return m_store_size; }
+    uint32_t reserved() const { return m_reserved; }
+    evsa_body_t* body() const { return m_body.get(); }
+    phoenix_evsa_t* _root() const { return m__root; }
+    kaitai::kstruct* _parent() const { return m__parent; }
+    std::string _raw_body() const { return m__raw_body; }
+    kaitai::kstream* _io__raw_body() const { return m__io__raw_body.get(); }
+};
diff --git a/common/ksy/phoenix_evsa.ksy b/common/ksy/phoenix_evsa.ksy
new file mode 100644
index 0000000..d680ebd
--- /dev/null
+++ b/common/ksy/phoenix_evsa.ksy
@@ -0,0 +1,99 @@
+meta:
+  id: phoenix_evsa
+  title: Phoenix EVSA NVRAM store
+  application: Phoenix-based UEFI firmware
+  file-extension: evsa
+  tags:
+    - firmware
+  license: CC0-1.0
+  ks-version: 0.9
+  endian: le
+  
+seq:
+- id: type
+  type: u1
+  valid: 0xEC
+- id: checksum
+  type: u1
+- id: size
+  type: u2
+  valid: 20
+- id: signature
+  type: u4
+  valid: 0x41535645
+- id: attributes
+  type: u4
+- id: store_size
+  type: u4
+- id: reserved
+  type: u4
+- id: body
+  type: evsa_body
+  size: store_size - 20
+  
+types:
+  evsa_guid:
+   seq:
+   - id: guid_id
+     type: u2
+   - id: guid
+     size: 16
+
+  evsa_name:
+   seq:
+   - id: var_id
+     type: u2
+   - id: name
+     size: _parent.size - 6
+
+  evsa_data:
+   seq:
+   - id: guid_id
+     type: u2
+   - id: var_id
+     type: u2
+   - id: attributes
+     type: u4
+   - id: data_size
+     type: u4
+     if: (attributes & 0x10000000) != 0x10000000
+   - id: data
+     size:  _parent.size - 12
+     if: (attributes & 0x10000000) == 0x10000000
+   - id: data_ext
+     size: data_size
+     if: (attributes & 0x10000000) != 0x10000000
+
+  evsa_unknown:
+   seq:
+   - id: unknown 
+     size: 0
+     
+  evsa_entry:
+   seq:
+   - id: type
+     type: u1
+   - id: checksum
+     type: u1
+   - id: size
+     type: u2
+   - id: body
+     type:
+      switch-on: type
+      cases:
+        0xED: evsa_guid
+        0xE1: evsa_guid
+        0xEE: evsa_name
+        0xE2: evsa_name
+        0xEF: evsa_data
+        0xE3: evsa_data
+        0x83: evsa_data
+        _:    evsa_unknown
+        
+  evsa_body:
+   seq:
+   - id: entries
+     type: evsa_entry
+     repeat: eos
+        
+        
\ No newline at end of file
diff --git a/common/nvramparser.cpp b/common/nvramparser.cpp
index ab48b9d..7e36c59 100644
--- a/common/nvramparser.cpp
+++ b/common/nvramparser.cpp
@@ -396,7 +396,7 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32
                     // Add free space or padding after all variables, if needed
                     UINT32 freeSpaceOffset = vssVariableOffset - storeOffset;
                     if (freeSpaceOffset < storeSize) {
-                        UByteArray freeSpace = vss.mid(freeSpaceOffset, storeSize - freeSpaceOffset);
+                        UByteArray freeSpace = volumeBody.mid(freeSpaceOffset, storeSize - freeSpaceOffset);
                         // Add info
                         info = usprintf("Full size: %Xh (%u)", (UINT32)freeSpace.size(), (UINT32)freeSpace.size());
                         
@@ -582,7 +582,7 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32
                     // Add free space or padding after all variables, if needed
                     UINT32 freeSpaceOffset = vss2VariableOffset - storeOffset;
                     if (freeSpaceOffset < storeSize) {
-                        UByteArray freeSpace = vss2.mid(freeSpaceOffset, storeSize - freeSpaceOffset);
+                        UByteArray freeSpace = volumeBody.mid(freeSpaceOffset, storeSize - freeSpaceOffset);
                         // Add info
                         info = usprintf("Full size: %Xh (%u)", (UINT32)freeSpace.size(), (UINT32)freeSpace.size());
                         
@@ -872,7 +872,7 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32
             // Add free space or padding after all variables, if needed
             UINT32 freeSpaceOffset = sysfVariableOffset - storeOffset;
             if (freeSpaceOffset < storeSize) {
-                UByteArray freeSpace = sysf.mid(freeSpaceOffset, storeSize - freeSpaceOffset);
+                UByteArray freeSpace = volumeBody.mid(freeSpaceOffset, storeSize - freeSpaceOffset);
                 // Add info
                 info = usprintf("Full size: %Xh (%u)", (UINT32)freeSpace.size(), (UINT32)freeSpace.size());