Add Hardware Health Frontpage Menu

A UEFI front page application which displays various fields of hardware error records to the user
This commit is contained in:
Taylor Beebe 2021-04-05 21:22:25 +00:00
Родитель 5f767678ad
Коммит 859ebe80ae
22 изменённых файлов: 2430 добавлений и 3 удалений

Просмотреть файл

@ -0,0 +1,37 @@
/** @file
CreatorIDParser.c
A function for parsing the creator ID which for now just prints the guid.
Created to more easily implement friendly strings in the future
Copyright (c) Microsoft Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi.h>
#include <Guid/Cper.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include "CreatorIDParser.h"
#include "HwhMenu.h"
/**
* Parses the Creator ID which, for now, just prints the GUID
*
* @param[in] EFI_GUID* Guid being parsed
*
* @retval VOID
**/
VOID
ParseCreatorID(
IN CONST EFI_GUID *CreatorID
)
{
// For now, just print the guid. Leaving this separate file
// to make extending guid parsing in the future a bit simpler
UnicodeDataToVFR((EFI_STRING_ID)STR_HWH_LOG_CREATORID_VALUE,
L"%g",
CreatorID);
}

Просмотреть файл

@ -0,0 +1,21 @@
/** @file
CreatorIDParser.h
A function for parsing the creator ID which for now just prints the guid.
Created to more easily implement friendly strings in the future
Copyright (c) Microsoft Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
/**
* Parses the Creator ID which, for now, just prints the GUID
*
* @param[in] EFI_GUID* Guid being parsed
*
* @retval VOID
**/
VOID
ParseCreatorID(
IN CONST EFI_GUID *CreatorID
);

971
MsWheaPkg/HwhMenu/HwhMenu.c Normal file
Просмотреть файл

@ -0,0 +1,971 @@
/** @file
Hwhmenu.c
Hardware Health - Menu to display HwErrRecs
Copyright (c) Microsoft Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi.h>
#include <Protocol/HiiConfigAccess.h>
#include <Guid/HwhMenuGuid.h>
#include <Guid/MdeModuleHii.h>
#include <Guid/Cper.h>
#include <Guid/MsWheaReportDataType.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/DevicePathLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/HiiLib.h>
#include <Library/UefiHiiServicesLib.h>
#include <Library/PrintLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/CheckHwErrRecHeaderLib.h>
#include <Library/ParserRegistryLib.h>
#include <MsWheaErrorStatus.h>
#include <MsWheaReport/MsWheaReportCommon.h>
#include "HwhMenu.h"
#include "HwhMenuVfr.h"
#include "CreatorIDParser.h"
#include "PlatformIDParser.h"
#pragma pack(1)
// Struct Containing a HWErrRec
typedef struct ErrorRecord
{
LIST_ENTRY entry; // Necessary for linked list structure
EFI_COMMON_ERROR_RECORD_HEADER *error; // Pointer to the HWErrRec
UINT32 val; // Page number
} ErrorRecord;
#pragma pack()
//*---------------------------------------------------------------------------------------*
//* Global Variables *
//*---------------------------------------------------------------------------------------*
STATIC HWH_MENU_CONFIG mHwhMenuConfiguration = {LOGS_TRUE}; // Configuration for VFR
LIST_ENTRY mListHead = INITIALIZE_LIST_HEAD_VARIABLE(mListHead); // Head of the linked list
UINT32 NumErrorEntries = 0; // Number of HwErrRec(s)
ErrorRecord *currentPage = NULL; // Current record displayed on the page
CHAR16 UnicodeString[MAX_DISPLAY_STRING_LENGTH + 1]; // Unicode buffer for printing
#define HWH_MENU_SIGNATURE SIGNATURE_32('H', 'w', 'h', 'm')
#define NUM_SEC_DATA_ROWS 15
#define NUM_SEC_DATA_COLUMNS 3
// Writable UNI strings. NOTE: We are using row-column addressing
CONST EFI_STRING_ID DisplayLines[NUM_SEC_DATA_ROWS][NUM_SEC_DATA_COLUMNS] =
{
{STRING_TOKEN(STR_HWH_LOG_LINE_0_0), STRING_TOKEN(STR_HWH_LOG_LINE_0_1), STRING_TOKEN(STR_HWH_LOG_LINE_0_2)},
{STRING_TOKEN(STR_HWH_LOG_LINE_1_0), STRING_TOKEN(STR_HWH_LOG_LINE_1_1), STRING_TOKEN(STR_HWH_LOG_LINE_1_2)},
{STRING_TOKEN(STR_HWH_LOG_LINE_2_0), STRING_TOKEN(STR_HWH_LOG_LINE_2_1), STRING_TOKEN(STR_HWH_LOG_LINE_2_2)},
{STRING_TOKEN(STR_HWH_LOG_LINE_3_0), STRING_TOKEN(STR_HWH_LOG_LINE_3_1), STRING_TOKEN(STR_HWH_LOG_LINE_3_2)},
{STRING_TOKEN(STR_HWH_LOG_LINE_4_0), STRING_TOKEN(STR_HWH_LOG_LINE_4_1), STRING_TOKEN(STR_HWH_LOG_LINE_4_2)},
{STRING_TOKEN(STR_HWH_LOG_LINE_5_0), STRING_TOKEN(STR_HWH_LOG_LINE_5_1), STRING_TOKEN(STR_HWH_LOG_LINE_5_2)},
{STRING_TOKEN(STR_HWH_LOG_LINE_6_0), STRING_TOKEN(STR_HWH_LOG_LINE_6_1), STRING_TOKEN(STR_HWH_LOG_LINE_6_2)},
{STRING_TOKEN(STR_HWH_LOG_LINE_7_0), STRING_TOKEN(STR_HWH_LOG_LINE_7_1), STRING_TOKEN(STR_HWH_LOG_LINE_7_2)},
{STRING_TOKEN(STR_HWH_LOG_LINE_8_0), STRING_TOKEN(STR_HWH_LOG_LINE_8_1), STRING_TOKEN(STR_HWH_LOG_LINE_8_2)},
{STRING_TOKEN(STR_HWH_LOG_LINE_9_0), STRING_TOKEN(STR_HWH_LOG_LINE_9_1), STRING_TOKEN(STR_HWH_LOG_LINE_9_2)},
{STRING_TOKEN(STR_HWH_LOG_LINE_10_0), STRING_TOKEN(STR_HWH_LOG_LINE_10_1), STRING_TOKEN(STR_HWH_LOG_LINE_10_2)},
{STRING_TOKEN(STR_HWH_LOG_LINE_11_0), STRING_TOKEN(STR_HWH_LOG_LINE_11_1), STRING_TOKEN(STR_HWH_LOG_LINE_11_2)},
{STRING_TOKEN(STR_HWH_LOG_LINE_12_0), STRING_TOKEN(STR_HWH_LOG_LINE_12_1), STRING_TOKEN(STR_HWH_LOG_LINE_12_2)},
{STRING_TOKEN(STR_HWH_LOG_LINE_13_0), STRING_TOKEN(STR_HWH_LOG_LINE_13_1), STRING_TOKEN(STR_HWH_LOG_LINE_13_2)},
{STRING_TOKEN(STR_HWH_LOG_LINE_14_0), STRING_TOKEN(STR_HWH_LOG_LINE_14_1), STRING_TOKEN(STR_HWH_LOG_LINE_14_2)}
};
//*---------------------------------------------------------------------------------------*
//* HII specific Vendor Device Path definition. *
//*---------------------------------------------------------------------------------------*
struct
{
VENDOR_DEVICE_PATH VendorDevicePath;
EFI_DEVICE_PATH_PROTOCOL End;
} mHiiVendorDevicePath = {
{
{
HARDWARE_DEVICE_PATH,
HW_VENDOR_DP,
{
(UINT8)(sizeof(VENDOR_DEVICE_PATH)),
(UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8)
}
},
EFI_CALLER_ID_GUID
},
{
END_DEVICE_PATH_TYPE,
END_ENTIRE_DEVICE_PATH_SUBTYPE,
{
(UINT8)(END_DEVICE_PATH_LENGTH),
(UINT8)((END_DEVICE_PATH_LENGTH) >> 8)
}
}
};
//*---------------------------------------------------------------------------------------*
//* Doubly Linked List Methods *
//*---------------------------------------------------------------------------------------*
/**
* Deletes the list structure containing WHEA Errors
*
* @retval VOID
**/
VOID
DeleteList(VOID)
{
while (!IsListEmpty(&mListHead)) {
currentPage = (ErrorRecord *)GetFirstNode(&mListHead); //get ErrorRecord being deleted
RemoveEntryList((LIST_ENTRY *)currentPage); //remove ErrorRecord from list
FreePool(currentPage->error); //free HwErrRecXXXX in record
FreePool(currentPage); //free ErrorRecord
}
currentPage = NULL;
}
/**
* Changes the current page to be the current error record to be the next in the list structure
*
* @retval BOOLEAN TRUE if currentPage was changed to next
* FALSE otherwise
**/
BOOLEAN
PageForward(VOID)
{
LIST_ENTRY *tmp;
tmp = GetNextNode(&mListHead, (LIST_ENTRY *)currentPage);
if (tmp != &mListHead) {
currentPage = (ErrorRecord *)tmp;
return TRUE;
}
return FALSE;
}
/**
* Changes the current page to be the current error record to be the previous in the list structure
*
* @retval BOOLEAN TRUE if currentPage was changed to previous
* FALSE otherwise
**/
BOOLEAN
PageBackward(VOID)
{
LIST_ENTRY *tmp;
tmp = GetPreviousNode(&mListHead, (LIST_ENTRY *)currentPage);
if (tmp != &mListHead) {
currentPage = (ErrorRecord *)tmp;
return TRUE;
}
return FALSE;
}
//*---------------------------------------------------------------------------------------*
//* Hii Config Access functions *
//*---------------------------------------------------------------------------------------*
EFI_STATUS
EFIAPI
ExtractConfig(
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
IN CONST EFI_STRING Request,
OUT EFI_STRING *Progress,
OUT EFI_STRING *Results
);
EFI_STATUS
EFIAPI
RouteConfig(
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
IN CONST EFI_STRING Configuration,
OUT EFI_STRING *Progress
);
EFI_STATUS
EFIAPI
DriverCallback(
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
IN EFI_BROWSER_ACTION Action,
IN EFI_QUESTION_ID QuestionId,
IN UINT8 Type,
IN EFI_IFR_TYPE_VALUE *Value,
OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
);
//*---------------------------------------------------------------------------------------*
//* Private internal data *
//*---------------------------------------------------------------------------------------*
struct
{
UINTN Signature;
EFI_HANDLE DriverHandle;
EFI_HII_HANDLE HiiHandle;
EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
} mHwhMenuPrivate = {
HWH_MENU_SIGNATURE,
NULL,
NULL,
{
ExtractConfig,
RouteConfig,
DriverCallback
}
};
//*---------------------------------------------------------------------------------------*
//* Main Functions *
//*---------------------------------------------------------------------------------------*
/**
* Writes a maximum of MAX_DISPLAY_STRING_LENGTH characters to the
* specified EFI_STRING_ID for the VFR
*
* @param[in] Str EFI_STRING being written to
* @param[in] Format Format string
* @param[in] ... Variables placed into format string
*
* @retval 0 No characters were written to Str. Note
* that it could be a blank string was written
* UINTN Number of characters written
**/
UINTN
UnicodeDataToVFR(
IN CONST EFI_STRING_ID Str,
IN CONST CHAR16 *Format,
...
)
{
CHAR16 Buffer[MAX_DISPLAY_STRING_LENGTH + 1];
VA_LIST Marker;
UINTN NumWritten;
VA_START(Marker, Format);
NumWritten = UnicodeVSPrint(Buffer, MAX_DISPLAY_STRING_LENGTH * sizeof(CHAR16), Format, Marker);
VA_END(Marker);
if (HiiSetString(mHwhMenuPrivate.HiiHandle, Str, Buffer, NULL) == 0) {
return 0;
}
return NumWritten;
}
/**
* UpdateForm
*
* Forces the form to update by inserting nothing into the label section of VFR file
*
* @retval VOID
*/
VOID
UpdateForm(VOID)
{
EFI_STATUS Status;
VOID *StartOpCodeHandle;
VOID *EndOpCodeHandle = NULL;
EFI_IFR_GUID_LABEL *StartLabel;
EFI_IFR_GUID_LABEL *EndLabel;
BOOLEAN Aborted = TRUE;
do {
// Init OpCode Handle and Allocate space for creation of UpdateData Buffer
StartOpCodeHandle = HiiAllocateOpCodeHandle();
ASSERT(StartOpCodeHandle != NULL);
if (NULL == StartOpCodeHandle) {
break;
}
EndOpCodeHandle = HiiAllocateOpCodeHandle();
ASSERT(EndOpCodeHandle != NULL);
if (NULL == EndOpCodeHandle) {
break;
}
// Create Hii Extend Label OpCode as the start opcode
StartLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode(StartOpCodeHandle,
&gEfiIfrTianoGuid,
NULL,
sizeof(EFI_IFR_GUID_LABEL));
if (NULL == StartLabel) {
break;
}
StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
// Create Hii Extend Label OpCode as the end opcode
EndLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode(EndOpCodeHandle,
&gEfiIfrTianoGuid,
NULL,
sizeof(EFI_IFR_GUID_LABEL));
if (NULL == EndLabel) {
break;
}
EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
StartLabel->Number = LABEL_UPDATE_LOCATION;
EndLabel->Number = LABEL_UPDATE_END;
Status = HiiUpdateForm(mHwhMenuPrivate.HiiHandle,
&gHwhMenuFormsetGuid,
HWH_MENU_FORM_ID,
StartOpCodeHandle,
EndOpCodeHandle);
if (EFI_ERROR(Status)) {
DEBUG((DEBUG_ERROR, "%a Error in HiiUpdateform. Code=%r\n", __FUNCTION__, Status));
}
else {
Aborted = FALSE;
}
} while (FALSE);
if (Aborted) {
DEBUG((DEBUG_ERROR, "%a Form Update aborted.\n", __FUNCTION__ ));
}
if (StartOpCodeHandle != NULL) {
HiiFreeOpCodeHandle(StartOpCodeHandle);
}
if (StartOpCodeHandle != NULL) {
HiiFreeOpCodeHandle(EndOpCodeHandle);
}
}
/**
* Dump the Section data in byte and ascii form
*
* @param[in] Strings Pointer to unallocated array of strings which will be populated by the parser
* @param[in] Err Pointer to the HwErrRec bing parsed
* @param[in] SectionHeader Pointer to Section Header of data being parsed
*
* @retval UINTN Number of CHAR16* allocated in Strings to be written to the form
**/
UINTN
SectionDump(
IN OUT CHAR16 ***Strings,
CONST IN EFI_COMMON_ERROR_RECORD_HEADER *Err,
CONST IN EFI_ERROR_SECTION_DESCRIPTOR *SecHead)
{
CONST UINT8 *Ptr2Data;
UINT32 BytesCurrentLine = 0;
UINT32 NumLines, OuterLoop, InnerLoop;
CHAR16 *Ptr2Buffer;
CHAR8 Ascii[17];
Ascii[16] = '\0';
// Quick Null-check
if (Err == NULL || SecHead == NULL || Strings == NULL) {
return 0;
}
// Get how many lines of bytes we are printing at 16 bytes per line
NumLines = SecHead->SectionLength % 16 == 0 ? SecHead->SectionLength / 16 : (SecHead->SectionLength / 16) + 1;
// Allocate a pool to contain all CHAR 16*
*Strings = AllocatePool(sizeof(CHAR16 *) * NumLines);
// Get a pointer to the beginning of the data
Ptr2Data = (CONST UINT8 *)Err + SecHead->SectionOffset;
// For each line...
for (OuterLoop = 0; OuterLoop < NumLines; OuterLoop++) {
// Allocate the line
(*Strings)[OuterLoop] = AllocatePool(sizeof(CHAR16) * MAX_DISPLAY_STRING_LENGTH);
// Get a pointer to the beginning of that line
Ptr2Buffer = (*Strings)[OuterLoop];
// See how many bytes need to be printed on this line
BytesCurrentLine = SecHead->SectionLength - (OuterLoop * 16) < 16 ? SecHead->SectionLength - (OuterLoop * 16) : 16;
// For each byte in the line...
for (InnerLoop = 0; InnerLoop < BytesCurrentLine; InnerLoop++) {
// Check if there is an ascii interpretation of the byte. If so, add it or just add a '.'
Ascii[InnerLoop] = ((*Ptr2Data >= 0x20) && (*Ptr2Data <= 0x7e)) ? *Ptr2Data : '.';
// Write the byte interpretation and more our buffer pointer forward
Ptr2Buffer += UnicodeSPrint(Ptr2Buffer, 4 * sizeof(CHAR16), L"%02X ", *Ptr2Data);
// Increment our data pointer to the next byte
Ptr2Data++;
}
// Finally, print the ascii interpretation of this line
UnicodeSPrint(Ptr2Buffer, 20 * sizeof(CHAR16), L"\n\n%a", Ascii);
}
// Let the caller know how many lines we wrote
return NumLines;
}
/**
* Parses the date and time and writes values to uni strings
*
* @retval VOID
**/
VOID
ParseDateTime(VOID)
{
UnicodeDataToVFR((EFI_STRING_ID)STR_HWH_LOG_DATE_VALUE,
L"%02X/%02X/%02X",
currentPage->error->TimeStamp.Month,
currentPage->error->TimeStamp.Day,
currentPage->error->TimeStamp.Year);
UnicodeDataToVFR((EFI_STRING_ID)STR_HWH_LOG_TIME_VALUE,
L"%02X:%02X:%02X",
currentPage->error->TimeStamp.Hours,
currentPage->error->TimeStamp.Minutes,
currentPage->error->TimeStamp.Seconds);
}
/**
* Parses the number of sections and writes value to uni string
*
* @retval VOID
**/
VOID
ParseNumberOfSections(VOID)
{
UnicodeDataToVFR((EFI_STRING_ID)STR_HWH_LOG_NUMSECTIONS_VALUE,
L"%d",
currentPage->error->SectionCount);
}
/**
* Parses the severity which (for now) simply displays the number value
*
* @retval VOID
**/
VOID
ParseSeverity(VOID)
{
UnicodeDataToVFR((EFI_STRING_ID)STR_HWH_LOG_SEVERITY_VALUE,
L"%d",
currentPage->error->ErrorSeverity);
}
/**
* Parses the current error out of total number of errors
* and writes value to uni strings
*
* @retval VOID
**/
VOID
ParsePageNumber(VOID)
{
UnicodeDataToVFR((EFI_STRING_ID)STR_HWH_PAGE_NUM,
L" Error %d of %d",
currentPage->val,
NumErrorEntries);
}
/**
* Finds the number of CHAR16s between source and either '\n' or '\0'
*
* @param[in] Str Pointer to string being parsed
*
* @retval UINTN Number of CHAR16s from source address where '\n' or '\0' is encountered
**/
UINTN
FindNewline(
IN CHAR16 **Source
)
{
// Null-check
if (Source == NULL || *Source == NULL) {
return 0;
}
UINTN Counter = 0;
CHAR16 *End = *Source;
// Walk the string until one of the following is true
while (*End != '\n' && *End != '\0' && Counter < MAX_DISPLAY_STRING_LENGTH + 1) {
End++;
Counter++;
}
// Return how far we walked
return Counter;
}
/**
* Parses the current page number out of overall number of pages
*
* @param[in] Err Pointer to HwErrRec being parsed
* @param[in] SectionHeader Pointer to Section Header of data being parsed
* @param[in] index Pointer to to the current line of the section data portion of
* front page being written to
*
* @retval VOID
**/
VOID
ParseSectionData(
IN CONST EFI_COMMON_ERROR_RECORD_HEADER *Err,
IN CONST EFI_ERROR_SECTION_DESCRIPTOR *SectionHeader,
IN OUT UINT8 *index
)
{
if (Err == NULL || SectionHeader == NULL || index == NULL) {
return;
}
CHAR16 **SectionDataStrings = NULL; // Array of strings which are written in the section data area of page
SECTIONFUNCTIONPTR SectionParser = NULL; // Pointer to function which can parse the section data
CHAR16 *StringParsePtr = NULL; // Pointer to current place in string being written
UINTN NumberOfStrings = 0; // Number of strings within SectionDataStrings
UINTN StringParseChars = 0; // Number of chars from CHAR16* to '\n' or '\0'
UINTN OuterLoop, InnerLoop;
// Get parser for the section data if available
SectionParser = ParserLibFindSectionParser(&(SectionHeader->SectionType));
if (SectionParser == NULL) {
SectionParser = (SECTIONFUNCTIONPTR)&SectionDump;
}
// Call the parser and get how many strings were returned
NumberOfStrings = SectionParser(&SectionDataStrings, Err, SectionHeader);
for (OuterLoop = 0; OuterLoop < NumberOfStrings; OuterLoop++) {
// Set the parse pointer to the start of the string
StringParsePtr = SectionDataStrings[OuterLoop];
// If this string was not allocated for some reason, just move on to the next one
if (StringParsePtr == NULL) {
continue;
}
// If we've run out of writtable lines, free this one and continue
// so the rest are freed as well
if ((*index) >= NUM_SEC_DATA_ROWS) {
FreePool(StringParsePtr);
continue;
}
// For each column in the row being written to
for (InnerLoop = 0; InnerLoop < NUM_SEC_DATA_COLUMNS; InnerLoop++) {
// Make sure we still have more chars to parse from the string. If not, just clear the uni string
if (StringParsePtr >= SectionDataStrings[OuterLoop] + StrnLenS(SectionDataStrings[OuterLoop], MAX_DISPLAY_STRING_LENGTH)) {
HiiSetString(mHwhMenuPrivate.HiiHandle, DisplayLines[*index][InnerLoop], L"\0", NULL);
}
else {
// Find distance from StringParsePtr to a '\0' or '\n'
StringParseChars = FindNewline(&StringParsePtr);
// Create null-terminated string from StringParsePtr to StringParsePtr + StringParseChars
if (!EFI_ERROR(StrnCpyS(UnicodeString, MAX_DISPLAY_STRING_LENGTH + 1, StringParsePtr, StringParseChars - 1))) {
// Write the string to .uni string in the InnerLoop-th column
HiiSetString(mHwhMenuPrivate.HiiHandle, DisplayLines[*index][InnerLoop], UnicodeString, NULL);
}
else {
// Just clear the string if for some reason it could not be copied
HiiSetString(mHwhMenuPrivate.HiiHandle, DisplayLines[*index][InnerLoop], L"\0", NULL);
}
// Put the ptr 1 CHAR16 ahead of whatever character stopped FindNewline()
StringParsePtr += StringParseChars + 1;
}
}
// Free the string and increment to the next line of the page
(*index)++;
FreePool(SectionDataStrings[OuterLoop]);
}
// Free the array if it was created
if (SectionDataStrings != NULL) {
FreePool(SectionDataStrings);
SectionDataStrings = NULL;
}
// Publish blank line
for (OuterLoop = 0; OuterLoop < NUM_SEC_DATA_COLUMNS; OuterLoop++) {
HiiSetString(mHwhMenuPrivate.HiiHandle, DisplayLines[*index][OuterLoop], L"\0", NULL);
}
(*index)++;
}
/**
* Updates all strings on the VFR with the new error record being displayed
*
* @retval VOID
**/
VOID
UpdateDisplayStrings(VOID)
{
UINT8 OuterLoop;
// Make sure there is data to populate the page
if (currentPage == NULL) {
return;
}
CONST EFI_COMMON_ERROR_RECORD_HEADER *Err = currentPage->error; // Pointer to Error being displayed
UINT8 SecLineIndex = 0; // Index of section line being written to
// DebugDumpMemory(DEBUG_INFO, Err, currentPage->error->RecordLength, DEBUG_DM_PRINT_ASCII);
ParseDateTime(); // Publish date and time fields
ParseNumberOfSections(); // Publish section num field
ParsePageNumber(); // Publish page number
ParseSeverity(); // Publish severity field
ParseSourceID(&(Err->PlatformID)); // Publish Source ID field
ParseCreatorID(&(Err->CreatorID)); // Publish Creator ID field
//display at most 2 Sections.
for (OuterLoop = 0; OuterLoop < 2; OuterLoop++) {
//if We have another section to display
if (OuterLoop < Err->SectionCount) {
UnicodeDataToVFR(DisplayLines[SecLineIndex++][0],
L"Section %d",
OuterLoop + 1);
ParseSectionData(Err, (((EFI_ERROR_SECTION_DESCRIPTOR *)(Err + 1)) + OuterLoop), &SecLineIndex);
}
}
// Set the rest of the lines to blank
while (SecLineIndex < NUM_SEC_DATA_ROWS) {
for (OuterLoop = 0; OuterLoop < NUM_SEC_DATA_COLUMNS; OuterLoop++) {
HiiSetString(mHwhMenuPrivate.HiiHandle, DisplayLines[SecLineIndex][OuterLoop], L"\0", NULL);
}
SecLineIndex++;
}
}
/**
* Finds the XXXX in the HwRecRecXXXX -> the next index at which a Whea record will be inserted.
*
* @retval UINT32 A Whea Index.
*
**/
UINT32
GetMaxWheaIndex(VOID)
{
EFI_STATUS Status; // Return status
UINTN Size = 0; // Used to store size of HwErrRec found
UINT32 OuterLoop = 0; // Store the current index we're checking
CHAR16 VarName[EFI_HW_ERR_REC_VAR_NAME_LEN]; // HwRecRecXXXX used to find variable
for (OuterLoop = 0; OuterLoop <= MAX_UINT32; OuterLoop++) {
UnicodeSPrint(VarName, sizeof(VarName), L"%s%04X", EFI_HW_ERR_REC_VAR_NAME, (UINT16)(OuterLoop & MAX_UINT16));
Status = gRT->GetVariable(VarName, &gEfiHardwareErrorVariableGuid, NULL, &Size, NULL);
// We've found the next index. Excellent.
if (Status == EFI_NOT_FOUND) {
break;
}
}
return OuterLoop;
}
/**
* Populates list structure with Whea Errors.
*
* @retval VOID
*
**/
EFI_STATUS
PopulateWheaErrorList(VOID)
{
EFI_STATUS Status; // Return status
UINTN Size = 0; // Size of variable being stored
CHAR16 VarName[EFI_HW_ERR_REC_VAR_NAME_LEN]; // HwRecRecXXXX name of var being stored
EFI_COMMON_ERROR_RECORD_HEADER *ErrorRecordPointer = NULL; // Pointer to the start of the record
ErrorRecord *new; // New record being added
UINT32 OuterLoop;
NumErrorEntries = GetMaxWheaIndex();
for (OuterLoop = NumErrorEntries; OuterLoop > 0; --OuterLoop) {
// Create HwRecRecXXXX string
UnicodeSPrint(VarName, sizeof(VarName), L"%s%04X", EFI_HW_ERR_REC_VAR_NAME, OuterLoop - 1);
// Determine size required to allocate
Status = gRT->GetVariable(VarName, &gEfiHardwareErrorVariableGuid, NULL, &Size, NULL);
if (Status != EFI_NOT_FOUND) {
ErrorRecordPointer = AllocatePool(Size);
// Populate the error record
Status = gRT->GetVariable(VarName, &gEfiHardwareErrorVariableGuid, NULL, &Size, ErrorRecordPointer);
if (ValidateCperHeader(ErrorRecordPointer, Size)) {
new = AllocateZeroPool(sizeof(ErrorRecord));
new->error = ErrorRecordPointer;
new->val = OuterLoop;
InsertHeadList(&mListHead, (LIST_ENTRY *)new);
}
}
}
if (!IsListEmpty(&mListHead)) {
currentPage = (ErrorRecord *)GetFirstNode(&mListHead);
return EFI_SUCCESS;
}
else {
return EFI_ABORTED;
}
}
/**
* This function processes the results of changes in configuration.
*
* @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
* @param[in] Action Specifies the type of action taken by the browser.
* @param[in] QuestionId A unique value which is sent to the original
* exporting driver so that it can identify the type
* of data to expect.
* @param[in] Type The type of value for the question.
* @param[in] Value A pointer to the data being sent to the original
* exporting driver.
* @param[out] ActionRequest On return, points to the action requested by the
* callback function.
*
* @retval EFI_SUCCESS The callback successfully handled the action.
* @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
* variable and its data.
* @retval EFI_DEVICE_ERROR The variable could not be saved.
* @retval EFI_UNSUPPORTED The specified Action is not supported by the
* callback.
**/
EFI_STATUS
EFIAPI
DriverCallback(
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
IN EFI_BROWSER_ACTION Action,
IN EFI_QUESTION_ID QuestionId,
IN UINT8 Type,
IN EFI_IFR_TYPE_VALUE *Value,
OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
)
{
EFI_STATUS Status = EFI_SUCCESS;
*ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
DEBUG((DEBUG_INFO, "*Hii - Hwh* - Question ID=0x%08x Type=0x%04x Action=0x%04x Value=0x%lx\n", QuestionId, Type, Action, Value->u64));
switch (Action) {
case EFI_BROWSER_ACTION_FORM_OPEN:
// Capture form opening
if (QuestionId == HWH_MENU_LEFT_ID) {
// Make sure there are errors to display. If not, set the configuration
// to suppress most of the page and set the "No Logs To Display" string at top
if (currentPage == NULL && mHwhMenuConfiguration.Logs != LOGS_FALSE) {
if (EFI_ERROR(PopulateWheaErrorList())) {
mHwhMenuConfiguration.Logs = LOGS_FALSE;
UpdateForm();
*ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
}
}
UpdateDisplayStrings();
}
break;
case EFI_BROWSER_ACTION_FORM_CLOSE:
// Capture form closing
if (QuestionId == HWH_MENU_LEFT_ID) {
currentPage = (ErrorRecord *)GetFirstNode(&mListHead);
}
break;
case EFI_BROWSER_ACTION_CHANGED:
//Rely on short-circuiting of && statement to avoid paging when unnecessary
if ((QuestionId == HWH_MENU_RIGHT_ID && PageForward()) || (QuestionId == HWH_MENU_LEFT_ID && PageBackward())) {
UpdateDisplayStrings();
UpdateForm();
*ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
}
break;
default:
break;
}
return Status;
}
/**
* This function processes the results of changes in configuration.
*
* @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
* @param[in] Configuration A null-terminated Unicode string in <ConfigResp>
* format.
* @param[out] Progress A pointer to a string filled in with the offset of
* the most recent '&' before the first failing
* name/value pair (or the beginning of the string if
* the failure is in the first name/value pair) or
* the terminating NULL if all was successful.
*
* @retval EFI_SUCCESS The Results is processed successfully.
* @retval EFI_INVALID_PARAMETER Configuration is NULL.
* @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
* driver.
*
**/
EFI_STATUS
EFIAPI
RouteConfig(
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
IN CONST EFI_STRING Configuration,
OUT EFI_STRING *Progress)
{
EFI_STATUS Status;
if (Configuration == NULL || Progress == NULL) {
return EFI_INVALID_PARAMETER;
}
if (Configuration == NULL) {
return EFI_UNSUPPORTED;
}
if (StrStr(Configuration, L"OFFSET") == NULL) {
return EFI_UNSUPPORTED;
}
Status = EFI_SUCCESS;
DEBUG((DEBUG_INFO, "%a: complete. Code = %r\n", __FUNCTION__, Status));
return Status;
}
/**
* This function allows a caller to extract the current configuration for one
* or more named elements from the target driver.
*
* @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
* @param[in] Request A null-terminated Unicode string in
* <ConfigRequest> format.
* @param[out] Progress On return, points to a character in the Request
* string. Points to the string's null terminator if
* request was successful. Points to the most recent
* '&' before the first failing name/value pair (or
* the beginning of the string if the failure is in
* the first name/value pair) if the request was not
* successful.
* @param[out] Results A null-terminated Unicode string in
* <ConfigAltResp> format which has all values filled
* in for the names in the Request string. String to
* be allocated by the called function.
*
* @retval EFI_SUCCESS The Results is filled with the requested values.
* @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
* @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
* @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
* driver.
*
**/
EFI_STATUS
EFIAPI
ExtractConfig(
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
IN CONST EFI_STRING Request,
OUT EFI_STRING *Progress,
OUT EFI_STRING *Results)
{
EFI_STATUS Status;
if (Progress == NULL || Results == NULL) {
return EFI_INVALID_PARAMETER;
}
if (Request == NULL) {
return EFI_UNSUPPORTED;
}
if (StrStr(Request, L"OFFSET") == NULL) {
return EFI_UNSUPPORTED;
}
// The Request string may be truncated as it is long. Ensure \n gets out
DEBUG((DEBUG_INFO, "%a: Request=%s\n", __FUNCTION__));
DEBUG((DEBUG_INFO, "%s", Request));
DEBUG((DEBUG_INFO, "\n"));
if (HiiIsConfigHdrMatch(Request, &gHwhMenuFormsetGuid, L"HwhMenuConfig")) {
Status = gHiiConfigRouting->BlockToConfig(gHiiConfigRouting,
Request,
(UINT8 *)&mHwhMenuConfiguration,
sizeof(mHwhMenuConfiguration),
Results,
Progress);
DEBUG((DEBUG_INFO, "%a: Size is %d, Code=%r\n", __FUNCTION__, sizeof(mHwhMenuConfiguration), Status));
}
Status = EFI_SUCCESS;
DEBUG((DEBUG_INFO, "%a: complete. Code = %r\n", __FUNCTION__, Status));
return Status;
}
/**
* This function is the main entry of the Hardware Health Menu application.
*
* @param[in] ImageHandle
* @param[in] SystemTable
*
**/
EFI_STATUS
EFIAPI
HwhMenuEntry(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable)
{
EFI_STATUS Status;
Status = gBS->InstallMultipleProtocolInterfaces(&mHwhMenuPrivate.DriverHandle,
&gEfiDevicePathProtocolGuid,
&mHiiVendorDevicePath,
&gEfiHiiConfigAccessProtocolGuid,
&mHwhMenuPrivate.ConfigAccess,
NULL);
mHwhMenuPrivate.HiiHandle = HiiAddPackages(&gHwhMenuFormsetGuid,
mHwhMenuPrivate.DriverHandle,
HwhMenuVfrBin,
HwhMenuStrings,
NULL);
return Status;
}

Просмотреть файл

@ -0,0 +1,35 @@
/** @file
HwhMenu.h
Header file for HwhMenu
Copyright (c) Microsoft Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef __HWH_MENU__
#define __HWH_MENU__
#define MAX_DISPLAY_STRING_LENGTH 100
extern UINT8 HwhMenuVfrBin[];
extern unsigned char HwhMenuStrings[];
/**
* Writes the input string to the input vfr string
*
* @param[in] Str EFI_STRING being written to
* @param[in] Format Format string
* @param[in] ... Variables placed into format string
*
* @retval VOID
**/
UINTN
UnicodeDataToVFR(
IN CONST EFI_STRING_ID Str,
IN CONST CHAR16 *Format,
...
);
#endif

Просмотреть файл

@ -0,0 +1,61 @@
## @file
# HwhMenu.inf
#
# Presents HwErrRecs to the user on Frontpage
#
# Copyright (c) Microsoft Corporation. All rights reserved.
# SPDX-License-Identifier: BSD-2-Clause-Patent
##
[Defines]
INF_VERSION = 0x00010006
BASE_NAME = HwhMenu
FILE_GUID = af8f0389-6ba2-47d3-9e55-80b3dd9b8a98
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = HwhMenuEntry
[Sources]
HwhMenu.h
HwhMenu.c
HwhMenuVfr.h
HwhMenuStrings.uni
HwhMenuVfr.Vfr
CreatorIDParser.h
CreatorIDParser.c
PlatformIDParser.h
PlatformIDParser.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
MsWheaPkg/MsWheaPkg.dec
[LibraryClasses]
BaseMemoryLib
DebugLib
DevicePathLib
PrintLib
HiiLib
UefiDriverEntryPoint
UefiBootServicesTableLib
UefiRuntimeServicesTableLib
UefiHiiServicesLib
CheckHwErrRecHeaderLib
MuTelemetryHelperLib
ParserRegistryLib
[Guids]
gHwhMenuFormsetGuid ## PRODUCES
gEfiHardwareErrorVariableGuid ## CONSUMES
gEfiIfrTianoGuid ## CONSUMES
[Protocols]
gEfiHiiConfigAccessProtocolGuid
[Depex]
gEfiHiiConfigRoutingProtocolGuid
[BuildOptions]
MSFT:*_*_*_CC_FLAGS = /FAcs /Oi-

Просмотреть файл

@ -0,0 +1,90 @@
/** @file
HwhMenuStrings.uni
This file maintains the text strings used by the Hardware Health Menu.
Copyright (c) Microsoft Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#langdef en-US " English "
#langdef en " Standard English "
// Common Form strings
#string STR_NULL_STRING #language en-US ""
#string STR_HWH_MENU_TITLE #language en-US "Hardware Health"
/////////////////////////////////////////////////////////////////////////////
// Dialog: Hardware Health
//
#string STR_HWH_PAGE_RIGHT #language en-US "Next"
#string STR_HWH_PAGE_LEFT #language en-US "Previous"
#string STR_HWH_PAGE_NUM #language en-US "Page 1 of 1"
#string STR_FP_HW_HEADER_LOGS_TRUE #language en-US "\fh!48!Error Logs"
#string STR_FP_HW_HEADER_LOGS_FALSE #language en-US "\fh!48!No Logs To Display"
#string STR_HWH_VIEW_LOGS #language en-US "View Logs"
#string STR_HWH_LOG_DATE #language en-US "Date (MM/DD/YY):"
#string STR_HWH_LOG_TIME #language en-US "Time:"
#string STR_HWH_LOG_SEVERITY #language en-US "Severity:"
#string STR_HWH_LOG_NUMSECTIONS #language en-US "Number of Sections:"
#string STR_HWH_LOG_CREATORID #language en-US "Creator ID:"
#string STR_HWH_LOG_SOURCEID #language en-US "Source ID:"
/////////////////////////////////////////////////////////////////////////////
// Error Report Strings
//
#string STR_HWH_LOG_SEVERITY_VALUE #language en-US "SEVERITY"
#string STR_HWH_LOG_TIME_VALUE #language en-US "TIME"
#string STR_HWH_LOG_DATE_VALUE #language en-US "DATE"
#string STR_HWH_LOG_NUMSECTIONS_VALUE #language en-US "NUMBER OF SECTIONS"
#string STR_HWH_LOG_CREATORID_VALUE #language en-US "CREATOR ID"
#string STR_HWH_LOG_SOURCEID_VALUE #language en-US "SOURCE ID"
#string STR_HWH_LOG_LINE_0_0 #language en-US ""
#string STR_HWH_LOG_LINE_0_1 #language en-US ""
#string STR_HWH_LOG_LINE_0_2 #language en-US ""
#string STR_HWH_LOG_LINE_1_0 #language en-US ""
#string STR_HWH_LOG_LINE_1_1 #language en-US ""
#string STR_HWH_LOG_LINE_1_2 #language en-US ""
#string STR_HWH_LOG_LINE_2_0 #language en-US ""
#string STR_HWH_LOG_LINE_2_1 #language en-US ""
#string STR_HWH_LOG_LINE_2_2 #language en-US ""
#string STR_HWH_LOG_LINE_3_0 #language en-US ""
#string STR_HWH_LOG_LINE_3_1 #language en-US ""
#string STR_HWH_LOG_LINE_3_2 #language en-US ""
#string STR_HWH_LOG_LINE_4_0 #language en-US ""
#string STR_HWH_LOG_LINE_4_1 #language en-US ""
#string STR_HWH_LOG_LINE_4_2 #language en-US ""
#string STR_HWH_LOG_LINE_5_0 #language en-US ""
#string STR_HWH_LOG_LINE_5_1 #language en-US ""
#string STR_HWH_LOG_LINE_5_2 #language en-US ""
#string STR_HWH_LOG_LINE_6_0 #language en-US ""
#string STR_HWH_LOG_LINE_6_1 #language en-US ""
#string STR_HWH_LOG_LINE_6_2 #language en-US ""
#string STR_HWH_LOG_LINE_7_0 #language en-US ""
#string STR_HWH_LOG_LINE_7_1 #language en-US ""
#string STR_HWH_LOG_LINE_7_2 #language en-US ""
#string STR_HWH_LOG_LINE_8_0 #language en-US ""
#string STR_HWH_LOG_LINE_8_1 #language en-US ""
#string STR_HWH_LOG_LINE_8_2 #language en-US ""
#string STR_HWH_LOG_LINE_9_0 #language en-US ""
#string STR_HWH_LOG_LINE_9_1 #language en-US ""
#string STR_HWH_LOG_LINE_9_2 #language en-US ""
#string STR_HWH_LOG_LINE_10_0 #language en-US ""
#string STR_HWH_LOG_LINE_10_1 #language en-US ""
#string STR_HWH_LOG_LINE_10_2 #language en-US ""
#string STR_HWH_LOG_LINE_11_0 #language en-US ""
#string STR_HWH_LOG_LINE_11_1 #language en-US ""
#string STR_HWH_LOG_LINE_11_2 #language en-US ""
#string STR_HWH_LOG_LINE_12_0 #language en-US ""
#string STR_HWH_LOG_LINE_12_1 #language en-US ""
#string STR_HWH_LOG_LINE_12_2 #language en-US ""
#string STR_HWH_LOG_LINE_13_0 #language en-US ""
#string STR_HWH_LOG_LINE_13_1 #language en-US ""
#string STR_HWH_LOG_LINE_13_2 #language en-US ""
#string STR_HWH_LOG_LINE_14_0 #language en-US ""
#string STR_HWH_LOG_LINE_14_1 #language en-US ""
#string STR_HWH_LOG_LINE_14_2 #language en-US ""

Просмотреть файл

@ -0,0 +1,542 @@
/** @file
HwhMenuVfr.Vfr
The Vfr to support the HwhMenu display.
Copyright (c) Microsoft Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "HwhMenuVfr.h"
formset
guid = HWH_MENU_FORMSET_GUID,
title = STRING_TOKEN(STR_HWH_MENU_TITLE),
help = STRING_TOKEN(STR_NULL_STRING),
classguid = HWH_MENU_FORMSET_GUID,
class = EFI_OTHER_DEVICE_CLASS,
subclass = EFI_GENERAL_APPLICATION_SUBCLASS,
varstore HWH_MENU_CONFIG,
varid = HWH_MENU_VARID,
name = HwhMenuConfig,
guid = HWH_MENU_FORMSET_GUID;
/////////////////////////////////////////////////////////////////////////////
// Form ID 6: HW
//
form formid = HWH_MENU_FORM_ID,
title = STRING_TOKEN(STR_NULL_STRING);
suppressif ideqval HwhMenuConfig.Logs == LOGS_FALSE;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_FP_HW_HEADER_LOGS_TRUE);
endif;
suppressif ideqval HwhMenuConfig.Logs == LOGS_TRUE;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_FP_HW_HEADER_LOGS_FALSE);
endif;
suppressif ideqval HwhMenuConfig.Logs == LOGS_FALSE;
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 70, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_DATE);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_DATE_VALUE);
text
help = STRING_TOKEN(STR_NULL_STRING), //Blank Column For Spacing
text = STRING_TOKEN(STR_NULL_STRING);
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 70, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_TIME);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_TIME_VALUE);
text
help = STRING_TOKEN(STR_NULL_STRING), //Blank Column For Spacing
text = STRING_TOKEN(STR_NULL_STRING);
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 70, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_SEVERITY);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_SEVERITY_VALUE);
text
help = STRING_TOKEN(STR_NULL_STRING), //Blank Column For Spacing
text = STRING_TOKEN(STR_NULL_STRING);
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 70, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_NUMSECTIONS);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_NUMSECTIONS_VALUE);
text
help = STRING_TOKEN(STR_NULL_STRING), //Blank Column For Spacing
text = STRING_TOKEN(STR_NULL_STRING);
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 70, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_CREATORID);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_CREATORID_VALUE);
text
help = STRING_TOKEN(STR_NULL_STRING), //Blank Column For Spacing
text = STRING_TOKEN(STR_NULL_STRING);
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 65, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_SOURCEID);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_SOURCEID_VALUE);
text
help = STRING_TOKEN(STR_NULL_STRING), //Blank Column For Spacing
text = STRING_TOKEN(STR_NULL_STRING);
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_NULL_STRING);
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 65, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_0_0);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_0_1);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_0_2);
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 65, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_1_0);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_1_1);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_1_2);
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 65, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_2_0);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_2_1);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_2_2);
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 65, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_3_0);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_3_1);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_3_2);
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 65, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_4_0);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_4_1);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_4_2);
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 65, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_5_0);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_5_1);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_5_2);
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 65, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_6_0);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_6_1);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_6_2);
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 65, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_7_0);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_7_1);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_7_2);
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 65, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_8_0);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_8_1);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_8_2);
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 65, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_9_0);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_9_1);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_9_2);
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 65, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_10_0);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_10_1);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_10_2);
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 65, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_11_0);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_11_1);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_11_2);
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 65, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_12_0);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_12_1);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_12_2);
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 65, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_13_0);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_13_1);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_13_2);
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 65, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_14_0);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_14_1);
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_LOG_LINE_14_2);
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
guidop
guid = GRID_CLASS_START_OPCODE_GUID, // Custom UI Grid opcode - START
datatype = UINT32, //
data = 100, // Grid cell height in pixels.
endguidop;
subtitle
text = STRING_TOKEN(STR_NULL_STRING),
flags = HORIZONTAL;
text
help = STRING_TOKEN(STR_NULL_STRING), //Page Left Button
text = STRING_TOKEN(STR_HWH_PAGE_LEFT),
flags = INTERACTIVE,
key = HWH_MENU_LEFT_ID;
text
help = STRING_TOKEN(STR_NULL_STRING),
text = STRING_TOKEN(STR_HWH_PAGE_NUM);
text
help = STRING_TOKEN(STR_NULL_STRING), //Page Right Button
text = STRING_TOKEN(STR_HWH_PAGE_RIGHT),
flags = INTERACTIVE,
key = HWH_MENU_RIGHT_ID;
guidop
guid = GRID_CLASS_END_OPCODE_GUID, // Custom UI Grid opcode - END
endguidop;
endif;
label LABEL_UPDATE_LOCATION;
//
// This is an unused update label location to force the form to be redrawn after UpdateForm() is called
//
label LABEL_UPDATE_END;
endform;
endformset;

Просмотреть файл

@ -0,0 +1,52 @@
/** @file
HwhMenuVfr.h
Header for the .vfr and .c hwh files
Copyright (c) Microsoft Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Guid/HwhMenuGuid.h>
#ifndef __HWH_MENU_VFR__
#define __HWH_MENU_VFR__
#define EFI_OTHER_DEVICE_CLASS 0x20
#define EFI_GENERAL_APPLICATION_SUBCLASS 0x01
// Aligned with 0x3000
#define HWH_MENU_MAIN_ID 0x3001
#define HWH_MENU_LEFT_ID 0x3002
#define HWH_MENU_RIGHT_ID 0x3003
#define LABEL_UPDATE_LOCATION 0x3100
#define LABEL_UPDATE_END 0x3101
#define HWH_MENU_VARID 0x3200
// Grid class Start delimeter (GUID opcode).
//
#define GRID_CLASS_START_OPCODE_GUID \
{ \
0xc0b6e247, 0xe140, 0x4b4d, { 0xa6, 0x4, 0xc3, 0xae, 0x1f, 0xa6, 0xcc, 0x12 } \
}
// Grid class End delimeter (GUID opcode).
//
#define GRID_CLASS_END_OPCODE_GUID \
{ \
0x30879de9, 0x7e69, 0x4f1b, { 0xb5, 0xa5, 0xda, 0x15, 0xbf, 0x6, 0x25, 0xce } \
}
#define LOGS_FALSE 0x00
#define LOGS_TRUE 0x01
#pragma pack(1)
typedef struct {
UINT8 Logs; // If equal to LOGS_TRUE, there are errors to display
} HWH_MENU_CONFIG;
#pragma pack()
#endif

Просмотреть файл

@ -0,0 +1,40 @@
/** @file
PlatformIDParser.c
A function for parsing the Platform ID which for now just prints the guid.
Created to more easily implement friendly strings in the future
Copyright (c) Microsoft Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi.h>
#include <Guid/Cper.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include "PlatformIDParser.h"
#include "HwhMenu.h"
/**
* Parses the Platform/Source ID
*
* @param[in] EFI_GUID *SourceID Guid being parsed
*
* @retval VOID
**/
VOID
ParseSourceID(
IN CONST EFI_GUID *SourceID
)
{
// For now, just print the guid. Leaving this separate file
// to make extending guid parsing in the future a bit simpler
UnicodeDataToVFR((EFI_STRING_ID)STR_HWH_LOG_SOURCEID_VALUE,
L"%g",
*SourceID);
}

Просмотреть файл

@ -0,0 +1,22 @@
/** @file
PlatformIDParser.h
A function for parsing the Platform ID which for now just prints the guid.
Created to more easily implement friendly strings in the future
Copyright (c) Microsoft Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
/**
* Parses the Platform/Source ID
*
* @param[in] EFI_GUID *SourceID Guid being parsed
*
* @retval VOID
**/
VOID
ParseSourceID(
IN CONST EFI_GUID *SourceID
);

Двоичные данные
MsWheaPkg/HwhMenu/hwh_menu_mu.gif Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 189 KiB

Просмотреть файл

@ -0,0 +1,97 @@
# HwhMenu
## About
![HWH Menu](hwh_menu_mu.gif)
A UEFI front page application which displays various fields of hardware error records to the user.
The application attempts to parse fields to provide more useful information and prints the raw
data if it cannot.
## Main File
### **HwhMenu.c**
The main application file.
### Loading Logs
The HwErrRecs are loaded when the Hardware Health tab is first opened using GetVariable().
The records are verified using CheckHwErrRecHeaderLib within MsWheaPkg before being added to a
linked list structure. The linked list is not being deleted because it will simply be reclaimed
when the OS boots or another allocation call is made which needs that memory. The config struct
used by the vfr holds a single UINT8 which if equal to LOGS_TRUE means there are errors to
display. If it is equal to LOGS_FALSE, the page will be suppressed and a string saying that
there are no logs present will be displayed at the top.
### Paging between logs and updating the form
There is a simple paging interface between records.
Whenever Next or Previous is pressed by the user, the page attempts to perform the desired action.
If it is successful, UpdateForm() is called which simply inserts nothing into the label section
of the VFR. What this does is make the form think it has been updated and tricks it into
refreshing, thus allowing all error specific strings which have been edited to be displayed to
the user.
### Parsing the logs
Each field which we display is parsed using the structs defined in Cper.h.
Parsing most fields is straightforward, but parsing section data requires a bit more work.
When preparing section data for the user, a call is made to ParserRegistryLib using the Section
Type guid within the section header of the hardware error record. The parser registry holds a
table which associates guids with function pointers, and any entity which employs its own section
guid should register a section data parser with the library. During parsing, if the section type
matches one in the register, the function pointer is called with the parameters specified in
ParserRegistryLib.h (SECTIONFUNCTIONPTR). The parser parses the data and populates an array of
strings with their desired display. HwhMenu.c holds a 2D array of EFI_STRING_IDs which are the
lines/columns where section data can be placed. The populated string array is written to these
strings until there is no more data to display or there are no more strings to put the data.
The user can place '\n' within their strings to separate a line into columns. See the
GenericSectionParserLib for a parsing example.
### Adding to the Section Parser
If you, the platform developer, recognize a section guid and know how to parse the bytes, you can provide a
function to do so by calling ParserLibRegisterSectionParser() with the guid you're able to parse and a function
pointer to parse it. This can be done within a new driver or by simply extending an existing driver. The HWH menu
will pass to your function (if the guid matches) a pointer to the section data and a pointer to an array of strings
to fill out with your completed parse.
## Secondary files
### **CreatorIDParser.c and PlatformIDParser.c**
Called from within the HwhMenu.c file to parse the Creator and Platform IDs.
### **HwhMenuVfr.h**
Holds configuration information and guid opcodes used in the VFR file
## Including the HWH Menu
To include, paste the following in the platform DSC flie:
``` { .md }
[LibraryClasses]
ParserRegistryLib |MsWheaPkg/Library/ParserRegistryLib/ParserRegistryLib.inf
CheckHwErrRecHeaderLib|MsWheaPkg/Library/CheckHwErrRecHeaderLib/CheckHwErrRecHeaderLib.inf
[Components.X64]
MsWheaPkg/HwhMenu/HwhMenu.inf
```
and the following in the platform FDF file
``` { .md }
[FV.FVDXE]
INF MsWheaPkg/HwhMenu/HwhMenu.inf
```
## Copyright
Copyright (C) Microsoft Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent

Просмотреть файл

@ -0,0 +1,24 @@
/** @file
HwhMenuGuid.h
This file defines the Hardware Health formset guid and page ID.
Copyright (c) Microsoft Corporation.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef __HWH_MENU_FORMSET_GUID_H__
#define __HWH_MENU_FORMSET_GUID_H__
//3b82383d-7add-4c6a-ad2b719b8d7b77c9
#define HWH_MENU_FORMSET_GUID \
{ \
0x3b82383d, 0x7add, 0x4c6a, {0xad, 0x2b, 0x71, 0x9b, 0x8d, 0x7b, 0x77, 0xc9} \
}
#define HWH_MENU_FORM_ID 0x3000
extern EFI_GUID gHwhMenuFormsetGuid;
#endif

Просмотреть файл

@ -0,0 +1,68 @@
/** @file
ParserRegistryLib.h
Header file for parser registry
ParserRegistryLib.c holds a table which associates a guid with a function. When
ParserLibRegisterSectionParser is called, a guid and function are put into the table.
And when ParserLibFindSectionParser is called, the input guid is used to return an
associated function (if one exists)
Copyright (c) Microsoft Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef _PARSER_REG_LIB_
#define _PARSER_REG_LIB_
typedef UINTN (*SECTIONFUNCTIONPTR)(IN OUT CHAR16***,
IN CONST EFI_COMMON_ERROR_RECORD_HEADER*,
IN CONST EFI_ERROR_SECTION_DESCRIPTOR*);
#pragma pack(1)
// Struct contained within the table in parserregistrylib.c
typedef struct SectionMapType
{
EFI_GUID Guid; // Section type
SECTIONFUNCTIONPTR Parser; // Function which parses the section data
} SectionMapType;
#pragma pack()
/**
* Inserts a guid and function pointer into the internal table. The function pointer can later be retrieved
* by calling ParserLibFindSectionParser with the guid used to register the function. Note that we do not allow one
* guid to register more than one function.
*
* @param[in] Ptr Function pointer being registered
* @param[in] Guid Guid being registered
*
* @retval EFI_SUCCESS The guid and pointer were successfully registered
* EFI_ABORTED The guid has already been registered
* EFI_OUT_OF_RESOURCES Couldn't allocate the space required to store the guid and pointer
**/
EFI_STATUS
EFIAPI
ParserLibRegisterSectionParser (
IN CONST SECTIONFUNCTIONPTR Ptr,
IN CONST GUID *Guid
);
/**
* Retrieves a function pointer from internal table using the input guid (if it exists)
*
* @param[in] Guid Guid used to find associated function pointer
*
* @retval NULL The guid was not registered with an associated function
* Anything else Function pointer returned
**/
SECTIONFUNCTIONPTR
EFIAPI
ParserLibFindSectionParser (
IN CONST GUID *Guid
);
#endif

Просмотреть файл

@ -0,0 +1,122 @@
/** @file
GenericSectionParser.c
This library implements a parser for the MS Generic WHEA section type.
It must be linked against the ParserRegistryLib.
Copyright (c) Microsoft Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi.h>
#include <Pi/PiStatusCode.h>
#include <Guid/Cper.h>
#include <Guid/MuTelemetryCperSection.h>
#include <Library/DebugLib.h>
#include <Library/BaseLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/PrintLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/ParserRegistryLib.h>
#define MAX_STRING 100
/**
* Parses the data located at Err + SectionHead->SectionOffset
*
* @param[in] Strings Pointer to unallocated array of strings which will be populated by the parser
* @param[in] Err Pointer to the HwErrRec bing parsed
* @param[in] SectionHeader Pointer to Section Header of data being parsed
*
* @retval UINTN Number of CHAR16* allocated in Strings
**/
UINTN
ParseGenericSection(
IN OUT CHAR16*** Strings,
IN CONST EFI_COMMON_ERROR_RECORD_HEADER* Err,
IN CONST EFI_ERROR_SECTION_DESCRIPTOR* SectionHead
)
{
// Pointer to section data of section we're looking at
CONST MU_TELEMETRY_CPER_SECTION_DATA *SectionData = (MU_TELEMETRY_CPER_SECTION_DATA*) ((UINT8*)Err + SectionHead->SectionOffset);
CONST UINT8 NumStrings = 4; // Number of CHAR16* which will be allocated within Strings
UINT8 *p; // For capturing each byte of AdditionalInfo Fields
CHAR8 str[9]; // For converting AdditionalInfo1 & 2 into ascii
str[8] = '\0';
// Allocate pointers to strings
*Strings = AllocatePool(NumStrings * sizeof(CHAR16*));
// Allocate actual strings
for(UINT8 i = 0; i < NumStrings; i++){
(*Strings)[i] = AllocatePool((MAX_STRING + 1) * sizeof(CHAR16));
}
//Output ComponentID and SubcomponentID
UnicodeSPrint((*Strings)[0],
(MAX_STRING + 1) * sizeof(CHAR16),
L"Component ID:\n%g",
SectionData->ComponentID);
UnicodeSPrint((*Strings)[1],
(MAX_STRING + 1) * sizeof(CHAR16),
L"SubComponent ID:\n%g",
SectionData->SubComponentID);
// Set p to the start of AdditionalInfo1 to print bytes and ascii
p = (UINT8*)&(SectionData->AdditionalInfo1);
// Capture ascii version of AdditionalInfo1
for(UINT8 i = 0; i < 8; i++)
{
str[i] = ((*(p + i) >= 0x20) && (*(p + i) <= 0x7e)) ? (*(p + i)) : '.';
}
UnicodeSPrint((*Strings)[2],
(MAX_STRING + 1) * sizeof(CHAR16),
L"AdditionalInfo1:\n%02X %02X %02X %02X %02X %02X %02X %02X\n%a",
*(p), *(p + 1), *(p + 2), *(p + 3), *(p + 4), *(p + 5), *(p + 6), *(p + 7),
str);
// Set p to the start of AdditionalInfo2 to print bytes and ascii
p = (UINT8*)&(SectionData->AdditionalInfo2);
// Capture ascii version of AdditionalInfo2
for(UINT8 i = 0; i < 8; i++)
{
str[i] = ((*(p + i) >= 0x20) && (*(p + i) <= 0x7e)) ? (CHAR8)(*(p + i)) : '.';
}
UnicodeSPrint((*Strings)[3],
(MAX_STRING + 1) * sizeof(CHAR16),
L"AdditionalInfo2:\n%02X %02X %02X %02X %02X %02X %02X %02X\n%a",
*(p), *(p + 1), *(p + 2), *(p + 3), *(p + 4), *(p + 5), *(p + 6), *(p + 7),
str);
return NumStrings;
}
/**
The driver's Constructor
Simply registers the generic section parser
**/
EFI_STATUS
EFIAPI
GenericSectionParserLibConstructor(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
// Register the generic section parser
DEBUG((DEBUG_ERROR,"%a Adding to section parser to registry: %r\n", __FUNCTION__,
ParserLibRegisterSectionParser((SECTIONFUNCTIONPTR) ParseGenericSection, &gMuTelemetrySectionTypeGuid)));
return RETURN_SUCCESS;
}

Просмотреть файл

@ -0,0 +1,40 @@
## @file
# GenericSectionParser.inf
#
# This library implements a parser for the MS Generic WHEA section type.
# It must be linked against the ParserRegistryLib.
#
# Copyright (c) Microsoft Corporation. All rights reserved.
# SPDX-License-Identifier: BSD-2-Clause-Patent
##
[Defines]
INF_VERSION = 0x00010006
BASE_NAME = GenericSectionParser
FILE_GUID = 3B42322C-F94B-4F57-636A-873D4DEDD256
VERSION_STRING = 1.0
MODULE_TYPE = DXE_DRIVER
CONSTRUCTOR = GenericSectionParserLibConstructor
[Sources]
GenericSectionParserLib.c
[Packages]
MdePkg/MdePkg.dec
MsWheaPkg/MsWheaPkg.dec
[LibraryClasses]
DebugLib
BaseLib
PrintLib
UefiBootServicesTableLib
UefiDriverEntryPoint
ParserRegistryLib
MuTelemetryHelperLib
[Guids]
gMuTelemetrySectionTypeGuid
[Depex]
gEfiRscHandlerProtocolGuid

Просмотреть файл

@ -0,0 +1,136 @@
/** @file
ParserRegistryLib.c
Holds a table which associates a guid with a function. When ParserLibRegisterSectionParser
is called, a guid and function are put into the table. And when ParserLibFindSectionParser
is called, the input guid is used to return an associated function (if one exists)
Copyright (c) Microsoft Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi.h>
#include <Guid/Cper.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/ParserRegistryLib.h>
struct {
SectionMapType **Map;
UINTN MaxNumber;
UINTN CurrentNumber;
} SectionMap = {NULL,0,0};
/**
* Inserts a guid and function pointer into the internal table. The function pointer can later be retrieved
* by calling ParserLibFindSectionParser with the guid used to register the function. Note that we do not allow one
* guid to register more than one function.
*
* @param[in,out] Map Pointer to Function map the entry is being added to
* @param[in,out] MaxNumber Max number of pointers which can be registered in current allocate
* @param[in,out] CurrentNumber Current number of pointers in the map
* @param[in] Entry Element being added to map
*
* @retval EFI_SUCCESS The entry was successfully added
* EFI_OUT_OF_RESOURCES Couldn't allocate the space required to store the entry
**/
EFI_STATUS
EFIAPI
AddTableEntry (
IN OUT VOID ***Map, // Keeping this void for generality
IN OUT UINTN *MaxNumber,
IN OUT UINTN *CurrentNumber,
IN VOID *Entry
)
{
VOID **TempMap;
// Check whether the table is enough to store new entry.
if (*CurrentNumber == *MaxNumber) {
// Reallocate memory for the table.
TempMap = ReallocatePool (*MaxNumber * sizeof (VOID*),
(*MaxNumber + 5) * sizeof (VOID*), //just increase 5 spaces for now
*Map);
// No enough resource to allocate.
if (TempMap == NULL) {
return EFI_OUT_OF_RESOURCES;
}
*Map = TempMap;
// Increase max number.
*MaxNumber += 5;
}
// Add entry to the table.
(*Map)[*CurrentNumber] = Entry;
(*CurrentNumber)++;
return EFI_SUCCESS;
}
/**
* Inserts a guid and function pointer into the internal table. The function pointer can later be retrieved
* by calling ParserLibFindSectionParser with the guid used to register the function. Note that we do not allow one
* guid to register more than one function.
*
* @param[in] Ptr Function pointer being registered
* @param[in] Guid Guid being registered
*
* @retval EFI_SUCCESS The guid and pointer were successfully registered
* EFI_ABORTED The guid has already been registered
* EFI_OUT_OF_RESOURCES Couldn't allocate the space required to store the guid and pointer
**/
EFI_STATUS
EFIAPI
ParserLibRegisterSectionParser (
IN CONST SECTIONFUNCTIONPTR Ptr,
IN CONST GUID *Guid
)
{
for(UINTN i = 0; i < SectionMap.CurrentNumber; i++)
{
if(CompareGuid((GUID *) &(SectionMap.Map[i]->Guid), Guid)) {
return EFI_ABORTED;
}
}
SectionMapType *new = AllocatePool(sizeof(SectionMapType));
new->Guid = *Guid;
new->Parser = Ptr;
return AddTableEntry((VOID*)(&SectionMap.Map), &SectionMap.MaxNumber, &SectionMap.CurrentNumber, (VOID*)new);
}
/**
* Retrieves a function pointer from internal table using the input guid (if it exists)
*
* @param[in] Guid Guid used to find associated function pointer
*
* @retval NULL The guid was not registered with an associated function
* Anything else Function pointer returned
**/
SECTIONFUNCTIONPTR
EFIAPI
ParserLibFindSectionParser (
IN CONST GUID *Guid
)
{
for(UINTN i = 0; i < SectionMap.CurrentNumber; i++)
{
if(CompareGuid((GUID *) &(SectionMap.Map[i]->Guid), Guid)) {
return SectionMap.Map[i]->Parser;
}
}
return NULL;
}

Просмотреть файл

@ -0,0 +1,34 @@
## @file
# ParserRegistryLib.inf
#
# Holds a table which associates a guid with a function. When ParserLibRegisterSectionParser
# is called, a guid and function are put into the table. And when ParserLibFindSectionParser
# is called, the input guid is used to return an associated function (if one exists)
#
##
# Copyright (c) Microsoft Corporation. All rights reserved.
# SPDX-License-Identifier: BSD-2-Clause-Patent
##
[Defines]
INF_VERSION = 0x00010006
BASE_NAME = ParserRegistryLib
FILE_GUID = 2B04327D-134B-4F53-B185-473742E43A57
VERSION_STRING = 1.0
MODULE_TYPE = DXE_DRIVER
LIBRARY_CLASS = ParserRegistryLib
[Sources]
ParserRegistryLib.c
[Packages]
MsWheaPkg/MsWheaPkg.dec
MdePkg/MdePkg.dec
[LibraryClasses]
BaseLib
BaseMemoryLib
DebugLib
MemoryAllocationLib

Просмотреть файл

@ -0,0 +1,16 @@
# ParserRegistryLib
## About
Holds a table which associates guids with function pointers used for parsing section data.
If an entity wishes to parse a section type in a specific way, they simply need to call the register
function using a the section type guid and function pointer. When HwhMenu.c tries to parse
section data, it will look through all guids and return a function pointer if one matches.
The functions being registered must adhere to the SECTIONFUNCTIONPTR type located in
ParserRegistryLib.h.
## Copyright
Copyright (C) Microsoft Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent

Просмотреть файл

@ -71,7 +71,13 @@
"MSCHANGE",
"BERTs",
"DXEIPL",
"hwerrrec"
"hwerrrec",
"hwhmenu",
"creatorid",
"hwhmenu",
"sectionfunctionptr",
"frontpage",
"fvdxe"
],
"AdditionalIncludePaths": [] # Additional paths to spell check relative to package root (wildcards supported)
}

Просмотреть файл

@ -31,6 +31,11 @@
#
gRaiseTelemetryErrorsAtBoot = {0x34b1e7cd, 0x9cc8, 0x4dcd, {0x9f, 0x9a, 0xf7, 0x1f, 0x1f, 0xae, 0xfd, 0xc6}}
## HWH Menu Formset Guid
#
# Include/Guid/HwhMenuGuid.h
gHwhMenuFormsetGuid = {0x3b82383d, 0x7add, 0x4c6a, {0xad, 0x2b, 0x71, 0x9b, 0x8d, 0x7b, 0x77, 0xc9}}
[Includes]
Include
@ -45,6 +50,7 @@
[LibraryClasses]
MsWheaEarlyStorageLib|Include/Library/MsWheaEarlyStorageLib.h
MuTelemetryHelperLib |Include/Library/MuTelemetryHelperLib.h
ParserRegistryLib|Include/Library/ParserRegistryLib.h
## @libraryclass Checks the validity of hardware error records
##

Просмотреть файл

@ -62,10 +62,14 @@
SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf
IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf
HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
MsWheaEarlyStorageLib|MsWheaPkg/Library/MsWheaEarlyStorageLib/MsWheaEarlyStorageLib.inf
CheckHwErrRecHeaderLib|MsWheaPkg/Library/CheckHwErrRecHeaderLib/CheckHwErrRecHeaderLib.inf
MuTelemetryHelperLib|MsWheaPkg/Library/MuTelemetryHelperLib/MuTelemetryHelperLib.inf
ParserRegistryLib|MsWheaPkg/Library/ParserRegistryLib/ParserRegistryLib.inf
GenericSectionParserLib|MsWheaPkg/Library/GenericSectionParserLib/GenericSectionParserLib.inf
XmlTreeLib|XmlSupportPkg/Library/XmlTreeLib/XmlTreeLib.inf
UnitTestLib|UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf
@ -83,9 +87,7 @@
PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf
DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf
HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf
FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf
@ -124,6 +126,8 @@
MsWheaPkg/Library/MsWheaEarlyStorageLibNull/MsWheaEarlyStorageLibNull.inf
MsWheaPkg/Library/CheckHwErrRecHeaderLib/CheckHwErrRecHeaderLib.inf
MsWheaPkg/Library/MuTelemetryHelperLib/MuTelemetryHelperLib.inf
MsWheaPkg/Library/ParserRegistryLib/ParserRegistryLib.inf
MsWheaPkg/Library/GenericSectionParserLib/GenericSectionParserLib.inf
[Components.IA32]
MsWheaPkg/MsWheaReport/Pei/MsWheaReportPei.inf {
@ -151,5 +155,8 @@
MsWheaPkg/Test/UnitTests/MsWheaReportUnitTestApp/MsWheaReportUnitTestApp.inf
MsWheaPkg/Test/UnitTests/MsWheaEarlyStorageUnitTestApp/MsWheaEarlyUnitTestApp.inf
# Hardware Health (Menu) application
MsWheaPkg/HwhMenu/HwhMenu.inf
[BuildOptions]
*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES