mirror of
https://github.com/Dasharo/edk2.git
synced 2026-06-13 10:16:24 -07:00
test
This commit is contained in:
@@ -27,6 +27,13 @@
|
||||
DEFINE SOURCE_DEBUG_ENABLE = FALSE
|
||||
DEFINE PS2_KEYBOARD_ENABLE = FALSE
|
||||
|
||||
#
|
||||
# Use the Dasharo graphical FORM_DISPLAY_ENGINE provider in place of
|
||||
# MdeModulePkg's text-mode DisplayEngineDxe. Set to FALSE to fall back
|
||||
# to the stock text-mode setup browser.
|
||||
#
|
||||
DEFINE USE_GRAPHICAL_SETUP = TRUE
|
||||
|
||||
#
|
||||
# SBL: UEFI payload for Slim Bootloader
|
||||
# COREBOOT: UEFI payload for coreboot
|
||||
@@ -799,6 +806,7 @@ OrderedCollectionLib|MdePkg/Library/BaseOrderedCollectionRedBlackTreeLib/BaseOrd
|
||||
<LibraryClasses>
|
||||
NULL|MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerUiLib.inf
|
||||
NULL|DasharoModulePkg/Library/DasharoSystemFeaturesUiLib/DasharoSystemFeaturesUiLib.inf
|
||||
NULL|DasharoPayloadPkg/Library/DasharoSaveExitUiLib/DasharoSaveExitUiLib.inf
|
||||
NULL|MdeModulePkg/Library/BootManagerUiLib/BootManagerUiLib.inf
|
||||
NULL|MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerUiLib.inf
|
||||
}
|
||||
@@ -863,7 +871,11 @@ OrderedCollectionLib|MdePkg/Library/BaseOrderedCollectionRedBlackTreeLib/BaseOrd
|
||||
MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf
|
||||
MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
|
||||
MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf
|
||||
!if $(USE_GRAPHICAL_SETUP) == TRUE
|
||||
DasharoPayloadPkg/GraphicsDisplayEngineDxe/GraphicsDisplayEngineDxe.inf
|
||||
!else
|
||||
MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf
|
||||
!endif
|
||||
DasharoPayloadPkg/BlSupportDxe/BlSupportDxe.inf
|
||||
CrScreenshotDxe/CrScreenshotDxe.inf {
|
||||
<BuildOptions>
|
||||
|
||||
@@ -151,7 +151,11 @@ INF MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
|
||||
INF MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf
|
||||
INF MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
|
||||
INF MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf
|
||||
!if $(USE_GRAPHICAL_SETUP) == TRUE
|
||||
INF DasharoPayloadPkg/GraphicsDisplayEngineDxe/GraphicsDisplayEngineDxe.inf
|
||||
!else
|
||||
INF MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf
|
||||
!endif
|
||||
INF DasharoPayloadPkg/BlSupportDxe/BlSupportDxe.inf
|
||||
|
||||
INF MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,181 @@
|
||||
/** @file
|
||||
Dasharo graphical display engine — shared internal definitions.
|
||||
|
||||
Copyright (c) 2026, 3mdeb Sp. z o.o. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#ifndef GRAPHICS_DISPLAY_ENGINE_H_
|
||||
#define GRAPHICS_DISPLAY_ENGINE_H_
|
||||
|
||||
#include <Uefi.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/HiiLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
|
||||
#include <Protocol/DisplayProtocol.h>
|
||||
#include <Protocol/FormBrowserEx2.h>
|
||||
#include <Protocol/GraphicsOutput.h>
|
||||
#include <Protocol/SimpleTextIn.h>
|
||||
#include <Protocol/SimpleTextOut.h>
|
||||
|
||||
#include <Uefi/UefiInternalFormRepresentation.h>
|
||||
|
||||
//
|
||||
// Layout constants. Sizes that aren't fixed pixels are percentages of the
|
||||
// active GOP mode and are recomputed on every FormDisplay call so that
|
||||
// resolution changes take effect immediately.
|
||||
//
|
||||
#define GFX_FONT_SIZE_PERCENT 2 // body font (% of vertical res)
|
||||
#define GFX_HEADER_PERCENT 7 // brand band (logo + product line)
|
||||
#define GFX_TABBAR_PERCENT 5 // numbered horizontal tab strip
|
||||
#define GFX_PAGEHEADER_LINES 4 // breadcrumb + section + title + spacer
|
||||
#define GFX_FOOTER_PERCENT 5 // hot-key band
|
||||
// Base values, scaled at runtime by mState.Scale (resolution-dependent).
|
||||
// All are referenced as `GFX_PADDING_PX` etc. at use sites; the macros
|
||||
// below resolve to a runtime expression that incorporates mState.Scale,
|
||||
// so simple uses like `2 * GFX_PADDING_PX` continue to compose correctly.
|
||||
#define GFX_PADDING_PX_BASE 8u
|
||||
#define GFX_HIGHLIGHT_INSET_PX_BASE 3u // gap above/below row highlight
|
||||
#define GFX_SCROLLBAR_RESERVE_PX_BASE 8u // right strip kept clear of row
|
||||
// fills so the scroll indicator
|
||||
// stays visible across redraws
|
||||
|
||||
#define GFX_PADDING_PX (GFX_PADDING_PX_BASE * mState.Scale)
|
||||
#define GFX_HIGHLIGHT_INSET_PX (GFX_HIGHLIGHT_INSET_PX_BASE * mState.Scale)
|
||||
#define GFX_SCROLLBAR_RESERVE_PX (GFX_SCROLLBAR_RESERVE_PX_BASE * mState.Scale)
|
||||
|
||||
//
|
||||
// Panel colors (used by Blt fills). Stored BGR + reserved to match
|
||||
// EFI_GRAPHICS_OUTPUT_BLT_PIXEL — Blt is pixel-format agnostic.
|
||||
//
|
||||
#define GFX_COLOR(R, G, B) ((EFI_GRAPHICS_OUTPUT_BLT_PIXEL){ (B), (G), (R), 0 })
|
||||
#define GFX_BG GFX_COLOR (0x05, 0x09, 0x14) // near-black, slight blue
|
||||
#define GFX_PANEL GFX_COLOR (0x0C, 0x14, 0x22) // header/footer bands
|
||||
#define GFX_PANEL_ALT GFX_COLOR (0x16, 0x1F, 0x30) // separator rules, popup title
|
||||
#define GFX_HIGHLIGHT GFX_COLOR (0x10, 0x60, 0x55) // selected row bg (teal-tinted)
|
||||
#define GFX_HIGHLIGHT_DIM GFX_COLOR (0x33, 0x3D, 0x52) // selected-but-not-actionable row
|
||||
// — bright enough to be obviously
|
||||
// a highlight even on rows with no text
|
||||
#define GFX_ACCENT GFX_COLOR (0x14, 0xB8, 0xA6) // primary accent (active indicators)
|
||||
#define GFX_TEXT GFX_COLOR (0xFF, 0xFF, 0xFF) // (legacy; text uses TC_*)
|
||||
#define GFX_TEXT_DIM GFX_COLOR (0x55, 0x60, 0x70) // outlines, separators
|
||||
|
||||
//
|
||||
// Text colors as RGB triplets — fed straight into GfxSetTextColor().
|
||||
//
|
||||
#define TC_WHITE 0xFF, 0xFF, 0xFF // primary
|
||||
#define TC_DIM 0x80, 0x88, 0x95 // descriptions, breadcrumbs
|
||||
#define TC_DIMMER 0x55, 0x60, 0x70 // hardly-there labels
|
||||
#define TC_TEAL 0x14, 0xB8, 0xA6 // active accents
|
||||
#define TC_AMBER 0xF5, 0x9E, 0x0B // warnings
|
||||
#define TC_RED 0xEF, 0x44, 0x4F // errors
|
||||
|
||||
typedef struct {
|
||||
EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop; // NULL => no graphics at all
|
||||
BOOLEAN SsfnReady; // direct framebuffer text usable
|
||||
UINT32 ScreenW;
|
||||
UINT32 ScreenH;
|
||||
UINTN FontPx;
|
||||
UINTN Scale; // 1, 2, 3 — driven by ScreenH
|
||||
|
||||
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL **SerialOutputs;
|
||||
UINTN SerialCount;
|
||||
|
||||
// The form we treat as "Main" — recorded the first time TabsCaptureFromForm
|
||||
// commits to a tab source, used to special-case rendering (system info
|
||||
// cards instead of plain REF list) and tab navigation (L/R wrapping).
|
||||
EFI_GUID MainFormSetGuid;
|
||||
UINT16 MainFormId;
|
||||
BOOLEAN MainFormIdentified;
|
||||
} GFX_DISPLAY_ENGINE_STATE;
|
||||
|
||||
extern GFX_DISPLAY_ENGINE_STATE mState;
|
||||
|
||||
//
|
||||
// Cached top-level navigation tabs. Captured from the REF statements on the
|
||||
// first form that contains REFs (typically the front page). Tab destinations
|
||||
// are referenced by FormSet GUID + Form ID, which stay valid across
|
||||
// FormDisplay calls (statement pointers do not).
|
||||
//
|
||||
#define MAX_TABS 16
|
||||
|
||||
typedef struct {
|
||||
EFI_GUID FormSetGuid;
|
||||
UINT16 FormId;
|
||||
EFI_HII_HANDLE HiiHandle; // kept for diagnostic / future use
|
||||
EFI_STRING_ID Prompt; // (likewise — string is cached below)
|
||||
CHAR16 Name[64]; // resolved at capture time (StringIds
|
||||
// can be invalidated when UiApp
|
||||
// rebuilds the front page)
|
||||
} TAB_ENTRY;
|
||||
|
||||
//
|
||||
// Output.c — protocol discovery, font init, drawing primitives, serial mirror.
|
||||
//
|
||||
EFI_STATUS GfxOutputInit (VOID);
|
||||
VOID GfxFillRect (IN UINTN X, IN UINTN Y, IN UINTN W, IN UINTN H,
|
||||
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color);
|
||||
VOID GfxClearScreen (IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color);
|
||||
VOID GfxDrawText (IN UINTN X, IN UINTN Y, IN CONST CHAR8 *Utf8);
|
||||
VOID GfxDrawTextW (IN UINTN X, IN UINTN Y, IN CONST CHAR16 *Wide);
|
||||
// Sets the foreground color used by all subsequent text draws until next call.
|
||||
VOID GfxSetTextColor (IN UINT8 R, IN UINT8 G, IN UINT8 B);
|
||||
// Truncates with an ellipsis if the string would render wider than MaxWidthPx.
|
||||
VOID GfxDrawTextWClipped (IN UINTN X, IN UINTN Y, IN UINTN MaxWidthPx,
|
||||
IN CONST CHAR16 *Wide);
|
||||
// Renders Wide so its right edge sits at RightX (text grows leftward).
|
||||
VOID GfxDrawTextWRightAligned (IN UINTN RightX, IN UINTN Y,
|
||||
IN CONST CHAR16 *Wide);
|
||||
// Like GfxDrawTextWRightAligned but truncates with an ellipsis when the
|
||||
// rendered width would exceed MaxWidthPx.
|
||||
VOID GfxDrawTextWRightAlignedClipped (IN UINTN RightX, IN UINTN Y,
|
||||
IN UINTN MaxWidthPx,
|
||||
IN CONST CHAR16 *Wide);
|
||||
// Renders Wide centered horizontally on CenterX.
|
||||
VOID GfxDrawTextWCentered (IN UINTN CenterX, IN UINTN Y,
|
||||
IN CONST CHAR16 *Wide);
|
||||
// Measures the rendered pixel width of Wide using the active font.
|
||||
UINTN GfxMeasureTextW (IN CONST CHAR16 *Wide);
|
||||
// Draws an outlined rectangle (1 px border, no fill).
|
||||
VOID GfxDrawRectOutline (IN UINTN X, IN UINTN Y, IN UINTN W, IN UINTN H,
|
||||
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color);
|
||||
VOID SerialOut (IN CONST CHAR16 *Text);
|
||||
VOID SerialOutLine (IN CONST CHAR16 *Text);
|
||||
|
||||
//
|
||||
// SystemInfo.c — SMBIOS-derived hardware summary + RTC clock formatting.
|
||||
//
|
||||
typedef struct {
|
||||
CHAR16 SystemVendor[64];
|
||||
CHAR16 SystemProduct[64];
|
||||
CHAR16 BiosVersion[64];
|
||||
CHAR16 CpuBrand[80];
|
||||
UINT64 TotalRamMB;
|
||||
BOOLEAN Collected;
|
||||
} SYSTEM_INFO;
|
||||
|
||||
extern SYSTEM_INFO mSysInfo;
|
||||
|
||||
VOID SystemInfoCollect (VOID);
|
||||
VOID SystemInfoFormatTime (OUT CHAR16 *Buf, IN UINTN BufSize);
|
||||
VOID SystemInfoFormatSummary (OUT CHAR16 *Buf, IN UINTN BufSize);
|
||||
|
||||
//
|
||||
// Tabs.c — top-level navigation tab cache.
|
||||
//
|
||||
VOID TabsCaptureFromForm (IN FORM_DISPLAY_ENGINE_FORM *Form);
|
||||
UINTN TabsCount (VOID);
|
||||
TAB_ENTRY *TabsGet (IN UINTN Index);
|
||||
INTN TabsFindActive (IN FORM_DISPLAY_ENGINE_FORM *Form);
|
||||
// Renders the horizontal tab bar across the strip [TopY .. TopY+BarH).
|
||||
VOID TabsRenderHorizontal (IN UINTN TopY, IN UINTN BarH,
|
||||
IN INTN ActiveIndex);
|
||||
|
||||
#endif // GRAPHICS_DISPLAY_ENGINE_H_
|
||||
@@ -0,0 +1,59 @@
|
||||
## @file
|
||||
# Dasharo graphical FORM_DISPLAY_ENGINE_PROTOCOL provider.
|
||||
#
|
||||
# Renders the HII setup menu graphically on GOP while mirroring an in-sync
|
||||
# text view to serial-only consoles. Falls back to plain text when no GOP
|
||||
# is available.
|
||||
#
|
||||
# Copyright (c) 2026, 3mdeb Sp. z o.o. All rights reserved.<BR>
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = GraphicsDisplayEngineDxe
|
||||
FILE_GUID = 7C5A0C11-2A5D-4F0A-9E8E-5CF6B1E1A401
|
||||
MODULE_TYPE = DXE_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
ENTRY_POINT = GraphicsDisplayEngineEntry
|
||||
|
||||
[Sources]
|
||||
GraphicsDisplayEngine.c
|
||||
GraphicsDisplayEngine.h
|
||||
Output.c
|
||||
SystemInfo.c
|
||||
Tabs.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
DasharoPayloadPkg/DasharoPayloadPkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
UefiDriverEntryPoint
|
||||
UefiBootServicesTableLib
|
||||
UefiRuntimeServicesTableLib
|
||||
DebugLib
|
||||
BaseMemoryLib
|
||||
BaseLib
|
||||
PrintLib
|
||||
HiiLib
|
||||
MemoryAllocationLib
|
||||
DevicePathLib
|
||||
|
||||
[Protocols]
|
||||
gEdkiiFormDisplayEngineProtocolGuid ## PRODUCES
|
||||
gEdkiiFormBrowserEx2ProtocolGuid ## CONSUMES
|
||||
gEfiGraphicsOutputProtocolGuid ## SOMETIMES_CONSUMES
|
||||
gEfiSimpleTextOutProtocolGuid ## CONSUMES
|
||||
gEfiDevicePathProtocolGuid ## CONSUMES
|
||||
gEfiSimpleTextInputExProtocolGuid ## CONSUMES
|
||||
|
||||
[Guids]
|
||||
gEfiSmbios3TableGuid ## SOMETIMES_CONSUMES
|
||||
gEfiSmbiosTableGuid ## SOMETIMES_CONSUMES
|
||||
|
||||
[Depex]
|
||||
gEfiHiiDatabaseProtocolGuid AND
|
||||
gEfiHiiConfigRoutingProtocolGuid AND
|
||||
gEdkiiFormBrowserEx2ProtocolGuid
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,266 @@
|
||||
/** @file
|
||||
SMBIOS-derived system information rendered in the graphical setup header
|
||||
(vendor / product, firmware version, CPU brand, total RAM) plus a helper
|
||||
to format the current real-time clock.
|
||||
|
||||
The lookup walks gST->ConfigurationTable for the SMBIOS 3.0 entry point
|
||||
(falling back to the 2.x entry point) and iterates structures linearly,
|
||||
pulling strings by their 1-based index from the trailing string list.
|
||||
Cached on first call — SMBIOS doesn't change at runtime.
|
||||
|
||||
Copyright (c) 2026, 3mdeb Sp. z o.o. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include "GraphicsDisplayEngine.h"
|
||||
|
||||
#include <Guid/SmBios.h>
|
||||
#include <IndustryStandard/SmBios.h>
|
||||
|
||||
SYSTEM_INFO mSysInfo;
|
||||
|
||||
STATIC
|
||||
BOOLEAN
|
||||
FindSmbiosTable (
|
||||
OUT VOID **TableBase,
|
||||
OUT UINT32 *TableLen
|
||||
)
|
||||
{
|
||||
UINTN i;
|
||||
|
||||
// Prefer the 64-bit entry point; otherwise fall back to legacy.
|
||||
for (i = 0; i < gST->NumberOfTableEntries; i++) {
|
||||
if (CompareGuid (&gST->ConfigurationTable[i].VendorGuid, &gEfiSmbios3TableGuid)) {
|
||||
SMBIOS_TABLE_3_0_ENTRY_POINT *Ep = gST->ConfigurationTable[i].VendorTable;
|
||||
*TableBase = (VOID *)(UINTN)Ep->TableAddress;
|
||||
*TableLen = Ep->TableMaximumSize;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < gST->NumberOfTableEntries; i++) {
|
||||
if (CompareGuid (&gST->ConfigurationTable[i].VendorGuid, &gEfiSmbiosTableGuid)) {
|
||||
SMBIOS_TABLE_ENTRY_POINT *Ep = gST->ConfigurationTable[i].VendorTable;
|
||||
*TableBase = (VOID *)(UINTN)Ep->TableAddress;
|
||||
*TableLen = Ep->TableLength;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Fetches the Index-th string (1-based) from the trailing string list of an
|
||||
// SMBIOS structure. Returns NULL if the index is 0 or out of range.
|
||||
STATIC
|
||||
CONST CHAR8 *
|
||||
SmbiosString (
|
||||
IN SMBIOS_STRUCTURE *Struct,
|
||||
IN UINT8 Index
|
||||
)
|
||||
{
|
||||
CONST CHAR8 *p;
|
||||
UINT8 n;
|
||||
|
||||
if ((Index == 0) || (Struct->Length < sizeof (SMBIOS_STRUCTURE))) {
|
||||
return NULL;
|
||||
}
|
||||
p = (CONST CHAR8 *)Struct + Struct->Length;
|
||||
for (n = 1; n < Index; n++) {
|
||||
while (*p != 0) {
|
||||
p++;
|
||||
}
|
||||
p++;
|
||||
if (*p == 0) {
|
||||
return NULL; // walked off the end of the string list
|
||||
}
|
||||
}
|
||||
return *p == 0 ? NULL : p;
|
||||
}
|
||||
|
||||
STATIC
|
||||
SMBIOS_STRUCTURE *
|
||||
NextStructure (
|
||||
IN SMBIOS_STRUCTURE *Cur
|
||||
)
|
||||
{
|
||||
CONST UINT8 *p = (CONST UINT8 *)Cur + Cur->Length;
|
||||
// String list ends with a double-NUL.
|
||||
while ((p[0] != 0) || (p[1] != 0)) {
|
||||
p++;
|
||||
}
|
||||
return (SMBIOS_STRUCTURE *)(p + 2);
|
||||
}
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
AsciiToWide (
|
||||
IN CONST CHAR8 *Src,
|
||||
OUT CHAR16 *Dst,
|
||||
IN UINTN DstChars
|
||||
)
|
||||
{
|
||||
UINTN i;
|
||||
|
||||
if ((Src == NULL) || (DstChars == 0)) {
|
||||
if (DstChars > 0) {
|
||||
Dst[0] = L'\0';
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (i = 0; (i < DstChars - 1) && (Src[i] != 0); i++) {
|
||||
Dst[i] = (CHAR16)(UINT8)Src[i];
|
||||
}
|
||||
Dst[i] = L'\0';
|
||||
}
|
||||
|
||||
VOID
|
||||
SystemInfoCollect (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
VOID *TableBase;
|
||||
UINT32 TableLen;
|
||||
SMBIOS_STRUCTURE *s;
|
||||
UINT8 *End;
|
||||
|
||||
if (mSysInfo.Collected) {
|
||||
return;
|
||||
}
|
||||
mSysInfo.Collected = TRUE;
|
||||
|
||||
StrCpyS (mSysInfo.SystemVendor, ARRAY_SIZE (mSysInfo.SystemVendor), L"?");
|
||||
StrCpyS (mSysInfo.SystemProduct, ARRAY_SIZE (mSysInfo.SystemProduct), L"?");
|
||||
StrCpyS (mSysInfo.BiosVersion, ARRAY_SIZE (mSysInfo.BiosVersion), L"?");
|
||||
StrCpyS (mSysInfo.CpuBrand, ARRAY_SIZE (mSysInfo.CpuBrand), L"?");
|
||||
mSysInfo.TotalRamMB = 0;
|
||||
|
||||
if (!FindSmbiosTable (&TableBase, &TableLen)) {
|
||||
DEBUG ((DEBUG_ERROR, "SystemInfo: no SMBIOS table found in ConfigurationTable\n"));
|
||||
return;
|
||||
}
|
||||
DEBUG ((
|
||||
DEBUG_ERROR,
|
||||
"SystemInfo: SMBIOS at 0x%p, len=0x%x\n",
|
||||
TableBase, (UINTN)TableLen
|
||||
));
|
||||
|
||||
s = (SMBIOS_STRUCTURE *)TableBase;
|
||||
End = (UINT8 *)TableBase + TableLen;
|
||||
|
||||
while (((UINT8 *)s + sizeof (SMBIOS_STRUCTURE)) <= End) {
|
||||
if (s->Length < sizeof (SMBIOS_STRUCTURE)) {
|
||||
break; // malformed
|
||||
}
|
||||
|
||||
switch (s->Type) {
|
||||
case 0: { // BIOS Information
|
||||
SMBIOS_TABLE_TYPE0 *t = (SMBIOS_TABLE_TYPE0 *)s;
|
||||
AsciiToWide (
|
||||
SmbiosString (s, t->BiosVersion),
|
||||
mSysInfo.BiosVersion, ARRAY_SIZE (mSysInfo.BiosVersion)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 1: { // System Information
|
||||
SMBIOS_TABLE_TYPE1 *t = (SMBIOS_TABLE_TYPE1 *)s;
|
||||
AsciiToWide (
|
||||
SmbiosString (s, t->Manufacturer),
|
||||
mSysInfo.SystemVendor, ARRAY_SIZE (mSysInfo.SystemVendor)
|
||||
);
|
||||
AsciiToWide (
|
||||
SmbiosString (s, t->ProductName),
|
||||
mSysInfo.SystemProduct, ARRAY_SIZE (mSysInfo.SystemProduct)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 4: { // Processor Information
|
||||
SMBIOS_TABLE_TYPE4 *t = (SMBIOS_TABLE_TYPE4 *)s;
|
||||
AsciiToWide (
|
||||
SmbiosString (s, t->ProcessorVersion),
|
||||
mSysInfo.CpuBrand, ARRAY_SIZE (mSysInfo.CpuBrand)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 17: { // Memory Device — sum sizes across DIMMs.
|
||||
SMBIOS_TABLE_TYPE17 *t = (SMBIOS_TABLE_TYPE17 *)s;
|
||||
UINT64 SizeMB = 0;
|
||||
if ((t->Size != 0xFFFF) && (t->Size != 0)) {
|
||||
if (t->Size == 0x7FFF) {
|
||||
SizeMB = t->ExtendedSize & 0x7FFFFFFF;
|
||||
} else if ((t->Size & 0x8000) != 0) {
|
||||
SizeMB = (t->Size & 0x7FFF) / 1024; // KB → MB (rounds down)
|
||||
} else {
|
||||
SizeMB = t->Size; // already MB
|
||||
}
|
||||
}
|
||||
mSysInfo.TotalRamMB += SizeMB;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (s->Type == SMBIOS_TYPE_END_OF_TABLE) {
|
||||
break;
|
||||
}
|
||||
s = NextStructure (s);
|
||||
if ((UINT8 *)s >= End) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG ((
|
||||
DEBUG_ERROR,
|
||||
"SystemInfo: vendor=\"%s\" product=\"%s\" bios=\"%s\" cpu=\"%s\" ram=%lu MB\n",
|
||||
mSysInfo.SystemVendor,
|
||||
mSysInfo.SystemProduct,
|
||||
mSysInfo.BiosVersion,
|
||||
mSysInfo.CpuBrand,
|
||||
mSysInfo.TotalRamMB
|
||||
));
|
||||
}
|
||||
|
||||
VOID
|
||||
SystemInfoFormatTime (
|
||||
OUT CHAR16 *Buf,
|
||||
IN UINTN BufSize
|
||||
)
|
||||
{
|
||||
EFI_TIME T;
|
||||
|
||||
if (EFI_ERROR (gRT->GetTime (&T, NULL))) {
|
||||
StrCpyS (Buf, BufSize / sizeof (CHAR16), L"--:--:--");
|
||||
return;
|
||||
}
|
||||
UnicodeSPrint (
|
||||
Buf, BufSize,
|
||||
L"%04u-%02u-%02u %02u:%02u:%02u",
|
||||
(UINT32)T.Year, (UINT32)T.Month, (UINT32)T.Day,
|
||||
(UINT32)T.Hour, (UINT32)T.Minute, (UINT32)T.Second
|
||||
);
|
||||
}
|
||||
|
||||
VOID
|
||||
SystemInfoFormatSummary (
|
||||
OUT CHAR16 *Buf,
|
||||
IN UINTN BufSize
|
||||
)
|
||||
{
|
||||
if (mSysInfo.TotalRamMB > 0) {
|
||||
UnicodeSPrint (
|
||||
Buf, BufSize,
|
||||
L"PLATFORM %s \x00B7 FW %s \x00B7 CPU %s \x00B7 RAM %u GiB",
|
||||
mSysInfo.SystemProduct,
|
||||
mSysInfo.BiosVersion,
|
||||
mSysInfo.CpuBrand,
|
||||
(UINT32)((mSysInfo.TotalRamMB + 1023) / 1024)
|
||||
);
|
||||
} else {
|
||||
UnicodeSPrint (
|
||||
Buf, BufSize,
|
||||
L"PLATFORM %s \x00B7 FW %s \x00B7 CPU %s",
|
||||
mSysInfo.SystemProduct,
|
||||
mSysInfo.BiosVersion,
|
||||
mSysInfo.CpuBrand
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
/** @file
|
||||
Top-level navigation tabs for the graphical setup menu.
|
||||
|
||||
The display engine receives forms one at a time via FormBrowser2; it has
|
||||
no inherent notion of "siblings" or a tab strip. To present persistent
|
||||
tabs we snapshot the REF statements from the first form that contains
|
||||
them (typically the front page) and render that snapshot on every form.
|
||||
|
||||
Statement pointers are owned by the form browser and are only valid for
|
||||
the duration of one FormDisplay call, so we cache by FormSet GUID +
|
||||
Form ID + HII handle + prompt StringId — all of which remain stable.
|
||||
|
||||
Copyright (c) 2026, 3mdeb Sp. z o.o. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include "GraphicsDisplayEngine.h"
|
||||
|
||||
STATIC TAB_ENTRY mTabs[MAX_TABS];
|
||||
STATIC UINTN mTabCount;
|
||||
|
||||
// Tabs that should always be pinned to the right end of the strip, in the
|
||||
// order listed here. Matched against the destination FormSetGuid of each
|
||||
// captured REF. Add new GUIDs (e.g. for additional "wrap-up" tabs) at the
|
||||
// end — entries are moved to the rightmost slots in this order.
|
||||
STATIC EFI_GUID mTrailingTabs[] = {
|
||||
// DasharoSaveExitUiLib: { 0x5b7f9a21, 0x3c44, 0x4e89, ... }
|
||||
{ 0x5b7f9a21, 0x3c44, 0x4e89, { 0xb1, 0xa6, 0xd8, 0xc7, 0xf2, 0xe5, 0xa9, 0x01 } },
|
||||
};
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
PinTrailingTabs (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
UINTN Pin;
|
||||
UINTN i;
|
||||
UINTN TargetSlot;
|
||||
|
||||
if (mTabCount < 2) {
|
||||
return;
|
||||
}
|
||||
// For each "trailing" GUID in registration order, find the tab in the
|
||||
// current array (skipping Main at index 0) and rotate it into the
|
||||
// appropriate slot near the end. We process front-to-back through
|
||||
// mTrailingTabs so multiple trailing tabs preserve their relative order.
|
||||
for (Pin = 0; Pin < ARRAY_SIZE (mTrailingTabs); Pin++) {
|
||||
TargetSlot = mTabCount - 1 - (ARRAY_SIZE (mTrailingTabs) - 1 - Pin);
|
||||
if (TargetSlot >= mTabCount) {
|
||||
continue;
|
||||
}
|
||||
for (i = 1; i < mTabCount; i++) {
|
||||
if (!CompareGuid (&mTabs[i].FormSetGuid, &mTrailingTabs[Pin])) {
|
||||
continue;
|
||||
}
|
||||
if (i == TargetSlot) {
|
||||
break;
|
||||
}
|
||||
// Rotate mTabs[i] to TargetSlot. If TargetSlot > i, shift the
|
||||
// intermediate range left; otherwise shift right. (For our cases
|
||||
// TargetSlot is always >= i so we only ever shift left.)
|
||||
{
|
||||
TAB_ENTRY Tmp = mTabs[i];
|
||||
if (TargetSlot > i) {
|
||||
UINTN k;
|
||||
for (k = i; k < TargetSlot; k++) {
|
||||
mTabs[k] = mTabs[k + 1];
|
||||
}
|
||||
} else {
|
||||
UINTN k;
|
||||
for (k = i; k > TargetSlot; k--) {
|
||||
mTabs[k] = mTabs[k - 1];
|
||||
}
|
||||
}
|
||||
mTabs[TargetSlot] = Tmp;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC
|
||||
BOOLEAN
|
||||
IsRefOpcode (
|
||||
IN UINT8 OpCode
|
||||
)
|
||||
{
|
||||
return (OpCode == EFI_IFR_REF_OP);
|
||||
}
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
ExtractRef (
|
||||
IN FORM_DISPLAY_ENGINE_STATEMENT *Stmt,
|
||||
IN EFI_HII_HANDLE HiiHandle,
|
||||
IN EFI_GUID *CurrentFormSetGuid,
|
||||
OUT TAB_ENTRY *Out
|
||||
)
|
||||
{
|
||||
EFI_IFR_REF *Ref = (EFI_IFR_REF *)Stmt->OpCode;
|
||||
CHAR16 *Resolved;
|
||||
|
||||
Out->FormId = Ref->FormId;
|
||||
Out->HiiHandle = HiiHandle;
|
||||
Out->Prompt = Ref->Question.Header.Prompt;
|
||||
|
||||
// Resolve the prompt string NOW and cache the literal — UiApp rebuilds
|
||||
// the Front Page on every entry, which can retire the StringIds we
|
||||
// captured. Holding the string itself keeps tabs stable across rebuilds.
|
||||
Resolved = HiiGetString (HiiHandle, Out->Prompt, NULL);
|
||||
if (Resolved != NULL) {
|
||||
StrCpyS (Out->Name, ARRAY_SIZE (Out->Name), Resolved);
|
||||
FreePool (Resolved);
|
||||
} else {
|
||||
Out->Name[0] = L'\0';
|
||||
}
|
||||
|
||||
// REF3 and REF4 carry an explicit destination FormSetId — that's how
|
||||
// cross-formset entries on the Front Page are encoded (HiiCreateGotoExOpCode
|
||||
// emits REF3 with FormId=0 and a FormSetId pointing at the target formset).
|
||||
if (Ref->Header.Length >= sizeof (EFI_IFR_REF3)) {
|
||||
EFI_IFR_REF3 *Ref3 = (EFI_IFR_REF3 *)Stmt->OpCode;
|
||||
CopyMem (&Out->FormSetGuid, &Ref3->FormSetId, sizeof (EFI_GUID));
|
||||
} else {
|
||||
CopyMem (&Out->FormSetGuid, CurrentFormSetGuid, sizeof (EFI_GUID));
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
TabsCaptureFromForm (
|
||||
IN FORM_DISPLAY_ENGINE_FORM *Form
|
||||
)
|
||||
{
|
||||
LIST_ENTRY *Link;
|
||||
FORM_DISPLAY_ENGINE_STATEMENT *Stmt;
|
||||
UINTN RefsTotal;
|
||||
|
||||
// One-shot capture: the first form we see with enough REFs becomes the
|
||||
// tab source for the rest of the session. We deliberately do NOT replace
|
||||
// the cache when the user navigates into a sub-menu (which itself may
|
||||
// have several REFs); doing so would make the tab strip mutate as the
|
||||
// user drills down, which is the opposite of what tabs are for.
|
||||
if (mTabCount > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefsTotal = 0;
|
||||
for (Link = GetFirstNode (&Form->StatementListHead);
|
||||
!IsNull (&Form->StatementListHead, Link);
|
||||
Link = GetNextNode (&Form->StatementListHead, Link))
|
||||
{
|
||||
Stmt = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
|
||||
if ((Stmt->OpCode != NULL) && IsRefOpcode (Stmt->OpCode->OpCode)) {
|
||||
RefsTotal++;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG ((
|
||||
DEBUG_ERROR,
|
||||
"Tabs: form FormId=0x%x has %u REFs\n",
|
||||
Form->FormId, (UINT32)RefsTotal
|
||||
));
|
||||
|
||||
if (RefsTotal < 2) {
|
||||
return; // not a tab-source form
|
||||
}
|
||||
|
||||
// Record this form as the canonical "Main" form so the rendering path
|
||||
// can recognize when we're on it and switch into the system-info card
|
||||
// layout (vs the plain REF list).
|
||||
CopyMem (&mState.MainFormSetGuid, &Form->FormSetGuid, sizeof (EFI_GUID));
|
||||
mState.MainFormId = Form->FormId;
|
||||
mState.MainFormIdentified = TRUE;
|
||||
|
||||
// Tab 01 is a synthetic "Main" entry pointing at the form we're capturing
|
||||
// from. It carries the actual FormSetGuid + FormId so navigation back to
|
||||
// it via L/R works through the same FindRefForTab + multi-step exit
|
||||
// path; the literal "Main" label sidesteps the form's own title.
|
||||
CopyMem (&mTabs[0].FormSetGuid, &mState.MainFormSetGuid, sizeof (EFI_GUID));
|
||||
mTabs[0].FormId = mState.MainFormId;
|
||||
mTabs[0].HiiHandle = Form->HiiHandle;
|
||||
mTabs[0].Prompt = 0;
|
||||
StrCpyS (mTabs[0].Name, ARRAY_SIZE (mTabs[0].Name), L"Main");
|
||||
mTabCount = 1;
|
||||
|
||||
for (Link = GetFirstNode (&Form->StatementListHead);
|
||||
!IsNull (&Form->StatementListHead, Link) && (mTabCount < MAX_TABS);
|
||||
Link = GetNextNode (&Form->StatementListHead, Link))
|
||||
{
|
||||
Stmt = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
|
||||
if ((Stmt->OpCode == NULL) || !IsRefOpcode (Stmt->OpCode->OpCode)) {
|
||||
continue;
|
||||
}
|
||||
ExtractRef (Stmt, Form->HiiHandle, &Form->FormSetGuid, &mTabs[mTabCount]);
|
||||
mTabCount++;
|
||||
}
|
||||
|
||||
PinTrailingTabs ();
|
||||
}
|
||||
|
||||
UINTN
|
||||
TabsCount (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return mTabCount;
|
||||
}
|
||||
|
||||
TAB_ENTRY *
|
||||
TabsGet (
|
||||
IN UINTN Index
|
||||
)
|
||||
{
|
||||
if (Index >= mTabCount) {
|
||||
return NULL;
|
||||
}
|
||||
return &mTabs[Index];
|
||||
}
|
||||
|
||||
INTN
|
||||
TabsFindActive (
|
||||
IN FORM_DISPLAY_ENGINE_FORM *Form
|
||||
)
|
||||
{
|
||||
UINTN i;
|
||||
|
||||
// Match on FormSetGuid first; that anchors us to the right top-level
|
||||
// section even when the user has drilled into a sub-form. The cached
|
||||
// FormId is only required to match if it's non-zero — cross-formset
|
||||
// tab entries store FormId=0 (meaning "the formset's main form") and
|
||||
// we want them to highlight while the user is anywhere inside that
|
||||
// formset, not just on its main form.
|
||||
for (i = 0; i < mTabCount; i++) {
|
||||
if (!CompareGuid (&mTabs[i].FormSetGuid, &Form->FormSetGuid)) {
|
||||
continue;
|
||||
}
|
||||
if ((mTabs[i].FormId == 0) || (mTabs[i].FormId == Form->FormId)) {
|
||||
return (INTN)i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
VOID
|
||||
TabsRenderHorizontal (
|
||||
IN UINTN TopY,
|
||||
IN UINTN BarH,
|
||||
IN INTN ActiveIndex
|
||||
)
|
||||
{
|
||||
UINTN TabW;
|
||||
UINTN x;
|
||||
UINTN yText;
|
||||
UINTN i;
|
||||
CHAR16 NumPrefix[8];
|
||||
UINTN PrefixW;
|
||||
|
||||
if (mTabCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
TabW = mState.ScreenW / mTabCount;
|
||||
yText = TopY + (BarH - mState.FontPx) / 2;
|
||||
|
||||
for (i = 0; i < mTabCount; i++) {
|
||||
x = i * TabW;
|
||||
|
||||
// Number prefix is always dim — it's purely for orientation, the
|
||||
// emphasis belongs on the name.
|
||||
UnicodeSPrint (NumPrefix, sizeof (NumPrefix), L"%02u ", (UINT32)(i + 1));
|
||||
GfxSetTextColor (TC_DIMMER);
|
||||
GfxDrawTextW (x + 2 * GFX_PADDING_PX, yText, NumPrefix);
|
||||
PrefixW = GfxMeasureTextW (NumPrefix);
|
||||
|
||||
// Active: bright white. Inactive: dim — visible but recedes.
|
||||
if ((INTN)i == ActiveIndex) {
|
||||
GfxSetTextColor (TC_WHITE);
|
||||
} else {
|
||||
GfxSetTextColor (TC_DIM);
|
||||
}
|
||||
GfxDrawTextWClipped (
|
||||
x + 2 * GFX_PADDING_PX + PrefixW,
|
||||
yText,
|
||||
TabW - 3 * GFX_PADDING_PX - PrefixW,
|
||||
mTabs[i].Name[0] != L'\0' ? mTabs[i].Name : L"?"
|
||||
);
|
||||
|
||||
if ((INTN)i == ActiveIndex) {
|
||||
GfxFillRect (
|
||||
x + GFX_PADDING_PX,
|
||||
TopY + BarH - 3,
|
||||
TabW - 2 * GFX_PADDING_PX, 3,
|
||||
GFX_ACCENT
|
||||
);
|
||||
}
|
||||
}
|
||||
GfxSetTextColor (TC_WHITE);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,246 @@
|
||||
/** @file
|
||||
Dasharo Save & Exit UI library.
|
||||
|
||||
Publishes a small HII formset on the Front Page (via classguid =
|
||||
gEfiIfrFrontPageGuid) containing action items for Save / Discard /
|
||||
Reset. Each action's question ID is dispatched to a browser action
|
||||
request inside the config-access callback.
|
||||
|
||||
Copyright (c) 2026, 3mdeb Sp. z o.o. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include "DasharoSaveExit.h"
|
||||
|
||||
#include <Uefi.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/DevicePathLib.h>
|
||||
#include <Library/HiiLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
|
||||
#include <Protocol/DevicePath.h>
|
||||
#include <Protocol/FormBrowserEx.h>
|
||||
#include <Protocol/FormBrowserEx2.h>
|
||||
#include <Protocol/HiiConfigAccess.h>
|
||||
|
||||
#include <Guid/MdeModuleHii.h>
|
||||
|
||||
extern UINT8 DasharoSaveExitUiLibStrings[];
|
||||
|
||||
#define DASHARO_SAVE_EXIT_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('D', 'S', 'E', 'X')
|
||||
|
||||
typedef struct {
|
||||
UINTN Signature;
|
||||
EFI_HII_HANDLE HiiHandle;
|
||||
EFI_HANDLE DriverHandle;
|
||||
EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
|
||||
} DASHARO_SAVE_EXIT_PRIVATE_DATA;
|
||||
|
||||
STATIC EFI_GUID mDasharoSaveExitGuid = DASHARO_SAVE_EXIT_GUID;
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
ExtractConfig (
|
||||
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
|
||||
IN CONST EFI_STRING Request,
|
||||
OUT EFI_STRING *Progress,
|
||||
OUT EFI_STRING *Results
|
||||
)
|
||||
{
|
||||
if (Progress != NULL) {
|
||||
*Progress = (EFI_STRING)Request;
|
||||
}
|
||||
// No varstore — actions only.
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
RouteConfig (
|
||||
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
|
||||
IN CONST EFI_STRING Configuration,
|
||||
OUT EFI_STRING *Progress
|
||||
)
|
||||
{
|
||||
if (Progress != NULL) {
|
||||
*Progress = (EFI_STRING)Configuration;
|
||||
}
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Callback (
|
||||
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
|
||||
IN EFI_BROWSER_ACTION Action,
|
||||
IN EFI_QUESTION_ID QuestionId,
|
||||
IN UINT8 Type,
|
||||
IN OUT EFI_IFR_TYPE_VALUE *Value,
|
||||
OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
|
||||
)
|
||||
{
|
||||
if (Action != EFI_BROWSER_ACTION_CHANGED) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
switch (QuestionId) {
|
||||
case KEY_SAVE_AND_EXIT: {
|
||||
// We need a real save-then-reset, system-wide. ExecuteAction with
|
||||
// SystemLevel scope walks every dirty formset's pending values and
|
||||
// commits them via ConfigRouting; ResetSystem then reboots.
|
||||
EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL *FormBrowserEx2;
|
||||
EFI_STATUS LookupStatus;
|
||||
|
||||
LookupStatus = gBS->LocateProtocol (
|
||||
&gEdkiiFormBrowserEx2ProtocolGuid,
|
||||
NULL,
|
||||
(VOID **)&FormBrowserEx2
|
||||
);
|
||||
if (!EFI_ERROR (LookupStatus) && (FormBrowserEx2 != NULL)) {
|
||||
if (FormBrowserEx2->SetScope != NULL) {
|
||||
FormBrowserEx2->SetScope (SystemLevel);
|
||||
}
|
||||
if (FormBrowserEx2->ExecuteAction != NULL) {
|
||||
FormBrowserEx2->ExecuteAction (BROWSER_ACTION_SUBMIT, 0);
|
||||
}
|
||||
}
|
||||
gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
|
||||
// Unreachable.
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
case KEY_DISCARD_AND_EXIT: {
|
||||
// FORM_DISCARD_EXIT only exits the current form (back to Front
|
||||
// Page). To exit setup entirely we drive the discard + exit
|
||||
// through ExecuteAction at SystemLevel scope, which sets the
|
||||
// browser's gExitRequired flag.
|
||||
EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL *FormBrowserEx2;
|
||||
EFI_STATUS LookupStatus;
|
||||
|
||||
LookupStatus = gBS->LocateProtocol (
|
||||
&gEdkiiFormBrowserEx2ProtocolGuid,
|
||||
NULL,
|
||||
(VOID **)&FormBrowserEx2
|
||||
);
|
||||
if (!EFI_ERROR (LookupStatus) && (FormBrowserEx2 != NULL)) {
|
||||
if (FormBrowserEx2->SetScope != NULL) {
|
||||
FormBrowserEx2->SetScope (SystemLevel);
|
||||
}
|
||||
if (FormBrowserEx2->ExecuteAction != NULL) {
|
||||
FormBrowserEx2->ExecuteAction (
|
||||
BROWSER_ACTION_DISCARD | BROWSER_ACTION_EXIT,
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
*ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
case KEY_SAVE:
|
||||
*ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
|
||||
return EFI_SUCCESS;
|
||||
|
||||
case KEY_DISCARD:
|
||||
*ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD;
|
||||
return EFI_SUCCESS;
|
||||
|
||||
case KEY_RESET_SYSTEM:
|
||||
// Hard reset — discards any unsaved changes by definition.
|
||||
gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
|
||||
// Unreachable.
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
STATIC DASHARO_SAVE_EXIT_PRIVATE_DATA mPrivate = {
|
||||
DASHARO_SAVE_EXIT_PRIVATE_DATA_SIGNATURE,
|
||||
NULL,
|
||||
NULL,
|
||||
{
|
||||
ExtractConfig,
|
||||
RouteConfig,
|
||||
Callback
|
||||
}
|
||||
};
|
||||
|
||||
STATIC HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath = {
|
||||
{
|
||||
{
|
||||
HARDWARE_DEVICE_PATH,
|
||||
HW_VENDOR_DP,
|
||||
{
|
||||
(UINT8)(sizeof (VENDOR_DEVICE_PATH)),
|
||||
(UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
|
||||
}
|
||||
},
|
||||
DASHARO_SAVE_EXIT_GUID
|
||||
},
|
||||
{
|
||||
END_DEVICE_PATH_TYPE,
|
||||
END_ENTIRE_DEVICE_PATH_SUBTYPE,
|
||||
{
|
||||
(UINT8)(END_DEVICE_PATH_LENGTH),
|
||||
(UINT8)((END_DEVICE_PATH_LENGTH) >> 8)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
DasharoSaveExitUiLibConstructor (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||
&mPrivate.DriverHandle,
|
||||
&gEfiDevicePathProtocolGuid, &mHiiVendorDevicePath,
|
||||
&gEfiHiiConfigAccessProtocolGuid, &mPrivate.ConfigAccess,
|
||||
NULL
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
mPrivate.HiiHandle = HiiAddPackages (
|
||||
&mDasharoSaveExitGuid,
|
||||
mPrivate.DriverHandle,
|
||||
DasharoSaveExitVfrBin,
|
||||
DasharoSaveExitUiLibStrings,
|
||||
NULL
|
||||
);
|
||||
ASSERT (mPrivate.HiiHandle != NULL);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
DasharoSaveExitUiLibDestructor (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
if (mPrivate.HiiHandle != NULL) {
|
||||
HiiRemovePackages (mPrivate.HiiHandle);
|
||||
}
|
||||
if (mPrivate.DriverHandle != NULL) {
|
||||
gBS->UninstallMultipleProtocolInterfaces (
|
||||
mPrivate.DriverHandle,
|
||||
&gEfiDevicePathProtocolGuid, &mHiiVendorDevicePath,
|
||||
&gEfiHiiConfigAccessProtocolGuid, &mPrivate.ConfigAccess,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/** @file
|
||||
Dasharo Save & Exit UI library — header shared between the VFR and the C
|
||||
glue. Defines the formset GUID, form / question IDs, and the local
|
||||
HII_VENDOR_DEVICE_PATH used to publish the formset.
|
||||
|
||||
Copyright (c) 2026, 3mdeb Sp. z o.o. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#ifndef _DASHARO_SAVE_EXIT_H_
|
||||
#define _DASHARO_SAVE_EXIT_H_
|
||||
|
||||
#define DASHARO_SAVE_EXIT_GUID \
|
||||
{ 0x5b7f9a21, 0x3c44, 0x4e89, { 0xb1, 0xa6, 0xd8, 0xc7, 0xf2, 0xe5, 0xa9, 0x01 } }
|
||||
|
||||
#define DASHARO_SAVE_EXIT_FORM_ID 0x1
|
||||
|
||||
// Question IDs for the action items. Browser invokes our config-access
|
||||
// callback with these on user activation.
|
||||
#define KEY_SAVE_AND_EXIT 0x1001
|
||||
#define KEY_DISCARD_AND_EXIT 0x1002
|
||||
#define KEY_SAVE 0x1003
|
||||
#define KEY_DISCARD 0x1004
|
||||
#define KEY_RESET_SYSTEM 0x1005
|
||||
|
||||
#ifndef VFRCOMPILE
|
||||
#include <Protocol/DevicePath.h>
|
||||
|
||||
extern UINT8 DasharoSaveExitVfrBin[];
|
||||
|
||||
typedef struct {
|
||||
VENDOR_DEVICE_PATH VendorDevicePath;
|
||||
EFI_DEVICE_PATH_PROTOCOL End;
|
||||
} HII_VENDOR_DEVICE_PATH;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
/** @file
|
||||
Dasharo Save & Exit UI library — string table.
|
||||
|
||||
Copyright (c) 2026, 3mdeb Sp. z o.o. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#langdef en-US "English"
|
||||
|
||||
#string STR_SAVE_EXIT_TITLE #language en-US "Save & Exit"
|
||||
#string STR_SAVE_EXIT_HELP #language en-US "Save / discard / reset options"
|
||||
|
||||
#string STR_SAVE_AND_EXIT #language en-US "Save changes and exit (reboot)"
|
||||
#string STR_SAVE_AND_EXIT_HELP #language en-US "Save all changes and reboot to apply them."
|
||||
|
||||
#string STR_DISCARD_AND_EXIT #language en-US "Discard changes and exit"
|
||||
#string STR_DISCARD_AND_EXIT_HELP #language en-US "Discard all unsaved changes and exit setup."
|
||||
|
||||
#string STR_SAVE #language en-US "Save changes"
|
||||
#string STR_SAVE_HELP #language en-US "Save all changes; remain in setup. Most settings only take effect after a reboot."
|
||||
|
||||
#string STR_DISCARD #language en-US "Discard changes"
|
||||
#string STR_DISCARD_HELP #language en-US "Discard all unsaved changes; remain in setup."
|
||||
|
||||
#string STR_RESET_SYSTEM #language en-US "Reset system"
|
||||
#string STR_RESET_SYSTEM_HELP #language en-US "Reboot the system. Unsaved changes are lost."
|
||||
|
||||
#string STR_EMPTY #language en-US ""
|
||||
@@ -0,0 +1,53 @@
|
||||
## @file
|
||||
# Dasharo Save & Exit UI library — adds the Save & Exit tab to the front
|
||||
# page (via classguid = gEfiIfrFrontPageGuid) with action items for
|
||||
# save / discard / reset.
|
||||
#
|
||||
# Copyright (c) 2026, 3mdeb Sp. z o.o. All rights reserved.<BR>
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = DasharoSaveExitUiLib
|
||||
FILE_GUID = 8FA1B244-9CDF-4A2E-AA34-5B7E89432101
|
||||
MODULE_TYPE = DXE_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
LIBRARY_CLASS = NULL|DXE_DRIVER UEFI_APPLICATION
|
||||
CONSTRUCTOR = DasharoSaveExitUiLibConstructor
|
||||
DESTRUCTOR = DasharoSaveExitUiLibDestructor
|
||||
|
||||
[Sources]
|
||||
DasharoSaveExit.h
|
||||
DasharoSaveExit.c
|
||||
DasharoSaveExitVfr.vfr
|
||||
DasharoSaveExitStrings.uni
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
DasharoPayloadPkg/DasharoPayloadPkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
||||
BaseMemoryLib
|
||||
DebugLib
|
||||
DevicePathLib
|
||||
HiiLib
|
||||
MemoryAllocationLib
|
||||
PrintLib
|
||||
UefiBootServicesTableLib
|
||||
UefiRuntimeServicesTableLib
|
||||
UefiHiiServicesLib
|
||||
|
||||
[Guids]
|
||||
gEfiIfrFrontPageGuid ## CONSUMES ## GUID (classguid for placement on the front page)
|
||||
gEfiIfrTianoGuid ## CONSUMES ## GUID (extended IFR opcodes)
|
||||
|
||||
[Protocols]
|
||||
gEfiDevicePathProtocolGuid ## PRODUCES
|
||||
gEfiHiiConfigAccessProtocolGuid ## PRODUCES
|
||||
gEdkiiFormBrowserEx2ProtocolGuid ## CONSUMES
|
||||
|
||||
[Depex]
|
||||
gEfiHiiDatabaseProtocolGuid
|
||||
@@ -0,0 +1,70 @@
|
||||
/** @file
|
||||
Dasharo Save & Exit formset.
|
||||
|
||||
Provides the action items that show up on the Save & Exit tab. Each item
|
||||
is a `text` opcode with INTERACTIVE flag + unique question ID; the
|
||||
config-access callback in DasharoSaveExit.c maps each ID to a browser
|
||||
action request (or, for Reset System, calls gRT->ResetSystem directly).
|
||||
|
||||
Copyright (c) 2026, 3mdeb Sp. z o.o. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include "DasharoSaveExit.h"
|
||||
|
||||
formset
|
||||
guid = DASHARO_SAVE_EXIT_GUID,
|
||||
title = STRING_TOKEN(STR_SAVE_EXIT_TITLE),
|
||||
help = STRING_TOKEN(STR_SAVE_EXIT_HELP),
|
||||
classguid = gEfiIfrFrontPageGuid,
|
||||
|
||||
form formid = DASHARO_SAVE_EXIT_FORM_ID,
|
||||
title = STRING_TOKEN(STR_SAVE_EXIT_TITLE);
|
||||
|
||||
action
|
||||
questionid = KEY_SAVE_AND_EXIT,
|
||||
prompt = STRING_TOKEN(STR_SAVE_AND_EXIT),
|
||||
help = STRING_TOKEN(STR_SAVE_AND_EXIT_HELP),
|
||||
flags = INTERACTIVE,
|
||||
config = STRING_TOKEN(STR_EMPTY),
|
||||
endaction;
|
||||
|
||||
action
|
||||
questionid = KEY_DISCARD_AND_EXIT,
|
||||
prompt = STRING_TOKEN(STR_DISCARD_AND_EXIT),
|
||||
help = STRING_TOKEN(STR_DISCARD_AND_EXIT_HELP),
|
||||
flags = INTERACTIVE,
|
||||
config = STRING_TOKEN(STR_EMPTY),
|
||||
endaction;
|
||||
|
||||
subtitle text = STRING_TOKEN(STR_EMPTY);
|
||||
|
||||
action
|
||||
questionid = KEY_SAVE,
|
||||
prompt = STRING_TOKEN(STR_SAVE),
|
||||
help = STRING_TOKEN(STR_SAVE_HELP),
|
||||
flags = INTERACTIVE,
|
||||
config = STRING_TOKEN(STR_EMPTY),
|
||||
endaction;
|
||||
|
||||
action
|
||||
questionid = KEY_DISCARD,
|
||||
prompt = STRING_TOKEN(STR_DISCARD),
|
||||
help = STRING_TOKEN(STR_DISCARD_HELP),
|
||||
flags = INTERACTIVE,
|
||||
config = STRING_TOKEN(STR_EMPTY),
|
||||
endaction;
|
||||
|
||||
subtitle text = STRING_TOKEN(STR_EMPTY);
|
||||
|
||||
action
|
||||
questionid = KEY_RESET_SYSTEM,
|
||||
prompt = STRING_TOKEN(STR_RESET_SYSTEM),
|
||||
help = STRING_TOKEN(STR_RESET_SYSTEM_HELP),
|
||||
flags = INTERACTIVE,
|
||||
config = STRING_TOKEN(STR_EMPTY),
|
||||
endaction;
|
||||
|
||||
endform;
|
||||
|
||||
endformset;
|
||||
Reference in New Issue
Block a user