1 /* nvramparser.cpp
2
3 Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
4
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php.
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 */
14
15 //TODO: relax fixed restrictions once NVRAM builder is ready
16
17 #include <map>
18
19 #include "nvramparser.h"
20 #include "parsingdata.h"
21 #include "utility.h"
22 #include "nvram.h"
23 #include "ffs.h"
24 #include "fit.h"
25 #include "uinttypes.h"
26
27 #ifdef U_ENABLE_NVRAM_PARSING_SUPPORT
parseNvarStore(const UModelIndex & index)28 USTATUS NvramParser::parseNvarStore(const UModelIndex & index)
29 {
30 // Sanity check
31 if (!index.isValid())
32 return U_INVALID_PARAMETER;
33
34 // Obtain required information from parent file
35 UINT8 emptyByte = 0xFF;
36 UModelIndex parentFileIndex = model->findParentOfType(index, Types::File);
37 if (parentFileIndex.isValid() && model->hasEmptyParsingData(parentFileIndex) == false) {
38 UByteArray data = model->parsingData(parentFileIndex);
39 const FILE_PARSING_DATA* pdata = (const FILE_PARSING_DATA*)data.constData();
40 emptyByte = readUnaligned(pdata).emptyByte;
41 }
42
43 // Get local offset
44 UINT32 localOffset = (UINT32)model->header(index).size();
45
46 // Get item data
47 const UByteArray data = model->body(index);
48
49 // Parse all entries
50 UINT32 offset = 0;
51 UINT32 guidsInStore = 0;
52 while (1) {
53 bool msgUnknownExtDataFormat = false;
54 bool msgExtHeaderTooLong = false;
55 bool msgExtDataTooShort = false;
56
57 bool isInvalid = false;
58 bool isInvalidLink = false;
59 bool hasExtendedHeader = false;
60 bool hasChecksum = false;
61 bool hasTimestamp = false;
62 bool hasHash = false;
63 bool hasGuidIndex = false;
64
65 UINT32 guidIndex = 0;
66 UINT8 storedChecksum = 0;
67 UINT8 calculatedChecksum = 0;
68 UINT32 extendedHeaderSize = 0;
69 UINT8 extendedAttributes = 0;
70 UINT64 timestamp = 0;
71 UByteArray hash;
72
73 UINT8 subtype = Subtypes::FullNvarEntry;
74 UString name;
75 UString guid;
76 UString text;
77 UByteArray header;
78 UByteArray body;
79 UByteArray tail;
80
81 UINT32 guidAreaSize = guidsInStore * sizeof(EFI_GUID);
82 UINT32 unparsedSize = (UINT32)data.size() - offset - guidAreaSize;
83
84 // Get entry header
85 const NVAR_ENTRY_HEADER* entryHeader = (const NVAR_ENTRY_HEADER*)(data.constData() + offset);
86
87 // Check header size and signature
88 if (unparsedSize < sizeof(NVAR_ENTRY_HEADER) ||
89 entryHeader->Signature != NVRAM_NVAR_ENTRY_SIGNATURE ||
90 unparsedSize < entryHeader->Size) {
91 // Check if the data left is a free space or a padding
92 UByteArray padding = data.mid(offset, unparsedSize);
93
94 // Get info
95 UString info = usprintf("Full size: %" PRIXQ "h (%" PRIuQ ")", padding.size(), padding.size());
96
97 if ((UINT32)padding.count(emptyByte) == unparsedSize) { // Free space
98 // Add tree item
99 model->addItem(localOffset + offset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
100 }
101 else {
102 // Nothing is parsed yet, but the file is not empty
103 if (!offset) {
104 msg(usprintf("%s: file can't be parsed as NVAR variables store", __FUNCTION__), index);
105 return U_SUCCESS;
106 }
107
108 // Add tree item
109 model->addItem(localOffset + offset, Types::Padding, getPaddingType(padding), UString("Padding"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
110 }
111
112 // Add GUID store area
113 UByteArray guidArea = data.right(guidAreaSize);
114 // Get info
115 name = UString("GUID store");
116 info = usprintf("Full size: %" PRIXQ "h (%" PRIuQ ")\nGUIDs in store: %u",
117 guidArea.size(), guidArea.size(),
118 guidsInStore);
119 // Add tree item
120 model->addItem((UINT32)(localOffset + offset + padding.size()), Types::Padding, getPaddingType(guidArea), name, UString(), info, UByteArray(), guidArea, UByteArray(), Fixed, index);
121
122 return U_SUCCESS;
123 }
124
125 // Contruct generic header and body
126 header = data.mid(offset, sizeof(NVAR_ENTRY_HEADER));
127 body = data.mid(offset + sizeof(NVAR_ENTRY_HEADER), entryHeader->Size - sizeof(NVAR_ENTRY_HEADER));
128
129 UINT32 lastVariableFlag = emptyByte ? 0xFFFFFF : 0;
130
131 // Set default next to predefined last value
132 NVAR_ENTRY_PARSING_DATA pdata;
133 pdata.emptyByte = emptyByte;
134 pdata.next = lastVariableFlag;
135
136 // Entry is marked as invalid
137 if ((entryHeader->Attributes & NVRAM_NVAR_ENTRY_VALID) == 0) { // Valid attribute is not set
138 isInvalid = true;
139 // Do not parse further
140 goto parsing_done;
141 }
142
143 // Add next node information to parsing data
144 if (entryHeader->Next != lastVariableFlag) {
145 subtype = Subtypes::LinkNvarEntry;
146 pdata.next = entryHeader->Next;
147 }
148
149 // Entry with extended header
150 if (entryHeader->Attributes & NVRAM_NVAR_ENTRY_EXT_HEADER) {
151 hasExtendedHeader = true;
152 msgUnknownExtDataFormat = true;
153
154 extendedHeaderSize = readUnaligned((UINT16*)(body.constData() + body.size() - sizeof(UINT16)));
155 if (extendedHeaderSize > (UINT32)body.size()) {
156 msgExtHeaderTooLong = true;
157 isInvalid = true;
158 // Do not parse further
159 goto parsing_done;
160 }
161
162 extendedAttributes = *(UINT8*)(body.constData() + body.size() - extendedHeaderSize);
163
164 // Variable with checksum
165 if (extendedAttributes & NVRAM_NVAR_ENTRY_EXT_CHECKSUM) {
166 // Get stored checksum
167 storedChecksum = *(UINT8*)(body.constData() + body.size() - sizeof(UINT16) - sizeof(UINT8));
168
169 // Recalculate checksum for the variable
170 calculatedChecksum = 0;
171 // Include entry data
172 UINT8* start = (UINT8*)(entryHeader + 1);
173 for (UINT8* p = start; p < start + entryHeader->Size - sizeof(NVAR_ENTRY_HEADER); p++) {
174 calculatedChecksum += *p;
175 }
176 // Include entry size and flags
177 start = (UINT8*)&entryHeader->Size;
178 for (UINT8*p = start; p < start + sizeof(UINT16); p++) {
179 calculatedChecksum += *p;
180 }
181 // Include entry attributes
182 calculatedChecksum += entryHeader->Attributes;
183
184 hasChecksum = true;
185 msgUnknownExtDataFormat = false;
186 }
187
188 tail = body.mid(body.size() - extendedHeaderSize);
189 body = body.left(body.size() - extendedHeaderSize);
190
191 // Entry with authenticated write (for SecureBoot)
192 if (entryHeader->Attributes & NVRAM_NVAR_ENTRY_AUTH_WRITE) {
193 if ((entryHeader->Attributes & NVRAM_NVAR_ENTRY_DATA_ONLY)) {// Data only auth. variables has no hash
194 if ((UINT32)tail.size() < sizeof(UINT64)) {
195 msgExtDataTooShort = true;
196 isInvalid = true;
197 // Do not parse further
198 goto parsing_done;
199 }
200
201 timestamp = readUnaligned(tail.constData() + sizeof(UINT8));
202 hasTimestamp = true;
203 msgUnknownExtDataFormat = false;
204 }
205 else { // Full or link variable have hash
206 if ((UINT32)tail.size() < sizeof(UINT64) + SHA256_HASH_SIZE) {
207 msgExtDataTooShort = true;
208 isInvalid = true;
209 // Do not parse further
210 goto parsing_done;
211 }
212
213 timestamp = readUnaligned((UINT64*)(tail.constData() + sizeof(UINT8)));
214 hash = tail.mid(sizeof(UINT64) + sizeof(UINT8), SHA256_HASH_SIZE);
215 hasTimestamp = true;
216 hasHash = true;
217 msgUnknownExtDataFormat = false;
218 }
219 }
220 }
221
222 // Entry is data-only (nameless and GUIDless entry or link)
223 if (entryHeader->Attributes & NVRAM_NVAR_ENTRY_DATA_ONLY) { // Data-only attribute is set
224 isInvalidLink = true;
225 UModelIndex nvarIndex;
226 // Search previously added entries for a link to this variable
227 // WARNING: O(n^2), may be very slow
228 for (int i = model->rowCount(index) - 1; i >= 0; i--) {
229 #if ((QT_VERSION_MAJOR == 5) && (QT_VERSION_MINOR < 6)) || (QT_VERSION_MAJOR < 5)
230 nvarIndex = index.child(i, 0);
231 #else
232 nvarIndex = index.model()->index(i, 0, index);
233 #endif
234
235 if (model->hasEmptyParsingData(nvarIndex) == false) {
236 UByteArray nvarData = model->parsingData(nvarIndex);
237 const NVAR_ENTRY_PARSING_DATA nvarPdata = readUnaligned((const NVAR_ENTRY_PARSING_DATA*)nvarData.constData());
238 if (nvarPdata.isValid && nvarPdata.next + model->offset(nvarIndex) - localOffset == offset) { // Previous link is present and valid
239 isInvalidLink = false;
240 break;
241 }
242 }
243 }
244 // Check if the link is valid
245 if (!isInvalidLink) {
246 // Use the name and text of the previous link
247 name = model->name(nvarIndex);
248 text = model->text(nvarIndex);
249
250 if (entryHeader->Next == lastVariableFlag)
251 subtype = Subtypes::DataNvarEntry;
252 }
253
254 // Do not parse further
255 goto parsing_done;
256 }
257
258 // Get entry name
259 {
260 UINT32 nameOffset = (entryHeader->Attributes & NVRAM_NVAR_ENTRY_GUID) ? sizeof(EFI_GUID) : sizeof(UINT8); // GUID can be stored with the variable or in a separate store, so there will only be an index of it
261 CHAR8* namePtr = (CHAR8*)(entryHeader + 1) + nameOffset;
262 UINT32 nameSize = 0;
263 if (entryHeader->Attributes & NVRAM_NVAR_ENTRY_ASCII_NAME) { // Name is stored as ASCII string of CHAR8s
264 text = UString(namePtr);
265 nameSize = (UINT32)(text.length() + 1);
266 }
267 else { // Name is stored as UCS2 string of CHAR16s
268 #if QT_VERSION_MAJOR >= 6
269 text = UString::fromUtf16((char16_t*)namePtr);
270 #else
271 text = UString::fromUtf16((CHAR16*)namePtr);
272 #endif
273
274 nameSize = (UINT32)((text.length() + 1) * 2);
275 }
276
277 // Get entry GUID
278 if (entryHeader->Attributes & NVRAM_NVAR_ENTRY_GUID) { // GUID is strored in the variable itself
279 name = guidToUString(readUnaligned((EFI_GUID*)(entryHeader + 1)));
280 guid = guidToUString(readUnaligned((EFI_GUID*)(entryHeader + 1)), false);
281 }
282 // GUID is stored in GUID list at the end of the store
283 else {
284 guidIndex = *(UINT8*)(entryHeader + 1);
285 if (guidsInStore < guidIndex + 1)
286 guidsInStore = guidIndex + 1;
287
288 // The list begins at the end of the store and goes backwards
289 const EFI_GUID* guidPtr = (const EFI_GUID*)(data.constData() + data.size()) - 1 - guidIndex;
290 name = guidToUString(readUnaligned(guidPtr));
291 guid = guidToUString(readUnaligned(guidPtr), false);
292 hasGuidIndex = true;
293 }
294
295 // Include name and GUID into the header and remove them from body
296 header = data.mid(offset, sizeof(NVAR_ENTRY_HEADER) + nameOffset + nameSize);
297 body = body.mid(nameOffset + nameSize);
298 }
299 parsing_done:
300 UString info;
301
302 // Rename invalid entries according to their types
303 pdata.isValid = TRUE;
304 if (isInvalid) {
305 name = UString("Invalid");
306 subtype = Subtypes::InvalidNvarEntry;
307 pdata.isValid = FALSE;
308 }
309 else if (isInvalidLink) {
310 name = UString("Invalid link");
311 subtype = Subtypes::InvalidLinkNvarEntry;
312 pdata.isValid = FALSE;
313 }
314 else // Add GUID info for valid entries
315 info += UString("Variable GUID: ") + guid + UString("\n");
316
317 // Add GUID index information
318 if (hasGuidIndex)
319 info += usprintf("GUID index: %u\n", guidIndex);
320
321 // Add header, body and extended data info
322 info += usprintf("Full size: %Xh (%u)\nHeader size: %" PRIXQ "h (%" PRIuQ ")\nBody size: %" PRIXQ "h (%" PRIuQ ")",
323 entryHeader->Size, entryHeader->Size,
324 header.size(), header.size(),
325 body.size(), body.size());
326
327 // Add attributes info
328 info += usprintf("\nAttributes: %02Xh", entryHeader->Attributes);
329 // Translate attributes to text
330 if (entryHeader->Attributes && entryHeader->Attributes != 0xFF)
331 info += UString(" (") + nvarAttributesToUString(entryHeader->Attributes) + UString(")");
332
333 // Add next node info
334 if (!isInvalid && entryHeader->Next != lastVariableFlag)
335 info += usprintf("\nNext node at offset: %Xh", localOffset + offset + entryHeader->Next);
336
337 // Add extended header info
338 if (hasExtendedHeader) {
339 info += usprintf("\nExtended header size: %Xh (%u)\nExtended attributes: %Xh (",
340 extendedHeaderSize, extendedHeaderSize,
341 extendedAttributes) + nvarExtendedAttributesToUString(extendedAttributes) + UString(")");
342
343 // Add checksum
344 if (hasChecksum)
345 info += usprintf("\nChecksum: %02Xh", storedChecksum) +
346 (calculatedChecksum ? usprintf(", invalid, should be %02Xh", 0x100 - calculatedChecksum) : UString(", valid"));
347
348 // Add timestamp
349 if (hasTimestamp)
350 info += usprintf("\nTimestamp: %" PRIX64 "h", timestamp);
351
352 // Add hash
353 if (hasHash)
354 info += UString("\nHash: ") + UString(hash.toHex().constData());
355 }
356
357 // Add tree item
358 UModelIndex varIndex = model->addItem(localOffset + offset, Types::NvarEntry, subtype, name, text, info, header, body, tail, Fixed, index);
359
360 // Set parsing data for created entry
361 model->setParsingData(varIndex, UByteArray((const char*)&pdata, sizeof(pdata)));
362
363 // Show messages
364 if (msgUnknownExtDataFormat) msg(usprintf("%s: unknown extended data format", __FUNCTION__), varIndex);
365 if (msgExtHeaderTooLong) msg(usprintf("%s: extended header size (%Xh) is greater than body size (%" PRIXQ "h)", __FUNCTION__,
366 extendedHeaderSize, body.size()), varIndex);
367 if (msgExtDataTooShort) msg(usprintf("%s: extended header size (%" PRIXQ "h) is too small for timestamp and hash", __FUNCTION__,
368 tail.size()), varIndex);
369
370 // Try parsing the entry data as NVAR storage if it begins with NVAR signature
371 if ((subtype == Subtypes::DataNvarEntry || subtype == Subtypes::FullNvarEntry)
372 && body.size() >= 4 && readUnaligned((const UINT32*)body.constData()) == NVRAM_NVAR_ENTRY_SIGNATURE)
373 parseNvarStore(varIndex);
374
375 // Move to next exntry
376 offset += entryHeader->Size;
377 }
378
379 return U_SUCCESS;
380 }
381
parseNvramVolumeBody(const UModelIndex & index)382 USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index)
383 {
384 // Sanity check
385 if (!index.isValid())
386 return U_INVALID_PARAMETER;
387
388 // Obtain required fields from parsing data
389 UINT8 emptyByte = 0xFF;
390 if (model->hasEmptyParsingData(index) == false) {
391 UByteArray data = model->parsingData(index);
392 const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData();
393 emptyByte = pdata->emptyByte;
394 }
395
396 // Get local offset
397 UINT32 localOffset = (UINT32)model->header(index).size();
398
399 // Get item data
400 UByteArray data = model->body(index);
401
402 // Search for first store
403 USTATUS result;
404 UINT32 prevStoreOffset;
405 result = findNextStore(index, data, localOffset, 0, prevStoreOffset);
406 if (result)
407 return result;
408
409 // First store is not at the beginning of volume body
410 UString name;
411 UString info;
412 if (prevStoreOffset > 0) {
413 // Get info
414 UByteArray padding = data.left(prevStoreOffset);
415 name = UString("Padding");
416 info = usprintf("Full size: %" PRIXQ "h (%" PRIuQ ")", padding.size(), padding.size());
417
418 // Add tree item
419 model->addItem(localOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
420 }
421
422 // Search for and parse all stores
423 UINT32 storeOffset = prevStoreOffset;
424 UINT32 prevStoreSize = 0;
425
426 while (!result) {
427 // Padding between stores
428 if (storeOffset > prevStoreOffset + prevStoreSize) {
429 UINT32 paddingOffset = prevStoreOffset + prevStoreSize;
430 UINT32 paddingSize = storeOffset - paddingOffset;
431 UByteArray padding = data.mid(paddingOffset, paddingSize);
432
433 // Get info
434 name = UString("Padding");
435 info = usprintf("Full size: %" PRIXQ "h (%" PRIuQ ")", padding.size(), padding.size());
436
437 // Add tree item
438 model->addItem(localOffset + paddingOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
439 }
440
441 // Get store size
442 UINT32 storeSize = 0;
443 result = getStoreSize(data, storeOffset, storeSize);
444 if (result) {
445 msg(usprintf("%s: getStoreSize failed with error ", __FUNCTION__) + errorCodeToUString(result), index);
446 return result;
447 }
448
449 // Check that current store is fully present in input
450 if (storeSize > (UINT32)data.size() || storeOffset + storeSize > (UINT32)data.size()) {
451 // Mark the rest as padding and finish parsing
452 UByteArray padding = data.mid(storeOffset);
453
454 // Get info
455 name = UString("Padding");
456 info = usprintf("Full size: %" PRIXQ "h (%" PRIuQ ")", padding.size(), padding.size());
457
458 // Add tree item
459 UModelIndex paddingIndex = model->addItem(localOffset + storeOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
460 msg(usprintf("%s: one of stores inside overlaps the end of data", __FUNCTION__), paddingIndex);
461
462 // Update variables
463 prevStoreOffset = storeOffset;
464 prevStoreSize = (UINT32)padding.size();
465 break;
466 }
467
468 // Parse current store header
469 UModelIndex storeIndex;
470 UByteArray store = data.mid(storeOffset, storeSize);
471 result = parseStoreHeader(store, localOffset + storeOffset, index, storeIndex);
472 if (result)
473 msg(usprintf("%s: store header parsing failed with error ", __FUNCTION__) + errorCodeToUString(result), index);
474
475 // Go to next store
476 prevStoreOffset = storeOffset;
477 prevStoreSize = storeSize;
478 result = findNextStore(index, data, localOffset, storeOffset + prevStoreSize, storeOffset);
479 }
480
481 // Padding/free space at the end
482 storeOffset = prevStoreOffset + prevStoreSize;
483 if ((UINT32)data.size() > storeOffset) {
484 UByteArray padding = data.mid(storeOffset);
485 // Add info
486 info = usprintf("Full size: %" PRIXQ "h (%" PRIuQ ")", padding.size(), padding.size());
487
488 if (padding.count(emptyByte) == padding.size()) { // Free space
489 // Add tree item
490 model->addItem(localOffset + storeOffset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
491 }
492 else {
493 // Nothing is parsed yet, but the file is not empty
494 if (!storeOffset) {
495 msg(usprintf("%s: can't be parsed as NVRAM volume", __FUNCTION__), index);
496 return U_SUCCESS;
497 }
498
499 // Add tree item
500 model->addItem(localOffset + storeOffset, Types::Padding, getPaddingType(padding), UString("Padding"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
501 }
502 }
503
504 // Parse bodies
505 for (int i = 0; i < model->rowCount(index); i++) {
506 #if ((QT_VERSION_MAJOR == 5) && (QT_VERSION_MINOR < 6)) || (QT_VERSION_MAJOR < 5)
507 UModelIndex current = index.child(i, 0);
508 #else
509 UModelIndex current = index.model()->index(i, 0, index);
510 #endif
511
512 switch (model->type(current)) {
513 case Types::FdcStore:
514 parseFdcStoreBody(current);
515 break;
516 case Types::VssStore:
517 parseVssStoreBody(current, 0);
518 break;
519 case Types::Vss2Store:
520 parseVssStoreBody(current, 4);
521 break;
522 case Types::FsysStore:
523 parseFsysStoreBody(current);
524 break;
525 case Types::EvsaStore:
526 parseEvsaStoreBody(current);
527 break;
528 case Types::FlashMapStore:
529 parseFlashMapBody(current);
530 break;
531 default:
532 // Ignore unknown!
533 break;
534 }
535 }
536
537 return U_SUCCESS;
538 }
539
findNextStore(const UModelIndex & index,const UByteArray & volume,const UINT32 localOffset,const UINT32 storeOffset,UINT32 & nextStoreOffset)540 USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & volume, const UINT32 localOffset, const UINT32 storeOffset, UINT32 & nextStoreOffset)
541 {
542 UINT32 dataSize = (UINT32)volume.size();
543
544 if (dataSize < sizeof(UINT32))
545 return U_STORES_NOT_FOUND;
546
547 // TODO: add checks for restSize
548 UINT32 offset = storeOffset;
549 for (; offset < dataSize - sizeof(UINT32); offset++) {
550 const UINT32* currentPos = (const UINT32*)(volume.constData() + offset);
551 if (*currentPos == NVRAM_VSS_STORE_SIGNATURE || *currentPos == NVRAM_APPLE_SVS_STORE_SIGNATURE || *currentPos == NVRAM_APPLE_NSS_STORE_SIGNATURE) { // $VSS, $SVS or $NSS signatures found, perform checks
552 const VSS_VARIABLE_STORE_HEADER* vssHeader = (const VSS_VARIABLE_STORE_HEADER*)currentPos;
553 if (vssHeader->Format != NVRAM_VSS_VARIABLE_STORE_FORMATTED) {
554 msg(usprintf("%s: VSS store candidate at offset %Xh skipped, has invalid format %02Xh", __FUNCTION__, localOffset + offset, vssHeader->Format), index);
555 continue;
556 }
557 if (vssHeader->Size == 0 || vssHeader->Size == 0xFFFFFFFF) {
558 msg(usprintf("%s: VSS store candidate at offset %Xh skipped, has invalid size %Xh", __FUNCTION__, localOffset + offset, vssHeader->Size), index);
559 continue;
560 }
561 // All checks passed, store found
562 break;
563 }
564 else if (*currentPos == NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID_PART1 || *currentPos == NVRAM_VSS2_STORE_GUID_PART1) { // VSS2 store signatures found, perform checks
565 UByteArray guid = UByteArray(volume.constData() + offset, sizeof(EFI_GUID));
566 if (guid != NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID && guid != NVRAM_VSS2_STORE_GUID) // Check the whole signature
567 continue;
568
569 const VSS2_VARIABLE_STORE_HEADER* vssHeader = (const VSS2_VARIABLE_STORE_HEADER*)currentPos;
570 if (vssHeader->Format != NVRAM_VSS_VARIABLE_STORE_FORMATTED) {
571 msg(usprintf("%s: VSS2 store candidate at offset %Xh skipped, has invalid format %02Xh", __FUNCTION__, localOffset + offset, vssHeader->Format), index);
572 continue;
573 }
574 if (vssHeader->Size == 0 || vssHeader->Size == 0xFFFFFFFF) {
575 msg(usprintf("%s: VSS2 store candidate at offset %Xh skipped, has invalid size %Xh", __FUNCTION__, localOffset + offset, vssHeader->Size), index);
576 continue;
577 }
578 // All checks passed, store found
579 break;
580 }
581 else if (*currentPos == NVRAM_FDC_VOLUME_SIGNATURE) { // FDC signature found
582 const FDC_VOLUME_HEADER* fdcHeader = (const FDC_VOLUME_HEADER*)currentPos;
583 if (fdcHeader->Size == 0 || fdcHeader->Size == 0xFFFFFFFF) {
584 msg(usprintf("%s: FDC store candidate at offset %Xh skipped, has invalid size %Xh", __FUNCTION__, localOffset + offset, fdcHeader->Size), index);
585 continue;
586 }
587 // All checks passed, store found
588 break;
589 }
590 else if (*currentPos == NVRAM_APPLE_FSYS_STORE_SIGNATURE || *currentPos == NVRAM_APPLE_GAID_STORE_SIGNATURE) { // Fsys or Gaid signature found
591 const APPLE_FSYS_STORE_HEADER* fsysHeader = (const APPLE_FSYS_STORE_HEADER*)currentPos;
592 if (fsysHeader->Size == 0 || fsysHeader->Size == 0xFFFF) {
593 msg(usprintf("%s: Fsys store candidate at offset %Xh skipped, has invalid size %Xh", __FUNCTION__, localOffset + offset, fsysHeader->Size), index);
594 continue;
595 }
596 // All checks passed, store found
597 break;
598 }
599 else if (*currentPos == NVRAM_EVSA_STORE_SIGNATURE) { //EVSA signature found
600 if (offset < sizeof(UINT32))
601 continue;
602
603 const EVSA_STORE_ENTRY* evsaHeader = (const EVSA_STORE_ENTRY*)(currentPos - 1);
604 if (evsaHeader->Header.Type != NVRAM_EVSA_ENTRY_TYPE_STORE) {
605 msg(usprintf("%s: EVSA store candidate at offset %Xh skipped, has invalid type %02Xh", __FUNCTION__, localOffset + offset - 4, evsaHeader->Header.Type), index);
606 continue;
607 }
608 if (evsaHeader->StoreSize == 0 || evsaHeader->StoreSize == 0xFFFFFFFF) {
609 msg(usprintf("%s: EVSA store candidate at offset %Xh skipped, has invalid size %Xh", __FUNCTION__, localOffset + offset, evsaHeader->StoreSize), index);
610 continue;
611 }
612 // All checks passed, store found
613 offset -= sizeof(UINT32);
614 break;
615 }
616 else if (*currentPos == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 || *currentPos == EDKII_WORKING_BLOCK_SIGNATURE_GUID_DATA1) { // Possible FTW block signature found
617 UByteArray guid = UByteArray(volume.constData() + offset, sizeof(EFI_GUID));
618 if (guid != NVRAM_MAIN_STORE_VOLUME_GUID && guid != EDKII_WORKING_BLOCK_SIGNATURE_GUID && guid != VSS2_WORKING_BLOCK_SIGNATURE_GUID) // Check the whole signature
619 continue;
620
621 // Detect header variant based on WriteQueueSize
622 const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32* ftwHeader = (const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32*)currentPos;
623 if (ftwHeader->WriteQueueSize % 0x10 == 0x04) { // Header with 32 bit WriteQueueSize
624 if (ftwHeader->WriteQueueSize == 0 || ftwHeader->WriteQueueSize == 0xFFFFFFFF) {
625 msg(usprintf("%s: FTW block candidate at offset %Xh skipped, has invalid body size %Xh", __FUNCTION__, localOffset + offset, ftwHeader->WriteQueueSize), index);
626 continue;
627 }
628 }
629 else if (ftwHeader->WriteQueueSize % 0x10 == 0x00) { // Header with 64 bit WriteQueueSize
630 const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64* ftw64Header = (const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64*)currentPos;
631 if (ftw64Header->WriteQueueSize == 0 || ftw64Header->WriteQueueSize >= 0xFFFFFFFF) {
632 msg(usprintf("%s: FTW block candidate at offset %Xh skipped, has invalid body size %llXh", __FUNCTION__, localOffset + offset, (unsigned long long)ftw64Header->WriteQueueSize), index);
633 continue;
634 }
635 }
636 else // Unknown header
637 continue;
638
639 // All checks passed, store found
640 break;
641 }
642 else if (*currentPos == NVRAM_PHOENIX_FLASH_MAP_SIGNATURE_PART1) {// Phoenix SCT flash map
643 UByteArray signature = UByteArray(volume.constData() + offset, NVRAM_PHOENIX_FLASH_MAP_SIGNATURE_LENGTH);
644 if (signature != NVRAM_PHOENIX_FLASH_MAP_SIGNATURE) // Check the whole signature
645 continue;
646
647 // All checks passed, store found
648 break;
649 }
650 else if (*currentPos == NVRAM_PHOENIX_CMDB_HEADER_SIGNATURE) { // Phoenix SCT CMDB store
651 const PHOENIX_CMDB_HEADER* cmdbHeader = (const PHOENIX_CMDB_HEADER*)currentPos;
652
653 // Check size
654 if (cmdbHeader->HeaderSize != sizeof(PHOENIX_CMDB_HEADER))
655 continue;
656
657 // All checks passed, store found
658 break;
659 }
660 else if (*currentPos == INTEL_MICROCODE_HEADER_VERSION_1) {// Intel microcode
661 const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)currentPos;
662
663 // TotalSize is greater then DataSize and is multiple of 1024
664 if (FALSE == ffsParser->microcodeHeaderValid(ucodeHeader)) {
665 continue;
666 }
667
668 // All checks passed, store found
669 break;
670 }
671 else if (*currentPos == OEM_ACTIVATION_PUBKEY_MAGIC) { // SLIC pubkey
672 if (offset < 4 * sizeof(UINT32))
673 continue;
674
675 const OEM_ACTIVATION_PUBKEY* pubkeyHeader = (const OEM_ACTIVATION_PUBKEY*)(currentPos - 4);
676 // Check type
677 if (pubkeyHeader->Type != OEM_ACTIVATION_PUBKEY_TYPE)
678 continue;
679
680 // All checks passed, store found
681 offset -= 4 * sizeof(UINT32);
682 break;
683 }
684 else if (*currentPos == OEM_ACTIVATION_MARKER_WINDOWS_FLAG_PART1) { // SLIC marker
685 if (offset >= dataSize - sizeof(UINT64) ||
686 *(const UINT64*)currentPos != OEM_ACTIVATION_MARKER_WINDOWS_FLAG ||
687 offset < 26) // Check full windows flag and structure size
688 continue;
689
690 const OEM_ACTIVATION_MARKER* markerHeader = (const OEM_ACTIVATION_MARKER*)(volume.constData() + offset - 26);
691 // Check reserved bytes
692 bool reservedBytesValid = true;
693 for (UINT32 i = 0; i < sizeof(markerHeader->Reserved); i++)
694 if (markerHeader->Reserved[i] != OEM_ACTIVATION_MARKER_RESERVED_BYTE) {
695 reservedBytesValid = false;
696 break;
697 }
698 if (!reservedBytesValid)
699 continue;
700
701 // All checks passed, store found
702 offset -= 26;
703 break;
704 }
705 }
706 // No more stores found
707 if (offset >= dataSize - sizeof(UINT32))
708 return U_STORES_NOT_FOUND;
709
710 nextStoreOffset = offset;
711
712 return U_SUCCESS;
713 }
714
getStoreSize(const UByteArray & data,const UINT32 storeOffset,UINT32 & storeSize)715 USTATUS NvramParser::getStoreSize(const UByteArray & data, const UINT32 storeOffset, UINT32 & storeSize)
716 {
717 const UINT32* signature = (const UINT32*)(data.constData() + storeOffset);
718 if (*signature == NVRAM_VSS_STORE_SIGNATURE || *signature == NVRAM_APPLE_SVS_STORE_SIGNATURE || *signature == NVRAM_APPLE_NSS_STORE_SIGNATURE) {
719 const VSS_VARIABLE_STORE_HEADER* vssHeader = (const VSS_VARIABLE_STORE_HEADER*)signature;
720 storeSize = vssHeader->Size;
721 }
722 else if (*signature == NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID_PART1 || *signature == NVRAM_VSS2_STORE_GUID_PART1) {
723 const VSS2_VARIABLE_STORE_HEADER* vssHeader = (const VSS2_VARIABLE_STORE_HEADER*)signature;
724 storeSize = vssHeader->Size;
725 }
726 else if (*signature == NVRAM_FDC_VOLUME_SIGNATURE) {
727 const FDC_VOLUME_HEADER* fdcHeader = (const FDC_VOLUME_HEADER*)signature;
728 storeSize = fdcHeader->Size;
729 }
730 else if (*signature == NVRAM_APPLE_FSYS_STORE_SIGNATURE || *signature == NVRAM_APPLE_GAID_STORE_SIGNATURE) {
731 const APPLE_FSYS_STORE_HEADER* fsysHeader = (const APPLE_FSYS_STORE_HEADER*)signature;
732 storeSize = fsysHeader->Size;
733 }
734 else if (*(signature + 1) == NVRAM_EVSA_STORE_SIGNATURE) {
735 const EVSA_STORE_ENTRY* evsaHeader = (const EVSA_STORE_ENTRY*)signature;
736 storeSize = evsaHeader->StoreSize;
737 }
738 else if (*signature == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 || *signature == EDKII_WORKING_BLOCK_SIGNATURE_GUID_DATA1) {
739 const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32* ftwHeader = (const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32*)signature;
740 if (ftwHeader->WriteQueueSize % 0x10 == 0x04) { // Header with 32 bit WriteQueueSize
741 storeSize = sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32) + ftwHeader->WriteQueueSize;
742 }
743 else { // Header with 64 bit WriteQueueSize
744 const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64* ftw64Header = (const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64*)signature;
745 storeSize = sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64) + (UINT32)ftw64Header->WriteQueueSize;
746 }
747 }
748 else if (*signature == NVRAM_PHOENIX_FLASH_MAP_SIGNATURE_PART1) { // Phoenix SCT flash map
749 const PHOENIX_FLASH_MAP_HEADER* flashMapHeader = (const PHOENIX_FLASH_MAP_HEADER*)signature;
750 storeSize = sizeof(PHOENIX_FLASH_MAP_HEADER) + sizeof(PHOENIX_FLASH_MAP_ENTRY) * flashMapHeader->NumEntries;
751 }
752 else if (*signature == NVRAM_PHOENIX_CMDB_HEADER_SIGNATURE) { // Phoenix SCT CMDB store
753 storeSize = NVRAM_PHOENIX_CMDB_SIZE; // It's a predefined max size, no need to calculate
754 }
755 else if (*(signature + 4) == OEM_ACTIVATION_PUBKEY_MAGIC) { // SLIC pubkey
756 const OEM_ACTIVATION_PUBKEY* pubkeyHeader = (const OEM_ACTIVATION_PUBKEY*)signature;
757 storeSize = pubkeyHeader->Size;
758 }
759 else if (*(const UINT64*)(data.constData() + storeOffset + 26) == OEM_ACTIVATION_MARKER_WINDOWS_FLAG) { // SLIC marker
760 const OEM_ACTIVATION_MARKER* markerHeader = (const OEM_ACTIVATION_MARKER*)signature;
761 storeSize = markerHeader->Size;
762 }
763 else if (*signature == INTEL_MICROCODE_HEADER_VERSION_1) { // Intel microcode, must be checked after SLIC marker because of the same *signature values
764 const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)signature;
765 storeSize = ucodeHeader->TotalSize;
766 } else {
767 return U_INVALID_PARAMETER; // Unreachable
768 }
769 return U_SUCCESS;
770 }
771
parseVssStoreHeader(const UByteArray & store,const UINT32 localOffset,const bool sizeOverride,const UModelIndex & parent,UModelIndex & index)772 USTATUS NvramParser::parseVssStoreHeader(const UByteArray & store, const UINT32 localOffset, const bool sizeOverride, const UModelIndex & parent, UModelIndex & index)
773 {
774 const UINT32 dataSize = (UINT32)store.size();
775
776 // Check store size
777 if (dataSize < sizeof(VSS_VARIABLE_STORE_HEADER)) {
778 msg(usprintf("%s: volume body is too small even for VSS store header", __FUNCTION__), parent);
779 return U_SUCCESS;
780 }
781
782 // Get VSS store header
783 const VSS_VARIABLE_STORE_HEADER* vssStoreHeader = (const VSS_VARIABLE_STORE_HEADER*)store.constData();
784
785 // Check for size override
786 UINT32 storeSize = vssStoreHeader->Size;
787 if (sizeOverride) {
788 storeSize = dataSize;
789 }
790
791 // Check store size
792 if (dataSize < storeSize) {
793 msg(usprintf("%s: VSS store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__,
794 storeSize, storeSize,
795 dataSize, dataSize), parent);
796 return U_SUCCESS;
797 }
798
799 // Construct header and body
800 UByteArray header = store.left(sizeof(VSS_VARIABLE_STORE_HEADER));
801 UByteArray body = store.mid(sizeof(VSS_VARIABLE_STORE_HEADER), storeSize - sizeof(VSS_VARIABLE_STORE_HEADER));
802
803 // Add info
804 UString name;
805 if (vssStoreHeader->Signature == NVRAM_APPLE_SVS_STORE_SIGNATURE) {
806 name = UString("SVS store");
807 }
808 else if (vssStoreHeader->Signature == NVRAM_APPLE_NSS_STORE_SIGNATURE) {
809 name = UString("NSS store");
810 }
811 else {
812 name = UString("VSS store");
813 }
814
815 UString info = usprintf("Signature: %Xh\nFull size: %Xh (%u)\nHeader size: %" PRIXQ "h (%" PRIuQ ")\nBody size: %" PRIXQ "h (%" PRIuQ ")\nFormat: %02Xh\nState: %02Xh\nUnknown: %04Xh",
816 vssStoreHeader->Signature,
817 storeSize, storeSize,
818 header.size(), header.size(),
819 body.size(), body.size(),
820 vssStoreHeader->Format,
821 vssStoreHeader->State,
822 vssStoreHeader->Unknown);
823
824 // Add tree item
825 index = model->addItem(localOffset, Types::VssStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
826
827 return U_SUCCESS;
828 }
829
parseVss2StoreHeader(const UByteArray & store,const UINT32 localOffset,const bool sizeOverride,const UModelIndex & parent,UModelIndex & index)830 USTATUS NvramParser::parseVss2StoreHeader(const UByteArray & store, const UINT32 localOffset, const bool sizeOverride, const UModelIndex & parent, UModelIndex & index)
831 {
832 const UINT32 dataSize = (UINT32)store.size();
833
834 // Check store size
835 if (dataSize < sizeof(VSS2_VARIABLE_STORE_HEADER)) {
836 msg(usprintf("%s: volume body is too small even for VSS2 store header", __FUNCTION__), parent);
837 return U_SUCCESS;
838 }
839
840 // Get VSS2 store header
841 const VSS2_VARIABLE_STORE_HEADER* vssStoreHeader = (const VSS2_VARIABLE_STORE_HEADER*)store.constData();
842
843 // Check for size override
844 UINT32 storeSize = vssStoreHeader->Size;
845 if (sizeOverride) {
846 storeSize = dataSize;
847 }
848
849 // Check store size
850 if (dataSize < storeSize) {
851 msg(usprintf("%s: VSS2 store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__,
852 storeSize, storeSize,
853 dataSize, dataSize), parent);
854 return U_SUCCESS;
855 }
856
857 // Construct header and body
858 UByteArray header = store.left(sizeof(VSS2_VARIABLE_STORE_HEADER));
859 UByteArray body = store.mid(sizeof(VSS2_VARIABLE_STORE_HEADER), storeSize - sizeof(VSS2_VARIABLE_STORE_HEADER));
860
861 // Add info
862 UString name = UString("VSS2 store");
863 UString info = UString("Signature: ") + guidToUString(vssStoreHeader->Signature, false) +
864 usprintf("\nFull size: %Xh (%u)\nHeader size: %" PRIXQ "h (%" PRIuQ ")\nBody size: %" PRIXQ "h (%" PRIuQ ")\nFormat: %02Xh\nState: %02Xh\nUnknown: %04Xh",
865 storeSize, storeSize,
866 header.size(), header.size(),
867 body.size(), body.size(),
868 vssStoreHeader->Format,
869 vssStoreHeader->State,
870 vssStoreHeader->Unknown);
871
872 // Add tree item
873 index = model->addItem(localOffset, Types::Vss2Store, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
874
875 return U_SUCCESS;
876 }
877
parseFtwStoreHeader(const UByteArray & store,const UINT32 localOffset,const UModelIndex & parent,UModelIndex & index)878 USTATUS NvramParser::parseFtwStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
879 {
880 const UINT32 dataSize = (UINT32)store.size();
881
882 // Check store size
883 if (dataSize < sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64)) {
884 msg(usprintf("%s: volume body is too small even for FTW store header", __FUNCTION__), parent);
885 return U_SUCCESS;
886 }
887
888 // Obtain required information from parent volume
889 UINT8 emptyByte = 0xFF;
890 UModelIndex parentVolumeIndex = model->findParentOfType(parent, Types::Volume);
891 if (parentVolumeIndex.isValid() && model->hasEmptyParsingData(parentVolumeIndex) == false) {
892 UByteArray data = model->parsingData(parentVolumeIndex);
893 const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData();
894 emptyByte = pdata->emptyByte;
895 }
896
897 // Get FTW block headers
898 const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32* ftw32BlockHeader = (const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32*)store.constData();
899 const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64* ftw64BlockHeader = (const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64*)store.constData();
900
901 // Check store size
902 UINT32 ftwBlockSize;
903 bool has32bitHeader;
904 if (ftw32BlockHeader->WriteQueueSize % 0x10 == 0x04) { // Header with 32 bit WriteQueueSize
905 ftwBlockSize = sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32) + ftw32BlockHeader->WriteQueueSize;
906 has32bitHeader = true;
907 }
908 else { // Header with 64 bit WriteQueueSize
909 ftwBlockSize = sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64) + (UINT32)ftw64BlockHeader->WriteQueueSize;
910 has32bitHeader = false;
911 }
912 if (dataSize < ftwBlockSize) {
913 msg(usprintf("%s: FTW store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__,
914 ftwBlockSize, ftwBlockSize,
915 dataSize, dataSize), parent);
916 return U_SUCCESS;
917 }
918
919 // Construct header and body
920 UINT32 headerSize = has32bitHeader ? sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32) : sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64);
921 UByteArray header = store.left(headerSize);
922 UByteArray body = store.mid(headerSize, ftwBlockSize - headerSize);
923
924 // Check block header checksum
925 UByteArray crcHeader = header;
926 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32* crcFtwBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32*)header.data();
927 crcFtwBlockHeader->Crc = emptyByte ? 0xFFFFFFFF : 0;
928 crcFtwBlockHeader->State = emptyByte ? 0xFF : 0;
929 UINT32 calculatedCrc = (UINT32)crc32(0, (const UINT8*)crcFtwBlockHeader, headerSize);
930
931 // Add info
932 UString name("FTW store");
933 UString info = UString("Signature: ") + guidToUString(ftw32BlockHeader->Signature, false) +
934 usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %" PRIXQ "h (%" PRIuQ ")\nState: %02Xh\nHeader CRC32: %08Xh",
935 ftwBlockSize, ftwBlockSize,
936 headerSize, headerSize,
937 body.size(), body.size(),
938 ftw32BlockHeader->State,
939 ftw32BlockHeader->Crc) +
940 (ftw32BlockHeader->Crc != calculatedCrc ? usprintf(", invalid, should be %08Xh", calculatedCrc) : UString(", valid"));
941
942 // Add tree item
943 index = model->addItem(localOffset, Types::FtwStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
944
945 return U_SUCCESS;
946 }
947
parseFdcStoreHeader(const UByteArray & store,const UINT32 localOffset,const UModelIndex & parent,UModelIndex & index)948 USTATUS NvramParser::parseFdcStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
949 {
950 const UINT32 dataSize = (UINT32)store.size();
951
952 // Check store size
953 if (dataSize < sizeof(FDC_VOLUME_HEADER)) {
954 msg(usprintf("%s: volume body is too small even for FDC store header", __FUNCTION__), parent);
955 return U_SUCCESS;
956 }
957
958 // Get Fdc store header
959 const FDC_VOLUME_HEADER* fdcStoreHeader = (const FDC_VOLUME_HEADER*)store.constData();
960
961 // Check store size
962 if (dataSize < fdcStoreHeader->Size) {
963 msg(usprintf("%s: FDC store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__,
964 fdcStoreHeader->Size, fdcStoreHeader->Size,
965 dataSize, dataSize), parent);
966 return U_SUCCESS;
967 }
968
969 // Construct header and body
970 UByteArray header = store.left(sizeof(FDC_VOLUME_HEADER));
971 UByteArray body = store.mid(sizeof(FDC_VOLUME_HEADER), fdcStoreHeader->Size - sizeof(FDC_VOLUME_HEADER));
972
973 // Add info
974 UString name("FDC store");
975 UString info = usprintf("Signature: _FDC\nFull size: %Xh (%u)\nHeader size: %" PRIXQ "h (%" PRIuQ ")\nBody size: %" PRIXQ "h (%" PRIuQ ")",
976 fdcStoreHeader->Size, fdcStoreHeader->Size,
977 header.size(), header.size(),
978 body.size(), body.size());
979
980 // Add tree item
981 index = model->addItem(localOffset, Types::FdcStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
982
983 return U_SUCCESS;
984 }
985
parseFsysStoreHeader(const UByteArray & store,const UINT32 localOffset,const UModelIndex & parent,UModelIndex & index)986 USTATUS NvramParser::parseFsysStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
987 {
988 const UINT32 dataSize = (UINT32)store.size();
989
990 // Check store size
991 if (dataSize < sizeof(APPLE_FSYS_STORE_HEADER)) {
992 msg(usprintf("%s: volume body is too small even for Fsys store header", __FUNCTION__), parent);
993 return U_SUCCESS;
994 }
995
996 // Get Fsys store header
997 const APPLE_FSYS_STORE_HEADER* fsysStoreHeader = (const APPLE_FSYS_STORE_HEADER*)store.constData();
998
999 // Check store size
1000 if (dataSize < fsysStoreHeader->Size) {
1001 msg(usprintf("%s: Fsys store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__,
1002 fsysStoreHeader->Size, fsysStoreHeader->Size,
1003 dataSize, dataSize), parent);
1004 return U_SUCCESS;
1005 }
1006
1007 // Construct header and body
1008 UByteArray header = store.left(sizeof(APPLE_FSYS_STORE_HEADER));
1009 UByteArray body = store.mid(sizeof(APPLE_FSYS_STORE_HEADER), fsysStoreHeader->Size - sizeof(APPLE_FSYS_STORE_HEADER) - sizeof(UINT32));
1010
1011 // Check store checksum
1012 UINT32 storedCrc = *(UINT32*)store.right(sizeof(UINT32)).constData();
1013 UINT32 calculatedCrc = (UINT32)crc32(0, (const UINT8*)store.constData(), (UINT32)store.size() - sizeof(UINT32));
1014
1015 // Add info
1016 bool isGaidStore = (fsysStoreHeader->Signature == NVRAM_APPLE_GAID_STORE_SIGNATURE);
1017 UString name = isGaidStore ? UString("Gaid store") : UString("Fsys store");
1018 UString info = usprintf("Signature: %s\nFull size: %Xh (%u)\nHeader size: %" PRIXQ "h (%" PRIuQ ")\nBody size: %" PRIXQ "h (%" PRIuQ ")\nUnknown0: %02Xh\nUnknown1: %08Xh\nCRC32: %08Xh",
1019 isGaidStore ? "Gaid" : "Fsys",
1020 fsysStoreHeader->Size, fsysStoreHeader->Size,
1021 header.size(), header.size(),
1022 body.size(), body.size(),
1023 fsysStoreHeader->Unknown0,
1024 fsysStoreHeader->Unknown1,
1025 storedCrc)
1026 + (storedCrc != calculatedCrc ? usprintf(", invalid, should be %08Xh", calculatedCrc) : UString(", valid"));
1027
1028 // Add tree item
1029 index = model->addItem(localOffset, Types::FsysStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
1030
1031 return U_SUCCESS;
1032 }
1033
parseEvsaStoreHeader(const UByteArray & store,const UINT32 localOffset,const UModelIndex & parent,UModelIndex & index)1034 USTATUS NvramParser::parseEvsaStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
1035 {
1036 const UINT32 dataSize = (UINT32)store.size();
1037
1038 // Check dataSize
1039 if (dataSize < sizeof(EVSA_STORE_ENTRY)) {
1040 msg(usprintf("%s: volume body is too small even for EVSA store header", __FUNCTION__), parent);
1041 return U_SUCCESS;
1042 }
1043
1044 // Get EVSA store header
1045 const EVSA_STORE_ENTRY* evsaStoreHeader = (const EVSA_STORE_ENTRY*)store.constData();
1046
1047 // Check store size
1048 if (dataSize < evsaStoreHeader->StoreSize) {
1049 msg(usprintf("%s: EVSA store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__,
1050 evsaStoreHeader->StoreSize, evsaStoreHeader->StoreSize,
1051 dataSize, dataSize), parent);
1052 return U_SUCCESS;
1053 }
1054
1055 // Construct header and body
1056 UByteArray header = store.left(evsaStoreHeader->Header.Size);
1057 UByteArray body = store.mid(evsaStoreHeader->Header.Size, evsaStoreHeader->StoreSize - evsaStoreHeader->Header.Size);
1058
1059 // Recalculate checksum
1060 UINT8 calculated = calculateChecksum8(((const UINT8*)evsaStoreHeader) + 2, evsaStoreHeader->Header.Size - 2);
1061
1062 // Add info
1063 UString name("EVSA store");
1064 UString info = usprintf("Signature: EVSA\nFull size: %Xh (%u)\nHeader size: %" PRIXQ "h (%" PRIuQ ")\nBody size: %" PRIXQ "h (%" PRIuQ ")\nType: %02Xh\nAttributes: %08Xh\nChecksum: %02Xh",
1065 evsaStoreHeader->StoreSize, evsaStoreHeader->StoreSize,
1066 header.size(), header.size(),
1067 body.size(), body.size(),
1068 evsaStoreHeader->Header.Type,
1069 evsaStoreHeader->Attributes,
1070 evsaStoreHeader->Header.Checksum) +
1071 (evsaStoreHeader->Header.Checksum != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid"));
1072
1073 // Add tree item
1074 index = model->addItem(localOffset, Types::EvsaStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
1075
1076 return U_SUCCESS;
1077 }
1078
parseFlashMapStoreHeader(const UByteArray & store,const UINT32 localOffset,const UModelIndex & parent,UModelIndex & index)1079 USTATUS NvramParser::parseFlashMapStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
1080 {
1081 const UINT32 dataSize = (UINT32)store.size();
1082
1083 // Check data size
1084 if (dataSize < sizeof(PHOENIX_FLASH_MAP_HEADER)) {
1085 msg(usprintf("%s: volume body is too small even for FlashMap block header", __FUNCTION__), parent);
1086 return U_SUCCESS;
1087 }
1088
1089 // Get FlashMap block header
1090 const PHOENIX_FLASH_MAP_HEADER* flashMapHeader = (const PHOENIX_FLASH_MAP_HEADER*)store.constData();
1091
1092 // Check store size
1093 UINT32 flashMapSize = sizeof(PHOENIX_FLASH_MAP_HEADER) + flashMapHeader->NumEntries * sizeof(PHOENIX_FLASH_MAP_ENTRY);
1094 if (dataSize < flashMapSize) {
1095 msg(usprintf("%s: FlashMap block size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__,
1096 flashMapSize, flashMapSize,
1097 dataSize, dataSize), parent);
1098 return U_SUCCESS;
1099 }
1100
1101 // Construct header and body
1102 UByteArray header = store.left(sizeof(PHOENIX_FLASH_MAP_HEADER));
1103 UByteArray body = store.mid(sizeof(PHOENIX_FLASH_MAP_HEADER), flashMapSize - sizeof(PHOENIX_FLASH_MAP_HEADER));
1104
1105 // Add info
1106 UString name("Phoenix SCT flash map");
1107 UString info = usprintf("Signature: _FLASH_MAP\nFull size: %Xh (%u)\nHeader size: %" PRIXQ "h (%" PRIuQ ")\nBody size: %" PRIXQ "h (%" PRIuQ ")\nNumber of entries: %u",
1108 flashMapSize, flashMapSize,
1109 header.size(), header.size(),
1110 body.size(), body.size(),
1111 flashMapHeader->NumEntries);
1112
1113 // Add tree item
1114 index = model->addItem(localOffset, Types::FlashMapStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
1115
1116 return U_SUCCESS;
1117 }
1118
parseCmdbStoreHeader(const UByteArray & store,const UINT32 localOffset,const UModelIndex & parent,UModelIndex & index)1119 USTATUS NvramParser::parseCmdbStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
1120 {
1121 const UINT32 dataSize = (UINT32)store.size();
1122
1123 // Check store size
1124 if (dataSize < sizeof(PHOENIX_CMDB_HEADER)) {
1125 msg(usprintf("%s: volume body is too small even for CMDB store header", __FUNCTION__), parent);
1126 return U_SUCCESS;
1127 }
1128
1129 UINT32 cmdbSize = NVRAM_PHOENIX_CMDB_SIZE;
1130 if (dataSize < cmdbSize) {
1131 msg(usprintf("%s: CMDB store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__,
1132 cmdbSize, cmdbSize,
1133 dataSize, dataSize), parent);
1134 return U_SUCCESS;
1135 }
1136
1137 // Get store header
1138 const PHOENIX_CMDB_HEADER* cmdbHeader = (const PHOENIX_CMDB_HEADER*)store.constData();
1139
1140 // Construct header and body
1141 UByteArray header = store.left(cmdbHeader->TotalSize);
1142 UByteArray body = store.mid(cmdbHeader->TotalSize, cmdbSize - cmdbHeader->TotalSize);
1143
1144 // Add info
1145 UString name("CMDB store");
1146 UString info = usprintf("Signature: CMDB\nFull size: %Xh (%u)\nHeader size: %" PRIXQ "h (%" PRIuQ ")\nBody size: %" PRIXQ "h (%" PRIuQ ")",
1147 cmdbSize, cmdbSize,
1148 header.size(), header.size(),
1149 body.size(), body.size());
1150
1151 // Add tree item
1152 index = model->addItem(localOffset, Types::CmdbStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
1153
1154 return U_SUCCESS;
1155 }
1156
parseSlicPubkeyHeader(const UByteArray & store,const UINT32 localOffset,const UModelIndex & parent,UModelIndex & index)1157 USTATUS NvramParser::parseSlicPubkeyHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
1158 {
1159 const UINT32 dataSize = (UINT32)store.size();
1160
1161 // Check data size
1162 if (dataSize < sizeof(OEM_ACTIVATION_PUBKEY)) {
1163 msg(usprintf("%s: volume body is too small even for SLIC pubkey header", __FUNCTION__), parent);
1164 return U_SUCCESS;
1165 }
1166
1167 // Get SLIC pubkey header
1168 const OEM_ACTIVATION_PUBKEY* pubkeyHeader = (const OEM_ACTIVATION_PUBKEY*)store.constData();
1169
1170 // Check store size
1171 if (dataSize < pubkeyHeader->Size) {
1172 msg(usprintf("%s: SLIC pubkey size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__,
1173 pubkeyHeader->Size, pubkeyHeader->Size,
1174 dataSize, dataSize), parent);
1175 return U_SUCCESS;
1176 }
1177
1178 // Construct header and body
1179 UByteArray header = store.left(sizeof(OEM_ACTIVATION_PUBKEY));
1180
1181 // Add info
1182 UString name("SLIC pubkey");
1183 UString info = usprintf("Type: 0h\nFull size: %Xh (%u)\nHeader size: %" PRIXQ "h (%" PRIuQ ")\nBody size: 0h (0)\n"
1184 "Key type: %02Xh\nVersion: %02Xh\nAlgorithm: %08Xh\nMagic: RSA1\nBit length: %08Xh\nExponent: %08Xh",
1185 pubkeyHeader->Size, pubkeyHeader->Size,
1186 header.size(), header.size(),
1187 pubkeyHeader->KeyType,
1188 pubkeyHeader->Version,
1189 pubkeyHeader->Algorithm,
1190 pubkeyHeader->BitLength,
1191 pubkeyHeader->Exponent);
1192
1193 // Add tree item
1194 index = model->addItem(localOffset, Types::SlicData, Subtypes::PubkeySlicData, name, UString(), info, header, UByteArray(), UByteArray(), Fixed, parent);
1195
1196 return U_SUCCESS;
1197 }
1198
parseSlicMarkerHeader(const UByteArray & store,const UINT32 localOffset,const UModelIndex & parent,UModelIndex & index)1199 USTATUS NvramParser::parseSlicMarkerHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
1200 {
1201 const UINT32 dataSize = (UINT32)store.size();
1202
1203 // Check data size
1204 if (dataSize < sizeof(OEM_ACTIVATION_MARKER)) {
1205 msg(usprintf("%s: volume body is too small even for SLIC marker header", __FUNCTION__), parent);
1206 return U_SUCCESS;
1207 }
1208
1209 // Get SLIC marker header
1210 const OEM_ACTIVATION_MARKER* markerHeader = (const OEM_ACTIVATION_MARKER*)store.constData();
1211
1212 // Check store size
1213 if (dataSize < markerHeader->Size) {
1214 msg(usprintf("%s: SLIC marker size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__,
1215 markerHeader->Size, markerHeader->Size,
1216 dataSize, dataSize), parent);
1217 return U_SUCCESS;
1218 }
1219
1220 // Construct header and body
1221 UByteArray header = store.left(sizeof(OEM_ACTIVATION_MARKER));
1222
1223 // Add info
1224 UString name("SLIC marker");
1225 UString info = usprintf("Type: 1h\nFull size: %Xh (%u)\nHeader size: %" PRIXQ "h (%" PRIuQ ")\nBody size: 0h (0)\n"
1226 "Version: %08Xh\nOEM ID: %s\nOEM table ID: %s\nWindows flag: WINDOWS\nSLIC version: %08Xh",
1227 markerHeader->Size, markerHeader->Size,
1228 header.size(), header.size(),
1229 markerHeader->Version,
1230 (const char*)UString((const char*)&(markerHeader->OemId)).left(6).toLocal8Bit(),
1231 (const char*)UString((const char*)&(markerHeader->OemTableId)).left(8).toLocal8Bit(),
1232 markerHeader->SlicVersion);
1233
1234
1235 // Add tree item
1236 index = model->addItem(localOffset, Types::SlicData, Subtypes::MarkerSlicData, name, UString(), info, header, UByteArray(), UByteArray(), Fixed, parent);
1237
1238 return U_SUCCESS;
1239 }
1240
parseStoreHeader(const UByteArray & store,const UINT32 localOffset,const UModelIndex & parent,UModelIndex & index)1241 USTATUS NvramParser::parseStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
1242 {
1243 const UINT32 dataSize = (UINT32)store.size();
1244 const UINT32* signature = (const UINT32*)store.constData();
1245 // Check store size
1246 if (dataSize < sizeof(UINT32)) {
1247 msg(usprintf("%s: volume body is too small even for a store signature", __FUNCTION__), parent);
1248 return U_SUCCESS;
1249 }
1250
1251 // Check signature and run parser function needed
1252 // VSS/SVS/NSS store
1253 if (*signature == NVRAM_VSS_STORE_SIGNATURE || *signature == NVRAM_APPLE_SVS_STORE_SIGNATURE || *signature == NVRAM_APPLE_NSS_STORE_SIGNATURE)
1254 return parseVssStoreHeader(store, localOffset, false, parent, index);
1255 // VSS2 store
1256 if (*signature == NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID_PART1 || *signature == NVRAM_VSS2_STORE_GUID_PART1)
1257 return parseVss2StoreHeader(store, localOffset, false, parent, index);
1258 // FTW store
1259 else if (*signature == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 || *signature == EDKII_WORKING_BLOCK_SIGNATURE_GUID_DATA1)
1260 return parseFtwStoreHeader(store, localOffset, parent, index);
1261 // FDC store
1262 else if (*signature == NVRAM_FDC_VOLUME_SIGNATURE)
1263 return parseFdcStoreHeader(store, localOffset, parent, index);
1264 // Apple Fsys/Gaid store
1265 else if (*signature == NVRAM_APPLE_FSYS_STORE_SIGNATURE || *signature == NVRAM_APPLE_GAID_STORE_SIGNATURE)
1266 return parseFsysStoreHeader(store, localOffset, parent, index);
1267 // EVSA store
1268 else if (dataSize >= 2 * sizeof(UINT32) && *(signature + 1) == NVRAM_EVSA_STORE_SIGNATURE)
1269 return parseEvsaStoreHeader(store, localOffset, parent, index);
1270 // Phoenix SCT flash map
1271 else if (*signature == NVRAM_PHOENIX_FLASH_MAP_SIGNATURE_PART1)
1272 return parseFlashMapStoreHeader(store, localOffset, parent, index);
1273 // Phoenix CMDB store
1274 else if (*signature == NVRAM_PHOENIX_CMDB_HEADER_SIGNATURE)
1275 return parseCmdbStoreHeader(store, localOffset, parent, index);
1276 // SLIC pubkey
1277 else if (dataSize >= 5 * sizeof(UINT32) && *(signature + 4) == OEM_ACTIVATION_PUBKEY_MAGIC)
1278 return parseSlicPubkeyHeader(store, localOffset, parent, index);
1279 // SLIC marker
1280 else if (dataSize >= 34 && *(const UINT64*)(store.constData() + 26) == OEM_ACTIVATION_MARKER_WINDOWS_FLAG)
1281 return parseSlicMarkerHeader(store, localOffset, parent, index);
1282 // Intel microcode
1283 // Must be checked after SLIC marker because of the same *signature values
1284 else if (*signature == INTEL_MICROCODE_HEADER_VERSION_1)
1285 return ffsParser->parseIntelMicrocodeHeader(store, localOffset, parent, index);
1286
1287 msg(usprintf("parseStoreHeader: don't know how to parse a header with signature %08Xh", *signature), parent);
1288 return U_SUCCESS;
1289 }
1290
parseFdcStoreBody(const UModelIndex & index)1291 USTATUS NvramParser::parseFdcStoreBody(const UModelIndex & index)
1292 {
1293 // Sanity check
1294 if (!index.isValid())
1295 return U_INVALID_PARAMETER;
1296
1297 // Get item data
1298 const UByteArray data = model->body(index);
1299
1300 // Get local offset
1301 UINT32 localOffset = (UINT32)model->header(index).size();
1302
1303 // The body is a firmware volume with either a VSS or VSS2 store
1304 UModelIndex volumeIndex;
1305 USTATUS status = ffsParser->parseVolumeHeader(data, localOffset, index, volumeIndex);
1306 if (status || !volumeIndex.isValid()) {
1307 msg(usprintf("%s: store can't be parsed as FDC store", __FUNCTION__), index);
1308 return U_SUCCESS;
1309 }
1310
1311 // Determine if it's a VSS or VSS2 store inside
1312 UByteArray store = model->body(volumeIndex);
1313 if ((UINT32)store.size() >= sizeof(UINT32) && *(const UINT32*)store.constData() == NVRAM_VSS_STORE_SIGNATURE) {
1314 UModelIndex vssIndex;
1315 status = parseVssStoreHeader(store, (UINT32)(localOffset + model->header(volumeIndex).size()), true, volumeIndex, vssIndex);
1316 if (status)
1317 return status;
1318 return parseVssStoreBody(vssIndex, 0);
1319 }
1320 else if ((UINT32)store.size() >= sizeof(EFI_GUID) && store.left(sizeof(EFI_GUID)) == NVRAM_FDC_STORE_GUID) {
1321 UModelIndex vss2Index;
1322 status = parseVss2StoreHeader(store, (UINT32)(localOffset + model->header(volumeIndex).size()), true, volumeIndex, vss2Index);
1323 if (status)
1324 return status;
1325 return parseVssStoreBody(vss2Index, 0);
1326 }
1327 else {
1328 msg(usprintf("%s: internal volume can't be parsed as VSS/VSS2 store", __FUNCTION__), index);
1329 return U_SUCCESS;
1330 }
1331
1332 }
1333
parseVssStoreBody(const UModelIndex & index,UINT8 alignment)1334 USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index, UINT8 alignment)
1335 {
1336 // Sanity check
1337 if (!index.isValid())
1338 return U_INVALID_PARAMETER;
1339
1340 // Obtain required information from parent volume
1341 UINT8 emptyByte = 0xFF;
1342 UModelIndex parentVolumeIndex = model->findParentOfType(index, Types::Volume);
1343 if (parentVolumeIndex.isValid() && model->hasEmptyParsingData(parentVolumeIndex) == false) {
1344 UByteArray data = model->parsingData(parentVolumeIndex);
1345 const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData();
1346 emptyByte = pdata->emptyByte;
1347 }
1348
1349 // Get local offset
1350 UINT32 localOffset = (UINT32)model->header(index).size();
1351
1352 // Get item data
1353 const UByteArray data = model->body(index);
1354
1355 // Check that the is enough space for variable header
1356 const UINT32 dataSize = (UINT32)data.size();
1357 if (dataSize < sizeof(VSS_VARIABLE_HEADER)) {
1358 msg(usprintf("%s: store body is too small even for VSS variable header", __FUNCTION__), index);
1359 return U_SUCCESS;
1360 }
1361
1362 UINT32 offset = 0;
1363
1364 // Parse all variables
1365 while (1) {
1366 bool isInvalid = true;
1367 bool isAuthenticated = false;
1368 bool isAppleCrc32 = false;
1369 bool isIntelSpecial = false;
1370
1371 UINT32 storedCrc32 = 0;
1372 UINT32 calculatedCrc32 = 0;
1373 UINT64 monotonicCounter = 0;
1374 EFI_TIME timestamp = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1375 UINT32 pubKeyIndex = 0;
1376
1377 UINT8 subtype = 0;
1378 UString name;
1379 UString text;
1380 EFI_GUID* variableGuid = NULL;
1381 CHAR16* variableName = (CHAR16*)L"";
1382 UByteArray header;
1383 UByteArray body;
1384
1385 UINT32 unparsedSize = dataSize - offset;
1386
1387 // Get variable header
1388 const VSS_VARIABLE_HEADER* variableHeader = (const VSS_VARIABLE_HEADER*)(data.constData() + offset);
1389
1390 // Check variable header to fit in still unparsed data
1391 UINT32 variableSize = 0;
1392 if (unparsedSize >= sizeof(VSS_VARIABLE_HEADER)
1393 && variableHeader->StartId == NVRAM_VSS_VARIABLE_START_ID) {
1394 // Apple VSS variable with CRC32 of the data
1395 if (variableHeader->Attributes & NVRAM_VSS_VARIABLE_APPLE_DATA_CHECKSUM) {
1396 isAppleCrc32 = true;
1397 if (unparsedSize < sizeof(VSS_APPLE_VARIABLE_HEADER)) {
1398 variableSize = 0;
1399 }
1400 else {
1401 const VSS_APPLE_VARIABLE_HEADER* appleVariableHeader = (const VSS_APPLE_VARIABLE_HEADER*)variableHeader;
1402 variableSize = sizeof(VSS_APPLE_VARIABLE_HEADER) + appleVariableHeader->NameSize + appleVariableHeader->DataSize;
1403 variableGuid = (EFI_GUID*)&appleVariableHeader->VendorGuid;
1404 variableName = (CHAR16*)(appleVariableHeader + 1);
1405
1406 header = data.mid(offset, sizeof(VSS_APPLE_VARIABLE_HEADER) + appleVariableHeader->NameSize);
1407 body = data.mid(offset + header.size(), appleVariableHeader->DataSize);
1408
1409 // Calculate CRC32 of the variable data
1410 storedCrc32 = appleVariableHeader->DataCrc32;
1411 calculatedCrc32 = (UINT32)crc32(0, (const UINT8*)body.constData(), (uInt)body.size());
1412 }
1413 }
1414
1415 // Authenticated variable
1416 else if ((variableHeader->Attributes & NVRAM_VSS_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
1417 || (variableHeader->Attributes & NVRAM_VSS_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
1418 || (variableHeader->Attributes & NVRAM_VSS_VARIABLE_APPEND_WRITE)
1419 || (variableHeader->NameSize == 0 && variableHeader->DataSize == 0)) { // If both NameSize and DataSize are zeros, it's auth variable with zero montonic counter
1420 isAuthenticated = true;
1421 if (unparsedSize < sizeof(VSS_AUTH_VARIABLE_HEADER)) {
1422 variableSize = 0;
1423 }
1424 else {
1425 const VSS_AUTH_VARIABLE_HEADER* authVariableHeader = (const VSS_AUTH_VARIABLE_HEADER*)variableHeader;
1426 variableSize = sizeof(VSS_AUTH_VARIABLE_HEADER) + authVariableHeader->NameSize + authVariableHeader->DataSize;
1427 variableGuid = (EFI_GUID*)&authVariableHeader->VendorGuid;
1428 variableName = (CHAR16*)(authVariableHeader + 1);
1429
1430 header = data.mid(offset, sizeof(VSS_AUTH_VARIABLE_HEADER) + authVariableHeader->NameSize);
1431 body = data.mid(offset + header.size(), authVariableHeader->DataSize);
1432
1433 monotonicCounter = authVariableHeader->MonotonicCounter;
1434 timestamp = authVariableHeader->Timestamp;
1435 pubKeyIndex = authVariableHeader->PubKeyIndex;
1436 }
1437 }
1438
1439 // Intel special variable
1440 else if (variableHeader->State == NVRAM_VSS_INTEL_VARIABLE_VALID
1441 || variableHeader->State == NVRAM_VSS_INTEL_VARIABLE_INVALID) {
1442 isIntelSpecial = true;
1443 const VSS_INTEL_VARIABLE_HEADER* intelVariableHeader = (const VSS_INTEL_VARIABLE_HEADER*)variableHeader;
1444 variableSize = intelVariableHeader->TotalSize;
1445 variableGuid = (EFI_GUID*)&intelVariableHeader->VendorGuid;
1446 variableName = (CHAR16*)(intelVariableHeader + 1);
1447
1448 UINT32 i = 0;
1449 while (variableName[i] != 0) ++i;
1450
1451 i = sizeof(VSS_INTEL_VARIABLE_HEADER) + 2 * (i + 1);
1452 i = i < variableSize ? i : variableSize;
1453
1454 header = data.mid(offset, i);
1455 body = data.mid(offset + header.size(), variableSize - i);
1456 }
1457
1458 // Normal VSS variable
1459 else {
1460 variableSize = sizeof(VSS_VARIABLE_HEADER) + variableHeader->NameSize + variableHeader->DataSize;
1461 variableGuid = (EFI_GUID*)&variableHeader->VendorGuid;
1462 variableName = (CHAR16*)(variableHeader + 1);
1463
1464 header = data.mid(offset, sizeof(VSS_VARIABLE_HEADER) + variableHeader->NameSize);
1465 body = data.mid(offset + header.size(), variableHeader->DataSize);
1466 }
1467
1468 // Check variable state
1469 if (variableHeader->State == NVRAM_VSS_INTEL_VARIABLE_VALID
1470 || variableHeader->State == NVRAM_VSS_VARIABLE_ADDED
1471 || variableHeader->State == NVRAM_VSS_VARIABLE_HEADER_VALID) {
1472 isInvalid = false;
1473 }
1474
1475 // Check variable size
1476 if (variableSize > unparsedSize) {
1477 variableSize = 0;
1478 }
1479 }
1480
1481 // Can't parse further, add the last element and break the loop
1482 if (!variableSize) {
1483 // Check if the data left is a free space or a padding
1484 UByteArray padding = data.mid(offset, unparsedSize);
1485 // Get info
1486 UString info = usprintf("Full size: %" PRIXQ "h (%" PRIuQ ")", padding.size(), padding.size());
1487
1488 if (padding.count(emptyByte) == padding.size()) { // Free space
1489 // Add tree item
1490 model->addItem(localOffset + offset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
1491 }
1492 else { // Padding
1493 // Nothing is parsed yet, but the store is not empty
1494 if (!offset) {
1495 msg(usprintf("%s: store can't be parsed as VSS store", __FUNCTION__), index);
1496 return U_SUCCESS;
1497 }
1498
1499 // Add tree item
1500 model->addItem(localOffset + offset, Types::Padding, getPaddingType(padding), UString("Padding"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
1501 }
1502
1503 return U_SUCCESS;
1504 }
1505
1506 UString info;
1507
1508 // Rename invalid variables
1509 if (isInvalid || !variableGuid) {
1510 isInvalid = true;
1511 name = UString("Invalid");
1512 }
1513 else { // Add GUID and text for valid variables
1514 name = guidToUString(readUnaligned(variableGuid));
1515 info += UString("Variable GUID: ") + guidToUString(readUnaligned(variableGuid), false) + UString("\n");
1516
1517 #if QT_VERSION_MAJOR >= 6
1518 text = UString::fromUtf16((char16_t *)variableName);
1519 #else
1520 text = UString::fromUtf16(variableName);
1521 #endif
1522 }
1523
1524 // Add info
1525 info += usprintf("Full size: %Xh (%u)\nHeader size: %" PRIXQ "h (%" PRIuQ ")\nBody size: %" PRIXQ "h (%" PRIuQ ")\nState: %02Xh\nReserved: %02Xh\nAttributes: %08Xh (",
1526 variableSize, variableSize,
1527 header.size(), header.size(),
1528 body.size(), body.size(),
1529 variableHeader->State,
1530 variableHeader->Reserved,
1531 variableHeader->Attributes) + vssAttributesToUString(variableHeader->Attributes) + UString(")");
1532
1533 // Set subtype and add related info
1534 if (isInvalid)
1535 subtype = Subtypes::InvalidVssEntry;
1536 else if (isAuthenticated) {
1537 subtype = Subtypes::AuthVssEntry;
1538 info += usprintf("\nMonotonic counter: %" PRIX64 "h\nTimestamp: ", monotonicCounter) + efiTimeToUString(timestamp)
1539 + usprintf("\nPubKey index: %u", pubKeyIndex);
1540 }
1541 else if (isAppleCrc32) {
1542 subtype = Subtypes::AppleVssEntry;
1543 info += usprintf("\nData checksum: %08Xh", storedCrc32) +
1544 (storedCrc32 != calculatedCrc32 ? usprintf(", invalid, should be %08Xh", calculatedCrc32) : UString(", valid"));
1545 }
1546 else if (isIntelSpecial) {
1547 subtype = Subtypes::IntelVssEntry;
1548 }
1549 else {
1550 subtype = Subtypes::StandardVssEntry;
1551 }
1552
1553 // Add tree item
1554 model->addItem(localOffset + offset, Types::VssEntry, subtype, name, text, info, header, body, UByteArray(), Fixed, index);
1555
1556 // Apply alignment, if needed
1557 if (alignment) {
1558 variableSize = ((variableSize + alignment - 1) & (~(alignment - 1)));
1559 }
1560
1561 // Move to next variable
1562 offset += variableSize;
1563 }
1564
1565 return U_SUCCESS;
1566 }
1567
parseFsysStoreBody(const UModelIndex & index)1568 USTATUS NvramParser::parseFsysStoreBody(const UModelIndex & index)
1569 {
1570 // Sanity check
1571 if (!index.isValid())
1572 return U_INVALID_PARAMETER;
1573
1574 // Get local offset
1575 UINT32 localOffset = (UINT32)model->header(index).size();
1576
1577 // Get item data
1578 const UByteArray data = model->body(index);
1579
1580 // Check that the is enough space for variable header
1581 const UINT32 storeDataSize = (UINT32)data.size();
1582 UINT32 offset = 0;
1583
1584 // Parse all variables
1585 while (1) {
1586 UINT32 unparsedSize = storeDataSize - offset;
1587 UINT32 variableSize = 0;
1588
1589 // Get nameSize and name of the variable
1590 UINT8 nameSize = *(UINT8*)(data.constData() + offset);
1591 bool valid = !(nameSize & 0x80); // Last bit is a validity bit, 0 means valid
1592 nameSize &= 0x7F;
1593
1594 // Check sanity
1595 if (unparsedSize >= nameSize + sizeof(UINT8)) {
1596 variableSize = nameSize + sizeof(UINT8);
1597 }
1598
1599 UByteArray name;
1600 if (variableSize) {
1601 name = data.mid(offset + sizeof(UINT8), nameSize);
1602 // Check for EOF variable
1603 if (nameSize == 3 && name[0] == 'E' && name[1] == 'O' && name[2] == 'F') {
1604 // There is no data afterward, add EOF variable and free space and return
1605 UByteArray header = data.mid(offset, sizeof(UINT8) + nameSize);
1606 UString info = usprintf("Full size: %" PRIXQ "h (%" PRIuQ ")", header.size(), header.size());
1607
1608 // Add EOF tree item
1609 model->addItem(localOffset + offset, Types::FsysEntry, Subtypes::NormalFsysEntry, UString("EOF"), UString(), info, header, UByteArray(), UByteArray(), Fixed, index);
1610
1611 // Add free space
1612 offset += header.size();
1613 UByteArray body = data.mid(offset);
1614 info = usprintf("Full size: %" PRIXQ "h (%" PRIuQ ")", body.size(), body.size());
1615
1616 // Add free space tree item
1617 model->addItem(localOffset + offset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index);
1618
1619 return U_SUCCESS;
1620 }
1621 }
1622
1623 // Get dataSize and data of the variable
1624 const UINT16 dataSize = *(UINT16*)(data.constData() + offset + sizeof(UINT8) + nameSize);
1625 if (unparsedSize >= sizeof(UINT8) + nameSize + sizeof(UINT16) + dataSize) {
1626 variableSize = sizeof(UINT8) + nameSize + sizeof(UINT16) + dataSize;
1627 }
1628 else {
1629 // Last variable is bad, add the rest as padding and return
1630 UByteArray body = data.mid(offset);
1631 UString info = usprintf("Full size: %" PRIXQ "h (%" PRIuQ ")", body.size(), body.size());
1632
1633 // Add padding tree item
1634 model->addItem(localOffset + offset, Types::Padding, getPaddingType(body), UString("Padding"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index);
1635
1636 // Show message
1637 msg(usprintf("%s: next variable appears too big, added as padding", __FUNCTION__), index);
1638
1639 return U_SUCCESS;
1640 }
1641
1642 // Construct header and body
1643 UByteArray header = data.mid(offset, sizeof(UINT8) + nameSize + sizeof(UINT16));
1644 UByteArray body = data.mid(offset + sizeof(UINT8) + nameSize + sizeof(UINT16), dataSize);
1645
1646 // Add info
1647 UString info = usprintf("Full size: %Xh (%u)\nHeader size: %" PRIXQ "h (%" PRIuQ ")\nBody size: %" PRIXQ "h (%" PRIuQ ")",
1648 variableSize, variableSize,
1649 header.size(), header.size(),
1650 body.size(), body.size());
1651
1652 // Add tree item
1653 model->addItem(localOffset + offset, Types::FsysEntry, valid ? Subtypes::NormalFsysEntry : Subtypes::InvalidFsysEntry, UString(name.constData()), UString(), info, header, body, UByteArray(), Fixed, index);
1654
1655 // Move to next variable
1656 offset += variableSize;
1657 }
1658
1659 return U_SUCCESS;
1660 }
1661
parseEvsaStoreBody(const UModelIndex & index)1662 USTATUS NvramParser::parseEvsaStoreBody(const UModelIndex & index)
1663 {
1664 // Sanity check
1665 if (!index.isValid())
1666 return U_INVALID_PARAMETER;
1667
1668 // Obtain required information from parent volume
1669 UINT8 emptyByte = 0xFF;
1670 UModelIndex parentVolumeIndex = model->findParentOfType(index, Types::Volume);
1671 if (parentVolumeIndex.isValid() && model->hasEmptyParsingData(parentVolumeIndex) == false) {
1672 UByteArray data = model->parsingData(parentVolumeIndex);
1673 const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData();
1674 emptyByte = pdata->emptyByte;
1675 }
1676
1677 // Get local offset
1678 UINT32 localOffset = (UINT32)model->header(index).size();
1679
1680 // Get item data
1681 const UByteArray data = model->body(index);
1682
1683 // Check that the is enough space for entry header
1684 const UINT32 storeDataSize = (UINT32)data.size();
1685 UINT32 offset = 0;
1686
1687 std::map<UINT16, EFI_GUID> guidMap;
1688 std::map<UINT16, UString> nameMap;
1689
1690 // Parse all entries
1691 UINT32 unparsedSize = storeDataSize;
1692 while (unparsedSize) {
1693 UINT32 variableSize = 0;
1694 UString name;
1695 UString info;
1696 UByteArray header;
1697 UByteArray body;
1698 UINT8 subtype;
1699 UINT8 calculated;
1700
1701 const EVSA_ENTRY_HEADER* entryHeader = (const EVSA_ENTRY_HEADER*)(data.constData() + offset);
1702
1703 // Check entry size
1704 variableSize = sizeof(EVSA_ENTRY_HEADER);
1705 if (unparsedSize < variableSize || unparsedSize < entryHeader->Size) {
1706 body = data.mid(offset);
1707 info = usprintf("Full size: %" PRIXQ "h (%" PRIuQ ")", body.size(), body.size());
1708
1709 if (body.count(emptyByte) == body.size()) { // Free space
1710 // Add free space tree item
1711 model->addItem(localOffset + offset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index);
1712 }
1713 else {
1714 // Add padding tree item
1715 UModelIndex itemIndex = model->addItem(localOffset + offset, Types::Padding, getPaddingType(body), UString("Padding"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index);
1716
1717 // Show message
1718 msg(usprintf("%s: variable parsing failed, the rest of unparsed store added as padding", __FUNCTION__), itemIndex);
1719 }
1720 break;
1721 }
1722 variableSize = entryHeader->Size;
1723
1724 // Recalculate entry checksum
1725 calculated = calculateChecksum8(((const UINT8*)entryHeader) + 2, entryHeader->Size - 2);
1726
1727 // GUID entry
1728 if (entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_GUID1 ||
1729 entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_GUID2) {
1730 const EVSA_GUID_ENTRY* guidHeader = (const EVSA_GUID_ENTRY*)entryHeader;
1731 header = data.mid(offset, sizeof(EVSA_GUID_ENTRY));
1732 body = data.mid(offset + sizeof(EVSA_GUID_ENTRY), guidHeader->Header.Size - sizeof(EVSA_GUID_ENTRY));
1733 EFI_GUID guid = *(EFI_GUID*)body.constData();
1734 name = guidToUString(guid);
1735 info = UString("GUID: ") + guidToUString(guid, false) + usprintf("\nFull size: %Xh (%u)\nHeader size: %" PRIXQ "h (%" PRIuQ ")\nBody size: %" PRIXQ "h (%" PRIuQ ")\nType: %02Xh\nChecksum: %02Xh",
1736 variableSize, variableSize,
1737 header.size(), header.size(),
1738 body.size(), body.size(),
1739 guidHeader->Header.Type,
1740 guidHeader->Header.Checksum)
1741 + (guidHeader->Header.Checksum != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid"))
1742 + usprintf("\nGuidId: %04Xh", guidHeader->GuidId);
1743 subtype = Subtypes::GuidEvsaEntry;
1744 guidMap.insert(std::pair<UINT16, EFI_GUID>(guidHeader->GuidId, guid));
1745 }
1746 // Name entry
1747 else if (entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_NAME1 ||
1748 entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_NAME2) {
1749 const EVSA_NAME_ENTRY* nameHeader = (const EVSA_NAME_ENTRY*)entryHeader;
1750 header = data.mid(offset, sizeof(EVSA_NAME_ENTRY));
1751 body = data.mid(offset + sizeof(EVSA_NAME_ENTRY), nameHeader->Header.Size - sizeof(EVSA_NAME_ENTRY));
1752
1753 #if QT_VERSION_MAJOR >= 6
1754 name = UString::fromUtf16((const char16_t *)body.constData());
1755 #else
1756 name = UString::fromUtf16((const CHAR16*)body.constData());
1757 #endif
1758
1759 info = UString("Name: ") + name + usprintf("\nFull size: %Xh (%u)\nHeader size: %" PRIXQ "h (%" PRIuQ ")\nBody size: %" PRIXQ "h (%" PRIuQ ")\nType: %02Xh\nChecksum: %02Xh",
1760 variableSize, variableSize,
1761 header.size(), header.size(),
1762 body.size(), body.size(),
1763 nameHeader->Header.Type,
1764 nameHeader->Header.Checksum)
1765 + (nameHeader->Header.Checksum != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid"))
1766 + usprintf("\nVarId: %04Xh", nameHeader->VarId);
1767 subtype = Subtypes::NameEvsaEntry;
1768 nameMap.insert(std::pair<UINT16, UString>(nameHeader->VarId, name));
1769 }
1770 // Data entry
1771 else if (entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_DATA1 ||
1772 entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_DATA2 ||
1773 entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_DATA_INVALID) {
1774 const EVSA_DATA_ENTRY* dataHeader = (const EVSA_DATA_ENTRY*)entryHeader;
1775 // Check for extended header
1776 UINT32 headerSize = sizeof(EVSA_DATA_ENTRY);
1777 UINT32 dataSize = dataHeader->Header.Size - sizeof(EVSA_DATA_ENTRY);
1778 if (dataHeader->Attributes & NVRAM_EVSA_DATA_EXTENDED_HEADER) {
1779 const EVSA_DATA_ENTRY_EXTENDED* dataHeaderExtended = (const EVSA_DATA_ENTRY_EXTENDED*)entryHeader;
1780 headerSize = sizeof(EVSA_DATA_ENTRY_EXTENDED);
1781 dataSize = dataHeaderExtended->DataSize;
1782 variableSize = headerSize + dataSize;
1783 }
1784
1785 header = data.mid(offset, headerSize);
1786 body = data.mid(offset + headerSize, dataSize);
1787 name = UString("Data");
1788 info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nType: %02Xh\nChecksum: %02Xh",
1789 variableSize, variableSize,
1790 headerSize, headerSize,
1791 dataSize, dataSize,
1792 dataHeader->Header.Type,
1793 dataHeader->Header.Checksum)
1794 + (dataHeader->Header.Checksum != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid"))
1795 + usprintf("\nVarId: %04Xh\nGuidId: %04Xh\nAttributes: %08Xh (",
1796 dataHeader->VarId,
1797 dataHeader->GuidId,
1798 dataHeader->Attributes)
1799 + evsaAttributesToUString(dataHeader->Attributes) + UString(")");
1800 subtype = Subtypes::DataEvsaEntry;
1801 }
1802 // Unknown entry or free space
1803 else {
1804 body = data.mid(offset);
1805 info = usprintf("Full size: %" PRIXQ "h (%" PRIuQ ")", body.size(), body.size());
1806
1807 if (body.count(emptyByte) == body.size()) { // Free space
1808 // Add free space tree item
1809 model->addItem(localOffset + offset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index);
1810 }
1811 else {
1812 // Add padding tree item
1813 UModelIndex itemIndex = model->addItem(localOffset + offset, Types::Padding, getPaddingType(body), UString("Padding"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index);
1814
1815 // Show message
1816 msg(usprintf("%s: unknown variable of type %02Xh found at offset %Xh, the rest of unparsed store added as padding", __FUNCTION__, entryHeader->Type, offset), itemIndex);
1817 }
1818 break;
1819 }
1820
1821 // Add tree item
1822 model->addItem(localOffset + offset, Types::EvsaEntry, subtype, name, UString(), info, header, body, UByteArray(), Fixed, index);
1823
1824 // Move to next variable
1825 offset += variableSize;
1826 unparsedSize = storeDataSize - offset;
1827 }
1828
1829 // Reparse all data variables to detect invalid ones and assign name and test to valid ones
1830 for (int i = 0; i < model->rowCount(index); i++) {
1831 #if ((QT_VERSION_MAJOR == 5) && (QT_VERSION_MINOR < 6)) || (QT_VERSION_MAJOR < 5)
1832 UModelIndex current = index.child(i, 0);
1833 #else
1834 UModelIndex current = index.model()->index(i, 0, index);
1835 #endif
1836
1837 if (model->subtype(current) == Subtypes::DataEvsaEntry) {
1838 UByteArray header = model->header(current);
1839 const EVSA_DATA_ENTRY* dataHeader = (const EVSA_DATA_ENTRY*)header.constData();
1840 UString guid;
1841 if (guidMap.count(dataHeader->GuidId))
1842 guid = guidToUString(guidMap[dataHeader->GuidId], false);
1843 UString name;
1844 if (nameMap.count(dataHeader->VarId))
1845 name = nameMap[dataHeader->VarId];
1846
1847 // Check for variable validity
1848 if (guid.isEmpty() && name.isEmpty()) { // Both name and guid aren't found
1849 model->setSubtype(current, Subtypes::InvalidEvsaEntry);
1850 model->setName(current, UString("Invalid"));
1851 msg(usprintf("%s: data variable with invalid GuidId and invalid VarId", __FUNCTION__), current);
1852 }
1853 else if (guid.isEmpty()) { // Guid not found
1854 model->setSubtype(current, Subtypes::InvalidEvsaEntry);
1855 model->setName(current, UString("Invalid"));
1856 msg(usprintf("%s: data variable with invalid GuidId", __FUNCTION__), current);
1857 }
1858 else if (name.isEmpty()) { // Name not found
1859 model->setSubtype(current, Subtypes::InvalidEvsaEntry);
1860 model->setName(current, UString("Invalid"));
1861 msg(usprintf("%s: data variable with invalid VarId", __FUNCTION__), current);
1862 }
1863 else { // Variable is OK, rename it
1864 if (dataHeader->Header.Type == NVRAM_EVSA_ENTRY_TYPE_DATA_INVALID) {
1865 model->setSubtype(current, Subtypes::InvalidEvsaEntry);
1866 model->setName(current, UString("Invalid"));
1867 }
1868 else {
1869 model->setName(current, guid);
1870 }
1871 model->setText(current, name);
1872 model->addInfo(current, UString("GUID: ") + guid + UString("\nName: ") + name + UString("\n"), false);
1873 }
1874 }
1875 }
1876
1877 return U_SUCCESS;
1878 }
1879
1880
parseFlashMapBody(const UModelIndex & index)1881 USTATUS NvramParser::parseFlashMapBody(const UModelIndex & index)
1882 {
1883 // Sanity check
1884 if (!index.isValid())
1885 return U_INVALID_PARAMETER;
1886
1887 // Get parsing data for the current item
1888 UINT32 localOffset = (UINT32)model->header(index).size();
1889 const UByteArray data = model->body(index);
1890
1891
1892 const UINT32 dataSize = (UINT32)data.size();
1893 UINT32 offset = 0;
1894 UINT32 unparsedSize = dataSize;
1895 // Parse all entries
1896 while (unparsedSize) {
1897 const PHOENIX_FLASH_MAP_ENTRY* entryHeader = (const PHOENIX_FLASH_MAP_ENTRY*)(data.constData() + offset);
1898
1899 // Check entry size
1900 if (unparsedSize < sizeof(PHOENIX_FLASH_MAP_ENTRY)) {
1901 // Last variable is bad, add the rest as padding and return
1902 UByteArray body = data.mid(offset);
1903 UString info = usprintf("Full size: %" PRIXQ "h (%" PRIuQ ")", body.size(), body.size());
1904
1905 // Add padding tree item
1906 model->addItem(localOffset + offset, Types::Padding, getPaddingType(body), UString("Padding"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index);
1907
1908 // Show message
1909 if (unparsedSize < entryHeader->Size)
1910 msg(usprintf("%s: next entry appears too big, added as padding", __FUNCTION__), index);
1911
1912 break;
1913 }
1914
1915 UString name = guidToUString(entryHeader->Guid);
1916
1917 // Construct header
1918 UByteArray header = data.mid(offset, sizeof(PHOENIX_FLASH_MAP_ENTRY));
1919
1920 // Add info
1921 UString info = UString("Entry GUID: ") + guidToUString(entryHeader->Guid, false) +
1922 usprintf("\nFull size: 24h (36)\nHeader size: 24h (36)\nBody size: 0h (0)\n"
1923 "Entry type: %04Xh\nData type: %04Xh\nMemory address: %08llXh\nSize: %08Xh\nOffset: %08Xh",
1924 entryHeader->EntryType,
1925 entryHeader->DataType,
1926 (unsigned long long)entryHeader->PhysicalAddress,
1927 entryHeader->Size,
1928 entryHeader->Offset);
1929
1930 // Determine subtype
1931 UINT8 subtype = 0;
1932 switch (entryHeader->DataType) {
1933 case NVRAM_PHOENIX_FLASH_MAP_ENTRY_TYPE_VOLUME:
1934 subtype = Subtypes::VolumeFlashMapEntry;
1935 break;
1936 case NVRAM_PHOENIX_FLASH_MAP_ENTRY_TYPE_DATA_BLOCK:
1937 subtype = Subtypes::DataFlashMapEntry;
1938 break;
1939 }
1940
1941 // Add tree item
1942 model->addItem(localOffset + offset, Types::FlashMapEntry, subtype, name, flashMapGuidToUString(entryHeader->Guid), info, header, UByteArray(), UByteArray(), Fixed, index);
1943
1944 // Move to next variable
1945 offset += sizeof(PHOENIX_FLASH_MAP_ENTRY);
1946 unparsedSize = dataSize - offset;
1947 }
1948
1949 return U_SUCCESS;
1950 }
1951 #endif // U_ENABLE_NVRAM_PARSING_SUPPORT
1952