diff --git a/UEFITool/ffsfinder.cpp b/UEFITool/ffsfinder.cpp
index fb8700d..fd29670 100644
--- a/UEFITool/ffsfinder.cpp
+++ b/UEFITool/ffsfinder.cpp
@@ -156,7 +156,7 @@ STATUS FfsFinder::findGuidPattern(const QModelIndex & index, const QByteArray &
     return ERR_SUCCESS;
 }
 
-STATUS FfsFinder::findTextPattern(const QModelIndex & index, const QString & pattern, const bool unicode, const Qt::CaseSensitivity caseSensitive)
+STATUS FfsFinder::findTextPattern(const QModelIndex & index, const QString & pattern, const UINT8 mode, const bool unicode, const Qt::CaseSensitivity caseSensitive)
 {
     if (pattern.isEmpty())
         return ERR_INVALID_PARAMETER;
@@ -166,24 +166,36 @@ STATUS FfsFinder::findTextPattern(const QModelIndex & index, const QString & pat
 
     bool hasChildren = (model->rowCount(index) > 0);
     for (int i = 0; i < model->rowCount(index); i++) {
-        findTextPattern(index.child(i, index.column()), pattern, unicode, caseSensitive);
+        findTextPattern(index.child(i, index.column()), pattern, mode, unicode, caseSensitive);
     }
 
-    if (hasChildren)
-        return ERR_SUCCESS;
+    QByteArray body;
+    if (hasChildren) {
+        if (mode != SEARCH_MODE_BODY)
+            body = model->header(index);
+    }
+    else {
+        if (mode == SEARCH_MODE_HEADER)
+            body.append(model->header(index));
+        else if (mode == SEARCH_MODE_BODY)
+            body.append(model->body(index));
+        else
+            body.append(model->header(index)).append(model->body(index));
+    }
 
     QString data;
     if (unicode)
-        data = QString::fromUtf16((const ushort*)model->body(index).data(), model->body(index).length() / 2);
+        data = QString::fromUtf16((const ushort*)body.constData(), body.length() / 2);
     else
-        data = QString::fromLatin1((const char*)model->body(index).data(), model->body(index).length());
+        data = QString::fromLatin1((const char*)body.constData(), body.length());
 
     int offset = -1;
     while ((offset = data.indexOf(pattern, offset + 1, caseSensitive)) >= 0) {
-        msg(QObject::tr("%1 text \"%2\" found in %3 at offset %4h")
+        msg(QObject::tr("%1 text \"%2\" found in %3 at %4-offset %5h")
             .arg(unicode ? "Unicode" : "ASCII")
             .arg(pattern)
             .arg(model->name(index))
+            .arg(mode == SEARCH_MODE_BODY ? QObject::tr("body") : QObject::tr("header"))
             .hexarg(unicode ? offset * 2 : offset),
             index);
     }
diff --git a/UEFITool/ffsfinder.h b/UEFITool/ffsfinder.h
index 5863399..789d1e0 100644
--- a/UEFITool/ffsfinder.h
+++ b/UEFITool/ffsfinder.h
@@ -36,7 +36,7 @@ public:
 	
     STATUS findHexPattern(const QModelIndex & index, const QByteArray & hexPattern, const UINT8 mode);
     STATUS findGuidPattern(const QModelIndex & index, const QByteArray & guidPattern, const UINT8 mode);
-    STATUS findTextPattern(const QModelIndex & index, const QString & pattern, const bool unicode, const Qt::CaseSensitivity caseSensitive);
+    STATUS findTextPattern(const QModelIndex & index, const QString & pattern, const UINT8 mode, const bool unicode, const Qt::CaseSensitivity caseSensitive);
 	
 private:
     const TreeModel* model;
diff --git a/UEFITool/searchdialog.ui b/UEFITool/searchdialog.ui
index 6442853..510a46f 100644
--- a/UEFITool/searchdialog.ui
+++ b/UEFITool/searchdialog.ui
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>400</width>
-    <height>237</height>
+    <height>218</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -143,20 +143,66 @@
       <layout class="QGridLayout" name="gridLayout_3">
        <item row="0" column="0">
         <widget class="QLabel" name="textLabel">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
          <property name="text">
           <string>Text:</string>
          </property>
         </widget>
        </item>
-       <item row="0" column="1">
-        <widget class="QLineEdit" name="textEdit"/>
+       <item row="0" column="1" colspan="2">
+        <widget class="QLineEdit" name="textEdit">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+        </widget>
        </item>
        <item row="1" column="0" colspan="2">
+        <widget class="QGroupBox" name="hexGroupBox_2">
+         <property name="title">
+          <string>Search scope</string>
+         </property>
+         <layout class="QVBoxLayout" name="verticalLayout_4">
+          <item>
+           <widget class="QRadioButton" name="textScopeFullRadioButton">
+            <property name="text">
+             <string>Header and body</string>
+            </property>
+            <property name="checked">
+             <bool>true</bool>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QRadioButton" name="textScopeHeaderRadioButton">
+            <property name="text">
+             <string>Header only</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QRadioButton" name="textScopeBodyRadioButton">
+            <property name="text">
+             <string>Body only</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item row="1" column="2">
         <widget class="QGroupBox" name="textGroupBox">
          <property name="title">
           <string>Text search options</string>
          </property>
-         <layout class="QVBoxLayout" name="verticalLayout_4">
+         <layout class="QVBoxLayout" name="verticalLayout_2">
           <item>
            <widget class="QCheckBox" name="textUnicodeCheckBox">
             <property name="text">
diff --git a/UEFITool/uefitool.cpp b/UEFITool/uefitool.cpp
index 7cbb2bb..d3febd1 100644
--- a/UEFITool/uefitool.cpp
+++ b/UEFITool/uefitool.cpp
@@ -17,7 +17,7 @@
 UEFITool::UEFITool(QWidget *parent) :
 QMainWindow(parent),
 ui(new Ui::UEFITool), 
-version(tr("0.30.0_alpha23"))
+version(tr("0.30.0_alpha24"))
 {
     clipboard = QApplication::clipboard();
 
@@ -175,8 +175,9 @@ void UEFITool::populateUi(const QModelIndex &current)
     ui->menuVolumeActions->setEnabled(type == Types::Volume);
     ui->menuFileActions->setEnabled(type == Types::File);
     ui->menuSectionActions->setEnabled(type == Types::Section);
-    ui->menuVariableActions->setEnabled(type == Types::NvramVariableNvar || type == Types::NvramVariableVss);
-
+    ui->menuVariableActions->setEnabled(type == Types::NvramVariableNvar || type == Types::NvramVariableVss || type == Types::NvramVariableFsys);
+    ui->menuStorageActions->setEnabled(type == Types::NvramStorageVss || type == Types::NvramStorageFdc || type == Types::NvramStorageFsys);
+    
     // Enable actions
     ui->actionExtract->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current));
     ui->actionGoToData->setEnabled(type == Types::NvramVariableNvar && subtype == Subtypes::LinkNvar);
@@ -267,8 +268,14 @@ void UEFITool::search()
         QString pattern = searchDialog->ui->textEdit->text();
         if (pattern.isEmpty())
             return;
-
-        ffsFinder->findTextPattern(rootIndex, pattern, searchDialog->ui->textUnicodeCheckBox->isChecked(),
+        UINT8 mode;
+        if (searchDialog->ui->textScopeHeaderRadioButton->isChecked())
+            mode = SEARCH_MODE_HEADER;
+        else if (searchDialog->ui->textScopeBodyRadioButton->isChecked())
+            mode = SEARCH_MODE_BODY;
+        else
+            mode = SEARCH_MODE_ALL;
+        ffsFinder->findTextPattern(rootIndex, pattern, mode, searchDialog->ui->textUnicodeCheckBox->isChecked(),
             (Qt::CaseSensitivity) searchDialog->ui->textCaseSensitiveCheckBox->isChecked());
         showFinderMessages();
     }
@@ -537,8 +544,12 @@ void UEFITool::extract(const UINT8 mode)
             path = QFileDialog::getSaveFileName(this, tr("Save variable to file"), name + ".var", "Variable files (*.var *.bin);;All files (*)");
             break;
         case Types::NvramStorageVss:
+        case Types::NvramStorageFdc:
             path = QFileDialog::getSaveFileName(this, tr("Save variable storage to file"), name + ".vss", "Variable storage files (*.vss *.bin);;All files (*)");
             break;
+        case Types::NvramStorageFsys:
+            path = QFileDialog::getSaveFileName(this, tr("Save Fsys storage to file"), name + ".fsys", "Fsys storage files (*.fsys *.bin);;All files (*)");
+            break;
         default:
             path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
         }
@@ -576,8 +587,12 @@ void UEFITool::extract(const UINT8 mode)
             path = QFileDialog::getSaveFileName(this, tr("Save variable body to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
             break;
         case Types::NvramStorageVss:
+        case Types::NvramStorageFdc:
             path = QFileDialog::getSaveFileName(this, tr("Save variable storage body to file"), name + ".vsb", "Variable storage body files (*.vsb *.bin);;All files (*)");
             break;
+        case Types::NvramStorageFsys:
+            path = QFileDialog::getSaveFileName(this, tr("Save Fsys storage body to file"), name + ".fsb", "Fsys storage body files (*.fsb *.bin);;All files (*)");
+            break;
         default:
             path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
         }
@@ -941,9 +956,12 @@ void UEFITool::contextMenuEvent(QContextMenuEvent* event)
         break;
     case Types::NvramVariableNvar:
     case Types::NvramVariableVss:
+    case Types::NvramVariableFsys:
         ui->menuVariableActions->exec(event->globalPos());
         break;
     case Types::NvramStorageVss:
+    case Types::NvramStorageFdc:
+    case Types::NvramStorageFsys:
         ui->menuStorageActions->exec(event->globalPos());
         break;
     }
diff --git a/common/ffs.h b/common/ffs.h
index 4ea0b51..a53a641 100644
--- a/common/ffs.h
+++ b/common/ffs.h
@@ -113,7 +113,7 @@ typedef struct _EFI_FIRMWARE_VOLUME_HEADER {
     UINT16                 ExtHeaderOffset;  //Reserved in Revision 1
     UINT8                  Reserved;
     UINT8                  Revision;
-    //EFI_FV_BLOCK_MAP_ENTRY FvBlockMap[1];
+    //EFI_FV_BLOCK_MAP_ENTRY FvBlockMap[2];
 } EFI_FIRMWARE_VOLUME_HEADER;
 
 // Standard file system GUIDs
diff --git a/common/ffsops.cpp b/common/ffsops.cpp
index 8b4bb87..6af8792 100644
--- a/common/ffsops.cpp
+++ b/common/ffsops.cpp
@@ -74,6 +74,8 @@ STATUS FfsOperations::extract(const QModelIndex & index, QString & name, QByteAr
     case Types::Region:
     case Types::Padding:
     case Types::NvramStorageVss:
+    case Types::NvramStorageFdc:
+    case Types::NvramStorageFsys:
     default:
         name = itemName.replace(' ', '_').replace('/', '_');
     }
diff --git a/common/ffsparser.cpp b/common/ffsparser.cpp
index d0e89f9..2c69eee 100644
--- a/common/ffsparser.cpp
+++ b/common/ffsparser.cpp
@@ -3364,8 +3364,12 @@ STATUS FfsParser::parseStorageArea(const QByteArray & data, const QModelIndex &
         QModelIndex current = index.child(i, 0);
         switch (model->type(current)) {
         case Types::NvramStorageVss:
+        case Types::NvramStorageFdc:
             parseVssStorageBody(current);
             break;
+        case Types::NvramStorageFsys:
+            parseFsysStorageBody(current);
+            break;
         case Types::Padding:
             // No parsing required
             break;
@@ -3402,16 +3406,21 @@ STATUS FfsParser::findNextStorage(const QModelIndex & index, const QByteArray &
             //    msg(QObject::tr("findNextStorage: VSS storage candidate at offset %1h skipped, has invalid state %2h").hexarg(parentOffset + offset).hexarg2(vssHeader->State, 2), index);
             //    continue;
             //}
+
             // All checks passed, storage found
             break;
         }
-        //else if (*currentPos == NVRAM_APPLE_FSYS_STORE_SIGNATURE) { //Fsys signature found
-        //  // No checks yet
-        //  break;
-        //}
+        else if (*currentPos == NVRAM_FDC_VOLUME_SIGNATURE) { //FDC signature found
+          // No checks needed
+          break;
+        }
+        else if (*currentPos == NVRAM_APPLE_FSYS_STORE_SIGNATURE) { //Fsys signature found
+          // No checks needed
+          break;
+        }
     }
     // No more storages found
-    if (offset == dataSize - sizeof(UINT32))
+    if (offset >= dataSize - sizeof(UINT32))
         return ERR_STORAGES_NOT_FOUND;
 
     nextStorageOffset = offset;
@@ -3421,66 +3430,198 @@ STATUS FfsParser::findNextStorage(const QModelIndex & index, const QByteArray &
 
 STATUS FfsParser::getStorageSize(const QByteArray & data, const UINT32 storageOffset, UINT32 & storageSize)
 {
-    //TODO: add Fsys, GUID and _FDC support
-    const VSS_VARIABLE_STORE_HEADER* vssHeader = (const VSS_VARIABLE_STORE_HEADER*)(data.constData() + storageOffset);
-    storageSize = vssHeader->Size;
+    //TODO: add GUID support
+    const UINT32* signature = (const UINT32*)(data.constData() + storageOffset);
+    if (*signature == NVRAM_VSS_STORE_SIGNATURE || *signature == NVRAM_APPLE_SVS_STORE_SIGNATURE) {
+        const VSS_VARIABLE_STORE_HEADER* vssHeader = (const VSS_VARIABLE_STORE_HEADER*)signature;
+        storageSize = vssHeader->Size;
+    }
+    else if (*signature == NVRAM_FDC_VOLUME_SIGNATURE) {
+        const FDC_VOLUME_HEADER* fdcHeader = (const FDC_VOLUME_HEADER*)signature;
+        storageSize = fdcHeader->Size;
+    }
+    else if (*signature == NVRAM_APPLE_FSYS_STORE_SIGNATURE) {
+        const APPLE_FSYS_STORE_HEADER* fsysHeader = (const APPLE_FSYS_STORE_HEADER*)signature;
+        storageSize = fsysHeader->Size;
+    }
     return ERR_SUCCESS;
 }
 
 STATUS FfsParser::parseStorageHeader(const QByteArray & storage, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
 {
-    // Parse VSS volume like raw area, seen for now
-    // $VSS, $SVS, Fsys, full volume GUID, _FDC and paddings 
+    // Parse VSS volume like raw area
+    //TODO: seen for now - $VSS, $SVS, Fsys, full volume GUID, _FDC and paddings 
 
-    // The volume must begin with VSS storage to be valid, but after the first one, there can be many variants
     const UINT32 dataSize = (UINT32)storage.size();
-    if (dataSize < sizeof(VSS_VARIABLE_STORE_HEADER)) {
-        msg(QObject::tr("parseStorageHeader: volume body is too small even for VSS storage header"), parent);
+    const UINT32* signature = (const UINT32*)storage.constData();
+    if (dataSize < sizeof(UINT32)) {
+        msg(QObject::tr("parseStorageHeader: volume body is too small even for storage signature"), parent);
         return ERR_SUCCESS;
     }
 
-    // Get VSS storage header
-    const VSS_VARIABLE_STORE_HEADER* vssStorageHeader = (const VSS_VARIABLE_STORE_HEADER*)storage.constData();
+    // VSS variable storages
+    if (*signature == NVRAM_VSS_STORE_SIGNATURE || *signature == NVRAM_APPLE_SVS_STORE_SIGNATURE) {
+        // The volume must begin with a storage to be valid, but after the first one, there can be many variants
+        if (dataSize < sizeof(VSS_VARIABLE_STORE_HEADER)) {
+            msg(QObject::tr("parseStorageHeader: volume body is too small even for VSS storage header"), parent);
+            return ERR_SUCCESS;
+        }
 
-    // Check signature
-    if (vssStorageHeader->Signature != NVRAM_VSS_STORE_SIGNATURE && vssStorageHeader->Signature != NVRAM_APPLE_SVS_STORE_SIGNATURE) {
-        msg(QObject::tr("parseStorageHeader: invalid storage signature %1h").hexarg2(vssStorageHeader->Signature, 8), parent);
-        return ERR_SUCCESS;
+        // Get VSS storage header
+        const VSS_VARIABLE_STORE_HEADER* vssStorageHeader = (const VSS_VARIABLE_STORE_HEADER*)signature;
+
+        // Check storage size
+        if (dataSize < vssStorageHeader->Size) {
+            msg(QObject::tr("parseStorageHeader: VSS storage size %1h (%2) is greater than volume body size %3h (%4)")
+                .hexarg2(vssStorageHeader->Size, 8).arg(vssStorageHeader->Size)
+                .hexarg2(dataSize, 8).arg(dataSize), parent);
+            return ERR_SUCCESS;
+        }
+
+        // Get parsing data
+        PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
+
+        // Construct header and body
+        QByteArray header = storage.left(sizeof(VSS_VARIABLE_STORE_HEADER));
+        QByteArray body = storage.mid(sizeof(VSS_VARIABLE_STORE_HEADER), vssStorageHeader->Size - sizeof(VSS_VARIABLE_STORE_HEADER));
+
+        // Add info
+        QString name = QObject::tr("VSS storage");
+        QString info = QObject::tr("Signature: %1h\nFull size: %2h (%3)\nHeader size: %4h (%5)\nBody size: %6h (%7)\nFormat: %8h\nState: %9h")
+            .hexarg2(vssStorageHeader->Signature, 8)
+            .hexarg(vssStorageHeader->Size).arg(vssStorageHeader->Size)
+            .hexarg(header.size()).arg(header.size())
+            .hexarg(body.size()).arg(body.size())
+            .hexarg2(vssStorageHeader->Format, 2)
+            .hexarg2(vssStorageHeader->State, 2);
+
+        // Add unknown field for $SVS storages
+        if (*signature == NVRAM_APPLE_SVS_STORE_SIGNATURE)
+            info += QObject::tr("\nUnknown: %1h").hexarg2(vssStorageHeader->Unknown, 4);
+
+        // Add correct offset
+        pdata.offset = parentOffset;
+
+        // Add tree item
+        index = model->addItem(Types::NvramStorageVss, 0, name, QString(), info, header, body, TRUE, parsingDataToQByteArray(pdata), parent);
     }
+    else if (*signature == NVRAM_FDC_VOLUME_SIGNATURE) {
+        // The volume must begin with a storage to be valid, but after the first one, there can be many variants
+        if (dataSize < sizeof(FDC_VOLUME_HEADER)) {
+            msg(QObject::tr("parseStorageHeader: volume body is too small even for FDC storage header"), parent);
+            return ERR_SUCCESS;
+        }
 
-    // Check storage size
-    if (dataSize < vssStorageHeader->Size) {
-        msg(QObject::tr("parseStorageHeader: first VSS storage size %1h (%2) is greater than volume body size %3h (%4)")
-            .hexarg2(vssStorageHeader->Size, 8).arg(vssStorageHeader->Size)
-            .hexarg2(dataSize, 8).arg(dataSize), parent);
-        return ERR_SUCCESS;
+        // Get VSS storage header
+        const FDC_VOLUME_HEADER* fdcStorageHeader = (const FDC_VOLUME_HEADER*)signature;
+
+        // Check storage size
+        if (dataSize < fdcStorageHeader->Size) {
+            msg(QObject::tr("parseStorageHeader: FDC storage size %1h (%2) is greater than volume body size %3h (%4)")
+                .hexarg2(fdcStorageHeader->Size, 8).arg(fdcStorageHeader->Size)
+                .hexarg2(dataSize, 8).arg(dataSize), parent);
+            return ERR_SUCCESS;
+        }
+
+        // Determine internal volume header size
+        const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(fdcStorageHeader + 1);
+        UINT32 headerSize;
+        if (volumeHeader->Revision > 1 && volumeHeader->ExtHeaderOffset) {
+            const EFI_FIRMWARE_VOLUME_EXT_HEADER* extendedHeader = (const EFI_FIRMWARE_VOLUME_EXT_HEADER*)((const UINT8*)volumeHeader + volumeHeader->ExtHeaderOffset);
+            headerSize = volumeHeader->ExtHeaderOffset + extendedHeader->ExtHeaderSize;
+        }
+        else
+            headerSize = volumeHeader->HeaderLength;
+
+        // Extended header end can be unaligned
+        headerSize = ALIGN8(headerSize);
+
+        // Add VSS storage header
+        headerSize += sizeof(VSS_VARIABLE_STORE_HEADER);
+        
+        // Add FDC header 
+        headerSize += sizeof(FDC_VOLUME_HEADER);
+
+        // Check sanity of combined header size
+        if (dataSize < headerSize) {
+            msg(QObject::tr("parseStorageHeader: FDC storage header size %1h (%2) is greater than volume body size %3h (%4)")
+                .hexarg2(fdcStorageHeader->Size, 8).arg(fdcStorageHeader->Size)
+                .hexarg2(dataSize, 8).arg(dataSize), parent);
+            return ERR_SUCCESS;
+        }
+
+        // Get parsing data
+        PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
+
+        // Construct header and body
+        QByteArray header = storage.left(headerSize);
+        QByteArray body = storage.mid(headerSize, fdcStorageHeader->Size - headerSize);
+
+        // Add info
+        QString name = QObject::tr("FDC storage");
+        QString info = QObject::tr("Signature: %1h\nFull size: %2h (%3)\nHeader size: %4h (%5)\nBody size: %6h (%7)")
+            .hexarg2(fdcStorageHeader->Signature, 8)
+            .hexarg(fdcStorageHeader->Size).arg(fdcStorageHeader->Size)
+            .hexarg(header.size()).arg(header.size())
+            .hexarg(body.size()).arg(body.size());
+
+        // TODO: add internal headers info
+
+        // Add correct offset
+        pdata.offset = parentOffset;
+
+        // Add tree item
+        index = model->addItem(Types::NvramStorageFdc, 0, name, QString(), info, header, body, TRUE, parsingDataToQByteArray(pdata), parent);
     }
+    else if (*signature == NVRAM_APPLE_FSYS_STORE_SIGNATURE) {
+        // The volume must begin with a storage to be valid, but after the first one, there can be many variants
+        if (dataSize < sizeof(APPLE_FSYS_STORE_HEADER)) {
+            msg(QObject::tr("parseStorageHeader: volume body is too small even for Fsys storage header"), parent);
+            return ERR_SUCCESS;
+        }
 
-    // Get parsing data
-    PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
+        // Get Fsys storage header
+        const APPLE_FSYS_STORE_HEADER* fsysStorageHeader = (const APPLE_FSYS_STORE_HEADER*)signature;
 
-    // Construct header and body
-    QByteArray header = storage.left(sizeof(VSS_VARIABLE_STORE_HEADER));
-    QByteArray body = storage.mid(sizeof(VSS_VARIABLE_STORE_HEADER), vssStorageHeader->Size - sizeof(VSS_VARIABLE_STORE_HEADER));
+        // Check storage size
+        if (dataSize < fsysStorageHeader->Size) {
+            msg(QObject::tr("parseStorageHeader: Fsys storage size %1h (%2) is greater than volume body size %3h (%4)")
+                .hexarg2(fsysStorageHeader->Size, 4).arg(fsysStorageHeader->Size)
+                .hexarg2(dataSize, 8).arg(dataSize), parent);
+            return ERR_SUCCESS;
+        }
 
-    // Add info
-    QString name = QObject::tr("VSS storage");
-    QString info = QObject::tr("Signature: %1h\nFull size: %2h (%3)\nHeader size: %4h (%5)\nBody size: %6h (%7)\nFormat: %8h\nState: %9h")
-        .hexarg2(vssStorageHeader->Signature, 8)
-        .hexarg(vssStorageHeader->Size).arg(vssStorageHeader->Size)
-        .hexarg(header.size()).arg(header.size())
-        .hexarg(body.size()).arg(body.size())
-        .hexarg2(vssStorageHeader->Format, 2)
-        .hexarg2(vssStorageHeader->State, 2);
+        // Get parsing data
+        PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
 
-    // Add correct offset
-    pdata.offset = parentOffset;
+        // Construct header and body
+        QByteArray header = storage.left(sizeof(APPLE_FSYS_STORE_HEADER));
+        QByteArray body = storage.mid(sizeof(APPLE_FSYS_STORE_HEADER), fsysStorageHeader->Size - sizeof(APPLE_FSYS_STORE_HEADER) - sizeof(UINT32));
 
-    // Add tree item
-    index = model->addItem(Types::NvramStorageVss, 0, name, QString(), info, header, body, TRUE, parsingDataToQByteArray(pdata), parent);
+        // Check storage checksum
+        UINT32 storedCrc = *(UINT32*)storage.right(sizeof(UINT32)).constBegin();
+        UINT32 calculatedCrc = calculatedCrc = crc32(0, (const UINT8*)storage.constData(), (const UINT32)storage.size() - sizeof(UINT32));
 
-    //Parse the storage
-    //parseVssStorageBody(body, index);
+        // Add info
+        QString name = QObject::tr("Fsys storage");
+        QString info = QObject::tr("Signature: %1h\nFull size: %2h (%3)\nHeader size: %4h (%5)\nBody size: %6h (%7)\nUnknown: %9 %10 %11 %12 %13\nCRC32: %14")
+            .hexarg2(fsysStorageHeader->Signature, 8)
+            .hexarg(fsysStorageHeader->Size).arg(fsysStorageHeader->Size)
+            .hexarg(header.size()).arg(header.size())
+            .hexarg(body.size()).arg(body.size())
+            .hexarg2(fsysStorageHeader->Unknown[0], 2)
+            .hexarg2(fsysStorageHeader->Unknown[1], 2)
+            .hexarg2(fsysStorageHeader->Unknown[2], 2)
+            .hexarg2(fsysStorageHeader->Unknown[3], 2)
+            .hexarg2(fsysStorageHeader->Unknown[4], 2)
+            .arg(storedCrc == calculatedCrc ? QObject::tr("%1h, valid").hexarg2(storedCrc, 8) : QObject::tr("%1h, invalid, should be %2h").hexarg2(storedCrc, 8).hexarg2(calculatedCrc, 8));
+
+        // Add correct offset
+        pdata.offset = parentOffset;
+
+        // Add tree item
+        index = model->addItem(Types::NvramStorageFsys, 0, name, QString(), info, header, body, TRUE, parsingDataToQByteArray(pdata), parent);
+    }
 
     return ERR_SUCCESS;
 }
@@ -3689,3 +3830,111 @@ STATUS FfsParser::parseVssStorageBody(const QModelIndex & index)
 
     return ERR_SUCCESS;
 }
+
+STATUS FfsParser::parseFsysStorageBody(const QModelIndex & index)
+{
+    // Sanity check
+    if (!index.isValid())
+        return ERR_INVALID_PARAMETER;
+
+    // Get parsing data for the current item
+    PARSING_DATA pdata = parsingDataFromQModelIndex(index);
+    UINT32 parentOffset = pdata.offset + model->header(index).size();
+    const QByteArray data = model->body(index);
+
+    // Check that the is enough space for variable header
+    const UINT32 dataSize = (UINT32)data.size();
+    UINT32 offset = 0;
+
+    // Parse all variables
+    while (1) {
+        UINT32 unparsedSize = dataSize - offset;
+        UINT32 variableSize = 0;
+
+        // Get nameSize and name of the variable
+        const UINT8 nameSize = *(UINT8*)(data.constData() + offset);
+        // Check sanity
+        if (unparsedSize >= nameSize + sizeof(UINT8)) {
+            variableSize = nameSize + sizeof(UINT8);
+        }
+
+        QByteArray name;
+        if (variableSize) {
+            name = data.mid(offset + sizeof(UINT8), nameSize);
+            // Check for EOF variable
+            if (nameSize == 3 && name[0] == 'E' && name[1] == 'O' && name[2] == 'F') {
+                // There is no data afterward, add EOF variable and free space and return
+                QByteArray header = data.mid(offset, sizeof(UINT8) + nameSize);
+                QString info = QObject::tr("Full size: %1h (%2)")
+                    .hexarg(header.size()).arg(header.size());
+                
+                // Add correct offset to parsing data
+                pdata.offset = parentOffset + offset;
+                
+                // Add EOF tree item
+                model->addItem(Types::NvramVariableFsys, 0, name, QString(), info, header, QByteArray(), FALSE, parsingDataToQByteArray(pdata), index);
+
+                // Add free space
+                offset += header.size();
+                unparsedSize = dataSize - offset;
+                QByteArray body = data.mid(offset);
+                info = QObject::tr("Full size: %1h (%2)")
+                    .hexarg(body.size()).arg(body.size());
+
+                // Add correct offset to parsing data
+                pdata.offset = parentOffset + offset;
+
+                // Add free space tree item
+                model->addItem(Types::FreeSpace, 0, QObject::tr("Free space"), QString(), info, QByteArray(), body, FALSE, parsingDataToQByteArray(pdata), index);
+
+                return ERR_SUCCESS;
+            }
+        }
+
+        // Get dataSize and data of the variable
+        const UINT16 dataSize = *(UINT16*)(data.constData() + offset + sizeof(UINT8) + nameSize);
+        if (unparsedSize >= sizeof(UINT8) + nameSize + sizeof(UINT16) + dataSize) {
+            variableSize = sizeof(UINT8) + nameSize + sizeof(UINT16) + dataSize;
+        }
+        else {
+            // Last variable is bad, add the rest as padding and return
+            QByteArray body = data.mid(offset);
+            QString info = QObject::tr("Full size: %1h (%2)")
+                .hexarg(body.size()).arg(body.size());
+
+            // Add correct offset to parsing data
+            pdata.offset = parentOffset + offset;
+
+            // Add free space tree item
+            model->addItem(Types::Padding, getPaddingType(body), QObject::tr("Padding"), QString(), info, QByteArray(), body, FALSE, parsingDataToQByteArray(pdata), index);
+            
+            // Show message
+            msg(QObject::tr("parseFsysStorageBody: variable appears too big, added as padding"), index);
+
+            return ERR_SUCCESS;
+        }
+
+        // Construct header and body
+        QByteArray header = data.mid(offset, sizeof(UINT8) + nameSize + sizeof(UINT16));
+        QByteArray body = data.mid(offset + sizeof(UINT8) + nameSize + sizeof(UINT16), dataSize);
+
+        // Add info
+        QString info = QObject::tr("Full size: %1h (%2)\nHeader size %3h (%4)\nBody size: %5h (%6)")
+            .hexarg(variableSize).arg(variableSize)
+            .hexarg(header.size()).arg(header.size())
+            .hexarg(body.size()).arg(body.size());
+
+        // Add correct offset to parsing data
+        pdata.offset = parentOffset + offset;
+
+        // Add tree item
+        model->addItem(Types::NvramVariableFsys, 0, name, QString(), info, header, body, FALSE, parsingDataToQByteArray(pdata), index);
+
+        // Move to next variable
+        offset += variableSize;
+    }
+    
+    return ERR_SUCCESS;
+}
+
+
diff --git a/common/ffsparser.h b/common/ffsparser.h
index e202187..6d9344f 100644
--- a/common/ffsparser.h
+++ b/common/ffsparser.h
@@ -114,6 +114,7 @@ private:
     STATUS getStorageSize(const QByteArray & data, const UINT32 storageOffset, UINT32 & storageSize);
     STATUS parseStorageHeader(const QByteArray & storage, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
     STATUS parseVssStorageBody(const QModelIndex & index);
+    STATUS parseFsysStorageBody(const QModelIndex & index);
 
     // Message helper
     void msg(const QString & message, const QModelIndex &index = QModelIndex());
diff --git a/common/nvram.h b/common/nvram.h
index 69b3f3f..d3756c0 100644
--- a/common/nvram.h
+++ b/common/nvram.h
@@ -99,10 +99,9 @@ typedef struct _VSS_VARIABLE_STORE_HEADER {
 
 // Apple Fsys store header
 typedef struct _APPLE_FSYS_STORE_HEADER {
-    UINT32  Signature; // Fsys signature
-    UINT8   Unknown;   // Still unknown
-    UINT32  Unknown2;  // Still unknown
-    UINT16  Size;      // Size of variable storage
+    UINT32  Signature;  // Fsys signature
+    UINT8   Unknown[5]; // Still unknown
+    UINT16  Size;       // Size of variable storage
 } APPLE_FSYS_STORE_HEADER;
 
 // Apple Fsys variable format
@@ -110,8 +109,8 @@ typedef struct _APPLE_FSYS_STORE_HEADER {
 // CHAR8 Name[];
 // UINT16 DataLength;
 // UINT8 Data[]
-// End with a chunk named "EOF" without data
-// All free bytes are zeros
+// Storage ends with a chunk named "EOF" without data
+// All free bytes in storage are zeroed
 // Has CRC32 of the whole store without checksum field at the end
 
 // Normal variable header
@@ -168,6 +167,19 @@ typedef struct _VSS_AUTH_VARIABLE_HEADER {
 #define NVRAM_VSS_VARIABLE_APPEND_WRITE                          0x00000040
 #define NVRAM_VSS_VARIABLE_APPLE_DATA_CHECKSUM                   0x80000000
 
+// FDC region can be found in some VSS volumes
+// It has another VSS volume inside
+// _FDC header structure
+typedef struct _FDC_VOLUME_HEADER {
+    UINT32 Signature;
+    UINT32 Size;
+    //EFI_FIRMWARE_VOLUME_HEADER VolumeHeader;
+    //EFI_FV_BLOCK_MAP_ENTRY FvBlockMap[2];
+    //VSS_VARIABLE_STORE_HEADER VssHeader;
+} FDC_VOLUME_HEADER;
+
+#define NVRAM_FDC_VOLUME_SIGNATURE 0x4344465F
+
 // Restore previous packing rules
 #pragma pack(pop)
 
diff --git a/common/types.cpp b/common/types.cpp
index 047d4a4..4888271 100644
--- a/common/types.cpp
+++ b/common/types.cpp
@@ -69,8 +69,14 @@ QString itemTypeToQString(const UINT8 type)
         return QObject::tr("NVAR variable");
     case Types::NvramStorageVss:
         return QObject::tr("VSS storage");
+    case Types::NvramStorageFdc:
+        return QObject::tr("FDC storage");
+    case Types::NvramStorageFsys:
+        return QObject::tr("Fsys storage");
     case Types::NvramVariableVss:
         return QObject::tr("VSS variable");
+    case Types::NvramVariableFsys:
+        return QObject::tr("Fsys variable");
     default:
         return QObject::tr("Unknown");
     }
@@ -140,6 +146,9 @@ QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype)
         else 
             return QObject::tr("Unknown subtype");
     case Types::NvramStorageVss:
+    case Types::NvramStorageFdc:
+    case Types::NvramStorageFsys:
+    case Types::NvramVariableFsys:
         return QString();
     case Types::NvramVariableVss:
         if (subtype == Subtypes::InvalidVss)
diff --git a/common/types.h b/common/types.h
index 32f71c8..878de73 100644
--- a/common/types.h
+++ b/common/types.h
@@ -45,7 +45,10 @@ namespace Types {
         FreeSpace,
         NvramVariableNvar,
         NvramStorageVss,
-        NvramVariableVss
+        NvramStorageFdc,
+        NvramStorageFsys,
+        NvramVariableVss,
+        NvramVariableFsys
     };
 }
 
diff --git a/common/utility.cpp b/common/utility.cpp
index e984968..020f30e 100644
--- a/common/utility.cpp
+++ b/common/utility.cpp
@@ -101,7 +101,7 @@ QString errorCodeToQString(UINT8 errorCode)
 }
 
 // CRC32 implementation
-UINT32 crc32(UINT32 initial, const UINT8* buffer, UINT32 length)
+UINT32 crc32(UINT32 initial, const UINT8* buffer, const UINT32 length)
 {
     static const UINT32 crcTable[256] = {
         0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
@@ -141,12 +141,10 @@ UINT32 crc32(UINT32 initial, const UINT8* buffer, UINT32 length)
         0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,
         0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
         0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D };
-    UINT32 crc32;
-    UINT32 i;
 
     // Accumulate crc32 for buffer
-    crc32 = initial ^ 0xFFFFFFFF;
-    for (i = 0; i < length; i++) {
+    UINT32 crc32 = initial ^ 0xFFFFFFFF;
+    for (UINT32 i = 0; i < length; i++) {
         crc32 = (crc32 >> 8) ^ crcTable[(crc32 ^ buffer[i]) & 0xFF];
     }
 
diff --git a/common/utility.h b/common/utility.h
index fc572f4..40d52d7 100644
--- a/common/utility.h
+++ b/common/utility.h
@@ -35,7 +35,7 @@ extern STATUS decompress(const QByteArray & compressed, UINT8 & algorithm, QByte
 //STATUS compress(const QByteArray & decompressed, QByteArray & compressed, const UINT8 & algorithm);
 
 // CRC32 calculation routine
-extern UINT32 crc32(UINT32 initial, const UINT8* buffer, UINT32 length);
+extern UINT32 crc32(UINT32 initial, const UINT8* buffer, const UINT32 length);
 
 // 8bit checksum calculation routine
 extern UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize);