diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:49:04 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:49:04 +0000 |
commit | 16f504a9dca3fe3b70568f67b7d41241ae485288 (patch) | |
tree | c60f36ada0496ba928b7161059ba5ab1ab224f9d /src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application | |
parent | Initial commit. (diff) | |
download | virtualbox-upstream.tar.xz virtualbox-upstream.zip |
Adding upstream version 7.0.6-dfsg.upstream/7.0.6-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application')
48 files changed, 11658 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.c new file mode 100644 index 00000000..da74e046 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.c @@ -0,0 +1,1074 @@ +/** @file + The application to show the Boot Manager Menu. + +Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "BootManagerMenu.h" + +EFI_HII_HANDLE gStringPackHandle; + +BOOLEAN mModeInitialized = FALSE; + +// +// Boot video resolution and text mode. +// +UINT32 mBootHorizontalResolution = 0; +UINT32 mBootVerticalResolution = 0; +UINT32 mBootTextModeColumn = 0; +UINT32 mBootTextModeRow = 0; +// +// BIOS setup video resolution and text mode. +// +UINT32 mSetupTextModeColumn = 0; +UINT32 mSetupTextModeRow = 0; +UINT32 mSetupHorizontalResolution = 0; +UINT32 mSetupVerticalResolution = 0; + +/** + Prints a unicode string to the default console, at + the supplied cursor position, using L"%s" format. + + @param Column The cursor position to print the string at. + @param Row The cursor position to print the string at + @param String String pointer. + + @return Length of string printed to the console + +**/ +UINTN +PrintStringAt ( + IN UINTN Column, + IN UINTN Row, + IN CHAR16 *String + ) +{ + + gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row); + return Print (L"%s", String); +} + +/** + Prints a character to the default console, at + the supplied cursor position, using L"%c" format. + + @param Column The cursor position to print the string at. + @param Row The cursor position to print the string at. + @param Character Character to print. + + @return Length of string printed to the console. + +**/ +UINTN +PrintCharAt ( + IN UINTN Column, + IN UINTN Row, + CHAR16 Character + ) +{ + gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row); + return Print (L"%c", Character); +} + +/** + Count the storage space of a Unicode string which uses current language to get + from input string ID. + + @param StringId The input string to be counted. + + @return Storage space for the input string. + +**/ +UINTN +GetLineWidth ( + IN EFI_STRING_ID StringId + ) +{ + UINTN Index; + UINTN IncrementValue; + EFI_STRING String; + UINTN LineWidth; + + LineWidth = 0; + String = HiiGetString (gStringPackHandle, StringId, NULL); + + if (String != NULL) { + Index = 0; + IncrementValue = 1; + + do { + // + // Advance to the null-terminator or to the first width directive + // + for (; + (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0); + Index++, LineWidth = LineWidth + IncrementValue + ) + ; + + // + // We hit the null-terminator, we now have a count + // + if (String[Index] == 0) { + break; + } + // + // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed + // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2) + // + if (String[Index] == NARROW_CHAR) { + // + // Skip to the next character + // + Index++; + IncrementValue = 1; + } else { + // + // Skip to the next character + // + Index++; + IncrementValue = 2; + } + } while (String[Index] != 0); + FreePool (String); + } + + return LineWidth; +} + +/** + This function uses calculate the boot menu location, size and scroll bar information. + + @param BootMenuData The boot menu data to be processed. + + @return EFI_SUCCESS calculate boot menu information successful. + @retval EFI_INVALID_PARAMETER Input parameter is invalid + +**/ +EFI_STATUS +InitializeBootMenuScreen ( + IN OUT BOOT_MENU_POPUP_DATA *BootMenuData + ) +{ + UINTN MaxStrWidth; + UINTN StrWidth; + UINTN Index; + UINTN Column; + UINTN Row; + UINTN MaxPrintRows; + UINTN UnSelectableItmes; + + if (BootMenuData == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Get maximum string width + // + MaxStrWidth = 0; + for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++) { + StrWidth = GetLineWidth (BootMenuData->TitleToken[Index]); + MaxStrWidth = MaxStrWidth > StrWidth ? MaxStrWidth : StrWidth; + } + + for (Index = 0; Index < BootMenuData->ItemCount; Index++) { + StrWidth = GetLineWidth (BootMenuData->PtrTokens[Index]); + MaxStrWidth = MaxStrWidth > StrWidth ? MaxStrWidth : StrWidth; + } + + for (Index = 0; Index < HELP_TOKEN_COUNT; Index++) { + StrWidth = GetLineWidth (BootMenuData->HelpToken[Index]); + MaxStrWidth = MaxStrWidth > StrWidth ? MaxStrWidth : StrWidth; + } + // + // query current row and column to calculate boot menu location + // + gST->ConOut->QueryMode ( + gST->ConOut, + gST->ConOut->Mode->Mode, + &Column, + &Row + ); + + MaxPrintRows = Row - 6; + UnSelectableItmes = TITLE_TOKEN_COUNT + 2 + HELP_TOKEN_COUNT + 2; + BootMenuData->MenuScreen.Width = MaxStrWidth + 8; + if (BootMenuData->ItemCount + UnSelectableItmes > MaxPrintRows) { + BootMenuData->MenuScreen.Height = MaxPrintRows; + BootMenuData->ScrollBarControl.HasScrollBar = TRUE; + BootMenuData->ScrollBarControl.ItemCountPerScreen = MaxPrintRows - UnSelectableItmes; + BootMenuData->ScrollBarControl.FirstItem = 0; + BootMenuData->ScrollBarControl.LastItem = MaxPrintRows - UnSelectableItmes - 1; + } else { + BootMenuData->MenuScreen.Height = BootMenuData->ItemCount + UnSelectableItmes; + BootMenuData->ScrollBarControl.HasScrollBar = FALSE; + BootMenuData->ScrollBarControl.ItemCountPerScreen = BootMenuData->ItemCount; + BootMenuData->ScrollBarControl.FirstItem = 0; + BootMenuData->ScrollBarControl.LastItem = BootMenuData->ItemCount - 1; + } + BootMenuData->MenuScreen.StartCol = (Column - BootMenuData->MenuScreen.Width) / 2; + BootMenuData->MenuScreen.StartRow = (Row - BootMenuData->MenuScreen.Height) / 2; + + return EFI_SUCCESS; +} +/** + This function uses check boot option is wheher setup application or no + + @param BootOption Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array. + + @retval TRUE This boot option is setup application. + @retval FALSE This boot options isn't setup application + +**/ +BOOLEAN +IsBootManagerMenu ( + IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption + ) +{ + EFI_STATUS Status; + EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu; + + Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu); + if (!EFI_ERROR (Status)) { + EfiBootManagerFreeLoadOption (&BootManagerMenu); + } + + return (BOOLEAN) (!EFI_ERROR (Status) && (BootOption->OptionNumber == BootManagerMenu.OptionNumber)); +} + +/** + Return whether to ignore the boot option. + + @param BootOption Pointer to EFI_BOOT_MANAGER_LOAD_OPTION to check. + + @retval TRUE Ignore the boot option. + @retval FALSE Do not ignore the boot option. +**/ +BOOLEAN +IgnoreBootOption ( + IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath; + + // + // Ignore myself. + // + Status = gBS->HandleProtocol (gImageHandle, &gEfiLoadedImageDevicePathProtocolGuid, (VOID **) &ImageDevicePath); + ASSERT_EFI_ERROR (Status); + if (CompareMem (BootOption->FilePath, ImageDevicePath, GetDevicePathSize (ImageDevicePath)) == 0) { + return TRUE; + } + + // + // Do not ignore Boot Manager Menu. + // + if (IsBootManagerMenu (BootOption)) { + return FALSE; + } + + // + // Ignore the hidden/inactive boot option. + // + if (((BootOption->Attributes & LOAD_OPTION_HIDDEN) != 0) || ((BootOption->Attributes & LOAD_OPTION_ACTIVE) == 0)) { + return TRUE; + } + + return FALSE; +} + +/** + This function uses to initialize boot menu data + + @param BootOption Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array. + @param BootOptionCount Number of boot option. + @param BootMenuData The Input BootMenuData to be initialized. + + @retval EFI_SUCCESS Initialize boot menu data successful. + @retval EFI_INVALID_PARAMETER Input parameter is invalid. + +**/ +EFI_STATUS +InitializeBootMenuData ( + IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption, + IN UINTN BootOptionCount, + OUT BOOT_MENU_POPUP_DATA *BootMenuData + ) +{ + UINTN Index; + UINTN StrIndex; + + if (BootOption == NULL || BootMenuData == NULL) { + return EFI_INVALID_PARAMETER; + } + + BootMenuData->TitleToken[0] = STRING_TOKEN (STR_BOOT_POPUP_MENU_TITLE_STRING); + BootMenuData->PtrTokens = AllocateZeroPool (BootOptionCount * sizeof (EFI_STRING_ID)); + ASSERT (BootMenuData->PtrTokens != NULL); + + // + // Skip boot option which created by BootNext Variable + // + for (StrIndex = 0, Index = 0; Index < BootOptionCount; Index++) { + if (IgnoreBootOption (&BootOption[Index])) { + continue; + } + + ASSERT (BootOption[Index].Description != NULL); + BootMenuData->PtrTokens[StrIndex++] = HiiSetString ( + gStringPackHandle, + 0, + BootOption[Index].Description, + NULL + ); + } + + BootMenuData->ItemCount = StrIndex; + BootMenuData->HelpToken[0] = STRING_TOKEN (STR_BOOT_POPUP_MENU_HELP1_STRING); + BootMenuData->HelpToken[1] = STRING_TOKEN (STR_BOOT_POPUP_MENU_HELP2_STRING); + BootMenuData->HelpToken[2] = STRING_TOKEN (STR_BOOT_POPUP_MENU_HELP3_STRING); + InitializeBootMenuScreen (BootMenuData); + BootMenuData->SelectItem = 0; + return EFI_SUCCESS; +} + +/** + This function uses input select item to highlight selected item + and set current selected item in BootMenuData + + @param WantSelectItem The user wants to select item. + @param BootMenuData The boot menu data to be processed + + @return EFI_SUCCESS Highlight selected item and update current selected + item successful + @retval EFI_INVALID_PARAMETER Input parameter is invalid +**/ +EFI_STATUS +BootMenuSelectItem ( + IN UINTN WantSelectItem, + IN OUT BOOT_MENU_POPUP_DATA *BootMenuData + ) +{ + INT32 SavedAttribute; + EFI_STRING String; + UINTN StartCol; + UINTN StartRow; + UINTN PrintCol; + UINTN PrintRow; + UINTN TopShadeNum; + UINTN LowShadeNum; + UINTN FirstItem; + UINTN LastItem; + UINTN ItemCountPerScreen; + UINTN Index; + BOOLEAN RePaintItems; + + if (BootMenuData == NULL || WantSelectItem >= BootMenuData->ItemCount) { + return EFI_INVALID_PARAMETER; + } + ASSERT (BootMenuData->ItemCount != 0); + SavedAttribute = gST->ConOut->Mode->Attribute; + RePaintItems = FALSE; + StartCol = BootMenuData->MenuScreen.StartCol; + StartRow = BootMenuData->MenuScreen.StartRow; + // + // print selectable items again and adjust scroll bar if need + // + if (BootMenuData->ScrollBarControl.HasScrollBar && + (WantSelectItem < BootMenuData->ScrollBarControl.FirstItem || + WantSelectItem > BootMenuData->ScrollBarControl.LastItem || + WantSelectItem == BootMenuData->SelectItem)) { + ItemCountPerScreen = BootMenuData->ScrollBarControl.ItemCountPerScreen; + // + // Set first item and last item + // + if (WantSelectItem < BootMenuData->ScrollBarControl.FirstItem) { + BootMenuData->ScrollBarControl.FirstItem = WantSelectItem; + BootMenuData->ScrollBarControl.LastItem = WantSelectItem + ItemCountPerScreen - 1; + } else if (WantSelectItem > BootMenuData->ScrollBarControl.LastItem) { + BootMenuData->ScrollBarControl.FirstItem = WantSelectItem - ItemCountPerScreen + 1; + BootMenuData->ScrollBarControl.LastItem = WantSelectItem; + } + gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE); + FirstItem = BootMenuData->ScrollBarControl.FirstItem; + LastItem = BootMenuData->ScrollBarControl.LastItem; + TopShadeNum = 0; + if (FirstItem != 0) { + TopShadeNum = (FirstItem * ItemCountPerScreen) / BootMenuData->ItemCount; + if ((FirstItem * ItemCountPerScreen) % BootMenuData->ItemCount != 0) { + TopShadeNum++; + } + PrintCol = StartCol + BootMenuData->MenuScreen.Width - 2; + PrintRow = StartRow + TITLE_TOKEN_COUNT + 2; + for (Index = 0; Index < TopShadeNum; Index++, PrintRow++) { + PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_LIGHT_SHADE); + } + } + LowShadeNum = 0; + if (LastItem != BootMenuData->ItemCount - 1) { + LowShadeNum = ((BootMenuData->ItemCount - 1 - LastItem) * ItemCountPerScreen) / BootMenuData->ItemCount; + if (((BootMenuData->ItemCount - 1 - LastItem) * ItemCountPerScreen) % BootMenuData->ItemCount != 0) { + LowShadeNum++; + } + PrintCol = StartCol + BootMenuData->MenuScreen.Width - 2; + PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + ItemCountPerScreen - LowShadeNum; + for (Index = 0; Index < LowShadeNum; Index++, PrintRow++) { + PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_LIGHT_SHADE); + } + } + PrintCol = StartCol + BootMenuData->MenuScreen.Width - 2; + PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + TopShadeNum; + for (Index = TopShadeNum; Index < ItemCountPerScreen - LowShadeNum; Index++, PrintRow++) { + PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_FULL_BLOCK); + } + + + // + // Clear selectable items first + // + PrintCol = StartCol + 1; + PrintRow = StartRow + TITLE_TOKEN_COUNT + 2; + String = AllocateZeroPool ((BootMenuData->MenuScreen.Width - 2) * sizeof (CHAR16)); + ASSERT (String != NULL); + for (Index = 0; Index < BootMenuData->MenuScreen.Width - 3; Index++) { + String[Index] = 0x20; + } + for (Index = 0; Index < ItemCountPerScreen; Index++) { + PrintStringAt (PrintCol, PrintRow + Index, String); + } + FreePool (String); + // + // print selectable items + // + for (Index = 0; Index < ItemCountPerScreen; Index++, PrintRow++) { + String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[Index + FirstItem], NULL); + PrintStringAt (PrintCol, PrintRow, String); + FreePool (String); + } + RePaintItems = TRUE; + } + + // + // if Want Select and selected item isn't the same and doesn't re-draw selectable + // items, clear select item + // + FirstItem = BootMenuData->ScrollBarControl.FirstItem; + if (WantSelectItem != BootMenuData->SelectItem && !RePaintItems) { + gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE); + String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[BootMenuData->SelectItem], NULL); + PrintCol = StartCol + 1; + PrintRow = StartRow + 3 + BootMenuData->SelectItem - FirstItem; + PrintStringAt (PrintCol, PrintRow, String); + FreePool (String); + } + + // + // Print want to select item + // + gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLACK); + String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[WantSelectItem], NULL); + PrintCol = StartCol + 1; + PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + WantSelectItem - FirstItem; + PrintStringAt (PrintCol, PrintRow, String); + FreePool (String); + + gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute); + BootMenuData->SelectItem = WantSelectItem; + return EFI_SUCCESS; +} + +/** + This function uses to draw boot popup menu + + @param BootMenuData The Input BootMenuData to be processed. + + @retval EFI_SUCCESS Draw boot popup menu successful. + +**/ +EFI_STATUS +DrawBootPopupMenu ( + IN BOOT_MENU_POPUP_DATA *BootMenuData + ) +{ + EFI_STRING String; + UINTN Index; + UINTN Width; + UINTN StartCol; + UINTN StartRow; + UINTN PrintRow; + UINTN PrintCol; + UINTN LineWidth; + INT32 SavedAttribute; + UINTN ItemCountPerScreen; + + gST->ConOut->ClearScreen (gST->ConOut); + + SavedAttribute = gST->ConOut->Mode->Attribute; + gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE); + Width = BootMenuData->MenuScreen.Width; + StartCol = BootMenuData->MenuScreen.StartCol; + StartRow = BootMenuData->MenuScreen.StartRow; + ItemCountPerScreen = BootMenuData->ScrollBarControl.ItemCountPerScreen; + PrintRow = StartRow; + + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + // + // Draw Boot popup menu screen + // + PrintCharAt (StartCol, PrintRow, BOXDRAW_DOWN_RIGHT); + for (Index = 1; Index < Width - 1; Index++) { + PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL); + } + PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_DOWN_LEFT); + + // + // Draw the screen for title + // + String = AllocateZeroPool ((Width - 1) * sizeof (CHAR16)); + ASSERT (String != NULL); + for (Index = 0; Index < Width - 2; Index++) { + String[Index] = 0x20; + } + + for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++) { + PrintRow++; + PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL); + PrintStringAt (StartCol + 1, PrintRow, String); + PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL); + } + + PrintRow++; + PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL_RIGHT); + for (Index = 1; Index < Width - 1; Index++) { + PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL); + } + PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL_LEFT); + + // + // Draw screen for selectable items + // + for (Index = 0; Index < ItemCountPerScreen; Index++) { + PrintRow++; + PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL); + PrintStringAt (StartCol + 1, PrintRow, String); + PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL); + } + + PrintRow++; + PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL_RIGHT); + for (Index = 1; Index < Width - 1; Index++) { + PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL); + } + PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL_LEFT); + + // + // Draw screen for Help + // + for (Index = 0; Index < HELP_TOKEN_COUNT; Index++) { + PrintRow++; + PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL); + PrintStringAt (StartCol + 1, PrintRow, String); + PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL); + } + FreePool (String); + + PrintRow++; + PrintCharAt (StartCol, PrintRow, BOXDRAW_UP_RIGHT); + for (Index = 1; Index < Width - 1; Index++) { + PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL); + } + PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_UP_LEFT); + + + // + // print title strings + // + PrintRow = StartRow + 1; + for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++, PrintRow++) { + String = HiiGetString (gStringPackHandle, BootMenuData->TitleToken[Index], NULL); + LineWidth = GetLineWidth (BootMenuData->TitleToken[Index]); + PrintCol = StartCol + (Width - LineWidth) / 2; + PrintStringAt (PrintCol, PrintRow, String); + FreePool (String); + } + + // + // print selectable items + // + PrintCol = StartCol + 1; + PrintRow = StartRow + TITLE_TOKEN_COUNT + 2; + for (Index = 0; Index < ItemCountPerScreen; Index++, PrintRow++) { + String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[Index], NULL); + PrintStringAt (PrintCol, PrintRow, String); + FreePool (String); + } + + // + // Print Help strings + // + PrintRow++; + for (Index = 0; Index < HELP_TOKEN_COUNT; Index++, PrintRow++) { + String = HiiGetString (gStringPackHandle, BootMenuData->HelpToken[Index], NULL); + LineWidth = GetLineWidth (BootMenuData->HelpToken[Index]); + PrintCol = StartCol + (Width - LineWidth) / 2; + PrintStringAt (PrintCol, PrintRow, String); + FreePool (String); + } + + // + // Print scroll bar if has scroll bar + // + if (BootMenuData->ScrollBarControl.HasScrollBar) { + PrintCol = StartCol + Width - 2; + PrintRow = StartRow + 2; + PrintCharAt (PrintCol, PrintRow, GEOMETRICSHAPE_UP_TRIANGLE); + PrintCharAt (PrintCol + 1, PrintRow, BOXDRAW_VERTICAL); + PrintRow += (ItemCountPerScreen + 1); + PrintCharAt (PrintCol, PrintRow, GEOMETRICSHAPE_DOWN_TRIANGLE); + PrintCharAt (PrintCol + 1, PrintRow, BOXDRAW_VERTICAL); + } + + gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute); + // + // Print Selected item + // + BootMenuSelectItem (BootMenuData->SelectItem, BootMenuData); + return EFI_SUCCESS; +} + +/** + This function uses to boot from selected item + + @param BootOptions Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array. + @param BootOptionCount Number of boot option. + @param SelectItem Current selected item. +**/ +VOID +BootFromSelectOption ( + IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions, + IN UINTN BootOptionCount, + IN UINTN SelectItem + ) +{ + UINTN ItemNum; + UINTN Index; + + ASSERT (BootOptions != NULL); + + for (ItemNum = 0, Index = 0; Index < BootOptionCount; Index++) { + if (IgnoreBootOption (&BootOptions[Index])) { + continue; + } + + if (ItemNum++ == SelectItem) { + EfiBootManagerBoot (&BootOptions[Index]); + break; + } + } +} + +/** + This function will change video resolution and text mode + according to defined setup mode or defined boot mode + + @param IsSetupMode Indicate mode is changed to setup mode or boot mode. + + @retval EFI_SUCCESS Mode is changed successfully. + @retval Others Mode failed to be changed. + +**/ +EFI_STATUS +EFIAPI +BdsSetConsoleMode ( + BOOLEAN IsSetupMode + ) +{ + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut; + UINTN SizeOfInfo; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; + UINT32 MaxGopMode; + UINT32 MaxTextMode; + UINT32 ModeNumber; + UINT32 NewHorizontalResolution; + UINT32 NewVerticalResolution; + UINT32 NewColumns; + UINT32 NewRows; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + EFI_STATUS Status; + UINTN Index; + UINTN CurrentColumn; + UINTN CurrentRow; + + MaxGopMode = 0; + MaxTextMode = 0; + + // + // Get current video resolution and text mode + // + Status = gBS->HandleProtocol ( + gST->ConsoleOutHandle, + &gEfiGraphicsOutputProtocolGuid, + (VOID**)&GraphicsOutput + ); + if (EFI_ERROR (Status)) { + GraphicsOutput = NULL; + } + + Status = gBS->HandleProtocol ( + gST->ConsoleOutHandle, + &gEfiSimpleTextOutProtocolGuid, + (VOID**)&SimpleTextOut + ); + if (EFI_ERROR (Status)) { + SimpleTextOut = NULL; + } + + if ((GraphicsOutput == NULL) || (SimpleTextOut == NULL)) { + return EFI_UNSUPPORTED; + } + + if (IsSetupMode) { + // + // The required resolution and text mode is setup mode. + // + NewHorizontalResolution = mSetupHorizontalResolution; + NewVerticalResolution = mSetupVerticalResolution; + NewColumns = mSetupTextModeColumn; + NewRows = mSetupTextModeRow; + } else { + // + // The required resolution and text mode is boot mode. + // + NewHorizontalResolution = mBootHorizontalResolution; + NewVerticalResolution = mBootVerticalResolution; + NewColumns = mBootTextModeColumn; + NewRows = mBootTextModeRow; + } + + if (GraphicsOutput != NULL) { + MaxGopMode = GraphicsOutput->Mode->MaxMode; + } + + if (SimpleTextOut != NULL) { + MaxTextMode = SimpleTextOut->Mode->MaxMode; + } + + // + // 1. If current video resolution is same with required video resolution, + // video resolution need not be changed. + // 1.1. If current text mode is same with required text mode, text mode need not be changed. + // 1.2. If current text mode is different from required text mode, text mode need be changed. + // 2. If current video resolution is different from required video resolution, we need restart whole console drivers. + // + for (ModeNumber = 0; ModeNumber < MaxGopMode; ModeNumber++) { + Status = GraphicsOutput->QueryMode ( + GraphicsOutput, + ModeNumber, + &SizeOfInfo, + &Info + ); + if (!EFI_ERROR (Status)) { + if ((Info->HorizontalResolution == NewHorizontalResolution) && + (Info->VerticalResolution == NewVerticalResolution)) { + if ((GraphicsOutput->Mode->Info->HorizontalResolution == NewHorizontalResolution) && + (GraphicsOutput->Mode->Info->VerticalResolution == NewVerticalResolution)) { + // + // Current resolution is same with required resolution, check if text mode need be set + // + Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, &CurrentColumn, &CurrentRow); + ASSERT_EFI_ERROR (Status); + if (CurrentColumn == NewColumns && CurrentRow == NewRows) { + // + // If current text mode is same with required text mode. Do nothing + // + FreePool (Info); + return EFI_SUCCESS; + } else { + // + // If current text mode is different from required text mode. Set new video mode + // + for (Index = 0; Index < MaxTextMode; Index++) { + Status = SimpleTextOut->QueryMode (SimpleTextOut, Index, &CurrentColumn, &CurrentRow); + if (!EFI_ERROR(Status)) { + if ((CurrentColumn == NewColumns) && (CurrentRow == NewRows)) { + // + // Required text mode is supported, set it. + // + Status = SimpleTextOut->SetMode (SimpleTextOut, Index); + ASSERT_EFI_ERROR (Status); + // + // Update text mode PCD. + // + Status = PcdSet32S (PcdConOutColumn, mSetupTextModeColumn); + ASSERT_EFI_ERROR (Status); + Status = PcdSet32S (PcdConOutRow, mSetupTextModeRow); + ASSERT_EFI_ERROR (Status); + FreePool (Info); + return EFI_SUCCESS; + } + } + } + if (Index == MaxTextMode) { + // + // If required text mode is not supported, return error. + // + FreePool (Info); + return EFI_UNSUPPORTED; + } + } + } else { + // + // If current video resolution is not same with the new one, set new video resolution. + // In this case, the driver which produces simple text out need be restarted. + // + Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber); + if (!EFI_ERROR (Status)) { + FreePool (Info); + break; + } + } + } + FreePool (Info); + } + } + + if (ModeNumber == MaxGopMode) { + // + // If the resolution is not supported, return error. + // + return EFI_UNSUPPORTED; + } + + // + // Set PCD to Inform GraphicsConsole to change video resolution. + // Set PCD to Inform Consplitter to change text mode. + // + Status = PcdSet32S (PcdVideoHorizontalResolution, NewHorizontalResolution); + ASSERT_EFI_ERROR (Status); + Status = PcdSet32S (PcdVideoVerticalResolution, NewVerticalResolution); + ASSERT_EFI_ERROR (Status); + Status = PcdSet32S (PcdConOutColumn, NewColumns); + ASSERT_EFI_ERROR (Status); + Status = PcdSet32S (PcdConOutRow, NewRows); + ASSERT_EFI_ERROR (Status); + + // + // Video mode is changed, so restart graphics console driver and higher level driver. + // Reconnect graphics console driver and higher level driver. + // Locate all the handles with GOP protocol and reconnect it. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleTextOutProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (!EFI_ERROR (Status)) { + for (Index = 0; Index < HandleCount; Index++) { + gBS->DisconnectController (HandleBuffer[Index], NULL, NULL); + } + for (Index = 0; Index < HandleCount; Index++) { + gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE); + } + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + } + + return EFI_SUCCESS; +} + +/** + Display the boot popup menu and allow user select boot item. + + @param ImageHandle The image handle. + @param SystemTable The system table. + + @retval EFI_SUCCESS Boot from selected boot option, and return success from boot option + @retval EFI_NOT_FOUND User select to enter setup or can not find boot option + +**/ +EFI_STATUS +EFIAPI +BootManagerMenuEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_BOOT_MANAGER_LOAD_OPTION *BootOption; + UINTN BootOptionCount; + EFI_STATUS Status; + BOOT_MENU_POPUP_DATA BootMenuData; + UINTN Index; + EFI_INPUT_KEY Key; + BOOLEAN ExitApplication; + UINTN SelectItem; + EFI_BOOT_LOGO_PROTOCOL *BootLogo; + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut; + UINTN BootTextColumn; + UINTN BootTextRow; + + // + // Set Logo status invalid when boot manager menu is launched + // + BootLogo = NULL; + Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo); + if (!EFI_ERROR (Status) && (BootLogo != NULL)) { + Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0); + ASSERT_EFI_ERROR (Status); + } + + gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL); + + gStringPackHandle = HiiAddPackages ( + &gEfiCallerIdGuid, + gImageHandle, + BootManagerMenuAppStrings, + NULL + ); + ASSERT (gStringPackHandle != NULL); + + // + // Connect all prior to entering the platform setup menu. + // + EfiBootManagerConnectAll (); + EfiBootManagerRefreshAllBootOption (); + + BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot); + + if (!mModeInitialized) { + // + // After the console is ready, get current video resolution + // and text mode before launching setup at first time. + // + Status = gBS->HandleProtocol ( + gST->ConsoleOutHandle, + &gEfiGraphicsOutputProtocolGuid, + (VOID**)&GraphicsOutput + ); + if (EFI_ERROR (Status)) { + GraphicsOutput = NULL; + } + + Status = gBS->HandleProtocol ( + gST->ConsoleOutHandle, + &gEfiSimpleTextOutProtocolGuid, + (VOID**)&SimpleTextOut + ); + if (EFI_ERROR (Status)) { + SimpleTextOut = NULL; + } + + if (GraphicsOutput != NULL) { + // + // Get current video resolution and text mode. + // + mBootHorizontalResolution = GraphicsOutput->Mode->Info->HorizontalResolution; + mBootVerticalResolution = GraphicsOutput->Mode->Info->VerticalResolution; + } + + if (SimpleTextOut != NULL) { + Status = SimpleTextOut->QueryMode ( + SimpleTextOut, + SimpleTextOut->Mode->Mode, + &BootTextColumn, + &BootTextRow + ); + mBootTextModeColumn = (UINT32)BootTextColumn; + mBootTextModeRow = (UINT32)BootTextRow; + } + + // + // Get user defined text mode for setup. + // + mSetupHorizontalResolution = PcdGet32 (PcdSetupVideoHorizontalResolution); + mSetupVerticalResolution = PcdGet32 (PcdSetupVideoVerticalResolution); + mSetupTextModeColumn = PcdGet32 (PcdSetupConOutColumn); + mSetupTextModeRow = PcdGet32 (PcdSetupConOutRow); + mModeInitialized = TRUE; + } + + // + // Set back to conventional setup resolution + // + BdsSetConsoleMode (TRUE); + + // + // Initialize Boot menu data + // + Status = InitializeBootMenuData (BootOption, BootOptionCount, &BootMenuData); + // + // According to boot menu data to draw boot popup menu + // + DrawBootPopupMenu (&BootMenuData); + + // + // check user input to determine want to re-draw or boot from user selected item + // + ExitApplication = FALSE; + while (!ExitApplication) { + gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index); + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + if (!EFI_ERROR (Status)) { + switch (Key.UnicodeChar) { + + case CHAR_NULL: + switch (Key.ScanCode) { + + case SCAN_UP: + SelectItem = BootMenuData.SelectItem == 0 ? BootMenuData.ItemCount - 1 : BootMenuData.SelectItem - 1; + BootMenuSelectItem (SelectItem, &BootMenuData); + break; + + case SCAN_DOWN: + SelectItem = BootMenuData.SelectItem == BootMenuData.ItemCount - 1 ? 0 : BootMenuData.SelectItem + 1; + BootMenuSelectItem (SelectItem, &BootMenuData); + break; + + case SCAN_ESC: + gST->ConOut->ClearScreen (gST->ConOut); + ExitApplication = TRUE; + // + // Set boot resolution for normal boot + // + BdsSetConsoleMode (FALSE); + break; + + default: + break; + } + break; + + case CHAR_CARRIAGE_RETURN: + gST->ConOut->ClearScreen (gST->ConOut); + // + // Set boot resolution for normal boot + // + BdsSetConsoleMode (FALSE); + BootFromSelectOption (BootOption, BootOptionCount, BootMenuData.SelectItem); + // + // Back to boot manager menu again, set back to setup resolution + // + BdsSetConsoleMode (TRUE); + DrawBootPopupMenu (&BootMenuData); + break; + + default: + break; + } + } + } + EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount); + FreePool (BootMenuData.PtrTokens); + + HiiRemovePackages (gStringPackHandle); + + return Status; + +} diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.h b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.h new file mode 100644 index 00000000..5c85023b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.h @@ -0,0 +1,54 @@ +/** @file + FrontPage routines to handle the callbacks and browser calls + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef _BOOT_MANAGER_MENU_H_ +#define _BOOT_MANAGER_MENU_H_ + +#include <Uefi.h> +#include <Guid/MdeModuleHii.h> +#include <Library/UefiBootManagerLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> +#include <Library/HiiLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DevicePathLib.h> +#include <Protocol/LoadedImage.h> +#include <Protocol/BootLogo.h> + +#define TITLE_TOKEN_COUNT 1 +#define HELP_TOKEN_COUNT 3 + +typedef struct _BOOT_MENU_SCREEN { + UINTN StartCol; + UINTN StartRow; + UINTN Width; + UINTN Height; +} BOOT_MENU_SCREEN; + +typedef struct _BOOT_MENU_SCROLL_BAR_CONTROL { + BOOLEAN HasScrollBar; + UINTN ItemCountPerScreen; + UINTN FirstItem; + UINTN LastItem; +} BOOT_MENU_SCROLL_BAR_CONTROL; + +typedef struct _BOOT_MENU_POPUP_DATA { + EFI_STRING_ID TitleToken[TITLE_TOKEN_COUNT]; // Title string ID + UINTN ItemCount; // Selectable item count + EFI_STRING_ID *PtrTokens; // All of selectable items string ID + EFI_STRING_ID HelpToken[HELP_TOKEN_COUNT]; // All of help string ID + UINTN SelectItem; // Current select item + BOOT_MENU_SCREEN MenuScreen; // Boot menu screen information + BOOT_MENU_SCROLL_BAR_CONTROL ScrollBarControl; // Boot menu scroll bar information +} BOOT_MENU_POPUP_DATA; + +#endif + diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf new file mode 100644 index 00000000..e2a31168 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf @@ -0,0 +1,62 @@ +## @file +# The application to show the Boot Manager Menu. +# +# The application pops up a menu showing all the boot options referenced by +# BootOrder NV variable and user can choose to boot from one of them. +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BootManagerMenuApp + MODULE_UNI_FILE = BootManagerMenuApp.uni + FILE_GUID = EEC25BDC-67F2-4D95-B1D5-F81B2039D11D + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = BootManagerMenuEntry + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + BootManagerMenu.c + BootManagerMenu.h + BootManagerMenuStrings.uni + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + HiiLib + DebugLib + UefiLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiApplicationEntryPoint + UefiBootManagerLib + +[Guids] + +[Protocols] + gEfiBootLogoProtocolGuid ## SOMETIMES_CONSUMES + gEfiLoadedImageDevicePathProtocolGuid ## CONSUMES + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow ## PRODUCES + gEfiMdeModulePkgTokenSpaceGuid.PcdConOutColumn ## PRODUCES + gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution ## PRODUCES + gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution ## PRODUCES + gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutColumn ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutRow ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoHorizontalResolution ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoVerticalResolution ## SOMETIMES_CONSUMES + +[UserExtensions.TianoCore."ExtraFiles"] + BootManagerMenuAppExtra.uni diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.uni new file mode 100644 index 00000000..8cda38fb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.uni @@ -0,0 +1,17 @@ +// /** @file
+// The application to show the Boot Manager Menu.
+//
+// The application pops up a menu showing all the boot options referenced by
+// BootOrder NV variable and user can choose to boot from one of them.
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "The application to show the Boot Manager Menu"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The application pops up a menu showing all the boot options referenced by BootOrder NV variable and user can choose to boot from one of them."
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuAppExtra.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuAppExtra.uni new file mode 100644 index 00000000..c43d78ec --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuAppExtra.uni @@ -0,0 +1,17 @@ +// /** @file
+// The application to show the Boot Manager Menu.
+//
+// The application pops up a menu showing all the boot options referenced by
+// BootOrder NV variable and user can choose to boot from one of them.
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Boot Manager Menu Application"
+
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuStrings.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuStrings.uni new file mode 100644 index 00000000..355bd52c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuStrings.uni @@ -0,0 +1,24 @@ +// /** @file
+// String definitions for BootManagerMenuApp.
+//
+// Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+/=#
+
+#langdef en-US "English"
+#langdef fr-FR "Français"
+
+#string STR_BOOT_POPUP_MENU_TITLE_STRING #language en-US "Please select boot device:"
+ #language fr-FR "Please select boot device:"
+
+#string STR_BOOT_POPUP_MENU_HELP1_STRING #language en-US "↑ and ↓ to move selection"
+ #language fr-FR "↑ and ↓ to move selection"
+
+#string STR_BOOT_POPUP_MENU_HELP2_STRING #language en-US "ENTER to select boot device"
+ #language fr-FR "ENTER to select boot device"
+
+#string STR_BOOT_POPUP_MENU_HELP3_STRING #language en-US "ESC to exit"
+ #language fr-FR "ESC to exit"
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/AppSupport.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/AppSupport.c new file mode 100644 index 00000000..65705f75 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/AppSupport.c @@ -0,0 +1,232 @@ +/** @file + A shell application that triggers capsule update process. + + Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "CapsuleApp.h" + +UINTN Argc; +CHAR16 **Argv; +EFI_SHELL_PROTOCOL *mShellProtocol = NULL; + +/** + + This function parse application ARG. + + @return Status +**/ +EFI_STATUS +GetArg ( + VOID + ) +{ + EFI_STATUS Status; + EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters; + + Status = gBS->HandleProtocol ( + gImageHandle, + &gEfiShellParametersProtocolGuid, + (VOID**)&ShellParameters + ); + if (EFI_ERROR(Status)) { + return Status; + } + + Argc = ShellParameters->Argc; + Argv = ShellParameters->Argv; + return EFI_SUCCESS; +} + +/** + Get shell protocol. + + @return Pointer to shell protocol. +**/ +EFI_SHELL_PROTOCOL * +GetShellProtocol ( + VOID + ) +{ + EFI_STATUS Status; + + if (mShellProtocol == NULL) { + Status = gBS->LocateProtocol ( + &gEfiShellProtocolGuid, + NULL, + (VOID **) &mShellProtocol + ); + if (EFI_ERROR (Status)) { + mShellProtocol = NULL; + } + } + + return mShellProtocol; +} + +/** + Read a file. + + @param[in] FileName The file to be read. + @param[out] BufferSize The file buffer size + @param[out] Buffer The file buffer + + @retval EFI_SUCCESS Read file successfully + @retval EFI_NOT_FOUND Shell protocol or file not found + @retval others Read file failed +**/ +EFI_STATUS +ReadFileToBuffer ( + IN CHAR16 *FileName, + OUT UINTN *BufferSize, + OUT VOID **Buffer + ) +{ + EFI_STATUS Status; + EFI_SHELL_PROTOCOL *ShellProtocol; + SHELL_FILE_HANDLE Handle; + UINT64 FileSize; + UINTN TempBufferSize; + VOID *TempBuffer; + + ShellProtocol = GetShellProtocol(); + if (ShellProtocol == NULL) { + return EFI_NOT_FOUND; + } + + // + // Open file by FileName. + // + Status = ShellProtocol->OpenFileByName ( + FileName, + &Handle, + EFI_FILE_MODE_READ + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the file size. + // + Status = ShellProtocol->GetFileSize (Handle, &FileSize); + if (EFI_ERROR (Status)) { + ShellProtocol->CloseFile (Handle); + return Status; + } + + TempBufferSize = (UINTN) FileSize; + TempBuffer = AllocateZeroPool (TempBufferSize); + if (TempBuffer == NULL) { + ShellProtocol->CloseFile (Handle); + return EFI_OUT_OF_RESOURCES; + } + + // + // Read the file data to the buffer + // + Status = ShellProtocol->ReadFile ( + Handle, + &TempBufferSize, + TempBuffer + ); + if (EFI_ERROR (Status)) { + ShellProtocol->CloseFile (Handle); + return Status; + } + + ShellProtocol->CloseFile (Handle); + + *BufferSize = TempBufferSize; + *Buffer = TempBuffer; + return EFI_SUCCESS; +} + +/** + Write a file. + + @param[in] FileName The file to be written. + @param[in] BufferSize The file buffer size + @param[in] Buffer The file buffer + + @retval EFI_SUCCESS Write file successfully + @retval EFI_NOT_FOUND Shell protocol not found + @retval others Write file failed +**/ +EFI_STATUS +WriteFileFromBuffer ( + IN CHAR16 *FileName, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + EFI_SHELL_PROTOCOL *ShellProtocol; + SHELL_FILE_HANDLE Handle; + EFI_FILE_INFO *FileInfo; + UINTN TempBufferSize; + + ShellProtocol = GetShellProtocol(); + if (ShellProtocol == NULL) { + return EFI_NOT_FOUND; + } + + // + // Open file by FileName. + // + Status = ShellProtocol->OpenFileByName ( + FileName, + &Handle, + EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Empty the file contents. + // + FileInfo = ShellProtocol->GetFileInfo (Handle); + if (FileInfo == NULL) { + ShellProtocol->CloseFile (Handle); + return EFI_DEVICE_ERROR; + } + + // + // If the file size is already 0, then it has been empty. + // + if (FileInfo->FileSize != 0) { + // + // Set the file size to 0. + // + FileInfo->FileSize = 0; + Status = ShellProtocol->SetFileInfo (Handle, FileInfo); + if (EFI_ERROR (Status)) { + FreePool (FileInfo); + ShellProtocol->CloseFile (Handle); + return Status; + } + } + FreePool (FileInfo); + + // + // Write the file data from the buffer + // + TempBufferSize = BufferSize; + Status = ShellProtocol->WriteFile ( + Handle, + &TempBufferSize, + Buffer + ); + if (EFI_ERROR (Status)) { + ShellProtocol->CloseFile (Handle); + return Status; + } + + ShellProtocol->CloseFile (Handle); + + return EFI_SUCCESS; +} + diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c new file mode 100644 index 00000000..57bb3f2b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c @@ -0,0 +1,1015 @@ +/** @file + A shell application that triggers capsule update process. + + Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "CapsuleApp.h" + +// +// Define how many block descriptors we want to test with. +// +UINTN NumberOfDescriptors = 1; +UINTN CapsuleFirstIndex; +UINTN CapsuleLastIndex; + +/** + Create UX capsule. + + @retval EFI_SUCCESS The capsule header is appended. + @retval EFI_UNSUPPORTED Input parameter is not valid. + @retval EFI_OUT_OF_RESOURCES No enough resource to create UX capsule. +**/ +EFI_STATUS +CreateBmpFmp ( + VOID + ) +{ + CHAR16 *OutputCapsuleName; + VOID *BmpBuffer; + UINTN FileSize; + CHAR16 *BmpName; + UINT8 *FullCapsuleBuffer; + UINTN FullCapsuleBufferSize; + EFI_DISPLAY_CAPSULE *DisplayCapsule; + EFI_STATUS Status; + EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GopBlt; + UINTN GopBltSize; + UINTN Height; + UINTN Width; + + Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&Gop); + if (EFI_ERROR(Status)) { + Print(L"CapsuleApp: NO GOP is found.\n"); + return EFI_UNSUPPORTED; + } + Info = Gop->Mode->Info; + Print(L"Current GOP: Mode - %d, ", Gop->Mode->Mode); + Print(L"HorizontalResolution - %d, ", Info->HorizontalResolution); + Print(L"VerticalResolution - %d\n", Info->VerticalResolution); + // HorizontalResolution >= BMP_IMAGE_HEADER.PixelWidth + // VerticalResolution >= BMP_IMAGE_HEADER.PixelHeight + + if (Argc != 5) { + Print(L"CapsuleApp: Incorrect parameter count.\n"); + return EFI_UNSUPPORTED; + } + + if (StrCmp(Argv[3], L"-O") != 0) { + Print(L"CapsuleApp: NO output capsule name.\n"); + return EFI_UNSUPPORTED; + } + OutputCapsuleName = Argv[4]; + + BmpBuffer = NULL; + FileSize = 0; + FullCapsuleBuffer = NULL; + + BmpName = Argv[2]; + Status = ReadFileToBuffer(BmpName, &FileSize, &BmpBuffer); + if (EFI_ERROR(Status)) { + Print(L"CapsuleApp: BMP image (%s) is not found.\n", BmpName); + goto Done; + } + + GopBlt = NULL; + Status = TranslateBmpToGopBlt ( + BmpBuffer, + FileSize, + &GopBlt, + &GopBltSize, + &Height, + &Width + ); + if (EFI_ERROR(Status)) { + Print(L"CapsuleApp: BMP image (%s) is not valid.\n", BmpName); + goto Done; + } + if (GopBlt != NULL) { + FreePool (GopBlt); + } + Print(L"BMP image (%s), Width - %d, Height - %d\n", BmpName, Width, Height); + + if (Height > Info->VerticalResolution) { + Status = EFI_INVALID_PARAMETER; + Print(L"CapsuleApp: BMP image (%s) height is larger than current resolution.\n", BmpName); + goto Done; + } + if (Width > Info->HorizontalResolution) { + Status = EFI_INVALID_PARAMETER; + Print(L"CapsuleApp: BMP image (%s) width is larger than current resolution.\n", BmpName); + goto Done; + } + + FullCapsuleBufferSize = sizeof(EFI_DISPLAY_CAPSULE) + FileSize; + FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize); + if (FullCapsuleBuffer == NULL) { + Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize); + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + DisplayCapsule = (EFI_DISPLAY_CAPSULE *)FullCapsuleBuffer; + CopyGuid(&DisplayCapsule->CapsuleHeader.CapsuleGuid, &gWindowsUxCapsuleGuid); + DisplayCapsule->CapsuleHeader.HeaderSize = sizeof(DisplayCapsule->CapsuleHeader); + DisplayCapsule->CapsuleHeader.Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET; + DisplayCapsule->CapsuleHeader.CapsuleImageSize = (UINT32)FullCapsuleBufferSize; + + DisplayCapsule->ImagePayload.Version = 1; + DisplayCapsule->ImagePayload.Checksum = 0; + DisplayCapsule->ImagePayload.ImageType = 0; // BMP + DisplayCapsule->ImagePayload.Reserved = 0; + DisplayCapsule->ImagePayload.Mode = Gop->Mode->Mode; + + // + // Center the bitmap horizontally + // + DisplayCapsule->ImagePayload.OffsetX = (UINT32)((Info->HorizontalResolution - Width) / 2); + + // + // Put bitmap 3/4 down the display. If bitmap is too tall, then align bottom + // of bitmap at bottom of display. + // + DisplayCapsule->ImagePayload.OffsetY = + MIN ( + (UINT32)(Info->VerticalResolution - Height), + (UINT32)(((3 * Info->VerticalResolution) - (2 * Height)) / 4) + ); + + Print(L"BMP image (%s), OffsetX - %d, OffsetY - %d\n", + BmpName, + DisplayCapsule->ImagePayload.OffsetX, + DisplayCapsule->ImagePayload.OffsetY + ); + + CopyMem((DisplayCapsule + 1), BmpBuffer, FileSize); + + DisplayCapsule->ImagePayload.Checksum = CalculateCheckSum8(FullCapsuleBuffer, FullCapsuleBufferSize); + + Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer); + Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status); + +Done: + if (BmpBuffer != NULL) { + FreePool(BmpBuffer); + } + + if (FullCapsuleBuffer != NULL) { + FreePool(FullCapsuleBuffer); + } + + return Status; +} + +/** + Get ImageTypeId in the FMP capsule header. + + @param[in] CapsuleHeader The FMP capsule image header. + + @return ImageTypeId +**/ +EFI_GUID * +GetCapsuleImageTypeId ( + IN EFI_CAPSULE_HEADER *CapsuleHeader + ) +{ + EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader; + UINT64 *ItemOffsetList; + EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader; + + FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize); + ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1); + if (FmpCapsuleHeader->PayloadItemCount == 0) { + return NULL; + } + ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[FmpCapsuleHeader->EmbeddedDriverCount]); + return &ImageHeader->UpdateImageTypeId; +} + +/** + Get ESRT FwType according to ImageTypeId + + @param[in] ImageTypeId ImageTypeId of an FMP capsule. + + @return ESRT FwType +**/ +UINT32 +GetEsrtFwType ( + IN EFI_GUID *ImageTypeId + ) +{ + EFI_STATUS Status; + EFI_SYSTEM_RESOURCE_TABLE *Esrt; + EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry; + UINTN Index; + + // + // Check ESRT + // + Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID **)&Esrt); + if (!EFI_ERROR(Status)) { + ASSERT(Esrt != NULL); + EsrtEntry = (VOID *)(Esrt + 1); + for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) { + if (CompareGuid(&EsrtEntry->FwClass, ImageTypeId)) { + return EsrtEntry->FwType; + } + } + } + + return ESRT_FW_TYPE_UNKNOWN; +} + +/** + Validate if it is valid capsule header + + This function assumes the caller provided correct CapsuleHeader pointer + and CapsuleSize. + + This function validates the fields in EFI_CAPSULE_HEADER. + + @param[in] CapsuleHeader Points to a capsule header. + @param[in] CapsuleSize Size of the whole capsule image. + +**/ +BOOLEAN +IsValidCapsuleHeader ( + IN EFI_CAPSULE_HEADER *CapsuleHeader, + IN UINT64 CapsuleSize + ) +{ + if (CapsuleSize < sizeof (EFI_CAPSULE_HEADER)) { + return FALSE; + } + if (CapsuleHeader->CapsuleImageSize != CapsuleSize) { + return FALSE; + } + if (CapsuleHeader->HeaderSize > CapsuleHeader->CapsuleImageSize) { + return FALSE; + } + if (CapsuleHeader->HeaderSize < sizeof (EFI_CAPSULE_HEADER)) { + return FALSE; + } + + return TRUE; +} + +/** + Return if this CapsuleGuid is a FMP capsule GUID or not. + + @param[in] CapsuleGuid A pointer to EFI_GUID + + @retval TRUE It is a FMP capsule GUID. + @retval FALSE It is not a FMP capsule GUID. +**/ +BOOLEAN +IsFmpCapsuleGuid ( + IN EFI_GUID *CapsuleGuid + ) +{ + if (CompareGuid(&gEfiFmpCapsuleGuid, CapsuleGuid)) { + return TRUE; + } + + return FALSE; +} + +/** + Append a capsule header on top of current image. + This function follows Windows UEFI Firmware Update Platform document. + + @retval EFI_SUCCESS The capsule header is appended. + @retval EFI_UNSUPPORTED Input parameter is not valid. + @retval EFI_OUT_OF_RESOURCES No enough resource to append capsule header. +**/ +EFI_STATUS +CreateNestedFmp ( + VOID + ) +{ + CHAR16 *OutputCapsuleName; + VOID *CapsuleBuffer; + UINTN FileSize; + CHAR16 *CapsuleName; + UINT8 *FullCapsuleBuffer; + UINTN FullCapsuleBufferSize; + EFI_CAPSULE_HEADER *NestedCapsuleHeader; + EFI_GUID *ImageTypeId; + UINT32 FwType; + EFI_STATUS Status; + + if (Argc != 5) { + Print(L"CapsuleApp: Incorrect parameter count.\n"); + return EFI_UNSUPPORTED; + } + + if (StrCmp(Argv[3], L"-O") != 0) { + Print(L"CapsuleApp: NO output capsule name.\n"); + return EFI_UNSUPPORTED; + } + OutputCapsuleName = Argv[4]; + + CapsuleBuffer = NULL; + FileSize = 0; + FullCapsuleBuffer = NULL; + + CapsuleName = Argv[2]; + Status = ReadFileToBuffer(CapsuleName, &FileSize, &CapsuleBuffer); + if (EFI_ERROR(Status)) { + Print(L"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName); + goto Done; + } + if (!IsValidCapsuleHeader (CapsuleBuffer, FileSize)) { + Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName); + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if (!IsFmpCapsuleGuid (&((EFI_CAPSULE_HEADER *) CapsuleBuffer)->CapsuleGuid)) { + Print(L"CapsuleApp: Capsule image (%s) is not a FMP capsule.\n", CapsuleName); + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + ImageTypeId = GetCapsuleImageTypeId(CapsuleBuffer); + if (ImageTypeId == NULL) { + Print(L"CapsuleApp: Capsule ImageTypeId is not found.\n"); + Status = EFI_INVALID_PARAMETER; + goto Done; + } + FwType = GetEsrtFwType(ImageTypeId); + if ((FwType != ESRT_FW_TYPE_SYSTEMFIRMWARE) && (FwType != ESRT_FW_TYPE_DEVICEFIRMWARE)) { + Print(L"CapsuleApp: Capsule FwType is invalid.\n"); + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + FullCapsuleBufferSize = NESTED_CAPSULE_HEADER_SIZE + FileSize; + FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize); + if (FullCapsuleBuffer == NULL) { + Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize); + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)FullCapsuleBuffer; + ZeroMem(NestedCapsuleHeader, NESTED_CAPSULE_HEADER_SIZE); + CopyGuid(&NestedCapsuleHeader->CapsuleGuid, ImageTypeId); + NestedCapsuleHeader->HeaderSize = NESTED_CAPSULE_HEADER_SIZE; + NestedCapsuleHeader->Flags = (FwType == ESRT_FW_TYPE_SYSTEMFIRMWARE) ? SYSTEM_FIRMWARE_FLAG : DEVICE_FIRMWARE_FLAG; + NestedCapsuleHeader->CapsuleImageSize = (UINT32)FullCapsuleBufferSize; + + CopyMem((UINT8 *)NestedCapsuleHeader + NestedCapsuleHeader->HeaderSize, CapsuleBuffer, FileSize); + + Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer); + Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status); + +Done: + if (CapsuleBuffer != NULL) { + FreePool(CapsuleBuffer); + } + + if (FullCapsuleBuffer != NULL) { + FreePool(FullCapsuleBuffer); + } + + return Status; +} + + +/** + Clear capsule status variable. + + @retval EFI_SUCCESS The capsule status variable is cleared. +**/ +EFI_STATUS +ClearCapsuleStatusVariable ( + VOID + ) +{ + EFI_STATUS Status; + UINT32 Index; + CHAR16 CapsuleVarName[20]; + CHAR16 *TempVarName; + BOOLEAN Found; + + StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), L"Capsule"); + TempVarName = CapsuleVarName + StrLen (CapsuleVarName); + Index = 0; + + Found = FALSE; + while (TRUE) { + UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index); + + Status = gRT->SetVariable ( + CapsuleVarName, + &gEfiCapsuleReportGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, + 0, + (VOID *)NULL + ); + if (Status == EFI_NOT_FOUND) { + // + // There is no more capsule variables, quit + // + break; + } + Found = TRUE; + + Print (L"Clear %s %r\n", CapsuleVarName, Status); + + Index++; + if (Index > 0xFFFF) { + break; + } + } + + if (!Found) { + Print (L"No any Capsule#### variable found\n"); + } + + return EFI_SUCCESS; +} + +/** + Build Gather list for a list of capsule images. + + @param[in] CapsuleBuffer An array of pointer to capsule images + @param[in] FileSize An array of UINTN to capsule images size + @param[in] CapsuleNum The count of capsule images + @param[out] BlockDescriptors The block descriptors for the capsule images + + @retval EFI_SUCCESS The block descriptors for the capsule images are constructed. +**/ +EFI_STATUS +BuildGatherList ( + IN VOID **CapsuleBuffer, + IN UINTN *FileSize, + IN UINTN CapsuleNum, + OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors + ) +{ + EFI_STATUS Status; + EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors1; + EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors2; + EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorPre; + EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorsHeader; + EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr; + UINT8 *TempDataPtr; + UINTN SizeLeft; + UINTN Size; + INT32 Count; + INT32 Number; + UINTN Index; + + TempBlockPtr = NULL; + BlockDescriptors1 = NULL; + BlockDescriptors2 = NULL; + BlockDescriptorPre = NULL; + BlockDescriptorsHeader = NULL; + + for (Index = 0; Index < CapsuleNum; Index++) { + // + // Allocate memory for the descriptors. + // + if (NumberOfDescriptors == 1) { + Count = 2; + } else { + Count = (INT32)(NumberOfDescriptors + 2) / 2; + } + + Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR); + BlockDescriptors1 = AllocateRuntimeZeroPool (Size); + if (BlockDescriptors1 == NULL) { + Print (L"CapsuleApp: failed to allocate memory for descriptors\n"); + Status = EFI_OUT_OF_RESOURCES; + goto ERREXIT; + } else { + Print (L"CapsuleApp: creating capsule descriptors at 0x%X\n", (UINTN) BlockDescriptors1); + Print (L"CapsuleApp: capsule data starts at 0x%X with size 0x%X\n", (UINTN) CapsuleBuffer[Index], FileSize[Index]); + } + + // + // Record descriptor header + // + if (Index == 0) { + BlockDescriptorsHeader = BlockDescriptors1; + } + + if (BlockDescriptorPre != NULL) { + BlockDescriptorPre->Union.ContinuationPointer = (UINTN) BlockDescriptors1; + BlockDescriptorPre->Length = 0; + } + + // + // Fill them in + // + TempBlockPtr = BlockDescriptors1; + TempDataPtr = CapsuleBuffer[Index]; + SizeLeft = FileSize[Index]; + for (Number = 0; (Number < Count - 1) && (SizeLeft != 0); Number++) { + // + // Divide remaining data in half + // + if (NumberOfDescriptors != 1) { + if (SizeLeft == 1) { + Size = 1; + } else { + Size = SizeLeft / 2; + } + } else { + Size = SizeLeft; + } + TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr; + TempBlockPtr->Length = Size; + Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN) TempDataPtr, Size); + SizeLeft -= Size; + TempDataPtr += Size; + TempBlockPtr++; + } + + // + // Allocate the second list, point the first block's last entry to point + // to this one, and fill this one in. Worst case is that the previous + // list only had one element that pointed here, so we need at least two + // elements -- one to point to all the data, another to terminate the list. + // + if ((NumberOfDescriptors != 1) && (SizeLeft != 0)) { + Count = (INT32)(NumberOfDescriptors + 2) - Count; + if (Count == 1) { + Count++; + } + + Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR); + BlockDescriptors2 = AllocateRuntimeZeroPool (Size); + if (BlockDescriptors2 == NULL) { + Print (L"CapsuleApp: failed to allocate memory for descriptors\n"); + Status = EFI_OUT_OF_RESOURCES; + goto ERREXIT; + } + + // + // Point the first list's last element to point to this second list. + // + TempBlockPtr->Union.ContinuationPointer = (UINTN) BlockDescriptors2; + + TempBlockPtr->Length = 0; + TempBlockPtr = BlockDescriptors2; + for (Number = 0; Number < Count - 1; Number++) { + // + // If second-to-last one, then dump rest to this element + // + if (Number == (Count - 2)) { + Size = SizeLeft; + } else { + // + // Divide remaining data in half + // + if (SizeLeft == 1) { + Size = 1; + } else { + Size = SizeLeft / 2; + } + } + + TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr; + TempBlockPtr->Length = Size; + Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN) TempDataPtr, Size); + SizeLeft -= Size; + TempDataPtr += Size; + TempBlockPtr++; + if (SizeLeft == 0) { + break; + } + } + } + + BlockDescriptorPre = TempBlockPtr; + BlockDescriptors1 = NULL; + } + + // + // Null-terminate. + // + if (TempBlockPtr != NULL) { + TempBlockPtr->Union.ContinuationPointer = (UINTN)NULL; + TempBlockPtr->Length = 0; + *BlockDescriptors = BlockDescriptorsHeader; + } + + return EFI_SUCCESS; + +ERREXIT: + if (BlockDescriptors1 != NULL) { + FreePool(BlockDescriptors1); + } + + if (BlockDescriptors2 != NULL) { + FreePool(BlockDescriptors2); + } + + return Status; +} + +/** + Clear the Gather list for a list of capsule images. + + @param[in] BlockDescriptors The block descriptors for the capsule images + @param[in] CapsuleNum The count of capsule images +**/ +VOID +CleanGatherList ( + IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors, + IN UINTN CapsuleNum + ) +{ + EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr; + EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr1; + EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr2; + UINTN Index; + + if (BlockDescriptors != NULL) { + TempBlockPtr1 = BlockDescriptors; + while (1){ + TempBlockPtr = TempBlockPtr1; + for (Index = 0; Index < CapsuleNum; Index++) { + if (TempBlockPtr[Index].Length == 0) { + break; + } + } + + if (TempBlockPtr[Index].Union.ContinuationPointer == (UINTN)NULL) { + break; + } + + TempBlockPtr2 = (VOID *) ((UINTN) TempBlockPtr[Index].Union.ContinuationPointer); + FreePool(TempBlockPtr1); + TempBlockPtr1 = TempBlockPtr2; + } + } +} + +/** + Print APP usage. +**/ +VOID +PrintUsage ( + VOID + ) +{ + Print(L"CapsuleApp: usage\n"); + Print(L" CapsuleApp <Capsule...> [-NR] [-OD [FSx]]\n"); + Print(L" CapsuleApp -S\n"); + Print(L" CapsuleApp -C\n"); + Print(L" CapsuleApp -P\n"); + Print(L" CapsuleApp -E\n"); + Print(L" CapsuleApp -L\n"); + Print(L" CapsuleApp -L INFO\n"); + Print(L" CapsuleApp -F\n"); + Print(L" CapsuleApp -G <BMP> -O <Capsule>\n"); + Print(L" CapsuleApp -N <Capsule> -O <NestedCapsule>\n"); + Print(L" CapsuleApp -D <Capsule>\n"); + Print(L" CapsuleApp -P GET <ImageTypeId> <Index> -O <FileName>\n"); + Print(L"Parameter:\n"); + Print(L" -NR: No reset will be triggered for the capsule\n"); + Print(L" with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET.\n"); + Print(L" -OD: Delivery of Capsules via file on Mass Storage device.\n"); + Print(L" -S: Dump capsule report variable (EFI_CAPSULE_REPORT_GUID),\n"); + Print(L" which is defined in UEFI specification.\n"); + Print(L" -C: Clear capsule report variable (EFI_CAPSULE_REPORT_GUID),\n"); + Print(L" which is defined in UEFI specification.\n"); + Print(L" -P: Dump UEFI FMP protocol info, or get image with specified\n"); + Print(L" ImageTypeId and Index (decimal format) to a file if 'GET'\n"); + Print(L" option is used.\n"); + Print(L" -E: Dump UEFI ESRT table info.\n"); + Print(L" -L: Dump provisioned capsule image information.\n"); + Print(L" -F: Dump all EFI System Partition.\n"); + Print(L" -G: Convert a BMP file to be an UX capsule,\n"); + Print(L" according to Windows Firmware Update document\n"); + Print(L" -N: Append a Capsule Header to an existing FMP capsule image\n"); + Print(L" with its ImageTypeId supported by the system,\n"); + Print(L" according to Windows Firmware Update document\n"); + Print(L" -O: Output new Capsule file name\n"); + Print(L" -D: Dump Capsule image header information, image payload\n"); + Print(L" information if it is an UX capsule and FMP header\n"); + Print(L" information if it is a FMP capsule.\n"); +} + +/** + Update Capsule image. + + @param[in] ImageHandle The image handle. + @param[in] SystemTable The system table. + + @retval EFI_SUCCESS Command completed successfully. + @retval EFI_UNSUPPORTED Command usage unsupported. + @retval EFI_INVALID_PARAMETER Command usage invalid. + @retval EFI_NOT_FOUND The input file can't be found. +**/ +EFI_STATUS +EFIAPI +UefiMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + RETURN_STATUS RStatus; + UINTN CapsuleBufferSize[MAX_CAPSULE_NUM]; + VOID *CapsuleBuffer[MAX_CAPSULE_NUM]; + EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors; + EFI_CAPSULE_HEADER *CapsuleHeaderArray[MAX_CAPSULE_NUM + 1]; + UINT64 MaxCapsuleSize; + EFI_RESET_TYPE ResetType; + BOOLEAN NeedReset; + BOOLEAN NoReset; + BOOLEAN CapsuleOnDisk; + CHAR16 *CapsuleName; + CHAR16 *CapsuleNames[MAX_CAPSULE_NUM]; + CHAR16 *MapFsStr; + UINTN CapsuleNum; + UINTN Index; + UINTN ParaOdIndex; + UINTN ParaNrIndex; + EFI_GUID ImageTypeId; + UINTN ImageIndex; + + BlockDescriptors = NULL; + MapFsStr = NULL; + CapsuleNum = 0; + + Status = GetArg(); + if (EFI_ERROR(Status)) { + Print(L"Please use UEFI SHELL to run this application!\n", Status); + return Status; + } + if (Argc < 2) { + PrintUsage(); + return EFI_UNSUPPORTED; + } + if (StrCmp(Argv[1], L"-D") == 0) { + if (Argc != 3) { + Print(L"CapsuleApp: Incorrect parameter count.\n"); + return EFI_UNSUPPORTED; + } + Status = DumpCapsule(Argv[2]); + return Status; + } + if (StrCmp(Argv[1], L"-G") == 0) { + Status = CreateBmpFmp(); + return Status; + } + if (StrCmp(Argv[1], L"-N") == 0) { + Status = CreateNestedFmp(); + return Status; + } + if (StrCmp(Argv[1], L"-S") == 0) { + Status = DumpCapsuleStatusVariable(); + return EFI_SUCCESS; + } + if (StrCmp(Argv[1], L"-C") == 0) { + Status = ClearCapsuleStatusVariable(); + return Status; + } + if (StrCmp(Argv[1], L"-P") == 0) { + if (Argc == 2) { + DumpFmpData(); + } + if (Argc >= 3) { + if (StrCmp(Argv[2], L"GET") != 0) { + Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[2]); + return EFI_UNSUPPORTED; + } else { + if (Argc != 7) { + Print(L"CapsuleApp: Incorrect parameter count.\n"); + return EFI_UNSUPPORTED; + } + + // + // FMP->GetImage() + // + RStatus = StrToGuid (Argv[3], &ImageTypeId); + if (RETURN_ERROR (RStatus) || (Argv[3][GUID_STRING_LENGTH] != L'\0')) { + Print (L"Invalid ImageTypeId - %s\n", Argv[3]); + return EFI_INVALID_PARAMETER; + } + ImageIndex = StrDecimalToUintn(Argv[4]); + if (StrCmp(Argv[5], L"-O") != 0) { + Print(L"CapsuleApp: NO output file name.\n"); + return EFI_UNSUPPORTED; + } + DumpFmpImage(&ImageTypeId, ImageIndex, Argv[6]); + } + } + return EFI_SUCCESS; + } + + if (StrCmp(Argv[1], L"-E") == 0) { + DumpEsrtData(); + return EFI_SUCCESS; + } + + if (StrCmp(Argv[1], L"-L") == 0) { + if (Argc >= 3 && StrCmp(Argv[2], L"INFO") == 0) { + DumpProvisionedCapsule(TRUE); + } else { + DumpProvisionedCapsule(FALSE); + } + return EFI_SUCCESS; + } + + if (StrCmp(Argv[1], L"-F") == 0) { + DumpAllEfiSysPartition(); + return EFI_SUCCESS; + } + + if (Argv[1][0] == L'-') { + Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[1]); + return EFI_UNSUPPORTED; + } + + CapsuleFirstIndex = 1; + NoReset = FALSE; + CapsuleOnDisk = FALSE; + ParaOdIndex = 0; + ParaNrIndex = 0; + + for (Index = 1; Index < Argc; Index++) { + if (StrCmp(Argv[Index], L"-OD") == 0) { + ParaOdIndex = Index; + CapsuleOnDisk = TRUE; + } else if (StrCmp(Argv[Index], L"-NR") == 0) { + ParaNrIndex = Index; + NoReset = TRUE; + } + } + + if (ParaOdIndex > ParaNrIndex) { + if (ParaNrIndex != 0) { + CapsuleLastIndex = ParaNrIndex - 1; + } else { + CapsuleLastIndex = ParaOdIndex - 1; + } + + if (ParaOdIndex == Argc -1) { + MapFsStr = NULL; + } else if (ParaOdIndex == Argc - 2) { + MapFsStr = Argv[Argc-1]; + } else { + Print (L"CapsuleApp: Cannot specify more than one FS mapping!\n"); + Status = EFI_INVALID_PARAMETER; + goto Done; + } + } else if (ParaOdIndex < ParaNrIndex) { + if (ParaOdIndex != 0) { + CapsuleLastIndex = ParaOdIndex - 1; + if (ParaOdIndex == ParaNrIndex - 1) { + MapFsStr = NULL; + } else if (ParaOdIndex == ParaNrIndex - 2) { + MapFsStr = Argv[ParaOdIndex + 1]; + } else { + Print (L"CapsuleApp: Cannot specify more than one FS mapping!\n"); + Status = EFI_INVALID_PARAMETER; + goto Done; + } + } else { + CapsuleLastIndex = ParaNrIndex - 1; + } + } else { + CapsuleLastIndex = Argc - 1; + } + + CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1; + + if (CapsuleFirstIndex > CapsuleLastIndex) { + Print(L"CapsuleApp: NO capsule image.\n"); + return EFI_UNSUPPORTED; + } + if (CapsuleNum > MAX_CAPSULE_NUM) { + Print(L"CapsuleApp: Too many capsule images.\n"); + return EFI_UNSUPPORTED; + } + + ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer)); + ZeroMem(&CapsuleBufferSize, sizeof(CapsuleBufferSize)); + BlockDescriptors = NULL; + + for (Index = 0; Index < CapsuleNum; Index++) { + CapsuleName = Argv[CapsuleFirstIndex + Index]; + Status = ReadFileToBuffer(CapsuleName, &CapsuleBufferSize[Index], &CapsuleBuffer[Index]); + if (EFI_ERROR(Status)) { + Print(L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName); + goto Done; + } + if (!IsValidCapsuleHeader (CapsuleBuffer[Index], CapsuleBufferSize[Index])) { + Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName); + return EFI_INVALID_PARAMETER; + } + CapsuleNames[Index] = CapsuleName; + } + + // + // Every capsule use 2 descriptor 1 for data 1 for end + // + Status = BuildGatherList(CapsuleBuffer, CapsuleBufferSize, CapsuleNum, &BlockDescriptors); + if (EFI_ERROR(Status)) { + goto Done; + } + + // + // Call the runtime service capsule. + // + NeedReset = FALSE; + for (Index = 0; Index < CapsuleNum; Index++) { + CapsuleHeaderArray[Index] = (EFI_CAPSULE_HEADER *) CapsuleBuffer[Index]; + if ((CapsuleHeaderArray[Index]->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) { + NeedReset = TRUE; + } + } + CapsuleHeaderArray[CapsuleNum] = NULL; + + // + // Inquire platform capability of UpdateCapsule. + // + Status = gRT->QueryCapsuleCapabilities (CapsuleHeaderArray, CapsuleNum, &MaxCapsuleSize, &ResetType); + if (EFI_ERROR(Status)) { + Print (L"CapsuleApp: failed to query capsule capability - %r\n", Status); + goto Done; + } + + for (Index = 0; Index < CapsuleNum; Index++) { + if (CapsuleBufferSize[Index] > MaxCapsuleSize) { + Print (L"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize); + Status = EFI_UNSUPPORTED; + goto Done; + } + } + + // + // Check whether is capsule on disk. + // + if (CapsuleOnDisk) { + Status = ProcessCapsuleOnDisk (CapsuleBuffer, CapsuleBufferSize, CapsuleNames, MapFsStr, CapsuleNum); + if (Status != EFI_SUCCESS) { + Print (L"CapsuleApp: failed to update capsule - %r\n", Status); + goto Done; + } else { + if (!NoReset) { + gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL); + } else { + goto Done; + } + } + } + + // + // Check whether the input capsule image has the flag of persist across system reset. + // + if (NeedReset) { + Status = gRT->UpdateCapsule(CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors); + if (Status != EFI_SUCCESS) { + Print (L"CapsuleApp: failed to update capsule - %r\n", Status); + goto Done; + } + // + // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET + CAPSULE_FLAGS_INITIATE_RESET, + // a system reset should have been triggered by gRT->UpdateCapsule() calling above. + // + // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET, + // check if -NR (no-reset) has been specified or not. + // + if (!NoReset) { + // + // For capsule who has reset flag and no -NR (no-reset) has been specified, after calling UpdateCapsule service, + // trigger a system reset to process capsule persist across a system reset. + // + gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL); + } + } else { + // + // For capsule who has no reset flag, only call UpdateCapsule Service without a + // system reset. The service will process the capsule immediately. + // + Status = gRT->UpdateCapsule (CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors); + if (Status != EFI_SUCCESS) { + Print (L"CapsuleApp: failed to update capsule - %r\n", Status); + } + } + + Status = EFI_SUCCESS; + +Done: + for (Index = 0; Index < CapsuleNum; Index++) { + if (CapsuleBuffer[Index] != NULL) { + FreePool (CapsuleBuffer[Index]); + } + } + + CleanGatherList(BlockDescriptors, CapsuleNum); + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleApp.h b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleApp.h new file mode 100644 index 00000000..7541f1fc --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleApp.h @@ -0,0 +1,240 @@ +/** @file + A shell application that triggers capsule update process. + + Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef _CAPSULE_APP_H_ +#define _CAPSULE_APP_H_ + +#include <Uefi.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/UefiLib.h> +#include <Library/PrintLib.h> +#include <Library/BmpSupportLib.h> +#include <Library/FileHandleLib.h> +#include <Library/SortLib.h> +#include <Library/UefiBootManagerLib.h> +#include <Library/DevicePathLib.h> +#include <Protocol/GraphicsOutput.h> +#include <Protocol/SimpleFileSystem.h> +#include <Protocol/ShellParameters.h> +#include <Protocol/Shell.h> +#include <Protocol/FirmwareManagement.h> +#include <Guid/GlobalVariable.h> +#include <Guid/CapsuleReport.h> +#include <Guid/SystemResourceTable.h> +#include <Guid/FmpCapsule.h> +#include <Guid/FileInfo.h> +#include <Guid/ImageAuthentication.h> +#include <Guid/CapsuleVendor.h> +#include <Guid/Gpt.h> +#include <IndustryStandard/WindowsUxCapsule.h> + +#define CAPSULE_HEADER_SIZE 0x20 + +#define NESTED_CAPSULE_HEADER_SIZE SIZE_4KB +#define SYSTEM_FIRMWARE_FLAG 0x50000 +#define DEVICE_FIRMWARE_FLAG 0x78010 + +#define MAJOR_VERSION 1 +#define MINOR_VERSION 0 + +#define MAX_CAPSULE_NUM 10 + +// +// (20 * (6+5+2))+1) unicode characters from EFI FAT spec (doubled for bytes) +// +#define MAX_FILE_NAME_SIZE 522 +#define MAX_FILE_NAME_LEN (MAX_FILE_NAME_SIZE / sizeof(CHAR16)) + +extern UINTN Argc; +extern CHAR16 **Argv; + +/** + + This function parse application ARG. + + @return Status +**/ +EFI_STATUS +GetArg ( + VOID + ); + +/** + Get shell protocol. + + @return Pointer to shell protocol. + +**/ +EFI_SHELL_PROTOCOL * +GetShellProtocol ( + VOID + ); + + +/** + Read a file. + + @param[in] FileName The file to be read. + @param[out] BufferSize The file buffer size + @param[out] Buffer The file buffer + + @retval EFI_SUCCESS Read file successfully + @retval EFI_NOT_FOUND Shell protocol or file not found + @retval others Read file failed +**/ +EFI_STATUS +ReadFileToBuffer ( + IN CHAR16 *FileName, + OUT UINTN *BufferSize, + OUT VOID **Buffer + ); + +/** + Write a file. + + @param[in] FileName The file to be written. + @param[in] BufferSize The file buffer size + @param[in] Buffer The file buffer + + @retval EFI_SUCCESS Write file successfully + @retval EFI_NOT_FOUND Shell protocol not found + @retval others Write file failed +**/ +EFI_STATUS +WriteFileFromBuffer ( + IN CHAR16 *FileName, + IN UINTN BufferSize, + IN VOID *Buffer + ); + + +/** + Dump capsule information + + @param[in] CapsuleName The name of the capsule image. + + @retval EFI_SUCCESS The capsule information is dumped. + @retval EFI_UNSUPPORTED Input parameter is not valid. +**/ +EFI_STATUS +DumpCapsule ( + IN CHAR16 *CapsuleName + ); + +/** + Dump capsule status variable. + + @retval EFI_SUCCESS The capsule status variable is dumped. + @retval EFI_UNSUPPORTED Input parameter is not valid. +**/ +EFI_STATUS +DumpCapsuleStatusVariable ( + VOID + ); + +/** + Dump FMP protocol info. +**/ +VOID +DumpFmpData ( + VOID + ); + +/** + Dump FMP image data. + + @param[in] ImageTypeId The ImageTypeId of the FMP image. + It is used to identify the FMP protocol. + @param[in] ImageIndex The ImageIndex of the FMP image. + It is the input parameter for FMP->GetImage(). + @param[in] ImageName The file name to hold the output FMP image. +**/ +VOID +DumpFmpImage ( + IN EFI_GUID *ImageTypeId, + IN UINTN ImageIndex, + IN CHAR16 *ImageName + ); + +/** + Dump ESRT info. +**/ +VOID +DumpEsrtData ( + VOID + ); + +/** + Dump Provisioned Capsule. + + @param[in] DumpCapsuleInfo The flag to indicate whether to dump the capsule inforomation. +**/ +VOID +DumpProvisionedCapsule ( + IN BOOLEAN DumpCapsuleInfo + ); + +/** + Dump all EFI System Partition. +**/ +VOID +DumpAllEfiSysPartition ( + VOID + ); + + +/** + Get SimpleFileSystem from boot option file path. + + @param[in] DevicePath The file path of boot option + @param[out] FullPath The full device path of boot device + @param[out] Fs The file system within EfiSysPartition + + @retval EFI_SUCCESS Get file system successfully + @retval EFI_NOT_FOUND No valid file system found + @retval others Get file system failed + +**/ +EFI_STATUS +GetEfiSysPartitionFromBootOptionFilePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, + OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs + ); + + +/** + Process Capsule On Disk. + + @param[in] CapsuleBuffer An array of pointer to capsule images + @param[in] CapsuleBufferSize An array of UINTN to capsule images size + @param[in] FilePath An array of capsule images file path + @param[in] Map File system mapping string + @param[in] CapsuleNum The count of capsule images + + @retval EFI_SUCCESS Capsule on disk success. + @retval others Capsule on disk fail. + +**/ +EFI_STATUS +ProcessCapsuleOnDisk ( + IN VOID **CapsuleBuffer, + IN UINTN *CapsuleBufferSize, + IN CHAR16 **FilePath, + IN CHAR16 *Map, + IN UINTN CapsuleNum + ); + +#endif + diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf new file mode 100644 index 00000000..e76b4fb2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf @@ -0,0 +1,69 @@ +## @file +# A shell application that triggers capsule update process. +# +# This application can trigger capsule update process. It can also +# generate capsule image, or dump capsule variable information. +# +# Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = CapsuleApp + MODULE_UNI_FILE = CapsuleApp.uni + FILE_GUID = 4CEF31DA-8682-4274-9CC4-AEE7516A5E7B + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = UefiMain + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + CapsuleApp.c + CapsuleApp.h + CapsuleDump.c + CapsuleOnDisk.c + AppSupport.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[Guids] + gEfiGlobalVariableGuid ## CONSUMES ## GUID + gEfiCapsuleReportGuid ## CONSUMES ## GUID + gEfiFmpCapsuleGuid ## CONSUMES ## GUID + gWindowsUxCapsuleGuid ## CONSUMES ## GUID + gEfiSystemResourceTableGuid ## CONSUMES ## GUID + gEfiCapsuleVendorGuid ## SOMETIMES_CONSUMES ## Variable:L"CapsuleUpdateData" + gEfiPartTypeSystemPartGuid ## SOMETIMES_CONSUMES ## GUID + +[Protocols] + gEfiGraphicsOutputProtocolGuid ## CONSUMES + gEfiFirmwareManagementProtocolGuid ## CONSUMES + gEfiShellParametersProtocolGuid ## CONSUMES + gEfiShellProtocolGuid ## CONSUMES + gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES + +[LibraryClasses] + BaseLib + UefiApplicationEntryPoint + DebugLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiLib + PrintLib + BmpSupportLib + FileHandleLib + UefiBootManagerLib + SortLib + +[UserExtensions.TianoCore."ExtraFiles"] + CapsuleAppExtra.uni diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni new file mode 100644 index 00000000..955979dc --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni @@ -0,0 +1,17 @@ +// /** @file
+// A shell application that triggers capsule update process.
+//
+// This application can trigger capsule update process. It can also
+// generate capsule image, or dump capsule variable information.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "A shell application that triggers capsule update process."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This application can trigger capsule update process. It can also generate capsule image, or dump capsule variable information."
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni new file mode 100644 index 00000000..42bd212a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni @@ -0,0 +1,14 @@ +// /** @file
+// CapsuleApp Localized Strings and Content
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Capsule Application"
+
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c new file mode 100644 index 00000000..0f8ddbb7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c @@ -0,0 +1,1444 @@ +/** @file + Dump Capsule image information. + + Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "CapsuleApp.h" + +/** + Validate if it is valid capsule header + + This function assumes the caller provided correct CapsuleHeader pointer + and CapsuleSize. + + This function validates the fields in EFI_CAPSULE_HEADER. + + @param[in] CapsuleHeader Points to a capsule header. + @param[in] CapsuleSize Size of the whole capsule image. + +**/ +BOOLEAN +IsValidCapsuleHeader ( + IN EFI_CAPSULE_HEADER *CapsuleHeader, + IN UINT64 CapsuleSize + ); + +/** + Dump UX capsule information. + + @param[in] CapsuleHeader The UX capsule header +**/ +VOID +DumpUxCapsule ( + IN EFI_CAPSULE_HEADER *CapsuleHeader + ) +{ + EFI_DISPLAY_CAPSULE *DisplayCapsule; + DisplayCapsule = (EFI_DISPLAY_CAPSULE *)CapsuleHeader; + Print(L"[UxCapsule]\n"); + Print(L"CapsuleHeader:\n"); + Print(L" CapsuleGuid - %g\n", &DisplayCapsule->CapsuleHeader.CapsuleGuid); + Print(L" HeaderSize - 0x%x\n", DisplayCapsule->CapsuleHeader.HeaderSize); + Print(L" Flags - 0x%x\n", DisplayCapsule->CapsuleHeader.Flags); + Print(L" CapsuleImageSize - 0x%x\n", DisplayCapsule->CapsuleHeader.CapsuleImageSize); + Print(L"ImagePayload:\n"); + Print(L" Version - 0x%x\n", DisplayCapsule->ImagePayload.Version); + Print(L" Checksum - 0x%x\n", DisplayCapsule->ImagePayload.Checksum); + Print(L" ImageType - 0x%x\n", DisplayCapsule->ImagePayload.ImageType); + Print(L" Mode - 0x%x\n", DisplayCapsule->ImagePayload.Mode); + Print(L" OffsetX - 0x%x\n", DisplayCapsule->ImagePayload.OffsetX); + Print(L" OffsetY - 0x%x\n", DisplayCapsule->ImagePayload.OffsetY); +} + + +/** + Dump a non-nested FMP capsule. + + @param[in] CapsuleHeader A pointer to CapsuleHeader +**/ +VOID +DumpFmpCapsule ( + IN EFI_CAPSULE_HEADER *CapsuleHeader + ) +{ + EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader; + UINT64 *ItemOffsetList; + UINTN Index; + UINTN Count; + EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *FmpImageHeader; + + Print(L"[FmpCapsule]\n"); + Print(L"CapsuleHeader:\n"); + Print(L" CapsuleGuid - %g\n", &CapsuleHeader->CapsuleGuid); + Print(L" HeaderSize - 0x%x\n", CapsuleHeader->HeaderSize); + Print(L" Flags - 0x%x\n", CapsuleHeader->Flags); + Print(L" CapsuleImageSize - 0x%x\n", CapsuleHeader->CapsuleImageSize); + + FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize); + ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1); + Print(L"FmpHeader:\n"); + Print(L" Version - 0x%x\n", FmpCapsuleHeader->Version); + Print(L" EmbeddedDriverCount - 0x%x\n", FmpCapsuleHeader->EmbeddedDriverCount); + Print(L" PayloadItemCount - 0x%x\n", FmpCapsuleHeader->PayloadItemCount); + Count = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount; + for (Index = 0; Index < Count; Index++) { + Print(L" Offset[%d] - 0x%x\n", Index, ItemOffsetList[Index]); + } + + for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < Count; Index++) { + Print(L"FmpPayload[%d] ImageHeader:\n", Index); + FmpImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]); + Print(L" Version - 0x%x\n", FmpImageHeader->Version); + Print(L" UpdateImageTypeId - %g\n", &FmpImageHeader->UpdateImageTypeId); + Print(L" UpdateImageIndex - 0x%x\n", FmpImageHeader->UpdateImageIndex); + Print(L" UpdateImageSize - 0x%x\n", FmpImageHeader->UpdateImageSize); + Print(L" UpdateVendorCodeSize - 0x%x\n", FmpImageHeader->UpdateVendorCodeSize); + if (FmpImageHeader->Version >= 2) { + Print(L" UpdateHardwareInstance - 0x%lx\n", FmpImageHeader->UpdateHardwareInstance); + if (FmpImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) { + Print(L" ImageCapsuleSupport - 0x%lx\n", FmpImageHeader->ImageCapsuleSupport); + } + } + } +} + +/** + Return if there is a FMP header below capsule header. + + @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER + + @retval TRUE There is a FMP header below capsule header. + @retval FALSE There is not a FMP header below capsule header +**/ +BOOLEAN +IsNestedFmpCapsule ( + IN EFI_CAPSULE_HEADER *CapsuleHeader + ) +{ + EFI_STATUS Status; + EFI_SYSTEM_RESOURCE_TABLE *Esrt; + EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry; + UINTN Index; + BOOLEAN EsrtGuidFound; + EFI_CAPSULE_HEADER *NestedCapsuleHeader; + UINTN NestedCapsuleSize; + + // + // Check ESRT + // + EsrtGuidFound = FALSE; + Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID **)&Esrt); + if (!EFI_ERROR(Status)) { + ASSERT (Esrt != NULL); + EsrtEntry = (VOID *)(Esrt + 1); + for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) { + if (CompareGuid(&EsrtEntry->FwClass, &CapsuleHeader->CapsuleGuid)) { + EsrtGuidFound = TRUE; + break; + } + } + } + + if (!EsrtGuidFound) { + return FALSE; + } + + // + // Check nested capsule header + // FMP GUID after ESRT one + // + NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize); + NestedCapsuleSize = (UINTN)CapsuleHeader + CapsuleHeader->CapsuleImageSize- (UINTN)NestedCapsuleHeader; + if (NestedCapsuleSize < sizeof(EFI_CAPSULE_HEADER)) { + return FALSE; + } + if (!CompareGuid(&NestedCapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)) { + return FALSE; + } + return TRUE; +} + +/** + Dump capsule information + + @param[in] CapsuleName The name of the capsule image. + + @retval EFI_SUCCESS The capsule information is dumped. + @retval EFI_UNSUPPORTED Input parameter is not valid. +**/ +EFI_STATUS +DumpCapsule ( + IN CHAR16 *CapsuleName + ) +{ + VOID *Buffer; + UINTN FileSize; + EFI_CAPSULE_HEADER *CapsuleHeader; + EFI_STATUS Status; + + Buffer = NULL; + Status = ReadFileToBuffer(CapsuleName, &FileSize, &Buffer); + if (EFI_ERROR(Status)) { + Print(L"CapsuleApp: Capsule (%s) is not found.\n", CapsuleName); + goto Done; + } + if (!IsValidCapsuleHeader (Buffer, FileSize)) { + Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName); + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + CapsuleHeader = Buffer; + if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) { + DumpUxCapsule(CapsuleHeader); + Status = EFI_SUCCESS; + goto Done; + } + + if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)) { + DumpFmpCapsule(CapsuleHeader); + } + if (IsNestedFmpCapsule(CapsuleHeader)) { + Print(L"[NestedCapsule]\n"); + Print(L"CapsuleHeader:\n"); + Print(L" CapsuleGuid - %g\n", &CapsuleHeader->CapsuleGuid); + Print(L" HeaderSize - 0x%x\n", CapsuleHeader->HeaderSize); + Print(L" Flags - 0x%x\n", CapsuleHeader->Flags); + Print(L" CapsuleImageSize - 0x%x\n", CapsuleHeader->CapsuleImageSize); + DumpFmpCapsule((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize)); + } + +Done: + if (Buffer != NULL) { + FreePool(Buffer); + } + return Status; +} + +/** + Dump capsule status variable. + + @retval EFI_SUCCESS The capsule status variable is dumped. + @retval EFI_UNSUPPORTED Input parameter is not valid. +**/ +EFI_STATUS +DumpCapsuleStatusVariable ( + VOID + ) +{ + EFI_STATUS Status; + UINT32 Index; + CHAR16 CapsuleVarName[20]; + CHAR16 *TempVarName; + EFI_CAPSULE_RESULT_VARIABLE_HEADER *CapsuleResult; + EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultFmp; + UINTN CapsuleFileNameSize; + CHAR16 CapsuleIndexData[12]; + CHAR16 *CapsuleIndex; + CHAR16 *CapsuleFileName; + CHAR16 *CapsuleTarget; + + Status = GetVariable2( + L"CapsuleMax", + &gEfiCapsuleReportGuid, + (VOID **)&CapsuleIndex, + NULL + ); + if (!EFI_ERROR(Status)) { + ASSERT (CapsuleIndex != NULL); + CopyMem(CapsuleIndexData, CapsuleIndex, 11 * sizeof(CHAR16)); + CapsuleIndexData[11] = 0; + Print(L"CapsuleMax - %s\n", CapsuleIndexData); + FreePool(CapsuleIndex); + } + Status = GetVariable2( + L"CapsuleLast", + &gEfiCapsuleReportGuid, + (VOID **)&CapsuleIndex, + NULL + ); + if (!EFI_ERROR(Status)) { + ASSERT (CapsuleIndex != NULL); + CopyMem(CapsuleIndexData, CapsuleIndex, 11 * sizeof(CHAR16)); + CapsuleIndexData[11] = 0; + Print(L"CapsuleLast - %s\n", CapsuleIndexData); + FreePool(CapsuleIndex); + } + + + StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), L"Capsule"); + TempVarName = CapsuleVarName + StrLen (CapsuleVarName); + Index = 0; + + while (TRUE) { + UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index); + + Status = GetVariable2 ( + CapsuleVarName, + &gEfiCapsuleReportGuid, + (VOID **) &CapsuleResult, + NULL + ); + if (Status == EFI_NOT_FOUND) { + break; + } else if (EFI_ERROR(Status)) { + continue; + } + ASSERT (CapsuleResult != NULL); + + // + // display capsule process status + // + if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER)) { + Print (L"CapsuleName: %s\n", CapsuleVarName); + Print (L" Capsule Guid: %g\n", &CapsuleResult->CapsuleGuid); + Print (L" Capsule ProcessedTime: %t\n", &CapsuleResult->CapsuleProcessed); + Print (L" Capsule Status: %r\n", CapsuleResult->CapsuleStatus); + } + + if (CompareGuid(&CapsuleResult->CapsuleGuid, &gEfiFmpCapsuleGuid)) { + if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + sizeof(CHAR16) * 2) { + CapsuleResultFmp = (EFI_CAPSULE_RESULT_VARIABLE_FMP *)(CapsuleResult + 1); + Print(L" Capsule FMP Version: 0x%x\n", CapsuleResultFmp->Version); + Print(L" Capsule FMP PayloadIndex: 0x%x\n", CapsuleResultFmp->PayloadIndex); + Print(L" Capsule FMP UpdateImageIndex: 0x%x\n", CapsuleResultFmp->UpdateImageIndex); + Print(L" Capsule FMP UpdateImageTypeId: %g\n", &CapsuleResultFmp->UpdateImageTypeId); + CapsuleFileName = (CHAR16 *)(CapsuleResultFmp + 1); + Print(L" Capsule FMP CapsuleFileName: \"%s\"\n", CapsuleFileName); + CapsuleFileNameSize = StrSize(CapsuleFileName); + CapsuleTarget = (CHAR16 *)((UINTN)CapsuleFileName + CapsuleFileNameSize); + Print(L" Capsule FMP CapsuleTarget: \"%s\"\n", CapsuleTarget); + } + } + + FreePool(CapsuleResult); + + Index++; + if (Index > 0xFFFF) { + break; + } + } + + return EFI_SUCCESS; +} + +CHAR8 *mFwTypeString[] = { + "Unknown", + "SystemFirmware", + "DeviceFirmware", + "UefiDriver", +}; + +CHAR8 *mLastAttemptStatusString[] = { + "Success", + "Error: Unsuccessful", + "Error: Insufficient Resources", + "Error: Incorrect Version", + "Error: Invalid Format", + "Error: Auth Error", + "Error: Power Event AC", + "Error: Power Event Battery", + "Error: Unsatisfied Dependencies", +}; + +/** + Convert FwType to a string. + + @param[in] FwType FwType in ESRT + + @return a string for FwType. +**/ +CHAR8 * +FwTypeToString ( + IN UINT32 FwType + ) +{ + if (FwType < sizeof(mFwTypeString) / sizeof(mFwTypeString[0])) { + return mFwTypeString[FwType]; + } else { + return "Invalid"; + } +} + +/** + Convert LastAttemptStatus to a string. + + @param[in] LastAttemptStatus LastAttemptStatus in FMP or ESRT + + @return a string for LastAttemptStatus. +**/ +CHAR8 * +LastAttemptStatusToString ( + IN UINT32 LastAttemptStatus + ) +{ + if (LastAttemptStatus < sizeof(mLastAttemptStatusString) / sizeof(mLastAttemptStatusString[0])) { + return mLastAttemptStatusString[LastAttemptStatus]; + } else { + return "Error: Unknown"; + } +} + +/** + Dump ESRT entry. + + @param[in] EsrtEntry ESRT entry +**/ +VOID +DumpEsrtEntry ( + IN EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry + ) +{ + Print(L" FwClass - %g\n", &EsrtEntry->FwClass); + Print(L" FwType - 0x%x (%a)\n", EsrtEntry->FwType, FwTypeToString(EsrtEntry->FwType)); + Print(L" FwVersion - 0x%x\n", EsrtEntry->FwVersion); + Print(L" LowestSupportedFwVersion - 0x%x\n", EsrtEntry->LowestSupportedFwVersion); + Print(L" CapsuleFlags - 0x%x\n", EsrtEntry->CapsuleFlags); + Print(L" LastAttemptVersion - 0x%x\n", EsrtEntry->LastAttemptVersion); + Print(L" LastAttemptStatus - 0x%x (%a)\n", EsrtEntry->LastAttemptStatus, LastAttemptStatusToString(EsrtEntry->LastAttemptStatus)); +} + +/** + Dump ESRT table. + + @param[in] Esrt ESRT table +**/ +VOID +DumpEsrt ( + IN EFI_SYSTEM_RESOURCE_TABLE *Esrt + ) +{ + UINTN Index; + EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry; + + if (Esrt == NULL) { + return ; + } + + Print(L"EFI_SYSTEM_RESOURCE_TABLE:\n"); + Print(L"FwResourceCount - 0x%x\n", Esrt->FwResourceCount); + Print(L"FwResourceCountMax - 0x%x\n", Esrt->FwResourceCountMax); + Print(L"FwResourceVersion - 0x%lx\n", Esrt->FwResourceVersion); + + EsrtEntry = (VOID *)(Esrt + 1); + for (Index = 0; Index < Esrt->FwResourceCount; Index++) { + Print(L"EFI_SYSTEM_RESOURCE_ENTRY (%d):\n", Index); + DumpEsrtEntry(EsrtEntry); + EsrtEntry++; + } +} + +/** + Dump ESRT info. +**/ +VOID +DumpEsrtData ( + VOID + ) +{ + EFI_STATUS Status; + EFI_SYSTEM_RESOURCE_TABLE *Esrt; + + Print(L"##############\n"); + Print(L"# ESRT TABLE #\n"); + Print(L"##############\n"); + + Status = EfiGetSystemConfigurationTable (&gEfiSystemResourceTableGuid, (VOID **)&Esrt); + if (EFI_ERROR(Status)) { + Print(L"ESRT - %r\n", Status); + return; + } + DumpEsrt(Esrt); + Print(L"\n"); +} + + +/** + Dump capsule information from CapsuleHeader + + @param[in] CapsuleHeader The CapsuleHeader of the capsule image. + + @retval EFI_SUCCESS The capsule information is dumped. + +**/ +EFI_STATUS +DumpCapsuleFromBuffer ( + IN EFI_CAPSULE_HEADER *CapsuleHeader + ) +{ + if (CompareGuid (&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) { + DumpUxCapsule (CapsuleHeader); + return EFI_SUCCESS; + } + + if (CompareGuid (&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)) { + DumpFmpCapsule (CapsuleHeader); + } + if (IsNestedFmpCapsule (CapsuleHeader)) { + Print (L"[NestedCapusule]\n"); + Print (L"CapsuleHeader:\n"); + Print (L" CapsuleGuid - %g\n", &CapsuleHeader->CapsuleGuid); + Print (L" HeaderSize - 0x%x\n", CapsuleHeader->HeaderSize); + Print (L" Flags - 0x%x\n", CapsuleHeader->Flags); + Print (L" CapsuleImageSize - 0x%x\n", CapsuleHeader->CapsuleImageSize); + DumpFmpCapsule ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize)); + } + + return EFI_SUCCESS; +} + +/** + This routine is called to upper case given unicode string. + + @param[in] Str String to upper case + + @retval upper cased string after process + +**/ +STATIC +CHAR16 * +UpperCaseString ( + IN CHAR16 *Str + ) +{ + CHAR16 *Cptr; + + for (Cptr = Str; *Cptr != L'\0'; Cptr++) { + if (L'a' <= *Cptr && *Cptr <= L'z') { + *Cptr = *Cptr - L'a' + L'A'; + } + } + + return Str; +} + +/** + This routine is used to return substring before period '.' or '\0' + Caller should respsonsible of substr space allocation & free + + @param[in] Str String to check + @param[out] SubStr First part of string before period or '\0' + @param[out] SubStrLen Length of first part of string + +**/ +STATIC +VOID +GetSubStringBeforePeriod ( + IN CHAR16 *Str, + OUT CHAR16 *SubStr, + OUT UINTN *SubStrLen + ) +{ + UINTN Index; + for (Index = 0; Str[Index] != L'.' && Str[Index] != L'\0'; Index++) { + SubStr[Index] = Str[Index]; + } + + SubStr[Index] = L'\0'; + *SubStrLen = Index; +} + +/** + This routine pad the string in tail with input character. + + @param[in] StrBuf Str buffer to be padded, should be enough room for + @param[in] PadLen Expected padding length + @param[in] Character Character used to pad + +**/ +STATIC +VOID +PadStrInTail ( + IN CHAR16 *StrBuf, + IN UINTN PadLen, + IN CHAR16 Character + ) +{ + UINTN Index; + + for (Index = 0; StrBuf[Index] != L'\0'; Index++); + + while(PadLen != 0) { + StrBuf[Index] = Character; + Index++; + PadLen--; + } + + StrBuf[Index] = L'\0'; +} + +/** + This routine find the offset of the last period '.' of string. if No period exists + function FileNameExtension is set to L'\0' + + @param[in] FileName File name to split between last period + @param[out] FileNameFirst First FileName before last period + @param[out] FileNameExtension FileName after last period + +**/ +STATIC +VOID +SplitFileNameExtension ( + IN CHAR16 *FileName, + OUT CHAR16 *FileNameFirst, + OUT CHAR16 *FileNameExtension + ) +{ + UINTN Index; + UINTN StringLen; + + StringLen = StrLen(FileName); + for (Index = StringLen; Index > 0 && FileName[Index] != L'.'; Index--); + + // + // No period exists. No FileName Extension + // + if (Index == 0 && FileName[Index] != L'.') { + FileNameExtension[0] = L'\0'; + Index = StringLen; + } else { + StrCpyS (FileNameExtension, MAX_FILE_NAME_LEN, &FileName[Index+1]); + } + + // + // Copy First file name + // + StrnCpyS (FileNameFirst, MAX_FILE_NAME_LEN, FileName, Index); + FileNameFirst[Index] = L'\0'; +} + +/** + The function is called by PerformQuickSort to sort file name in alphabet. + + @param[in] Left The pointer to first buffer. + @param[in] Right The pointer to second buffer. + + @retval 0 Buffer1 equal to Buffer2. + @return <0 Buffer1 is less than Buffer2. + @return >0 Buffer1 is greater than Buffer2. + +**/ +INTN +CompareFileNameInAlphabet ( + IN VOID *Left, + IN VOID *Right + ) +{ + EFI_FILE_INFO *FileInfo1; + EFI_FILE_INFO *FileInfo2; + CHAR16 FileName1[MAX_FILE_NAME_SIZE]; + CHAR16 FileExtension1[MAX_FILE_NAME_SIZE]; + CHAR16 FileName2[MAX_FILE_NAME_SIZE]; + CHAR16 FileExtension2[MAX_FILE_NAME_SIZE]; + CHAR16 TempSubStr1[MAX_FILE_NAME_SIZE]; + CHAR16 TempSubStr2[MAX_FILE_NAME_SIZE]; + UINTN SubStrLen1; + UINTN SubStrLen2; + INTN SubStrCmpResult; + + FileInfo1 = (EFI_FILE_INFO *) (*(UINTN *)Left); + FileInfo2 = (EFI_FILE_INFO *) (*(UINTN *)Right); + + SplitFileNameExtension (FileInfo1->FileName, FileName1, FileExtension1); + SplitFileNameExtension (FileInfo2->FileName, FileName2, FileExtension2); + + UpperCaseString (FileName1); + UpperCaseString (FileName2); + + GetSubStringBeforePeriod (FileName1, TempSubStr1, &SubStrLen1); + GetSubStringBeforePeriod (FileName2, TempSubStr2, &SubStrLen2); + + if (SubStrLen1 > SubStrLen2) { + // + // Substr in NewFileName is longer. Pad tail with SPACE + // + PadStrInTail (TempSubStr2, SubStrLen1 - SubStrLen2, L' '); + } else if (SubStrLen1 < SubStrLen2){ + // + // Substr in ListedFileName is longer. Pad tail with SPACE + // + PadStrInTail (TempSubStr1, SubStrLen2 - SubStrLen1, L' '); + } + + SubStrCmpResult = StrnCmp (TempSubStr1, TempSubStr2, MAX_FILE_NAME_LEN); + if (SubStrCmpResult != 0) { + return SubStrCmpResult; + } + + UpperCaseString (FileExtension1); + UpperCaseString (FileExtension2); + + return StrnCmp (FileExtension1, FileExtension2, MAX_FILE_NAME_LEN); +} + +/** + Dump capsule information from disk. + + @param[in] Fs The device path of disk. + @param[in] DumpCapsuleInfo The flag to indicate whether to dump the capsule inforomation. + + @retval EFI_SUCCESS The capsule information is dumped. + +**/ +EFI_STATUS +DumpCapsuleFromDisk ( + IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs, + IN BOOLEAN DumpCapsuleInfo + ) +{ + EFI_STATUS Status; + EFI_FILE *Root; + EFI_FILE *DirHandle; + EFI_FILE *FileHandle; + UINTN Index; + UINTN FileSize; + VOID *FileBuffer; + EFI_FILE_INFO **FileInfoBuffer; + EFI_FILE_INFO *FileInfo; + UINTN FileCount; + BOOLEAN NoFile; + + DirHandle = NULL; + FileHandle = NULL; + Index = 0; + FileInfoBuffer = NULL; + FileInfo = NULL; + FileCount = 0; + NoFile = FALSE; + + Status = Fs->OpenVolume (Fs, &Root); + if (EFI_ERROR (Status)) { + Print (L"Cannot open volume. Status = %r\n", Status); + goto Done; + } + + Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE , 0); + if (EFI_ERROR (Status)) { + Print (L"Cannot open %s. Status = %r\n", EFI_CAPSULE_FILE_DIRECTORY, Status); + goto Done; + } + + // + // Get file count first + // + Status = FileHandleFindFirstFile (DirHandle, &FileInfo); + do { + if (EFI_ERROR (Status) || FileInfo == NULL) { + Print (L"Get File Info Fail. Status = %r\n", Status); + goto Done; + } + + if ((FileInfo->Attribute & (EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE)) != 0) { + FileCount++; + } + + Status = FileHandleFindNextFile (DirHandle, FileInfo, &NoFile); + if (EFI_ERROR (Status)) { + Print (L"Get Next File Fail. Status = %r\n", Status); + goto Done; + } + } while (!NoFile); + + if (FileCount == 0) { + Print (L"Error: No capsule file found!\n"); + Status = EFI_NOT_FOUND; + goto Done; + } + + FileInfoBuffer = AllocateZeroPool (sizeof (FileInfo) * FileCount); + if (FileInfoBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + NoFile = FALSE; + + // + // Get all file info + // + Status = FileHandleFindFirstFile (DirHandle, &FileInfo); + do { + if (EFI_ERROR (Status) || FileInfo == NULL) { + Print (L"Get File Info Fail. Status = %r\n", Status); + goto Done; + } + + if ((FileInfo->Attribute & (EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE)) != 0) { + FileInfoBuffer[Index++] = AllocateCopyPool ((UINTN)FileInfo->Size, FileInfo); + } + + Status = FileHandleFindNextFile (DirHandle, FileInfo, &NoFile); + if (EFI_ERROR (Status)) { + Print (L"Get Next File Fail. Status = %r\n", Status); + goto Done; + } + } while (!NoFile); + + // + // Sort FileInfoBuffer by alphabet order + // + PerformQuickSort ( + FileInfoBuffer, + FileCount, + sizeof (FileInfo), + (SORT_COMPARE) CompareFileNameInAlphabet + ); + + Print (L"The capsules will be performed by following order:\n"); + + for (Index = 0; Index < FileCount; Index++) { + Print (L" %d.%s\n", Index + 1, FileInfoBuffer[Index]->FileName); + } + + if (!DumpCapsuleInfo) { + Status = EFI_SUCCESS; + goto Done; + } + + Print(L"The infomation of the capsules:\n"); + + for (Index = 0; Index < FileCount; Index++) { + FileHandle = NULL; + Status = DirHandle->Open (DirHandle, &FileHandle, FileInfoBuffer[Index]->FileName, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = FileHandleGetSize (FileHandle, (UINT64 *) &FileSize); + if (EFI_ERROR (Status)) { + Print (L"Cannot read file %s. Status = %r\n", FileInfoBuffer[Index]->FileName, Status); + FileHandleClose (FileHandle); + goto Done; + } + + FileBuffer = AllocatePool (FileSize); + if (FileBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + Status = FileHandleRead (FileHandle, &FileSize, FileBuffer); + if (EFI_ERROR (Status)) { + Print (L"Cannot read file %s. Status = %r\n", FileInfoBuffer[Index]->FileName, Status); + FileHandleClose (FileHandle); + FreePool (FileBuffer); + goto Done; + } + + Print (L"**************************\n"); + Print (L" %d.%s:\n", Index + 1, FileInfoBuffer[Index]->FileName); + Print (L"**************************\n"); + DumpCapsuleFromBuffer ((EFI_CAPSULE_HEADER *) FileBuffer); + FileHandleClose (FileHandle); + FreePool (FileBuffer); + } + +Done: + if (FileInfoBuffer != NULL) { + for (Index = 0; Index < FileCount; Index++) { + if (FileInfoBuffer[Index] != NULL) { + FreePool (FileInfoBuffer[Index]); + } + } + FreePool (FileInfoBuffer); + } + + return Status; +} + +/** + Dump capsule inforomation form Gather list. + + @param[in] BlockDescriptors The block descriptors for the capsule images + @param[in] DumpCapsuleInfo The flag to indicate whether to dump the capsule inforomation. + +**/ +VOID +DumpBlockDescriptors ( + IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors, + IN BOOLEAN DumpCapsuleInfo + ) +{ + EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr; + + TempBlockPtr = BlockDescriptors; + + while (TRUE) { + if (TempBlockPtr->Length != 0) { + if (DumpCapsuleInfo) { + Print(L"******************************************************\n"); + } + Print(L"Capsule data starts at 0x%08x with size 0x%08x\n", TempBlockPtr->Union.DataBlock, TempBlockPtr->Length); + if (DumpCapsuleInfo) { + Print(L"******************************************************\n"); + DumpCapsuleFromBuffer ((EFI_CAPSULE_HEADER *) (UINTN) TempBlockPtr->Union.DataBlock); + } + TempBlockPtr += 1; + } else { + if (TempBlockPtr->Union.ContinuationPointer == (UINTN)NULL) { + break; + } else { + TempBlockPtr = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockPtr->Union.ContinuationPointer; + } + } + } +} + +/** + Dump Provisioned Capsule. + + @param[in] DumpCapsuleInfo The flag to indicate whether to dump the capsule inforomation. + +**/ +VOID +DumpProvisionedCapsule ( + IN BOOLEAN DumpCapsuleInfo + ) +{ + EFI_STATUS Status; + CHAR16 CapsuleVarName[30]; + CHAR16 *TempVarName; + UINTN Index; + EFI_PHYSICAL_ADDRESS *CapsuleDataPtr64; + UINT16 *BootNext; + CHAR16 BootOptionName[20]; + EFI_BOOT_MANAGER_LOAD_OPTION BootNextOptionEntry; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs; + EFI_SHELL_PROTOCOL *ShellProtocol; + + Index = 0; + CapsuleDataPtr64 = NULL; + BootNext = NULL; + + ShellProtocol = GetShellProtocol (); + if (ShellProtocol == NULL) { + Print (L"Get Shell Protocol Fail\n"); + return ; + } + + // + // Dump capsule provisioned on Memory + // + Print (L"#########################\n"); + Print (L"### Capsule on Memory ###\n"); + Print (L"#########################\n"); + StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CHAR16), EFI_CAPSULE_VARIABLE_NAME); + TempVarName = CapsuleVarName + StrLen (CapsuleVarName); + while (TRUE) { + if (Index > 0) { + UnicodeValueToStringS ( + TempVarName, + sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName), + 0, + Index, + 0 + ); + } + + Status = GetVariable2 ( + CapsuleVarName, + &gEfiCapsuleVendorGuid, + (VOID **) &CapsuleDataPtr64, + NULL + ); + if (EFI_ERROR (Status) || CapsuleDataPtr64 == NULL) { + if (Index == 0) { + Print (L"No data.\n"); + } + break; + } + + Index++; + Print (L"Capsule Description at 0x%08x\n", *CapsuleDataPtr64); + DumpBlockDescriptors ((EFI_CAPSULE_BLOCK_DESCRIPTOR*) (UINTN) *CapsuleDataPtr64, DumpCapsuleInfo); + } + + // + // Dump capsule provisioned on Disk + // + Print (L"#########################\n"); + Print (L"### Capsule on Disk #####\n"); + Print (L"#########################\n"); + Status = GetVariable2 ( + L"BootNext", + &gEfiGlobalVariableGuid, + (VOID **) &BootNext, + NULL + ); + if (EFI_ERROR (Status) || BootNext == NULL) { + Print (L"Get BootNext Variable Fail. Status = %r\n", Status); + } else { + UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", *BootNext); + Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootNextOptionEntry); + if (!EFI_ERROR (Status)) { + // + // Display description and device path + // + GetEfiSysPartitionFromBootOptionFilePath (BootNextOptionEntry.FilePath, &DevicePath, &Fs); + if(!EFI_ERROR (Status)) { + Print (L"Capsules are provisioned on BootOption: %s\n", BootNextOptionEntry.Description); + Print (L" %s %s\n", ShellProtocol->GetMapFromDevicePath (&DevicePath), ConvertDevicePathToText(DevicePath, TRUE, TRUE)); + DumpCapsuleFromDisk (Fs, DumpCapsuleInfo); + } + } + } +} + +/** + Dump FMP information. + + @param[in] ImageInfoSize The size of ImageInfo, in bytes. + @param[in] ImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[in] DescriptorVersion The version of EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[in] DescriptorCount The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[in] DescriptorSize The size of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes. + @param[in] PackageVersion The version of package. + @param[in] PackageVersionName The version name of package. +**/ +VOID +DumpFmpImageInfo ( + IN UINTN ImageInfoSize, + IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo, + IN UINT32 DescriptorVersion, + IN UINT8 DescriptorCount, + IN UINTN DescriptorSize, + IN UINT32 PackageVersion, + IN CHAR16 *PackageVersionName + ) +{ + EFI_FIRMWARE_IMAGE_DESCRIPTOR *CurrentImageInfo; + UINTN Index; + UINTN Index2; + + Print(L" DescriptorVersion - 0x%x\n", DescriptorVersion); + Print(L" DescriptorCount - 0x%x\n", DescriptorCount); + Print(L" DescriptorSize - 0x%x\n", DescriptorSize); + Print(L" PackageVersion - 0x%x\n", PackageVersion); + Print(L" PackageVersionName - \"%s\"\n", PackageVersionName); + CurrentImageInfo = ImageInfo; + for (Index = 0; Index < DescriptorCount; Index++) { + Print(L" ImageDescriptor (%d)\n", Index); + Print(L" ImageIndex - 0x%x\n", CurrentImageInfo->ImageIndex); + Print(L" ImageTypeId - %g\n", &CurrentImageInfo->ImageTypeId); + Print(L" ImageId - 0x%lx\n", CurrentImageInfo->ImageId); + Print(L" ImageIdName - \"%s\"\n", CurrentImageInfo->ImageIdName); + Print(L" Version - 0x%x\n", CurrentImageInfo->Version); + Print(L" VersionName - \"%s\"\n", CurrentImageInfo->VersionName); + Print(L" Size - 0x%x\n", CurrentImageInfo->Size); + Print(L" AttributesSupported - 0x%lx\n", CurrentImageInfo->AttributesSupported); + Print(L" IMAGE_UPDATABLE - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE); + Print(L" RESET_REQUIRED - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_RESET_REQUIRED); + Print(L" AUTHENTICATION_REQUIRED - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED); + Print(L" IN_USE - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_IN_USE); + Print(L" UEFI_IMAGE - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_UEFI_IMAGE); + Print(L" AttributesSetting - 0x%lx\n", CurrentImageInfo->AttributesSetting); + Print(L" IMAGE_UPDATABLE - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE); + Print(L" RESET_REQUIRED - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_RESET_REQUIRED); + Print(L" AUTHENTICATION_REQUIRED - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED); + Print(L" IN_USE - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_IN_USE); + Print(L" UEFI_IMAGE - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_UEFI_IMAGE); + Print(L" Compatibilities - 0x%lx\n", CurrentImageInfo->Compatibilities); + Print(L" COMPATIB_CHECK_SUPPORTED - 0x%lx\n", CurrentImageInfo->Compatibilities & IMAGE_COMPATIBILITY_CHECK_SUPPORTED); + if (DescriptorVersion > 1) { + Print(L" LowestSupportedImageVersion - 0x%x\n", CurrentImageInfo->LowestSupportedImageVersion); + if (DescriptorVersion > 2) { + Print(L" LastAttemptVersion - 0x%x\n", CurrentImageInfo->LastAttemptVersion); + Print(L" LastAttemptStatus - 0x%x (%a)\n", CurrentImageInfo->LastAttemptStatus, LastAttemptStatusToString(CurrentImageInfo->LastAttemptStatus)); + Print(L" HardwareInstance - 0x%lx\n", CurrentImageInfo->HardwareInstance); + if (DescriptorVersion > 3) { + Print(L" Dependencies - "); + if (CurrentImageInfo->Dependencies == NULL) { + Print(L"NULL\n"); + } else { + Index2 = 0; + do { + Print(L"%02x ", CurrentImageInfo->Dependencies->Dependencies[Index2]); + } while (CurrentImageInfo->Dependencies->Dependencies[Index2 ++] != EFI_FMP_DEP_END); + Print(L"\n"); + } + } + } + } + // + // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version + // + CurrentImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)CurrentImageInfo + DescriptorSize); + } +} + +/** + Dump FMP package information. + + @param[in] PackageVersion The version of package. + @param[in] PackageVersionName The version name of package. + @param[in] PackageVersionNameMaxLen The maximum length of PackageVersionName. + @param[in] AttributesSupported Package attributes that are supported by this device. + @param[in] AttributesSetting Package attributes. +**/ +VOID +DumpFmpPackageInfo ( + IN UINT32 PackageVersion, + IN CHAR16 *PackageVersionName, + IN UINT32 PackageVersionNameMaxLen, + IN UINT64 AttributesSupported, + IN UINT64 AttributesSetting + ) +{ + Print(L" PackageVersion - 0x%x\n", PackageVersion); + Print(L" PackageVersionName - \"%s\"\n", PackageVersionName); + Print(L" PackageVersionNameMaxLen - 0x%x\n", PackageVersionNameMaxLen); + Print(L" AttributesSupported - 0x%lx\n", AttributesSupported); + Print(L" IMAGE_UPDATABLE - 0x%lx\n", AttributesSupported & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE); + Print(L" RESET_REQUIRED - 0x%lx\n", AttributesSupported & IMAGE_ATTRIBUTE_RESET_REQUIRED); + Print(L" AUTHENTICATION_REQUIRED - 0x%lx\n", AttributesSupported & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED); + Print(L" AttributesSetting - 0x%lx\n", AttributesSetting); + Print(L" IMAGE_UPDATABLE - 0x%lx\n", AttributesSetting & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE); + Print(L" RESET_REQUIRED - 0x%lx\n", AttributesSetting & IMAGE_ATTRIBUTE_RESET_REQUIRED); + Print(L" AUTHENTICATION_REQUIRED - 0x%lx\n", AttributesSetting & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED); +} + +/** + Dump FMP protocol info. +**/ +VOID +DumpFmpData ( + VOID + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp; + EFI_HANDLE *HandleBuffer; + UINTN NumberOfHandles; + UINTN Index; + EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf; + UINTN ImageInfoSize; + UINT32 FmpImageInfoDescriptorVer; + UINT8 FmpImageInfoCount; + UINTN DescriptorSize; + UINT32 PackageVersion; + CHAR16 *PackageVersionName; + UINT32 PackageVersionNameMaxLen; + UINT64 AttributesSupported; + UINT64 AttributesSetting; + + Print(L"############\n"); + Print(L"# FMP DATA #\n"); + Print(L"############\n"); + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareManagementProtocolGuid, + NULL, + &NumberOfHandles, + &HandleBuffer + ); + if (EFI_ERROR(Status)) { + Print(L"FMP protocol - %r\n", EFI_NOT_FOUND); + return; + } + + for (Index = 0; Index < NumberOfHandles; Index++) { + Status = gBS->HandleProtocol( + HandleBuffer[Index], + &gEfiFirmwareManagementProtocolGuid, + (VOID **)&Fmp + ); + if (EFI_ERROR(Status)) { + continue; + } + + ImageInfoSize = 0; + Status = Fmp->GetImageInfo ( + Fmp, + &ImageInfoSize, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL + ); + if (Status != EFI_BUFFER_TOO_SMALL) { + continue; + } + + FmpImageInfoBuf = NULL; + FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize); + if (FmpImageInfoBuf == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + PackageVersionName = NULL; + Status = Fmp->GetImageInfo ( + Fmp, + &ImageInfoSize, // ImageInfoSize + FmpImageInfoBuf, // ImageInfo + &FmpImageInfoDescriptorVer, // DescriptorVersion + &FmpImageInfoCount, // DescriptorCount + &DescriptorSize, // DescriptorSize + &PackageVersion, // PackageVersion + &PackageVersionName // PackageVersionName + ); + + // + // If FMP GetInformation interface failed, skip this resource + // + if (EFI_ERROR(Status)) { + Print(L"FMP (%d) ImageInfo - %r\n", Index, Status); + FreePool(FmpImageInfoBuf); + continue; + } + + Print(L"FMP (%d) ImageInfo:\n", Index); + DumpFmpImageInfo( + ImageInfoSize, // ImageInfoSize + FmpImageInfoBuf, // ImageInfo + FmpImageInfoDescriptorVer, // DescriptorVersion + FmpImageInfoCount, // DescriptorCount + DescriptorSize, // DescriptorSize + PackageVersion, // PackageVersion + PackageVersionName // PackageVersionName + ); + + if (PackageVersionName != NULL) { + FreePool(PackageVersionName); + } + FreePool(FmpImageInfoBuf); + + // + // Get package info + // + PackageVersionName = NULL; + Status = Fmp->GetPackageInfo ( + Fmp, + &PackageVersion, // PackageVersion + &PackageVersionName, // PackageVersionName + &PackageVersionNameMaxLen, // PackageVersionNameMaxLen + &AttributesSupported, // AttributesSupported + &AttributesSetting // AttributesSetting + ); + if (EFI_ERROR(Status)) { + Print(L"FMP (%d) PackageInfo - %r\n", Index, Status); + } else { + Print(L"FMP (%d) ImageInfo:\n", Index); + DumpFmpPackageInfo( + PackageVersion, // PackageVersion + PackageVersionName, // PackageVersionName + PackageVersionNameMaxLen, // PackageVersionNameMaxLen + AttributesSupported, // AttributesSupported + AttributesSetting // AttributesSetting + ); + + if (PackageVersionName != NULL) { + FreePool(PackageVersionName); + } + } + } + Print(L"\n"); + +EXIT: + FreePool(HandleBuffer); +} + +/** + Check if the ImageInfo includes the ImageTypeId. + + @param[in] ImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[in] DescriptorCount The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[in] DescriptorSize The size of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes. + @param[in] ImageTypeId A unique GUID identifying the firmware image type. + + @return TRUE This ImageInfo includes the ImageTypeId + @return FALSE This ImageInfo does not include the ImageTypeId +**/ +BOOLEAN +IsThisFmpImageInfo ( + IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo, + IN UINT8 DescriptorCount, + IN UINTN DescriptorSize, + IN EFI_GUID *ImageTypeId + ) +{ + EFI_FIRMWARE_IMAGE_DESCRIPTOR *CurrentImageInfo; + UINTN Index; + + CurrentImageInfo = ImageInfo; + for (Index = 0; Index < DescriptorCount; Index++) { + if (CompareGuid (&CurrentImageInfo->ImageTypeId, ImageTypeId)) { + return TRUE; + } + CurrentImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)CurrentImageInfo + DescriptorSize); + } + return FALSE; +} + +/** + return the FMP whoes ImageInfo includes the ImageTypeId. + + @param[in] ImageTypeId A unique GUID identifying the firmware image type. + + @return The FMP whoes ImageInfo includes the ImageTypeId +**/ +EFI_FIRMWARE_MANAGEMENT_PROTOCOL * +FindFmpFromImageTypeId ( + IN EFI_GUID *ImageTypeId + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL *TargetFmp; + EFI_HANDLE *HandleBuffer; + UINTN NumberOfHandles; + UINTN Index; + EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf; + UINTN ImageInfoSize; + UINT32 FmpImageInfoDescriptorVer; + UINT8 FmpImageInfoCount; + UINTN DescriptorSize; + UINT32 PackageVersion; + CHAR16 *PackageVersionName; + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareManagementProtocolGuid, + NULL, + &NumberOfHandles, + &HandleBuffer + ); + if (EFI_ERROR(Status)) { + Print(L"FMP protocol - %r\n", EFI_NOT_FOUND); + return NULL; + } + + TargetFmp = NULL; + for (Index = 0; Index < NumberOfHandles; Index++) { + Status = gBS->HandleProtocol( + HandleBuffer[Index], + &gEfiFirmwareManagementProtocolGuid, + (VOID **)&Fmp + ); + if (EFI_ERROR(Status)) { + continue; + } + + ImageInfoSize = 0; + Status = Fmp->GetImageInfo ( + Fmp, + &ImageInfoSize, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL + ); + if (Status != EFI_BUFFER_TOO_SMALL) { + continue; + } + + FmpImageInfoBuf = NULL; + FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize); + if (FmpImageInfoBuf == NULL) { + FreePool(HandleBuffer); + Print(L"Out of resource\n"); + return NULL; + } + + PackageVersionName = NULL; + Status = Fmp->GetImageInfo ( + Fmp, + &ImageInfoSize, // ImageInfoSize + FmpImageInfoBuf, // ImageInfo + &FmpImageInfoDescriptorVer, // DescriptorVersion + &FmpImageInfoCount, // DescriptorCount + &DescriptorSize, // DescriptorSize + &PackageVersion, // PackageVersion + &PackageVersionName // PackageVersionName + ); + + // + // If FMP GetInformation interface failed, skip this resource + // + if (EFI_ERROR(Status)) { + FreePool(FmpImageInfoBuf); + continue; + } + + if (PackageVersionName != NULL) { + FreePool(PackageVersionName); + } + + if (IsThisFmpImageInfo (FmpImageInfoBuf, FmpImageInfoCount, DescriptorSize, ImageTypeId)) { + TargetFmp = Fmp; + } + FreePool(FmpImageInfoBuf); + if (TargetFmp != NULL) { + break; + } + } + FreePool(HandleBuffer); + return TargetFmp; +} + +/** + Dump FMP image data. + + @param[in] ImageTypeId The ImageTypeId of the FMP image. + It is used to identify the FMP protocol. + @param[in] ImageIndex The ImageIndex of the FMP image. + It is the input parameter for FMP->GetImage(). + @param[in] ImageName The file name to hold the output FMP image. +**/ +VOID +DumpFmpImage ( + IN EFI_GUID *ImageTypeId, + IN UINTN ImageIndex, + IN CHAR16 *ImageName + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp; + VOID *Image; + UINTN ImageSize; + + Fmp = FindFmpFromImageTypeId (ImageTypeId); + if (Fmp == NULL) { + Print(L"No FMP include ImageTypeId %g\n", ImageTypeId); + return ; + } + + if (ImageIndex > 0xFF) { + Print(L"ImageIndex 0x%x too big\n", ImageIndex); + return ; + } + + Image = Fmp; + ImageSize = 0; + Status = Fmp->GetImage (Fmp, (UINT8)ImageIndex, Image, &ImageSize); + if (Status != EFI_BUFFER_TOO_SMALL) { + Print(L"Fmp->GetImage - %r\n", Status); + return ; + } + + Image = AllocatePool (ImageSize); + if (Image == NULL) { + Print(L"Allocate FmpImage 0x%x - %r\n", ImageSize, EFI_OUT_OF_RESOURCES); + return ; + } + + Status = Fmp->GetImage (Fmp, (UINT8)ImageIndex, Image, &ImageSize); + if (EFI_ERROR(Status)) { + Print(L"Fmp->GetImage - %r\n", Status); + return ; + } + + Status = WriteFileFromBuffer(ImageName, ImageSize, Image); + Print(L"CapsuleApp: Dump %g ImageIndex (0x%x) to %s %r\n", ImageTypeId, ImageIndex, ImageName, Status); + + FreePool (Image); + + return ; +} diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c new file mode 100644 index 00000000..b1cf39ca --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c @@ -0,0 +1,842 @@ +/** @file + Process Capsule On Disk. + + Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "CapsuleApp.h" + +EFI_GUID mCapsuleOnDiskBootOptionGuid = { 0x4CC29BB7, 0x2413, 0x40A2, { 0xB0, 0x6D, 0x25, 0x3E, 0x37, 0x10, 0xF5, 0x32 } }; + +/** + Get file name from file path. + + @param FilePath File path. + + @return Pointer to file name. + +**/ +CHAR16 * +GetFileNameFromPath ( + CHAR16 *FilePath + ) +{ + EFI_STATUS Status; + EFI_SHELL_PROTOCOL *ShellProtocol; + SHELL_FILE_HANDLE Handle; + EFI_FILE_INFO *FileInfo; + + ShellProtocol = GetShellProtocol (); + if (ShellProtocol == NULL) { + return NULL; + } + + // + // Open file by FileName. + // + Status = ShellProtocol->OpenFileByName ( + FilePath, + &Handle, + EFI_FILE_MODE_READ + ); + if (EFI_ERROR (Status)) { + return NULL; + } + + // + // Get file name from EFI_FILE_INFO. + // + FileInfo = ShellProtocol->GetFileInfo (Handle); + ShellProtocol->CloseFile (Handle); + if (FileInfo == NULL) { + return NULL; + } + + return FileInfo->FileName; +} + +/** + Check if the device path is EFI system Partition. + + @param DevicePath The ESP device path. + + @retval TRUE DevicePath is a device path for ESP. + @retval FALSE DevicePath is not a device path for ESP. + +**/ +BOOLEAN +IsEfiSysPartitionDevicePath ( + EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + HARDDRIVE_DEVICE_PATH *Hd; + EFI_HANDLE Handle; + + // + // Check if the device path contains GPT node + // + TempDevicePath = DevicePath; + + while (!IsDevicePathEnd (TempDevicePath)) { + if ((DevicePathType (TempDevicePath) == MEDIA_DEVICE_PATH) && + (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP)) { + Hd = (HARDDRIVE_DEVICE_PATH *)TempDevicePath; + if (Hd->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER) { + break; + } + } + TempDevicePath = NextDevicePathNode (TempDevicePath); + } + + if (!IsDevicePathEnd (TempDevicePath)) { + // + // Search for EFI system partition protocol on full device path in Boot Option + // + Status = gBS->LocateDevicePath (&gEfiPartTypeSystemPartGuid, &DevicePath, &Handle); + return EFI_ERROR (Status) ? FALSE : TRUE; + } else { + return FALSE; + } +} + +/** + Dump all EFI System Partition. + +**/ +VOID +DumpAllEfiSysPartition ( + VOID + ) +{ + EFI_HANDLE *SimpleFileSystemHandles; + UINTN NumberSimpleFileSystemHandles; + UINTN Index; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINTN NumberEfiSystemPartitions; + EFI_SHELL_PROTOCOL *ShellProtocol; + + NumberEfiSystemPartitions = 0; + + ShellProtocol = GetShellProtocol (); + if (ShellProtocol == NULL) { + Print (L"Get Shell Protocol Fail\n");; + return ; + } + + Print (L"EFI System Partition list:\n"); + + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleFileSystemProtocolGuid, + NULL, + &NumberSimpleFileSystemHandles, + &SimpleFileSystemHandles + ); + + for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) { + DevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]); + if (IsEfiSysPartitionDevicePath (DevicePath)) { + NumberEfiSystemPartitions++; + Print(L" %s\n %s\n", ShellProtocol->GetMapFromDevicePath (&DevicePath), ConvertDevicePathToText (DevicePath, TRUE, TRUE)); + } + } + + if (NumberEfiSystemPartitions == 0) { + Print(L" No ESP found.\n"); + } +} + +/** + Check if capsule is provisioned. + + @retval TRUE Capsule is provisioned previously. + @retval FALSE No capsule is provisioned. + +**/ +BOOLEAN +IsCapsuleProvisioned ( + VOID + ) +{ + EFI_STATUS Status; + UINT64 OsIndication; + UINTN DataSize; + + OsIndication = 0; + DataSize = sizeof(UINT64); + Status = gRT->GetVariable ( + L"OsIndications", + &gEfiGlobalVariableGuid, + NULL, + &DataSize, + &OsIndication + ); + if (!EFI_ERROR (Status) && + (OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0) { + return TRUE; + } + + return FALSE; +} + +/** + Get one active Efi System Partition. + + @param[out] FsDevicePath The device path of Fs + @param[out] Fs The file system within EfiSysPartition + + @retval EFI_SUCCESS Get file system successfully + @retval EFI_NOT_FOUND No valid file system found + +**/ +EFI_STATUS +GetEfiSysPartition ( + OUT EFI_DEVICE_PATH_PROTOCOL **FsDevicePath, + OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs + ) +{ + EFI_HANDLE *SimpleFileSystemHandles; + UINTN NumberSimpleFileSystemHandles; + UINTN Index; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_STATUS Status; + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleFileSystemProtocolGuid, + NULL, + &NumberSimpleFileSystemHandles, + &SimpleFileSystemHandles + ); + + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) { + DevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]); + if (IsEfiSysPartitionDevicePath (DevicePath)) { + Status = gBS->HandleProtocol (SimpleFileSystemHandles[Index], &gEfiSimpleFileSystemProtocolGuid, (VOID **)Fs); + if (!EFI_ERROR (Status)) { + *FsDevicePath = DevicePath; + return EFI_SUCCESS; + } + } + } + + return EFI_NOT_FOUND; +} + +/** + Check if Active Efi System Partition within GPT is in the device path. + + @param[in] DevicePath The device path + @param[out] FsDevicePath The device path of Fs + @param[out] Fs The file system within EfiSysPartition + + @retval EFI_SUCCESS Get file system successfully + @retval EFI_NOT_FOUND No valid file system found + @retval others Get file system failed + +**/ +EFI_STATUS +GetEfiSysPartitionFromDevPath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT EFI_DEVICE_PATH_PROTOCOL **FsDevicePath, + OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + HARDDRIVE_DEVICE_PATH *Hd; + EFI_HANDLE Handle; + + // + // Check if the device path contains GPT node + // + TempDevicePath = DevicePath; + while (!IsDevicePathEnd (TempDevicePath)) { + if ((DevicePathType (TempDevicePath) == MEDIA_DEVICE_PATH) && + (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP)) { + Hd = (HARDDRIVE_DEVICE_PATH *)TempDevicePath; + if (Hd->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER) { + break; + } + } + TempDevicePath = NextDevicePathNode (TempDevicePath); + } + + if (!IsDevicePathEnd (TempDevicePath)) { + // + // Search for EFI system partition protocol on full device path in Boot Option + // + Status = gBS->LocateDevicePath (&gEfiPartTypeSystemPartGuid, &DevicePath, &Handle); + + // + // Search for simple file system on this handler + // + if (!EFI_ERROR (Status)) { + Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)Fs); + if (!EFI_ERROR (Status)) { + *FsDevicePath = DevicePathFromHandle (Handle); + return EFI_SUCCESS; + } + } + } + + return EFI_NOT_FOUND; +} + +/** + Get SimpleFileSystem from boot option file path. + + @param[in] DevicePath The file path of boot option + @param[out] FullPath The full device path of boot device + @param[out] Fs The file system within EfiSysPartition + + @retval EFI_SUCCESS Get file system successfully + @retval EFI_NOT_FOUND No valid file system found + @retval others Get file system failed + +**/ +EFI_STATUS +GetEfiSysPartitionFromBootOptionFilePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, + OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *CurFullPath; + EFI_DEVICE_PATH_PROTOCOL *PreFullPath; + EFI_DEVICE_PATH_PROTOCOL *FsFullPath; + + CurFullPath = NULL; + FsFullPath = NULL; + // + // Try every full device Path generated from bootoption + // + do { + PreFullPath = CurFullPath; + CurFullPath = EfiBootManagerGetNextLoadOptionDevicePath (DevicePath, CurFullPath); + + if (PreFullPath != NULL) { + FreePool (PreFullPath); + } + + if (CurFullPath == NULL) { + // + // No Active EFI system partition is found in BootOption device path + // + Status = EFI_NOT_FOUND; + break; + } + + DEBUG_CODE ( + CHAR16 *DevicePathStr; + + DevicePathStr = ConvertDevicePathToText (CurFullPath, TRUE, TRUE); + if (DevicePathStr != NULL){ + DEBUG ((DEBUG_INFO, "Full device path %s\n", DevicePathStr)); + FreePool (DevicePathStr); + } + ); + + Status = GetEfiSysPartitionFromDevPath (CurFullPath, &FsFullPath, Fs); + } while (EFI_ERROR (Status)); + + if (*Fs != NULL) { + *FullPath = FsFullPath; + return EFI_SUCCESS; + } else { + return EFI_NOT_FOUND; + } +} + +/** + Get a valid SimpleFileSystem within EFI system partition. + + @param[in] Map The FS mapping capsule write to + @param[out] BootNext The value of BootNext Variable + @param[out] Fs The file system within EfiSysPartition + @param[out] UpdateBootNext The flag to indicate whether update BootNext Variable + + @retval EFI_SUCCESS Get FS successfully + @retval EFI_NOT_FOUND No valid FS found + @retval others Get FS failed + +**/ +EFI_STATUS +GetUpdateFileSystem ( + IN CHAR16 *Map, + OUT UINT16 *BootNext, + OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs, + OUT BOOLEAN *UpdateBootNext +) +{ + EFI_STATUS Status; + CHAR16 BootOptionName[20]; + UINTN Index; + CONST EFI_DEVICE_PATH_PROTOCOL *MappedDevicePath; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *FullPath; + UINT16 *BootNextData; + EFI_BOOT_MANAGER_LOAD_OPTION BootNextOption; + EFI_BOOT_MANAGER_LOAD_OPTION *BootOptionBuffer; + UINTN BootOptionCount; + EFI_SHELL_PROTOCOL *ShellProtocol; + EFI_BOOT_MANAGER_LOAD_OPTION NewOption; + + MappedDevicePath = NULL; + BootOptionBuffer = NULL; + + ShellProtocol = GetShellProtocol (); + if (ShellProtocol == NULL) { + Print (L"Get Shell Protocol Fail\n");; + return EFI_NOT_FOUND; + } + + // + // 1. If Fs is not assigned and there are capsule provisioned before, + // Get EFI system partition from BootNext. + // + if (IsCapsuleProvisioned () && Map == NULL) { + Status = GetVariable2 ( + L"BootNext", + &gEfiGlobalVariableGuid, + (VOID **)&BootNextData, + NULL + ); + if (EFI_ERROR (Status) || BootNextData == NULL) { + Print (L"Get Boot Next Data Fail. Status = %r\n", Status); + return EFI_NOT_FOUND; + } else { + UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", *BootNextData); + Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootNextOption); + if (!EFI_ERROR (Status)) { + DevicePath = BootNextOption.FilePath; + Status = GetEfiSysPartitionFromBootOptionFilePath (DevicePath, &FullPath, Fs); + if (!EFI_ERROR (Status)) { + *UpdateBootNext = FALSE; + Print(L"Get EFI system partition from BootNext : %s\n", BootNextOption.Description); + Print(L"%s %s\n", ShellProtocol->GetMapFromDevicePath (&FullPath), ConvertDevicePathToText (FullPath, TRUE, TRUE)); + return EFI_SUCCESS; + } + } + } + } + + // + // Check if Map is valid. + // + if (Map != NULL) { + MappedDevicePath = ShellProtocol->GetDevicePathFromMap (Map); + if (MappedDevicePath == NULL) { + Print(L"'%s' is not a valid mapping.\n", Map); + return EFI_INVALID_PARAMETER; + } else if (!IsEfiSysPartitionDevicePath (DuplicateDevicePath (MappedDevicePath))) { + Print(L"'%s' is not a EFI System Partition.\n", Map); + return EFI_INVALID_PARAMETER; + } + } + + // + // 2. Get EFI system partition form boot options. + // + BootOptionBuffer = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot); + if ( (BootOptionBuffer == NULL) || + (BootOptionCount == 0 && Map == NULL) + ) { + return EFI_NOT_FOUND; + } + + for (Index = 0; Index < BootOptionCount; Index++) { + // + // Get the boot option from the link list + // + DevicePath = BootOptionBuffer[Index].FilePath; + + // + // Skip inactive or legacy boot options + // + if ((BootOptionBuffer[Index].Attributes & LOAD_OPTION_ACTIVE) == 0 || + DevicePathType (DevicePath) == BBS_DEVICE_PATH) { + continue; + } + + DEBUG_CODE ( + CHAR16 *DevicePathStr; + + DevicePathStr = ConvertDevicePathToText (DevicePath, TRUE, TRUE); + if (DevicePathStr != NULL){ + DEBUG ((DEBUG_INFO, "Try BootOption %s\n", DevicePathStr)); + FreePool (DevicePathStr); + } else { + DEBUG ((DEBUG_INFO, "DevicePathToStr failed\n")); + } + ); + + Status = GetEfiSysPartitionFromBootOptionFilePath (DevicePath, &FullPath, Fs); + if (!EFI_ERROR (Status)) { + if (Map == NULL) { + *BootNext = (UINT16) BootOptionBuffer[Index].OptionNumber; + *UpdateBootNext = TRUE; + Print (L"Found EFI system partition on Boot%04x: %s\n", *BootNext, BootOptionBuffer[Index].Description); + Print (L"%s %s\n", ShellProtocol->GetMapFromDevicePath (&FullPath), ConvertDevicePathToText (FullPath, TRUE, TRUE)); + return EFI_SUCCESS; + } + + if (StrnCmp (Map, ShellProtocol->GetMapFromDevicePath (&FullPath), StrLen (Map)) == 0) { + *BootNext = (UINT16) BootOptionBuffer[Index].OptionNumber; + *UpdateBootNext = TRUE; + Print (L"Found Boot Option on %s : %s\n", Map, BootOptionBuffer[Index].Description); + return EFI_SUCCESS; + } + } + } + + // + // 3. If no ESP is found on boot option, try to find a ESP and create boot option for it. + // + if (Map != NULL) { + // + // If map is assigned, try to get ESP from mapped Fs. + // + DevicePath = DuplicateDevicePath (MappedDevicePath); + Status = GetEfiSysPartitionFromDevPath (DevicePath, &FullPath, Fs); + if (EFI_ERROR (Status)) { + Print (L"Error: Cannot get EFI system partiion from '%s' - %r\n", Map, Status); + return EFI_NOT_FOUND; + } + Print (L"Warning: Cannot find Boot Option on '%s'!\n", Map); + } else { + Status = GetEfiSysPartition (&DevicePath, Fs); + if (EFI_ERROR (Status)) { + Print (L"Error: Cannot find a EFI system partition!\n"); + return EFI_NOT_FOUND; + } + } + + Print (L"Create Boot option for capsule on disk:\n"); + Status = EfiBootManagerInitializeLoadOption ( + &NewOption, + LoadOptionNumberUnassigned, + LoadOptionTypeBoot, + LOAD_OPTION_ACTIVE, + L"UEFI Capsule On Disk", + DevicePath, + (UINT8 *) &mCapsuleOnDiskBootOptionGuid, + sizeof(EFI_GUID) + ); + if (!EFI_ERROR (Status)) { + Status = EfiBootManagerAddLoadOptionVariable (&NewOption, (UINTN) -1); { + if (!EFI_ERROR (Status)) { + *UpdateBootNext = TRUE; + *BootNext = (UINT16) NewOption.OptionNumber; + Print (L" Boot%04x: %s\n", *BootNext, ConvertDevicePathToText(DevicePath, TRUE, TRUE)); + return EFI_SUCCESS; + } + } + } + + Print (L"ERROR: Cannot create boot option! - %r\n", Status); + + return EFI_NOT_FOUND; +} + +/** + Write files to a given SimpleFileSystem. + + @param[in] Buffer The buffer array + @param[in] BufferSize The buffer size array + @param[in] FileName The file name array + @param[in] BufferNum The buffer number + @param[in] Fs The SimpleFileSystem handle to be written + + @retval EFI_SUCCESS Write file successfully + @retval EFI_NOT_FOUND SFS protocol not found + @retval others Write file failed + +**/ +EFI_STATUS +WriteUpdateFile ( + IN VOID **Buffer, + IN UINTN *BufferSize, + IN CHAR16 **FileName, + IN UINTN BufferNum, + IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs +) +{ + EFI_STATUS Status; + EFI_FILE *Root; + EFI_FILE *FileHandle; + EFI_FILE_PROTOCOL *DirHandle; + UINT64 FileInfo; + VOID *Filebuffer; + UINTN FileSize; + UINTN Index; + + DirHandle = NULL; + FileHandle = NULL; + Index = 0; + + // + // Open Root from SFS + // + Status = Fs->OpenVolume (Fs, &Root); + if (EFI_ERROR (Status)) { + Print (L"Cannot open volume. Status = %r\n", Status); + return EFI_NOT_FOUND; + } + + // + // Ensure that efi and updatecapsule directories exist + // + Status = Root->Open (Root, &DirHandle, L"\\EFI", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0); + if (EFI_ERROR (Status)) { + Status = Root->Open (Root, &DirHandle, L"\\EFI", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY); + if (EFI_ERROR (Status)) { + Print(L"Unable to create %s directory\n", L"\\EFI"); + return EFI_NOT_FOUND; + } + } + Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE , 0); + if (EFI_ERROR (Status)) { + Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY); + if (EFI_ERROR (Status)) { + Print(L"Unable to create %s directory\n", EFI_CAPSULE_FILE_DIRECTORY); + return EFI_NOT_FOUND; + } + } + + for (Index = 0; Index < BufferNum; Index++) { + FileHandle = NULL; + + // + // Open UpdateCapsule file + // + Status = DirHandle->Open (DirHandle, &FileHandle, FileName[Index], EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 0); + if (EFI_ERROR (Status)) { + Print (L"Unable to create %s file\n", FileName[Index]); + return EFI_NOT_FOUND; + } + + // + // Empty the file contents + // + Status = FileHandleGetSize (FileHandle, &FileInfo); + if (EFI_ERROR (Status)) { + FileHandleClose (FileHandle); + Print (L"Error Reading %s\n", FileName[Index]); + return EFI_DEVICE_ERROR; + } + + // + // If the file size is already 0, then it has been empty. + // + if (FileInfo != 0) { + // + // Set the file size to 0. + // + FileInfo = 0; + Status = FileHandleSetSize (FileHandle, FileInfo); + if (EFI_ERROR (Status)) { + Print (L"Error Deleting %s\n", FileName[Index]); + FileHandleClose (FileHandle); + return Status; + } + } + + // + // Write Filebuffer to file + // + Filebuffer = Buffer[Index]; + FileSize = BufferSize[Index]; + Status = FileHandleWrite (FileHandle, &FileSize, Filebuffer); + if (EFI_ERROR (Status)) { + Print (L"Unable to write Capsule Update to %s, Status = %r\n", FileName[Index], Status); + return EFI_NOT_FOUND; + } + + Print (L"Succeed to write %s\n", FileName[Index]); + FileHandleClose (FileHandle); + } + + return EFI_SUCCESS; +} + +/** + Set capsule status variable. + + @param[in] SetCap Set or clear the capsule flag. + + @retval EFI_SUCCESS Succeed to set SetCap variable. + @retval others Fail to set the variable. + +**/ +EFI_STATUS +SetCapsuleStatusVariable ( + BOOLEAN SetCap + ) +{ + EFI_STATUS Status; + UINT64 OsIndication; + UINTN DataSize; + + OsIndication = 0; + DataSize = sizeof(UINT64); + Status = gRT->GetVariable ( + L"OsIndications", + &gEfiGlobalVariableGuid, + NULL, + &DataSize, + &OsIndication + ); + if (EFI_ERROR (Status)) { + OsIndication = 0; + } + if (SetCap) { + OsIndication |= ((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED); + } + else { + OsIndication &= ~((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED); + } + Status = gRT->SetVariable ( + L"OsIndications", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + sizeof(UINT64), + &OsIndication + ); + + return Status; +} + +/** + Check if Capsule On Disk is supported. + + @retval TRUE Capsule On Disk is supported. + @retval FALSE Capsule On Disk is not supported. + +**/ +BOOLEAN +IsCapsuleOnDiskSupported ( + VOID + ) +{ + EFI_STATUS Status; + UINT64 OsIndicationsSupported; + UINTN DataSize; + + DataSize = sizeof(UINT64); + Status = gRT->GetVariable ( + L"OsIndicationsSupported", + &gEfiGlobalVariableGuid, + NULL, + &DataSize, + &OsIndicationsSupported + ); + if (EFI_ERROR (Status)) { + return FALSE; + } + + if ((OsIndicationsSupported & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0) { + return TRUE; + } + + return FALSE; +} + +/** + Process Capsule On Disk. + + @param[in] CapsuleBuffer An array of pointer to capsule images + @param[in] CapsuleBufferSize An array of UINTN to capsule images size + @param[in] FilePath An array of capsule images file path + @param[in] Map File system mapping string + @param[in] CapsuleNum The count of capsule images + + @retval EFI_SUCCESS Capsule on disk success. + @retval others Capsule on disk fail. + +**/ +EFI_STATUS +ProcessCapsuleOnDisk ( + IN VOID **CapsuleBuffer, + IN UINTN *CapsuleBufferSize, + IN CHAR16 **FilePath, + IN CHAR16 *Map, + IN UINTN CapsuleNum + ) +{ + EFI_STATUS Status; + UINT16 BootNext; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs; + BOOLEAN UpdateBootNext; + CHAR16 *FileName[MAX_CAPSULE_NUM]; + UINTN Index; + + // + // Check if Capsule On Disk is supported + // + if (!IsCapsuleOnDiskSupported ()) { + Print (L"CapsuleApp: Capsule On Disk is not supported.\n"); + return EFI_UNSUPPORTED; + } + + // + // Get a valid file system from boot path + // + Fs = NULL; + + Status = GetUpdateFileSystem (Map, &BootNext, &Fs, &UpdateBootNext); + if (EFI_ERROR (Status)) { + Print (L"CapsuleApp: cannot find a valid file system on boot devices. Status = %r\n", Status); + return Status; + } + + // + // Get file name from file path + // + for (Index = 0; Index < CapsuleNum; Index ++) { + FileName[Index] = GetFileNameFromPath (FilePath[Index]); + } + + // + // Copy capsule image to '\efi\UpdateCapsule\' + // + Status = WriteUpdateFile (CapsuleBuffer, CapsuleBufferSize, FileName, CapsuleNum, Fs); + if (EFI_ERROR (Status)) { + Print (L"CapsuleApp: capsule image could not be copied for update.\n"); + return Status; + } + + // + // Set variable then reset + // + Status = SetCapsuleStatusVariable (TRUE); + if (EFI_ERROR (Status)) { + Print (L"CapsuleApp: unable to set OSIndication variable.\n"); + return Status; + } + + if (UpdateBootNext) { + Status = gRT->SetVariable ( + L"BootNext", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + sizeof(UINT16), + &BootNext + ); + if (EFI_ERROR (Status)){ + Print (L"CapsuleApp: unable to set BootNext variable.\n"); + return Status; + } + } + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.c new file mode 100644 index 00000000..784c9bd6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.c @@ -0,0 +1,610 @@ +/** @file + A shell application to dump dynamic PCD settings. + + Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Uefi.h> +#include <PiDxe.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> + + +#include <Protocol/UnicodeCollation.h> +#include <Protocol/PiPcd.h> +#include <Protocol/Pcd.h> +#include <Protocol/PiPcdInfo.h> +#include <Protocol/PcdInfo.h> +#include <Protocol/ShellParameters.h> +#include <Protocol/Shell.h> + + +// +// String token ID of help message text. +// Shell supports to find help message in the resource section of an application image if +// .MAN file is not found. This global variable is added to make build tool recognizes +// that the help string is consumed by user and then build tool will add the string into +// the resource section. Thus the application can use '-?' option to show help message in +// Shell. +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_STRING_ID mStrDumpDynPcdHelpTokenId = STRING_TOKEN (STR_DUMP_DYN_PCD_HELP_INFORMATION); + +#define MAJOR_VERSION 1 +#define MINOR_VERSION 0 + +static EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL; +static EFI_PCD_PROTOCOL *mPiPcd = NULL; +static PCD_PROTOCOL *mPcd = NULL; +static EFI_GET_PCD_INFO_PROTOCOL *mPiPcdInfo = NULL; +static GET_PCD_INFO_PROTOCOL *mPcdInfo = NULL; +static CHAR16 *mTempPcdNameBuffer = NULL; +static UINTN mTempPcdNameBufferSize = 0; + +static CONST CHAR8 mHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + +static UINTN Argc; +static CHAR16 **Argv; + + +/** + + This function parse application ARG. + + @return Status +**/ +static +EFI_STATUS +GetArg ( + VOID + ) +{ + EFI_STATUS Status; + EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters; + + Status = gBS->HandleProtocol ( + gImageHandle, + &gEfiShellParametersProtocolGuid, + (VOID**)&ShellParameters + ); + if (EFI_ERROR(Status)) { + return Status; + } + + Argc = ShellParameters->Argc; + Argv = ShellParameters->Argv; + return EFI_SUCCESS; +} + +/** + Display current version. +**/ +static +VOID +ShowVersion ( + ) +{ + Print (L"DumpDynPcd Version %d.%02d\n", MAJOR_VERSION, MINOR_VERSION); +} + +/** + Display Usage and Help information. +**/ +static +VOID +ShowHelp ( + ) +{ + Print (L"Dump dynamic[ex] PCD info.\n"); + Print (L"\n"); + Print (L"DumpDynPcd [PcdName]\n"); + Print (L"\n"); + Print (L" PcdName Specifies the name of PCD.\n"); + Print (L" A literal[or partial] name or a pattern as specified in\n"); + Print (L" the MetaiMatch() function of the EFI_UNICODE_COLLATION2_PROCOOL.\n"); + Print (L" If it is absent, dump all PCDs' info.\n"); + Print (L"The PCD data is printed as hexadecimal dump.\n"); +} + +/** + Dump some hexadecimal data to the screen. + + @param[in] Indent How many spaces to indent the output. + @param[in] Offset The offset of the printing. + @param[in] DataSize The size in bytes of UserData. + @param[in] UserData The data to print out. +**/ +static +VOID +DumpHex ( + IN UINTN Indent, + IN UINTN Offset, + IN UINTN DataSize, + IN VOID *UserData + ) +{ + UINT8 *Data; + + CHAR8 Val[50]; + + CHAR8 Str[20]; + + UINT8 TempByte; + UINTN Size; + UINTN Index; + + Data = UserData; + while (DataSize != 0) { + Size = 16; + if (Size > DataSize) { + Size = DataSize; + } + + for (Index = 0; Index < Size; Index += 1) { + TempByte = Data[Index]; + Val[Index * 3 + 0] = mHex[TempByte >> 4]; + Val[Index * 3 + 1] = mHex[TempByte & 0xF]; + Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' '); + Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte); + } + + Val[Index * 3] = 0; + Str[Index] = 0; + Print (L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str); + + Data += Size; + Offset += Size; + DataSize -= Size; + } +} + + +/** + Safely append with automatic string resizing given length of Destination and + desired length of copy from Source. + + append the first D characters of Source to the end of Destination, where D is + the lesser of Count and the StrLen() of Source. If appending those D characters + will fit within Destination (whose Size is given as CurrentSize) and + still leave room for a NULL terminator, then those characters are appended, + starting at the original terminating NULL of Destination, and a new terminating + NULL is appended. + + If appending D characters onto Destination will result in a overflow of the size + given in CurrentSize the string will be grown such that the copy can be performed + and CurrentSize will be updated to the new size. + + If Source is NULL, there is nothing to append, just return the current buffer in + Destination. + + if Destination is NULL, then ASSERT() + if Destination's current length (including NULL terminator) is already more then + CurrentSize, then ASSERT() + + @param[in, out] Destination The String to append onto + @param[in, out] CurrentSize on call the number of bytes in Destination. On + return possibly the new size (still in bytes). if NULL + then allocate whatever is needed. + @param[in] Source The String to append from + + @return Destination return the resultant string. +**/ +static +CHAR16* +InternalStrnCatGrow ( + IN OUT CHAR16 **Destination, + IN OUT UINTN *CurrentSize, + IN CONST CHAR16 *Source + ) +{ + UINTN DestinationStartSize; + UINTN NewSize; + UINTN SourceLen; + + SourceLen = StrLen(Source); + + // + // ASSERTs + // + ASSERT(Destination != NULL); + + // + // If there's nothing to do then just return Destination + // + if (Source == NULL) { + return (*Destination); + } + + // + // allow for un-initialized pointers, based on size being 0 + // + if (CurrentSize != NULL && *CurrentSize == 0) { + *Destination = NULL; + } + + // + // allow for NULL pointers address as Destination + // + if (*Destination != NULL) { + ASSERT(CurrentSize != 0); + DestinationStartSize = StrSize(*Destination); + ASSERT(DestinationStartSize <= *CurrentSize); + } else { + DestinationStartSize = 0; + } + + // + // Test and grow if required + // + if (CurrentSize != NULL) { + NewSize = *CurrentSize; + if (NewSize < DestinationStartSize + (SourceLen * sizeof(CHAR16))) { + while (NewSize < (DestinationStartSize + (SourceLen*sizeof(CHAR16)))) { + NewSize += 2 * SourceLen * sizeof(CHAR16); + } + *Destination = ReallocatePool(*CurrentSize, NewSize, *Destination); + *CurrentSize = NewSize; + } + } else { + NewSize = (SourceLen + 1)*sizeof(CHAR16); + *Destination = AllocateZeroPool(NewSize); + } + + // + // Now use standard StrnCat on a big enough buffer + // + if (*Destination == NULL) { + return (NULL); + } + + StrnCatS(*Destination, NewSize/sizeof(CHAR16), Source, SourceLen); + return *Destination; +} + +/** + Get PCD type string based on input PCD type. + + @param[in] TokenSpace PCD Token Space. + @param[in] PcdType The input PCD type. + + @return Pointer to PCD type string. +**/ +static +CHAR16 * +GetPcdTypeString ( + IN CONST EFI_GUID *TokenSpace, + IN EFI_PCD_TYPE PcdType + ) +{ + UINTN BufLen; + CHAR16 *RetString; + + BufLen = 0; + RetString = NULL; + + switch (PcdType) { + case EFI_PCD_TYPE_8: + InternalStrnCatGrow (&RetString, &BufLen, L"UINT8"); + break; + case EFI_PCD_TYPE_16: + InternalStrnCatGrow (&RetString, &BufLen, L"UINT16"); + break; + case EFI_PCD_TYPE_32: + InternalStrnCatGrow (&RetString, &BufLen, L"UINT32"); + break; + case EFI_PCD_TYPE_64: + InternalStrnCatGrow (&RetString, &BufLen, L"UINT64"); + break; + case EFI_PCD_TYPE_BOOL: + InternalStrnCatGrow (&RetString, &BufLen, L"BOOLEAN"); + break; + case EFI_PCD_TYPE_PTR: + InternalStrnCatGrow (&RetString, &BufLen, L"POINTER"); + break; + default: + InternalStrnCatGrow (&RetString, &BufLen, L"UNKNOWN"); + break; + } + + if (TokenSpace == NULL) { + InternalStrnCatGrow (&RetString, &BufLen, L":DYNAMIC"); + } else { + InternalStrnCatGrow (&RetString, &BufLen, L":DYNAMICEX"); + } + + return RetString; +} + +/** + Dump PCD info. + + @param[in] TokenSpace PCD Token Space. + @param[in] TokenNumber PCD Token Number. + @param[in] PcdInfo Pointer to PCD info. +**/ +static +VOID +DumpPcdInfo ( + IN CONST EFI_GUID *TokenSpace, + IN UINTN TokenNumber, + IN EFI_PCD_INFO *PcdInfo + ) +{ + CHAR16 *RetString; + UINT8 Uint8; + UINT16 Uint16; + UINT32 Uint32; + UINT64 Uint64; + BOOLEAN Boolean; + VOID *PcdData; + + RetString = NULL; + + if (PcdInfo->PcdName != NULL) { + Print (L"%a\n", PcdInfo->PcdName); + } else { + if (TokenSpace == NULL) { + Print (L"Default Token Space\n"); + } else { + Print (L"%g\n", TokenSpace); + } + } + + RetString = GetPcdTypeString (TokenSpace, PcdInfo->PcdType); + + switch (PcdInfo->PcdType) { + case EFI_PCD_TYPE_8: + if (TokenSpace == NULL) { + Uint8 = mPcd->Get8 (TokenNumber); + } else { + Uint8 = mPiPcd->Get8 (TokenSpace, TokenNumber); + } + Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = 0x%x\n", TokenNumber, RetString, PcdInfo->PcdSize, Uint8); + break; + case EFI_PCD_TYPE_16: + if (TokenSpace == NULL) { + Uint16 = mPcd->Get16 (TokenNumber); + } else { + Uint16 = mPiPcd->Get16 (TokenSpace, TokenNumber); + } + Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = 0x%x\n", TokenNumber, RetString, PcdInfo->PcdSize, Uint16); + break; + case EFI_PCD_TYPE_32: + if (TokenSpace == NULL) { + Uint32 = mPcd->Get32 (TokenNumber); + } else { + Uint32 = mPiPcd->Get32 (TokenSpace, TokenNumber); + } + Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = 0x%x\n", TokenNumber, RetString, PcdInfo->PcdSize, Uint32); + break; + case EFI_PCD_TYPE_64: + if (TokenSpace == NULL) { + Uint64 = mPcd->Get64 (TokenNumber); + } else { + Uint64 = mPiPcd->Get64 (TokenSpace, TokenNumber); + } + Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = 0x%lx\n", TokenNumber, RetString, PcdInfo->PcdSize, Uint64); + break; + case EFI_PCD_TYPE_BOOL: + if (TokenSpace == NULL) { + Boolean = mPcd->GetBool (TokenNumber); + } else { + Boolean = mPiPcd->GetBool (TokenSpace, TokenNumber); + } + Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = %a\n", TokenNumber, RetString, PcdInfo->PcdSize, Boolean ? "TRUE" : "FALSE"); + break; + case EFI_PCD_TYPE_PTR: + if (TokenSpace == NULL) { + PcdData = mPcd->GetPtr (TokenNumber); + } else { + PcdData = mPiPcd->GetPtr (TokenSpace, TokenNumber); + } + Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x\n", TokenNumber, RetString, PcdInfo->PcdSize); + DumpHex (2, 0, PcdInfo->PcdSize, PcdData); + break; + default: + return; + } + + if (RetString != NULL) { + FreePool (RetString); + } + Print (L"\n"); +} + +/** + Show one or all PCDs' info. + + @param[in] InputPcdName Pointer to PCD name to show. If NULL, show all PCDs' info. + + @retval EFI_SUCCESS Command completed successfully. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to run the command. + @retval EFI_ABORTED Aborted by user. + @retval EFI_NOT_FOUND The specified PCD is not found. +**/ +static +EFI_STATUS +ProcessPcd ( + IN CHAR16 *InputPcdName + ) +{ + EFI_STATUS Status; + EFI_GUID *TokenSpace; + UINTN TokenNumber; + EFI_PCD_INFO PcdInfo; + BOOLEAN Found; + UINTN PcdNameSize; + + PcdInfo.PcdName = NULL; + PcdInfo.PcdSize = 0; + PcdInfo.PcdType = 0xFF; + Found = FALSE; + + Print (L"Current system SKU ID: 0x%x\n\n", mPiPcdInfo->GetSku ()); + + TokenSpace = NULL; + do { + TokenNumber = 0; + do { + Status = mPiPcd->GetNextToken (TokenSpace, &TokenNumber); + if (!EFI_ERROR (Status) && TokenNumber != 0) { + if (TokenSpace == NULL) { + // + // PCD in default Token Space. + // + mPcdInfo->GetInfo (TokenNumber, &PcdInfo); + } else { + mPiPcdInfo->GetInfo (TokenSpace, TokenNumber, &PcdInfo); + } + if (InputPcdName != NULL) { + if (PcdInfo.PcdName == NULL) { + continue; + } + PcdNameSize = AsciiStrSize (PcdInfo.PcdName) * sizeof (CHAR16); + if (mTempPcdNameBuffer == NULL) { + mTempPcdNameBufferSize = PcdNameSize; + mTempPcdNameBuffer = AllocatePool (mTempPcdNameBufferSize); + } else if (mTempPcdNameBufferSize < PcdNameSize) { + mTempPcdNameBuffer = ReallocatePool (mTempPcdNameBufferSize, PcdNameSize, mTempPcdNameBuffer); + mTempPcdNameBufferSize = PcdNameSize; + } + if (mTempPcdNameBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + AsciiStrToUnicodeStrS (PcdInfo.PcdName, mTempPcdNameBuffer, mTempPcdNameBufferSize / sizeof (CHAR16)); + // + // Compare the input PCD name with the PCD name in PCD database. + // + if ((StrStr (mTempPcdNameBuffer, InputPcdName) != NULL) || + (mUnicodeCollation != NULL && mUnicodeCollation->MetaiMatch (mUnicodeCollation, mTempPcdNameBuffer, InputPcdName))) { + // + // Found matched PCD. + // + DumpPcdInfo (TokenSpace, TokenNumber, &PcdInfo); + Found = TRUE; + } + } else { + DumpPcdInfo (TokenSpace, TokenNumber, &PcdInfo); + } + } + } while (!EFI_ERROR (Status) && TokenNumber != 0); + + Status = mPiPcd->GetNextTokenSpace ((CONST EFI_GUID **) &TokenSpace); + } while (!EFI_ERROR (Status) && TokenSpace != NULL); + + if ((InputPcdName != NULL) && !Found) { + // + // The specified PCD is not found, print error. + // + Print (L"%EError. %NNo matching PCD found: %s.\n", InputPcdName); + return EFI_NOT_FOUND; + } + return EFI_SUCCESS; +} + +/** + Main entrypoint for DumpDynPcd shell application. + + @param[in] ImageHandle The image handle. + @param[in] SystemTable The system table. + + @retval EFI_SUCCESS Command completed successfully. + @retval EFI_INVALID_PARAMETER Command usage error. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to run the command. + @retval EFI_ABORTED Aborted by user. + @retval EFI_NOT_FOUND The specified PCD is not found. + @retval Others Error status returned from gBS->LocateProtocol. +**/ +EFI_STATUS +EFIAPI +DumpDynPcdMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + CHAR16 *InputPcdName; + + InputPcdName = NULL; + + Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID **) &mUnicodeCollation); + if (EFI_ERROR (Status)) { + mUnicodeCollation = NULL; + } + + Status = gBS->LocateProtocol (&gEfiPcdProtocolGuid, NULL, (VOID **) &mPiPcd); + if (EFI_ERROR (Status)) { + Print (L"DumpDynPcd: %EError. %NPI PCD protocol is not present.\n"); + return Status; + } + + Status = gBS->LocateProtocol (&gEfiGetPcdInfoProtocolGuid, NULL, (VOID **) &mPiPcdInfo); + if (EFI_ERROR (Status)) { + Print (L"DumpDynPcd: %EError. %NPI PCD info protocol is not present.\n"); + return Status; + } + + Status = gBS->LocateProtocol (&gPcdProtocolGuid, NULL, (VOID **) &mPcd); + if (EFI_ERROR (Status)) { + Print (L"DumpDynPcd: %EError. %NPCD protocol is not present.\n"); + return Status; + } + + Status = gBS->LocateProtocol (&gGetPcdInfoProtocolGuid, NULL, (VOID **) &mPcdInfo); + if (EFI_ERROR (Status)) { + Print (L"DumpDynPcd: %EError. %NPCD info protocol is not present.\n"); + return Status; + } + + // + // get the command line arguments + // + Status = GetArg(); + if (EFI_ERROR(Status)){ + Print (L"DumpDynPcd: %EError. %NThe input parameters are not recognized.\n"); + Status = EFI_INVALID_PARAMETER; + return Status; + } + + if (Argc > 2){ + Print (L"DumpDynPcd: %EError. %NToo many arguments specified.\n"); + Status = EFI_INVALID_PARAMETER; + return Status; + } + + if (Argc == 1){ + Status = ProcessPcd (InputPcdName); + goto Done; + } + + if ((StrCmp(Argv[1], L"-?") == 0)||(StrCmp(Argv[1], L"-h") == 0)||(StrCmp(Argv[1], L"-H") == 0)){ + ShowHelp (); + goto Done; + } else { + if ((StrCmp(Argv[1], L"-v") == 0)||(StrCmp(Argv[1], L"-V") == 0)){ + ShowVersion (); + goto Done; + } else { + if (StrStr(Argv[1], L"-") != NULL){ + Print (L"DumpDynPcd: %EError. %NThe argument '%B%s%N' is invalid.\n", Argv[1]); + goto Done; + } + } + } + + InputPcdName = Argv[1]; + Status = ProcessPcd (InputPcdName); + + Done: + + if (mTempPcdNameBuffer != NULL) { + FreePool (mTempPcdNameBuffer); + } + + return Status; +} + diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf new file mode 100644 index 00000000..afacf1a8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf @@ -0,0 +1,50 @@ +## @file +# DumpDynPcd is a shell application to dump dynamic pcd information. +# +# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = DumpDynPcd + FILE_GUID = 31ADA2B2-62EA-4866-9B87-03FEA8425974 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = DumpDynPcdMain + +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + DumpDynPcd.c + DumpDynPcdStr.uni + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + UefiApplicationEntryPoint + DebugLib + MemoryAllocationLib + UefiLib + UefiBootServicesTableLib + +[Protocols] + gEfiUnicodeCollation2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiPcdProtocolGuid ## CONSUMES + gPcdProtocolGuid ## CONSUMES + gEfiGetPcdInfoProtocolGuid ## CONSUMES + gGetPcdInfoProtocolGuid ## CONSUMES + gEfiShellParametersProtocolGuid ## CONSUMES + diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/DumpDynPcd/DumpDynPcdStr.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/DumpDynPcd/DumpDynPcdStr.uni new file mode 100644 index 00000000..f0ee9821 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/DumpDynPcd/DumpDynPcdStr.uni @@ -0,0 +1,28 @@ +//
+// DumpDynPcd is a shell application to dump dynamic pcd information.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+//**/
+
+/=#
+
+#langdef en-US "English"
+
+#string STR_DUMP_DYN_PCD_HELP_INFORMATION #language en-US ""
+ ".TH DumpDynPcd 0 "Dump dynamic[ex] PCD info."\r\n"
+ ".SH NAME\r\n"
+ "Dump dynamic[ex] PCD info.\r\n"
+ ".SH SYNOPSIS\r\n"
+ " \r\n"
+ "DumpDynPcd [PcdName].\r\n"
+ ".SH OPTIONS\r\n"
+ " \r\n"
+ " PcdName Specifies the name of PCD.\r\n"
+ " A literal[or partial] name or a pattern as specified in\r\n"
+ " the MetaiMatch() function of the EFI_UNICODE_COLLATION2_PROCOOL.\r\n"
+ " If it is absent, dump all PCDs' info.\r\n"
+ "The PCD data is printed as hexadecimal dump.\n"
+ "\r\n"
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/HelloWorld/HelloWorld.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/HelloWorld/HelloWorld.c new file mode 100644 index 00000000..68b13287 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/HelloWorld/HelloWorld.c @@ -0,0 +1,60 @@ +/** @file + This sample application bases on HelloWorld PCD setting + to print "UEFI Hello World!" to the UEFI Console. + + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Uefi.h> +#include <Library/PcdLib.h> +#include <Library/UefiLib.h> +#include <Library/UefiApplicationEntryPoint.h> + +// +// String token ID of help message text. +// Shell supports to find help message in the resource section of an application image if +// .MAN file is not found. This global variable is added to make build tool recognizes +// that the help string is consumed by user and then build tool will add the string into +// the resource section. Thus the application can use '-?' option to show help message in +// Shell. +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_STRING_ID mStringHelpTokenId = STRING_TOKEN (STR_HELLO_WORLD_HELP_INFORMATION); + +/** + The user Entry Point for Application. The user code starts with this function + as the real entry point for the application. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +UefiMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + UINT32 Index; + + Index = 0; + + // + // Three PCD type (FeatureFlag, UINT32 and String) are used as the sample. + // + if (FeaturePcdGet (PcdHelloWorldPrintEnable)) { + for (Index = 0; Index < PcdGet32 (PcdHelloWorldPrintTimes); Index ++) { + // + // Use UefiLib Print API to print string to UEFI console + // + Print ((CHAR16*)PcdGetPtr (PcdHelloWorldPrintString)); + } + } + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/HelloWorld/HelloWorld.inf b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/HelloWorld/HelloWorld.inf new file mode 100644 index 00000000..340601e1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/HelloWorld/HelloWorld.inf @@ -0,0 +1,57 @@ +## @file +# Sample UEFI Application Reference EDKII Module. +# +# This is a sample shell application that will print "UEFI Hello World!" to the +# UEFI Console based on PCD setting. +# +# It demos how to use EDKII PCD mechanism to make code more flexible. +# +# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = HelloWorld + MODULE_UNI_FILE = HelloWorld.uni + FILE_GUID = 6987936E-ED34-44db-AE97-1FA5E4ED2116 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = UefiMain + +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + HelloWorld.c + HelloWorldStr.uni + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + UefiLib + PcdLib + +[FeaturePcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintEnable ## CONSUMES + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintString ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintTimes ## SOMETIMES_CONSUMES + +[UserExtensions.TianoCore."ExtraFiles"] + HelloWorldExtra.uni diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/HelloWorld/HelloWorld.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/HelloWorld/HelloWorld.uni new file mode 100644 index 00000000..aade016c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/HelloWorld/HelloWorld.uni @@ -0,0 +1,19 @@ +// /** @file
+// Sample UEFI Application Reference EDKII Module.
+//
+// This is a sample shell application that will print "UEFI Hello World!" to the
+// UEFI Console based on PCD setting.
+//
+// It demos how to use EDKII PCD mechanism to make code more flexible.
+//
+// Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Sample UEFI Application Reference EDKII Module"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This is a sample shell application that will print UEFI Hello World! to the UEFI Console based on PCD setting. It demonstrates how to use the EDKII PCD mechanism to make code more flexible"
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/HelloWorld/HelloWorldExtra.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/HelloWorld/HelloWorldExtra.uni new file mode 100644 index 00000000..70dd81e8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/HelloWorld/HelloWorldExtra.uni @@ -0,0 +1,14 @@ +// /** @file
+// HelloWorld Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Hello World Application"
+
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/HelloWorld/HelloWorldStr.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/HelloWorld/HelloWorldStr.uni new file mode 100644 index 00000000..eb03b78d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/HelloWorld/HelloWorldStr.uni @@ -0,0 +1,22 @@ +// /** @file
+// Sample UEFI Application Reference EDKII Module.
+//
+// This is a sample shell application that will print "UEFI Hello World!" to the
+// UEFI Console based on PCD setting.
+//
+// It demos how to use EDKII PCD mechanism to make code more flexible.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+/=#
+
+#langdef en-US "English"
+
+#string STR_HELLO_WORLD_HELP_INFORMATION #language en-US ""
+".TH HelloWorld 0 "Displays a \"UEFI Hello World!\" string."\r\n"
+".SH NAME\r\n"
+"HelloWorld application.\r\n"
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.c new file mode 100644 index 00000000..5c63e6c6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.c @@ -0,0 +1,1361 @@ +/** @file + + Copyright (c) 2014 - 2017, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Uefi.h> +#include <PiDxe.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiLib.h> +#include <Library/UefiApplicationEntryPoint.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/DebugLib.h> +#include <Library/DxeServicesLib.h> +#include <Library/PrintLib.h> + +#include <Protocol/SmmCommunication.h> +#include <Protocol/SmmAccess2.h> + +#include <Guid/MemoryProfile.h> +#include <Guid/PiSmmCommunicationRegionTable.h> + +CHAR8 *mActionString[] = { + "Unknown", + "gBS->AllocatePages", + "gBS->FreePages", + "gBS->AllocatePool", + "gBS->FreePool", +}; + +CHAR8 *mSmmActionString[] = { + "SmmUnknown", + "gSmst->SmmAllocatePages", + "gSmst->SmmFreePages", + "gSmst->SmmAllocatePool", + "gSmst->SmmFreePool", +}; + +typedef struct { + MEMORY_PROFILE_ACTION Action; + CHAR8 *String; +} ACTION_STRING; + +ACTION_STRING mExtActionString[] = { + {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_PAGES, "Lib:AllocatePages"}, + {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_PAGES, "Lib:AllocateRuntimePages"}, + {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_PAGES, "Lib:AllocateReservedPages"}, + {MEMORY_PROFILE_ACTION_LIB_FREE_PAGES, "Lib:FreePages"}, + {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_PAGES, "Lib:AllocateAlignedPages"}, + {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RUNTIME_PAGES, "Lib:AllocateAlignedRuntimePages"}, + {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RESERVED_PAGES, "Lib:AllocateAlignedReservedPages"}, + {MEMORY_PROFILE_ACTION_LIB_FREE_ALIGNED_PAGES, "Lib:FreeAlignedPages"}, + {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_POOL, "Lib:AllocatePool"}, + {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_POOL, "Lib:AllocateRuntimePool"}, + {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_POOL, "Lib:AllocateReservedPool"}, + {MEMORY_PROFILE_ACTION_LIB_FREE_POOL, "Lib:FreePool"}, + {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ZERO_POOL, "Lib:AllocateZeroPool"}, + {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_ZERO_POOL, "Lib:AllocateRuntimeZeroPool"}, + {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_ZERO_POOL, "Lib:AllocateReservedZeroPool"}, + {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_COPY_POOL, "Lib:AllocateCopyPool"}, + {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_COPY_POOL, "Lib:AllocateRuntimeCopyPool"}, + {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_COPY_POOL, "Lib:AllocateReservedCopyPool"}, + {MEMORY_PROFILE_ACTION_LIB_REALLOCATE_POOL, "Lib:ReallocatePool"}, + {MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RUNTIME_POOL, "Lib:ReallocateRuntimePool"}, + {MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RESERVED_POOL, "Lib:ReallocateReservedPool"}, +}; + +CHAR8 mUserDefinedActionString[] = {"UserDefined-0x80000000"}; + +CHAR8 *mMemoryTypeString[] = { + "EfiReservedMemoryType", + "EfiLoaderCode", + "EfiLoaderData", + "EfiBootServicesCode", + "EfiBootServicesData", + "EfiRuntimeServicesCode", + "EfiRuntimeServicesData", + "EfiConventionalMemory", + "EfiUnusableMemory", + "EfiACPIReclaimMemory", + "EfiACPIMemoryNVS", + "EfiMemoryMappedIO", + "EfiMemoryMappedIOPortSpace", + "EfiPalCode", + "EfiPersistentMemory", + "EfiOSReserved", + "EfiOemReserved", +}; + +CHAR8 *mSubsystemString[] = { + "Unknown", + "NATIVE", + "WINDOWS_GUI", + "WINDOWS_CUI", + "Unknown", + "Unknown", + "Unknown", + "POSIX_CUI", + "Unknown", + "WINDOWS_CE_GUI", + "EFI_APPLICATION", + "EFI_BOOT_SERVICE_DRIVER", + "EFI_RUNTIME_DRIVER", + "EFI_ROM", + "XBOX", + "Unknown", +}; + +CHAR8 *mFileTypeString[] = { + "Unknown", + "RAW", + "FREEFORM", + "SECURITY_CORE", + "PEI_CORE", + "DXE_CORE", + "PEIM", + "DRIVER", + "COMBINED_PEIM_DRIVER", + "APPLICATION", + "SMM", + "FIRMWARE_VOLUME_IMAGE", + "COMBINED_SMM_DXE", + "SMM_CORE", +}; + +#define PROFILE_NAME_STRING_LENGTH 64 +CHAR8 mNameString[PROFILE_NAME_STRING_LENGTH + 1]; + +// +// Profile summary information +// +#define MEMORY_PROFILE_ALLOC_SUMMARY_INFO_SIGNATURE SIGNATURE_32 ('M','P','A','S') +#define MEMORY_PROFILE_ALLOC_SUMMARY_INFO_REVISION 0x0001 + +typedef struct { + MEMORY_PROFILE_COMMON_HEADER Header; + PHYSICAL_ADDRESS CallerAddress; + MEMORY_PROFILE_ACTION Action; + CHAR8 *ActionString; + UINT32 AllocateCount; + UINT64 TotalSize; +} MEMORY_PROFILE_ALLOC_SUMMARY_INFO; + +typedef struct { + UINT32 Signature; + MEMORY_PROFILE_ALLOC_SUMMARY_INFO AllocSummaryInfo; + LIST_ENTRY Link; +} MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA; + +typedef struct { + UINT32 Signature; + MEMORY_PROFILE_DRIVER_INFO *DriverInfo; + LIST_ENTRY *AllocSummaryInfoList; + LIST_ENTRY Link; +} MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA; + +typedef struct { + UINT32 Signature; + MEMORY_PROFILE_CONTEXT *Context; + LIST_ENTRY *DriverSummaryInfoList; +} MEMORY_PROFILE_CONTEXT_SUMMARY_DATA; + +LIST_ENTRY mImageSummaryQueue = INITIALIZE_LIST_HEAD_VARIABLE (mImageSummaryQueue); +MEMORY_PROFILE_CONTEXT_SUMMARY_DATA mMemoryProfileContextSummary; + +/** + Get the file name portion of the Pdb File Name. + + The portion of the Pdb File Name between the last backslash and + either a following period or the end of the string is copied into + AsciiBuffer. The name is truncated, if necessary, to ensure that + AsciiBuffer is not overrun. + + @param[in] PdbFileName Pdb file name. + @param[out] AsciiBuffer The resultant Ascii File Name. + +**/ +VOID +GetShortPdbFileName ( + IN CHAR8 *PdbFileName, + OUT CHAR8 *AsciiBuffer + ) +{ + UINTN IndexPdb; // Current work location within a Pdb string. + UINTN IndexBuffer; // Current work location within a Buffer string. + UINTN StartIndex; + UINTN EndIndex; + + ZeroMem (AsciiBuffer, PROFILE_NAME_STRING_LENGTH + 1); + + if (PdbFileName == NULL) { + AsciiStrnCpyS (AsciiBuffer, PROFILE_NAME_STRING_LENGTH + 1, " ", 1); + } else { + StartIndex = 0; + for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++); + for (IndexPdb = 0; PdbFileName[IndexPdb] != 0; IndexPdb++) { + if ((PdbFileName[IndexPdb] == '\\') || (PdbFileName[IndexPdb] == '/')) { + StartIndex = IndexPdb + 1; + } + + if (PdbFileName[IndexPdb] == '.') { + EndIndex = IndexPdb; + } + } + + IndexBuffer = 0; + for (IndexPdb = StartIndex; IndexPdb < EndIndex; IndexPdb++) { + AsciiBuffer[IndexBuffer] = PdbFileName[IndexPdb]; + IndexBuffer++; + if (IndexBuffer >= PROFILE_NAME_STRING_LENGTH) { + AsciiBuffer[PROFILE_NAME_STRING_LENGTH] = 0; + break; + } + } + } +} + +/** + Get a human readable name for an image. + The following methods will be tried orderly: + 1. Image PDB + 2. FFS UI section + 3. Image GUID + + @param[in] DriverInfo Pointer to memory profile driver info. + + @return The resulting Ascii name string is stored in the mNameString global array. + +**/ +CHAR8 * +GetDriverNameString ( + IN MEMORY_PROFILE_DRIVER_INFO *DriverInfo + ) +{ + EFI_STATUS Status; + CHAR16 *NameString; + UINTN StringSize; + + // + // Method 1: Get the name string from image PDB + // + if (DriverInfo->PdbStringOffset != 0) { + GetShortPdbFileName ((CHAR8 *) ((UINTN) DriverInfo + DriverInfo->PdbStringOffset), mNameString); + return mNameString; + } + + if (!IsZeroGuid (&DriverInfo->FileName)) { + // + // Try to get the image's FFS UI section by image GUID + // + NameString = NULL; + StringSize = 0; + Status = GetSectionFromAnyFv ( + &DriverInfo->FileName, + EFI_SECTION_USER_INTERFACE, + 0, + (VOID **) &NameString, + &StringSize + ); + if (!EFI_ERROR (Status)) { + // + // Method 2: Get the name string from FFS UI section + // + if (StrLen (NameString) > PROFILE_NAME_STRING_LENGTH) { + NameString[PROFILE_NAME_STRING_LENGTH] = 0; + } + UnicodeStrToAsciiStrS (NameString, mNameString, sizeof (mNameString)); + FreePool (NameString); + return mNameString; + } + } + + // + // Method 3: Get the name string from image GUID + // + AsciiSPrint (mNameString, sizeof (mNameString), "%g", &DriverInfo->FileName); + return mNameString; +} + +/** + Memory type to string. + + @param[in] MemoryType Memory type. + + @return Pointer to string. + +**/ +CHAR8 * +ProfileMemoryTypeToStr ( + IN EFI_MEMORY_TYPE MemoryType + ) +{ + UINTN Index; + + if ((UINT32) MemoryType >= 0x80000000) { + // + // OS reserved memory type. + // + Index = EfiMaxMemoryType; + } else if ((UINT32) MemoryType >= 0x70000000) { + // + // OEM reserved memory type. + // + Index = EfiMaxMemoryType + 1; + } else { + Index = MemoryType; + } + + return mMemoryTypeString[Index]; +} + +/** + Action to string. + + @param[in] Action Profile action. + @param[in] UserDefinedActionString Pointer to user defined action string. + @param[in] IsForSmm TRUE - SMRAM profile. + FALSE - UEFI memory profile. + + @return Pointer to string. + +**/ +CHAR8 * +ProfileActionToStr ( + IN MEMORY_PROFILE_ACTION Action, + IN CHAR8 *UserDefinedActionString, + IN BOOLEAN IsForSmm + ) +{ + UINTN Index; + UINTN ActionStringCount; + CHAR8 **ActionString; + + if (IsForSmm) { + ActionString = mSmmActionString; + ActionStringCount = ARRAY_SIZE (mSmmActionString); + } else { + ActionString = mActionString; + ActionStringCount = ARRAY_SIZE (mActionString); + } + + if ((UINTN) (UINT32) Action < ActionStringCount) { + return ActionString[Action]; + } + for (Index = 0; Index < ARRAY_SIZE (mExtActionString); Index++) { + if (mExtActionString[Index].Action == Action) { + return mExtActionString[Index].String; + } + } + if ((Action & MEMORY_PROFILE_ACTION_USER_DEFINED_MASK) != 0) { + if (UserDefinedActionString != NULL) { + return UserDefinedActionString; + } + AsciiSPrint (mUserDefinedActionString, sizeof (mUserDefinedActionString), "UserDefined-0x%08x", Action); + return mUserDefinedActionString; + } + + return ActionString[0]; +} + +/** + Dump memory profile allocate information. + + @param[in] DriverInfo Pointer to memory profile driver info. + @param[in] AllocIndex Memory profile alloc info index. + @param[in] AllocInfo Pointer to memory profile alloc info. + @param[in] IsForSmm TRUE - SMRAM profile. + FALSE - UEFI memory profile. + + @return Pointer to next memory profile alloc info. + +**/ +MEMORY_PROFILE_ALLOC_INFO * +DumpMemoryProfileAllocInfo ( + IN MEMORY_PROFILE_DRIVER_INFO *DriverInfo, + IN UINTN AllocIndex, + IN MEMORY_PROFILE_ALLOC_INFO *AllocInfo, + IN BOOLEAN IsForSmm + ) +{ + CHAR8 *ActionString; + + if (AllocInfo->Header.Signature != MEMORY_PROFILE_ALLOC_INFO_SIGNATURE) { + return NULL; + } + + if (AllocInfo->ActionStringOffset != 0) { + ActionString = (CHAR8 *) ((UINTN) AllocInfo + AllocInfo->ActionStringOffset); + } else { + ActionString = NULL; + } + + Print (L" MEMORY_PROFILE_ALLOC_INFO (0x%x)\n", AllocIndex); + Print (L" Signature - 0x%08x\n", AllocInfo->Header.Signature); + Print (L" Length - 0x%04x\n", AllocInfo->Header.Length); + Print (L" Revision - 0x%04x\n", AllocInfo->Header.Revision); + Print (L" CallerAddress - 0x%016lx (Offset: 0x%08x)\n", AllocInfo->CallerAddress, (UINTN) (AllocInfo->CallerAddress - DriverInfo->ImageBase)); + Print (L" SequenceId - 0x%08x\n", AllocInfo->SequenceId); + Print (L" Action - 0x%08x (%a)\n", AllocInfo->Action, ProfileActionToStr (AllocInfo->Action, ActionString, IsForSmm)); + Print (L" MemoryType - 0x%08x (%a)\n", AllocInfo->MemoryType, ProfileMemoryTypeToStr (AllocInfo->MemoryType)); + Print (L" Buffer - 0x%016lx\n", AllocInfo->Buffer); + Print (L" Size - 0x%016lx\n", AllocInfo->Size); + + return (MEMORY_PROFILE_ALLOC_INFO *) ((UINTN) AllocInfo + AllocInfo->Header.Length); +} + +/** + Dump memory profile driver information. + + @param[in] DriverIndex Memory profile driver info index. + @param[in] DriverInfo Pointer to memory profile driver info. + @param[in] IsForSmm TRUE - SMRAM profile. + FALSE - UEFI memory profile. + + @return Pointer to next memory profile driver info. + +**/ +MEMORY_PROFILE_DRIVER_INFO * +DumpMemoryProfileDriverInfo ( + IN UINTN DriverIndex, + IN MEMORY_PROFILE_DRIVER_INFO *DriverInfo, + IN BOOLEAN IsForSmm + ) +{ + UINTN TypeIndex; + MEMORY_PROFILE_ALLOC_INFO *AllocInfo; + UINTN AllocIndex; + CHAR8 *NameString; + + if (DriverInfo->Header.Signature != MEMORY_PROFILE_DRIVER_INFO_SIGNATURE) { + return NULL; + } + Print (L" MEMORY_PROFILE_DRIVER_INFO (0x%x)\n", DriverIndex); + Print (L" Signature - 0x%08x\n", DriverInfo->Header.Signature); + Print (L" Length - 0x%04x\n", DriverInfo->Header.Length); + Print (L" Revision - 0x%04x\n", DriverInfo->Header.Revision); + NameString = GetDriverNameString (DriverInfo); + Print (L" FileName - %a\n", NameString); + if (DriverInfo->PdbStringOffset != 0) { + Print (L" Pdb - %a\n", (CHAR8 *) ((UINTN) DriverInfo + DriverInfo->PdbStringOffset)); + } + Print (L" ImageBase - 0x%016lx\n", DriverInfo->ImageBase); + Print (L" ImageSize - 0x%016lx\n", DriverInfo->ImageSize); + Print (L" EntryPoint - 0x%016lx\n", DriverInfo->EntryPoint); + Print (L" ImageSubsystem - 0x%04x (%a)\n", DriverInfo->ImageSubsystem, mSubsystemString[(DriverInfo->ImageSubsystem < sizeof(mSubsystemString)/sizeof(mSubsystemString[0])) ? DriverInfo->ImageSubsystem : 0]); + Print (L" FileType - 0x%02x (%a)\n", DriverInfo->FileType, mFileTypeString[(DriverInfo->FileType < sizeof(mFileTypeString)/sizeof(mFileTypeString[0])) ? DriverInfo->FileType : 0]); + Print (L" CurrentUsage - 0x%016lx\n", DriverInfo->CurrentUsage); + Print (L" PeakUsage - 0x%016lx\n", DriverInfo->PeakUsage); + for (TypeIndex = 0; TypeIndex < sizeof (DriverInfo->CurrentUsageByType) / sizeof (DriverInfo->CurrentUsageByType[0]); TypeIndex++) { + if ((DriverInfo->CurrentUsageByType[TypeIndex] != 0) || + (DriverInfo->PeakUsageByType[TypeIndex] != 0)) { + Print (L" CurrentUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, DriverInfo->CurrentUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]); + Print (L" PeakUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, DriverInfo->PeakUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]); + } + } + Print (L" AllocRecordCount - 0x%08x\n", DriverInfo->AllocRecordCount); + + AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *) ((UINTN) DriverInfo + DriverInfo->Header.Length); + for (AllocIndex = 0; AllocIndex < DriverInfo->AllocRecordCount; AllocIndex++) { + AllocInfo = DumpMemoryProfileAllocInfo (DriverInfo, AllocIndex, AllocInfo, IsForSmm); + if (AllocInfo == NULL) { + return NULL; + } + } + return (MEMORY_PROFILE_DRIVER_INFO *) AllocInfo; +} + +/** + Dump memory profile context information. + + @param[in] Context Pointer to memory profile context. + @param[in] IsForSmm TRUE - SMRAM profile. + FALSE - UEFI memory profile. + + @return Pointer to the end of memory profile context buffer. + +**/ +VOID * +DumpMemoryProfileContext ( + IN MEMORY_PROFILE_CONTEXT *Context, + IN BOOLEAN IsForSmm + ) +{ + UINTN TypeIndex; + MEMORY_PROFILE_DRIVER_INFO *DriverInfo; + UINTN DriverIndex; + + if (Context->Header.Signature != MEMORY_PROFILE_CONTEXT_SIGNATURE) { + return NULL; + } + Print (L"MEMORY_PROFILE_CONTEXT\n"); + Print (L" Signature - 0x%08x\n", Context->Header.Signature); + Print (L" Length - 0x%04x\n", Context->Header.Length); + Print (L" Revision - 0x%04x\n", Context->Header.Revision); + Print (L" CurrentTotalUsage - 0x%016lx\n", Context->CurrentTotalUsage); + Print (L" PeakTotalUsage - 0x%016lx\n", Context->PeakTotalUsage); + for (TypeIndex = 0; TypeIndex < sizeof (Context->CurrentTotalUsageByType) / sizeof (Context->CurrentTotalUsageByType[0]); TypeIndex++) { + if ((Context->CurrentTotalUsageByType[TypeIndex] != 0) || + (Context->PeakTotalUsageByType[TypeIndex] != 0)) { + Print (L" CurrentTotalUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, Context->CurrentTotalUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]); + Print (L" PeakTotalUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, Context->PeakTotalUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]); + } + } + Print (L" TotalImageSize - 0x%016lx\n", Context->TotalImageSize); + Print (L" ImageCount - 0x%08x\n", Context->ImageCount); + Print (L" SequenceCount - 0x%08x\n", Context->SequenceCount); + + DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) ((UINTN) Context + Context->Header.Length); + for (DriverIndex = 0; DriverIndex < Context->ImageCount; DriverIndex++) { + DriverInfo = DumpMemoryProfileDriverInfo (DriverIndex, DriverInfo, IsForSmm); + if (DriverInfo == NULL) { + return NULL; + } + } + return (VOID *) DriverInfo; +} + +/** + Dump memory profile descriptor information. + + @param[in] DescriptorIndex Memory profile descriptor index. + @param[in] Descriptor Pointer to memory profile descriptor. + + @return Pointer to next memory profile descriptor. + +**/ +MEMORY_PROFILE_DESCRIPTOR * +DumpMemoryProfileDescriptor ( + IN UINTN DescriptorIndex, + IN MEMORY_PROFILE_DESCRIPTOR *Descriptor + ) +{ + if (Descriptor->Header.Signature != MEMORY_PROFILE_DESCRIPTOR_SIGNATURE) { + return NULL; + } + Print (L" MEMORY_PROFILE_DESCRIPTOR (0x%x)\n", DescriptorIndex); + Print (L" Signature - 0x%08x\n", Descriptor->Header.Signature); + Print (L" Length - 0x%04x\n", Descriptor->Header.Length); + Print (L" Revision - 0x%04x\n", Descriptor->Header.Revision); + Print (L" Address - 0x%016lx\n", Descriptor->Address); + Print (L" Size - 0x%016lx\n", Descriptor->Size); + + return (MEMORY_PROFILE_DESCRIPTOR *) ((UINTN) Descriptor + Descriptor->Header.Length); +} + +/** + Dump memory profile free memory information. + + @param[in] FreeMemory Pointer to memory profile free memory. + + @return Pointer to the end of memory profile free memory buffer. + +**/ +VOID * +DumpMemoryProfileFreeMemory ( + IN MEMORY_PROFILE_FREE_MEMORY *FreeMemory + ) +{ + MEMORY_PROFILE_DESCRIPTOR *Descriptor; + UINTN DescriptorIndex; + + if (FreeMemory->Header.Signature != MEMORY_PROFILE_FREE_MEMORY_SIGNATURE) { + return NULL; + } + Print (L"MEMORY_PROFILE_FREE_MEMORY\n"); + Print (L" Signature - 0x%08x\n", FreeMemory->Header.Signature); + Print (L" Length - 0x%04x\n", FreeMemory->Header.Length); + Print (L" Revision - 0x%04x\n", FreeMemory->Header.Revision); + Print (L" TotalFreeMemoryPages - 0x%016lx\n", FreeMemory->TotalFreeMemoryPages); + Print (L" FreeMemoryEntryCount - 0x%08x\n", FreeMemory->FreeMemoryEntryCount); + + Descriptor = (MEMORY_PROFILE_DESCRIPTOR *) ((UINTN) FreeMemory + FreeMemory->Header.Length); + for (DescriptorIndex = 0; DescriptorIndex < FreeMemory->FreeMemoryEntryCount; DescriptorIndex++) { + Descriptor = DumpMemoryProfileDescriptor (DescriptorIndex, Descriptor); + if (Descriptor == NULL) { + return NULL; + } + } + + return (VOID *) Descriptor; +} + +/** + Dump memory profile memory range information. + + @param[in] MemoryRange Pointer to memory profile memory range. + + @return Pointer to the end of memory profile memory range buffer. + +**/ +VOID * +DumpMemoryProfileMemoryRange ( + IN MEMORY_PROFILE_MEMORY_RANGE *MemoryRange + ) +{ + MEMORY_PROFILE_DESCRIPTOR *Descriptor; + UINTN DescriptorIndex; + + if (MemoryRange->Header.Signature != MEMORY_PROFILE_MEMORY_RANGE_SIGNATURE) { + return NULL; + } + Print (L"MEMORY_PROFILE_MEMORY_RANGE\n"); + Print (L" Signature - 0x%08x\n", MemoryRange->Header.Signature); + Print (L" Length - 0x%04x\n", MemoryRange->Header.Length); + Print (L" Revision - 0x%04x\n", MemoryRange->Header.Revision); + Print (L" MemoryRangeCount - 0x%08x\n", MemoryRange->MemoryRangeCount); + + Descriptor = (MEMORY_PROFILE_DESCRIPTOR *) ((UINTN) MemoryRange + MemoryRange->Header.Length); + for (DescriptorIndex = 0; DescriptorIndex < MemoryRange->MemoryRangeCount; DescriptorIndex++) { + Descriptor = DumpMemoryProfileDescriptor (DescriptorIndex, Descriptor); + if (Descriptor == NULL) { + return NULL; + } + } + + return (VOID *) Descriptor; +} + +/** + Scan memory profile by Signature. + + @param[in] ProfileBuffer Memory profile base address. + @param[in] ProfileSize Memory profile size. + @param[in] Signature Signature. + + @return Pointer to the structure with the signature. + +**/ +VOID * +ScanMemoryProfileBySignature ( + IN PHYSICAL_ADDRESS ProfileBuffer, + IN UINT64 ProfileSize, + IN UINT32 Signature + ) +{ + MEMORY_PROFILE_COMMON_HEADER *CommonHeader; + UINTN ProfileEnd; + + ProfileEnd = (UINTN) (ProfileBuffer + ProfileSize); + CommonHeader = (MEMORY_PROFILE_COMMON_HEADER *) (UINTN) ProfileBuffer; + while ((UINTN) CommonHeader < ProfileEnd) { + if (CommonHeader->Signature == Signature) { + // + // Found it. + // + return (VOID *) CommonHeader; + } + if (CommonHeader->Length == 0) { + ASSERT (FALSE); + return NULL; + } + CommonHeader = (MEMORY_PROFILE_COMMON_HEADER *) ((UINTN) CommonHeader + CommonHeader->Length); + } + + return NULL; +} + +/** + Dump memory profile information. + + @param[in] ProfileBuffer Memory profile base address. + @param[in] ProfileSize Memory profile size. + @param[in] IsForSmm TRUE - SMRAM profile. + FALSE - UEFI memory profile. + +**/ +VOID +DumpMemoryProfile ( + IN PHYSICAL_ADDRESS ProfileBuffer, + IN UINT64 ProfileSize, + IN BOOLEAN IsForSmm + ) +{ + MEMORY_PROFILE_CONTEXT *Context; + MEMORY_PROFILE_FREE_MEMORY *FreeMemory; + MEMORY_PROFILE_MEMORY_RANGE *MemoryRange; + + Context = (MEMORY_PROFILE_CONTEXT *) ScanMemoryProfileBySignature (ProfileBuffer, ProfileSize, MEMORY_PROFILE_CONTEXT_SIGNATURE); + if (Context != NULL) { + DumpMemoryProfileContext (Context, IsForSmm); + } + + FreeMemory = (MEMORY_PROFILE_FREE_MEMORY *) ScanMemoryProfileBySignature (ProfileBuffer, ProfileSize, MEMORY_PROFILE_FREE_MEMORY_SIGNATURE); + if (FreeMemory != NULL) { + DumpMemoryProfileFreeMemory (FreeMemory); + } + + MemoryRange = (MEMORY_PROFILE_MEMORY_RANGE *) ScanMemoryProfileBySignature (ProfileBuffer, ProfileSize, MEMORY_PROFILE_MEMORY_RANGE_SIGNATURE); + if (MemoryRange != NULL) { + DumpMemoryProfileMemoryRange (MemoryRange); + } +} + +/** + Get Allocate summary information structure by caller address. + + @param[in] CallerAddress Caller address. + @param[in] DriverSummaryInfoData Driver summary information data structure. + + @return Allocate summary information structure by caller address. + +**/ +MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA * +GetAllocSummaryInfoByCallerAddress ( + IN PHYSICAL_ADDRESS CallerAddress, + IN MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA *DriverSummaryInfoData + ) +{ + LIST_ENTRY *AllocSummaryInfoList; + LIST_ENTRY *AllocSummaryLink; + MEMORY_PROFILE_ALLOC_SUMMARY_INFO *AllocSummaryInfo; + MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA *AllocSummaryInfoData; + + AllocSummaryInfoList = DriverSummaryInfoData->AllocSummaryInfoList; + + for (AllocSummaryLink = AllocSummaryInfoList->ForwardLink; + AllocSummaryLink != AllocSummaryInfoList; + AllocSummaryLink = AllocSummaryLink->ForwardLink) { + AllocSummaryInfoData = CR ( + AllocSummaryLink, + MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA, + Link, + MEMORY_PROFILE_ALLOC_SUMMARY_INFO_SIGNATURE + ); + AllocSummaryInfo = &AllocSummaryInfoData->AllocSummaryInfo; + if (AllocSummaryInfo->CallerAddress == CallerAddress) { + return AllocSummaryInfoData; + } + } + return NULL; +} + +/** + Create Allocate summary information structure and + link to Driver summary information data structure. + + @param[in, out] DriverSummaryInfoData Driver summary information data structure. + @param[in] AllocInfo Pointer to memory profile alloc info. + + @return Pointer to next memory profile alloc info. + +**/ +MEMORY_PROFILE_ALLOC_INFO * +CreateAllocSummaryInfo ( + IN OUT MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA *DriverSummaryInfoData, + IN MEMORY_PROFILE_ALLOC_INFO *AllocInfo + ) +{ + MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA *AllocSummaryInfoData; + MEMORY_PROFILE_ALLOC_SUMMARY_INFO *AllocSummaryInfo; + + if (AllocInfo->Header.Signature != MEMORY_PROFILE_ALLOC_INFO_SIGNATURE) { + return NULL; + } + + AllocSummaryInfoData = GetAllocSummaryInfoByCallerAddress (AllocInfo->CallerAddress, DriverSummaryInfoData); + if (AllocSummaryInfoData == NULL) { + AllocSummaryInfoData = AllocatePool (sizeof (*AllocSummaryInfoData)); + if (AllocSummaryInfoData == NULL) { + return NULL; + } + + AllocSummaryInfoData->Signature = MEMORY_PROFILE_ALLOC_SUMMARY_INFO_SIGNATURE; + AllocSummaryInfo = &AllocSummaryInfoData->AllocSummaryInfo; + AllocSummaryInfo->Header.Signature = MEMORY_PROFILE_ALLOC_SUMMARY_INFO_SIGNATURE; + AllocSummaryInfo->Header.Length = sizeof (*AllocSummaryInfo); + AllocSummaryInfo->Header.Revision = MEMORY_PROFILE_ALLOC_SUMMARY_INFO_REVISION; + AllocSummaryInfo->CallerAddress = AllocInfo->CallerAddress; + AllocSummaryInfo->Action = AllocInfo->Action; + if (AllocInfo->ActionStringOffset != 0) { + AllocSummaryInfo->ActionString = (CHAR8 *) ((UINTN) AllocInfo + AllocInfo->ActionStringOffset); + } else { + AllocSummaryInfo->ActionString = NULL; + } + AllocSummaryInfo->AllocateCount = 0; + AllocSummaryInfo->TotalSize = 0; + InsertTailList (DriverSummaryInfoData->AllocSummaryInfoList, &AllocSummaryInfoData->Link); + } + AllocSummaryInfo = &AllocSummaryInfoData->AllocSummaryInfo; + AllocSummaryInfo->AllocateCount ++; + AllocSummaryInfo->TotalSize += AllocInfo->Size; + + return (MEMORY_PROFILE_ALLOC_INFO *) ((UINTN) AllocInfo + AllocInfo->Header.Length); +} + +/** + Create Driver summary information structure and + link to Context summary information data structure. + + @param[in, out] ContextSummaryData Context summary information data structure. + @param[in] DriverInfo Pointer to memory profile driver info. + + @return Pointer to next memory profile driver info. + +**/ +MEMORY_PROFILE_DRIVER_INFO * +CreateDriverSummaryInfo ( + IN OUT MEMORY_PROFILE_CONTEXT_SUMMARY_DATA *ContextSummaryData, + IN MEMORY_PROFILE_DRIVER_INFO *DriverInfo + ) +{ + MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA *DriverSummaryInfoData; + MEMORY_PROFILE_ALLOC_INFO *AllocInfo; + UINTN AllocIndex; + + if (DriverInfo->Header.Signature != MEMORY_PROFILE_DRIVER_INFO_SIGNATURE) { + return NULL; + } + + DriverSummaryInfoData = AllocatePool (sizeof (*DriverSummaryInfoData) + sizeof (LIST_ENTRY)); + if (DriverSummaryInfoData == NULL) { + return NULL; + } + DriverSummaryInfoData->Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE; + DriverSummaryInfoData->DriverInfo = DriverInfo; + DriverSummaryInfoData->AllocSummaryInfoList = (LIST_ENTRY *) (DriverSummaryInfoData + 1); + InitializeListHead (DriverSummaryInfoData->AllocSummaryInfoList); + InsertTailList (ContextSummaryData->DriverSummaryInfoList, &DriverSummaryInfoData->Link); + + AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *) ((UINTN) DriverInfo + DriverInfo->Header.Length); + for (AllocIndex = 0; AllocIndex < DriverInfo->AllocRecordCount; AllocIndex++) { + AllocInfo = CreateAllocSummaryInfo (DriverSummaryInfoData, AllocInfo); + if (AllocInfo == NULL) { + return NULL; + } + } + return (MEMORY_PROFILE_DRIVER_INFO *) AllocInfo; +} + +/** + Create Context summary information structure. + + @param[in] ProfileBuffer Memory profile base address. + @param[in] ProfileSize Memory profile size. + + @return Context summary information structure. + +**/ +MEMORY_PROFILE_CONTEXT_SUMMARY_DATA * +CreateContextSummaryData ( + IN PHYSICAL_ADDRESS ProfileBuffer, + IN UINT64 ProfileSize + ) +{ + MEMORY_PROFILE_CONTEXT *Context; + MEMORY_PROFILE_DRIVER_INFO *DriverInfo; + UINTN DriverIndex; + + Context = (MEMORY_PROFILE_CONTEXT *) ScanMemoryProfileBySignature (ProfileBuffer, ProfileSize, MEMORY_PROFILE_CONTEXT_SIGNATURE); + if (Context == NULL) { + return NULL; + } + + mMemoryProfileContextSummary.Signature = MEMORY_PROFILE_CONTEXT_SIGNATURE; + mMemoryProfileContextSummary.Context = Context; + mMemoryProfileContextSummary.DriverSummaryInfoList = &mImageSummaryQueue; + + DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) ((UINTN) Context + Context->Header.Length); + for (DriverIndex = 0; DriverIndex < Context->ImageCount; DriverIndex++) { + DriverInfo = CreateDriverSummaryInfo (&mMemoryProfileContextSummary, DriverInfo); + if (DriverInfo == NULL) { + return NULL; + } + } + + return &mMemoryProfileContextSummary; +} + +/** + Dump Context summary information. + + @param[in] ContextSummaryData Context summary information data. + @param[in] IsForSmm TRUE - SMRAM profile. + FALSE - UEFI memory profile. + +**/ +VOID +DumpContextSummaryData ( + IN MEMORY_PROFILE_CONTEXT_SUMMARY_DATA *ContextSummaryData, + IN BOOLEAN IsForSmm + ) +{ + MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA *DriverSummaryInfoData; + MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA *AllocSummaryInfoData; + LIST_ENTRY *DriverSummaryInfoList; + LIST_ENTRY *DriverSummaryLink; + LIST_ENTRY *AllocSummaryInfoList; + LIST_ENTRY *AllocSummaryLink; + MEMORY_PROFILE_DRIVER_INFO *DriverInfo; + MEMORY_PROFILE_ALLOC_SUMMARY_INFO *AllocSummaryInfo; + CHAR8 *NameString; + + if (ContextSummaryData == NULL) { + return ; + } + + Print (L"\nSummary Data:\n"); + + DriverSummaryInfoList = ContextSummaryData->DriverSummaryInfoList; + for (DriverSummaryLink = DriverSummaryInfoList->ForwardLink; + DriverSummaryLink != DriverSummaryInfoList; + DriverSummaryLink = DriverSummaryLink->ForwardLink) { + DriverSummaryInfoData = CR ( + DriverSummaryLink, + MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA, + Link, + MEMORY_PROFILE_DRIVER_INFO_SIGNATURE + ); + DriverInfo = DriverSummaryInfoData->DriverInfo; + + NameString = GetDriverNameString (DriverInfo); + Print (L"\nDriver - %a (Usage - 0x%08x)", NameString, DriverInfo->CurrentUsage); + if (DriverInfo->CurrentUsage == 0) { + Print (L"\n"); + continue; + } + + if (DriverInfo->PdbStringOffset != 0) { + Print (L" (Pdb - %a)\n", (CHAR8 *) ((UINTN) DriverInfo + DriverInfo->PdbStringOffset)); + } else { + Print (L"\n"); + } + Print (L"Caller List:\n"); + Print(L" Count Size RVA Action\n"); + Print(L"========== ================== ================== (================================)\n"); + AllocSummaryInfoList = DriverSummaryInfoData->AllocSummaryInfoList; + for (AllocSummaryLink = AllocSummaryInfoList->ForwardLink; + AllocSummaryLink != AllocSummaryInfoList; + AllocSummaryLink = AllocSummaryLink->ForwardLink) { + AllocSummaryInfoData = CR ( + AllocSummaryLink, + MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA, + Link, + MEMORY_PROFILE_ALLOC_SUMMARY_INFO_SIGNATURE + ); + AllocSummaryInfo = &AllocSummaryInfoData->AllocSummaryInfo; + + Print(L"0x%08x 0x%016lx <== 0x%016lx", + AllocSummaryInfo->AllocateCount, + AllocSummaryInfo->TotalSize, + AllocSummaryInfo->CallerAddress - DriverInfo->ImageBase + ); + Print (L" (%a)\n", ProfileActionToStr (AllocSummaryInfo->Action, AllocSummaryInfo->ActionString, IsForSmm)); + } + } + return ; +} + +/** + Destroy Context summary information. + + @param[in, out] ContextSummaryData Context summary information data. + +**/ +VOID +DestroyContextSummaryData ( + IN OUT MEMORY_PROFILE_CONTEXT_SUMMARY_DATA *ContextSummaryData + ) +{ + MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA *DriverSummaryInfoData; + MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA *AllocSummaryInfoData; + LIST_ENTRY *DriverSummaryInfoList; + LIST_ENTRY *DriverSummaryLink; + LIST_ENTRY *AllocSummaryInfoList; + LIST_ENTRY *AllocSummaryLink; + + if (ContextSummaryData == NULL) { + return ; + } + + DriverSummaryInfoList = ContextSummaryData->DriverSummaryInfoList; + for (DriverSummaryLink = DriverSummaryInfoList->ForwardLink; + DriverSummaryLink != DriverSummaryInfoList; + ) { + DriverSummaryInfoData = CR ( + DriverSummaryLink, + MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA, + Link, + MEMORY_PROFILE_DRIVER_INFO_SIGNATURE + ); + DriverSummaryLink = DriverSummaryLink->ForwardLink; + + AllocSummaryInfoList = DriverSummaryInfoData->AllocSummaryInfoList; + for (AllocSummaryLink = AllocSummaryInfoList->ForwardLink; + AllocSummaryLink != AllocSummaryInfoList; + ) { + AllocSummaryInfoData = CR ( + AllocSummaryLink, + MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA, + Link, + MEMORY_PROFILE_ALLOC_SUMMARY_INFO_SIGNATURE + ); + AllocSummaryLink = AllocSummaryLink->ForwardLink; + + RemoveEntryList (&AllocSummaryInfoData->Link); + FreePool (AllocSummaryInfoData); + } + + RemoveEntryList (&DriverSummaryInfoData->Link); + FreePool (DriverSummaryInfoData); + } + return ; +} + +/** + Get and dump UEFI memory profile data. + + @return EFI_SUCCESS Get the memory profile data successfully. + @return other Fail to get the memory profile data. + +**/ +EFI_STATUS +GetUefiMemoryProfileData ( + VOID + ) +{ + EFI_STATUS Status; + EDKII_MEMORY_PROFILE_PROTOCOL *ProfileProtocol; + VOID *Data; + UINT64 Size; + MEMORY_PROFILE_CONTEXT_SUMMARY_DATA *MemoryProfileContextSummaryData; + BOOLEAN RecordingState; + + Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID **) &ProfileProtocol); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "UefiMemoryProfile: Locate MemoryProfile protocol - %r\n", Status)); + return Status; + } + + // + // Set recording state if needed. + // + RecordingState = MEMORY_PROFILE_RECORDING_DISABLE; + Status = ProfileProtocol->GetRecordingState (ProfileProtocol, &RecordingState); + if (RecordingState == MEMORY_PROFILE_RECORDING_ENABLE) { + ProfileProtocol->SetRecordingState (ProfileProtocol, MEMORY_PROFILE_RECORDING_DISABLE); + } + + Size = 0; + Data = NULL; + Status = ProfileProtocol->GetData ( + ProfileProtocol, + &Size, + Data + ); + if (Status != EFI_BUFFER_TOO_SMALL) { + Print (L"UefiMemoryProfile: GetData - %r\n", Status); + goto Done; + } + + Data = AllocateZeroPool ((UINTN) Size); + if (Data == NULL) { + Status = EFI_OUT_OF_RESOURCES; + Print (L"UefiMemoryProfile: AllocateZeroPool (0x%x) - %r\n", Size, Status); + return Status; + } + + Status = ProfileProtocol->GetData ( + ProfileProtocol, + &Size, + Data + ); + if (EFI_ERROR (Status)) { + Print (L"UefiMemoryProfile: GetData - %r\n", Status); + goto Done; + } + + + Print (L"UefiMemoryProfileSize - 0x%x\n", Size); + Print (L"======= UefiMemoryProfile begin =======\n"); + DumpMemoryProfile ((PHYSICAL_ADDRESS) (UINTN) Data, Size, FALSE); + + // + // Dump summary information + // + MemoryProfileContextSummaryData = CreateContextSummaryData ((PHYSICAL_ADDRESS) (UINTN) Data, Size); + if (MemoryProfileContextSummaryData != NULL) { + DumpContextSummaryData (MemoryProfileContextSummaryData, FALSE); + DestroyContextSummaryData (MemoryProfileContextSummaryData); + } + + Print (L"======= UefiMemoryProfile end =======\n\n\n"); + +Done: + if (Data != NULL) { + FreePool (Data); + } + + // + // Restore recording state if needed. + // + if (RecordingState == MEMORY_PROFILE_RECORDING_ENABLE) { + ProfileProtocol->SetRecordingState (ProfileProtocol, MEMORY_PROFILE_RECORDING_ENABLE); + } + + return Status; +} + +/** + Get and dump SMRAM profile data. + + @return EFI_SUCCESS Get the SMRAM profile data successfully. + @return other Fail to get the SMRAM profile data. + +**/ +EFI_STATUS +GetSmramProfileData ( + VOID + ) +{ + EFI_STATUS Status; + UINTN CommSize; + UINT8 *CommBuffer; + EFI_SMM_COMMUNICATE_HEADER *CommHeader; + SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *CommGetProfileInfo; + SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET *CommGetProfileData; + SMRAM_PROFILE_PARAMETER_RECORDING_STATE *CommRecordingState; + UINTN ProfileSize; + VOID *ProfileBuffer; + EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication; + UINTN MinimalSizeNeeded; + EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *PiSmmCommunicationRegionTable; + UINT32 Index; + EFI_MEMORY_DESCRIPTOR *Entry; + VOID *Buffer; + UINTN Size; + UINTN Offset; + MEMORY_PROFILE_CONTEXT_SUMMARY_DATA *MemoryProfileContextSummaryData; + BOOLEAN RecordingState; + + ProfileBuffer = NULL; + + Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &SmmCommunication); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "SmramProfile: Locate SmmCommunication protocol - %r\n", Status)); + return Status; + } + + MinimalSizeNeeded = sizeof (EFI_GUID) + + sizeof (UINTN) + + MAX (sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO), + MAX (sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET), + sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE))); + MinimalSizeNeeded += MAX (sizeof (MEMORY_PROFILE_CONTEXT), + MAX (sizeof (MEMORY_PROFILE_DRIVER_INFO), + MAX (sizeof (MEMORY_PROFILE_ALLOC_INFO), + MAX (sizeof (MEMORY_PROFILE_DESCRIPTOR), + MAX (sizeof (MEMORY_PROFILE_FREE_MEMORY), + sizeof (MEMORY_PROFILE_MEMORY_RANGE)))))); + + Status = EfiGetSystemConfigurationTable ( + &gEdkiiPiSmmCommunicationRegionTableGuid, + (VOID **) &PiSmmCommunicationRegionTable + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "SmramProfile: Get PiSmmCommunicationRegionTable - %r\n", Status)); + return Status; + } + ASSERT (PiSmmCommunicationRegionTable != NULL); + Entry = (EFI_MEMORY_DESCRIPTOR *) (PiSmmCommunicationRegionTable + 1); + Size = 0; + for (Index = 0; Index < PiSmmCommunicationRegionTable->NumberOfEntries; Index++) { + if (Entry->Type == EfiConventionalMemory) { + Size = EFI_PAGES_TO_SIZE ((UINTN) Entry->NumberOfPages); + if (Size >= MinimalSizeNeeded) { + break; + } + } + Entry = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) Entry + PiSmmCommunicationRegionTable->DescriptorSize); + } + ASSERT (Index < PiSmmCommunicationRegionTable->NumberOfEntries); + CommBuffer = (UINT8 *) (UINTN) Entry->PhysicalStart; + + // + // Set recording state if needed. + // + RecordingState = MEMORY_PROFILE_RECORDING_DISABLE; + + CommHeader = (EFI_SMM_COMMUNICATE_HEADER *) &CommBuffer[0]; + CopyMem (&CommHeader->HeaderGuid, &gEdkiiMemoryProfileGuid, sizeof (gEdkiiMemoryProfileGuid)); + CommHeader->MessageLength = sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE); + + CommRecordingState = (SMRAM_PROFILE_PARAMETER_RECORDING_STATE *) &CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)]; + CommRecordingState->Header.Command = SMRAM_PROFILE_COMMAND_GET_RECORDING_STATE; + CommRecordingState->Header.DataLength = sizeof (*CommRecordingState); + CommRecordingState->Header.ReturnStatus = (UINT64)-1; + CommRecordingState->RecordingState = MEMORY_PROFILE_RECORDING_DISABLE; + + CommSize = sizeof (EFI_GUID) + sizeof (UINTN) + CommHeader->MessageLength; + Status = SmmCommunication->Communicate (SmmCommunication, CommBuffer, &CommSize); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "SmramProfile: SmmCommunication - %r\n", Status)); + return Status; + } + + if (CommRecordingState->Header.ReturnStatus != 0) { + Print (L"SmramProfile: GetRecordingState - 0x%0x\n", CommRecordingState->Header.ReturnStatus); + return EFI_SUCCESS; + } + RecordingState = CommRecordingState->RecordingState; + if (RecordingState == MEMORY_PROFILE_RECORDING_ENABLE) { + CommHeader = (EFI_SMM_COMMUNICATE_HEADER *) &CommBuffer[0]; + CopyMem (&CommHeader->HeaderGuid, &gEdkiiMemoryProfileGuid, sizeof (gEdkiiMemoryProfileGuid)); + CommHeader->MessageLength = sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE); + + CommRecordingState = (SMRAM_PROFILE_PARAMETER_RECORDING_STATE *) &CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)]; + CommRecordingState->Header.Command = SMRAM_PROFILE_COMMAND_SET_RECORDING_STATE; + CommRecordingState->Header.DataLength = sizeof (*CommRecordingState); + CommRecordingState->Header.ReturnStatus = (UINT64)-1; + CommRecordingState->RecordingState = MEMORY_PROFILE_RECORDING_DISABLE; + + CommSize = sizeof (EFI_GUID) + sizeof (UINTN) + CommHeader->MessageLength; + SmmCommunication->Communicate (SmmCommunication, CommBuffer, &CommSize); + } + + // + // Get Size + // + CommHeader = (EFI_SMM_COMMUNICATE_HEADER *) &CommBuffer[0]; + CopyMem (&CommHeader->HeaderGuid, &gEdkiiMemoryProfileGuid, sizeof (gEdkiiMemoryProfileGuid)); + CommHeader->MessageLength = sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO); + + CommGetProfileInfo = (SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *) &CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)]; + CommGetProfileInfo->Header.Command = SMRAM_PROFILE_COMMAND_GET_PROFILE_INFO; + CommGetProfileInfo->Header.DataLength = sizeof (*CommGetProfileInfo); + CommGetProfileInfo->Header.ReturnStatus = (UINT64)-1; + CommGetProfileInfo->ProfileSize = 0; + + CommSize = sizeof (EFI_GUID) + sizeof (UINTN) + CommHeader->MessageLength; + Status = SmmCommunication->Communicate (SmmCommunication, CommBuffer, &CommSize); + ASSERT_EFI_ERROR (Status); + + if (CommGetProfileInfo->Header.ReturnStatus != 0) { + Status = EFI_SUCCESS; + Print (L"SmramProfile: GetProfileInfo - 0x%0x\n", CommGetProfileInfo->Header.ReturnStatus); + goto Done; + } + + ProfileSize = (UINTN) CommGetProfileInfo->ProfileSize; + + // + // Get Data + // + ProfileBuffer = AllocateZeroPool (ProfileSize); + if (ProfileBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + Print (L"SmramProfile: AllocateZeroPool (0x%x) for profile buffer - %r\n", ProfileSize, Status); + goto Done; + } + + CommHeader = (EFI_SMM_COMMUNICATE_HEADER *) &CommBuffer[0]; + CopyMem (&CommHeader->HeaderGuid, &gEdkiiMemoryProfileGuid, sizeof(gEdkiiMemoryProfileGuid)); + CommHeader->MessageLength = sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET); + + CommGetProfileData = (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET *) &CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)]; + CommGetProfileData->Header.Command = SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA_BY_OFFSET; + CommGetProfileData->Header.DataLength = sizeof (*CommGetProfileData); + CommGetProfileData->Header.ReturnStatus = (UINT64)-1; + + CommSize = sizeof (EFI_GUID) + sizeof (UINTN) + CommHeader->MessageLength; + Buffer = (UINT8 *) CommHeader + CommSize; + Size -= CommSize; + + CommGetProfileData->ProfileBuffer = (PHYSICAL_ADDRESS) (UINTN) Buffer; + CommGetProfileData->ProfileOffset = 0; + while (CommGetProfileData->ProfileOffset < ProfileSize) { + Offset = (UINTN) CommGetProfileData->ProfileOffset; + if (Size <= (ProfileSize - CommGetProfileData->ProfileOffset)) { + CommGetProfileData->ProfileSize = (UINT64) Size; + } else { + CommGetProfileData->ProfileSize = (UINT64) (ProfileSize - CommGetProfileData->ProfileOffset); + } + Status = SmmCommunication->Communicate (SmmCommunication, CommBuffer, &CommSize); + ASSERT_EFI_ERROR (Status); + + if (CommGetProfileData->Header.ReturnStatus != 0) { + Status = EFI_SUCCESS; + Print (L"GetProfileData - 0x%x\n", CommGetProfileData->Header.ReturnStatus); + goto Done; + } + CopyMem ((UINT8 *) ProfileBuffer + Offset, (VOID *) (UINTN) CommGetProfileData->ProfileBuffer, (UINTN) CommGetProfileData->ProfileSize); + } + + + Print (L"SmramProfileSize - 0x%x\n", ProfileSize); + Print (L"======= SmramProfile begin =======\n"); + DumpMemoryProfile ((PHYSICAL_ADDRESS) (UINTN) ProfileBuffer, ProfileSize, TRUE); + + // + // Dump summary information + // + MemoryProfileContextSummaryData = CreateContextSummaryData ((PHYSICAL_ADDRESS) (UINTN) ProfileBuffer, ProfileSize); + if (MemoryProfileContextSummaryData != NULL) { + DumpContextSummaryData (MemoryProfileContextSummaryData, TRUE); + DestroyContextSummaryData (MemoryProfileContextSummaryData); + } + + Print (L"======= SmramProfile end =======\n\n\n"); + +Done: + if (ProfileBuffer != NULL) { + FreePool (ProfileBuffer); + } + + // + // Restore recording state if needed. + // + if (RecordingState == MEMORY_PROFILE_RECORDING_ENABLE) { + CommHeader = (EFI_SMM_COMMUNICATE_HEADER *) &CommBuffer[0]; + CopyMem (&CommHeader->HeaderGuid, &gEdkiiMemoryProfileGuid, sizeof (gEdkiiMemoryProfileGuid)); + CommHeader->MessageLength = sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE); + + CommRecordingState = (SMRAM_PROFILE_PARAMETER_RECORDING_STATE *) &CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)]; + CommRecordingState->Header.Command = SMRAM_PROFILE_COMMAND_SET_RECORDING_STATE; + CommRecordingState->Header.DataLength = sizeof (*CommRecordingState); + CommRecordingState->Header.ReturnStatus = (UINT64)-1; + CommRecordingState->RecordingState = MEMORY_PROFILE_RECORDING_ENABLE; + + CommSize = sizeof (EFI_GUID) + sizeof (UINTN) + CommHeader->MessageLength; + SmmCommunication->Communicate (SmmCommunication, CommBuffer, &CommSize); + } + + return Status; +} + +/** + The user Entry Point for Application. The user code starts with this function + as the real entry point for the image goes into a library that calls this function. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +UefiMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = GetUefiMemoryProfileData (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "GetUefiMemoryProfileData - %r\n", Status)); + } + + Status = GetSmramProfileData (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "GetSmramProfileData - %r\n", Status)); + } + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf new file mode 100644 index 00000000..cb1cc4f3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf @@ -0,0 +1,56 @@ +## @file +# Shell application to dump UEFI memory and SMRAM profile information. +# +# Note that if the feature is not enabled by setting PcdMemoryProfilePropertyMask, +# the application will not display memory profile information. +# +# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MemoryProfileInfo + MODULE_UNI_FILE = MemoryProfileInfo.uni + FILE_GUID = 21429B90-5F67-4e93-AF55-1D314D646E12 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = UefiMain + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + MemoryProfileInfo.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + BaseLib + BaseMemoryLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + DebugLib + UefiLib + MemoryAllocationLib + DxeServicesLib + PrintLib + +[Guids] + ## SOMETIMES_CONSUMES ## GUID # Locate protocol + ## SOMETIMES_CONSUMES ## GUID # SmiHandlerRegister + gEdkiiMemoryProfileGuid + gEdkiiPiSmmCommunicationRegionTableGuid ## SOMETIMES_CONSUMES ## SystemTable + +[Protocols] + gEfiSmmCommunicationProtocolGuid ## SOMETIMES_CONSUMES + +[UserExtensions.TianoCore."ExtraFiles"] + MemoryProfileInfoExtra.uni diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.uni new file mode 100644 index 00000000..675316f5 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.uni @@ -0,0 +1,17 @@ +// /** @file
+// Shell application to dump UEFI memory and SMRAM profile information.
+//
+// Note that if the feature is not enabled by setting PcdMemoryProfilePropertyMask,
+// the application will not display memory profile information.
+//
+// Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Shell application to dump UEFI memory and SMRAM profile information."
+
+#string STR_MODULE_DESCRIPTION #language en-US "Note that if the feature is not enabled by setting PcdMemoryProfilePropertyMask, the application will not display memory profile information."
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfoExtra.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfoExtra.uni new file mode 100644 index 00000000..354edd98 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfoExtra.uni @@ -0,0 +1,14 @@ +// /** @file
+// MemoryProfileInfo Localized Strings and Content
+//
+// Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Memory Profile Information Application"
+
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.c new file mode 100644 index 00000000..3f52e687 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.c @@ -0,0 +1,686 @@ +/** @file + Shell application to dump SMI handler profile information. + +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/DebugLib.h> +#include <Library/PrintLib.h> +#include <Library/UefiLib.h> +#include <Library/DevicePathLib.h> +#include <Library/DxeServicesLib.h> +#include <Protocol/SmmCommunication.h> +#include <Guid/PiSmmCommunicationRegionTable.h> + +#include <Guid/SmiHandlerProfile.h> + +#define PROFILE_NAME_STRING_LENGTH 64 +CHAR8 mNameString[PROFILE_NAME_STRING_LENGTH + 1]; + +VOID *mSmiHandlerProfileDatabase; +UINTN mSmiHandlerProfileDatabaseSize; + +/** + This function dump raw data. + + @param Data raw data + @param Size raw data size +**/ +VOID +InternalDumpData ( + IN UINT8 *Data, + IN UINTN Size + ) +{ + UINTN Index; + for (Index = 0; Index < Size; Index++) { + Print (L"%02x", (UINTN)Data[Index]); + if ((Index + 1) != Size) { + Print (L" "); + } + } +} + +/** + Get SMI handler profile database. +**/ +VOID +GetSmiHandlerProfileDatabase( + VOID + ) +{ + EFI_STATUS Status; + UINTN CommSize; + UINT8 *CommBuffer; + EFI_SMM_COMMUNICATE_HEADER *CommHeader; + SMI_HANDLER_PROFILE_PARAMETER_GET_INFO *CommGetInfo; + SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET *CommGetData; + EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication; + UINTN MinimalSizeNeeded; + EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *PiSmmCommunicationRegionTable; + UINT32 Index; + EFI_MEMORY_DESCRIPTOR *Entry; + VOID *Buffer; + UINTN Size; + UINTN Offset; + + Status = gBS->LocateProtocol(&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **)&SmmCommunication); + if (EFI_ERROR(Status)) { + Print(L"SmiHandlerProfile: Locate SmmCommunication protocol - %r\n", Status); + return ; + } + + MinimalSizeNeeded = EFI_PAGE_SIZE; + + Status = EfiGetSystemConfigurationTable( + &gEdkiiPiSmmCommunicationRegionTableGuid, + (VOID **)&PiSmmCommunicationRegionTable + ); + if (EFI_ERROR(Status)) { + Print(L"SmiHandlerProfile: Get PiSmmCommunicationRegionTable - %r\n", Status); + return ; + } + ASSERT(PiSmmCommunicationRegionTable != NULL); + Entry = (EFI_MEMORY_DESCRIPTOR *)(PiSmmCommunicationRegionTable + 1); + Size = 0; + for (Index = 0; Index < PiSmmCommunicationRegionTable->NumberOfEntries; Index++) { + if (Entry->Type == EfiConventionalMemory) { + Size = EFI_PAGES_TO_SIZE((UINTN)Entry->NumberOfPages); + if (Size >= MinimalSizeNeeded) { + break; + } + } + Entry = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)Entry + PiSmmCommunicationRegionTable->DescriptorSize); + } + ASSERT(Index < PiSmmCommunicationRegionTable->NumberOfEntries); + CommBuffer = (UINT8 *)(UINTN)Entry->PhysicalStart; + + // + // Get Size + // + CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0]; + CopyMem(&CommHeader->HeaderGuid, &gSmiHandlerProfileGuid, sizeof(gSmiHandlerProfileGuid)); + CommHeader->MessageLength = sizeof(SMI_HANDLER_PROFILE_PARAMETER_GET_INFO); + + CommGetInfo = (SMI_HANDLER_PROFILE_PARAMETER_GET_INFO *)&CommBuffer[OFFSET_OF(EFI_SMM_COMMUNICATE_HEADER, Data)]; + CommGetInfo->Header.Command = SMI_HANDLER_PROFILE_COMMAND_GET_INFO; + CommGetInfo->Header.DataLength = sizeof(*CommGetInfo); + CommGetInfo->Header.ReturnStatus = (UINT64)-1; + CommGetInfo->DataSize = 0; + + CommSize = sizeof(EFI_GUID) + sizeof(UINTN) + CommHeader->MessageLength; + Status = SmmCommunication->Communicate(SmmCommunication, CommBuffer, &CommSize); + if (EFI_ERROR(Status)) { + Print(L"SmiHandlerProfile: SmmCommunication - %r\n", Status); + return ; + } + + if (CommGetInfo->Header.ReturnStatus != 0) { + Print(L"SmiHandlerProfile: GetInfo - 0x%0x\n", CommGetInfo->Header.ReturnStatus); + return ; + } + + mSmiHandlerProfileDatabaseSize = (UINTN)CommGetInfo->DataSize; + + // + // Get Data + // + mSmiHandlerProfileDatabase = AllocateZeroPool(mSmiHandlerProfileDatabaseSize); + if (mSmiHandlerProfileDatabase == NULL) { + Status = EFI_OUT_OF_RESOURCES; + Print(L"SmiHandlerProfile: AllocateZeroPool (0x%x) for dump buffer - %r\n", mSmiHandlerProfileDatabaseSize, Status); + return ; + } + + CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0]; + CopyMem(&CommHeader->HeaderGuid, &gSmiHandlerProfileGuid, sizeof(gSmiHandlerProfileGuid)); + CommHeader->MessageLength = sizeof(SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET); + + CommGetData = (SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET *)&CommBuffer[OFFSET_OF(EFI_SMM_COMMUNICATE_HEADER, Data)]; + CommGetData->Header.Command = SMI_HANDLER_PROFILE_COMMAND_GET_DATA_BY_OFFSET; + CommGetData->Header.DataLength = sizeof(*CommGetData); + CommGetData->Header.ReturnStatus = (UINT64)-1; + + CommSize = sizeof(EFI_GUID) + sizeof(UINTN) + CommHeader->MessageLength; + Buffer = (UINT8 *)CommHeader + CommSize; + Size -= CommSize; + + CommGetData->DataBuffer = (PHYSICAL_ADDRESS)(UINTN)Buffer; + CommGetData->DataOffset = 0; + while (CommGetData->DataOffset < mSmiHandlerProfileDatabaseSize) { + Offset = (UINTN)CommGetData->DataOffset; + if (Size <= (mSmiHandlerProfileDatabaseSize - CommGetData->DataOffset)) { + CommGetData->DataSize = (UINT64)Size; + } else { + CommGetData->DataSize = (UINT64)(mSmiHandlerProfileDatabaseSize - CommGetData->DataOffset); + } + Status = SmmCommunication->Communicate(SmmCommunication, CommBuffer, &CommSize); + ASSERT_EFI_ERROR(Status); + + if (CommGetData->Header.ReturnStatus != 0) { + FreePool(mSmiHandlerProfileDatabase); + mSmiHandlerProfileDatabase = NULL; + Print(L"SmiHandlerProfile: GetData - 0x%x\n", CommGetData->Header.ReturnStatus); + return ; + } + CopyMem((UINT8 *)mSmiHandlerProfileDatabase + Offset, (VOID *)(UINTN)CommGetData->DataBuffer, (UINTN)CommGetData->DataSize); + } + + DEBUG ((DEBUG_INFO, "SmiHandlerProfileSize - 0x%x\n", mSmiHandlerProfileDatabaseSize)); + + return ; +} + +/** + Get the file name portion of the Pdb File Name. + + The portion of the Pdb File Name between the last backslash and + either a following period or the end of the string is copied into + AsciiBuffer. The name is truncated, if necessary, to ensure that + AsciiBuffer is not overrun. + + @param[in] PdbFileName Pdb file name. + @param[out] AsciiBuffer The resultant Ascii File Name. + +**/ +VOID +GetShortPdbFileName ( + IN CHAR8 *PdbFileName, + OUT CHAR8 *AsciiBuffer + ) +{ + UINTN IndexPdb; // Current work location within a Pdb string. + UINTN IndexBuffer; // Current work location within a Buffer string. + UINTN StartIndex; + UINTN EndIndex; + + ZeroMem (AsciiBuffer, PROFILE_NAME_STRING_LENGTH + 1); + + if (PdbFileName == NULL) { + AsciiStrnCpyS (AsciiBuffer, PROFILE_NAME_STRING_LENGTH + 1, " ", 1); + } else { + StartIndex = 0; + for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++); + for (IndexPdb = 0; PdbFileName[IndexPdb] != 0; IndexPdb++) { + if ((PdbFileName[IndexPdb] == '\\') || (PdbFileName[IndexPdb] == '/')) { + StartIndex = IndexPdb + 1; + } + + if (PdbFileName[IndexPdb] == '.') { + EndIndex = IndexPdb; + } + } + + IndexBuffer = 0; + for (IndexPdb = StartIndex; IndexPdb < EndIndex; IndexPdb++) { + AsciiBuffer[IndexBuffer] = PdbFileName[IndexPdb]; + IndexBuffer++; + if (IndexBuffer >= PROFILE_NAME_STRING_LENGTH) { + AsciiBuffer[PROFILE_NAME_STRING_LENGTH] = 0; + break; + } + } + } +} + +/** + Get a human readable name for an image. + The following methods will be tried orderly: + 1. Image PDB + 2. FFS UI section + 3. Image GUID + + @param[in] ImageStruct Point to the image structure. + + @return The resulting Ascii name string is stored in the mNameString global array. + +**/ +CHAR8 * +GetDriverNameString ( + IN SMM_CORE_IMAGE_DATABASE_STRUCTURE *ImageStruct + ) +{ + EFI_STATUS Status; + CHAR16 *NameString; + UINTN StringSize; + + if (ImageStruct == NULL) { + return "???"; + } + + // + // Method 1: Get the name string from image PDB + // + if (ImageStruct->PdbStringOffset != 0) { + GetShortPdbFileName ((CHAR8 *) ((UINTN) ImageStruct + ImageStruct->PdbStringOffset), mNameString); + return mNameString; + } + + if (!IsZeroGuid (&ImageStruct->FileGuid)) { + // + // Try to get the image's FFS UI section by image GUID + // + NameString = NULL; + StringSize = 0; + Status = GetSectionFromAnyFv ( + &ImageStruct->FileGuid, + EFI_SECTION_USER_INTERFACE, + 0, + (VOID **) &NameString, + &StringSize + ); + if (!EFI_ERROR (Status)) { + // + // Method 2: Get the name string from FFS UI section + // + if (StrLen (NameString) > PROFILE_NAME_STRING_LENGTH) { + NameString[PROFILE_NAME_STRING_LENGTH] = 0; + } + UnicodeStrToAsciiStrS (NameString, mNameString, sizeof (mNameString)); + FreePool (NameString); + return mNameString; + } + } + + // + // Method 3: Get the name string from image GUID + // + AsciiSPrint (mNameString, sizeof (mNameString), "%g", &ImageStruct->FileGuid); + return mNameString; +} + +/** + Get image structure from reference index. + + @param ImageRef the image reference index + + @return image structure +**/ +SMM_CORE_IMAGE_DATABASE_STRUCTURE * +GetImageFromRef ( + IN UINTN ImageRef + ) +{ + SMM_CORE_IMAGE_DATABASE_STRUCTURE *ImageStruct; + + ImageStruct = (VOID *)mSmiHandlerProfileDatabase; + while ((UINTN)ImageStruct < (UINTN)mSmiHandlerProfileDatabase + mSmiHandlerProfileDatabaseSize) { + if (ImageStruct->Header.Signature == SMM_CORE_IMAGE_DATABASE_SIGNATURE) { + if (ImageStruct->ImageRef == ImageRef) { + return ImageStruct; + } + } + ImageStruct = (VOID *)((UINTN)ImageStruct + ImageStruct->Header.Length); + } + + return NULL; +} + +/** + Dump SMM loaded image information. +**/ +VOID +DumpSmmLoadedImage( + VOID + ) +{ + SMM_CORE_IMAGE_DATABASE_STRUCTURE *ImageStruct; + CHAR8 *PdbString; + CHAR8 *NameString; + + ImageStruct = (VOID *)mSmiHandlerProfileDatabase; + while ((UINTN)ImageStruct < (UINTN)mSmiHandlerProfileDatabase + mSmiHandlerProfileDatabaseSize) { + if (ImageStruct->Header.Signature == SMM_CORE_IMAGE_DATABASE_SIGNATURE) { + NameString = GetDriverNameString (ImageStruct); + Print(L" <Image Name=\"%a\"", NameString); + Print(L" Base=\"0x%lx\" Size=\"0x%lx\"", ImageStruct->ImageBase, ImageStruct->ImageSize); + if (ImageStruct->EntryPoint != 0) { + Print(L" EntryPoint=\"0x%lx\"", ImageStruct->EntryPoint); + } + Print(L" FvFile=\"%g\"", &ImageStruct->FileGuid); + Print(L" RefId=\"0x%x\"", ImageStruct->ImageRef); + Print(L">\n"); + if (ImageStruct->PdbStringOffset != 0) { + PdbString = (CHAR8 *)((UINTN)ImageStruct + ImageStruct->PdbStringOffset); + Print(L" <Pdb>%a</Pdb>\n", PdbString); + } + Print(L" </Image>\n"); + } + + ImageStruct = (VOID *)((UINTN)ImageStruct + ImageStruct->Header.Length); + } + + return; +} + +CHAR8 *mSxTypeString[] = { + "SxS0", + "SxS1", + "SxS2", + "SxS3", + "SxS4", + "SxS5", +}; + +/** + Convert SxType to a string. + + @param Type SxType + + @return SxType string +**/ +CHAR8 * +SxTypeToString ( + IN EFI_SLEEP_TYPE Type + ) +{ + if (Type >= 0 && Type < ARRAY_SIZE(mSxTypeString)) { + return mSxTypeString[Type]; + } else { + AsciiSPrint (mNameString, sizeof(mNameString), "0x%x", Type); + return mNameString; + } +} + +CHAR8 *mSxPhaseString[] = { + "SxEntry", + "SxExit", +}; + +/** + Convert SxPhase to a string. + + @param Phase SxPhase + + @return SxPhase string +**/ +CHAR8 * +SxPhaseToString ( + IN EFI_SLEEP_PHASE Phase + ) +{ + if (Phase >= 0 && Phase < ARRAY_SIZE(mSxPhaseString)) { + return mSxPhaseString[Phase]; + } else { + AsciiSPrint (mNameString, sizeof(mNameString), "0x%x", Phase); + return mNameString; + } +} + +CHAR8 *mPowerButtonPhaseString[] = { + "PowerButtonEntry", + "PowerButtonExit", +}; + +/** + Convert PowerButtonPhase to a string. + + @param Phase PowerButtonPhase + + @return PowerButtonPhase string +**/ +CHAR8 * +PowerButtonPhaseToString ( + IN EFI_POWER_BUTTON_PHASE Phase + ) +{ + if (Phase >= 0 && Phase < ARRAY_SIZE(mPowerButtonPhaseString)) { + return mPowerButtonPhaseString[Phase]; + } else { + AsciiSPrint (mNameString, sizeof(mNameString), "0x%x", Phase); + return mNameString; + } +} + +CHAR8 *mStandbyButtonPhaseString[] = { + "StandbyButtonEntry", + "StandbyButtonExit", +}; + +/** + Convert StandbyButtonPhase to a string. + + @param Phase StandbyButtonPhase + + @return StandbyButtonPhase string +**/ +CHAR8 * +StandbyButtonPhaseToString ( + IN EFI_STANDBY_BUTTON_PHASE Phase + ) +{ + if (Phase >= 0 && Phase < ARRAY_SIZE(mStandbyButtonPhaseString)) { + return mStandbyButtonPhaseString[Phase]; + } else { + AsciiSPrint (mNameString, sizeof(mNameString), "0x%x", Phase); + return mNameString; + } +} + +CHAR8 *mIoTrapTypeString[] = { + "WriteTrap", + "ReadTrap", + "ReadWriteTrap", +}; + +/** + Convert IoTrapType to a string. + + @param Type IoTrapType + + @return IoTrapType string +**/ +CHAR8 * +IoTrapTypeToString ( + IN EFI_SMM_IO_TRAP_DISPATCH_TYPE Type + ) +{ + if (Type >= 0 && Type < ARRAY_SIZE(mIoTrapTypeString)) { + return mIoTrapTypeString[Type]; + } else { + AsciiSPrint (mNameString, sizeof(mNameString), "0x%x", Type); + return mNameString; + } +} + +CHAR8 *mUsbTypeString[] = { + "UsbLegacy", + "UsbWake", +}; + +/** + Convert UsbType to a string. + + @param Type UsbType + + @return UsbType string +**/ +CHAR8 * +UsbTypeToString ( + IN EFI_USB_SMI_TYPE Type + ) +{ + if (Type >= 0 && Type < ARRAY_SIZE(mUsbTypeString)) { + return mUsbTypeString[Type]; + } else { + AsciiSPrint (mNameString, sizeof(mNameString), "0x%x", Type); + return mNameString; + } +} + +/** + Dump SMI child context. + + @param HandlerType the handler type + @param Context the handler context + @param ContextSize the handler context size +**/ +VOID +DumpSmiChildContext ( + IN EFI_GUID *HandlerType, + IN VOID *Context, + IN UINTN ContextSize + ) +{ + CHAR16 *Str; + + if (CompareGuid (HandlerType, &gEfiSmmSwDispatch2ProtocolGuid)) { + Print(L" SwSmi=\"0x%lx\"", ((SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT *)Context)->SwSmiInputValue); + } else if (CompareGuid (HandlerType, &gEfiSmmSxDispatch2ProtocolGuid)) { + Print(L" SxType=\"%a\"", SxTypeToString(((EFI_SMM_SX_REGISTER_CONTEXT *)Context)->Type)); + Print(L" SxPhase=\"%a\"", SxPhaseToString(((EFI_SMM_SX_REGISTER_CONTEXT *)Context)->Phase)); + } else if (CompareGuid (HandlerType, &gEfiSmmPowerButtonDispatch2ProtocolGuid)) { + Print(L" PowerButtonPhase=\"%a\"", PowerButtonPhaseToString(((EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT *)Context)->Phase)); + } else if (CompareGuid (HandlerType, &gEfiSmmStandbyButtonDispatch2ProtocolGuid)) { + Print(L" StandbyButtonPhase=\"%a\"", StandbyButtonPhaseToString(((EFI_SMM_STANDBY_BUTTON_REGISTER_CONTEXT *)Context)->Phase)); + } else if (CompareGuid (HandlerType, &gEfiSmmPeriodicTimerDispatch2ProtocolGuid)) { + Print(L" PeriodicTimerPeriod=\"%ld\"", ((EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT *)Context)->Period); + Print(L" PeriodicTimerSmiTickInterval=\"%ld\"", ((EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT *)Context)->SmiTickInterval); + } else if (CompareGuid (HandlerType, &gEfiSmmGpiDispatch2ProtocolGuid)) { + Print(L" GpiNum=\"0x%lx\"", ((EFI_SMM_GPI_REGISTER_CONTEXT *)Context)->GpiNum); + } else if (CompareGuid (HandlerType, &gEfiSmmIoTrapDispatch2ProtocolGuid)) { + Print(L" IoTrapAddress=\"0x%x\"", ((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Address); + Print(L" IoTrapLength=\"0x%x\"", ((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Length); + Print(L" IoTrapType=\"%a\"", IoTrapTypeToString(((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Type)); + } else if (CompareGuid (HandlerType, &gEfiSmmUsbDispatch2ProtocolGuid)) { + Print(L" UsbType=\"0x%x\"", UsbTypeToString(((SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *)Context)->Type)); + Str = ConvertDevicePathToText((EFI_DEVICE_PATH_PROTOCOL *)(((SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *)Context) + 1), TRUE, TRUE); + Print(L" UsbDevicePath=\"%s\"", Str); + if (Str != NULL) { + FreePool (Str); + } + } else { + Print(L" Context=\""); + InternalDumpData (Context, ContextSize); + Print(L"\""); + } +} + +/** + Dump SMI handler in HandlerCategory. + + @param HandlerCategory SMI handler category +**/ +VOID +DumpSmiHandler( + IN UINT32 HandlerCategory + ) +{ + SMM_CORE_SMI_DATABASE_STRUCTURE *SmiStruct; + SMM_CORE_SMI_HANDLER_STRUCTURE *SmiHandlerStruct; + UINTN Index; + SMM_CORE_IMAGE_DATABASE_STRUCTURE *ImageStruct; + CHAR8 *NameString; + + SmiStruct = (VOID *)mSmiHandlerProfileDatabase; + while ((UINTN)SmiStruct < (UINTN)mSmiHandlerProfileDatabase + mSmiHandlerProfileDatabaseSize) { + if ((SmiStruct->Header.Signature == SMM_CORE_SMI_DATABASE_SIGNATURE) && (SmiStruct->HandlerCategory == HandlerCategory)) { + SmiHandlerStruct = (VOID *)(SmiStruct + 1); + Print(L" <SmiEntry"); + if (!IsZeroGuid (&SmiStruct->HandlerType)) { + Print(L" HandlerType=\"%g\"", &SmiStruct->HandlerType); + } + Print(L">\n"); + for (Index = 0; Index < SmiStruct->HandlerCount; Index++) { + Print(L" <SmiHandler"); + if (SmiHandlerStruct->ContextBufferSize != 0) { + DumpSmiChildContext (&SmiStruct->HandlerType, (UINT8 *)SmiHandlerStruct + SmiHandlerStruct->ContextBufferOffset, SmiHandlerStruct->ContextBufferSize); + } + Print(L">\n"); + ImageStruct = GetImageFromRef((UINTN)SmiHandlerStruct->ImageRef); + NameString = GetDriverNameString (ImageStruct); + Print(L" <Module RefId=\"0x%x\" Name=\"%a\">\n", SmiHandlerStruct->ImageRef, NameString); + if ((ImageStruct != NULL) && (ImageStruct->PdbStringOffset != 0)) { + Print(L" <Pdb>%a</Pdb>\n", (UINT8 *)ImageStruct + ImageStruct->PdbStringOffset); + } + Print(L" </Module>\n"); + Print(L" <Handler Address=\"0x%lx\">\n", SmiHandlerStruct->Handler); + if (ImageStruct != NULL) { + Print(L" <RVA>0x%x</RVA>\n", (UINTN) (SmiHandlerStruct->Handler - ImageStruct->ImageBase)); + } + Print(L" </Handler>\n", SmiHandlerStruct->Handler); + Print(L" <Caller Address=\"0x%lx\">\n", SmiHandlerStruct->CallerAddr); + if (ImageStruct != NULL) { + Print(L" <RVA>0x%x</RVA>\n", (UINTN) (SmiHandlerStruct->CallerAddr - ImageStruct->ImageBase)); + } + Print(L" </Caller>\n", SmiHandlerStruct->Handler); + SmiHandlerStruct = (VOID *)((UINTN)SmiHandlerStruct + SmiHandlerStruct->Length); + Print(L" </SmiHandler>\n"); + } + Print(L" </SmiEntry>\n"); + } + SmiStruct = (VOID *)((UINTN)SmiStruct + SmiStruct->Header.Length); + } + + return; +} + +/** + The Entry Point for SMI handler profile info application. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval Other Some error occurred when executing this entry point. +**/ +EFI_STATUS +EFIAPI +SmiHandlerProfileInfoEntrypoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + GetSmiHandlerProfileDatabase(); + + if (mSmiHandlerProfileDatabase == NULL) { + return EFI_SUCCESS; + } + + // + // Dump all image + // + Print(L"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); + Print(L"<SmiHandlerProfile>\n"); + Print(L"<ImageDatabase>\n"); + Print(L" <!-- SMM image loaded -->\n"); + DumpSmmLoadedImage(); + Print(L"</ImageDatabase>\n\n"); + + // + // Dump SMI Handler + // + Print(L"<SmiHandlerDatabase>\n"); + Print(L" <!-- SMI Handler registered -->\n\n"); + Print(L" <SmiHandlerCategory Name=\"RootSmi\">\n"); + Print(L" <!-- The root SMI Handler registered by SmmCore -->\n"); + DumpSmiHandler(SmmCoreSmiHandlerCategoryRootHandler); + Print(L" </SmiHandlerCategory>\n\n"); + + Print(L" <SmiHandlerCategory Name=\"GuidSmi\">\n"); + Print(L" <!-- The GUID SMI Handler registered by SmmCore -->\n"); + DumpSmiHandler(SmmCoreSmiHandlerCategoryGuidHandler); + Print(L" </SmiHandlerCategory>\n\n"); + + Print(L" <SmiHandlerCategory Name=\"HardwareSmi\">\n"); + Print(L" <!-- The hardware SMI Handler registered by SmmChildDispatcher -->\n"); + DumpSmiHandler(SmmCoreSmiHandlerCategoryHardwareHandler); + Print(L" </SmiHandlerCategory>\n\n"); + + Print(L"</SmiHandlerDatabase>\n"); + Print(L"</SmiHandlerProfile>\n"); + + if (mSmiHandlerProfileDatabase != NULL) { + FreePool(mSmiHandlerProfileDatabase); + } + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.inf b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.inf new file mode 100644 index 00000000..75fff79d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.inf @@ -0,0 +1,58 @@ +## @file +# Shell application to dump SMI handler profile information. +# +# Note that if the feature is not enabled by setting PcdSmiHandlerProfilePropertyMask, +# the application will not display SMI handler profile information. +# +# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SmiHandlerProfileInfo + MODULE_UNI_FILE = SmiHandlerProfileInfo.uni + FILE_GUID = 611EA796-8DF8-4BB6-91FE-6540ED70DC66 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = SmiHandlerProfileInfoEntrypoint + +[Sources] + SmiHandlerProfileInfo.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + BaseLib + BaseMemoryLib + MemoryAllocationLib + DebugLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiLib + PrintLib + DevicePathLib + DxeServicesLib + +[Protocols] + gEfiSmmCommunicationProtocolGuid ## CONSUMES + gEfiSmmSwDispatch2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiSmmSxDispatch2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiSmmPowerButtonDispatch2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiSmmStandbyButtonDispatch2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiSmmPeriodicTimerDispatch2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiSmmGpiDispatch2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiSmmIoTrapDispatch2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiSmmUsbDispatch2ProtocolGuid ## SOMETIMES_CONSUMES + +[Guids] + gEdkiiPiSmmCommunicationRegionTableGuid ## CONSUMES ## SystemTable + gSmiHandlerProfileGuid ## SOMETIMES_CONSUMES ## GUID # SmiHandlerRegister + +[UserExtensions.TianoCore."ExtraFiles"] + SmiHandlerProfileInfoExtra.uni + diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.uni new file mode 100644 index 00000000..71ec9c22 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.uni @@ -0,0 +1,17 @@ +// /** @file
+// Shell application to dump SMI handler profile information.
+//
+// Note that if the feature is not enabled by setting PcdSmiHandlerProfilePropertyMask,
+// the application will not display SMI handler profile information.
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Shell application to dump SMI handler profile information."
+
+#string STR_MODULE_DESCRIPTION #language en-US "Note that if the feature is not enabled by setting PcdSmiHandlerProfilePropertyMask, the application will not display SMI handler profile information."
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfoExtra.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfoExtra.uni new file mode 100644 index 00000000..449e6a10 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfoExtra.uni @@ -0,0 +1,14 @@ +// /** @file
+// SmiHandlerProfileInfo Localized Strings and Content
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"SMI Handler Profile Information Application"
+
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPage.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPage.c new file mode 100644 index 00000000..2b8828b1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPage.c @@ -0,0 +1,1113 @@ +/** @file + FrontPage routines to handle the callbacks and browser calls + +Copyright (c) 2004 - 2017, Intel Corporation. All rights reserved.<BR> +(C) Copyright 2018 Hewlett Packard Enterprise Development LP<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "FrontPage.h" +#include "FrontPageCustomizedUi.h" + +#define MAX_STRING_LEN 200 + +EFI_GUID mFrontPageGuid = FRONT_PAGE_FORMSET_GUID; + +BOOLEAN mResetRequired = FALSE; + +EFI_FORM_BROWSER2_PROTOCOL *gFormBrowser2; +CHAR8 *mLanguageString; +BOOLEAN mModeInitialized = FALSE; +// +// Boot video resolution and text mode. +// +UINT32 mBootHorizontalResolution = 0; +UINT32 mBootVerticalResolution = 0; +UINT32 mBootTextModeColumn = 0; +UINT32 mBootTextModeRow = 0; +// +// BIOS setup video resolution and text mode. +// +UINT32 mSetupTextModeColumn = 0; +UINT32 mSetupTextModeRow = 0; +UINT32 mSetupHorizontalResolution = 0; +UINT32 mSetupVerticalResolution = 0; + +FRONT_PAGE_CALLBACK_DATA gFrontPagePrivate = { + FRONT_PAGE_CALLBACK_DATA_SIGNATURE, + NULL, + NULL, + NULL, + { + FakeExtractConfig, + FakeRouteConfig, + FrontPageCallback + } +}; + +HII_VENDOR_DEVICE_PATH mFrontPageHiiVendorDevicePath = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) + } + }, + // + // {8E6D99EE-7531-48f8-8745-7F6144468FF2} + // + { 0x8e6d99ee, 0x7531, 0x48f8, { 0x87, 0x45, 0x7f, 0x61, 0x44, 0x46, 0x8f, 0xf2 } } + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + (UINT8) (END_DEVICE_PATH_LENGTH), + (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) + } + } +}; + +/** + Update the banner information for the Front Page based on Smbios information. + +**/ +VOID +UpdateFrontPageBannerStrings ( + VOID + ); + +/** + This function allows a caller to extract the current configuration for one + or more named elements from the target driver. + + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Request A null-terminated Unicode string in <ConfigRequest> format. + @param 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 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 +FakeExtractConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Request, + OUT EFI_STRING *Progress, + OUT EFI_STRING *Results + ) +{ + if (Progress == NULL || Results == NULL) { + return EFI_INVALID_PARAMETER; + } + *Progress = Request; + return EFI_NOT_FOUND; +} + +/** + This function processes the results of changes in configuration. + + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Configuration A null-terminated Unicode string in <ConfigResp> format. + @param 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 +FakeRouteConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ) +{ + if (Configuration == NULL || Progress == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Progress = Configuration; + + return EFI_NOT_FOUND; +} + +/** + This function processes the results of changes in configuration. + + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Action Specifies the type of action taken by the browser. + @param QuestionId A unique value which is sent to the original exporting driver + so that it can identify the type of data to expect. + @param Type The type of value for the question. + @param Value A pointer to the data being sent to the original exporting driver. + @param 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 +FrontPageCallback ( + 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 + ) +{ + return UiFrontPageCallbackHandler (gFrontPagePrivate.HiiHandle, Action, QuestionId, Type, Value, ActionRequest); +} + +/** + + Update the menus in the front page. + +**/ +VOID +UpdateFrontPageForm ( + VOID + ) +{ + VOID *StartOpCodeHandle; + VOID *EndOpCodeHandle; + EFI_IFR_GUID_LABEL *StartGuidLabel; + EFI_IFR_GUID_LABEL *EndGuidLabel; + + // + // Allocate space for creation of UpdateData Buffer + // + StartOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (StartOpCodeHandle != NULL); + + EndOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (EndOpCodeHandle != NULL); + // + // Create Hii Extend Label OpCode as the start opcode + // + StartGuidLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL)); + StartGuidLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + StartGuidLabel->Number = LABEL_FRANTPAGE_INFORMATION; + // + // Create Hii Extend Label OpCode as the end opcode + // + EndGuidLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL)); + EndGuidLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + EndGuidLabel->Number = LABEL_END; + + // + //Updata Front Page form + // + UiCustomizeFrontPage ( + gFrontPagePrivate.HiiHandle, + StartOpCodeHandle + ); + + HiiUpdateForm ( + gFrontPagePrivate.HiiHandle, + &mFrontPageGuid, + FRONT_PAGE_FORM_ID, + StartOpCodeHandle, + EndOpCodeHandle + ); + + HiiFreeOpCodeHandle (StartOpCodeHandle); + HiiFreeOpCodeHandle (EndOpCodeHandle); +} + +/** + Initialize HII information for the FrontPage + + + @retval EFI_SUCCESS The operation is successful. + @retval EFI_DEVICE_ERROR If the dynamic opcode creation failed. + +**/ +EFI_STATUS +InitializeFrontPage ( + VOID + ) +{ + EFI_STATUS Status; + // + // Locate Hii relative protocols + // + Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &gFormBrowser2); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Install Device Path Protocol and Config Access protocol to driver handle + // + gFrontPagePrivate.DriverHandle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &gFrontPagePrivate.DriverHandle, + &gEfiDevicePathProtocolGuid, + &mFrontPageHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &gFrontPagePrivate.ConfigAccess, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Publish our HII data + // + gFrontPagePrivate.HiiHandle = HiiAddPackages ( + &mFrontPageGuid, + gFrontPagePrivate.DriverHandle, + FrontPageVfrBin, + UiAppStrings, + NULL + ); + ASSERT (gFrontPagePrivate.HiiHandle != NULL); + + // + //Updata Front Page banner strings + // + UpdateFrontPageBannerStrings (); + + // + // Update front page menus. + // + UpdateFrontPageForm(); + + return Status; +} + +/** + Call the browser and display the front page + + @return Status code that will be returned by + EFI_FORM_BROWSER2_PROTOCOL.SendForm (). + +**/ +EFI_STATUS +CallFrontPage ( + VOID + ) +{ + EFI_STATUS Status; + EFI_BROWSER_ACTION_REQUEST ActionRequest; + + // + // Begin waiting for USER INPUT + // + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_INPUT_WAIT) + ); + + ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; + Status = gFormBrowser2->SendForm ( + gFormBrowser2, + &gFrontPagePrivate.HiiHandle, + 1, + &mFrontPageGuid, + 0, + NULL, + &ActionRequest + ); + // + // Check whether user change any option setting which needs a reset to be effective + // + if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) { + EnableResetRequired (); + } + + return Status; +} + +/** + Remove the installed packages from the HiiDatabase. + +**/ +VOID +FreeFrontPage( + VOID + ) +{ + EFI_STATUS Status; + Status = gBS->UninstallMultipleProtocolInterfaces ( + gFrontPagePrivate.DriverHandle, + &gEfiDevicePathProtocolGuid, + &mFrontPageHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &gFrontPagePrivate.ConfigAccess, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Publish our HII data + // + HiiRemovePackages (gFrontPagePrivate.HiiHandle); + if (gFrontPagePrivate.LanguageToken != NULL) { + FreePool (gFrontPagePrivate.LanguageToken); + gFrontPagePrivate.LanguageToken = NULL; + } +} + +/** + Convert Processor Frequency Data to a string. + + @param ProcessorFrequency The frequency data to process + @param Base10Exponent The exponent based on 10 + @param String The string that is created + +**/ +VOID +ConvertProcessorToString ( + IN UINT16 ProcessorFrequency, + IN UINT16 Base10Exponent, + OUT CHAR16 **String + ) +{ + CHAR16 *StringBuffer; + UINTN Index; + UINTN DestMax; + UINT32 FreqMhz; + + if (Base10Exponent >= 6) { + FreqMhz = ProcessorFrequency; + for (Index = 0; Index < (UINT32) Base10Exponent - 6; Index++) { + FreqMhz *= 10; + } + } else { + FreqMhz = 0; + } + DestMax = 0x20 / sizeof (CHAR16); + StringBuffer = AllocateZeroPool (0x20); + ASSERT (StringBuffer != NULL); + UnicodeValueToStringS (StringBuffer, sizeof (CHAR16) * DestMax, LEFT_JUSTIFY, FreqMhz / 1000, 3); + Index = StrnLenS (StringBuffer, DestMax); + StrCatS (StringBuffer, DestMax, L"."); + UnicodeValueToStringS ( + StringBuffer + Index + 1, + sizeof (CHAR16) * (DestMax - (Index + 1)), + PREFIX_ZERO, + (FreqMhz % 1000) / 10, + 2 + ); + StrCatS (StringBuffer, DestMax, L" GHz"); + *String = (CHAR16 *) StringBuffer; + return ; +} + + +/** + Convert Memory Size to a string. + + @param MemorySize The size of the memory to process + @param String The string that is created + +**/ +VOID +ConvertMemorySizeToString ( + IN UINT32 MemorySize, + OUT CHAR16 **String + ) +{ + CHAR16 *StringBuffer; + + StringBuffer = AllocateZeroPool (0x24); + ASSERT (StringBuffer != NULL); + UnicodeValueToStringS (StringBuffer, 0x24, LEFT_JUSTIFY, MemorySize, 10); + StrCatS (StringBuffer, 0x24 / sizeof (CHAR16), L" MB RAM"); + + *String = (CHAR16 *) StringBuffer; + + return ; +} + +/** + + Acquire the string associated with the Index from smbios structure and return it. + The caller is responsible for free the string buffer. + + @param OptionalStrStart The start position to search the string + @param Index The index of the string to extract + @param String The string that is extracted + + @retval EFI_SUCCESS The function returns EFI_SUCCESS always. + +**/ +EFI_STATUS +GetOptionalStringByIndex ( + IN CHAR8 *OptionalStrStart, + IN UINT8 Index, + OUT CHAR16 **String + ) +{ + UINTN StrSize; + + if (Index == 0) { + *String = AllocateZeroPool (sizeof (CHAR16)); + return EFI_SUCCESS; + } + + StrSize = 0; + do { + Index--; + OptionalStrStart += StrSize; + StrSize = AsciiStrSize (OptionalStrStart); + } while (OptionalStrStart[StrSize] != 0 && Index != 0); + + if ((Index != 0) || (StrSize == 1)) { + // + // Meet the end of strings set but Index is non-zero, or + // Find an empty string + // + *String = GetStringById (STRING_TOKEN (STR_MISSING_STRING)); + } else { + *String = AllocatePool (StrSize * sizeof (CHAR16)); + AsciiStrToUnicodeStrS (OptionalStrStart, *String, StrSize); + } + + return EFI_SUCCESS; +} + + +/** + + Update the banner information for the Front Page based on Smbios information. + +**/ +VOID +UpdateFrontPageBannerStrings ( + VOID + ) +{ + UINT8 StrIndex; + CHAR16 *NewString; + CHAR16 *FirmwareVersionString; + EFI_STATUS Status; + EFI_SMBIOS_HANDLE SmbiosHandle; + EFI_SMBIOS_PROTOCOL *Smbios; + SMBIOS_TABLE_TYPE0 *Type0Record; + SMBIOS_TABLE_TYPE1 *Type1Record; + SMBIOS_TABLE_TYPE4 *Type4Record; + SMBIOS_TABLE_TYPE19 *Type19Record; + EFI_SMBIOS_TABLE_HEADER *Record; + UINT64 InstalledMemory; + BOOLEAN FoundCpu; + + InstalledMemory = 0; + FoundCpu = 0; + + // + // Update default banner string. + // + NewString = HiiGetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_CUSTOMIZE_BANNER_LINE4_LEFT), NULL); + UiCustomizeFrontPageBanner (4, TRUE, &NewString); + HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_CUSTOMIZE_BANNER_LINE4_LEFT), NewString, NULL); + FreePool (NewString); + + NewString = HiiGetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_CUSTOMIZE_BANNER_LINE4_RIGHT), NULL); + UiCustomizeFrontPageBanner (4, FALSE, &NewString); + HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_CUSTOMIZE_BANNER_LINE4_RIGHT), NewString, NULL); + FreePool (NewString); + + NewString = HiiGetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_CUSTOMIZE_BANNER_LINE5_LEFT), NULL); + UiCustomizeFrontPageBanner (5, TRUE, &NewString); + HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_CUSTOMIZE_BANNER_LINE5_LEFT), NewString, NULL); + FreePool (NewString); + + NewString = HiiGetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_CUSTOMIZE_BANNER_LINE5_RIGHT), NULL); + UiCustomizeFrontPageBanner (5, FALSE, &NewString); + HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_CUSTOMIZE_BANNER_LINE5_RIGHT), NewString, NULL); + FreePool (NewString); + + // + // Update Front Page banner strings base on SmBios Table. + // + Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **) &Smbios); + if (EFI_ERROR (Status)) { + // + // Smbios protocol not found, get the default value. + // + NewString = HiiGetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_COMPUTER_MODEL), NULL); + UiCustomizeFrontPageBanner (1, TRUE, &NewString); + HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_COMPUTER_MODEL), NewString, NULL); + FreePool (NewString); + + NewString = HiiGetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_CPU_MODEL), NULL); + UiCustomizeFrontPageBanner (2, TRUE, &NewString); + HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_CPU_MODEL), NewString, NULL); + FreePool (NewString); + + NewString = HiiGetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_CPU_SPEED), NULL); + UiCustomizeFrontPageBanner (2, FALSE, &NewString); + HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_CPU_SPEED), NewString, NULL); + FreePool (NewString); + + NewString = HiiGetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_BIOS_VERSION), NULL); + UiCustomizeFrontPageBanner (3, TRUE, &NewString); + HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_BIOS_VERSION), NewString, NULL); + FreePool (NewString); + + NewString = HiiGetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_MEMORY_SIZE), NULL); + UiCustomizeFrontPageBanner (3, FALSE, &NewString); + HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_MEMORY_SIZE), NewString, NULL); + FreePool (NewString); + + return; + } + + SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED; + Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record, NULL); + while (!EFI_ERROR(Status)) { + if (Record->Type == SMBIOS_TYPE_BIOS_INFORMATION) { + Type0Record = (SMBIOS_TABLE_TYPE0 *) Record; + StrIndex = Type0Record->BiosVersion; + GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type0Record + Type0Record->Hdr.Length), StrIndex, &NewString); + + FirmwareVersionString = (CHAR16 *) PcdGetPtr (PcdFirmwareVersionString); + if (*FirmwareVersionString != 0x0000 ) { + FreePool (NewString); + NewString = (CHAR16 *) PcdGetPtr (PcdFirmwareVersionString); + UiCustomizeFrontPageBanner (3, TRUE, &NewString); + HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_BIOS_VERSION), NewString, NULL); + } else { + UiCustomizeFrontPageBanner (3, TRUE, &NewString); + HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_BIOS_VERSION), NewString, NULL); + FreePool (NewString); + } + } + + if (Record->Type == SMBIOS_TYPE_SYSTEM_INFORMATION) { + Type1Record = (SMBIOS_TABLE_TYPE1 *) Record; + StrIndex = Type1Record->ProductName; + GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type1Record + Type1Record->Hdr.Length), StrIndex, &NewString); + UiCustomizeFrontPageBanner (1, TRUE, &NewString); + HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_COMPUTER_MODEL), NewString, NULL); + FreePool (NewString); + } + + if ((Record->Type == SMBIOS_TYPE_PROCESSOR_INFORMATION) && !FoundCpu) { + Type4Record = (SMBIOS_TABLE_TYPE4 *) Record; + // + // The information in the record should be only valid when the CPU Socket is populated. + // + if ((Type4Record->Status & SMBIOS_TYPE4_CPU_SOCKET_POPULATED) == SMBIOS_TYPE4_CPU_SOCKET_POPULATED) { + StrIndex = Type4Record->ProcessorVersion; + GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type4Record + Type4Record->Hdr.Length), StrIndex, &NewString); + UiCustomizeFrontPageBanner (2, TRUE, &NewString); + HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_CPU_MODEL), NewString, NULL); + FreePool (NewString); + + ConvertProcessorToString(Type4Record->CurrentSpeed, 6, &NewString); + UiCustomizeFrontPageBanner (2, FALSE, &NewString); + HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_CPU_SPEED), NewString, NULL); + FreePool (NewString); + + FoundCpu = TRUE; + } + } + + if ( Record->Type == SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS ) { + Type19Record = (SMBIOS_TABLE_TYPE19 *) Record; + if (Type19Record->StartingAddress != 0xFFFFFFFF ) { + InstalledMemory += RShiftU64(Type19Record->EndingAddress - + Type19Record->StartingAddress + 1, 10); + } else { + InstalledMemory += RShiftU64(Type19Record->ExtendedEndingAddress - + Type19Record->ExtendedStartingAddress + 1, 20); + } + } + + Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record, NULL); + } + + // + // Now update the total installed RAM size + // + ConvertMemorySizeToString ((UINT32)InstalledMemory, &NewString ); + UiCustomizeFrontPageBanner (3, FALSE, &NewString); + HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_MEMORY_SIZE), NewString, NULL); + FreePool (NewString); +} + +/** + This function will change video resolution and text mode + according to defined setup mode or defined boot mode + + @param IsSetupMode Indicate mode is changed to setup mode or boot mode. + + @retval EFI_SUCCESS Mode is changed successfully. + @retval Others Mode failed to be changed. + +**/ +EFI_STATUS +UiSetConsoleMode ( + BOOLEAN IsSetupMode + ) +{ + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut; + UINTN SizeOfInfo; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; + UINT32 MaxGopMode; + UINT32 MaxTextMode; + UINT32 ModeNumber; + UINT32 NewHorizontalResolution; + UINT32 NewVerticalResolution; + UINT32 NewColumns; + UINT32 NewRows; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + EFI_STATUS Status; + UINTN Index; + UINTN CurrentColumn; + UINTN CurrentRow; + + MaxGopMode = 0; + MaxTextMode = 0; + + // + // Get current video resolution and text mode + // + Status = gBS->HandleProtocol ( + gST->ConsoleOutHandle, + &gEfiGraphicsOutputProtocolGuid, + (VOID**)&GraphicsOutput + ); + if (EFI_ERROR (Status)) { + GraphicsOutput = NULL; + } + + Status = gBS->HandleProtocol ( + gST->ConsoleOutHandle, + &gEfiSimpleTextOutProtocolGuid, + (VOID**)&SimpleTextOut + ); + if (EFI_ERROR (Status)) { + SimpleTextOut = NULL; + } + + if ((GraphicsOutput == NULL) || (SimpleTextOut == NULL)) { + return EFI_UNSUPPORTED; + } + + if (IsSetupMode) { + // + // The required resolution and text mode is setup mode. + // + NewHorizontalResolution = mSetupHorizontalResolution; + NewVerticalResolution = mSetupVerticalResolution; + NewColumns = mSetupTextModeColumn; + NewRows = mSetupTextModeRow; + } else { + // + // The required resolution and text mode is boot mode. + // + NewHorizontalResolution = mBootHorizontalResolution; + NewVerticalResolution = mBootVerticalResolution; + NewColumns = mBootTextModeColumn; + NewRows = mBootTextModeRow; + } + + if (GraphicsOutput != NULL) { + MaxGopMode = GraphicsOutput->Mode->MaxMode; + } + + if (SimpleTextOut != NULL) { + MaxTextMode = SimpleTextOut->Mode->MaxMode; + } + + // + // 1. If current video resolution is same with required video resolution, + // video resolution need not be changed. + // 1.1. If current text mode is same with required text mode, text mode need not be changed. + // 1.2. If current text mode is different from required text mode, text mode need be changed. + // 2. If current video resolution is different from required video resolution, we need restart whole console drivers. + // + for (ModeNumber = 0; ModeNumber < MaxGopMode; ModeNumber++) { + Status = GraphicsOutput->QueryMode ( + GraphicsOutput, + ModeNumber, + &SizeOfInfo, + &Info + ); + if (!EFI_ERROR (Status)) { + if ((Info->HorizontalResolution == NewHorizontalResolution) && + (Info->VerticalResolution == NewVerticalResolution)) { + if ((GraphicsOutput->Mode->Info->HorizontalResolution == NewHorizontalResolution) && + (GraphicsOutput->Mode->Info->VerticalResolution == NewVerticalResolution)) { + // + // Current resolution is same with required resolution, check if text mode need be set + // + Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, &CurrentColumn, &CurrentRow); + ASSERT_EFI_ERROR (Status); + if (CurrentColumn == NewColumns && CurrentRow == NewRows) { + // + // If current text mode is same with required text mode. Do nothing + // + FreePool (Info); + return EFI_SUCCESS; + } else { + // + // If current text mode is different from required text mode. Set new video mode + // + for (Index = 0; Index < MaxTextMode; Index++) { + Status = SimpleTextOut->QueryMode (SimpleTextOut, Index, &CurrentColumn, &CurrentRow); + if (!EFI_ERROR(Status)) { + if ((CurrentColumn == NewColumns) && (CurrentRow == NewRows)) { + // + // Required text mode is supported, set it. + // + Status = SimpleTextOut->SetMode (SimpleTextOut, Index); + ASSERT_EFI_ERROR (Status); + // + // Update text mode PCD. + // + Status = PcdSet32S (PcdConOutColumn, mSetupTextModeColumn); + ASSERT_EFI_ERROR (Status); + Status = PcdSet32S (PcdConOutRow, mSetupTextModeRow); + ASSERT_EFI_ERROR (Status); + FreePool (Info); + return EFI_SUCCESS; + } + } + } + if (Index == MaxTextMode) { + // + // If required text mode is not supported, return error. + // + FreePool (Info); + return EFI_UNSUPPORTED; + } + } + } else { + // + // If current video resolution is not same with the new one, set new video resolution. + // In this case, the driver which produces simple text out need be restarted. + // + Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber); + if (!EFI_ERROR (Status)) { + FreePool (Info); + break; + } + } + } + FreePool (Info); + } + } + + if (ModeNumber == MaxGopMode) { + // + // If the resolution is not supported, return error. + // + return EFI_UNSUPPORTED; + } + + // + // Set PCD to Inform GraphicsConsole to change video resolution. + // Set PCD to Inform Consplitter to change text mode. + // + Status = PcdSet32S (PcdVideoHorizontalResolution, NewHorizontalResolution); + ASSERT_EFI_ERROR (Status); + Status = PcdSet32S (PcdVideoVerticalResolution, NewVerticalResolution); + ASSERT_EFI_ERROR (Status); + Status = PcdSet32S (PcdConOutColumn, NewColumns); + ASSERT_EFI_ERROR (Status); + Status = PcdSet32S (PcdConOutRow, NewRows); + ASSERT_EFI_ERROR (Status); + + // + // Video mode is changed, so restart graphics console driver and higher level driver. + // Reconnect graphics console driver and higher level driver. + // Locate all the handles with GOP protocol and reconnect it. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleTextOutProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (!EFI_ERROR (Status)) { + for (Index = 0; Index < HandleCount; Index++) { + gBS->DisconnectController (HandleBuffer[Index], NULL, NULL); + } + for (Index = 0; Index < HandleCount; Index++) { + gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE); + } + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + } + + return EFI_SUCCESS; +} + +/** + The user Entry Point for Application. The user code starts with this function + as the real entry point for the image goes into a library that calls this + function. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +InitializeUserInterface ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_HII_HANDLE HiiHandle; + EFI_STATUS Status; + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut; + UINTN BootTextColumn; + UINTN BootTextRow; + + if (!mModeInitialized) { + // + // After the console is ready, get current video resolution + // and text mode before launching setup at first time. + // + Status = gBS->HandleProtocol ( + gST->ConsoleOutHandle, + &gEfiGraphicsOutputProtocolGuid, + (VOID**)&GraphicsOutput + ); + if (EFI_ERROR (Status)) { + GraphicsOutput = NULL; + } + + Status = gBS->HandleProtocol ( + gST->ConsoleOutHandle, + &gEfiSimpleTextOutProtocolGuid, + (VOID**)&SimpleTextOut + ); + if (EFI_ERROR (Status)) { + SimpleTextOut = NULL; + } + + if (GraphicsOutput != NULL) { + // + // Get current video resolution and text mode. + // + mBootHorizontalResolution = GraphicsOutput->Mode->Info->HorizontalResolution; + mBootVerticalResolution = GraphicsOutput->Mode->Info->VerticalResolution; + } + + if (SimpleTextOut != NULL) { + Status = SimpleTextOut->QueryMode ( + SimpleTextOut, + SimpleTextOut->Mode->Mode, + &BootTextColumn, + &BootTextRow + ); + mBootTextModeColumn = (UINT32)BootTextColumn; + mBootTextModeRow = (UINT32)BootTextRow; + } + + // + // Get user defined text mode for setup. + // + mSetupHorizontalResolution = PcdGet32 (PcdSetupVideoHorizontalResolution); + mSetupVerticalResolution = PcdGet32 (PcdSetupVideoVerticalResolution); + mSetupTextModeColumn = PcdGet32 (PcdSetupConOutColumn); + mSetupTextModeRow = PcdGet32 (PcdSetupConOutRow); + + mModeInitialized = TRUE; + } + + gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL); + gST->ConOut->ClearScreen (gST->ConOut); + + // + // Install customized fonts needed by Front Page + // + HiiHandle = ExportFonts (); + ASSERT (HiiHandle != NULL); + + InitializeStringSupport (); + + UiSetConsoleMode (TRUE); + UiEntry (FALSE); + UiSetConsoleMode (FALSE); + + UninitializeStringSupport (); + HiiRemovePackages (HiiHandle); + + return EFI_SUCCESS; +} + +/** + This function is the main entry of the UI entry. + The function will present the main menu of the system UI. + + @param ConnectAllHappened Caller passes the value to UI to avoid unnecessary connect-all. + +**/ +VOID +EFIAPI +UiEntry ( + IN BOOLEAN ConnectAllHappened + ) +{ + EFI_STATUS Status; + EFI_BOOT_LOGO_PROTOCOL *BootLogo; + + // + // Enter Setup page. + // + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_USER_SETUP) + ); + + // + // Indicate if the connect all has been performed before. + // If has not been performed before, do here. + // + if (!ConnectAllHappened) { + EfiBootManagerConnectAll (); + } + + // + // The boot option enumeration time is acceptable in Ui driver + // + EfiBootManagerRefreshAllBootOption (); + + // + // Boot Logo is corrupted, report it using Boot Logo protocol. + // + Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo); + if (!EFI_ERROR (Status) && (BootLogo != NULL)) { + BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0); + } + + InitializeFrontPage (); + + CallFrontPage (); + + FreeFrontPage (); + + if (mLanguageString != NULL) { + FreePool (mLanguageString); + mLanguageString = NULL; + } + + // + //Will leave browser, check any reset required change is applied? if yes, reset system + // + SetupResetReminder (); +} + +// +// Following are BDS Lib functions which contain all the code about setup browser reset reminder feature. +// Setup Browser reset reminder feature is that an reset reminder will be given before user leaves the setup browser if +// user change any option setting which needs a reset to be effective, and the reset will be applied according to the user selection. +// + + + + + +/** + Record the info that a reset is required. + A module boolean variable is used to record whether a reset is required. + +**/ +VOID +EFIAPI +EnableResetRequired ( + VOID + ) +{ + mResetRequired = TRUE; +} + + + + + +/** + Check if user changed any option setting which needs a system reset to be effective. + +**/ +BOOLEAN +EFIAPI +IsResetRequired ( + VOID + ) +{ + return mResetRequired; +} + + +/** + Check whether a reset is needed, and finish the reset reminder feature. + If a reset is needed, Popup a menu to notice user, and finish the feature + according to the user selection. + +**/ +VOID +EFIAPI +SetupResetReminder ( + VOID + ) +{ + EFI_INPUT_KEY Key; + CHAR16 *StringBuffer1; + CHAR16 *StringBuffer2; + + // + //check any reset required change is applied? if yes, reset system + // + if (IsResetRequired ()) { + + StringBuffer1 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16)); + ASSERT (StringBuffer1 != NULL); + StringBuffer2 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16)); + ASSERT (StringBuffer2 != NULL); + StrCpyS (StringBuffer1, MAX_STRING_LEN, L"Configuration changed. Reset to apply it Now."); + StrCpyS (StringBuffer2, MAX_STRING_LEN, L"Press ENTER to reset"); + // + // Popup a menu to notice user + // + do { + CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, StringBuffer1, StringBuffer2, NULL); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + FreePool (StringBuffer1); + FreePool (StringBuffer2); + + gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); + } +} + diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPage.h b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPage.h new file mode 100644 index 00000000..e7407eca --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPage.h @@ -0,0 +1,213 @@ +/** @file +Head file for front page. + +Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _FRONT_PAGE_H_ +#define _FRONT_PAGE_H_ + +#include "String.h" +#include "Ui.h" + +#include <Protocol/BootLogo.h> +// +// These is the VFR compiler generated data representing our VFR data. +// +extern UINT8 FrontPageVfrBin[]; + +extern EFI_FORM_BROWSER2_PROTOCOL *gFormBrowser2; + + +#define SMBIOS_TYPE4_CPU_SOCKET_POPULATED BIT6 + +// +// This is the VFR compiler generated header file which defines the +// string identifiers. +// +#define PRINTABLE_LANGUAGE_NAME_STRING_ID 0x0001 + +// +// These are defined as the same with vfr file +// +#define FRONT_PAGE_FORM_ID 0x1000 + +#define LABEL_FRANTPAGE_INFORMATION 0x1000 +#define LABEL_END 0xffff + +#define FRONT_PAGE_FORMSET_GUID \ + { \ + 0x9e0c30bc, 0x3f06, 0x4ba6, {0x82, 0x88, 0x9, 0x17, 0x9b, 0x85, 0x5d, 0xbe} \ + } + +#define FRONT_PAGE_CALLBACK_DATA_SIGNATURE SIGNATURE_32 ('F', 'P', 'C', 'B') + +typedef struct { + UINTN Signature; + + // + // HII relative handles + // + EFI_HII_HANDLE HiiHandle; + EFI_HANDLE DriverHandle; + EFI_STRING_ID *LanguageToken; + + // + // Produced protocols + // + EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess; +} FRONT_PAGE_CALLBACK_DATA; + + +#define EFI_FP_CALLBACK_DATA_FROM_THIS(a) \ + CR (a, \ + FRONT_PAGE_CALLBACK_DATA, \ + ConfigAccess, \ + FRONT_PAGE_CALLBACK_DATA_SIGNATURE \ + ) + +/** + This function allows a caller to extract the current configuration for one + or more named elements from the target driver. + + + @param This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Request - A null-terminated Unicode string in <ConfigRequest> format. + @param 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 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 NULL, illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. + +**/ +EFI_STATUS +EFIAPI +FakeExtractConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Request, + OUT EFI_STRING *Progress, + OUT EFI_STRING *Results + ); + +/** + This function processes the results of changes in configuration. + + + @param This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Configuration - A null-terminated Unicode string in <ConfigResp> format. + @param 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 +FakeRouteConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ); + +/** + This function processes the results of changes in configuration. + + + @param This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Action - Specifies the type of action taken by the browser. + @param QuestionId - A unique value which is sent to the original exporting driver + so that it can identify the type of data to expect. + @param Type - The type of value for the question. + @param Value - A pointer to the data being sent to the original exporting driver. + @param 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 +FrontPageCallback ( + 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 + ); + +/** + Initialize HII information for the FrontPage + + @retval EFI_SUCCESS The operation is successful. + @retval EFI_DEVICE_ERROR If the dynamic opcode creation failed. + +**/ +EFI_STATUS +InitializeFrontPage ( + VOID + ); + +/** + Acquire the string associated with the ProducerGuid and return it. + + + @param ProducerGuid - The Guid to search the HII database for + @param Token - The token value of the string to extract + @param String - The string that is extracted + + @retval EFI_SUCCESS The function returns EFI_SUCCESS always. + +**/ +EFI_STATUS +GetProducerString ( + IN EFI_GUID *ProducerGuid, + IN EFI_STRING_ID Token, + OUT CHAR16 **String + ); + +/** + This function is the main entry of the UI entry. + The function will present the main menu of the system UI. + + @param ConnectAllHappened Caller passes the value to UI to avoid unnecessary connect-all. + +**/ +VOID +EFIAPI +UiEntry ( + IN BOOLEAN ConnectAllHappened + ); + +/** + Extract device path for given HII handle and class guid. + + @param Handle The HII handle. + + @retval NULL Fail to get the device path string. + @return PathString Get the device path string. + +**/ +CHAR16 * +ExtractDevicePathFromHiiHandle ( + IN EFI_HII_HANDLE Handle + ); + +#endif // _FRONT_PAGE_H_ + diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPageCustomizedUi.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPageCustomizedUi.c new file mode 100644 index 00000000..3b777d7c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPageCustomizedUi.c @@ -0,0 +1,139 @@ +/** @file + + This library class defines a set of interfaces to customize Ui module + +Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include <Uefi.h> +#include <Protocol/HiiConfigAccess.h> +#include <Library/BaseLib.h> +#include <Library/MemoryAllocationLib.h> +#include "FrontPage.h" +#include "FrontPageCustomizedUiSupport.h" + +extern FRONT_PAGE_CALLBACK_DATA gFrontPagePrivate; + +/** + Customize menus in the page. + + @param[in] HiiHandle The HII Handle of the form to update. + @param[in] StartOpCodeHandle The context used to insert opcode. + @param[in] CustomizePageType The page type need to be customized. + +**/ +VOID +UiCustomizeFrontPage ( + IN EFI_HII_HANDLE HiiHandle, + IN VOID *StartOpCodeHandle + ) +{ + // + // Create "Select Language" menu with Oneof opcode. + // + UiCreateLanguageMenu (HiiHandle, StartOpCodeHandle); + + // + // Create empty line. + // + UiCreateEmptyLine(HiiHandle, StartOpCodeHandle); + + // + // Find third party drivers which need to be shown in the front page. + // + UiListThirdPartyDrivers (HiiHandle, &gEfiIfrFrontPageGuid, NULL, StartOpCodeHandle); + + // + // Create empty line. + // + UiCreateEmptyLine(HiiHandle, StartOpCodeHandle); + + // + // Create "Continue" menu. + // + UiCreateContinueMenu(HiiHandle, StartOpCodeHandle); + + // + // Create reset menu. + // + UiCreateResetMenu(HiiHandle, StartOpCodeHandle); +} + +/** + This function processes the results of changes in configuration. + + + @param HiiHandle Points to the hii handle for this formset. + @param Action Specifies the type of action taken by the browser. + @param QuestionId A unique value which is sent to the original exporting driver + so that it can identify the type of data to expect. + @param Type The type of value for the question. + @param Value A pointer to the data being sent to the original exporting driver. + @param 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 +UiFrontPageCallbackHandler ( + IN EFI_HII_HANDLE HiiHandle, + 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; + + if (UiSupportLibCallbackHandler (HiiHandle, Action, QuestionId, Type, Value, ActionRequest, &Status)) { + return Status; + } + + return EFI_UNSUPPORTED; +} + +/** + Update the banner string in the front page. + + Current layout for the banner string like below: + PS: Totally only 5 lines of banner supported. + + Line 1: Left BannerStr RightBannerStr + Line 2: Left BannerStr RightBannerStr + Line 3: Left BannerStr RightBannerStr + Line 4: Left BannerStr RightBannerStr + Line 5: Left BannerStr RightBannerStr + <EmptyLine> + First menu in front page. + ... + + @param LineIndex The line index of the banner need to check. + @param LeftOrRight The left or right banner need to check. + @param BannerStr Banner string need to update. + Input the current string and user can update + it and return the new string. + +**/ +VOID +UiCustomizeFrontPageBanner ( + IN UINTN LineIndex, + IN BOOLEAN LeftOrRight, + IN OUT EFI_STRING *BannerStr + ) +{ + if ((LineIndex == 5) && LeftOrRight) { + // Update STR_CUSTOMIZE_BANNER_LINE5_LEFT + if (PcdGetBool(PcdTestKeyUsed)) { + if (BannerStr != NULL) { + FreePool(*BannerStr); + } + *BannerStr = HiiGetString(gFrontPagePrivate.HiiHandle, STRING_TOKEN(STR_TEST_KEY_USED), NULL); + } + } + return; +} diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPageCustomizedUi.h b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPageCustomizedUi.h new file mode 100644 index 00000000..ecb58a1c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPageCustomizedUi.h @@ -0,0 +1,82 @@ +/** @file + This library class defines a set of interfaces to customize Ui module + +Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __FRONTPAGE_CUSTOMIZED_UI_H__ +#define __FRONTPAGE_CUSTOMIZED_UI_H__ + +/** + Update the banner string in the front page. + + Current layout for the banner string like below: + PS: Totally only 5 lines of banner supported. + + Line 1: Left BannerStr RightBannerStr + Line 2: Left BannerStr RightBannerStr + Line 3: Left BannerStr RightBannerStr + Line 4: Left BannerStr RightBannerStr + Line 5: Left BannerStr RightBannerStr + <EmptyLine> + First menu in front page. + ... + + @param LineIndex The line index of the banner need to check. + @param LeftOrRight The left or right banner need to check. + @param BannerStr Banner string need to update. + Input the current string and user can update + it and return the new string. + +**/ +VOID +UiCustomizeFrontPageBanner ( + IN UINTN LineIndex, + IN BOOLEAN LeftOrRight, + IN OUT EFI_STRING *BannerStr + ); + +/** + Customize menus in the page. + + @param[in] HiiHandle The HII Handle of the form to update. + @param[in] StartOpCodeHandle The context used to insert opcode. + +**/ +VOID +UiCustomizeFrontPage ( + IN EFI_HII_HANDLE HiiHandle, + IN VOID *StartOpCodeHandle + ); + +/** + This function processes the results of changes in configuration. + + + @param HiiHandle Points to the hii handle for this formset. + @param Action Specifies the type of action taken by the browser. + @param QuestionId A unique value which is sent to the original exporting driver + so that it can identify the type of data to expect. + @param Type The type of value for the question. + @param Value A pointer to the data being sent to the original exporting driver. + @param 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 +UiFrontPageCallbackHandler ( + IN EFI_HII_HANDLE HiiHandle, + 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 + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPageCustomizedUiSupport.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPageCustomizedUiSupport.c new file mode 100644 index 00000000..73baa037 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPageCustomizedUiSupport.c @@ -0,0 +1,672 @@ +/** @file + + This library class defines a set of interfaces to customize Ui module + +Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include <Uefi.h> + +#include <Guid/MdeModuleHii.h> +#include <Guid/GlobalVariable.h> + +#include <Protocol/HiiConfigAccess.h> +#include <Protocol/HiiString.h> + +#include <Library/HiiLib.h> +#include <Library/DebugLib.h> +#include <Library/UefiLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/PcdLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/UefiHiiServicesLib.h> +#include <Library/DevicePathLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include "FrontPageCustomizedUiSupport.h" + +// +// This is the VFR compiler generated header file which defines the +// string identifiers. +// +#define PRINTABLE_LANGUAGE_NAME_STRING_ID 0x0001 + +#define UI_HII_DRIVER_LIST_SIZE 0x8 + +#define FRONT_PAGE_KEY_CONTINUE 0x1000 +#define FRONT_PAGE_KEY_RESET 0x1001 +#define FRONT_PAGE_KEY_LANGUAGE 0x1002 +#define FRONT_PAGE_KEY_DRIVER 0x2000 + +typedef struct { + EFI_STRING_ID PromptId; + EFI_STRING_ID HelpId; + EFI_STRING_ID DevicePathId; + EFI_GUID FormSetGuid; + BOOLEAN EmptyLineAfter; +} UI_HII_DRIVER_INSTANCE; + +CHAR8 *gLanguageString; +EFI_STRING_ID *gLanguageToken; +UI_HII_DRIVER_INSTANCE *gHiiDriverList; +extern EFI_HII_HANDLE gStringPackHandle; +UINT8 gCurrentLanguageIndex; + + +/** + Get next language from language code list (with separator ';'). + + If LangCode is NULL, then ASSERT. + If Lang is NULL, then ASSERT. + + @param LangCode On input: point to first language in the list. On + output: point to next language in the list, or + NULL if no more language in the list. + @param Lang The first language in the list. + +**/ +VOID +GetNextLanguage ( + IN OUT CHAR8 **LangCode, + OUT CHAR8 *Lang + ) +{ + UINTN Index; + CHAR8 *StringPtr; + + ASSERT (LangCode != NULL); + ASSERT (*LangCode != NULL); + ASSERT (Lang != NULL); + + Index = 0; + StringPtr = *LangCode; + while (StringPtr[Index] != 0 && StringPtr[Index] != ';') { + Index++; + } + + CopyMem (Lang, StringPtr, Index); + Lang[Index] = 0; + + if (StringPtr[Index] == ';') { + Index++; + } + *LangCode = StringPtr + Index; +} + +/** + This function processes the language changes in configuration. + + @param Value A pointer to the data being sent to the original exporting driver. + + + @retval TRUE The callback successfully handled the action. + @retval FALSE The callback not supported in this handler. + +**/ +EFI_STATUS +LanguageChangeHandler ( + IN EFI_IFR_TYPE_VALUE *Value + ) +{ + CHAR8 *LangCode; + CHAR8 *Lang; + UINTN Index; + EFI_STATUS Status; + + // + // Allocate working buffer for RFC 4646 language in supported LanguageString. + // + Lang = AllocatePool (AsciiStrSize (gLanguageString)); + ASSERT (Lang != NULL); + + Index = 0; + LangCode = gLanguageString; + while (*LangCode != 0) { + GetNextLanguage (&LangCode, Lang); + + if (Index == Value->u8) { + gCurrentLanguageIndex = Value->u8; + break; + } + + Index++; + } + + if (Index == Value->u8) { + Status = gRT->SetVariable ( + L"PlatformLang", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + AsciiStrSize (Lang), + Lang + ); + if (EFI_ERROR (Status)) { + FreePool (Lang); + return EFI_DEVICE_ERROR; + } + } else { + ASSERT (FALSE); + } + FreePool (Lang); + + return EFI_SUCCESS; +} + +/** + This function processes the results of changes in configuration. + + + @param HiiHandle Points to the hii handle for this formset. + @param Action Specifies the type of action taken by the browser. + @param QuestionId A unique value which is sent to the original exporting driver + so that it can identify the type of data to expect. + @param Type The type of value for the question. + @param Value A pointer to the data being sent to the original exporting driver. + @param ActionRequest On return, points to the action requested by the callback function. + @param Status Return the handle status. + + @retval TRUE The callback successfully handled the action. + @retval FALSE The callback not supported in this handler. + +**/ +BOOLEAN +UiSupportLibCallbackHandler ( + IN EFI_HII_HANDLE HiiHandle, + 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, + OUT EFI_STATUS *Status + ) +{ + if (QuestionId != FRONT_PAGE_KEY_CONTINUE && + QuestionId != FRONT_PAGE_KEY_RESET && + QuestionId != FRONT_PAGE_KEY_LANGUAGE) { + return FALSE; + } + + if (Action == EFI_BROWSER_ACTION_RETRIEVE) { + if (QuestionId == FRONT_PAGE_KEY_LANGUAGE) { + Value->u8 = gCurrentLanguageIndex; + *Status = EFI_SUCCESS; + } else { + *Status = EFI_UNSUPPORTED; + } + return TRUE; + } + + if (Action != EFI_BROWSER_ACTION_CHANGED) { + // + // Do nothing for other UEFI Action. Only do call back when data is changed. + // + *Status = EFI_UNSUPPORTED; + return TRUE; + } + + if (Action == EFI_BROWSER_ACTION_CHANGED) { + if ((Value == NULL) || (ActionRequest == NULL)) { + *Status = EFI_INVALID_PARAMETER; + return TRUE; + } + + *Status = EFI_SUCCESS; + switch (QuestionId) { + case FRONT_PAGE_KEY_CONTINUE: + // + // This is the continue - clear the screen and return an error to get out of FrontPage loop + // + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; + break; + + case FRONT_PAGE_KEY_LANGUAGE: + *Status = LanguageChangeHandler(Value); + break; + + case FRONT_PAGE_KEY_RESET: + // + // Reset + // + gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); + *Status = EFI_UNSUPPORTED; + + default: + break; + } + } + + return TRUE; +} + +/** + Create Select language menu in the front page with oneof opcode. + + @param[in] HiiHandle The hii handle for the Uiapp driver. + @param[in] StartOpCodeHandle The opcode handle to save the new opcode. + +**/ +VOID +UiCreateLanguageMenu ( + IN EFI_HII_HANDLE HiiHandle, + IN VOID *StartOpCodeHandle + ) +{ + CHAR8 *LangCode; + CHAR8 *Lang; + UINTN LangSize; + CHAR8 *CurrentLang; + UINTN OptionCount; + CHAR16 *StringBuffer; + VOID *OptionsOpCodeHandle; + UINTN StringSize; + EFI_STATUS Status; + EFI_HII_STRING_PROTOCOL *HiiString; + + Lang = NULL; + StringBuffer = NULL; + + // + // Init OpCode Handle and Allocate space for creation of UpdateData Buffer + // + OptionsOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (OptionsOpCodeHandle != NULL); + + GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&CurrentLang, NULL); + + // + // Get Support language list from variable. + // + GetEfiGlobalVariable2 (L"PlatformLangCodes", (VOID**)&gLanguageString, NULL); + if (gLanguageString == NULL) { + gLanguageString = AllocateCopyPool ( + AsciiStrSize ((CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)), + (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes) + ); + ASSERT (gLanguageString != NULL); + } + + if (gLanguageToken == NULL) { + // + // Count the language list number. + // + LangCode = gLanguageString; + Lang = AllocatePool (AsciiStrSize (gLanguageString)); + ASSERT (Lang != NULL); + + OptionCount = 0; + while (*LangCode != 0) { + GetNextLanguage (&LangCode, Lang); + OptionCount ++; + } + + // + // Allocate extra 1 as the end tag. + // + gLanguageToken = AllocateZeroPool ((OptionCount + 1) * sizeof (EFI_STRING_ID)); + ASSERT (gLanguageToken != NULL); + + Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString); + ASSERT_EFI_ERROR (Status); + + LangCode = gLanguageString; + OptionCount = 0; + while (*LangCode != 0) { + GetNextLanguage (&LangCode, Lang); + + StringSize = 0; + Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL); + if (Status == EFI_BUFFER_TOO_SMALL) { + StringBuffer = AllocateZeroPool (StringSize); + ASSERT (StringBuffer != NULL); + Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL); + ASSERT_EFI_ERROR (Status); + } + + if (EFI_ERROR (Status)) { + LangSize = AsciiStrSize (Lang); + StringBuffer = AllocatePool (LangSize * sizeof (CHAR16)); + ASSERT (StringBuffer != NULL); + AsciiStrToUnicodeStrS (Lang, StringBuffer, LangSize); + } + + ASSERT (StringBuffer != NULL); + gLanguageToken[OptionCount] = HiiSetString (HiiHandle, 0, StringBuffer, NULL); + FreePool (StringBuffer); + + OptionCount++; + } + } + + ASSERT (gLanguageToken != NULL); + LangCode = gLanguageString; + OptionCount = 0; + if (Lang == NULL) { + Lang = AllocatePool (AsciiStrSize (gLanguageString)); + ASSERT (Lang != NULL); + } + while (*LangCode != 0) { + GetNextLanguage (&LangCode, Lang); + + if (CurrentLang != NULL && AsciiStrCmp (Lang, CurrentLang) == 0) { + HiiCreateOneOfOptionOpCode ( + OptionsOpCodeHandle, + gLanguageToken[OptionCount], + EFI_IFR_OPTION_DEFAULT, + EFI_IFR_NUMERIC_SIZE_1, + (UINT8) OptionCount + ); + gCurrentLanguageIndex = (UINT8) OptionCount; + } else { + HiiCreateOneOfOptionOpCode ( + OptionsOpCodeHandle, + gLanguageToken[OptionCount], + 0, + EFI_IFR_NUMERIC_SIZE_1, + (UINT8) OptionCount + ); + } + + OptionCount++; + } + + if (CurrentLang != NULL) { + FreePool (CurrentLang); + } + FreePool (Lang); + + HiiCreateOneOfOpCode ( + StartOpCodeHandle, + FRONT_PAGE_KEY_LANGUAGE, + 0, + 0, + STRING_TOKEN (STR_LANGUAGE_SELECT), + STRING_TOKEN (STR_LANGUAGE_SELECT_HELP), + EFI_IFR_FLAG_CALLBACK, + EFI_IFR_NUMERIC_SIZE_1, + OptionsOpCodeHandle, + NULL + ); +} + +/** + Create continue menu in the front page. + + @param[in] HiiHandle The hii handle for the Uiapp driver. + @param[in] StartOpCodeHandle The opcode handle to save the new opcode. + +**/ +VOID +UiCreateContinueMenu ( + IN EFI_HII_HANDLE HiiHandle, + IN VOID *StartOpCodeHandle + ) +{ + HiiCreateActionOpCode ( + StartOpCodeHandle, + FRONT_PAGE_KEY_CONTINUE, + STRING_TOKEN (STR_CONTINUE_PROMPT), + STRING_TOKEN (STR_CONTINUE_PROMPT), + EFI_IFR_FLAG_CALLBACK, + 0 + ); +} + +/** + Create empty line menu in the front page. + + @param HiiHandle The hii handle for the Uiapp driver. + @param StartOpCodeHandle The opcode handle to save the new opcode. + +**/ +VOID +UiCreateEmptyLine ( + IN EFI_HII_HANDLE HiiHandle, + IN VOID *StartOpCodeHandle + ) +{ + HiiCreateSubTitleOpCode (StartOpCodeHandle, STRING_TOKEN (STR_NULL_STRING), 0, 0, 0); +} + +/** + Create Reset menu in the front page. + + @param[in] HiiHandle The hii handle for the Uiapp driver. + @param[in] StartOpCodeHandle The opcode handle to save the new opcode. + +**/ +VOID +UiCreateResetMenu ( + IN EFI_HII_HANDLE HiiHandle, + IN VOID *StartOpCodeHandle + ) +{ + HiiCreateActionOpCode ( + StartOpCodeHandle, + FRONT_PAGE_KEY_RESET, + STRING_TOKEN (STR_RESET_STRING), + STRING_TOKEN (STR_RESET_STRING), + EFI_IFR_FLAG_CALLBACK, + 0 + ); +} + +/** + Extract device path for given HII handle and class guid. + + @param Handle The HII handle. + + @retval NULL Fail to get the device path string. + @return PathString Get the device path string. + +**/ +CHAR16 * +ExtractDevicePathFromHiiHandle ( + IN EFI_HII_HANDLE Handle + ) +{ + EFI_STATUS Status; + EFI_HANDLE DriverHandle; + + ASSERT (Handle != NULL); + + if (Handle == NULL) { + return NULL; + } + + Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, Handle, &DriverHandle); + if (EFI_ERROR (Status)) { + return NULL; + } + + return ConvertDevicePathToText(DevicePathFromHandle (DriverHandle), FALSE, FALSE); +} + +/** + Check whether this driver need to be shown in the front page. + + @param HiiHandle The hii handle for the driver. + @param Guid The special guid for the driver which is the target. + @param PromptId Return the prompt string id. + @param HelpId Return the help string id. + @param FormsetGuid Return the formset guid info. + + @retval EFI_SUCCESS Search the driver success + +**/ +BOOLEAN +RequiredDriver ( + IN EFI_HII_HANDLE HiiHandle, + IN EFI_GUID *Guid, + OUT EFI_STRING_ID *PromptId, + OUT EFI_STRING_ID *HelpId, + OUT VOID *FormsetGuid + ) +{ + EFI_STATUS Status; + UINT8 ClassGuidNum; + EFI_GUID *ClassGuid; + EFI_IFR_FORM_SET *Buffer; + UINTN BufferSize; + UINT8 *Ptr; + UINTN TempSize; + BOOLEAN RetVal; + + Status = HiiGetFormSetFromHiiHandle(HiiHandle, &Buffer,&BufferSize); + if (EFI_ERROR (Status)) { + return FALSE; + } + + RetVal = FALSE; + TempSize = 0; + Ptr = (UINT8 *) Buffer; + while(TempSize < BufferSize) { + TempSize += ((EFI_IFR_OP_HEADER *) Ptr)->Length; + + if (((EFI_IFR_OP_HEADER *) Ptr)->Length <= OFFSET_OF (EFI_IFR_FORM_SET, Flags)){ + Ptr += ((EFI_IFR_OP_HEADER *) Ptr)->Length; + continue; + } + + ClassGuidNum = (UINT8) (((EFI_IFR_FORM_SET *)Ptr)->Flags & 0x3); + ClassGuid = (EFI_GUID *) (VOID *)(Ptr + sizeof (EFI_IFR_FORM_SET)); + while (ClassGuidNum-- > 0) { + if (!CompareGuid (Guid, ClassGuid)){ + ClassGuid ++; + continue; + } + + *PromptId = ((EFI_IFR_FORM_SET *)Ptr)->FormSetTitle; + *HelpId = ((EFI_IFR_FORM_SET *)Ptr)->Help; + CopyMem (FormsetGuid, &((EFI_IFR_FORM_SET *) Ptr)->Guid, sizeof (EFI_GUID)); + RetVal = TRUE; + } + } + + FreePool (Buffer); + + return RetVal; +} + +/** + Search the drivers in the system which need to show in the front page + and insert the menu to the front page. + + @param HiiHandle The hii handle for the Uiapp driver. + @param ClassGuid The class guid for the driver which is the target. + @param SpecialHandlerFn The pointer to the special handler function, if any. + @param StartOpCodeHandle The opcode handle to save the new opcode. + + @retval EFI_SUCCESS Search the driver success + +**/ +EFI_STATUS +UiListThirdPartyDrivers ( + IN EFI_HII_HANDLE HiiHandle, + IN EFI_GUID *ClassGuid, + IN DRIVER_SPECIAL_HANDLER SpecialHandlerFn, + IN VOID *StartOpCodeHandle + ) +{ + UINTN Index; + EFI_STRING String; + EFI_STRING_ID Token; + EFI_STRING_ID TokenHelp; + EFI_HII_HANDLE *HiiHandles; + CHAR16 *DevicePathStr; + UINTN Count; + UINTN CurrentSize; + UI_HII_DRIVER_INSTANCE *DriverListPtr; + EFI_STRING NewName; + BOOLEAN EmptyLineAfter; + + if (gHiiDriverList != NULL) { + FreePool (gHiiDriverList); + } + + HiiHandles = HiiGetHiiHandles (NULL); + ASSERT (HiiHandles != NULL); + + gHiiDriverList = AllocateZeroPool (UI_HII_DRIVER_LIST_SIZE * sizeof (UI_HII_DRIVER_INSTANCE)); + ASSERT (gHiiDriverList != NULL); + DriverListPtr = gHiiDriverList; + CurrentSize = UI_HII_DRIVER_LIST_SIZE; + + for (Index = 0, Count = 0; HiiHandles[Index] != NULL; Index++) { + if (!RequiredDriver (HiiHandles[Index], ClassGuid, &Token, &TokenHelp, &gHiiDriverList[Count].FormSetGuid)) { + continue; + } + + String = HiiGetString (HiiHandles[Index], Token, NULL); + if (String == NULL) { + String = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_MISSING_STRING), NULL); + ASSERT (String != NULL); + } else if (SpecialHandlerFn != NULL) { + // + // Check whether need to rename the driver name. + // + EmptyLineAfter = FALSE; + if (SpecialHandlerFn (String, &NewName, &EmptyLineAfter)) { + FreePool (String); + String = NewName; + DriverListPtr[Count].EmptyLineAfter = EmptyLineAfter; + } + } + DriverListPtr[Count].PromptId = HiiSetString (HiiHandle, 0, String, NULL); + FreePool (String); + + String = HiiGetString (HiiHandles[Index], TokenHelp, NULL); + if (String == NULL) { + String = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_MISSING_STRING), NULL); + ASSERT (String != NULL); + } + DriverListPtr[Count].HelpId = HiiSetString (HiiHandle, 0, String, NULL); + FreePool (String); + + DevicePathStr = ExtractDevicePathFromHiiHandle(HiiHandles[Index]); + if (DevicePathStr != NULL){ + DriverListPtr[Count].DevicePathId = HiiSetString (HiiHandle, 0, DevicePathStr, NULL); + FreePool (DevicePathStr); + } else { + DriverListPtr[Count].DevicePathId = 0; + } + + Count++; + if (Count >= CurrentSize) { + DriverListPtr = ReallocatePool ( + CurrentSize * sizeof (UI_HII_DRIVER_INSTANCE), + (Count + UI_HII_DRIVER_LIST_SIZE) + * sizeof (UI_HII_DRIVER_INSTANCE), + gHiiDriverList + ); + ASSERT (DriverListPtr != NULL); + gHiiDriverList = DriverListPtr; + CurrentSize += UI_HII_DRIVER_LIST_SIZE; + } + } + + FreePool (HiiHandles); + + Index = 0; + while (gHiiDriverList[Index].PromptId != 0) { + HiiCreateGotoExOpCode ( + StartOpCodeHandle, + 0, + gHiiDriverList[Index].PromptId, + gHiiDriverList[Index].HelpId, + 0, + (EFI_QUESTION_ID) (Index + FRONT_PAGE_KEY_DRIVER), + 0, + &gHiiDriverList[Index].FormSetGuid, + gHiiDriverList[Index].DevicePathId + ); + + if (gHiiDriverList[Index].EmptyLineAfter) { + UiCreateEmptyLine (HiiHandle, StartOpCodeHandle); + } + + Index ++; + } + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPageCustomizedUiSupport.h b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPageCustomizedUiSupport.h new file mode 100644 index 00000000..58759fe1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPageCustomizedUiSupport.h @@ -0,0 +1,130 @@ +/** @file + This library class defines a set of interfaces to be used by customize Ui module + +Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __FRONTPAGE_CUSTOMIZE_UI_SUPPORT_UI_H__ +#define __FRONTPAGE_CUSTOMIZE_UI_SUPPORT_UI_H__ + +/** + Create continue menu in the front page. + + @param[in] HiiHandle The hii handle for the Uiapp driver. + @param[in] StartOpCodeHandle The opcode handle to save the new opcode. + +**/ +VOID +UiCreateContinueMenu ( + IN EFI_HII_HANDLE HiiHandle, + IN VOID *StartOpCodeHandle + ); + +/** + Create empty line menu. + + @param HiiHandle The hii handle for the Uiapp driver. + @param StartOpCodeHandle The opcode handle to save the new opcode. + +**/ +VOID +UiCreateEmptyLine ( + IN EFI_HII_HANDLE HiiHandle, + IN VOID *StartOpCodeHandle + ); + +/** + Create Select language menu in the front page with oneof opcode. + + @param[in] HiiHandle The hii handle for the Uiapp driver. + @param[in] StartOpCodeHandle The opcode handle to save the new opcode. + +**/ +VOID +UiCreateLanguageMenu ( + IN EFI_HII_HANDLE HiiHandle, + IN VOID *StartOpCodeHandle + ); + +/** + Create Reset menu. + + @param[in] HiiHandle The hii handle for the Uiapp driver. + @param[in] StartOpCodeHandle The opcode handle to save the new opcode. + +**/ +VOID +UiCreateResetMenu ( + IN EFI_HII_HANDLE HiiHandle, + IN VOID *StartOpCodeHandle + ); + +/** + Rename the driver name if necessary. + + @param DriverName Input the driver name. + @param NewDriverName Return the new driver name. + @param EmptyLineAfter Whether need to insert empty line. + + @retval New driver name if compared, else NULL. + +**/ +typedef +BOOLEAN +(EFIAPI *DRIVER_SPECIAL_HANDLER)( + IN CHAR16 *DriverName, + OUT CHAR16 **NewName, + OUT BOOLEAN *EmptyLineAfter +); + +/** + Search the drivers in the system which need to show in the front page + and insert the menu to the front page. + + @param HiiHandle The hii handle for the Uiapp driver. + @param ClassGuid The class guid for the driver which is the target. + @param SpecialHandlerFn The pointer to the special handler function, if any. + @param StartOpCodeHandle The opcode handle to save the new opcode. + + @retval EFI_SUCCESS Search the driver success + +**/ +EFI_STATUS +UiListThirdPartyDrivers ( + IN EFI_HII_HANDLE HiiHandle, + IN EFI_GUID *ClassGuid, + IN DRIVER_SPECIAL_HANDLER SpecialHandlerFn, + IN VOID *StartOpCodeHandle + ); + +/** + This function processes the results of changes in configuration. + + + @param HiiHandle Points to the hii handle for this formset. + @param Action Specifies the type of action taken by the browser. + @param QuestionId A unique value which is sent to the original exporting driver + so that it can identify the type of data to expect. + @param Type The type of value for the question. + @param Value A pointer to the data being sent to the original exporting driver. + @param ActionRequest On return, points to the action requested by the callback function. + @param Status Return the handle status. + + @retval TRUE The callback successfully handled the action. + @retval FALSE The callback not supported in this handler. + +**/ +BOOLEAN +UiSupportLibCallbackHandler ( + IN EFI_HII_HANDLE HiiHandle, + 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, + OUT EFI_STATUS *Status + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPageStrings.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPageStrings.uni new file mode 100644 index 00000000..a0ab9abc --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPageStrings.uni @@ -0,0 +1,68 @@ +///** @file
+//
+// String definitions for BdsPlatform formset.
+//
+// Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+//**/
+
+/=#
+
+#langdef en-US "English"
+#langdef fr-FR "Français"
+#langdef en "Standard English"
+#langdef fr "Standard Français"
+
+#string STR_FRONT_PAGE_TITLE #language en-US "Front Page"
+ #language fr-FR "Front Page"
+#string STR_FRONT_PAGE_COMPUTER_MODEL #language en-US ""
+ #language fr-FR ""
+#string STR_FRONT_PAGE_CPU_MODEL #language en-US ""
+ #language fr-FR ""
+#string STR_FRONT_PAGE_CPU_SPEED #language en-US ""
+ #language fr-FR ""
+#string STR_FRONT_PAGE_MEMORY_SIZE #language en-US ""
+ #language fr-FR ""
+#string STR_FRONT_PAGE_BIOS_VERSION #language en-US ""
+ #language fr-FR ""
+#string STR_FRONT_PAGE_BANNER_0_LEFT #language en-US "Wonder Computer Model 1000Z Manufactured by Intel®"
+ #language fr-FR "Demander le Modèle d'Ordinateur 1000Z A Fabriqué par Intel®"
+#string STR_FRONT_PAGE_BANNER_0_RIGHT #language en-US "OK"
+ #language fr-FR "Bon"
+#string STR_FRONT_PAGE_BANNER_1_LEFT #language en-US "2 Pentium® X Xeon processors running at 800Thz"
+ #language fr-FR "2 processeurs Pentium® X Xeon tournants à 800Thz"
+#string STR_FRONT_PAGE_BANNER_1_RIGHT #language en-US "24 TB System RAM"
+ #language fr-FR "24 TB RAM de Système"
+#string STR_FRONT_PAGE_BANNER_2_LEFT #language en-US "ACME® EFI BIOS Version 13.5 Release 1039.92"
+ #language fr-FR "ACME® EFI BIOS Version 13.5 Release 1039.92"
+#string STR_FRONT_PAGE_BANNER_3_LEFT #language en-US "Serial Number: 1Z123456789MARMAR (Need SMBIOS entries)"
+ #language fr-FR "Numéro de série: 1Z123456789MARMAR (Les entrées de SMBIOS de besoin)"
+#string STR_CONTINUE_PROMPT #language en-US "Continue"
+ #language fr-FR "Continuer"
+#string STR_CONTINUE_HELP #language en-US "This selection will direct the system to continue to booting process"
+ #language fr-FR "Cette sélection dirigera le système pour continuer au processus d'amorçage"
+#string STR_LANGUAGE_SELECT #language en-US "Select Language"
+ #language fr-FR "Choisir la Langue"
+#string STR_LANGUAGE_SELECT_HELP #language en-US "This is the option one adjusts to change the language for the current system"
+ #language fr-FR "Ceci est l'option qu'on ajuste pour changer la langue pour le système actuel"
+#string STR_MISSING_STRING #language en-US "Missing String"
+ #language fr-FR "Missing String"
+#string STR_EMPTY_STRING #language en-US ""
+ #language fr-FR ""
+#string STR_RESET_STRING #language en-US "Reset"
+ #language fr-FR "Reset"
+#string STR_RESET_STRING_HELP #language en-US "Reset the current setting."
+ #language fr-FR "Reset the current setting."
+#string STR_CUSTOMIZE_BANNER_LINE4_LEFT #language en-US ""
+ #language fr-FR ""
+#string STR_CUSTOMIZE_BANNER_LINE4_RIGHT #language en-US ""
+ #language fr-FR ""
+#string STR_CUSTOMIZE_BANNER_LINE5_LEFT #language en-US ""
+ #language fr-FR ""
+#string STR_CUSTOMIZE_BANNER_LINE5_RIGHT #language en-US ""
+ #language fr-FR ""
+#string STR_TEST_KEY_USED #language en-US "WARNING: Test key detected."
+ #language fr-FR "WARNING: Test key detected."
+#string STR_NULL_STRING #language en-US " "
+ #language fr-FR " "
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPageVfr.Vfr b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPageVfr.Vfr new file mode 100644 index 00000000..bf75bf22 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/FrontPageVfr.Vfr @@ -0,0 +1,80 @@ +///** @file +// +// Front page formset. +// +// Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR> +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +//**/ + +#define FORMSET_GUID { 0x9e0c30bc, 0x3f06, 0x4ba6, 0x82, 0x88, 0x9, 0x17, 0x9b, 0x85, 0x5d, 0xbe } + +#define FRONT_PAGE_FORM_ID 0x1000 + +#define LABEL_FRANTPAGE_INFORMATION 0x1000 +#define LABEL_END 0xffff + +formset + guid = FORMSET_GUID, + title = STRING_TOKEN(STR_FRONT_PAGE_TITLE), + help = STRING_TOKEN(STR_EMPTY_STRING ), + classguid = FORMSET_GUID, + + form formid = FRONT_PAGE_FORM_ID, + title = STRING_TOKEN(STR_FRONT_PAGE_TITLE); + + banner + title = STRING_TOKEN(STR_FRONT_PAGE_COMPUTER_MODEL), + line 1, + align left; + + banner + title = STRING_TOKEN(STR_FRONT_PAGE_CPU_MODEL), + line 2, + align left; + + banner + title = STRING_TOKEN(STR_FRONT_PAGE_CPU_SPEED), + line 2, + align right; + + banner + title = STRING_TOKEN(STR_FRONT_PAGE_BIOS_VERSION), + line 3, + align left; + + banner + title = STRING_TOKEN(STR_FRONT_PAGE_MEMORY_SIZE), + line 3, + align right; + + banner + title = STRING_TOKEN(STR_CUSTOMIZE_BANNER_LINE4_LEFT), + line 4, + align left; + + banner + title = STRING_TOKEN(STR_CUSTOMIZE_BANNER_LINE4_RIGHT), + line 4, + align right; + + banner + title = STRING_TOKEN(STR_CUSTOMIZE_BANNER_LINE5_LEFT), + line 5, + align left; + + banner + title = STRING_TOKEN(STR_CUSTOMIZE_BANNER_LINE5_RIGHT), + line 5, + align right; + + label LABEL_FRANTPAGE_INFORMATION; + // + // This is where we will dynamically add a Action type op-code to show + // the platform information. + // + label LABEL_END; + + endform; + +endformset; diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/String.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/String.c new file mode 100644 index 00000000..d40c06f6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/String.c @@ -0,0 +1,316 @@ +/** @file + String support + +Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Ui.h" +#include "FrontPage.h" + +EFI_HII_HANDLE gStringPackHandle; + +EFI_GUID mUiStringPackGuid = { + 0x136a3048, 0x752a, 0x4bf6, { 0xa7, 0x57, 0x9, 0x36, 0x11, 0x95, 0x38, 0xed } +}; + +EFI_GUID mFontPackageGuid = { + 0x78941450, 0x90ab, 0x4fb1, {0xb7, 0x5f, 0x58, 0x92, 0x14, 0xe2, 0x4a, 0xc} +}; + +#define NARROW_GLYPH_NUMBER 8 +#define WIDE_GLYPH_NUMBER 75 + +typedef struct { + /// + /// This 4-bytes total array length is required by HiiAddPackages() + /// + UINT32 Length; + + // + // This is the Font package definition + // + EFI_HII_PACKAGE_HEADER Header; + UINT16 NumberOfNarrowGlyphs; + UINT16 NumberOfWideGlyphs; + EFI_NARROW_GLYPH NarrowArray[NARROW_GLYPH_NUMBER]; + EFI_WIDE_GLYPH WideArray[WIDE_GLYPH_NUMBER]; +} FONT_PACK_BIN; + +FONT_PACK_BIN mFontBin = { + sizeof (FONT_PACK_BIN), + { + sizeof (FONT_PACK_BIN) - sizeof (UINT32), + EFI_HII_PACKAGE_SIMPLE_FONTS, + }, + NARROW_GLYPH_NUMBER, + 0, + { // Narrow Glyphs + { + 0x05d0, + 0x00, + { + 0x00, + 0x00, + 0x00, + 0x4E, + 0x6E, + 0x62, + 0x32, + 0x32, + 0x3C, + 0x68, + 0x4C, + 0x4C, + 0x46, + 0x76, + 0x72, + 0x00, + 0x00, + 0x00, + 0x00 + } + }, + { + 0x05d1, + 0x00, + { + 0x00, + 0x00, + 0x00, + 0x78, + 0x7C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x7E, + 0x7E, + 0x00, + 0x00, + 0x00, + 0x00 + } + }, + { + 0x05d2, + 0x00, + { + 0x00, + 0x00, + 0x00, + 0x78, + 0x7C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x1C, + 0x3E, + 0x66, + 0x66, + 0x00, + 0x00, + 0x00, + 0x00 + } + }, + { + 0x05d3, + 0x00, + { + 0x00, + 0x00, + 0x00, + 0x7E, + 0x7E, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x00, + 0x00, + 0x00, + 0x00 + } + }, + { + 0x05d4, + 0x00, + { + 0x00, + 0x00, + 0x00, + 0x7C, + 0x7E, + 0x06, + 0x06, + 0x06, + 0x06, + 0x66, + 0x66, + 0x66, + 0x66, + 0x66, + 0x66, + 0x00, + 0x00, + 0x00, + 0x00 + } + }, + { + 0x05d5, + 0x00, + { + 0x00, + 0x00, + 0x00, + 0x3C, + 0x3C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x00, + 0x00, + 0x00, + 0x00 + } + }, + { + 0x05d6, + 0x00, + { + 0x00, + 0x00, + 0x00, + 0x38, + 0x38, + 0x1E, + 0x1E, + 0x18, + 0x18, + 0x18, + 0x18, + 0x18, + 0x18, + 0x18, + 0x18, + 0x00, + 0x00, + 0x00, + 0x00 + } + }, + { + 0x0000, + 0x00, + { + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 + } + } + } +}; + +/** + Initialize HII global accessor for string support. + +**/ +VOID +InitializeStringSupport ( + VOID + ) +{ + gStringPackHandle = HiiAddPackages ( + &mUiStringPackGuid, + gImageHandle, + UiAppStrings, + NULL + ); + ASSERT (gStringPackHandle != NULL); +} + +/** + Remove the string package. + +**/ +VOID +UninitializeStringSupport ( + VOID + ) +{ + HiiRemovePackages (gStringPackHandle); +} + +/** + Get string by string id from HII Interface + + + @param Id String ID. + + @retval CHAR16 * String from ID. + @retval NULL If error occurs. + +**/ +CHAR16 * +GetStringById ( + IN EFI_STRING_ID Id + ) +{ + return HiiGetString (gStringPackHandle, Id, NULL); +} + +/** + Routine to export glyphs to the HII database. This is in addition to whatever is defined in the Graphics Console driver. + +**/ +EFI_HII_HANDLE +ExportFonts ( + VOID + ) +{ + return HiiAddPackages ( + &mFontPackageGuid, + gImageHandle, + &mFontBin, + NULL + ); +} diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/String.h b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/String.h new file mode 100644 index 00000000..2171e3c1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/String.h @@ -0,0 +1,71 @@ +/** @file + String support + +Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _STRING_H_ +#define _STRING_H_ + +extern EFI_HII_HANDLE gStringPackHandle; + +// +// This is the VFR compiler generated header file which defines the +// string identifiers. +// + +extern UINT8 BdsDxeStrings[]; + +// +// String Definition Guid for BDS Platform +// +#define EFI_BDS_PLATFORM_GUID \ + { \ + 0x7777E939, 0xD57E, 0x4DCB, 0xA0, 0x8E, 0x64, 0xD7, 0x98, 0x57, 0x1E, 0x0F \ + } + +/** + Get string by string id from HII Interface + + + @param Id String ID. + + @retval CHAR16 * String from ID. + @retval NULL If error occurs. + +**/ +CHAR16 * +GetStringById ( + IN EFI_STRING_ID Id + ); + +/** + Initialize HII global accessor for string support. + +**/ +VOID +InitializeStringSupport ( + VOID + ); + +/** + Remove the string package. + +**/ +VOID +UninitializeStringSupport ( + VOID + ); + +/** + Routine to export glyphs to the HII database. This is in addition to whatever is defined in the Graphics Console driver. + +**/ +EFI_HII_HANDLE +ExportFonts ( + VOID + ); + +#endif // _STRING_H_ diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/Ui.h b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/Ui.h new file mode 100644 index 00000000..def221c7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/Ui.h @@ -0,0 +1,97 @@ +/** @file + FrontPage routines to handle the callbacks and browser calls + +Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef _BDS_MODULE_H_ +#define _BDS_MODULE_H_ + +#include <IndustryStandard/SmBios.h> + +#include <Guid/MdeModuleHii.h> +#include <Guid/StatusCodeDataTypeId.h> + +#include <Protocol/Smbios.h> +#include <Protocol/HiiConfigAccess.h> + +#include <Library/PrintLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/ReportStatusCodeLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/HiiLib.h> +#include <Library/DevicePathLib.h> +#include <Library/UefiHiiServicesLib.h> +#include <Library/UefiBootManagerLib.h> + +#pragma pack(1) + +/// +/// HII specific Vendor Device Path definition. +/// +typedef struct { + VENDOR_DEVICE_PATH VendorDevicePath; + EFI_DEVICE_PATH_PROTOCOL End; +} HII_VENDOR_DEVICE_PATH; + +#pragma pack() + + +// +//The interface functions related to the Setup Browser Reset Reminder feature +// + + +/** + Record the info that a reset is required. + A module boolean variable is used to record whether a reset is required. + +**/ +VOID +EFIAPI +EnableResetRequired ( + VOID + ); + + + +/** + Check whether platform policy enables the reset reminder feature. The default is enabled. + +**/ +BOOLEAN +EFIAPI +IsResetReminderFeatureEnable ( + VOID + ); + +/** + Check if the user changed any option setting that needs a system reset to be effective. + +**/ +BOOLEAN +EFIAPI +IsResetRequired ( + VOID + ); + +/** + Check whether a reset is needed, and finish the reset reminder feature. + If a reset is needed, pop up a menu to notice user, and finish the feature + according to the user selection. + +**/ +VOID +EFIAPI +SetupResetReminder ( + VOID + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/UiApp.inf b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/UiApp.inf new file mode 100644 index 00000000..216619ad --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/UiApp.inf @@ -0,0 +1,82 @@ +## @file +# UiApp module is driver for BDS phase. +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = UiApp + MODULE_UNI_FILE = UiApp.uni + FILE_GUID = 462CAA21-7614-4503-836E-8AB6F4662331 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeUserInterface + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + FrontPage.h + String.h + Ui.h + FrontPageVfr.Vfr + FrontPageStrings.uni + FrontPage.c + String.c + FrontPageCustomizedUi.c + FrontPageCustomizedUiSupport.c + FrontPageCustomizedUi.h + FrontPageCustomizedUiSupport.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + DevicePathLib + BaseLib + UefiRuntimeServicesTableLib + ReportStatusCodeLib + MemoryAllocationLib + UefiLib + UefiBootServicesTableLib + BaseMemoryLib + DebugLib + PrintLib + HiiLib + UefiApplicationEntryPoint + PcdLib + UefiHiiServicesLib + UefiBootManagerLib + +[Guids] + gEfiIfrTianoGuid ## CONSUMES ## GUID (Extended IFR Guid Opcode) + gEfiIfrFrontPageGuid ## CONSUMES ## GUID + +[Protocols] + gEfiSmbiosProtocolGuid ## CONSUMES + gEfiHiiConfigAccessProtocolGuid ## CONSUMES + +[FeaturePcd] + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLangCodes ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow ## PRODUCES + gEfiMdeModulePkgTokenSpaceGuid.PcdConOutColumn ## PRODUCES + gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution ## PRODUCES + gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution ## PRODUCES + gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutColumn ## CONSUMES ## SOMETIMES_PRODUCES + gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutRow ## CONSUMES ## SOMETIMES_PRODUCES + gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoHorizontalResolution ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoVerticalResolution ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdTestKeyUsed ## CONSUMES + +[UserExtensions.TianoCore."ExtraFiles"] + UiAppExtra.uni diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/UiApp.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/UiApp.uni new file mode 100644 index 00000000..89448ef2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/UiApp.uni @@ -0,0 +1,17 @@ +// /** @file
+// UiApp module is driver for BDS phase.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT
+#language en-US
+"UiApp module is driver for BDS phase."
+
+#string STR_MODULE_DESCRIPTION
+#language en-US
+"UiApp module is driver for BDS phase."
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/UiAppExtra.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/UiAppExtra.uni new file mode 100644 index 00000000..2e0972ce --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/UiApp/UiAppExtra.uni @@ -0,0 +1,12 @@ +// /** @file
+// UiApp Localized Strings and Content
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME #language en-US "UiApp module"
+
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/VariableInfo/VariableInfo.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/VariableInfo/VariableInfo.c new file mode 100644 index 00000000..54aafed0 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/VariableInfo/VariableInfo.c @@ -0,0 +1,273 @@ +/** @file + If the Variable services have PcdVariableCollectStatistics set to TRUE then + this utility will print out the statistics information. You can use console + redirection to capture the data. + + Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Uefi.h> +#include <Library/UefiLib.h> +#include <Library/UefiApplicationEntryPoint.h> +#include <Library/BaseMemoryLib.h> +#include <Library/BaseLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/DebugLib.h> +#include <Library/UefiBootServicesTableLib.h> + +#include <Guid/VariableFormat.h> +#include <Guid/SmmVariableCommon.h> +#include <Guid/PiSmmCommunicationRegionTable.h> +#include <Protocol/MmCommunication2.h> +#include <Protocol/SmmVariable.h> + +EFI_MM_COMMUNICATION2_PROTOCOL *mMmCommunication2 = NULL; + +/** + This function get the variable statistics data from SMM variable driver. + + @param[in, out] SmmCommunicateHeader In input, a pointer to a collection of data that will + be passed into an SMM environment. In output, a pointer + to a collection of data that comes from an SMM environment. + @param[in, out] SmmCommunicateSize The size of the SmmCommunicateHeader. + + @retval EFI_SUCCESS Get the statistics data information. + @retval EFI_NOT_FOUND Not found. + @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result. + +**/ +EFI_STATUS +EFIAPI +GetVariableStatisticsData ( + IN OUT EFI_MM_COMMUNICATE_HEADER *SmmCommunicateHeader, + IN OUT UINTN *SmmCommunicateSize + ) +{ + EFI_STATUS Status; + SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader; + + CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid); + SmmCommunicateHeader->MessageLength = *SmmCommunicateSize - OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data); + + SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) &SmmCommunicateHeader->Data[0]; + SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_STATISTICS; + + Status = mMmCommunication2->Communicate (mMmCommunication2, + SmmCommunicateHeader, + SmmCommunicateHeader, + SmmCommunicateSize); + ASSERT_EFI_ERROR (Status); + + Status = SmmVariableFunctionHeader->ReturnStatus; + return Status; +} + +/** + + This function get and print the variable statistics data from SMM variable driver. + + @retval EFI_SUCCESS Print the statistics information successfully. + @retval EFI_NOT_FOUND Not found the statistics information. + +**/ +EFI_STATUS +PrintInfoFromSmm ( + VOID + ) +{ + EFI_STATUS Status; + VARIABLE_INFO_ENTRY *VariableInfo; + EFI_MM_COMMUNICATE_HEADER *CommBuffer; + UINTN RealCommSize; + UINTN CommSize; + SMM_VARIABLE_COMMUNICATE_HEADER *FunctionHeader; + EFI_SMM_VARIABLE_PROTOCOL *Smmvariable; + EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *PiSmmCommunicationRegionTable; + UINT32 Index; + EFI_MEMORY_DESCRIPTOR *Entry; + UINTN Size; + UINTN MaxSize; + + Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &Smmvariable); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->LocateProtocol (&gEfiMmCommunication2ProtocolGuid, NULL, (VOID **) &mMmCommunication2); + if (EFI_ERROR (Status)) { + return Status; + } + + CommBuffer = NULL; + RealCommSize = 0; + Status = EfiGetSystemConfigurationTable ( + &gEdkiiPiSmmCommunicationRegionTableGuid, + (VOID **) &PiSmmCommunicationRegionTable + ); + if (EFI_ERROR (Status)) { + return Status; + } + ASSERT (PiSmmCommunicationRegionTable != NULL); + Entry = (EFI_MEMORY_DESCRIPTOR *) (PiSmmCommunicationRegionTable + 1); + Size = 0; + MaxSize = 0; + for (Index = 0; Index < PiSmmCommunicationRegionTable->NumberOfEntries; Index++) { + if (Entry->Type == EfiConventionalMemory) { + Size = EFI_PAGES_TO_SIZE ((UINTN) Entry->NumberOfPages); + if (Size > (SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (VARIABLE_INFO_ENTRY))) { + if (Size > MaxSize) { + MaxSize = Size; + RealCommSize = MaxSize; + CommBuffer = (EFI_MM_COMMUNICATE_HEADER *) (UINTN) Entry->PhysicalStart; + } + } + } + Entry = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) Entry + PiSmmCommunicationRegionTable->DescriptorSize); + } + ASSERT (CommBuffer != NULL); + ZeroMem (CommBuffer, RealCommSize); + + Print (L"SMM Driver Non-Volatile Variables:\n"); + do { + CommSize = RealCommSize; + Status = GetVariableStatisticsData (CommBuffer, &CommSize); + if (Status == EFI_BUFFER_TOO_SMALL) { + Print (L"The generic SMM communication buffer provided by SmmCommunicationRegionTable is too small\n"); + return Status; + } + + if (EFI_ERROR (Status) || (CommSize <= SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE)) { + break; + } + + FunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) CommBuffer->Data; + VariableInfo = (VARIABLE_INFO_ENTRY *) FunctionHeader->Data; + + if (!VariableInfo->Volatile) { + Print ( + L"%g R%03d(%03d) W%03d D%03d:%s\n", + &VariableInfo->VendorGuid, + VariableInfo->ReadCount, + VariableInfo->CacheCount, + VariableInfo->WriteCount, + VariableInfo->DeleteCount, + (CHAR16 *)(VariableInfo + 1) + ); + } + } while (TRUE); + + Print (L"SMM Driver Volatile Variables:\n"); + ZeroMem (CommBuffer, RealCommSize); + do { + CommSize = RealCommSize; + Status = GetVariableStatisticsData (CommBuffer, &CommSize); + if (Status == EFI_BUFFER_TOO_SMALL) { + Print (L"The generic SMM communication buffer provided by SmmCommunicationRegionTable is too small\n"); + return Status; + } + + if (EFI_ERROR (Status) || (CommSize <= SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE)) { + break; + } + + FunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) CommBuffer->Data; + VariableInfo = (VARIABLE_INFO_ENTRY *) FunctionHeader->Data; + + if (VariableInfo->Volatile) { + Print ( + L"%g R%03d(%03d) W%03d D%03d:%s\n", + &VariableInfo->VendorGuid, + VariableInfo->ReadCount, + VariableInfo->CacheCount, + VariableInfo->WriteCount, + VariableInfo->DeleteCount, + (CHAR16 *)(VariableInfo + 1) + ); + } + } while (TRUE); + + return Status; +} + +/** + The user Entry Point for Application. The user code starts with this function + as the real entry point for the image goes into a library that calls this + function. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +UefiMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS RuntimeDxeStatus; + EFI_STATUS SmmStatus; + VARIABLE_INFO_ENTRY *VariableInfo; + VARIABLE_INFO_ENTRY *Entry; + + RuntimeDxeStatus = EfiGetSystemConfigurationTable (&gEfiVariableGuid, (VOID **) &Entry); + if (EFI_ERROR (RuntimeDxeStatus) || (Entry == NULL)) { + RuntimeDxeStatus = EfiGetSystemConfigurationTable (&gEfiAuthenticatedVariableGuid, (VOID **) &Entry); + } + + if (!EFI_ERROR (RuntimeDxeStatus) && (Entry != NULL)) { + Print (L"Runtime DXE Driver Non-Volatile EFI Variables:\n"); + VariableInfo = Entry; + do { + if (!VariableInfo->Volatile) { + Print ( + L"%g R%03d(%03d) W%03d D%03d:%s\n", + &VariableInfo->VendorGuid, + VariableInfo->ReadCount, + VariableInfo->CacheCount, + VariableInfo->WriteCount, + VariableInfo->DeleteCount, + VariableInfo->Name + ); + } + + VariableInfo = VariableInfo->Next; + } while (VariableInfo != NULL); + + Print (L"Runtime DXE Driver Volatile EFI Variables:\n"); + VariableInfo = Entry; + do { + if (VariableInfo->Volatile) { + Print ( + L"%g R%03d(%03d) W%03d D%03d:%s\n", + &VariableInfo->VendorGuid, + VariableInfo->ReadCount, + VariableInfo->CacheCount, + VariableInfo->WriteCount, + VariableInfo->DeleteCount, + VariableInfo->Name + ); + } + VariableInfo = VariableInfo->Next; + } while (VariableInfo != NULL); + } + + SmmStatus = PrintInfoFromSmm (); + + if (EFI_ERROR (RuntimeDxeStatus) && EFI_ERROR (SmmStatus)) { + Print (L"Warning: Variable Dxe/Smm driver doesn't enable the feature of statistical information!\n"); + Print (L"If you want to see this info, please:\n"); + Print (L" 1. Set PcdVariableCollectStatistics as TRUE\n"); + Print (L" 2. Rebuild Variable Dxe/Smm driver\n"); + Print (L" 3. Run \"VariableInfo\" cmd again\n"); + + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/VariableInfo/VariableInfo.inf b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/VariableInfo/VariableInfo.inf new file mode 100644 index 00000000..feb8935a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/VariableInfo/VariableInfo.inf @@ -0,0 +1,56 @@ +## @file +# A shell application that displays statistical information about variable usage. +# +# This application can display statistical information about variable usage for SMM variable +# driver and non-SMM variable driver. +# Note that if Variable Dxe/Smm driver doesn't enable the feature by setting PcdVariableCollectStatistics +# as TRUE, the application will not display variable statistical information. +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = VariableInfo + MODULE_UNI_FILE = VariableInfo.uni + FILE_GUID = 202A2922-8C27-4943-9855-26180BF9F113 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = UefiMain + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + VariableInfo.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + UefiLib + UefiBootServicesTableLib + BaseMemoryLib + MemoryAllocationLib + +[Protocols] + gEfiMmCommunication2ProtocolGuid ## SOMETIMES_CONSUMES + + ## UNDEFINED # Used to do smm communication + ## SOMETIMES_CONSUMES + gEfiSmmVariableProtocolGuid + +[Guids] + gEfiAuthenticatedVariableGuid ## SOMETIMES_CONSUMES ## SystemTable + gEfiVariableGuid ## SOMETIMES_CONSUMES ## SystemTable + gEdkiiPiSmmCommunicationRegionTableGuid ## SOMETIMES_CONSUMES ## SystemTable + +[UserExtensions.TianoCore."ExtraFiles"] + VariableInfoExtra.uni diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/VariableInfo/VariableInfo.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/VariableInfo/VariableInfo.uni new file mode 100644 index 00000000..efd614d9 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/VariableInfo/VariableInfo.uni @@ -0,0 +1,19 @@ +// /** @file
+// A shell application that displays statistical information about variable usage.
+//
+// This application can display statistical information about variable usage for SMM variable
+// driver and non-SMM variable driver.
+// Note that if Variable Dxe/Smm driver doesn't enable the feature by setting PcdVariableCollectStatistics
+// as TRUE, the application will not display variable statistical information.
+//
+// Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "A shell application that displays statistical information about variable usage"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This application can display statistical information about variable usage for SMM variable driver and non-SMM variable driver. Note that if Variable DXE/SMM driver doesn't enable the feature by setting PcdVariableCollectStatistics as TRUE, the application will not display variable statistical information."
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/VariableInfo/VariableInfoExtra.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/VariableInfo/VariableInfoExtra.uni new file mode 100644 index 00000000..529e781a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/VariableInfo/VariableInfoExtra.uni @@ -0,0 +1,14 @@ +// /** @file
+// VariableInfo Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Variable Information Application"
+
+
|