зеркало из https://github.com/microsoft/mu_plus.git
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:
Родитель
5f767678ad
Коммит
859ebe80ae
|
@ -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
|
||||
);
|
|
@ -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
|
||||
);
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 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
|
Загрузка…
Ссылка в новой задаче